Created
January 17, 2023 21:03
-
-
Save marnanel/90f256b17b8cd4a98724ede9a95ca6b8 to your computer and use it in GitHub Desktop.
Analysis of Kryptos panels
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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