## CS 150 - Test Project 2 - Memory

#### Due: Monday 5/15 by 11:59pm

Like the first test project, this test project is an assignment that you complete on your own, without the help of others. It is a take-home exam, and will count for 10% of your final grade. You may use the textbook, your notes, your previous assignments, the notes and examples on the course web page and the Python library documentation (linked on the course web page), but use of any other source is not allowed. You may not discuss these problems with anyone except the course instructor. You may only ask the tutors for help with hardware problems or difficulties in retrieving or submitting your program.

To be extra clear, you may not work with, discuss, or in any way collaborate with anyone else.

You are encouraged to reuse code from your assignments or our class examples. Partial credit will be awarded, so try to get as far as you can. If you are completely stuck, come see me. While I cannot help you solve the test project itself, I may be able to suggest general problem-solving strategies, help with conceptual difficulties about Python, and/or direct you to relevant examples from class.

### Memory

For this test project you will be implementing a text-based version of the game "Memory" (aka concentration), where the user has to find matching pairs of cards. See the Wikipedia page on the game for more information.

When the game starts, all of the cards are face down. In our version there are 16 cards, each indicated by a numbered square. The cards are laid out in four rows with four cards each:

```1  2  3  4
5  6  7  8
9  10 11 12
13 14 15 16
```
"Underneath" each of these numbers is a letter. The user does not see these, but the program will keep track of them. For example, the board above may have the following letters underneath:
```G  D  B  F
H  B  C  D
A  A  E  E
F  H  G  C
```
The game proceeds by having the user pick two squares to look under by entering the numbers of the squares separated by a space.
```1  2  3  4
5  6  7  8
9  10 11 12
13 14 15 16
Guess two squares:
```
For example, to view 1 and 2 the user would type "1 2"; to view 7 and 15 the user would type "7 15". The two cards that the user specified are then shown. For example, if the user entered "7 15" one would see:
```1  2  3  4
5  6  C  8
9  10 11 12
13 14 G  16
```
If the user's selected cards do NOT match, like 7 (C) and 15 (G), then the cards are displayed for 2 seconds and then turned back over leaving just the numbers. The user is then prompted for another choice:
```1  2  3  4
5  6  7  8
9  10 11 12
13 14 15 16
Guess two squares:
```
If the user selects two that do match, for example 2 and 8 (both D) then those two are flipped over and they stay flipped over for the rest of the game. The user is then immediately prompted to enter an additional pair.
```1  D  3  4
5  6  7  D
9  10 11 12
13 14 15 16
Guess two squares:
```

If the user enters invalid numbers (outside the range 1-16, or cards that have already been turned over), the program complains and asks again:

```Guess two squares: 1 33
Invalid number(s).
Guess two squares:
```
The game ends once the user finds all matching pairs. When the game ends, the text "You win!" is displayed along with the finished board, the number of moves, and the amount of time it took the player to solve the game. For example:
```You win!
G  D  B  F
H  B  C  D
A  A  E  E
F  H  G  C
It took you 15 guesses and 99 seconds.
```

### Demo

To help you understand how the game works, I have made a demo version available on our lab machines. To run it, log into one of the desktops in MBH 505 and type
```~schar/cs150/tp2/memory
```
You can also run the demo program from your Mac laptop by connecting to the CS department server "basin". Open a terminal and type
```ssh YourUserName@basin
```

From a Windows laptop, you can connect to basin using the program Putty. Don't use the package installer, just download putty.exe directly, and save it to your desktop. Then, double-click on putty.exe, type basin in the Host Name box, and click on Open. Enter your user name and password to log in.

Once you're logged in from either Mac or PC, type the same command as above to run the game:

```~schar/cs150/tp2/memory
```

### Requirements

• The displayed board must look exactly like the board above with the columns lined up correctly.
• It must display the flipped over entries for 2 seconds if the guess is incorrect. If the guess is correct it immediately shows the updated board and prompts for another guess.
• The game should stop/finish when all of the entries have been correctly guessed and are flipped over. You should then display the amount of time it took and the total number of valid guesses that the user made. A valid guess is any guess where the cards are flipped over, both when they match and don't match.
• The underside of the entries will be pairs of the letters 'A' through 'H'. Each time the game is played you should get a different configuration of the letters.

2. When run, your program should start playing the game automatically. If your module is imported, however, the game will not start playing.

3. You can assume that the user enters two numbers separated by a space. However, you must check that the user input is valid, specifically:
• that the numbers are valid entries on the board (1-16)
• that the entries corresponding to the numbers entered have not already been correctly guessed (i.e., flipped over)
• that the two numbers are different (e.g., "3 3" is NOT valid)

4. Your program must make use of appropriate data structures for storing the game state.

5. You should define constants for the number of rows and columns at the top of your program, and use these constants throughout.
If you follow the above requirements (and also get full credit for style and documentation), you will receive 43 / 45 points. For the remaining two points, your program should easily generalize to other board sizes, solely by changing your two constants to specify a different number of rows and columns. This means you will need to use loops for initializing and printing the board. Any even number of squares should be supported, up to 50 squares (25 pairs of letters), with no more than 10 rows or 10 columns. For instance, if 5 rows and 8 columns are specified, the game should use 20 pairs of letters ('A' through 'T').

### Implementation thoughts

As always, I strongly suggest an incremental approach to developing this program. Before you start programming, develop a design that describes what functions you will need, the parameters each function should take and how each function will work. You won't turn this in, but it will save you a lot of time if you think through the design of the program first. As you start to code, work incrementally: pick one function and get it working before moving on. Read through this entire section before you start the program since I give some hints about implementing certain parts.

### Representation

As you're thinking about how you will write your program, think about what information you need to store and update as the game progresses and how you are going to represent this information. For example, for hangman we had a number of pieces of information:
• The word the user was trying to guess
• The current version of the guessed word
• The letters that had been guessed so far
• The number of guesses that the user had left
What information do we need to keep track of for this game? As you think about this, think about how you will store this data (as a string, a list, a set, a dictionary, etc.). You should choose an option that is convenient and efficient. You will be graded based on your choices (for example, if you use strings for everything you will not get full credit).

### Game flow

Besides the representation, also think about the general flow of the game. There will be some sort of loop where you repeat some steps over and over as long as the game is in session. Think about what will happen during one "turn":
• the current version of the board should be displayed
• get the guess from the user
• check the validity of the user's guess
• check whether the guess is a match or not and act accordingly
This is a rough skeleton of the flow of the game. Flesh out the details a bit more before you start coding and it will make your life much easier down the road.

### One route

There are many ways of implementing this and getting it working. Here is one approach:
1. Pick your board representation and figure out a way to generate a random board configuration. For each number, the board will need to keep track of which letters are associated with each letter. Hint: the random class has a function called shuffle that takes any list and randomly shuffles all of the elements in the list. For example, try shuffling ['A', 'A', 'B', 'B'].

2. Decide how you're going to keep track of which numbers on the board have been correctly guessed. Write some code to display the board. The board should be printed out as 4 lines. If a square/number has not been correctly guessed, then the number will be printed. If the square/number has been correctly guessed, then the letter will be printed. To check that you have this working correctly, manually add numbers that have been "correctly guessed" and make sure that the board is displayed correctly by your code.

3. Get the input from the user and then regardless of whether they match or not, show the updated version of the board (i.e., with the letters flipped over the selected numbers), then revert back to the original board after the 2 second pause. Hints:
• In the time module there is a function called sleep that takes the number of seconds as a parameter and the program stops executing for that number of seconds.
• You cannot "delete" text that you've already printed on the screen. However, one way to make it look like the text has been deleted is to print out a number of blank lines (e.g., 100). This causes anything that was on the screen to disappear. If you do this every time before you display the board, it will appear to the user like the board is simply being updated.
• There are many ways of updating the board to reflect the current guess and then undoing them if the guess is not right. Think about the best approach for your implementation.

4. Update the functionality to differentiate when the pairs match vs. when the pairs don't match. To help you when you're debugging, you can print out what the "underneath" letters are, though make sure to remove this printing before you submit.

5. Add checking to make sure that the user enters valid numbers. You may assume that the user enters two integers separated by a space. You must however check to see if they are valid board spaces and whether or not they have already been selected. As long as either of these cases applies, then you should prompt the user to enter another selection. If you write a separate function that checks all of these different scenarios in one place, then it should make your code much simpler.

6. Add functionality to check if the user has won and print "You win!" when the game is won. Also print the number of valid guesses and time it took the user to solve the problem. At this point you should have a working version of the memory game. Hint: During testing, it may be easier if you make your game easier (for example, use just a 2 x 2 board or 2 x 4 board).

### Python tip: printing multiple items on the same line

To print multiple strings on the same line, use the keyword parameter 'end' to specify what should be printed after each item (by default end is the newline character). See help(print). Examples:
```>>> for i in range(3):
...     print(i)
...
0
1
2
>>> for i in range(3):
...     print(i, end=" ")
...
0 1 2 >>>
>>>
>>> for i in range(3):
...     print(i, end="")
...
012>>>
```
Note that in both cases of using the "end" parameter, no newlines are printed at all, not even after the last number.

An alternate approach is to build up a string, and then print that:

```>>> s = ''
>>> for i in range(3):
...     s += str(i)
...
>>> print(s)
012
```

### When you're done

Before submitting your code, be sure to check all requirements. One third of the points for the test project come from style, so be sure to check your program for that as well. In particular:

Make sure that your program is properly commented:

• You should have a docstring comment for your module at the top of the file explaining what your program does.
• You should have comments after the module docstring stating your name, course (including section number), assignment number and the date.
• Each function should have an appropriate docstring.
• Other miscellaneous comments to make things clear, especially for complicated pieces of code.
In addition, make sure that you've used good style:
• Use constants as noted above, and avoid hard-coded numbers in your code.
• Avoid code duplication as much as possible and define functions to capture repeated patterns.
• Each function should represent roughly one task. If a function definition is getting longer and longer, consider defining additional functions for subtasks.
• Avoid global variables, i.e., variables used inside a function that were declared outside the fuction (pass them as parameters instead).
• Use good names for functions, variables, and parameters.
• Make your code readable by avoiding long lines that wrap, as well as using both spaces and empty lines to structure your code.

#### Submission procedure

Submit your .py file through the submission page for "TP 2". Please submit a version of the game with 4 rows and 4 columns, even if you have implemented the generalization to other sizes.

```
constants
if/while/for
variable naming
formatting
parameters
division into functions
avoiding code duplication
representation choices
misc

Functionality ....................... 28
board displays correctly       4
board is randomly initialized  4
loops until game completed     4
properly handles match         4
properly handles non-match     4
handles improper user input    4
counts guesses and seconds     4

Generalizes to other sizes ..........  2

Total ............................... 45
```

...and just for fun:

#### Extreme Gaming

http://xkcd.com/chesscoaster/