Skip to content

Instantly share code, notes, and snippets.

@marnanel
Created January 17, 2023 21:03
Show Gist options
  • Save marnanel/90f256b17b8cd4a98724ede9a95ca6b8 to your computer and use it in GitHub Desktop.
Save marnanel/90f256b17b8cd4a98724ede9a95ca6b8 to your computer and use it in GitHub Desktop.
Analysis of Kryptos panels
from PIL import Image, ImageDraw
# non-Python people should note that this is valid JSON
PANELS = {
"A000": "BETWEENSUBTLESHADINGANDTHEABSENC",
"A001": "EOFLIGHTLIESTHENUANCEOFIQLUSION",
"A002": "ITWASTOTALLYINVISIBLEHOWSTHATPO",
"A003": "SSIBLE?THEYUSEDTHEEARTHSMAGNET",
"A004": "ICFIELDXTHEINFORMATIONWASGATHER",
"A005": "EDANDTRANSMITTEDUNDERGRUUNDTOANU",
"A006": "NKNOWNLOCATIONXDOESLANGLEYKNOWA",
"A007": "BOUTTHIS?THEYSHOULDITSBURIEDOUT",
"A008": "THERESOMEWHEREXWHOKNOWSTHEEXACTL",
"A009": "OCATION?ONLYWWTHISWASHISLASTMES",
"A010": "SAGEXTHIRTYEIGHTDEGREESFIFTYSE",
"A011": "VENMINUTESSIXPOINTFIVESECONDSNO",
"A012": "RTHSEVENTYSEVENDEGREESEIGHTMINU",
"A013": "TESFORTYFOURSECONDSWESTXLAYERTW",
"A100": "SLOWLYDESPARATLYSLOWLYTHEREMAINS",
"A101": "OFPASSAGEDEBRISTHATENCUMBEREDT",
"A102": "HELOWERPARTOFTHEDOORWAYWASREMOV",
"A103": "EDWITHTREMBLINGHANDSIMADEATINY",
"A104": "BREACHINTHEUPPERLEFTHANDCORNERAN",
"A105": "DTHENWIDENINGTHEHOLEALITTLEIIN",
"A106": "SERTEDTHECANDLEANDPEEREDINTHEHOT",
"A107": "AIRESCAPINGFROMTHECHAMBERCAUSED",
"A108": "THEFLAMETOFLICKERBUTPRESENTLYDETA",
"A109": "ILSOFTHEROOMWITHINEMERGEDFROM",
"A110": "THEMISTXCANYOUSEEANYTHINGQ?",
"A111": "",
"A112": "",
"A113": "",
"Q000": "EMUFPHZLRFAXYUSDJKZLDKRNSHGNFIVJ",
"Q001": "YQTQUXQBQVYUVLLTREVJYQTMKYRDMFD",
"Q002": "VFPJUDEEHZWETZYVGWHKKQETGFQJNCE",
"Q003": "GGWHKK?DQMCPFQZDQMMIAGPFXHQRLG",
"Q004": "TIMVMZJANQLVKQEDAGDVFRPJUNGEUNA",
"Q005": "QZGZLECGYUXUEENJTBJLBQCRTBJDFHRR",
"Q006": "YIZETKZEMVDUFKSJHKFWHKUWQLSZFTI",
"Q007": "HHDDDUVH?DWKBFUFPWNTDFIYCUQZERE",
"Q008": "EVLDKFEZMOQQJLTTUGSYQPFEUNLAVIDX",
"Q009": "FLGGTEZ?FKZBSFDQVGOGIPUFXHHDRKF",
"Q010": "FHQNTGPUAECNUVPDJMQCLQUMUNEDFQ",
"Q011": "ELZZVRRGKFFVOEEXBDMVPNFQXEZLGRE",
"Q012": "DNQFMPNZGLFLPMRJQYALMGNUVPDXVKP",
"Q013": "DQUMEBEDMHDAFMJGZNUPLGEWJLLAETG",
"Q100": ".ABCDEFGHIJKLMNOPQRSTUVWXYZABCD",
"Q101": "AKRYPTOSABCDEFGHIJLMNQUVWXZKRYP",
"Q102": "BRYPTOSABCDEFGHIJLMNQUVWXZKRYPT",
"Q103": "CYPTOSABCDEFGHIJLMNQUVWXZKRYPTO",
"Q104": "DPTOSABCDEFGHIJLMNQUVWXZKRYPTOS",
"Q105": "ETOSABCDEFGHIJLMNQUVWXZKRYPTOSA",
"Q106": "FOSABCDEFGHIJLMNQUVWXZKRYPTOSAB",
"Q107": "GSABCDEFGHIJLMNQUVWXZKRYPTOSABC",
"Q108": "HABCDEFGHIJLMNQUVWXZKRYPTOSABCD",
"Q109": "IBCDEFGHIJLMNQUVWXZKRYPTOSABCDE",
"Q110": "JCDEFGHIJLMNQUVWXZKRYPTOSABCDEF",
"Q111": "KDEFGHIJLMNQUVWXZKRYPTOSABCDEFG",
"Q112": "LEFGHIJLMNQUVWXZKRYPTOSABCDEFGH",
"Q113": "MFGHIJLMNQUVWXZKRYPTOSABCDEFGHI",
"Q200": "ENDYAHROHNLSRHEOCPTEOIBIDYSHNAIA",
"Q201": "CHTNREYULDSLLSLLNOHSNOSMRWXMNE",
"Q202": "TPRNGATIHNRARPESLNNELEBLPIIACAE",
"Q203": "WMTWNDITEENRAHCTENEUDRETNHAEOE",
"Q204": "TFOLSEDTIWENHAEIOYTEYQHEENCTAYCR",
"Q205": "EIFTBRSPAMHHEWENATAMATEGYEERLB",
"Q206": "TEEFOASFIOTUETUAEOTOARMAEERTNRTI",
"Q207": "BSEDDNIAAHTTMSTEWPIEROAGRIEWFEB",
"Q208": "AECTDDHILCEIHSITEGOEAOSDDRYDLORIT",
"Q209": "RKLMLEHAGTDHARDPNEOHMGFMFEUHE",
"Q210": "ECDMRIPFEIMEHNLSSTTRTVDOHW?OBKR",
"Q211": "UOXOGHULBSOLIFBBWFLRVQQPRNGKSSO",
"Q212": "TWTQSJQSSEKZZWATJKLUDIAWINFBNYP",
"Q213": "VTTMZFPKWGDKZXTJCDIGKUHUAUEKCAR",
"Q300": "NGHIJLMNQUVWXZKRYPTOSABCDEFGHIJ",
"Q301": "OHIJLMNQUVWXZKRYPTOSABCDEFGHIJL",
"Q302": "PIJLMNQUVWXZKRYPTOSABCDEFGHIJLM",
"Q303": "QJLMNQUVWXZKRYPTOSABCDEFGHIJLMN",
"Q304": "RLMNQUVWXZKRYPTOSABCDEFGHIJLMNQ",
"Q305": "SMNQUVWXZKRYPTOSABCDEFGHIJLMNQU",
"Q306": "TNQUVWXZKRYPTOSABCDEFGHIJLMNQUV",
"Q307": "UQUVWXZKRYPTOSABCDEFGHIJLMNQUVW",
"Q308": "VUVWXZKRYPTOSABCDEFGHIJLMNQUVWX",
"Q309": "WVWXZKRYPTOSABCDEFGHIJLMNQUVWXZ",
"Q310": "XWXZKRYPTOSABCDEFGHIJLMNQUVWXZK",
"Q311": "YXZKRYPTOSABCDEFGHIJLMNQUVWXZKR",
"Q312": "ZZKRYPTOSABCDEFGHIJLMNQUVWXZKRY",
"Q313": ".ABCDEFGHIJKLMNOPQRSTUVWXYZABCD"
}
FORWARDS = [
('B', 'N', '#ff0000'),
('E', 'Y', '#ff7700'),
('R', 'P', '#ffff00'),
('L', 'V', '#00ff00'),
('I', 'T', '#0000ff'),
('N', 'T', '#7777ff'),
]
BACKWARDS = [
('N', 'B', '#ff0000'),
('Y', 'E', '#ff7700'),
('P', 'R', '#ffff00'),
('V', 'L', '#00ff00'),
('T', 'I', '#0000ff'),
('T', 'N', '#7777ff'),
]
def main(goals, output_filename):
pivoted_panels = {}
for plane in ('Q0', 'Q1', 'Q2', 'Q3', 'A0', 'A1'):
for i in range(40):
key = 'p%s%02d' % (plane, i)
pivoted_panels[key] = ''
for j in sorted(PANELS.keys()):
if not j.startswith(plane):
continue
try:
pivoted_panels[key] += PANELS[j][i]
except:
pass
def burial_lookup(naming, buried, letter):
result = set()
for i in range(min(len(naming), len(buried))):
if naming[i]==letter:
result.add(buried[i])
return result
panel_keys = sorted(PANELS.keys())
pivoted_keys = sorted(pivoted_panels.keys())
im = Image.new("RGB", (len(pivoted_keys)*8+10, len(pivoted_keys)*8+10), color="#ffffff")
draw = ImageDraw.Draw(im, "RGBA")
for naming_i in range(len(pivoted_keys)):
for buried_i in range(len(pivoted_keys)):
naming = pivoted_panels[pivoted_keys[naming_i]]
buried = pivoted_panels[pivoted_keys[buried_i]]
x = 5 + naming_i * 8
y = 5 + buried_i * 8
colours = []
for (source, target, then_colour) in goals:
if target in burial_lookup(naming, buried, source):
colours.append(then_colour)
if len(colours)==0:
draw.rectangle(((x,y), (x+5,y+5)), fill='#bbbbbb')
else:
ALLOCATION = [
[],
[0,0,0,0,0,0],
[0,0,0,1,1,1],
[0,0,1,1,2,2],
[0,0,1,2,2,3],
[0,1,1,2,3,4],
[0,1,2,3,4,5],
]
allocation = ALLOCATION[len(colours)]
for c in range(5):
draw.rectangle(((x,y+c), (x+5,y+c)),
fill=colours[allocation[c]])
im.save(open(output_filename, 'wb'), 'PNG')
if __name__=='__main__':
main(FORWARDS, 'forwards.png')
main(BACKWARDS, 'backwards.png')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment