Python Forum

Full Version: Tic-Tac game (Beginner's coding)
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
I have tried to code Tic-Tac game.
I think my code needs lots of optimization but can't figure that out.
FYI: I haven't studied maths/matrix after schooling that is 15years ago.
That's why I used list and dict operations to create this game.

def status_print(game):
    print(game[0])
    print(game[1])
    print(game[2])


new_game = [
    [111, 222, 333],
    [444, 555, 666],
    [777, 888, 999]
]
game_dict = {111: (0, 0), 222: (0, 1), 333: (0, 2),
             444: (1, 0), 555: (1, 1), 666: (1, 2),
             777: (2, 0), 888: (2, 1), 999: (2, 2)}

status_print(new_game)
result_pending = True
game = new_game.copy()
entry_count = 0
while result_pending or entry_count < 5:
    
    player_1 = int(input("Player 1, enter positional number of X: "))
    
    entry_count += 1
    x, y = game_dict.get(player_1)
    game[x].pop(y)
    game[x].insert(y, 'X')
    status_print(game)
    any_rowX = list((game[0].count('X'), game[1].count('X'), game[2].count('X')))
    column1 = list((game[0][0], game[1][0], game[2][0]))
    column2 = list((game[0][1], game[1][1], game[2][1]))
    column3 = list((game[0][2], game[1][2], game[2][2]))
    any_columnX = list((column1.count('X'), column2.count('X'), column3.count('X')))
    diagonal1 = list((game[0][0], game[1][1], game[2][2]))
    diagonal2 = list((game[2][0], game[1][1], game[0][2]))
    any_diagonalX = list((diagonal1.count('X'), diagonal2.count('X')))

    if 3 in any_rowX or 3 in any_columnX or 3 in any_diagonalX:
        print("Player 1 won (X-X-X)!!")
        print("Congratulations!!")
        break
    if entry_count == 5:
        print("Drawn")
        result_pending = False
        break
    
    player_2 = int(input("Player 2, enter positional number of O: "))

    x, y = game_dict.get(player_2)
    game[x].pop(y)
    game[x].insert(y, 'O')
    status_print(game)
    any_rowO = list((game[0].count('O'), game[1].count('O'), game[2].count('O')))
    column1 = list((game[0][0], game[1][0], game[2][0]))
    column2 = list((game[0][1], game[1][1], game[2][1]))
    column3 = list((game[0][2], game[1][2], game[2][2]))
    any_columnO = list((column1.count('O'), column2.count('O'), column3.count('O')))
    diagonal1 = list((game[0][0], game[1][1], game[2][2]))
    diagonal2 = list((game[2][0], game[1][1], game[0][2]))
    any_diagonalO = list((diagonal1.count('O'), diagonal2.count('O')))

    if 3 in any_rowO or 3 in any_columnO or 3 in any_diagonalO:
        print("Player 2 won (O-O-O)!!")
        print("Congratulations!!")
        break
print("Thank you for playing")
Your even little bit tip/suggestion is appreciated.
Thank you
Hi,

This seems to work.
What exactly do you want to fix?
Montesquieu said: better is the enemy of good. :-)

Paul
I tried to column1, 2, 3 and diagonal1, 2 variables in starting of while loop instead of repeating after each player's input entry.
But doing that, diagonal and column win condition never work out.
Go through this page. It will be helpful
I'm not an expert by any means, but here is my quick version of tic-tac-toe:
board = [[" ", " ", " "], [" ", " ", " "], [" ", " ", " "]]
lines = (((0,0), (0,1), (0,2)), ((1,0), (1,1), (1,2)), ((2,0), (2,1), (2,2)),
         ((0,0), (1,0), (2,0)), ((0,1), (1,1), (2,1)), ((0,2), (1,2), (2,2)),
         ((0,0), (1,1), (2,2)), ((0,2), (1,1), (2,0)))
players = ["X", "O"]

def print_board():
    for row in board:
        print(row)

def check_winner():
    for line in lines:
        piece = list(set([board[line[0][0]][line[0][1]], board[line[1][0]][line[1][1]], board[line[2][0]][line[2][1]]]))
        if len(piece) == 1 and piece[0] != ' ':
            return piece[0]
    return ' '

def tic_tac_toe():
    winner = ' '
    turn = 0
    while turn < 9:
        player = players[turn % 2]
        print_board()
        row = -1 # Python needs a do-while loop
        while row == -1 or board[row][column] != ' ':
            row = int(input("Select row: ")) - 1
            column = int(input("Select column: ")) - 1
        board[row][column] = player
        winner = check_winner()
        if winner != ' ':
            break
        turn += 1
    print_board()
    if winner == ' ':
        print("Draw")
    else:
        print("Winner:", winner)
        
tic_tac_toe()
I think mine's pretty optimized.

I do not understand the need for a dictionary and a list as on lines 7 & 12, and you repeat 29-36 on 53-60 with only one minor change. I would look to combine some of those to slim down your code and improve readability. Clues on how to do this are in my code.
I like your idea of using markers or keys to help the player make a selection, but I would make them characters instead of numbers. This makes it really easy to test if the input is valid.
board = ['1', '2', '3', '4', '5', '6', '7', '8', '9']
while not (choice := input(f'Place {marker} at ')) in board:
   print(f'{choice} is not a valid choice')
board[board.index(choice)] = marker
I see no reason to use rows and columns. The first row is board[0] through board[2]. The first column is board[0], board[3], board[6]. If you want to print the second row of the board it's as simple as
print(f'{board[3]} {board[4]} {board[5]}')
Do three prints and you have a board.
Output:
X|O|3 X|O|6 7|8|9 Place X at 7
Since there are only 8 possible ways to win tic-tac-toe, testing for a win is a managable if statement.
def check_win(board):
    return board[0] == board[1] == board[2] or \
           ...
           board[0] == board[3] == board[6] or \
           ...
           board[0] == board[4] == board[8] or \
           board[6] == board[4] == board[2]
And the most important thing to remember about tic-tac-toe is; there is only one player. I cannot think of any multi-player board games. There are games where multiple players take turns at the board, but all the games are single player games and in many of those games only the last player can win. Your game will ask players to place an 'X' or an 'O', but there should not be separate code for each player. The game should only care about the current player. Draw the board, ask where to place the marker, check for the win. Repeat 9 times or until one of the players win.