コード例 #1
0
    def __init__(self, word, word_set=None):
        # Word is handled the same way, but word_set needs to be a WordSetHelper.
        super(WordScrabbleHelper, self).__init__(word, None)

        # If a word set was given, use it. Else create a new one.
        if word_set is not None:
            if not isinstance(word_set, WordSet):
                raise TypeError("WordSet expected.")
            # If a WordSet was passed in, upgrade it.
            if not isinstance(word_set, WordSetHelper):
                self.word_set = WordSetHelper(word_set())
            else:
                self.word_set = word_set  
        else:
            self.word_set = WordSet()

        # The first two searches can be skipped, since we're interested
        # in suggestions that require tiles we don't have.
        self.word_set.search_order = self.word_set.search_order[2:]
コード例 #2
0
class WordScrabbleHelper(WordScrabbleCalculator):
    """
        A class combining the WordScrabbleCalculator and WordCorrector
        to provide improved assistance to Scrabble players.
        Gives a list of possible words, ordered by their Scrabble scores,
        as well as some suggestions for words to try go for, also ordered
        the same way.
    """
    def __init__(self, word, word_set=None):
        # Word is handled the same way, but word_set needs to be a WordSetHelper.
        super(WordScrabbleHelper, self).__init__(word, None)

        # If a word set was given, use it. Else create a new one.
        if word_set is not None:
            if not isinstance(word_set, WordSet):
                raise TypeError("WordSet expected.")
            # If a WordSet was passed in, upgrade it.
            if not isinstance(word_set, WordSetHelper):
                self.word_set = WordSetHelper(word_set())
            else:
                self.word_set = word_set  
        else:
            self.word_set = WordSet()

        # The first two searches can be skipped, since we're interested
        # in suggestions that require tiles we don't have.
        self.word_set.search_order = self.word_set.search_order[2:]
    
    def __repr__(self):
        print_string = super(WordScrabbleHelper, self).__repr__()
        
        new_suggestions = self.get_alternative_suggestions(5)
        if new_suggestions:
            print_suggestions = '\n'.join(self._get_suggestion_description(suggestion) 
                                            for suggestion in new_suggestions)
            print_string += "\n\nPerhaps you should try going for: \n%s" % (print_suggestions)
        else:
            print_string += "\nNo idea what to go for."

        return print_string

    def get_alternative_suggestions(self, n):
        """
            Gets a list of words that are worth attempting to get,
            based on the current word or set of letters.
        """
        # Works best on existing words (the alternatives were originally meant as spelling correctors).
        # If there are no possible words, use the tiles as they are.
        possible_words = self.get_possible_words() or [self.word]

        # There are many alternative words, so use a generator.
        alternative_words = (alternative for word in possible_words
                                          for alternative in self.word_set.get_alternative_words(word))
 
        def limiter(iterator, limit):
            """A limiter function to stop the generator after a given number of iterations. 
                I love Python."""
            for i in xrange(limit):
                yield next(iterator)
            raise StopIteration

        # Suggestions are only valid if they aren't possible, and are within the word length limits.
        suggestion_valid = lambda x: (x not in possible_words) and (1 < len(x) <= 7)
        # Put twice the target number in the limiter, in case there are invalid suggestions.
        suggestions = [word for word in limiter(alternative_words, 10*n) if suggestion_valid(word)]

        # Return suggestions, ordered by their highest possible Scrabble score value.
        sorter = lambda x: self._get_suggestion_score(x)[-1]
        return sorted(suggestions, key=sorter, reverse=True)[:n]

    def _get_suggestion_description(self, suggestion):
        """
            Get a readable description of the given suggestion.
        """
        # Get information about the suggestion
        number_of_blanks = self.word.count(' ')
        letters_needed = self._get_letters_needed(suggestion)
        score = self._get_suggestion_score(suggestion)
        
        description = "- %s. You need" % suggestion

        # Print letters needed (only a subset of these is required if there are any blanks).
        if number_of_blanks:
            description += " %d of" % (len(letters_needed) - number_of_blanks)
        description += " these letter(s): [%s]" % (','.join(letters_needed))

        # Print the score of the word (might be a range if there are any blanks).
        description += ", for a total score of %d" % (score[0])
        if (len(score) > 1) and (score[0] != score[-1]):
            description += " to %d" % (score[-1])

        return description

    def _get_letters_needed(self, suggestion):
        """
            Get the letters required to make a suggested word.
            A Counter is used to preserve words containing more than 
            one of the same letter.
        """
        return list((Counter(suggestion) - Counter(self.word)).elements())

    def _get_suggestion_score(self, suggestion):
        """
            Get the score of a word suggestion. If the current
            word contains a blank, this will be a range.
        """
        number_of_blanks = self.word.count(' ')
        if not number_of_blanks:
            return (self._get_score(suggestion),)
        else:
            # Get the letters (and number thereof) required to make the suggestion.
            letters_needed = self._get_letters_needed(suggestion)
            # Subtract the number of blanks from the number of letters needed.
            number_of_letters_needed = len(letters_needed) - number_of_blanks

            # Sort the letters by their Scrabble value.
            values = sorted(letters_needed, key=lambda x: self.letter_values[x])

            # Get the least and most valuable letter combos (depending on how many are needed).
            least_valuable = values[:number_of_letters_needed]
            most_valuable = values[-number_of_letters_needed:]

            # Calculate the resulting scores, if these numbered were added.
            score_without = lambda x: self._get_score(suggestion) - self._get_score(''.join(x))
            lower_score, highest_score = score_without(most_valuable), score_without(least_valuable)

            # Return the result as a tuple.
            return (lower_score, highest_score)