SHARE
TWEET

Reverse engineering scratchie tickets

Mr327 Aug 21st, 2012 324 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. # This is incredibly hackish, and was my first experiment with python.
  2. # It's once off throwaway code, ugly as hell, unoptimised, but it works!
  3. #
  4. # Run the script with two arguments:
  5. #     the input file with the scratchie ticket info
  6. #     the number of words you wish to find on said cards (N)
  7. # The script will then try try to find a combination of the hidden letters
  8. # that will result N words being found.
  9. #
  10. # See https://danielkinsman.wordpress.com/2011/03/26/reverse-engineering-scratchie-tickets/
  11. #
  12. # Example card input file:
  13. # fzdviwrloychtsbkmxnu area fiasco fist dab unfeeling estuary onset eyeball hustle eke arid cede buttress all forbear yolk awful aside song oat tone
  14. # slmdhibjxaquzocfwpgk sky foible prelude panda linseed fortnight elk angora refuse adze soap air down young two opal imitate era brunette eddy knee
  15. # rvpfguhzybmlcwdknios wily eschew edge yes operation whisker altar peasant rhythm tee whey swap solitary yew enlarge rate crest stunt grow woe rose
  16. # fadpyoqlvjmbitwsugcx sun instil license mitre freesia platitude nay pagoda equate fond slim pie plea nifty two clef retrace off tungsten exam yard
  17. # ixpwrvlmabhdnfjgckuo keel peanut tide tip albatross granule close eyelash mutiny day knit ogre parakeet lap pinball echo after nomad dash tie easy
  18. # thukdxspfabemvywgqco apt crease lexicon suite freesia portfolio men recede pacify give axis rap role timid toe clef rookery egg accustom neat nice
  19.  
  20. import sys
  21. import string
  22.  
  23. def getUniqueLetters(stringy):
  24.     found = ''
  25.     for khr in stringy:
  26.         if found.find(khr) < 0:
  27.             found += khr
  28.        
  29.     return found
  30.    
  31. def countBinary1s(num):
  32.     count = 0
  33.     while num > 0:
  34.         if num % 2 == 1:
  35.             count += 1
  36.    
  37.         num /= 2
  38.  
  39.     return count
  40.    
  41. def constructPossibilityUsingBitmask(mask, alphabet):
  42.     result = ''
  43.     index = 0
  44.    
  45.     while mask > 0:
  46.         if mask % 2 == 1:
  47.             result += alphabet[index]
  48.    
  49.         mask /= 2
  50.         index += 1
  51.  
  52.     return result
  53.    
  54. def stringnuke(stringy, victims):
  55.     return stringy.translate(string.maketrans('',''), victims)
  56.  
  57. class ScratchieCard(object):
  58.     letterCount = 20
  59.     letters = None
  60.     words = None
  61.    
  62.     #Format of "entry" parameter: letters(20 char string, no space) word word word...
  63.     def __init__(self, entry = None):
  64.         if(entry == None):
  65.             return
  66.        
  67.         entries = entry.split()
  68.         self.letters = entries[0]
  69.            
  70.         self.words = list()
  71.         for i in range(1, 22):
  72.             self.words.append(entries[i])
  73.            
  74.     def wordsFound(self, lLetters = None):
  75.         if(lLetters == None):
  76.             lLetters = self.letters
  77.  
  78.         if len(lLetters) != 20:
  79.             raise ValueError('there must be exactly 20 scratchie letters')
  80.  
  81.         found = 0
  82.         for word in self.words:
  83.             if len(stringnuke(word, lLetters)) == 0:
  84.                 found += 1
  85.  
  86.         return found
  87.  
  88.     def generateMatchingLetters(self, numMatch, wordcat):
  89.         matches = list()
  90.         musthaves = getUniqueLetters(wordcat)
  91.         leftovers = stringnuke('abcdefhijklmnopqrstuvwxyz', musthaves)
  92.         #print 'must ', musthaves, 'left ', leftovers
  93.         comboCount = 0
  94.        
  95.         for i in range(1, pow(2, len(leftovers))):
  96.             if countBinary1s(i) == 20 - len(musthaves):
  97.                 comboCount += 1
  98.                 pobby = musthaves + constructPossibilityUsingBitmask(i, leftovers)
  99.                 if self.wordsFound(pobby) == numMatch:
  100.                     #print pobby + ' is a match.'
  101.                     matches.append(pobby)
  102.            
  103.         #print str(comboCount) + ' possible letter combinations found for wordcat (' + wordcat + ').'
  104.         #print str(len(matches)) + ' ' + str(numMatch) + ' word matches found amongst these.'
  105.         #sys.stdout.flush()
  106.         return matches
  107.    
  108.     def generateNMatchLetterList(self, numMatch):
  109.         matchingCombinations = list()
  110.        
  111.         #this is extremely ugly, but it works and i'm too lazy to do it better
  112.         if numMatch == 1:
  113.             for i in range(0, 20):
  114.                 matchingLetters = self.generateMatchingLetters(numMatch, self.words[i])
  115.                 for letts in matchingLetters:
  116.                     matchingCombinations.append(letts)
  117.         if numMatch == 2:
  118.             for i in range(0, 20):
  119.                 for j in range(i+1, 20):
  120.                     matchingLetters = self.generateMatchingLetters(numMatch, self.words[i] + self.words[j])
  121.                     for letts in matchingLetters:
  122.                         matchingCombinations.append(letts)
  123.         elif numMatch == 3:
  124.             for i in range(0, 20):
  125.                 for j in range(i+1, 20):
  126.                     for k in range(j+1, 20):
  127.                         matchingLetters = self.generateMatchingLetters(numMatch, self.words[i] + self.words[j] + self.words[k])
  128.                         for letts in matchingLetters:
  129.                             matchingCombinations.append(letts)
  130.         elif numMatch == 4:
  131.             for i in range(0, 20):
  132.                 for j in range(i+1, 20):
  133.                     for k in range(j+1, 20):
  134.                         for l in range(k+1, 20):
  135.                             matchingLetters = self.generateMatchingLetters(numMatch, self.words[i] + self.words[j] + self.words[k] + self.words[l])
  136.                             for letts in matchingLetters:
  137.                                 matchingCombinations.append(letts)
  138.         elif numMatch == 5:
  139.             for i in range(0, 20):
  140.                 for j in range(i+1, 20):
  141.                     for k in range(j+1, 20):
  142.                         for l in range(k+1, 20):
  143.                             for m in range(l+1, 20):
  144.                                 matchingLetters = self.generateMatchingLetters(numMatch, self.words[i] + self.words[j] + self.words[k] + self.words[l] + self.words[m])
  145.                                 for letts in matchingLetters:
  146.                                     matchingCombinations.append(letts)
  147.         elif numMatch == 6:
  148.             for i in range(0, 20):
  149.                 for j in range(i+1, 20):
  150.                     for k in range(j+1, 20):
  151.                         for l in range(k+1, 20):
  152.                             for m in range(l+1, 20):
  153.                                 for n in range(m+1, 20):
  154.                                     matchingLetters = self.generateMatchingLetters(numMatch, self.words[i] + self.words[j] + self.words[k] + self.words[l] + self.words[m] + self.words[n])
  155.                                     for letts in matchingLetters:
  156.                                         matchingCombinations.append(letts)
  157.         elif numMatch == 7:
  158.             for i in range(0, 20):
  159.                 for j in range(i+1, 20):
  160.                     for k in range(j+1, 20):
  161.                         for l in range(k+1, 20):
  162.                             for m in range(l+1, 20):
  163.                                 for n in range(m+1, 20):
  164.                                     for o in range(n+1, 20):
  165.                                         matchingLetters = self.generateMatchingLetters(numMatch, self.words[i] + self.words[j] + self.words[k] + self.words[l] + self.words[m] + self.words[n] + self.words[o])
  166.                                         for letts in matchingLetters:
  167.                                             matchingCombinations.append(letts)
  168.         elif numMatch == 8:
  169.             for i in range(0, 20):
  170.                 for j in range(i+1, 20):
  171.                     for k in range(j+1, 20):
  172.                         for l in range(k+1, 20):
  173.                             for m in range(l+1, 20):
  174.                                 for n in range(m+1, 20):
  175.                                     for o in range(n+1, 20):
  176.                                         for p in range(o+1, 20):
  177.                                             matchingLetters = self.generateMatchingLetters(numMatch, self.words[i] + self.words[j] + self.words[k] + self.words[l] + self.words[m] + self.words[n] + self.words[o] + self.words[p])
  178.                                             for letts in matchingLetters:
  179.                                                 matchingCombinations.append(letts)
  180.         elif numMatch == 9:
  181.             for i in range(0, 20):
  182.                 for j in range(i+1, 20):
  183.                     for k in range(j+1, 20):
  184.                         for l in range(k+1, 20):
  185.                             for m in range(l+1, 20):
  186.                                 for n in range(m+1, 20):
  187.                                     for o in range(n+1, 20):
  188.                                         for p in range(o+1, 20):
  189.                                             for q in range(p+1, 20):
  190.                                                 matchingLetters = self.generateMatchingLetters(numMatch, self.words[i] + self.words[j] + self.words[k] + self.words[l] + self.words[m] + self.words[n] + self.words[o] + self.words[p] + self.words[q])
  191.                                                 for letts in matchingLetters:
  192.                                                     matchingCombinations.append(letts)
  193.         elif numMatch == 10:
  194.             for i in range(0, 20):
  195.                 for j in range(i+1, 20):
  196.                     for k in range(j+1, 20):
  197.                         for l in range(k+1, 20):
  198.                             for m in range(l+1, 20):
  199.                                 for n in range(m+1, 20):
  200.                                     for o in range(n+1, 20):
  201.                                         for p in range(o+1, 20):
  202.                                             for q in range(p+1, 20):
  203.                                                 for r in range(q+1, 20):
  204.                                                     matchingLetters = self.generateMatchingLetters(numMatch, self.words[i] + self.words[j] + self.words[k] + self.words[l] + self.words[m] + self.words[n] + self.words[o] + self.words[p] + self.words[q] + self.words[r])
  205.                                                     for letts in matchingLetters:
  206.                                                         matchingCombinations.append(letts)
  207.  
  208.         return matchingCombinations
  209.  
  210. # Main method, first arg input file, second number of words to find
  211. if __name__ == '__main__':
  212.     fInput = open(sys.argv[1], 'r')
  213.  
  214.     wordsToFind = int(sys.argv[2])
  215.  
  216.     for line in fInput:
  217.         print line
  218.         card = ScratchieCard(line)
  219.         print str(card.wordsFound()) + ' words found on card.'
  220.         sys.stdout.flush()
  221.         print str(len(card.generateNMatchLetterList(wordsToFind))) + ' ' + str(wordsToFind) + ' word letter combinations found for this card.'
  222.         sys.stdout.flush()
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top