Goals of this Assignment
Use the Function Design Recipe to plan, implement, and test functions.
Write function bodies using variables, numeric types, strings, and conditional statements. (You can do
this whole assignment with only the concepts from Weeks 1, 2, and 3 of the course.)
Learn to use Python 3, Wing 101, provided starter code, a checker module, and other tools.
Phrase Puzzler
In this assignment, you'll be writing a Phrase Puzzler game. To see how the game is played, please
watch the demo below.
The video demonstrates playing the one-player version of the game, but your code will eventually also
have a two-player human vs. human version and also a human vs. computer version.
Starter code
For this assignment, we are giving you some files, including Python starter code files. Please
download the Assignment 1 Files and extract the zip archive.
There are three starter code Python files, two sample text input files, and a Python program that helps
you check (not fully test!) your solutions for Python style violations:
puzzler_functions.py
This file contains some code that sets up your use of constants form constants.py, a helper function
for you to use (see the table of functions to implement below), as well as the header and the complete
docstring (but not body) for the first function you are to write. Your job is to complete this file.
constants.py
This file contains some useful constants that you should use in your solution. You will not modify this
file.
puzzler.py
This is the main program. You will not modify this file. Rather, you will run this file to play the Phrase
Puzzler game. Please note that puzzler.py depends on functions you will write in puzzler_functions.py,
so this program won't run properly until you've implemented the functions.
puzzles_small.txt and puzzles.txt
Each of these files contains puzzle phrases used by puzzler.py to select a puzzle for a game and also
to provide a pool of phrases that the computer player "knows". You may want to use puzzles_small.txt
when you are in the beginning of developing and debugging your solution, and puzzles.txt to play the
game.
a1_checker.py
This is a checker program that you should use to check your code. See below for more information
about a1_checker.py.
Constants
Constants are special variables whose values should not change once assigned. A different naming
convention (uppercase pothole) is used for constants, so that programmers know to not change their
values. For example, in the starter code, the constant CONSONANT_POINTS is assigned the value 1
at the beginning of the module and the value of CONSONANT_POINTS should never change in your
code. When writing your code, if you need to use the number of points awarded for a guessed
consonant, you should use CONSONANT_POINTS. The same goes for the other constant values.
Using constants simplifies code modifications and improves readability and changeability. For
example, if we later decide to use a different character to represent a hidden index in our puzzle, we
would only have to make a change in one place (the HIDDEN assignment statement), rather than
throughout the program. This also makes our code more readable — whether we use '^' or any other
character to represent a hidden index, we write our code using the constant HIDDEN so it is clear to
the reader what we mean.
More about the Phrase Puzzler program:
Two strings are used to represent information about a Phrase Puzzler puzzle:
puzzle is made up of alphabetic and non-alphabetic characters (e.g., spaces, punctuation, and digits).
An example puzzle string is 'e-mail inbox'.
view is the current view of the puzzle as seen by the players. In it, the alphabetic characters are either
displayed (if they have been revealed) or hidden (using a special character (a caret '^' by default), if
they have not yet been revealed). Non-alphabetic characters (spaces, punctuation, and digits) are
always displayed. For example, at the beginning of the game, the view string for the puzzle above
would be (with a caret to represent a hidden character): '^-^^^^ ^^^^^'.
As the game progresses and players guess letters to be revealed, the view is updated. Continuing
with the example above, if the player guesses "m", the view becomes '^-m^^^ ^^^^^' and then if "i" is
guessed, it becomes '^-m^i^ i^^^^'.
There are three types of games that your program will play: human, human vs human, and human vs
computer. We will use the constants HUMAN, HUMAN_HUMAN, and HUMAN_COMPUTER
respectively, to represent the type of game being played.
When a player guesses a consonant, each occurrence of that consonant in the puzzle earns a certain
number points for that player: the value of the constant CONSONANT_POINTS. If a player correctly
guesses a consonant, they play again in the next turn. If the guess is incorrect, the turn goes to the
next player (in a two-player game).
Players have to pay to guess a vowel. The cost does not depend on the number of occurrences of the
vowel, and is always equal to the value of the constant VOWEL_PRICE. Thus, guessing a vowel
decreases the player's points. A player is not allowed to guess a vowel if they do not have sufficient
points to pay for it. If the vowel occurs in the puzzle, then the player plays again. Otherwise, the turn
goes to the next player (in a two-player game).
When a player solves the puzzle, CONSONANT_BONUS bonus points are added to their score for
each occurrence of a consonant that is still HIDDEN.
All puzzles are always lower-case. That is, the puzzles will not contain any upper-case letters.
You should read the file constants.py carefully to understand the purpose of each defined constant.
You must use these constants in your code and not the literal values. For example, you must use
HIDDEN instead of '^'.
What to do
In the starter code file puzzler_functions.py, complete the following function definitions. Use the
Function Design Recipe that you have been learning in this course. We have included the type
contracts in the following table; please read through the table to understand how the functions will be
used.
We will be evaluating your docstrings in addition to your code. Please include two examples in your
docstrings. You will need to paraphrase the full descriptions of the functions to get an appropriate
docstring description.
Functions to write for A1
Function name:
(Parameter types) -> Return type Full Description (paraphrase to get a proper docstring description)
is_win:
(str, str) -> bool
The first parameter represents the puzzle phrase. The second parameter represents the current view.
The function should return True if and only if they represent a winning combination, i.e., they are the
same.
is_game_over:
(str, str, str) -> bool
The first parameter represents the puzzle phrase. The second parameter represents the current view.
The third parameter represents the next move. The function should return True if and only if this is a
game-over combination, i.e., either this is a winning combination or the move is "quit".
is_one_player_game:
(str) -> bool
The parameter represents the type of game being played: human, human-human, or humancomputer. The function should return True if and only if this is a one-player game.
is_human:
(str, str) -> bool
The first parameter represents the current player — the player whose turn it is — player one or player
two. The second parameter represents the type of game being played: human, human-human, or
human-computer. The function should return True if and only if the current player is a human.
current_player_score:
(int, int, str) -> int
The first parameter represents the score of player one. The second parameter represents the score of
player two. The third parameter represents the current player — the player whose turn it is. The
function should return the score of the current player.
is_bonus_letter:
(str, str, str) -> bool
The first parameter represents a letter. The second parameter represents the phrase puzzle. The third
parameter represents the current view. The function should return True if and only if the first argument
is a bonus letter. Recall that bonus letters are consonants that are currently hidden.
update_char_view:
(str, str, int, str) -> str
The first parameter represents the phrase puzzle. The second parameter represents the current view.
The third parameter represents the index of a character whose view we are updating. The fourth
parameter represents the guess for that character. The function returns what the updated view of the
character should be: if the guess is correct, the character should be revealed; otherwise, the view
should not change.
calculate_score:
(int, int, str) -> int
The first parameter represents the current score. The second parameter represents the number of
occurrences revealed as a result of the player's current move. The third parameter represents the
current move: guess a consonant or buy a vowel. The function should return the new updated score.
Recall that guessing a consonant increases the score and the increase depends on the number of
letters guessed, and that buying a vowel decreases the score by a fixed amount.
next_player:
(str, int, str) -> str
The first parameter represents the current player — the player whose turn it is — player one or player
two. The second parameter represents the number of occurrences revealed by the current player as a
result of the player's latest move. The third parameter represents the type of the game being played:
human, human-human, or human-computer. The function should return the player to play in the next
turn — player one or player two. Recall that if the current player correctly guesses a consonant or
buys a vowel that occurs in the puzzle, then the player plays again. If the player guesses incorrectly,
the other player plays in the next turn. Of course, in a one-player game the player does not change.
is_hidden:
(int, str, str) -> bool
The first parameter represents the index of a character. The second parameter represents the phrase
puzzle. The third parameter represents the current view. The function should return True if and only if
the character at the given index is currently hidden in the game. Note that a hidden character cannot
be revealed at any location in the view.
computer_chooses_solve:
(str, str, str) -> bool
This function is used to decide what to do when it is the computer's turn to play. The first parameter
represents the current view. The second parameter represents the difficulty of the current game: easy
or hard. The third parameter represents the consonants that have not yet been guessed in this game.
The function should return True if and only if the computer should decide to solve the puzzle.
You can assume this function is only called in a human-computer game.
The strategy we will use for the computer is as follows: If difficulty is hard, the computer chooses to
solve if at least half of the letters have been revealed or if there are no more consonants to guess. If
difficulty is easy, the computer chooses to solve if there are no more consonants to choose from.
Otherwise, the computer does not choose to solve. We have provided a helper function half_revealed
that you want to use in this function.
erase:
(str, int) -> str
The first parameter represents a string of letters. The second parameter represents an index. The
function should return the given letters with the character at the given index removed, if the index is
between 0 and the index of the last character in the string. Otherwise, it should return the original
string of letters unchanged.
Using Constants
As we discuss in section Constants above, your code should make use of the provided constants. If
the value of one of those constants were changed, and your program rerun, your functions should
work with those new values.
For example, if CONSONANT_POINTS were changed, then your functions should work according to
the new number of bonus points that should be earned for guessing a consonant. Using constants in
your code means that this happens automatically.
Your docstring examples should reflect the given values of the constants in the provided starter code,
and do not need to change.
No Input or Output
Your puzzler_functions.py file should contain the starter code, plus the function definitions specified
above. puzzler_functions.py must not include any calls to the print and input functions. Do not add any
import statements. Also, do not include any function calls or other code outside of the function
definitions.
A1 Checker
We are providing a checker module (a1_checker.py) that tests two things:
whether your code follows the Python style guidelines, and
whether your functions are named correctly, have the correct number of parameters, and return the
correct types.
To run the checker, open a1_checker.py and run it. Note: the checker file should be in the same
directory as your puzzler_functions.py, as provided in the starter code zip file. Here is a demo of the
checker being run. Be sure to scroll up to the top and read all messages!
If the checker passes for both style and types:
Your code follows the style guidelines.
Your function names, number of parameters, and return types match the assignment specification.
This does not mean that your code works correctly in all situations. We will run a different set of tests
on your code once you hand it in, so be sure to thoroughly test your code yourself before submitting.
If the checker fails, carefully read the message provided:
It may have failed because your code did not follow the style guidelines. Review the error
description(s) and fix the code style. Please see the PyTA documentation for more information about
errors.
It may have failed because:
you are missing one or more function,
one or more of your functions is misnamed,
one or more of your functions has the incorrect number or type of parameters, or
one of more of your function return types does not match the assignment specification.
Read the error message to identify the problematic function, review the function specification in the
handout, and fix your code.
Make sure the checker passes before submitting.
Marking
These are the aspects of your work that may be marked for A1:
Coding style (20%):
Make sure that you follow Python style guidelines that we have introduced and the Python coding
conventions that we have been using throughout the semester. Although we don't provide an
exhaustive list of style rules, the checker tests for style are complete, so if your code passes the
checker, then it will earn full marks for coding style with one exception: docstrings may be evaluated
separately. For each occurrence of a PyTA error, one mark (out of 20) deduction will be applied. For
example, if a C0301 (line-too-long) error occurs 3 times, then 3 marks will be deducted.
All functions, including helper functions, should have complete docstrings including preconditions
when you think they are necessary.
Correctness (80%):
Your functions should perform as specified. Correctness, as measured by our tests, will count for the
largest single portion of your marks. Once your assignment is submitted, we will run additional tests
not provided in the checker. Passing the checker does not mean that your code will earn full marks for
correctness.
What to Hand In
The very last thing you do before submitting should be to run the checker program one last time.
Otherwise, you could make a small error in your final changes before submitting that causes your
code to receive zero for correctness.
Submit puzzler_functions.py on MarkUs by following the instructions on the course website.
Remember that spelling of filenames, including case, counts: your file must be named exactly as
above.