Search code examples
pythontic-tac-toe

TicTacToe Nobody wins AND overriding player's choices


I am a new programmer and i started learning python and wanted to learn to code a tic tac toe game.

The game goes on but the winning conditions and computer field selection do not work properly: it doesn't know when to stop playing and sometimes the computer selects an already selected field, thus overriding my choice (if i try to do the same, i get a ValueError).

For the win algorithm, i didn't want to go through all options by hand, so i used sets. I created a set with all winning conditions. While iterating on each subset (rows, cols and diagonals) i check if this is a subset of player/computer positions.

Problem is: it doesn't work. If i try to do anything i get a ValueError: list.remove(x) x not in list. I get this error sometimes on the line where the playerChoice gets removed, or the one from the computer. Another problem as stated above is that the computer can override my choice.

I think the problem lies on removing elements from one set and adding them to the other, but i can't find a way to get around this

Here is the code:

import random

board = [" ", " ", " ", " ", " ", " ", " ", " ", " "]
playerSymbol = ""
playerPosition = []
aiSymbol = ""
aiPosition = []
possiblePositions = [0, 1, 2, 3, 4, 5, 6, 7, 8]
turn = 0


def drawBoard():
    print(board[0] + " | " + board[1] + " | " + board[2])
    print("___" + "___" + "___")
    print(board[3] + " | " + board[4] + " | " + board[5])
    print("___" + "___" + "___")
    print(board[6] + " | " + board[7] + " | " + board[8])


def choice():
    global playerSymbol
    global aiSymbol

    answer = input("What do you want to play as? (type x or o) ")

    if answer.upper() == "X":
        playerSymbol = "X"
        aiSymbol = "O"
    else:
        playerSymbol = "O"
        aiSymbol = "X"


def won():
    winningPositions = [{0, 1, 2}, {3, 4, 5}, {6, 7, 8}, {0, 4, 8}, {2, 4, 6}, {0, 3, 6}, {1, 4, 7}, {2, 5, 8}]

    for position in winningPositions:
        if position.issubset(playerPosition):
            print("Player Wins :)")
            return True
        elif position.issubset(aiPosition):
            print("AI wins :(")
            return True
        else:
            return False


def play():
    global turn
    choice()

    while not won():
        if turn % 2 == 0:
            pos = int(input("Where would you like to play? (0-8) "))
            possiblePositions.remove(pos)
            playerPosition.append(pos)
            board[pos] = playerSymbol
            turn += 1
            drawBoard()
        else:
            aiTurn = random.randint(0, len(possiblePositions) - 1)
            possiblePositions.remove(possiblePositions[aiTurn])
            aiPosition.append(aiTurn)
            board[aiTurn] = aiSymbol
            turn += 1
            print("\n")
            print("\n")
            drawBoard()
    else:
        print("Thanks for playing :)")


play()

I am open to all sorts of suggestions and ways to improve my code. Thanks in advance and stay healthy, Kristi


Solution

  • Two things:

    1. In AI's turn, you're generating "upto the length of available positions". You need to generate "One of available positions".

    Change these lines:

        aiTurn = random.randint(0, len(possiblePositions) - 1)
        possiblePositions.remove(possiblePositions[aiTurn])
    

    to

        aiTurn = random.choice(possiblePositions)
        possiblePositions.remove(aiTurn)
    
    1. In won(), you need to iterate over every possible combination until a comparision eveluates to True. However, you return either true or false after just the first comparision. Move the return False outside the loop:

    Change

        for position in winningPositions:
            if position.issubset(playerPosition):
                print("Player Wins :)")
                return True
            elif position.issubset(aiPosition):
                print("AI wins :(")
                return True
            else:
                return False
    

    to

        for position in winningPositions:
            if position.issubset(playerPosition):
                print("Player Wins :)")
                return True
            elif position.issubset(aiPosition):
                print("AI wins :(")
                return True
    
        return False