CS303E Project 2

Instructor: Dr. Bill Young
Due Date: Monday, November 7, 2022 at 11:59pm

It is pretty common in computing to collaborate with others in a team to build a system/program. In this project, you will be supplied with some code and be required to write other code to interact with what is supplied to produce a working system. Of course, in this class you should never use work that you find on the internet or done by anyone other than youself, except as specifically allowed, as in this case!

Playing Tic-Tac-Toe

Did you know that video games constitute a larger entertainment industry than the international film industry and all professional sports combined? In 2020, the gaming industry generated $155 billion in revenue. By 2025, analysts predict the industry will generate more than $260 billion in revenue. UT Computer Science has a thriving video game group. Your professor isn't in it, but many of his colleagues are.

In this assignment, you'll program a simple version of the game, Tic-Tac-Toe (also called Noughts and Crosses). This is a two player game where players alternate placing their tokens on a 3x3 board with the goal of placing three of their tokens in a row. The first player uses the token "X" and the other player uses token "O".

In your version of the game, the two players will be a human and a program. The human will go first using token "X". The human player will be asked via an input statement to specify an empty location to place "X". The program will use token "O". The program player is particularly mindless, placing its token on any randomly chosen open space. Think about how you could make it a bit smarter.

You will be supplied a class template and a driver function which will play the game (below). You will have to fill in some other code including some constants, class methods, and possibly some subsidiary functions. Below is the template and driver. This is also in the following file: Tic Tac Toe template. Note that the board is simply a 2D (3x3) list of characters (" ", "X", "O"); this makes it pretty simple to print.

With each human move, you should ensure that the move is legal: has form r, c where r and c are in the range [0..2]. You can assume that r and c are integers, but not that they are in the correct range. Spaces shouldn't matter. Also, check that the selected space isn't already occupied. Machine moves are guaranteed to be legal.

import random

# Some global constants:

HUMAN   = 0
MACHINE = 1

YOU_WON  = "Congratulations! You won!\n"

 ... other constants (see the driver and output).

def initialBoard():
    return  [ [" ", " ", " "], \
              [" ", " ", " "], \
              [" ", " ", " "] ]

class TicTacToe:
    def __init__(self):
        # Initialize the game with the board and current player

    def __str__(self):
        # Return a string representation of the board.

    def getPlayer( self ):
        # Return the current player.

    def isWin( self ):
        # See if the board represents a win for the current
        # player. A win is three of the current player's tokens
        # in a single row, column, or either diagonal.

    def swapPlayers( self ):
        # Change the current player from HUMAN to MACHINE or
        # vice versa.
        
    def humanMove( self ):
        # Ask the HUMAN to specify a move.  Check that it's 
        # valid (syntactically, in range, and the space is 
        # not occupied).  Update the board appropriately.

    def machineMove( self ):
        # This is the MACHINE's move.  It picks squares randomly
        # until it finds an empty one. Update the board appropriately.
        # Note: this is a really dumb way to play tic-tac-toe.  
        print("Machine's turn:")
        while True:
            r = random.randint(0, 2)
            c = random.randint(0, 2)
            if self.__board[r][c] == " ":
                print("  Machine chooses: ", r, ", ", c, sep="")
                self.__board[r][c] = "O"
                return

def driver( ):
    """ This plays tic-tac-toe in a pretty simple-minded
    fashion.  The human player goes first with token "X" and
    alternates with the machine using token "O".  We print
    the board before the first move and after each move. """

    # Print the welcome message
    print( WELCOME )

    # Initialize the board and current player
    ttt = TicTacToe()
    print( ttt )

    # There are up to 9 moves in tic-tac-toe.
    for move in range(9):
        # The current player may be HUMAN
        # or MACHINE
        if ttt.getPlayer() == HUMAN:
            # If HUMAN, take a move, print the board,
            # and see if it's a win.
            ttt.humanMove()
            print( ttt )
            if ttt.isWin():
                print( YOU_WON )
                return

        else:
            # Else MACHINE takes a move.  Print the
            # board and see if the machine won.
            ttt.machineMove()
            print( ttt )
            if ttt.isWin():
                print( YOU_LOST )
                return

        # Swap players.
        ttt.swapPlayers()

    # After nine moves with no winner, it's a tie.
    print( YOU_TIED )
    
driver()
Notice that this is a pretty dumb way to play tic-tac-toe. Fixing these issues is a pretty good programming exercise. You are encouraged to play with this on your own time. If we didn't have 600 of these to grade, I'd offer extra credit, but it makes the TAs' job a lot harder, so I'm afraid I can't do that this semester.

Sample Output:

This shows pretty bad playing on the part of the human just to give examples of the possible outcomes.
> python Project2.py

Welcome to our Tic-Tac-Toe game! 
Please begin playing.

 | | 
-----
 | | 
-----
 | | 

Your turn:
  Specify a move r, c: 9, 2

Illegal move specified. Try again!
  Specify a move r, c: 0 0

Response should be r, c. Try again!
  Specify a move r, c: 0, 0

X| | 
-----
 | | 
-----
 | | 

Machine's turn:
  Machine chooses: 1, 0

X| | 
-----
O| | 
-----
 | | 

Your turn:
  Specify a move r, c: 2, 0

X| | 
-----
O| | 
-----
X| | 

Machine's turn:
  Machine chooses: 2, 2

X| | 
-----
O| | 
-----
X| |O

Your turn:
  Specify a move r, c: 1,2

X| | 
-----
O| |X
-----
X| |O

Machine's turn:
  Machine chooses: 0, 2

X| |O
-----
O| |X
-----
X| |O

Your turn:
  Specify a move r, c: 1, 1

X| |O
-----
O|X|X
-----
X| |O

Machine's turn:
  Machine chooses: 0, 1

X|O|O
-----
O|X|X
-----
X| |O

Your turn:
  Specify a move r, c: 2, 1

X|O|O
-----
O|X|X
-----
X|X|O

Looks like a tie.  Better luck next time!

> python Project2.py

Welcome to our Tic-Tac-Toe game! 
Please begin playing.

 | | 
-----
 | | 
-----
 | | 

Your turn:
  Specify a move r, c: 3 3

Response should be r, c. Try again!
  Specify a move r, c: 3, 3

Illegal move specified. Try again!
  Specify a move r, c: 0, 0

X| | 
-----
 | | 
-----
 | | 

Machine's turn:
  Machine chooses: 2, 2

X| | 
-----
 | | 
-----
 | |O

Your turn:
  Specify a move r, c: 2, 0

X| | 
-----
 | | 
-----
X| |O

Machine's turn:
  Machine chooses: 1, 2

X| | 
-----
 | |O
-----
X| |O

Your turn:
  Specify a move r, c: 0, 1

X|X| 
-----
 | |O
-----
X| |O

Machine's turn:
  Machine chooses: 1, 1

X|X| 
-----
 |O|O
-----
X| |O

Your turn:
  Specify a move r, c: 2, 1

X|X| 
-----
 |O|O
-----
X|X|O

Machine's turn:
  Machine chooses: 0, 2

X|X|O
-----
 |O|O
-----
X|X|O

Sorry!  You lost!

> python Project2.py

Welcome to our Tic-Tac-Toe game! 
Please begin playing.

 | | 
-----
 | | 
-----
 | | 

Your turn:
  Specify a move r, c: 1, 1

 | | 
-----
 |X| 
-----
 | | 

Machine's turn:
  Machine chooses: 0, 2

 | |O
-----
 |X| 
-----
 | | 

Your turn:
  Specify a move r, c: 0, 0

X| |O
-----
 |X| 
-----
 | | 

Machine's turn:
  Machine chooses: 2, 2

X| |O
-----
 |X| 
-----
 | |O

Your turn:
  Specify a move r, c: 2, 1

X| |O
-----
 |X| 
-----
 |X|O

Machine's turn:
  Machine chooses: 2, 0

X| |O
-----
 |X| 
-----
O|X|O

Your turn:
  Specify a move r, c: 0, 1

X|X|O
-----
 |X| 
-----
O|X|O

Congratulations! You won!

>

Programming Tips:

Using functions: I have described the values of functions in several of these programming tips. Still I'm getting questions like: do we need to have auxiliary functions (or functions at all)? To me, that's like asking your English teacher, who just assigned you a 5-page paper: "Do I have to have paragraphs?"

Functions are one of your most useful tools for managing the complexity of code. Strictly speaking, you can get by without them. But your code is likely to be an unreadable, unmaintainable jumble. Consider the question of whether the tic-tac-toe player who just placed a token on the board thereby won the game. She did if there are now three of her tokens in a row, either within one row of the board, one column of the board, or either of the two diagonals.

As an experienced programmer and someone who appreciates the value of functional abstraction, my natural inclination is to write the following auxiliary function:

    def isWin( board, token ):
        return    isRowWin( board, token ) \
               or isColumnWin( board, token ) \
               or isDiagonalWin( board, token )
And then go off and write the other three functions isRowWin, isColumnWin, and isDiagonalWin. And yes, I could write one big complicated expression involving lots of ands, ors, and indexes into the board. But I'd be much less sure that it was correct. Having broken it up into a series of simple functions, it's much easier to see that I'm doing it right.

Students often think that writing functions is a waste of time; they're wrong. Just the increase in clarity is well worth the effort.

Turning in the Assignment:

The program should be in a file named Project2.py. Submit the file via Canvas before the deadline shown at the top of this page. Submit it to the assignment project2 under the assignments sections by uploading your python file.

Your file must compile and run before submission. It must also contain a header with the following format:

# File: Project2.py
# Student: 
# UT EID:
# Course Name: CS303E
# 
# Date: 
# Description of Program: