Skip to content

Instantly share code, notes, and snippets.

@xsot
Last active January 18, 2019 13:22
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xsot/cd08dfb284474c12aedec7497060e602 to your computer and use it in GitHub Desktop.
Save xsot/cd08dfb284474c12aedec7497060e602 to your computer and use it in GitHub Desktop.
Minimal charset quine
names = {
43 => 'e',
'prog' => 'x', # the program will be stored in this variable
'template' => 'c',
0 => 'ee', # register?
1 => 'ex',
2 => 'ec',
4 => 'xe',
8 => 'xx',
16 => 'xc',
32 => 'ce',
64 => 'cc',
'data' => 'cx', # source program will be encoded here
}
# string to be executed during last exec step
# this needs to be constructed by the encoder
execstring = 'h,t=cx.split(";;");print h+\'"""\'+cx+\'""";\'+t'
charset = ('exc="%;'+execstring).chars.uniq.sort
codepoints = charset.map(&:ord)
init = (
# create template for joining multiple characters
"#{names['template']}=\"%c%%c%%%%c%%%%%%%%c\";" +
# create 1
"#{names[1]}=#{names['template']}==#{names['template']};" +
# create 0
"#{names[0]}=#{names['template']}==\"\";" +
# create 3
# store it at names[43] temporarily
"exec\"#{names[43]}=%x%%x\"%#{names[1]}%#{names[1]};" +
"exec\"#{names[43]}%%%%%%%%=%x%%x%%%%x\"%#{names[0]}%#{names[1]}%#{names[0]};" +
# create 4
# this step overwrites the value stored at names[0]
"exec\"#{names[0]}=%x%%x\"%#{names[43]}%#{names[0]};" +
"exec\"#{names[0]}%%%%=%x%%x\"%#{names[1]}%#{names[43]};" +
# create 43
"exec\"#{names[43]}=%x%%x\"%#{names[0]}%#{names[43]};"
)
# create powers of 2
(1..6).map{ |i| 2**i }.each do |i|
init += "exec\"#{names[i]}=#{names[i/2]}%c#{names[i/2]}\"%#{names[43]};"
end
codepoints.map.with_index do |c, i|
# skip code point if it is already aliased (e.g. power of two)
next if names.include?(c)
def genname(length, i)
varname = ''
length.times do
varname += 'exc'[i%3]
i /= 3
end
return varname
end
# generate a new name for this variable
if i < 27
names[c] = genname(3, i)
else
i -= 27
names[c] = genname(4, i)
end
# decompose code point into powers of two
rem = c
pows = []
while rem > 0
pows << (rem&-rem)
rem -= rem&-rem
end
# generate the code that defines this variable
front = "exec\"#{names[c]}=#{names[pows.pop]}"
back = '"'
pows.map.with_index do |p, i|
front += '%'*(2**i) + 'c' + names[p]
back += '%' + names[43]
end
init += front + back + ';'
end
# length of execstring must be a multiple of 4
length = execstring.size
if length%4 != 0
puts length%4
exit
end
# generate code to build execstring
builder = ""
i = 0
while i < length
# extract the next four characters
w, x, y, z = (0..3).map{|j| names[execstring[i+j].ord]}
if builder == ""
builder += "exec\"#{names['prog']}=#{names['template']}%#{w}%#{x}%#{y}%#{z}\";"
else
builder += "exec\"#{names['prog']}%c=#{names['template']}%%#{w}%%#{x}%%#{y}%%#{z}\"%#{names[43]};"
end
i += 4
end
header = init+builder
# to be appended to actual program
# exec'exec%c___'%___
execstep = "exec\"exec%c#{names['prog']}\"%#{names[32]}"
datastring="#{names['data']}=\"\"\"#{header}#{names['data']}=;;#{execstep}\"\"\";"
puts header+datastring+execstep
c="%c%%c%%%%c%%%%%%%%c";ex=c==c;ee=c=="";exec"e=%x%%x"%ex%ex;exec"e%%%%%%%%=%x%%x%%%%x"%ee%ex%ee;exec"ee=%x%%x"%e%ee;exec"ee%%%%=%x%%x"%ex%e;exec"e=%x%%x"%ee%e;exec"ec=ex%cex"%e;exec"xe=ec%cec"%e;exec"xx=xe%cxe"%e;exec"xc=xx%cxx"%e;exec"ce=xc%cxc"%e;exec"cc=ce%cce"%e;exec"xee=ce%cec"%e;exec"cee=ce%cex%%cxe"%e%e;exec"exe=ce%cex%%cec%%%%cxe"%e%e%e;exec"xxe=ce%cxx"%e;exec"cxe=ce%cex%%cxx"%e%e;exec"xce=ce%cxe%%cxx"%e%e;exec"cce=ce%cec%%cxe%%%%cxx"%e%e%e;exec"eex=ce%cex%%cec%%%%cxx%%%%%%%%cxc"%e%e%e%e;exec"xex=ce%cex%%cxe%%%%cxx%%%%%%%%cxc"%e%e%e%e;exec"cex=cc%cex%%cec%%%%cce"%e%e%e;exec"exx=cc%cex%%cxe%%%%cce"%e%e%e;exec"xxx=cc%cxx%%cce"%e%e;exec"cxx=cc%cex%%cxx%%%%cce"%e%e%e;exec"ecx=cc%cxe%%cxx%%%%cce"%e%e%e;exec"xcx=cc%cec%%cxe%%%%cxx%%%%%%%%cce"%e%e%e%e;exec"ccx=cc%cxc%%cce"%e%e;exec"eec=cc%cec%%cxc%%%%cce"%e%e%e;exec"xec=cc%cex%%cec%%%%cxc%%%%%%%%cce"%e%e%e%e;exec"cec=cc%cxe%%cxc%%%%cce"%e%e%e;exec"exc=cc%cxx%%cxc%%%%cce"%e%e%e;exec"x=c%xxx%xce%cec%xex";exec"x%c=c%%cex%%exc%%cce%%xec"%e;exec"x%c=c%%ccx%%ecx%%cxx%%cec"%e;exec"x%c=c%%xxe%%xee%%eex%%eex"%e;exec"x%c=c%%xee%%cxe%%eex%%ccx"%e;exec"x%c=c%%eec%%cxx%%xcx%%cec"%e;exec"x%c=c%%ce%%xxx%%e%%exe"%e;exec"x%c=c%%xee%%xee%%xee%%exe"%e;exec"x%c=c%%e%%cex%%exc%%e"%e;exec"x%c=c%%exe%%xee%%xee%%xee"%e;exec"x%c=c%%eex%%exe%%e%%cec"%e;cx="""c="%c%%c%%%%c%%%%%%%%c";ex=c==c;ee=c=="";exec"e=%x%%x"%ex%ex;exec"e%%%%%%%%=%x%%x%%%%x"%ee%ex%ee;exec"ee=%x%%x"%e%ee;exec"ee%%%%=%x%%x"%ex%e;exec"e=%x%%x"%ee%e;exec"ec=ex%cex"%e;exec"xe=ec%cec"%e;exec"xx=xe%cxe"%e;exec"xc=xx%cxx"%e;exec"ce=xc%cxc"%e;exec"cc=ce%cce"%e;exec"xee=ce%cec"%e;exec"cee=ce%cex%%cxe"%e%e;exec"exe=ce%cex%%cec%%%%cxe"%e%e%e;exec"xxe=ce%cxx"%e;exec"cxe=ce%cex%%cxx"%e%e;exec"xce=ce%cxe%%cxx"%e%e;exec"cce=ce%cec%%cxe%%%%cxx"%e%e%e;exec"eex=ce%cex%%cec%%%%cxx%%%%%%%%cxc"%e%e%e%e;exec"xex=ce%cex%%cxe%%%%cxx%%%%%%%%cxc"%e%e%e%e;exec"cex=cc%cex%%cec%%%%cce"%e%e%e;exec"exx=cc%cex%%cxe%%%%cce"%e%e%e;exec"xxx=cc%cxx%%cce"%e%e;exec"cxx=cc%cex%%cxx%%%%cce"%e%e%e;exec"ecx=cc%cxe%%cxx%%%%cce"%e%e%e;exec"xcx=cc%cec%%cxe%%%%cxx%%%%%%%%cce"%e%e%e%e;exec"ccx=cc%cxc%%cce"%e%e;exec"eec=cc%cec%%cxc%%%%cce"%e%e%e;exec"xec=cc%cex%%cec%%%%cxc%%%%%%%%cce"%e%e%e%e;exec"cec=cc%cxe%%cxc%%%%cce"%e%e%e;exec"exc=cc%cxx%%cxc%%%%cce"%e%e%e;exec"x=c%xxx%xce%cec%xex";exec"x%c=c%%cex%%exc%%cce%%xec"%e;exec"x%c=c%%ccx%%ecx%%cxx%%cec"%e;exec"x%c=c%%xxe%%xee%%eex%%eex"%e;exec"x%c=c%%xee%%cxe%%eex%%ccx"%e;exec"x%c=c%%eec%%cxx%%xcx%%cec"%e;exec"x%c=c%%ce%%xxx%%e%%exe"%e;exec"x%c=c%%xee%%xee%%xee%%exe"%e;exec"x%c=c%%e%%cex%%exc%%e"%e;exec"x%c=c%%exe%%xee%%xee%%xee"%e;exec"x%c=c%%eex%%exe%%e%%cec"%e;cx=;;exec"exec%cx"%ce""";exec"exec%cx"%ce
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment