CPTR 124 Fundamentals of Programming


In this lab you will write graphical Tic-Tac-Toe game.


  1. Teams

    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.

  2. What to do

    http://en.wikipedia.org/wiki/Tic-tac-toe provides the background and rules for the game Tic-Tac-Toe. Your task is to implement the graphical user interface and the controlling logic for a two-player Tic-Tac-Toe computer game.

    A game in progress might look like

    Screenshot of the Tic-Tac-Toe game

    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.

    Your program must draw the lines of the Tic-Tac-Toe game board and allow the user to click an area of the board to place a mark (X or O).

    One task to solve is how to determine which square a player selects. You mouse processing method receives an (xy) point location within the window, and your program must map that point to a square on the game board. Conversely, when your program needs to draw and X or an O in a square, the program must center the mark at a point within a square.

    You can define a custom enumerated type called Location to represent squares on the board as shown here:

    Constant-names squares

    Your Tic-Tac-Toe game object can maintain nine instance variables that keep track of the players' marks at the various locations. These variables could be assigned one of the following values of a custom enumerated type named Player:

    • Player::None—This is the value you can assign to all the square variables at the start of the game indicating that no player initially owns any of the squares.

    • Player::X—This is the value you can assign to a square variable when player X legally chooses that square.

    • Player::O—This is the value you can assign to a square variable when player O legally chooses that square.

    Your program also must keep track of whose turn it is. You can use an instance variable that alternates between the values Player::X and Player::O to serve this purpose.

    You will find implementing the following functions or methods helpful:

    • point_to_square. This function accepts two parameters, x and y, representing the coordinates of a point on the game board. This function returns one of the values Location::Northwest, Location::North, etc. that represents a square on the board. In this function you need to provide code that maps a point to a particular square.

      The goal of this function is to be able to determine which square on the Tic-Tac-Toe game grid corresponds to a particular point in the graphics window. The user can click the mouse at multiple locations within a particular square, and all of those clicks should be treated the same. Your GUI will use this function to determine which square a player chose.

    • square_to_point. This function accepts one of the square values Location::Northwest, Location::North, etc. and returns a point object (x, y) representing the center of the corresponding square on your game board. This function is similar to a reverse mapping of point_to_square, except for the fact that many points map to the same square, but a square always maps to the one point at its center.

      This function is useful when when drawing a player's mark on the game board: the lines that make up player X's mark cross at this point, and the circle that makes up player O's mark is centered at this point.

      The two functions point_to_square and square_to_point work together. When the user clicks anywhere within a valid square on the Tic-Tac-Toe game board, the program can determine which square the user selected via point_to_square. The game itself is concerned only with the nine square positions, not the thousands of possible pixel locations within the graphics window. Presented with a square, the program then can use square_to_point to compute exactly where to center a player's mark for drawing.

    • draw_mark. This function accepts one of the location values Location::Northwest, Location::North, etc. and draws an X (two big lines that cross), an O (big circle), or nothing depending on whose mark should appear within that square. If drawing an X or O, the mark should be centered within the square on the game board. This function should use the square_to_point function to determine where to draw the centered mark.

    • move. This method accepts one of the location values Location::Northwest, Location::North, etc. It places the current player's value (Player::X or Player::O) into one of the nine variables keeping track of the player marks in the squares. Your move method could return true if successful and false if the square already is occupied. This would enable your GUI to provide negative feedback (like the flashing yellow background) if the user attempts an illegal move.

    • look. This method accepts one of the location values Location::Northwest, Location::North, etc. It returns the player's mark in that square: Player::None, Player::X, or Player::O.

    • check_status. This method accepts no parameters and returns the status of the game. You can use values from a custom enumerated type named Status to represent the game's status. Examples include the following:

      • Status::Playing—the game is not over yet

      • Status::Win_NW_N—a player has won the game filling in the top row of the board

      • Status::Win_NW_SE—a player has won the by game filling in the diagonal from the top left to the bottom right of the board

      • Status::Draw—all the squares are filled with no winner

      Note that while the above list contains two examples of winning configurations, there actually are eight different winning configurations in Tic-Tac-Toe. Your program must account for all ten game states (playing, draw, and eight different ways to win).

    • mouse_released (and/or mouse_pressed)—You will need to override the mouse_released method to process user mouse clicks. This method needs to map the point it receives from the graphical framework to its corresponding square on the game board and then do what is necessary to process a legal move or reject an illegal move. You mouse_released method should call repaint at the end so the graphical framework will call your paint method and redraw the window in its new state.

    • paint— It is the responsibility of your paint method to draw the lines for the game board and draw the player's marks on the board. Your paint method can access the instance variables you are using to keep track of square owners so it can determine what to draw. The paint method will use the draw_mark method mentioned above to draw the players' marks.

    Your class must maintain several instance variables that keep track of the state of the game. At a minimum they need to do the following:

    • Keep track of the current player—Player X begins each game, and control moves to player O after a legal move by player X. Control alternates between player X and player O until the game is over.

    • Determine if the game play continues—the game continues until a player wins or the game is a draw.

    Your program should disallow illegal moves. Illegal moves include selecting a position outside of the game board or selecting a square already occupied by a mark. Your program should ignore an illegal move attempt, and such an attempt should not pass control to the other player (that is, a player cannot avoid making a move by trying to make an illegal move).

    At the game's end, your program should indicate the winner by drawing a line through the sequence of three marks that established the win. You can draw lines everywhere or do something more creative to indicate a draw.

    If the user clicks the mouse over the window at the end of a game, the game should reset and allow a fresh, new game to begin.

  3. Check out

    Play many Tic-Tac-Toe games with your program until you are satisfied that it works perfectly. You will be asked to demonstrate that your game behaves properly.

    After your program has been checked off you should upload your code 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.