So I have got this Python code for my TicTacToe. Everything is working normal except when there is no winner the program must return 'Tie' and instead it just continues asking for X and O even if the board is already filled. I'm assuming the problem is in the check_if_tie() function but I can't figure it out.
# -------Global variables--------
# If game is still going
game_still_going = True
# Who won? Or tie
winner = None
# Whose turn it is
current_player = 'X'
# The board displaying function
board = [' '] * 10
def display_board():
print(' ' + board[6] + ' | ' + board[7] + ' | ' + board[8])
print('---+-' '--+--- ')
print(' ' + board[3] + ' | ' + board[4] + ' | ' + board[5])
print('---+-' '--+--- ')
print(' ' + board[0] + ' | ' + board[1] + ' | ' + board[2])
# Checks if game is over
def check_if_game_over():
check_if_tie()
check_if_win()
# Checks if there is a winner
def check_if_win():
global winner
if check_row():
winner = check_row()
elif check_columns():
winner = check_columns()
elif check_diagonals():
winner = check_columns()
else:
winner = None
return
def check_row():
global game_still_going
row1 = board[6] == board[7] == board[8] != " "
row2 = board[3] == board[4] == board[5] != " "
row3 = board[0] == board[1] == board[2] != " "
if row1 or row2 or row3:
game_still_going = False
if row1:
return board[6]
elif row2:
return board[3]
elif row3:
return board[0]
return
def check_columns():
global game_still_going
column1 = board[6] == board[3] == board[0] != " "
column2 = board[7] == board[4] == board[1] != " "
column3 = board[8] == board[5] == board[2] != " "
if column1 or column2 or column3:
game_still_going = False
if column1:
return board[6]
elif column2:
return board[7]
elif column3:
return board[8]
return
def check_diagonals():
global game_still_going
diagonal1 = board[6] == board[4] == board[2] != " "
diagonal2 = board[0] == board[4] == board[8] != " "
if diagonal1 or diagonal2:
game_still_going = False
elif diagonal1:
return board[6]
elif diagonal2:
return board[0]
return
def check_if_tie():
global game_still_going
if ' ' not in board:
game_still_going = False
return
def flip_player():
global current_player
if current_player == 'X':
current_player = 'O'
elif current_player == 'O':
current_player = 'X'
return
# Whose turn it is to play
def handle_turn(player):
print(player + "'s turn")
position = int(input('Please write your position from 1 - 9: ')) - 1
if position not in [0,1,2,3,4,5,6,7,8,9]:
return input('Invalid position. Please write 1-9: ')
board[position] = player
display_board()
# Main gameplay function
def play_game():
global winner
# Displays initial board
display_board()
# Loop running the game
while game_still_going:
handle_turn(current_player)
flip_player()
check_if_game_over()
if winner == 'X' or winner == 'O':
print(winner + ' won.')
elif winner:
print('Tie')
play_game()
You're having quite a lot of issues in this code and most of the problem could be avoided by avoiding the use of globals.
When you use globals you change a global state that makes it difficult to understand what's going on. You have functions that return nothing but change state that will make the game end or not.
One simple change would be to have you check_
method return an actual boolean and use that value in the loop to check if you have a tie or a win.
If you're not in a tie or a win, it means the game isn't finished. So you don't need to store a global value and certainly do not have to modify the state of the is a tie or a win anywhere else.
Keep you functions as simple as possible. I often say that but think how you actually play a game.
In a game you have 2 players and 1 board, in which you set values anywhere.
Each turn adds a piece until the game ends in a tie or a win.
Everytime you add a piece you can check the state of the game. If it's not finished then you can swith the current player and enter a new piece and repeat.
None of this requires a global state and you can always pass the game board to your methods...
In your case it would be as simple as doing this:
def is_tie():
return ' ' not in board
def is_win():
... is_win logic
return result
while not is_tie() or not is_win():
... game logic
To go a step further, instead of having globals you'd have to pass the game state as arugment like this:
def is_tie(game):
return ' ' not in game.board
And to go a step further, entering a new piece in the board would return a new state. So instead of modifying the current state you'd have a main loop that looks like this:
game = Game()
while True:
position = game.prompt_choice()
if not game.position_available(position)
# loop again to select a new position
continue
game = game.execute_turn(position)
if game.is_done()
break
else:
# if game not done switch player and move to next turn
game = game.switch_player()
# current game player is winner
game.print_winner()
The cool thing is that if you wanted to "replay" the game, you'd just have to save the state of the game just before looping again. each "game" being returned is a modified version of the previous game object so you're never modifying the actual object.