# tic-tac-toe This silly little repo showcases the stupid amount of effort I put into a python course. You can see in the full spec it just wanted me to write out four silly little functions, but that's not what I did. Because I was trying to be thorough and not hardcode anything. I ended up hardcoding the display and logic for who wins, along with poor detection for ties. Way way way more effort than it was worth and I don't even think it'll get accepted lol. ~~Plot twist: You didn't have to do it at all!!!~~ ## Running the program uhh...okay I guess? Just download `main.py` and run `py main.py` on Windows or `./main.py` on Linux ## The specific instructions
It did NOT tell me to make classes or anything, it just wanted simple programming ### Scenario Your task is to write **a simple program which pretends to play *tic-tac-toe* with the user**. To make it all easier for you, we've decided to simplify the game. Here are our assumptions: - the computer (i.e., your program) should play the game using `'X's`; - the user (e.g., you) should play the game using `'O'`s; - the first move belongs to the computer − it always puts its first `'X'` in the middle of the board; - all the squares are numbered row by row starting with `1` (see the example session below for reference) - the user inputs their move by entering the number of the square they choose − the number must be valid, i.e., it must be an integer, it must be greater than `0` and less than `10`, and it cannot point to a field which is already occupied; - the program checks if the game is over − there are four possible verdicts: the game should continue, the game ends with a tie, you win, or the computer wins; - the computer responds with its move and the check is repeated; - don't implement any form of artificial intelligence − a random field choice made by the computer is good enough for the game. The example session with the program may look as follows: ``` +-------+-------+-------+ | | | | | 1 | 2 | 3 | | | | | +-------+-------+-------+ | | | | | 4 | X | 6 | | | | | +-------+-------+-------+ | | | | | 7 | 8 | 9 | | | | | +-------+-------+-------+ Enter your move: 1 +-------+-------+-------+ | | | | | O | 2 | 3 | | | | | +-------+-------+-------+ | | | | | 4 | X | 6 | | | | | +-------+-------+-------+ | | | | | 7 | 8 | 9 | | | | | +-------+-------+-------+ +-------+-------+-------+ | | | | | O | X | 3 | | | | | +-------+-------+-------+ | | | | | 4 | X | 6 | | | | | +-------+-------+-------+ | | | | | 7 | 8 | 9 | | | | | +-------+-------+-------+ Enter your move: 8 +-------+-------+-------+ | | | | | O | X | 3 | | | | | +-------+-------+-------+ | | | | | 4 | X | 6 | | | | | +-------+-------+-------+ | | | | | 7 | O | 9 | | | | | +-------+-------+-------+ +-------+-------+-------+ | | | | | O | X | 3 | | | | | +-------+-------+-------+ | | | | | 4 | X | X | | | | | +-------+-------+-------+ | | | | | 7 | O | 9 | | | | | +-------+-------+-------+ Enter your move: 4 +-------+-------+-------+ | | | | | O | X | 3 | | | | | +-------+-------+-------+ | | | | | O | X | X | | | | | +-------+-------+-------+ | | | | | 7 | O | 9 | | | | | +-------+-------+-------+ +-------+-------+-------+ | | | | | O | X | X | | | | | +-------+-------+-------+ | | | | | O | X | X | | | | | +-------+-------+-------+ | | | | | 7 | O | 9 | | | | | +-------+-------+-------+ Enter your move: 7 +-------+-------+-------+ | | | | | O | X | X | | | | | +-------+-------+-------+ | | | | | O | X | X | | | | | +-------+-------+-------+ | | | | | O | O | 9 | | | | | +-------+-------+-------+ You won! ``` ### Requirements Implement the following features: - the board should be stored as a three-element list, while each element is another three-element list (the inner lists represent rows) so that all of the squares may be accessed using the following syntax: ``` board[row][column] ``` each of the inner list's elements can contain 'O', 'X', or a digit representing the square's number (such a square is considered free) the board's appearance should be exactly the same as the one presented in the example. implement the functions defined for you in the editor. Drawing a random integer number can be done by utilizing a Python function called `randrange()`. The example program below shows how to use it (the program prints ten random numbers from 0 to 8). [!NOTE] the `from-import` instruction provides access to the `randrange` function defined within an external Python module callled `random`. ```python from random import randrange for i in range(10): print(randrange(8)) ``` ```python def display_board(board): # The function accepts one parameter containing the board's current status # and prints it out to the console. def enter_move(board): # The function accepts the board's current status, asks the user about their move, # checks the input, and updates the board according to the user's decision. def make_list_of_free_fields(board): # The function browses the board and builds a list of all the free squares; # the list consists of tuples, while each tuple is a pair of row and column numbers. def victory_for(board, sign): # The function analyzes the board's status in order to check if # the player using 'O's or 'X's has won the game def draw_move(board): # The function draws the computer's move and updates the board. ```
Their solution ```python from random import randrange def display_board(board): print("+-------" * 3,"+", sep="") for row in range(3): print("| " * 3,"|", sep="") for col in range(3): print("| " + str(board[row][col]) + " ", end="") print("|") print("| " * 3,"|",sep="") print("+-------" * 3,"+",sep="") def enter_move(board): ok = False # fake assumption - we need it to enter the loop while not ok: move = input("Enter your move: ") ok = len(move) == 1 and move >= '1' and move <= '9' # is user's input valid? if not ok: print("Bad move - repeat your input!") # no, it isn't - do the input again continue move = int(move) - 1 # cell's number from 0 to 8 row = move // 3 # cell's row col = move % 3 # cell's column sign = board[row][col] # check the selected square ok = sign not in ['O','X'] if not ok: # it's occupied - to the input again print("Field already occupied - repeat your input!") continue board[row][col] = 'O' # set '0' at the selected square def make_list_of_free_fields(board): free = [] for row in range(3): # iterate through rows for col in range(3): # iterate through columns if board[row][col] not in ['O','X']: # is the cell free? free.append((row,col)) # yes, it is - append new tuple to the list return free def victory_for(board,sgn): if sgn == "X": # are we looking for X? who = 'me' # yes - it's computer's side elif sgn == "O": # ... or for O? who = 'you' # yes - it's our side else: who = None # we should not fall here! cross1 = cross2 = True # for diagonals for rc in range(3): if board[rc][0] == sgn and board[rc][1] == sgn and board[rc][2] == sgn: # check row rc return who if board[0][rc] == sgn and board[1][rc] == sgn and board[2][rc] == sgn: # check column rc return who if board[rc][rc] != sgn: # check 1st diagonal cross1 = False if board[2 - rc][2 - rc] != sgn: # check 2nd diagonal cross2 = False if cross1 or cross2: return who return None def draw_move(board): free = make_list_of_free_fields(board) # make a list of free fields cnt = len(free) if cnt > 0: this = randrange(cnt) row, col = free[this] board[row][col] = 'X' board = [ [3 * j + i + 1 for i in range(3)] for j in range(3) ] board[1][1] = 'X' # set first 'X' in the middle free = make_list_of_free_fields(board) human_turn = True # which turn is it now? while len(free): display_board(board) if human_turn: enter_move(board) victor = victory_for(board,'O') else: draw_move(board) victor = victory_for(board,'X') if victor != None: break human_turn = not human_turn free = make_list_of_free_fields(board) display_board(board) if victor == 'you': print("You won!") elif victor == 'me': print("I won") else: print("Tie!") ```