Tic Tac Toe AI recursing infinitely and not following rules - python

I'm not that new to programming, but I haven't tried making too many things without following a tutorial before. This is my first attempt at a REAL project without following a video or copy-pasting code. I created a simple tic tac toe game, it works fine if both players manually choose positions, but when I tried to implement a simple AI using the minimax algorithm, it will play all of the AI moves at once and I have no idea why.
I reviewed the code so many times but I can't figure out why the AI can keep placing pieces/making moves when the player can only make 1 move. According to the code, only 1 move at a time should be allowed. What is going on? When it gets to the AI's turn, the AI places pieces until it wins, no regard for turn or anything. Player pieces are placed too, which is strange because Player needs to be prompted for selection input. I think the problem lies in the minimax function itself, but I can't pinpoint where. Any help would be greatly appreciated! Thank you so much. Full file:
import random
from time import sleep
from math import inf
PLAYER = 0
AI = 1
BOARD = [[' ', ' ', ' '],
[' ', ' ', ' '],
[' ', ' ', ' ']]
#AVAILABLE = [[0,0],[0,1],[0,2],[1,0],[1,1],[1,2],[2,0],[2,1],[2,2]]
AVAILABLE = [1,2,3,4,5,6,7,8,9]
SELECTION = 0
TURN = random.randint(0, 1)
def display_board(board):
print(f'\t[{board[0][0]}] [{board[0][1]}] [{board[0][2]}]\n\t[{board[1][0]}] [{board[1][1]}] [{board[1][2]}]\n\t[{board[2][0]}] [{board[2][1]}] [{board[2][2]}]')
def convert_position(available_locations, position):
if position in available_locations:
available_locations.remove(position)
position -= 1
converted = (position // 3, position % 3)
return converted
def is_valid_location(board):
pass
def place_piece(board, position, player):
a, b = position
if a in [0, 1, 2] and b in [0, 1, 2]:
if board[a][b] == ' ' and player == PLAYER:
board[a][b] = 'X'
if board[a][b] == ' ' and player == AI:
board[a][b] = 'O'
def clear_board(board):
board = [[' ', ' ', ' '],
[' ', ' ', ' '],
[' ', ' ', ' ']]
return board
def is_win_player(board):
if board[0][0] != ' ' and board[0][1] == board[0][0] and board[0][2] == board[0][0]:
if board[0][0] == 'X':
return True
if board[1][0] != ' ' and board[1][1] == board[1][0] and board[1][2] == board[1][0]:
if board[1][0] == 'X':
return True
if board[2][0] != ' ' and board[2][1] == board[2][0] and board[2][2] == board[2][0]:
if board[2][0] == 'X':
return True
if board[0][0] != ' ' and board[1][1] == board[0][0] and board[2][2] == board[0][0]:
if board[0][0] == 'X':
return True
if board[2][0] != ' ' and board[1][1] == board[2][0] and board[0][2] == board[2][0]:
if board[2][0] == 'X':
return True
if board[0][0] != ' ' and board[1][0] == board[0][0] and board[2][0] == board[0][0]:
if board[0][0] == 'X':
return True
if board[0][1] != ' ' and board[1][1] == board[0][1] and board[2][1] == board[0][1]:
if board[0][1] == 'X':
return True
if board[0][2] != ' ' and board[1][2] == board[0][2] and board[2][2] == board[0][2]:
if board[0][2] == 'X':
return True
def is_win_ai(board):
if board[0][0] != ' ' and board[0][1] == board[0][0] and board[0][2] == board[0][0]:
if board[0][0] == 'O':
return True
if board[1][0] != ' ' and board[1][1] == board[1][0] and board[1][2] == board[1][0]:
if board[1][0] == 'O':
return True
if board[2][0] != ' ' and board[2][1] == board[2][0] and board[2][2] == board[2][0]:
if board[2][0] == 'O':
return True
if board[0][0] != ' ' and board[1][1] == board[0][0] and board[2][2] == board[0][0]:
if board[0][0] == 'O':
return True
if board[2][0] != ' ' and board[1][1] == board[2][0] and board[0][2] == board[2][0]:
if board[2][0] == 'O':
return True
if board[0][0] != ' ' and board[1][0] == board[0][0] and board[2][0] == board[0][0]:
if board[0][0] == 'O':
return True
if board[0][1] != ' ' and board[1][1] == board[0][1] and board[2][1] == board[0][1]:
if board[0][1] == 'O':
return True
if board[0][2] != ' ' and board[1][2] == board[0][2] and board[2][2] == board[0][2]:
if board[0][2] == 'O':
return True
def score_eval(board):
for row in range(0, 3):
if board[row][0] == board[row][1] and board[row][1] == board[row][2]:
if board[row][0] == 'O':
return 10
if board[row][0] == 'X':
return -10
for col in range(0, 3):
if board[0][col] == board[1][col] and board[1][col] == board[2][col]:
if board[row][0] == 'O':
return 10
if board[row][0] == 'X':
return -10
if board[0][0] == board[1][1] and board[1][1] == board[2][2]:
if board[0][0] == 'O':
return 10
if board[0][0] == 'X':
return -10
if board[2][0] == board[1][1] and board[1][1] == board[0][2]:
if board[2][0] == 'O':
return 10
if board[2][0] == 'X':
return -10
def is_tie(board):
counter = 0
for array in board:
for index in array:
if index == ' ':
counter += 1
if counter == 0:
return True
def is_terminal(board):
return is_tie(board) or is_win_player(board) or is_win_ai(board)
def minimax(board, depth, maximizingPlayer, available_positions):
valid_locations = available_positions
print(valid_locations)
terminal = is_terminal(board)
if depth == 0 or terminal:
if terminal:
if is_win_ai(board):
return None, 99999999
if is_win_player(board):
return None, -99999999
if is_tie(board):
return None, 1
else:
return None, score_eval(board)
if maximizingPlayer:
value = -inf
selection = random.choice(valid_locations)
for num in valid_locations:
board_copy = board.copy()
position = convert_position(valid_locations, num)
place_piece(board_copy, position, AI)
new_score = minimax(board_copy, depth-1, False, valid_locations)[1]
if new_score > value:
value = new_score
selection = num
return selection, value
else:
value = inf
selection = random.choice(valid_locations)
for num in valid_locations:
board_copy = board.copy()
position = convert_position(valid_locations, num)
place_piece(board_copy, position, PLAYER)
new_score = minimax(board_copy, depth-1, True, valid_locations)[1]
if new_score < value:
value = new_score
selection = num
return selection, value
while SELECTION != 'QUIT':
print('\t< Tic Tac Toe >\n')
print('\tPlease make a selection:')
print("\t'PLAY' to play a game")
print("\t'QUIT' to exit application\n")
SELECTION = input('> ').upper()
if SELECTION != 'QUIT' and SELECTION != 'PLAY':
print(SELECTION)
print('Please enter a valid selection.')
elif SELECTION == 'PLAY':
game_over = False
while not game_over:
display_board(BOARD)
if is_tie(BOARD):
print('Tie game. No winner.')
input('Press any key to continue...')
game_over = True
elif TURN == PLAYER:
print("Player's turn!")
position = int(input('Please enter a number 1 - 9 to make a mark: '))
selection = convert_position(AVAILABLE, position)
place_piece(BOARD, selection, PLAYER)
if is_win_player(BOARD):
print('Player has won the game!')
display_board(BOARD)
game_over = True
elif TURN == AI:
print("AI's turn!")
sleep(0.9)
x, y = minimax(BOARD, 7, True, AVAILABLE) #x = position, y = score
selection = convert_position(AVAILABLE, x)
place_piece(BOARD, selection, AI)
if is_win_ai(BOARD):
print('AI has won the game!')
display_board(BOARD)
game_over = True
TURN += 1
TURN = TURN % 2
print(AVAILABLE)
BOARD = clear_board(BOARD)
AVAILABLE = [1,2,3,4,5,6,7,8,9]

One of the possible culprits is the bit which attempts to "clone" the board in your minimax function:
board_copy = board.copy()
In Python, list.copy method returns a shallow copy of a list, which is essentially a new list with 3 elements which are references to the "rows" in your original board. Try using copy.deepcopy() documentation
import copy
...
board_copy = copy.deepcopy(board)

Related

Why does my TicTacToe code fail to detect is someone has won? Python 3

I recently took it upon myself to try and code a TicTacToe board in order to test my understanding of the concepts I learned online. However, I encountered a few problems within my code and do not understand why it doesn't work as intended.
While attempting to get the code to print a winner, my code does not work as intended and does not choose a winner based on the values I have inputted. Sometimes the code runs and a winner is detected two turns after someone has already won, and sometimes it exits the code without a 5th move having even been played.
Below is the code I worked on. It includes insurance that you cannot input an X or an O in a position that has already been taken up and prints the Xs and Os where the players choose. I believe that the errors take place somewhere in the row(), column(), and diagonal() parts of the code.
player = 0
player_add = 1
winner = None
already_taken = []
turns_taken = 0
board = [
"-", "-", "-",
"-", "-", "-",
"-", "-", "-"
]
def handle_turn(turn, turn_add):
while turn % 2 == 0:
position = int(input("Choose a position from 1-9 to add an \"X\": ")) - 1
already_taken.append(position)
board[position] = "X"
turn += turn_add
display_board()
while already_taken.count(position) > 1:
print("Position already taken.")
board[position] = "O"
display_board()
already_taken.remove(position)
turn += turn_add
while turn % 2 == 1:
position = int(input("Choose a position from 1-9 to add an \"O\": ")) - 1
already_taken.append(position)
board[position] = "O"
turn += turn_add
display_board()
while already_taken.count(position) > 1:
print("Position already taken.")
board[position] = "X"
display_board()
already_taken.remove(position)
turn += turn_add
def display_board():
print(board[0] + "|" + board[1] + "|" + board[2])
print(board[3] + "|" + board[4] + "|" + board[5])
print(board[6] + "|" + board[7] + "|" + board[8])
def play_game():
display_board()
handle_turn(player, player_add)
def rows():
global running
if board[0] and board[1] and board[2] == board[0] and board[0] != "-":
running = False
return board[0]
if board[3] and board[4] and board[5] == board[3] and board[3] != "-":
running = False
return board[3]
if board[6] and board[7] and board[8] == board[6] and board[6] != "-":
running = False
return board[6]
return
def columns():
global running
if board[0] and board[3] and board[6] == board[0] and board[0] != "-":
running = False
return board[0]
if board[1] and board[4] and board[7] == board[1] and board[1] != "-":
running = False
return board[3]
if board[2] and board[5] and board[8] == board[2] and board[2] != "-":
running = False
return board[6]
return
def diagonals():
global running
if board[0] and board[4] and board[8] == board[0] and board[0] != "-":
running = False
return board[0]
if board[2] and board[4] and board[6] == board[2] and board[2] != "-":
running = False
return board[3]
return
def check_if_win():
global winner
# Rows
row_winner = rows()
# Columns
column_winner = columns()
# Diagonals
diagonal_winner = diagonals()
if row_winner:
winner = row_winner
elif column_winner:
winner = column_winner
elif diagonal_winner:
winner = diagonal_winner
else:
winner = None
def check_if_game_over():
check_if_win()
running = True
while running:
play_game()
check_if_game_over()
if winner == "X":
print("Player " + str(winner) + " has won!")
elif winner == "O":
print("Player " + str(winner) + " has won!")
elif winner is None:
print("Whoops! Looks like you both loose.")
'''
You almost got it right, but you made a typo:
if board[0] and board[3] and board[6] == board[0] and board[0] != "-":
This should be:
if board[0] == board[3] and board[6] == board[0] and board[0] != "-":
I would say, if you fix all of those. It may work - at least a little bit better.
Hope this taught you not to copy-paste code too much, as you can easily copy the same mistake over and over again.
So, what happened? Well, if you have if(board[0] and board[3]) like you did, it checks if board[0] evaluates to true and the same for board[3]. The way true and false is implemented is that false = 0, and true is just the opposite of false: true = !false. So, what you were checking for was pretty much, "is board[0] zero?" No, so that is true. So, no wonder that you were confused.

Why does my tic tac toe minimax algortihm not work?

I was trying to develop a minimax algorithm for the game tic tac toe. I don't understand why my tic tac toe algorithm doesn't work. The board variable is set up as an array and works like an x and y plane. I would really appreciate it if you could take a look at my code and help me fix any errors I might have. I was looking into getting into AI but I can't really do that if I can't even master this so I'd be really grateful for any time spent on trying to fix my errors.
import copy
def get_o_win(board):
if (
board[0][0] == board[0][1] == board[0][2] == "o"
or board[1][0] == board[1][1] == board[1][2] == "o"
or board[2][0] == board[2][1] == board[2][2] == "o"
or board[0][0] == board[1][0] == board[2][0] == "o"
or board[0][1] == board[1][1] == board[2][1] == "o"
or board[0][2] == board[1][2] == board[2][2] == "o"
or board[0][0] == board[1][1] == board[2][2] == "o"
or board[2][0] == board[1][1] == board[0][2] == "o"
):
return True
else:
return False
def get_x_win(board):
if (
board[0][0] == board[0][1] == board[0][2] == "x"
or board[1][0] == board[1][1] == board[1][2] == "x"
or board[2][0] == board[2][1] == board[2][2] == "x"
or board[0][0] == board[1][0] == board[2][0] == "x"
or board[0][1] == board[1][1] == board[2][1] == "x"
or board[0][2] == board[1][2] == board[2][2] == "x"
or board[0][0] == board[1][1] == board[2][2] == "x"
or board[2][0] == board[1][1] == board[0][2] == "x"
):
return True
else:
return False
def AI_Turn(board):
turn = 0
for _ in board:
for __ in _:
if __ != "n":
turn +=1
print('turn: '.join(str(turn)))
o_win = get_o_win(board)
x_win = get_x_win(board)
if o_win: # PLAYER WINS
return (-1, None)
elif x_win: # AI WINS
return (1, None)
elif turn == 9: #TIE
return (0, None)
else:
if turn%2==0: # Player's Turn
for x in range(3):
for y in range(3):
best = (0, None)
board_copy = copy.deepcopy(board)
if board_copy[x][y] == "n":
board_copy[x][y] = "o"
print('User Trying:')
print ([''.join(['{:3}'.format(item) for item in row]) for row in board_copy])
temporary_score_tuple = AI_Turn(board_copy)
best_score = best[0]
temporary_score = temporary_score_tuple[0]
if temporary_score > best_score:
best = (temporary_score,[x,y])
return best
else: # AI's Turn
for x in range(3):
for y in range(3):
best = (0, None)
board_copy = copy.deepcopy(board)
if board_copy[x][y] == "n":
board_copy[x][y] = "x"
print('AI Trying:')
print ([''.join(['{:3}'.format(item) for item in row]) for row in board_copy])
temporary_score_tuple = AI_Turn(board_copy)
best_score = best[0]
temporary_score = temporary_score_tuple[0]
if temporary_score > best_score:
best = (temporary_score,[x,y])
return best
# n means that there's nothing in that spot
# o means that there is an o in that spot
# x means that there is an x in that spot
# You can alter this board to make it look it look like whatever you need...
board = [['o','x','o'],['x','x','n'],['o','n','n']]
print(AI_Turn(board))

Loop To Change Value In Matrix for Tic Tac Toe Game?

Im making a Tic Tac Toe game and I do have working code and it does what I want it to do so far. I was just wondering if there was a way to shorten this function at all. My code is as follows...
def EnterMove(board):
move = input("Enter your move (number between 1 - 9): ")
if move == '1':
board[0][0] = 'O'
elif move == '2':
board[0][1] = 'O'
elif move == '3':
board[0][2] = 'O'
elif move == '4':
board[1][0] = 'O'
elif move == '5':
board[1][1] = 'O'
elif move == '6':
board[1][2] = 'O'
elif move == '7':
board[2][0] = 'O'
elif move == '8':
board[2][1] = 'O'
elif move == '9':
board[2][2] = 'O'
#Making the playing board
board = []
for i in range(3):
row = [Empty for i in range(3)]
board.append(row)
board[0][0] = '1'
board[0][1] = '2'
board[0][2] = '3'
board[1][0] = '4'
board[1][1] = '5'
board[1][2] = '6'
board[2][0] = '7'
board[2][1] = '8'
board[2][2] = '9'
So like I said this all works just fine for what I want it to do so far, I was just wondering if there was an easier way to build the board and build the EnterMove function. Thanks so much.
(Note: The player move is going to be "O's" while the computer's will be "X's" and I'm just going to us pretty much the same code for the player move function, but just use str(random.randint(1,9)) for it to decided the computer's move)
You can use division and modulo to obtain the rows and columns instead:
def EnterMove(board):
move = int(input("Enter your move (number between 1 - 9): ")) - 1
board[move // 3][move % 3] = 'O'
board = []
for i in range(3):
row = [Empty for i in range(3)]
board.append(row)
for i in range(9):
board[i // 3][i % 3] = str(i + 1)

How to avoid multiple `elif` statements?

So, I was trying to make a basic Tic-Tac-Toe game with python, And I created one which works perfectly fine, but my code is not so good, as it has a lot of code for checking the list indexes(Winner Of The Game), which kinda bothers me. So, How I avoid using the left index for checking the winner of the game?
My Code:
board = [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']
def show_board():# for showing the tic-tac-toe board
print(' | ' + str(board[0]) + ' | ' +
str(board[1]) + ' | ' + str(board[2]) + ' | ')
print(' | ' + str(board[3]) + ' | ' +
str(board[4]) + ' | ' + str(board[5]) + ' | ')
print(' | ' + str(board[6]) + ' | ' +
str(board[7]) + ' | ' + str(board[8]) + ' | ')
def main():
one = 1
flag = 1
show_board()
while one == 1:
if flag == 1:
x_o = 'X'
if flag == 2:
x_o = 'O'
pos = int(input('Player "' + x_o + '" Turn: '))
if x_o == 'o':
x_o = 'O'
if x_o == 'x':
x_o = 'X'
if board[pos - 1] == 'O' or board[pos - 1] == 'O':
print('That Place Is Already Filled By Player "0"')
if board[pos - 1] == 'X' or board[pos - 1] == 'X':
print('That Place Is Already Filled By Player "X"')
else:
try:
board[pos - 1] = x_o
except IndexError:
print('Type Numbers Between Only 1 And 9')
if flag == 1:
flag = 2
elif flag == 2:
flag = 1
show_board()
# Checking The Winner Of The Game
# for horizontal X
if board[0] == board[1] == board[2] == 'X':
one = 2
print('The Winner Is Player "X"!')
elif board[3] == board[4] == board[5] == 'X':
one = 2
print('The Winner Is Player "X"!')
elif board[6] == board[7] == board[8] == 'X':
one = 2
print('The Winner Is Player "X"!')
# for Daigonal X
elif board[0] == board[4] == board[8] == 'X':
one = 2
print('The Winner Is Player "X"!')
elif board[2] == board[4] == board[6] == 'X':
one = 2
print('The Winner Is Player "X"!')
# for Vertical X
elif board[1] == board[4] == board[7] == 'X':
one = 2
print('The Winner Is Player "X"!')
elif board[2] == board[5] == board[8] == 'X':
one = 2
print('The Winner Is Player "X"!')
elif board[0] == board[3] == board[6] == 'X':
one = 2
print('The Winner Is Player "X"!')
# for horizontal O
elif board[0] == board[1] == board[2] == 'O':
one = 2
print('The Winner Is Player "O"!')
elif board[3] == board[4] == board[5] == 'O':
one = 2
print('The Winner Is Player "O"!')
elif board[6] == board[7] == board[8] == 'O':
one = 2
print('The Winner Is Player "O"!')
# for Diagonal O
elif board[0] == board[4] == board[8] == 'O':
one = 2
print('The Winner Is Player "O"!')
elif board[2] == board[4] == board[6] == 'O':
one = 2
print('The Winner Is Player "O"!')
# for Vertical 0
elif board[1] == board[4] == board[7] == 'O':
one = 2
print('The Winner Is Player "O"!')
elif board[2] == board[5] == board[8] == 'O':
one = 2
print('The Winner Is Player "O"!')
elif board[0] == board[3] == board[6] == 'O':
one = 2
print('The Winner Is Player "O"!')
elif board[0] != ' ' and board[1] != ' ' and board[2] != ' ' and board[3] != ' ' and board[4] != ' ' and board[5] != ' ' and board[6] != ' ' and board[7] != ' ' and board[8] != ' ':
print('The Match Is A Tie!')
one = 2
main()
So, as you can see I'm using a lot of if statements for checking the winner of the game. How can I avoid that and do it in fewer lines.
You can replace them with some loops like:
board = [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']
def show_board():# for showing the tic-tac-toe board
print(' | ' + str(board[0]) + ' | ' +
str(board[1]) + ' | ' + str(board[2]) + ' | ')
print(' | ' + str(board[3]) + ' | ' +
str(board[4]) + ' | ' + str(board[5]) + ' | ')
print(' | ' + str(board[6]) + ' | ' +
str(board[7]) + ' | ' + str(board[8]) + ' | ')
def main():
one = 1
flag = 1
show_board()
while one == 1:
if flag == 1:
x_o = 'X'
if flag == 2:
x_o = 'O'
pos = int(input('Player "' + x_o + '" Turn: '))
if x_o == 'o':
x_o = 'O'
if x_o == 'x':
x_o = 'X'
if board[pos - 1] == 'O' or board[pos - 1] == 'O':
print('That Place Is Already Filled By Player "0"')
if board[pos - 1] == 'X' or board[pos - 1] == 'X':
print('That Place Is Already Filled By Player "X"')
else:
try:
board[pos - 1] = x_o
except IndexError:
print('Type Numbers Between Only 1 And 9')
if flag == 1:
flag = 2
elif flag == 2:
flag = 1
show_board()
# Checking The Winner Of The Game
won = False
for turn in ('X', 'O'):
# horizontal
if not won:
for i in (0, 3, 6):
if all(board[i + k] == turn for k in range(3)):
won = True
break
# vertical
if not won:
for i in range(3):
if all(board[i + k] == turn for k in (0, 3, 6)):
won = True
break
# diagonal
if not won:
if all(board[k] == turn for k in (0, 4, 8)) or \
all(board[k] == turn for k in (2, 4, 6)):
won = True
# handle winning
if won:
one = 2
print(f'The Winner Is Player "{turn}"!')
break
# handle a tie
if not won and all(square != ' ' for square in board):
one = 2
print('The Match Is A Tie!')
main()
(You can probably also polish/simplify the rest of the code quite a bit)
EDIT
Here is some similar code simplified / polished / expanded to:
handle boards of arbitrary sizes
correctly handle non-numerical input
use more functions
get rid of redundant variables
NUM_ROWS = 3
NUM_COLS = 3
NUM_WIN = 3
BOARD_SIZE = NUM_ROWS * NUM_COLS
EMPTY = ' '
BOARD = [EMPTY] * BOARD_SIZE
TURNS = 'X', 'O'
def show_board(board):
"""Show the tic-tac-toe board."""
for i in range(0, BOARD_SIZE, NUM_COLS):
print(' | ' + ' | '.join(board[i:i + NUM_COLS]) + ' | ')
def ij(i, j):
"""Convert (row, col) to board index."""
return i + NUM_COLS * j
def check_winner(board, turn):
"""Check if there is a winner."""
# horizontal
for i in range(NUM_ROWS):
for j in range(NUM_COLS - NUM_WIN + 1):
if all(board[ij(i, j + k)] == turn for k in range(NUM_WIN)):
return True
# vertical
for i in range(NUM_ROWS - NUM_WIN + 1):
for j in range(NUM_COLS):
if all(board[ij(i + k, j)] == turn for k in range(NUM_WIN)):
return True
# diagonal
for i in range(NUM_ROWS - NUM_WIN + 1):
for j in range(NUM_COLS - NUM_WIN + 1):
K = NUM_WIN
if all(board[ij(i + k, j + k)] == turn for k in range(NUM_WIN)):
return True
if all(board[ij(i + NUM_WIN - k - 1, j + k)] == turn
for k in range(NUM_WIN)):
return True
def check_tie(board):
"""Check if tie."""
return all(square != EMPTY for square in board)
def next_turn(turn):
"""Advance to next turn."""
return TURNS[(TURNS.index(turn) + 1) % 2]
def main():
"""Tic-tac-toe game."""
turn = TURNS[0]
show_board(BOARD)
while True:
valid_input = False
while not valid_input:
try:
choice = int(input(f'Player `{turn}` turn: '))
valid_input = (1 <= choice <= BOARD_SIZE)
if not valid_input:
raise ValueError
except ValueError:
print(f'Type numbers between 1 and {BOARD_SIZE} only.')
else:
idx = choice - 1
if BOARD[idx] != EMPTY:
print(f'Position `{idx}` already taken by `{BOARD[idx]}`')
else:
BOARD[idx] = turn
show_board(BOARD)
won = check_winner(BOARD, turn)
if won:
print(f'The winner is player `{turn}`!')
break
# handle a tie
if not won and check_tie(BOARD):
print('The match is a tie!')
break
turn = next_turn(turn)
if __name__ == '__main__':
main()
Please check mnk-game's source code for a similar implementation using NumPy and classes (especially Board.py). DISCLAIMER: I am the author of the package.
EDIT 2
Note that for tic-tac-toe only, check_winner() could be shortend using an approach similar to what #rusu_ro1 proposed :
WIN_CASES = [
[0, 1, 2], [3, 4, 5], [6, 7, 8], # horizontal
[0, 3, 6], [1, 4, 7], [2, 5, 8], # vertical
[0, 4, 8], [2, 4, 6], # diagonal
]
def check_winner(board, turn, win_cases=WIN_CASES):
"""Check if there is a winner."""
for win_case in win_cases:
if all(board[i] == turn for i in win_case):
return True
import random as rnd
size = 3
## random board to test
board = [[rnd.choice(["X", "O"]) for _ in range(size)] for _ in range(size)]
print(board)
def check_winner(board):
for mark in ["X", "O"]:
## count mark in all rows
count_in_rows = [row.count(mark) for row in board]
## count mark in all columns
count_in_columns = [ [board[row_n][col_n] for row_n in range(size)].count(mark) for col_n in range(size)]
## count mark in fwd diagonal
count_in_diag = [[board[i][i] for i in range(size)].count(mark)]
## count in backward diagonal
count_in_diag.append([board[i][size-i-1] for i in range(size)].count(mark))
print((count_in_rows + count_in_columns + count_in_diag))
## if there is 3 count of mark in any rows, columns or diagonal
if 3 in (count_in_rows + count_in_columns + [count_in_diag]):
print(f"winner is {mark}")
return mark
return
check_winner(board)
you can definition o_list =['o', 'o', 'o'] and x_list = ['x', 'x', 'x']
and then just comparison them like:
#l = board
if(l[0:3] == o_list or l[3:6] == o_list or l[6:9] == o_list or l[0:9:3] == o_list or l[1:9:3] == o_list or l[8:0:-3] == o_list):
print('The Winner Is Player "O"!')
same as for x_list.
;)
o_list =['o', 'o', 'o']
x_list =['x', 'x', 'x']
board = [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']
def show_board():# for showing the tic-tac-toe board
print(' | ' + str(board[0]) + ' | ' +
str(board[1]) + ' | ' + str(board[2]) + ' | ')
print(' | ' + str(board[3]) + ' | ' +
str(board[4]) + ' | ' + str(board[5]) + ' | ')
print(' | ' + str(board[6]) + ' | ' +
str(board[7]) + ' | ' + str(board[8]) + ' | ')
def main():
one = 1
flag = 1
o_list =['o', 'o', 'o']
x_list =['x', 'x', 'x']
show_board()
while one == 1:
if flag == 1:
x_o = 'X'
if flag == 2:
x_o = 'O'
pos = int(input('Player "' + x_o + '" Turn: '))
if x_o == 'o':
x_o = 'O'
if x_o == 'x':
x_o = 'X'
if board[pos - 1] == 'O' or board[pos - 1] == 'O':
print('That Place Is Already Filled By Player "0"')
if board[pos - 1] == 'X' or board[pos - 1] == 'X':
print('That Place Is Already Filled By Player "X"')
else:
try:
board[pos - 1] = x_o
except IndexError:
print('Type Numbers Between Only 1 And 9')
if flag == 1:
flag = 2
elif flag == 2:
flag = 1
show_board()
# Checking The Winner Of The Game
# for horizontal X
if(board[0:3] == x_list or board[3:6] == x_list or board[6:9] == x_list or board[0:9:3] == x_list or board[1:9:3] == x_list or board[8:0:-3] == x_list):
one = 2
print('The Winner Is Player "X"!')
if(board[0:3] == o_list or board[3:6] == o_list or board[6:9] == o_list or board[0:9:3] == o_list or board[1:9:3] == o_list or board[8:0:-3] == o_list):
one = 2
print('The Winner Is Player "O"!')
elif board[0] != ' ' and board[1] != ' ' and board[2] != ' ' and board[3] != ' ' and board[4] != ' ' and board[5] != ' ' and board[6] != ' ' and board[7] != ' ' and board[8] != ' ':
print('The Match Is A Tie!')
one = 2
main()
You can use this functions(input:board and a player's letter, output: True if that player has won):
def isWinner(board, letter):
return (
(board[1] == board[2] == board[3] == letter) or
(board[4] == board[5] == board[6] == letter) or
(board[7] == board[8] == board[9] == letter) or
(board[7] == board[4] == board[1] == letter) or
(board[8] == board[5] == board[2] == letter) or
(board[9] == board[6] == board[3] == letter) or
(board[7] == board[5] == board[3] == letter) or
(board[9] == board[5] == board[1] == letter))
for checking the winner you can use:
from operator import itemgetter
from itertools import chain
winning_cases = {'diags' : [[0, 4, 8], [2, 4, 6]],
'rows': [[0, 1, 2], [3, 4, 5], [6, 7, 8]],
'cols': [[0, 3, 6], [1, 4, 7], [2, 5, 8]]}
def check_winner(board=board):
for case in chain(*winning_cases.values()):
candidates = set(itemgetter(*case)(board))
if len(candidates) == 1 and '' not in candidates: # check if a diag, row or col has only one charcter
winner, = candidates
return winner
return None
for example:
board = ['X', 'X', 'O', 'X', 'O','O', 'X', 'O', 'X']
check_winner(board)
output:
X
the method check_winner will return the winner if there is one, otherwise None

Make Python Zelle graphics tic tac toe play until one player gets 10 points

I want the computer playing with the player with until one of them scores 10 points:
from graphics import *
board=[[0,0,0],[0,0,0],[0,0,0]]#as bourd
window=GraphWin("Tic Tac Toe",700,700)
L0=Line(Point(250,50),Point(250,650)).draw(window)
L1=Line(Point(450,50),Point(450,650)).draw(window)
L2=Line(Point(50,250),Point(650,250))
L2.draw(window)
L3=Line(Point(50,450),Point(650,450))
L3.draw(window)
xTurn=True
num=0
while num<9:
b=window.getMouse()
pa,pb=int((b.x-50)/200)+1,int((b.y-50)/200)+1
if board[pb-1][pa-1]==0:
num+=1
if xTurn:
tex="X"
xTurn=False
else:
tex="O"
xTurn=True
h=Text(Point(pa*150+50*(pa-1),pb*150+50*(pb-1)),tex).draw(window)
h.setSize(36)
if xTurn:
h.setFill("blue")
board[pb-1][pa-1]=1
else:
h.setFill("red")
board[pb-1][pa-1]=2
if num>4:
if (board[0][0]==1 and board[0][1]==1 and board[0][2]==1) or(board[1][0]==1 and board[1][1]==1 and board[1][2]==1) or(board[2][0]==1 and board[2][1]==1 and board[2][2]==1):
print(" O is winner")
break
elif (board[0][0]==2 and board[0][1]==2 and board[0][2]==2) or(board[1][0]==2 and board[1][1]==2 and board[1][2]==2) or (board[2][0]==2 and board[2][1]==2 and board[2][2]==2):
print(" X is winner")
break
elif (board[0][0]==2 and board[1][0]==2 and board[2][0]==2) or(board[0][1]==2 and board[1][1]==2 and board[2][1]==2) or (board[0][2]==2 and board[1][2]==2 and board[2][2]==2):
print(" X is winner")
break
elif (board[0][0]==1 and board[1][0]==1 and board[2][0]==1) or(board[0][1]==1 and board[1][1]==1 and board[2][1]==1) or (board[0][2]==1 and board[1][2]==1 and board[2][2]==1):
print(" O is winner")
break
elif (board[0][0]==1 and board[1][1]==1 and board[2][2]==1) or(board[0][2]==1 and board[1][1]==1 and board[2][0]==1):
print(" O is winner")
break
elif (board[0][0]==2 and board[1][1]==2 and board[2][2]==2) or(board[0][2]==2 and board[1][1]==2 and board[2][0]==2):
print(" X is winner")
break
if num>=9:
print("There is no winner!")
I took your program apart and put it back together again to streamline it and allow it to play ten games before quitting. It prints the results of the ten games as it exits. This isn't exactly what you are after, but I believe gives you the tools you need to do what you want:
from graphics import *
from time import sleep
PLAYERS = ['Draw', 'O', 'X']
DRAW = PLAYERS.index('Draw')
COLORS = ['black', 'blue', 'red']
EMPTY = 0
window = GraphWin("Tic Tac Toe", 700, 700)
Line(Point(250, 50), Point(250, 650)).draw(window)
Line(Point(450, 50), Point(450, 650)).draw(window)
Line(Point(50, 250), Point(650, 250)).draw(window)
Line(Point(50, 450), Point(650, 450)).draw(window)
turn = PLAYERS.index('X')
scores = [0] * len(PLAYERS)
tokens = []
while sum(scores) < 10:
for token in tokens:
token.undraw()
board = [[EMPTY, EMPTY, EMPTY], [EMPTY, EMPTY, EMPTY], [EMPTY, EMPTY, EMPTY]]
squares_played = 0
while squares_played < 9:
point = window.getMouse()
x, y = int((point.x - 50) / 200), int((point.y - 50) / 200)
if board[y][x] == EMPTY:
squares_played += 1
board[y][x] = turn
text = PLAYERS[turn]
token = Text(Point(200 * x + 150, 200 * y + 150), text)
token.setSize(36)
token.setFill(COLORS[turn])
token.draw(window)
tokens.append(token)
turn = len(PLAYERS) - turn
if squares_played > 4:
if EMPTY != board[0][0] == board[0][1] == board[0][2]:
print("{} is winner".format(PLAYERS[board[0][0]]))
scores[turn] += 1
break
elif EMPTY != board[1][0] == board[1][1] == board[1][2]:
print("{} is winner".format(PLAYERS[board[1][1]]))
scores[turn] += 1
break
elif EMPTY != board[2][0] == board[2][1] == board[2][2]:
print("{} is winner".format(PLAYERS[board[2][2]]))
scores[turn] += 1
break
elif EMPTY != board[0][0] == board[1][0] == board[2][0]:
print("{} is winner".format(PLAYERS[board[0][0]]))
scores[turn] += 1
break
elif EMPTY != board[0][1] == board[1][1] == board[2][1]:
print("{} is winner".format(PLAYERS[board[1][1]]))
scores[turn] += 1
break
elif EMPTY != board[0][2] == board[1][2] == board[2][2]:
print("{} is winner".format(PLAYERS[board[2][2]]))
scores[turn] += 1
break
elif EMPTY != board[0][0] == board[1][1] == board[2][2]:
print("{} is winner".format(PLAYERS[board[1][1]]))
scores[turn] += 1
break
elif EMPTY != board[0][2] == board[1][1] == board[2][0]:
print("{} is winner".format(PLAYERS[board[1][1]]))
scores[turn] += 1
break
if squares_played >= 9:
print("There is no winner!")
scores[DRAW] += 1
sleep(2)
for index, player in enumerate(PLAYERS):
print("{}: {}".format(player, scores[index]))
My rework relies on some parallel arrays, which is better than no arrays, but should evolve to a real data structure.

Categories

Resources