Search code examples
pythonpython-3.xfunctiontic-tac-toe

My tic tac toe game is working fine. But I am having trouble designing replay functionality in it once the 1st game is over?


I have designed a tic tac toe game and it is working fine when I play only a single game. But I am having trouble to implement replay functionality in it once 1st game is over successfully. I have declared player_position as global. It stores the values of the position of X and O after every move.

player_position={'X':[],'O':[]}

And I have made the tic tac toe table as follows:

def print_tic_tac_toe(values):
    print("\n")
    print("\t     |     |")
    print("\t  {}  |  {}  |  {}".format(values[0], values[1], values[2]))
    print('\t_____|_____|_____')

    print("\t     |     |")
    print("\t  {}  |  {}  |  {}".format(values[3], values[4], values[5]))
    print('\t_____|_____|_____')

    print("\t     |     |")

    print("\t  {}  |  {}  |  {}".format(values[6], values[7], values[8]))
    print("\t     |     |")
    print("\n")

Following is values variable defined and above function called:

values=[' ' for x in range(9)]
print_tic_tac_toe(values)

Then I have made the functions to check winning condition and draw condition after each move:

def winning_condition(player_position, current_player):
soln = [[0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6]]
for x in soln:
    if set(x).issubset(player_position[current_player]):
        return True
    
return False      
    
def draw_condition(player_position):
    if (len(player_position['X'])+len(player_position['O'])==9):
        return True
    
    return False

Following is the replay function which is the main problem I am facing and want to know how to call it in my main function:

def replay():
    play_again=input('Do you want to play again? y/n :')
    return (play_again=='y')

Following is the main function:

import random
def start_game():

toss=random.randint(0,1)
print ('Toss result is: ',toss)
if toss==0:
    current_player='X'
    print ('X will go first')
else:
    current_player='O'
    print ('O will go first')

while True:
    print_tic_tac_toe(values)
    print ('Enter your position player ', current_player)
    move=int(input())
    
    if move<0 or move>8:
        print('Position does not exist. Try again!!')
        continue
    
    if values[move]!=' ':
        print('Position already occupied. Try again!!')
        continue
    
    values[move]=current_player
    player_position[current_player].append(move)
    
    if winning_condition(player_position, current_player):      
        print_tic_tac_toe(values)
        print ('Congrats Player ', current_player, ' you have won the game')
        print ('\n')
        if not replay():
            print ('Game Ended')
            break
    
    if draw_condition(player_position):
        print_tic_tac_toe(values)
        print ('Game Drawn')
        print('\n')
        if not replay():
            print ('Game Ended')
            break
    
    if current_player=='X':
        current_player='O'
    else:
        current_player='X'

Now I know replay function will be called when I am checking winning_condition and draw_condition inside start_game function. But I don't know how. What I want is when I call replay function, it should give me an empty tic tac toe table and consequently remove all the values of X and O from player_position. Following is the way to clear values of X and O from player_position when the game has ended:

for k in player_position:
player_position[k]=[]

But I don't know how to use it and how to get an empty tic tac toe table after first game has finished. Any help to help me design replay functionality in this code will be highly appreciated. Thanks.


Solution

  • Okay so a few things got changed. I rewrote your board printing function because it was messy and I felt like cleaning it up. I used unicode box-drawing characters, which you can get here.

    Now the important stuff:

    1. the replay() function now ensures proper input from the user
    2. both checks for win/draw in the main gameplay loop now return the boolean from replay(), meaning that the start_game() function is exited
    3. the script now uses the if __name__ == "__main__" pattern, which you can read more about here
    4. the player_position and values variables are now entirely local to the start_game function's scope
    5. the player_position and values variables are now initialized at the top of start_game() so that when start_game() is called, a new game is created
    6. all interpolated strings now use f-strings instead of interpolation

    Now that you've got this under your belt, I'd suggest learning some basic OOP, and turning the game board into an object.

    import random
    
    
    def print_board(values):
        s = """
        \t . ┃ . ┃ .
        \t━━━╋━━━╋━━━
        \t . ┃ . ┃ .
        \t━━━╋━━━╋━━━
        \t . ┃ . ┃ .
        """
        print(s.replace(".", "{}").format(*values))
    
    
    def replay():
        while True:
            play_again = input("Do you want to play again? y/n :")
            if play_again.lower() in ["y", "n"]:
                return play_again.lower() == "y"
            print("Invalid input!")
    
    
    def winning_condition(player_position, current_player):
        soln = [[0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6]]
        for x in soln:
            if set(x).issubset(player_position[current_player]):
                return True
        return False      
    
    
    def draw_condition(player_position):
        if (len(player_position["X"]) + len(player_position["O"]) == 9):
            return True
        return False
    
    
    def start_game():
        player_position={"X": [], "O": []}
        values = [" " for x in range(9)]
        toss = random.randint(0, 1)
        print(f"Toss result is: {toss}")
    
        if toss == 0:
            current_player = "X"
        else:
            current_player = "O"
        print(f"{current_player} will go first")
    
        while True:
            print_board(values)
            move = int(input(f"Enter your position player {current_player}: "))
            
            if move < 0 or move > 8:
                print("Position does not exist. Try again!!")
                continue
            
            if values[move] != " ":
                print("Position already occupied. Try again!!")
                continue
            
            values[move] = current_player
            player_position[current_player].append(move)
    
            if winning_condition(player_position, current_player):      
                print_board(values)
                print(f"Congrats Player {current_player}, you have won the game!")
                return replay()
    
            elif draw_condition(player_position):
                print_board(values)
                print("Game Drawn!")
                return replay()
    
            if current_player == "X":
                current_player = "O"
            else:
                current_player = "X"
    
    
    if __name__ == "__main__":
        play_again = True
        while play_again:
            play_again = start_game()
        print("Thanks for playing!")
    

    Here's what the game board looks like now:

             X ┃ O ┃ X
            ━━━╋━━━╋━━━
             O ┃ O ┃ X
            ━━━╋━━━╋━━━
             O ┃ X ┃ O
    

    It looks less gappy in the Python REPL.