CS21 Lab 5: Fruitful functions
Due Saturday, October 17, before midnight
Programming Tips
As you write your first programs, start using good programming practices now:
-
Use a comment at the top of the file to describe the purpose of the program (see example).
-
All programs should have a
main()
function (see example). -
Use variable names that describe the contents of the variables.
-
Write your programs incrementally and test them as you go. This is really crucial to success: don’t write lots of code and then test it all at once! Write a little code, make sure it works, then add some more and test it again.
-
Don’t assume that if your program passes the sample tests we provide that it is completely correct. Come up with your own test cases and verify that the program is producing the right output on them.
-
Avoid writing any lines of code that exceed 80 columns. In
emacs
, at the bottom, center of the window, there is an indication of both the line and the column of the cursor.
Function Comments
All functions should have a top-level comment! Please see our function example page if you are confused about writing function comments.
Are your files in the correct place?
Make sure all programs are saved to your cs21/labs/05
directory! Files
outside that directory will not be graded.
$ update21
$ cd ~/cs21/labs/05
$ pwd
/home/username/cs21/labs/05
$ ls
Questions-05.txt
(should see your program files here)
Goals
-
Work with functions and lists
-
Work with mutable and immutable function parameters
-
Work with functions that return values
-
Work with functions done only for their side effect
1. Checkpoint
At the end of your lab session, be sure to run handin21
.
Your lab instructor will check your files, which should reflect that you have made non-trivial progress (in python or pseudocode) towards the solution. Note that if you have not made much progress towards your solution, we expect that you would have been actively seeking help during your lab over Slack.
A portion of your final lab grade is dependent on this checkpoint.
If there are circumstances which prevent you from making substantial progress on this lab, please contact your lab instructor as soon as possible.
2. Tic-Tac-Toe
In tictactoe.py
you will implement a version of the
tic-tac-toe game. In this
game, players alternate between placing their symbol (either "X" or
"O") inside a 3x3 grid. The first player to get three in a line
(either on a row, a column, or a diagonal) wins.
In our version, the user will play against the computer. The computer will always play first and use the symbol "O", and the user will play second and use the symbol "X". The game can end with the user winning, the computer winning, or a tie.
Here are examples of playing the game showing the three possible outcomes:
2.1. Incrementally develop main
Start by creating a main
program that prints the welcome message.
Test and modify your main
until you are happy with the look of
the welcome message.
As you add each function to your program, you will be using main
to test them, so your main
program will go through many iterations
before you get to the final version. This is normal.
2.2. Display the board
In order to implement tic-tac-toe we will be using a list of characters to represent the board. The board will begin as a list of 9 empty spaces:
board = [" "," "," "," "," "," "," "," "," "]
Add the above assignment statement to your main
program.
The board will be modified after each player takes a turn. For example, if the computer chooses to play in position 3, then the board will change to:
[" "," "," ","O"," "," "," "," "," "]
If the user chooses to play in position 7, then the board will change to:
[" "," "," ","O"," "," "," ","X"," "]
Write a function called display_board(board)
, that takes in a
board represented in this way, and prints the board in the
familiar grid format of tic-tac-toe. This function does not return
any value, it is done for its side effect.
For example, the board above would print as:
| | ----------- O | | ----------- | X |
2.2.1. Test display_board
Add the following assignment statement to your main
program:
sample_board = ["0","1","2","3","4","5","6","7","8"]
Update your main
program to print the instructions about how to play
the game, and use your display_board
function to draw out the sample
board:
0 | 1 | 2
-----------
3 | 4 | 5
-----------
6 | 7 | 8
Once you are convinced that your function works you may move on.
2.3. User turn
Write a function called user_turn(board)
that takes in the current
board as input and modifies the board to contain the user’s chosen
play.
This function should prompt the user for a choice between 0 and 8.
Your function will continue to prompt the user until they provide
a valid choice. A valid choice must be between 0 and 8 (inclusive)
and it must be an empty spot on the board. You should modify
the board with a "X"
at their valid choice. Note that
this function does not return any value, but as a side effect
modifies the board.
You should review Example 1 above to see how the function continues to prompt the user until a valid input is provided.
2.3.1. Test user_turn
In your main
program, create a for
loop to call the user_turn
function and the display_board
function 3 times. Ensure that your
function only allows valid plays. Clearly, in the real game, the user
will not be allowed to take multiple turns in a row. However, this is
just a convenient way to test the function. Once you are convinced
the function is correct you may move on.
2.4. Computer turn
Write a function called computer_turn(board)
that takes in the
current board as input and modifies the board to contain the
computer’s chosen play. There is no return value for this function
To implement the computer’s turn you should create a list of all of
the empty locations on the current board. Then you should you the
random
library’s choice
function to select one of these empty
locations. Be sure to update the board with an "O"
at the chosen
location and to also print out the computer’s selection. Like the
user_turn
function, the computer_turn
function does not return any
value, but as a side effect it modifies the board.
2.4.1. Test computer_turn
In your main
program, add to the for
loop that you previously
created. Before you get the user’s selection, call your
computer_turn
function and your display_board
function again. So
your loop should now have four statements. We are not worried about
recognizing a win at this point. We just want to see if the
computer_turn
function correctly selects valid empty locations to
play and that the board is properly updated. Once you are convinced
that your function is correct you may move on.
2.5. Determining a win
Write a function called check_player_win(board, symbol)
that takes as
input a board and the symbol representing one of the players (either
"X" or "O"), and returns True
if that player has won. Otherwise
it returns False
.
For example, if the current board look like this:
O | X | O ----------- O | X | ----------- | X |
then check_player_win(board, "O")
should return False
and
check_player_win(board, "X")
should return True
There are a number of cases you need to check. We suggest that you:
-
use a
for
loop to check the three possible horizontal wins -
use another
for
loop to check the three possible vertical wins -
test separately for the two possible diagonal wins
2.5.1. Test check_player_win
In the main
program, remove the for
loop that you used to test the
turn functions. Now create some test boards, like those shown below,
that represent a win for one of the players and a loss for the other.
Try cut and pasting this code from the web page right into your
program. The outputs of the print
statements should be True
for
the winner and False
for the other player.
board1 = ["O", " ", "O", "X", "X", "X", "O", " ", " "]
display_board(board1)
print("Is O winner?", check_player_win(board1, "O")) # False
print("Is X winner?", check_player_win(board1, "X")) # True
board2 = ["O", " ", " ", "O", "X", "X", "O", " ", " "]
display_board(board2)
print("Is O winner?",check_player_win(board2, "O")) # True
print("Is X winner?",check_player_win(board2, "X")) # False
board3 = ["O", "X", "X", " ", "O", " ", " ", " ", "O"]
display_board(board3)
print("Is O winner?",check_player_win(board3, "O")) # True
print("Is X winner?",check_player_win(board3, "X")) # False
Once you are convinced that your function is correct, you may move on.
Go ahead and delete all of the sample boards and extra code that you
added to test your check_player_win
function.
2.6. Putting it all together
Once all of your helper functions are complete and tested, it is
time to build the final version of your main
program.
Your main
program should initially contain the statements that print
the welcome message, initialize the board and the sample board, print
the instructions, and display the sample board.
Now you are ready to create the game loop. Should you use a for
loop
or a while
loop? Do you know exactly how many times you’ll run the
loop or does it depend on the circumstances?
Each time through the game loop either the user will play or the computer will play. We recommend keeping a turn counter that you initialize to 1 and increment each time through the loop. When the turn counter is odd, it is the computer’s turn, because the computer gets to go first, otherwise it is the player’s turn. After each player’s turn you should check if that player has won. You should also display the updated game board.
The game loop ends when one of the player’s has won, or if the turn counter reaches 10 without a winner, indicating a tie. Be sure to print the outcome of the game at the end.
2.6.1. Test main
and the whole game
To catch possible mistakes you might have made you should play lots of games using your program. Be sure that it works properly for all of the possible outcomes: a user win, a computer win, or a tie. Once you are convinced it’s correct you’re done programming! You just need to complete the questionnaire.
2.7. Extra Challenge
This extra challenge is not required and should only be attempted once the rest of your program is complete.
Update your program so that the computer player makes intelligent choices, rather than just choosing randomly from the open locations. For example, the computer could recognize when the user has the chance to win in the next turn, and block that location.
3. Answer the Questionnaire
Each lab will have a short questionnaire at the end. Please edit
the Questions-05.txt
file in your cs21/labs/05
directory
and answer the questions in that file.
Once you’re done with that, run handin21
again.
Turning in your labs….
Remember to run handin21
to turn in your lab files!
You may run handin21
as many times as you want. Each time it will
turn in any new work. We recommend running handin21
after
you complete each program or after you complete significant
work on any one program.