Python 100 project #44: PyBites “Code Challenge 02 – Word Values Part II – A Simple Game”

This is day 02 for PyBites Code Challenge to make a simple scribble game. Make a word with max value from given characters.

 

Output:

$ python3 game-help.py 
Letters drawn: p, z, i, o, t, o, a
Form a valid word: pot
Word chosen: pot (value: 5)
Optimal word possible: topaz (value: 16)
You scored: 31.2

 

Here is the code:

#!python3
# Code Challenge 02 - Word Values Part II - a simple game
# http://pybit.es/codechallenge02.html

from collections import Counter
import itertools
import random

from data import DICTIONARY, LETTER_SCORES, POUCH

NUM_LETTERS = 7


def draw_letters():
    """Pick NUM_LETTERS letters randomly. Hint: use stdlib random"""
    return [ c.lower() for c in random.sample(POUCH, NUM_LETTERS) ]


def input_word(draw):
    """Ask player for a word and validate against draw.
    Use _validation(word, draw) helper."""
    while True:
        word = input("Form a valid word: ")
        if _validation(word, draw):
            break
    return word


def _validation(word, draw):
    """Validations: 1) only use letters of draw, 2) valid dictionary word"""
    draw_counter = Counter(draw)
    draw_counter.subtract(Counter(word))

    if all(val >= 0 for val in draw_counter.values()):
        if word in DICTIONARY:
            return True
    return False


# From challenge 01:
def calc_word_value(word):
    """Calc a given word value based on Scrabble LETTER_SCORES mapping"""
    return sum(LETTER_SCORES.get(char.upper(), 0) for char in word)


# Below 2 functions pass through the same 'draw' argument (smell?).
# Maybe you want to abstract this into a class?
# get_possible_dict_words and _get_permutations_draw would be instance methods.
# 'draw' would be set in the class constructor (__init__).
def get_possible_dict_words(draw):
    """Get all possible words from draw which are valid dictionary words.
    Use the _get_permutations_draw helper and DICTIONARY constant"""
    words = []
    for word_list in _get_permutations_draw(draw):
        word = ''.join(word_list)
        if word in DICTIONARY:
            words.append(word)
    return words


def _get_permutations_draw(draw):
    """Helper for get_possible_dict_words to get all permutations of draw letters.
    Hint: use itertools.permutations"""
    for l in range(1, NUM_LETTERS +1):
        for permutation in itertools.permutations(draw, l):
            yield permutation


# From challenge 01:
def max_word_value(words):
    """Calc the max value of a collection of words"""
    return max(words, key=calc_word_value)


def main():
    """Main game interface calling the previously defined methods"""
    draw = draw_letters()
    print('Letters drawn: {}'.format(', '.join(draw)))

    word = input_word(draw)
    word_score = calc_word_value(word)
    print('Word chosen: {} (value: {})'.format(word, word_score))

    possible_words = get_possible_dict_words(draw)

    max_word = max_word_value(possible_words)
    max_word_score = calc_word_value(max_word)
    print('Optimal word possible: {} (value: {})'.format(
        max_word, max_word_score))

    game_score = word_score / max_word_score * 100
    print('You scored: {:.1f}'.format(game_score))


if __name__ == "__main__":
    main()