Tic-Tac-Toe
Let’s Play a Game¶
Small games like Tic-Tac-Toe have a very easy ruleset and you can implement them in a Python program with what you already know. Since this is a rather long task, instead of letting you figure out all the details by yourself, you will be given some guidance.
Preparations¶
Start by creating a separate folder tic_tac_toe
for your project.
We will need the file constants.py
inside to note down some constants to make our program a bit more readable.
Further, a __main__.py
will hold the central part of our program.
Some Things never Change¶
In the constants.py
you will have to define the following:
- Assign some symbols to
PLAYER_X
andPLAYER_O
respectively- These are used to identify the players on the board later, so using letters makes sense here
- Please use the exact names for these constants, some other code later depends on it.
Bookkeeping¶
During the game you will need to keep track of some information.
In __main__.py
, create the appropriate variables for the following data.
Consider which data types and initial values they might have.
- The
board_state
which keeps track which fields are already taken and by whom- Since the board is made up of nine fields in a 2-D arrangement (i.e. rows and columns) it can not be represented by a single value
- Extra challenge: or can it?
- You will have to carefully which data type to use to represent the board.
- The data type must be able to hold multiple elements
- You must be allowed to change these elements, so you can set a player to a field
- Alternatively, instead of remembering the whole board, you could remember for each player which fields they occupy (if any).
- On this decision hinges a lot of how your code works in the end, so feel free to discuss your ideas with other people.
- Since the board is made up of nine fields in a 2-D arrangement (i.e. rows and columns) it can not be represented by a single value
- The
current_player
who is about to make a move. - The
winner
, as soon as there is one
Little Helpers¶
You will need to repeatedly do certain things, so it might be a good idea to write some functions for those. If any of those functions becomes to unwieldy consider to split it into smaller pieces or move it to its own file. Don’t forget to add some documantation,this can also help with getting to grips with the problem at hand.
You can try out each of the functions in isolation to test if they do what they are supposed to.
reset_board
¶
is_occupied
¶
Checks if a cell is occuoied by a player.
Providing incorrect values for any of the arguments may have unexpected results.
Args:
board_state: The board state which to check.
row: The row of the cell to be checked. Must be in the interval (0…2).
column: The column of the cell to be checked. Must be in the interval (0…2).
Returns:
`True` if a player occupies the field, `False` otherwise.
set_player
¶
Set a cell of a board to be occupied by a player.
This does not check if the cell is already occupied.
Providing incorrect values for any of the arguments may have unexpected results.
Args:
board_state: The board state before the change.
row: The row of the cell to be set. Must be in the interval (0…2).
column: The column of the cell to be set. Must be in the interval (0…2).
player: The player which occupies the cell, either `PLAYER_X`, `PLAYER_O` or `None`.
Returns:
The board state after the change was made.
get_player
¶
Get the player who occupies a given cell.
Providing incorrect values for any of the arguments may have unexpected results.
Args:
board_state: The board state from which to extract the player.
row: The row of the cell to be gotten. Must be in the interval (0…2).
column: The column of the cell to be gotten. Must be in the interval (0…2).
Returns:
The player which occupies the cell, either `PLAYER_X`, `PLAYER_O` or `None`.
print_board
¶
Notes
The printed output could look something like this:
Note that you already have some utility functions to extract the current player at a given position.
next_player
¶
Switch from one player to the next.
Also print some nice text to inform the players who is next.
Args:
current_player: The player that is currently playing
Returns:
The next player in order
Notes
Note that you aleady have some constants for each of the players, make good use of them!
input_row
¶
Ask the current player to select a row which can be used to specify the cell where the player wants to place their mark.
Make sure that the input is an integer in the intervals (0…2).
Returns:
The row selected by the player as integer.
input_column
¶
Ask the current player to select a column which can be used to specify the cell where the player wants to place their mark.
Make sure that the input is an integer in the intervals (0…2).
Returns:
The column selected by the player as integer.
check_for_victory
¶
Check the board if one of the following conditions are fulfilled.
The possible scenarios are:
* One player has occupied a complete row, column or diagonal
* That player would then be the winner
* All fields are occupied
* No more moves are possible, resulting in a draw
Args:
board_state: The current state of the game board
Returns:
Either the winning player, `DRAW` if no more move is possible or None if the game is not over yet.
Notes
Add a constant to represent a DRAW
, since None
would be used to represent that the game is not yet over
Tying it all Together¶
With all those building pieces, you can now implement a whole game in the __main__.py
.
Here is a suggested program flow to give you some inspiration.
(Of course you may chose your own approach if you desire to do so.)
Rematch¶
After some rounds, your fellow players have come up with some additional suggestions:
- Run the game in a loop so it automatically starts a new game once the old one is over
- Keep a score of
- How many games have been played
- How often each player won
- Print the
wins/total games
ratio in percent for each player
Closing Remarks
Simple games like theese are a good way to train programming. The rules are not overburdening and well-known so you can go directly to problem-solving. Breaking these problems down into step-by-step solutions and considering how to represent the game situations in a program is a very good exercise for training to think in the more strict ruleset that programming imposes.
It is strongly recommended to revisit this exercise once you have learned more. This first implementation is still very much guided and does not take advantage of all the possible features Python offers to you. Once you get to know more language features you will likely find new ways to represent the board and structure the program flow.
Extra challenge: There is a variation that is played by three players (X
, O
and T
(often called triangle)), which is played on a 4×4 board.
Can you implement that as well? Can you implement an even more generic variant for n players, that is played on an n+1×n+1 board?