CPTR 124 Fundamentals of Programming
In this lab you will write functions that control the logic of your graphical Tic-Tac-Toe game.
You are welcome to work with a partner on this lab. You and your partner should begin thinking about the problems and begin writing the code before lab time. You may work by yourself if you wish.
- What to do
http://en.wikipedia.org/wiki/Tic-tac-toe provides the rules Tic-Tac-Toe. Your task is to provide the controlling logic for a two-player Tic-Tac-Toe computer game. This game engine should work independently of the application's presentation. It should be able to drive a modified version of your graphical Tic-Tac-Toe prototype, but also must work correctly for a non-graphical test program. A game in progress might look like
Since it is a two-player game, your program does not play against a human opponent but simply allows the user(s) to interact with the board, making marks with the mouse.
We divide the code of the program into two separate components: the program logic and the presentation. The program logic forms the game engine, enforcing the rules of the game. The presentation is the interface to the user. The presentation can be graphical (pointing device and graphical screen), text based (keyboard input and text output), or something else, such as hand gestures, voice recognition, brain wave analysis, etc.
The following table shows some of the division of labor between the program logic and presentation:
Responsibilty of Engine
Responsibility of Presentation
Keep track of whose turn it is
Indicate the current player (X cursor or O cursor)
Keep track of the marks in each square
Indicate to the user the marks in each square (draw an X, O, or nothing)
Determine if there is a winner
Show the winning configuration by drawing a visual line across the three-in-a-row marks
Disallow illegal moves
Provide feedback to user about an illegal move (display message box to user)
Place a mark in a specified position, if possible
Allow user to specify a move (process mouse clicks over the board)
Reset the game
Provide a dialog box that indicates the winner and gives the user the option to play again or quit
The presentation gets its information about what to display from the game engine, and the game engine gets its input from the presentation.
We will implement this clean separation of control logic and presentation by writing a program that consists of two separate Python source files:
tttlogic.py(the game engine) and
tictactoe.py(the GUI—an adapted version of your previous assignment).
- Game Logic. The file
tttlogic.pyis responsible for making the game work properly and enforcing the rules. Your job is to complete the
tttlogic.pyfile—in essence to program the rules of the game in Python. Some of the things your code must handle include
- ignore illegal moves like trying to make a mark over an existing mark.
- control whose turn it is
- detect when the game is over (win or draw).
Study the docstrings and comments in the
tttlogic.pyPython module. The file contains the skeletal definitions of seven functions. Observe that several of the functions accept string parameters and may return string results. It is important to use the exact strings specified in the comments so that the engine and the presentation can communicate successfully. The following is a comprehensive list of the strings the game engine and presentation use for communicating and making the game work:
Player X or player X's mark
Player O or player O's mark
No one has won and a move is available
Win across top row
Win across middle row
Win across bottom row
Win along left column
Win along center column
Win along right column
Win from left-top corner to right-bottom corner
Win from right-top corner to left-bottom corner
All squares filled with no winner
Your first task is to implement the missing code in the functions and add global variables as needed to keep track of the state of the game.
lookexpects a location string (
'North', etc.) as a parameter and returns the mark in that particular square (
None(if the square is empty). The graphical system uses the
lookfunction to determine what, if anything, to draw in a given square.
moveputs the mark of a player (
'O') in a given square, if possible. The exact mark depends on the player with the current turn. A mark may be placed in a square only if the square is unoccupied. The
movefunction requires its parameter to be one of the board location strings (
'North', etc.). If the move is a valid move, it addition to placing the mark, the function should ensure that turn transitions to the other player and finally return
TrueIf the attempted move is not valid, the function should not change the state of the game and simply return
False. (You may elect to ignore
move's return value in your GUI code, but your function should return the correct result regardless.)
initialize_boardclears all marks off the board making it ready for a new game. It also makes player X the current player. The function should reset any data the program may be using to monitor or control the progress of a game.
current_playerreturns the player whose turn it is (
change_playeralternates the turn to the other player.
set_playerforces the current player to be
check_statusdetermines if one player has won, the game is a draw, or if the game can continue. It returns a value the graphical system can use to render the board properly; for example, if player X has three marks in a line from the northeast corner of the board to the southwest corner as shown in the figure below,
check_statuswould return to the graphical interface the tuple
('X', 'Win_NE_SW'). The first element of the tuple is the winner, and the second element represents winning configuration. With this tuple the graphical interface in turn produces the presentation shown in the figure below. The playing and draw tuples would be
(None, 'Draw'), respectively, as neither status involves a winner.
check_statusfunction should not in any way alter the state of the game.
Think about it: If you can clear the board, put marks in specified squares, see what is in a given square, and check to see if the game is over or should continue, you have all the pieces necessary to model the control logic for a two-player Tic-Tac-Toe game.
In conjunction with implementing the seven functions above, you will need to add global variables in the
tttlogic.pymodule that maintain the state of the game. Your functions will use and potentially modify these global variables as the game progresses. You need a variable to keep track of whose turn it is. You need nine variables that keep track of the marks assigned to each of the squares on the Tic-tac-toe board. You may want to add a variable to keep track of the number of moves during a game (so you can declare a draw if no one has won after nine moves)—although you can handle a tie in other ways.
tttlogic.pyfile should contain NO input or output statements; that is,
inputshould not appear in your code. It is fine to use printing statements during development to help debug your code, but you should remove these statements when your work is complete. Also, your
tttlogic.pymodule should contain no Turtle graphics code. The game engine code should make no assumptions about how to show the user the progress of the game. It is the presentation's job (
tictactoe.py) to draw in the graphics window.
- Presentation. Copy the file
tictactoe.pyfrom your previous assignment to a new folder. It must reside in the same folder as the
tictactoe.pyPython source file is responsible for the presentation, and you must augment it to work with the game engine. Unlike with the code in the
tttlogicmodule, you have much freedom as to how you organize your functions and code within
tictactoe.py. You must, however, use graphics capabilities from the
turtlemodule only, with the exception of the
messageboxfunction that is found in the
tictactoe.pyfile provides a graphical user interface (GUI) that allows the user to make moves with a pointing device such as a mouse or touch pad. The GUI draws a natural looking Tic-tac-toe game board within a window (see the figure above). Your original version of
tictactoe.pydid not enforce the rules of the game, so it requires some modification to interact properly with the game engine.
You will need to modify parts of your
tictactoe.pyfile so it cooperates with the game engine. If you correctly implemented the mandated functions from the previous assignment (
drawO), you should not have to touch these functions. Your prototype had to keep track of the current player, but now a global variable in the
tttlogicmodule will do this. Instead of blindly drawing a mark in a board position, your modified graphical application can do so only as allowed by the game engine. This means you will need to modify your function that processes mouse clicks.
After each move, the function you registered with
onscreenclickin the graphical application must do several things:
- The function you registered with
onscreenclickmust check to see if the move was valid (via
tttlogic.move's return value) to determine if it should draw a mark in the selected square. If the move was valid, your graphical program can ask the game engine (via
tttlogic.look) which player owns the square in order to determine which mark to draw. If the move was not valid (for example, the player attempted to mark an already marked square), your GUI can show a message box that reports the failed move. The game engine can do this checking for you, so you should not do this work inside of your mouse clicked function.
Note that your GUI does not have to keep track of whose turn it is—the game engine does that. Your GUI does maintain the ability to force the current player to be X or O via the keyboard as before, but users ordinarily do not exercise this power when playing Tic-Tac-Toe under the normal game rules.
- The function you registered with
onscreenclickalso must check (via
tttlogic.check_status) to see if a valid move resulted in a win or draw to determine if the game should continue. You will need to add code somewhere (most likely in a new function) that draws a line across the appropriate squares for a win or draws lines everywhere for a tie.
Another helpful function in the GUI would provide a way to initialize the presentation (necessarily calling
tttlogic.initialize_boardalong the way). Your GUI would need to call this initialization function in between games to ensure all remnants of the previous game were cleared.
In addition to augmenting your screen click callback, you will need to tweak the callback functions you wrote for pressing the X key and O key so that they properly cooperate with the services your
- The function you registered with
- Game Logic. The file
When you are finished, thoroughly play with your Tic-Tac-Toe game, trying all combinations of moves, to ensure that your logic is correct. Does your code handle tie games properly? Does player X always have the first turn in a new game? If the very last move in a game uses the last available square but results in a win, does your code recognize the win or does it mistakenly report a draw?
When you are satisfied that your
tttlogicmodule is correct, run it on the command line (CMD.EXE for Windows or Terminal on a Mac) with the following program:
test_tttlogic.py. The program's output should be (the time can vary):... ---------------------------------------------------------------------- Ran 3 tests in 0.001s OKIf you get this output, your
tttlogic.pyfile probably is ready to move to the next level of verification. If the program's output indicates any failures, you need to fix the errors in
tttlogic.pybefore subjecting it to additional scrutiny.
- Check out
Your finished application consisting of your
tttlogic.pyfiles will be evaluated for correctness and compliance. Double check to ensure the following:
- that your
tttlogic.pyfile contains no printing statements and no Turtle graphics code, and
- that two players can play your graphical Tic-Tac-Toe game and things work as they would in the paper version.
Remember that your
tttlogicmodule is intended to work with different presentations, not just yours; therefore, your
tttlogic.pyfile will receive additional scrutiny. Follow the special instructions given during lab for the evaluation component. When approved, you should submit both Python source files to http://eclass.e.southern.edu. Be sure your name (and your partner's name, if necessary) are included in comments at the top of each source file.
- that your