Next / Previous / Contents / Shipman's homepage

23. Puzzle.__matchLengths(): Does the word list match the slot set?

kkck
# - - -   P u z z l e . _ _ m a t c h L e n g t h s

    def __matchLengths ( self ):
        '''See if the word lengths match the slot lengths.

          [ (self.__slotMap contains a set of slots) and
            (self.__wordMap contains a set of words) ->
              if (the counts of slots of each length in self.__slotMap
              do not exactly match the counts of words of each length
              in self.__wordBank) ->
                raise SyntaxError
              else -> I ]
        '''

In a properly structured puzzle, there are exactly as many slots as words; see Section 63, “WordBank.__len__(): How many total words?”.

kkck
        #-- 1 --
        # [ if the number of words in self is the same as the 
        #   number of slots in self ->
        #     I
        #   else -> raise SyntaxError ]
        if len(self.__slotMap) != len(self.__wordBank):
            raise SyntaxError ( "This puzzle has %d slots but "
                "%d words to go in them." %
                (len(self.__slotMap), len(self.__wordBank)) )

Furthermore, for each different word length in the word list, there must be exactly as many slots of that length as words of that length. We'll start this by counting the slots of each length. The expression “defaultdict(int)” returns a new dictionary in which new entries will automatically default to 0. See http://docs.python.org/2/library/collections.html#collections.defaultdict for this container; also see Section 20, “Puzzle.__genSlots(): Detect slots in a row or column” for the generator that visits every slot.

kkck
        #-- 2 --
        # [ countByLen  :=  a dictionary whose keys are the
        #       unique lengths of slots in self, and each
        #       corresponding value is the number of slots in
        #       self that have that length ]
        countByLen = defaultdict(int)
        for slot in self.__slotMap.values():
            countByLen[len(slot)] += 1

See Section 60, “class WordBank: The word list and puzzle state” for the .maxLen attribute that gives the maximum word length, and the Section 64, “WordBank.wordsOfLen(): How many words have a given length?” for the method that returns the number of words of a given length.

kkck
        #-- 3 --
        # [ if the counts of slots of each length in countByLen
        #   correspond exactly to the counts of words of each
        #   length in self.__wordBank ->
        #     I
        #   else -> raise SyntaxError ]
        for length in range(2, 1+self.__wordBank.maxLen):
            nWords = self.__wordBank.wordsOfLen ( length )
            nSlots = countByLen[length]
            if nWords != nSlots:
                raise SyntaxError ( "There are %d words of length %d, "
                    "but there are %d slots of that length." %
                    (nWords, length, nSlots) )