Code Challenge 02 - Word Values Part II - A Simple Game - Review

Posted by PyBites on Fri 20 January 2017 in Challenges • 3 min read

It's Friday again so we review the code challenge of this week. It's never late to join, just fork our challenges repo and start coding.

A possible solution

See here for the complete solution.

Some learnings:

  • First we had the user interface like this:

    def input_word(draw):
        while True:
            word = input('Form a valid word: ').upper()
            if not set(word) < set(draw):
                print('One or more characters not in draw, try again')
                continue
            elif not word.lower() in DICTIONARY:
                print('Not a valid dictionary word, try again')
                continue
            return word
    

    But after learning about EAFP (easier to ask for forgiveness than permission) we thought it was more Pythonic to use exceptions. There was also a bug in the first check above (see comments, great learning!)

    def input_word(draw):
        while True:
            word = input('Form a valid word: ').upper()
            try:
                return _validation(word, draw)
            except ValueError as e:
                print(e)
                continue
    
    def _validation(word, draw):
        # thanks Durmus
        for char in word.upper():
            if char in draw:
                draw.remove(char)
            else:
            raise ValueError("{} is not a valid word!".format(word))
        if not word.lower() in DICTIONARY:
            raise ValueError('Not a valid dictionary word, try again')
        return word
    
  • random.sample makes it easy to get n number of random letters in one go:

    def draw_letters():
        return random.sample(POUCH, NUM_LETTERS)
    
  • get_possible_dict_words - the hardest part. To get all possible letter combinations from the letter draw, you need itertools.permutations, not combinations, because order does matter:

    >>> len(list(itertools.combinations(letters, 2)))
    21
    >>> len(list(itertools.permutations(letters, 2)))
    42
    

    See also our post on itertools. See also Durmus' comment / solution here for an alternative using combinations ...

  • First the helper generator to do the work:

    def _get_permutations_draw(draw):
        for i in range(1, 8):
            yield from list(itertools.permutations(draw, i))  # >= 3.3
    

    This creates all permutation of 1, 2, 3, 4, 5, 6, and 7 letters.

    We store all those in permutations and then use a set operation again to get all valid dictionary words:

    def get_possible_dict_words(draw):
        permutations = [''.join(word).lower() for word in _get_permutations_draw(draw)]
        return set(permutations) & set(DICTIONARY)
    

We use the calc_word_value and max_word_value methods from challenge 01 to calculate which word has the most value.

The rest is main() calling the methods and outputting (as was provided in the template).

Tests

We got a request in the comments for tests to verify the work. Good idea, they are here.

$ python test_game.py 
......
----------------------------------------------------------------------
Ran 6 tests in 0.056s

OK

Its fun (addictive?) to play :)

[bbelderb@macbook 02 (master)]$ python game.py 
Letters drawn: T, I, I, G, T, T, L
Form a valid word: tig
Word chosen: TIG (value: 4)
Optimal word possible: gilt (value: 5)
You scored: 80.0
[bbelderb@macbook 02 (master)]$ python game.py 
Letters drawn: O, N, V, R, A, Z, H
Form a valid word: zar
Word chosen: ZAR (value: 12)
Optimal word possible: zonar (value: 14)
You scored: 85.7
[bbelderb@macbook 02 (master)]$ python game.py 
Letters drawn: E, P, A, E, I, O, A
Form a valid word: pi
Word chosen: PI (value: 4)
Optimal word possible: apio (value: 6)
You scored: 66.7
[bbelderb@macbook 02 (master)]$ python game.py 
Letters drawn: B, R, C, O, O, E, O
Form a valid word: broc
Not a valid dictionary word, try again
Form a valid word: f
One or more characters not in draw, try again
Form a valid word: bore
Word chosen: BORE (value: 6)
Optimal word possible: boce (value: 8)
You scored: 75.0

Any issues or feedback?

What did you learn this challenge? Feel free to share you code in the comments below.

How are you experiencing these challenges? You like the format? What can we do differently and/or better?

next(challenges)

Monday we will be back with a new challenge, stay tuned ...

Again to start coding fork our challenges repo or sync it if you already forked it.

>>> next(PyBites)

Get our 'Become a Better Python Developer' cheat sheet sent straight to your inbox by signing up for our Newsletter: