Skip to content

Instantly share code, notes, and snippets.

@jbalboni
Last active December 15, 2015 20:58
Show Gist options
  • Save jbalboni/5322150 to your computer and use it in GitHub Desktop.
Save jbalboni/5322150 to your computer and use it in GitHub Desktop.
Python solution for generating a string that contains all possible N digit combinations and is as short as possible. The problem was described as Batman needing the combinations to open a lock and escape, hence the numerous cheesy Batman references. Default number of digits is 4.
import math
import sys
class BatSequenceGenerator():
"""Class to generate a key sequence Batman can use to escape"""
def __init__(self, digits=4):
self.digits = digits
#char sequence
self.bat_sequence = []
#Batman thought Bat Hash sounded cooler than Bat Dict
self.bat_hash = {}
#Add the new combinations covered, based on how much was added to the sequence
def update_bat_hash(self, str_size):
if str_size < 0:
for str_len in xrange(1, abs(str_size) + 1):
self.bat_hash["".join(self.bat_sequence[-(str_len + self.digits):-str_len])] = 1
else:
for str_len in xrange(1, abs(str_size) + 1):
self.bat_hash["".join(self.bat_sequence[str_len:str_len + self.digits])] = 1
#The important, Batman-saving method
def generate_bat_sequence(self):
self.bat_sequence = []
self.bat_hash = {}
#loop through all possible combinations
bat_combos = xrange(int(math.pow(10, self.digits)))
for combo in bat_combos:
bat_combo = "%04d" % combo
#there's no need to add the combination to our string if it's in the hash
if bat_combo not in self.bat_hash:
#just getting started
if len(self.bat_sequence) == 0:
self.bat_sequence.extend(list(bat_combo))
self.bat_hash[bat_combo] = 1
else:
added = False
#we want to add as few digits as possible, so see if there's a matching substring
#at either end of the sequence and then add the non-matching digits
for str_size in reversed(xrange(1, self.digits)):
if list(bat_combo[:str_size]) == self.bat_sequence[-str_size:]:
added = True
self.bat_sequence.extend(list(bat_combo[-(self.digits - str_size):]))
self.update_bat_hash(-self.digits - str_size)
break
elif list(bat_combo[-str_size:]) == self.bat_sequence[:str_size]:
added = True
self.bat_sequence = list(bat_combo[:self.digits - str_size]) + self.bat_sequence
self.update_bat_hash(self.digits - str_size)
break
#No substring, just append the combo to the sequence
if not added:
self.bat_sequence.extend(list(bat_combo))
self.update_bat_hash(-self.digits)
return self.bat_sequence
#Batman wanted some assurance you didn't screw this up
def bat_tester(self, sequence):
for combo in xrange(int(math.pow(10, self.digits))):
bat_combo = "%04d" % combo
if bat_combo not in sequence:
print "Batman DIED because you missed %s! HOW COULD YOU!?" % bat_combo
return
print "Batman ESCAPED! You must be very proud."
if __name__ == '__main__':
if len(sys.argv) > 1 and sys.argv[1].lower() == "--quiet":
sequencer = BatSequenceGenerator()
output = sequencer.generate_bat_sequence()
print "".join(output)
else:
print "Welcome to the Save Batman Key Sequence Generator Thingy"
print "How many digits is the combination?"
input = raw_input()
try:
input_digits = int(input)
except ValueError:
print "I'm sorry, Batman doesn't know that number and assumes you meant 4."
input_digits = 4
print "Finding sequence for Batman..."
sequencer = BatSequenceGenerator(input_digits)
output = sequencer.generate_bat_sequence()
print "".join(output)
print "You gave Batman a %d digit combination. Batman is not looking forward to this." % len(output)
print "Batman is using your combination to escape..."
sequencer.bat_tester("".join(output))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment