import random from string import ascii_lowercase from flask import Flask, render_template, session, request, redirect, url_for, flash import sensitive from lib import cat_words, ROUNDS, WORD_LENGTH from play import build_non_letter_hint, build_letter_hint app = Flask(__name__) app.config['SECRET_KEY'] = sensitive.SECRET_KEY WORDS = list(cat_words()) NUM_GAMES = len(WORDS) - 1 GUESS_SPLITTER = '|' RANDOM_GAME_ID = -1 KEY_WORD = 'word' KEY_GAME_ID = 'game_id' KEY_GUESSES = 'guesses' KEY_GUESS = 'guess' KEY_STATE = 'state' STATE_PLAYING = 'PLAYING' STATE_WIN = 'WIN' STATE_LOSE = 'LOSE' COLOR_GREY = 'grey' COLOR_GREEN = 'green' COLOR_YELLOW = 'yellow' ERROR_GAME_ID_RANGE = "game_id must be between 0 and {}".format(NUM_GAMES) ERROR_NEED_WORD = 'Need a word' ERROR_GUESS_LENGTH = "Need {} letters.".format(WORD_LENGTH) ERROR_WORD_NOT_IN_LIST = 'Not in word list: {}' ERROR_NO_GAME = 'No game started.' def verify_word_length(word): return len(word) == WORD_LENGTH and all([x in ascii_lowercase for x in word]) def init_game(game_id, word): session[KEY_GAME_ID] = game_id session[KEY_WORD] = word session[KEY_GUESSES] = '' session[KEY_STATE] = STATE_PLAYING def resolve_guesses(): word = session[KEY_WORD] guesses = session.get(KEY_GUESSES, '').split(GUESS_SPLITTER) guesses_colored = [] for guess in guesses: non_letters_hints = build_non_letter_hint(guess, word) letters_hints = build_letter_hint(guess, word) colored_guess = [] for pos, letter in enumerate(guess): if letter in non_letters_hints: color = COLOR_GREY elif letters_hints[pos] == letter.upper(): color = COLOR_GREEN elif letters_hints[pos] == letter: color = COLOR_YELLOW else: color = COLOR_GREY colored_guess.append((letter, color)) guesses_colored.append(colored_guess) return guesses_colored def build_game_state(): guesses_colored = resolve_guesses() return render_template('game.html', guesses=guesses_colored, state_playing=session[KEY_STATE] == STATE_PLAYING, WORD_LENGTH=WORD_LENGTH, KEY_GUESS=KEY_GUESS, state=session[KEY_STATE]) # ############################################################################# # ROUTES # ############################################################################# @app.route('/') def home(): num_games = NUM_GAMES return render_template('home.html', num_games=num_games, KEY_GAME_ID=KEY_GAME_ID) @app.route('/find/') def find_word(word): if not verify_word_length(word): flash(ERROR_GUESS_LENGTH) return redirect(url_for('home')) if word not in WORDS: flash(ERROR_WORD_NOT_IN_LIST.format(word)) return redirect(url_for('home')) game_id = WORDS.index(word) return redirect(url_for('init_deterministic_game_id', game_id=game_id)) @app.route('/init/random') def init_random_game(): word = random.choice(WORDS) init_game(RANDOM_GAME_ID, word) return redirect(url_for('random_game')) @app.route('/init/deterministic', methods=['post']) def init_deterministic_game(): game_id = request.form.get(KEY_GAME_ID) return redirect(url_for('init_deterministic_game_id', game_id=game_id)) @app.route('/init/deterministic/') def init_deterministic_game_id(game_id): if not 0 <= int(game_id) <= NUM_GAMES: flash(ERROR_GAME_ID_RANGE) return redirect(url_for('home')) word = WORDS[int(game_id)] init_game(game_id, word) return redirect(url_for('deterministic_game_id', game_id=game_id)) @app.route('/random') def random_game(): if KEY_WORD not in session or KEY_STATE not in session: return redirect(url_for('init_random_game')) return build_game_state() @app.route('/deterministic/') def deterministic_game_id(game_id): if (KEY_WORD not in session or KEY_STATE not in session or (KEY_GAME_ID in session and session[KEY_GAME_ID] != game_id)): return redirect(url_for('init_deterministic_game_id', game_id=game_id)) return build_game_state() @app.route('/guess', methods=['post']) def make_guess(): if KEY_WORD not in session or KEY_GUESSES not in session: flash(ERROR_NEED_WORD) return redirect(url_for('home')) guess = request.form.get(KEY_GUESS) guess = guess.lower() if not verify_word_length(guess): flash(ERROR_GUESS_LENGTH) return build_game_state() if guess not in WORDS: flash(ERROR_WORD_NOT_IN_LIST.format(guess)) return build_game_state() word = session[KEY_WORD] round_i = len(session[KEY_GUESSES].split(GUESS_SPLITTER)) if round_i >= ROUNDS: session[KEY_STATE] = STATE_LOSE if guess == word: session[KEY_STATE] = STATE_WIN session[KEY_GUESSES] += '{}{}'.format(guess, GUESS_SPLITTER) if KEY_GAME_ID not in session: flash(ERROR_NO_GAME) return redirect(url_for('home')) game_id = session[KEY_GAME_ID] if game_id == RANDOM_GAME_ID: return redirect(url_for('random_game')) return redirect(url_for('deterministic_game_id', game_id=game_id)) def main(): app.run(debug=True) if __name__ == "__main__": main()