from random import seed, shuffle
from string import ascii_lowercase as alphabet
from string import ascii_uppercase as capitals
from string import maketrans as mt
from sys import argv, exit
""" some cypherin' tricks
"""
long_message = """
anztheX yhnC -
"?ffbepn frzbp ru jbu bg qrfbccb fn ,gutve fv
ag - rfhnc fergebcre xfn bg obw lz gv g'afV" ,friyrfzrug xfn gfnry gn gutvz lrug gnug - rfhnc fergebcre
rivt qyhbj rparverckrheg ruGfrqabp rug ugvj tabyn frbt tavgebcre fjra uphz lnj rug fv ,uthbug ,tavug qnf lyheg ruGfrqabp rug ugvj tabyn frbt tavgebcre fjra uphz lnj rug fv ,uthbug ,tavug qnf lyheg ruG
.ugebj-syrf sb rfarf evrug ab xpnggn an f'gv
- pvtby pvfno eb fgpns evrug ab ch ajbuf re'lrug aruj rtne ugvj gpnre rycbrc uphf ,arug ,lyongviraV
)".rxvy fqahbf abferc yhsguthbug n gnuj sb nrqv f'abferc qvchgf n rxvy f'rU" :fhug lrzeN xpvQ qrovepfrq
rpab avryX nemR( .genzf qahbf zrug frxnz fvug gnug srvyro rug av zrug gnrcre qan ,frqhgvgnyc rfbug ch
xpvc bg qarg fhbvehpav lyynhgpryyrgav ren gho fpvgvybc ghbon ftavyrrs tabegf rinu buj rycbrC .frqhgvgnyc
rivgnierfabp sb rab lytavzyrujerib fv rfvba qahbetxpno rug ,rehgyhp ynpvgvybc gareehp ehb av :gv rrf V
jbu f'rerU .uphz bf gba ,rZ .lgvehprfav ynhgpryyrgav f'gutve rug lo qrymmhc syrfzvu frffrsbec gvnuP
?gba luJ .ba ghO .lqnynz fvug sb rfehbpfvq ehb qrehp rinu qyhbj - sshgf
tavjbax lyynhgpn ebs qrufvahc fnj rebT yN rfhnpro lyrfvprec rfhbU rgvuJ rug sb rpangfvq qnup-tavtanu
avugvj gbt buj - ufhO .J rtebrT ugvj rparverckr f'abvgna rug gnug qrcbu ,gvzqn bg rinu V ,qnu V
.tavqarpfrqabp qan gantbeen fn ffbepn rznp ru ,rrf hbl - rtanupkr rug gfby rinu bg qrerqvfabp fv O abferC qaN
".fgpns rug ren reru - rgvuj g'afv xpnyo ,bA" ,flnf O abferC .rgnpfhsob bg gebssr rgnerovyrq n sb ghb argsb
rebz uthbugyn ,rpanebatv sb ghb fcnuerc - "rgvuj fv xpnyO" flnf N abferC :fvug rxvy frbt gV
.ghbon tavxyng re'lrug gnuj tavjbax lyynhgpn ebs qrufvahc ren frehtvs pvyohC
""".encode("rot13")[-1:0:-1] # somewhat obscured in case you actually want to solve it after you read the code
# print long_message # uncomment to cheat
def make_cypher(Seed=None):
""" returns a shuffled alphabet
return is random if Seed not provided
return is repeatable function of Seed if provided
"""
if Seed:
seed(Seed)
L = (list(alphabet))
shuffle(L)
return "".join(L)
def encrypt_factory(cypher = None,Seed = None):
""" creates an encryptor and a decryptor function from a cypher, or a seed, or randomly
"""
if not cypher:
cypher = make_cypher(Seed)
trans = mt(alphabet,cypher)
untrans = mt(cypher,alphabet)
def encryptor(message):
return message.lower().translate(trans)
def decryptor(message):
return message.lower().translate(untrans)
return encryptor, decryptor
def strip_cases(mixed_message):
""" returns a lowercase version of input and a corrsponding list of booleans for case changes
note: ASCII
"""
return mixed_message.lower(), [ch in capitals for ch in mixed_message]
def restore_cases(lower_message,cases):
""" applies a list of case changes to a message; assumes input message all lowercase
note: ASCII
"""
assert len(lower_message) == len(cases)
return "".join([case and ch.upper() or ch for (ch,case) in zip(lower_message,cases)])
if __name__ == "__main__":
"""
#tests
message = "Python rocks"
#stripping, restoring cases
message_l,cases = strip_cases(message)
assert message == restore_cases(message_l,cases)
# basic usage (random encryptor)
encryptor,decryptor = encrypt_factory()
assert decryptor(encryptor(message)) == message.lower()
# prespecified encryptor
rot13 = alphabet[13:] + alphabet[:13]
e2,d2 = encrypt_factory(rot13) # rot13 repeated is a null operation
assert e2(e2(message)) == message.lower()
# repeatability, also demonstrates the relation between the two-step and one-step approach
e3,d3 = encrypt_factory(Seed=1234)
cypher = make_cypher(1234)
e4,d4 = encrypt_factory(cypher) # these will be the same because the random seed is set
assert d4(e3(message)) == message.lower() # so the decryption works
# tests pass!
"""
# play the game
# You can provide text from a file; alter this ad lib
# note: apply .encode("rot13")[-1:0:-1] to a string to obscure it;
# apply again to unobscure it
if len(argv) > 1:
long_message = file(argv[1]).read().encode("rot13")[-1:0:-1]
# random encrypt/decrypt pair
E,D = encrypt_factory(Seed = seed())
# save uppercase info as a list of booleans
long_l,cases2 = strip_cases(long_message)
# encode
cyphertext = E(long_message)
# display coded message
print "\n\n"+80*"="
print restore_cases(cyphertext,cases2)
print 80*"="
# collect up the coded symbols in the message
cypherbet = "".join([ch for ch in alphabet if ch in cyphertext])
# wait for the user to provide an answer
print "enter the decyphered alphabet below the letters of the code"
# print D(" ".join(cypherbet)) # uncomment to cheat
answer = None
try:
while not answer:
answer = raw_input(" ".join(cypherbet)+"\n")
if not answer:
print "Please enter some text or ^C to exit"
else:
decypher = "".join([ch for ch in answer if ch.isalpha()])
if len(decypher) != len(cypherbet):
print "\nPlease enter the correct number of characters."
answer = ""
except KeyboardInterrupt:
print "Thanks for trying!"
exit()
# test answer
decypher_table = mt(cypherbet,decypher)
print 80*"="
try:
assert cyphertext.translate(decypher_table) == long_message.lower()
except:
print "\n\nSorry. It should have been:\n%s\n%s" % (" ".join(cypherbet)," ".join(D(cypherbet)))
else:
print "\n\nYes!\n"
Diff to Previous Revision
--- revision 1 2010-04-20 23:49:54
+++ revision 2 2010-04-21 22:09:55
@@ -2,11 +2,9 @@
from string import ascii_lowercase as alphabet
from string import ascii_uppercase as capitals
from string import maketrans as mt
-from sys import argv
+from sys import argv, exit
""" some cypherin' tricks
-
- case preservation is left as an exercise for the reader
"""
long_message = """
@@ -152,7 +150,7 @@
print "enter the decyphered alphabet below the letters of the code"
- print D(" ".join(cypherbet)) # uncomment to cheat
+ # print D(" ".join(cypherbet)) # uncomment to cheat
answer = None
try:
@@ -163,13 +161,11 @@
else:
decypher = "".join([ch for ch in answer if ch.isalpha()])
if len(decypher) != len(cypherbet):
- print decypher
- print cypherbet
- print len(decypher), len(cypherbet)
print "\nPlease enter the correct number of characters."
answer = ""
except KeyboardInterrupt:
print "Thanks for trying!"
+ exit()
# test answer