Short Exercises #4¶
Due: Wednesday, November 2nd at 4:30pm CT
The following short exercises are intended to help you practice some of the programming concepts introduced in the first four weeks of the quarter. These exercises should not take more than 1-2 hours in total to complete.
Fetching the instructor files¶
To get the files for this set of short exercises, first set the
GITHUB_USERNAME
environment variable by running the following
command at the Linux command line (replacing replace_me
with your
GitHub username):
GITHUB_USERNAME=replace_me
(remember you can double-check whether the variable is properly set by
running echo $GITHUB_USERNAME
)
Then navigate to your Short Exercises repository and pull
the new material:
cd ~/capp30121
cd short-exercises-$GITHUB_USERNAME
git pull upstream main
You will find the files you need in the se4
directory.
IMPORTANT: If you are unable to obtain the instructor files by running the commands above do not try to add the files in some other way. Doing so will likely prevent you from submitting your code. Instead, please seek assistance on Ed Discussion or at office hours.
Testing¶
As usual, you will want to test your solution manually before you try the automated tests. (See below for examples.) Remember to set up auto reload before you start testing.
$ ipython3
In [1]: %load_ext autoreload
In [2]: %autoreload 2
In [3]: import se4
A Game¶
Tic-tac-toe (also known as “noughts and crosses” or “Xs and Os”) is a game for two players who take turns marking cells in a 3 by 3 grid that is initially empty. One player marks cells with an “X” and the other marks cells with an “O”. The first player who places three marks in a row horiztonally, vertially, or diagonally is the winner. You can read more about tic-tac-toe here or play a few games against Google here.
In this set of short exercises, you will complete the implementation of a two player
terminal-based tic-tac-toe game. You are going to implement several
methods for managing the board (that is, the grid). We have provided a Player
class which encapsulates
information about a tic-tac-toe player and a Game
class which runs the game.
Player
class¶
The Player
class encapsulates information about a
tic-tac-toe player and has the the following attributes.
name
(string): the name of the playersymbol
(string): the player’s one character symbol
In [4]: p1 = se4.Player("Hannah", "X")
In [5]: p1.name
Out[5]: 'Hannah'
In [6]: p1.symbol
Out[6]: 'X'
In [7]: p2 = se4.Player("Guido", "O")
In [8]: p2.name
Out[8]: 'Guido'
In [9]: p2.symbol
Out[9]: 'O'
Game
class¶
The Game
class starts the game, repeately asks players for their next
move, and plays each move in turn.
A demonstration of the game is shown in the “Playing the Game” section below.
We encourage you to read through the Game
class after you have completed the
exercises below.
It is okay if you don’t understand every detail, but reading the code will help
you understand how Game
interacts with Player
and Board
.
Exercises¶
The Board
class encapsulates information about the 3 by 3
tic-tac-toe board and contains methods for interacting with the
board. In these exercises, you will implement the Board
class.
Important: The Game
class and our tests access attributes and
call methods of your Board
class. It is important that you use the required
names for the attributes and methods.
Magic numbers: Near the top of se4.py
, you will see the global constant
SIZE = 3
. You should use this constant in your implementation to avoid the use
of the “magic number” 3 throughout your code. We’ve used it in Game
, too.
Exercise 1
Implement the following attribute in the Board
class:
board
(list of list of string): the 3 by 3 tic-tac-toe board, with all locations initially set to empty ("E"
).
In [10]: b1 = se4.Board()
In [11]: len(b1.board) # number of rows
Out[11]: 3
In [12]: len(b1.board[0]) # number of columns
Out[12]: 3
In [14]: b1.board
Out[14]: [['E', 'E', 'E'], ['E', 'E', 'E'], ['E', 'E', 'E']]
Exercise 2
Implement the __str__
method. This method should return a string
representation of the board.
A row should be represented by a string that contains the symbol
from each element in the row separated by space. For example,
a row of all "E"
would be represented with: "E E E"
.
The string method join
will be very useful for this task.
The rows in turn should be terminated by newline characters "\n"
. The initial board
would yield the string: "E E E\nE E E\nE E E\n"
.
Printing this string yields:
In [15]: print(b1)
E E E
E E E
E E E
Exercise 3
Implement the method valid_move
, which takes a tuple of two integers (a row number and a column number)
and returns True
if the move is valid, and False
otherwise.
A move to any unoccupied cell on the board is valid.
In [20]: print(b1)
E E E
E X O
E E E
In [21]: b1.valid_move((1, 1)) # location of "X"
Out[21]: False
In [22]: b1.valid_move((1, 2)) # location of "O"
Out[22]: False
In [23]: b1.valid_move((1, 3)) # not on the board
Out[23]: False
In [24]: b1.valid_move((-1, 0)) # not on the board
Out[24]: False
In [25]: b1.valid_move((0, 0))
Out[25]: True
In [26]: b1.valid_move((0, 1))
Out[26]: True
Exercise 4
Implement the method play_move
, which takes the following parameters:
location
(tuple): the location of the player’s move as the tuple (row, column)player
(Player): the player who is moving
play_move
checks to make sure that the player’s move is valid and, if it is,
updates the board at the indicated location with the player’s symbol and returns True
.
If the player’s move is not valid, this method should return False
. An invalid
move should not modify the board.
In [27]: print(b1)
E E E
E X O
E E E
In [29]: b1.play_move((2, 2), p1)
Out[29]: True
In [30]: print(b1)
E E E
E X O
E E X
In [31]: b1.play_move((0, 0), p2)
Out[31]: True
In [32]: print(b1)
O E E
E X O
E E X
In [33]: b1.play_move((0, 0), p1) # invalid move
Out[33]: False
In [34]: print(b1)
O E E
E X O
E E X
Exercise 5
Implement the method winner
, which takes a Player
object
as a parameter and returns True
if that player is a winner, and False
otherwise.
We will play a simplified version of tick-tac-toe, where a player wins if they place three of their symbols in a row horizontally or vertically. In the full game, a player also wins if they get three-in-a-row along either diagonal. You are not required to implement this, but you’re welcome to.
In [46]: p1.symbol
Out[46]: 'X'
In [47]: p2.symbol
Out[47]: 'O'
In [48]: print(b2)
X O O
E X O
X E O
In [50]: b2.winner(p1)
Out[50]: False
In [51]: b2.winner(p2)
Out[51]: True
In [62]: print(b3)
E X O
X X X
O O O
In [63]: b3.winner(p1)
Out[63]: True
In [64]: b3.winner(p2)
Out[64]: True
In [72]: print(b4)
X O E
O X O
E X E
In [73]: b4.winner(p1)
Out[73]: False
In [74]: b4.winner(p2)
Out[74]: False
Automated Tests¶
As usual, we have included automated tests for each exercises. Please see the Testing Your Code page on the course website for more information about automated testing.
To test Exercises 1-5 invidually, use the commands:
py.test -xvk constructor
py.test -xvk str
py.test -xvk valid
py.test -xvk play
py.test -xvk winner
Playing the Game¶
We have included code to allow you to play against another person. To start the game, run:
python3 se4.py
from the command line. The first few turns might look like this:
$ python3 se4.py
Ready to play tic-tac-toe?
Player 1: Enter you name and pick your symbol: Hannah X
Player 2: Enter you name and pick your symbol: Guido O
Enter your move Hannah: 1 2
E E E
E E X
E E E
Enter your move Guido: 2 0
E E E
E E X
O E E
Note
Wondering how we’re able to run a game by running python3 se4.py
?
Confused about the line if __name__ == "__main__":
in our code?
Now might be a good moment to read the textbook chapter on the
Basics of Code Organization,
which explains the difference between importing a Python file
and running a Python file.
Submitting your work¶
Once you’ve completed the exercises, you must submit your work through Gradescope (linked from our Canvas site). Gradescope will fetch your files directly from your GitHub repository, so it is important that you remember to commit and push your work!
To submit your work, go to the “Gradescope” section on our Canvas
site. Then, click on “Short Exercises #4”. Then, under “Repository”,
make sure to select your
uchicago-CAPP30121-aut-2022/short-exercises-$GITHUB_USERNAME.git
repository.
Under “Branch”, just select “main”.
Finally, click on “Upload”. An autograder will run, and will report back a score. Please note that this autograder runs the exact same tests (and the exact same grading script) described in Testing Your Code. If there is a discrepancy between the tests when you run them on your computer, and when you submit your code to Gradescope, please let us know.
Your ESNU score on this set of exercises will be determined solely on the basis of these automated tests:
Grade |
Percent tests passed |
---|---|
Exemplary |
at least 95% |
Satisfactory |
at least 80% |
Needs Improvement |
at least 60% |
Ungradable |
less than 60% |
If there is a discrepancy between the tests when you run them on your computer, and when you submit your code to Gradescope, please let us know. Please remember that you can submit as many times as you want before the deadline. We will only look at your last submission, and the number of submissions you make has no bearing on your score.