TicTacToe Exercise

This pair-programming exercise serves as the "show your instructor that you're ready to start working on the major term project" experience. In the process you and your teammate (thereafter referred to as you) should learn a few new things, and firm up what you already know.

TicTacToe is usually played on a 3-by-3 square board. To make things more interesting (and to help you learn how to write flexible code) our version will allow any square board size. To see what the finished product might look like, run this file: TicTacToe6.pyc. Enter the board size (e.g. 3, 4, or 5 for a 3-by-3, 4-by-4, or 5-by-5 square board, respectively) and press the <ENTER> key.  When the board appears, click on it with the left mouse button to select squares. Note that it is possible that the board will pop up behind other windows. If you don't see the board after entering the board size, try moving or minimizing some other windows.

One step at a time!

After you have completed each in-class step of the assignment, show your code to the instructor or TA (if you are working on it in class) and commit it to your Subversion repository. Don't forget to update your working copy each time before you edit your code and commit after each step. Of course, please don't hesitate to ask us for help whenever you need it. As a team, you should primarily depend on each other for help, but you should also get help from other sources (your instructor, TAs, lab assistants) when you need it. Be sure you understand each thing you do before you go on.

This is a pair programming exercise so you should switch roles so that for one step a teammate is the navigator while the other is the driver, and for the next step the navigator and driver switch roles.  Continue with this approach until you complete the assignment.
  1. All good programmers start with 0: Find the module TicTacToe.py within the TicTacToe project. Each team member should independently add his or her name to the comments at the top of the file. This involves each of you editing the file, so it requires careful use of SVN. Follow the steps below in one sitting. If you are interrupted during this process, repeat the steps:
    1. Right-click TicTacToe.py in the Pydev Package Explorer view. Choose Team→Update. This ensures that you have the most recent changes from your teammates.
    2. Edit the comments in the file to add your name.
    3. Save the file.
    4. Right-click again on TicTacToe.py in the Pydev Package Explorer view. Choose Team→Commit... This shares your change with your teammates.

    Follow this cycle of update-edit-commit whenever you make changes to your program.

    Edit the TicTacToe.py module in your project so that it creates a graphics window and draws a 3-by-3 TicTacToe grid. Your finished program may look something like TicTacToe0.pyc . Try it out before writing your code.

    This task is fairly simple, but you should do it in a way that will help you plan ahead for future versions. Here are a few lines of code that you should use. Defining named constants and using them in your code instead of numbers can avoid the use of "magic numbers" that can make code difficult to enhance and maintain. In this case, it helps because the board size will not always be 3 in later versions of the program,

         BOARDSIZE  = 3                   # number of rows and columns
         BOARDRANGE = range(BOARDSIZE)    # range of rows and columns
         PPS        = 150                 # pixels per square
         WINDOWSIZE = PPS * BOARDSIZE     # width and height of window
         INSET      = 15                  # num of white pixels around X's and O's in squares
         
    

    If you want to make the board linger on the screen for a few seconds and then disappear like the sample program does, import the time module, and include the line time.sleep(3) before your window.close() statement. Don't forget that you also need to import the zellegraphics module.

    If you want to require the user to click on the window to make it disappear instead of making it linger for a few seconds, include the line  window.getMouse() before your window.close() statement, instead of the line time.sleep(3).

    Before going on to the next step, commit your project to your Subversion repository by right-clicking it and choosing Team → Commit... Please make sure your commit comment begins with the words  Phase 0.

    Before moving on to the next step, both you and your team should update your working copy so it reflects what's in the repository.

  2. Enhance your program so it asks the user for the board size, then draws the grid, as in this program: TicTacToe1.pyc . The number the user enters should become the new value of BOARDSIZE; then after you calculate WINDOWSIZE so that the window will hold the different-sized board, the rest of the program should not have to be changed.

    Before going on to the next step, commit your project to your Subversion repository. Please begin your commit comment with Phase 1.

    Before moving on to the next step, both you and your team should update your working copy so it reflects what's in the repository.

  3. Define two functions, drawX(row, col) and drawO(row, col). Each should take two parameters, a row number and a column number. For example, the call drawX(1, 2) should cause an X to be drawn in the second row and third column (don't forget that row and column numbers start with 0), while the call drawO(0, 0) should cause an O to be drawn in the upper left square. See this example: TicTacToe2.pyc. You may find it helpful to write some helper functions that map row and column positions to window pixel locations. For, example, this function calculates the coordinates of the upper-right point of an X drawn in the square of a given row and column:
    def rectUpperRight(row, col):
       """coordinates of top right corner of inset X or O"""
       return Point(PPS*(col+1) - INSET, PPS*row + INSET)
    

    Call each function, drawX() and drawO(), with some different values for the parameters and verify that they work correctly. Can you put an X and an O in the same square? (In a later step you will solve this).

    Before going on to the next step, commit your project to your Subversion repository. Please make sure your commit comment indicates which phase you just completed.

    Before moving on to the next step, both you and your team should update your working copy so it reflects what's in the repository.

  4. Enhance your program (using loops) by writing a fillBoard( ) function that fills the entire board with alternating Xs and Os, as in this example: TicTacToe3.pyc. Your code should work similarly to the example whether the board size is even or odd. Don't forget to actually call fillBoard!

    Before going on to the next step, commit your project to your Subversion repository. Please make sure your commit comment indicates which phase you just completed.

    Before moving on to the next step, both you and your team should update your working copy so it reflects what's in the repository.

  5. Use the window's getMouse() method to determine where the user clicks, and draw an X in that square. The next click should cause an O to be placed, etc. When there are enough clicks to fill the board, the program should terminate. At this point, we have no mechanism for keeping track of previously-clicked squares, so there is no way to prevent having an X and an O drawn in the same square. Here is an example: TicTacToe4.pyc. [Hint: You should remove the call to fillBoard.  Also, you might find integer division helpful for determining in which square the user clicked.]

    Before going on to the next step, commit your project to your Subversion repository. Please make sure your commit comment indicates which phase you just completed.

    Before moving on to the next step, both you and your team should update your working copy so it reflects what's in the repository.

  6. Keep track of which squares on the board are already filled. We suggest that you use a two-dimensional list of numbers, one number for each square on the board. In the following example, a -1 represents that the corresponding square is unfilled , 0 for an X, and 1 for an O .
    For example, if the board is , then the corresponding nested list is
    [[-1, 1, 0, -1], [-1, -1, 0, -1], [0, 1, -1, -1], [-1, -1, -1, -1]].
    Now, when the user clicks a square, see if the corresponding list position contains -1. If so, draw the appropriate X or O, and mark the list position to indicate which symbol is in that square. If not, ignore the click altogether (make sure that you only count the number of successful clicks, so that the program will not quit until the board is actually full). Here is an example: TicTacToe5.pyc

    Before going on to the next step, commit your project to your Subversion repository. Please make sure your commit comment indicates which phase you just completed.

    Before moving on to the next step, both you and your team should update your working copy so it reflects what's in the repository.

  7. After each successful user click, check to see if this move caused a win by making an entire row, column or diagonal contain the same symbol (X or O). It might be easiest to do this by breaking the task up into several small tasks and writing a short function for each task. If there is a winner, draw a line through the winning squares, and stop the loop by using a break statement. The phase should have the functionality of the version that you ran at the beginning of this document.

    Congratulations on completing this interesting project. This was a challenge but you did well by completing it.

    Commit your project to your Subversion repository. Please make sure your commit comment indicates that you have completed the project.

    You and your team should update your working copy so it reflects the completed version of the project.