Related
I am currently trying to make a Tic Tac Toe game with minimax implemented in Python. Another feature that I'm trying to implement is different board sizes. But overall, unfortunately, the algorithm is not working.
As a beginner, this is not a surprise for me, but this case seems hopeless. I tried tweaking quite a lot of things (may seem like a lot just to me) just to end up with the same result - the computer filling up the fields from top left to bottom right.
#Sprawdzenie czy ktos wygral w poziomie lub pionie / straight line check
def winLine(line, letter):
return all(n == letter for n in line)
#Utworzenie nowej listy z elementow przekatnych / diagonal check
def winDiagonal(board, letter):
arr = []
tArr = []
for n in range(boardSize):
arr.append(board[n][n])
tArr.append(board[n][boardSize-n-1])
if winLine(arr, letter):
return True
elif winLine(tArr, letter):
return True
else:
return False
def checkWinner (board):
#Liczenie wolnych pol / checking the available fields
openSpots = 9
for n in range(boardSize):
for m in range(boardSize):
if board[n][m] == '0':
openSpots += 1
#Transpozycja planszy, by mozna bylo latwo zastosowac winLine na kolumach / transposition of the board
for letter in (person, ai):
transPos = list(zip(*board))
#Sprawdzanie w poziomie / horizontal check
if any(winLine(row, letter) for row in board):
#print('winline horizontal')
return letter
#Sprawdzanie w pionie / vertical check
elif any (winLine(col, letter) for col in transPos):
#print('winline vertical')
return letter
#Sprawdzanie po przekatnych / diagonal check
elif winDiagonal(board, letter):
return letter
elif openSpots == 0: return 'tie'
else: return 'none'
#Funkcja sprawdzajaca czy dane pole jest wolne / checks whether the field is available
def available (row, col):
global board
#Sprawdzenie czy pole jest wolne
if board[row][col] == '0':
return True
else:
return False
#Stale dla algorytmu minimax / minimax initial scores to compare against
minTarget = float('inf')
maxTarget = float('-inf')
#Slownik z wartosciami liczbowi dla wynikow, komputer maksymalizuje / a dictionary with scores for particular results
scores = {
'X': 10,
'O': -10,
'tie': 0
}
#Algorytm minimax
def minimax(myBoard, depth, maximizes):
#Sprawdzenie czy zaszla wygrana lub remis / Checking whether there is a win or tie
res = checkWinner(myBoard)
if (res != 'none'):
return scores[res]
#Gracz maksymalizujacy/ Maximizing player
elif maximizes == True:
bestScoreMax = maxTarget
for n in range(boardSize):
for m in range(boardSize):
if board[n][m] == '0':
board[n][m] = person
score = minimax(board, depth + 1, False)
board[n][m] = '0'
bestScoreMax = max([score, bestScoreMax])
return bestScoreMax
#Gracz minimalizujacy / minimizing player
elif maximizes == False:
bestScoreMin = minTarget
for n in range(boardSize):
for m in range(boardSize):
if board[n][m] == '0':
board[n][m] = ai
score = minimax(board, depth + 1, True)
board[n][m] = '0'
bestScoreMin = min([score, bestScoreMin])
return bestScoreMin
def makeMove(row, col):
global board
board[row][col] = ai
def computedMove():
global board
myBoard = board
computedTarget = maxTarget
moveX = 2
moveY = 2
for n in range(boardSize):
for m in range(boardSize):
if myBoard[n][m] == '0':
score = minimax(myBoard, 0, True)
if score > computedTarget:
computedTarget = score
moveX = n
moveY = m
makeMove(moveX, moveY)
#print(str(move.x) + ' ' + str(move.y))
# Funkcja pobierajaca ruch uzytkownika / player input for the move
def getPlayerMove():
global board
res = input('Please type in your move on the form \"x y\", x being the number of the row and y the number of the column of your choosing.\n')
col, row = res.split(" ")
row = int(row)
col = int(col)
if available(row-1, col-1):
board[row-1][col-1] = person
else:
print('You cannot make that move')
getPlayerMove()
def drawBoard():
global board
for n in range(boardSize):
for m in range(boardSize):
if board[n][m] == '0':
print(' - ', end='')
else:
print(' '+board[n][m]+' ', end='')
print('\n')
#Zmienna powiadamiajaca o stanie rozgrywki / variable indicating the state of the game
playing = False
# initializing the variable
boardSize = 0
# initializing the players
person = 'X'
ai = 'O'
#Gracz posiadajacy ruch (a takze rozpoczynajacy) / player who is playing at the moment
currentPlayer = ''
while True:
currentPlayer = person
boardSize = int(input("Please enter the size of the board. (one side)\n"))
global board
board = [['0' for i in range(boardSize)] for i in range(boardSize)]
print("You go first.")
playing = True
while playing:
if currentPlayer == person:
drawBoard()
getPlayerMove()
if checkWinner(board) == person:
drawBoard()
print("Yaay, you won!")
playing = False
else:
if checkWinner(board) == 'tie':
drawBoard()
print('It\'s a tie!')
break
else:
currentPlayer = ai
elif currentPlayer == ai:
computedMove()
if checkWinner(board) == ai:
drawBoard()
print('You lose!')
playing = False
else:
if checkWinner(board) == 'tie':
drawBoard()
print('It\'s a tie!')
break
else:
currentPlayer = person
if not input('Do you want to play again?').lower().startswith('y'):
break
In computedMove, you should first play the ai move then check the scores.
def computedMove():
global board
myBoard = board
computedTarget = maxTarget
moveX = 2
moveY = 2
for n in range(boardSize):
for m in range(boardSize):
if myBoard[n][m] == '0':
myBoard[n][m] = ai #This is added
score = minimax(myBoard, 0, True)
if score > computedTarget:
computedTarget = score
moveX = n
moveY = m
makeMove(moveX, moveY)
Also in minimax function, you should use same variable for myBoard and board.
I've been trying to write a solver for 15 puzzle in python but now I reached a dead end where I can't figure out what's wrong with my code. It works for simple cases, where amount of moves required to solve the puzzle is low, this one for example:
5 1 2 3
9 7 11 4
13 6 15 8
14 10 0 12
where 0 represents blank tile.
When I use more complex cases (generated here), the program seems to go into an infinite loop, and even for simple cases I feel like it's not finding the optimal solution. I've been trying to figure out what's causing the problem, but after debugging it for multiple hours I didn't find anything, all of the methods seem to work properly.
Can you tell me what is wrong with this code?
Here's the solver class:
from copy import deepcopy
class Fifteen:
heur = ''
tiles = []
undo_move = ''
h_score = 0 # calculated using heuristic
depth = 0
previous_moves = []
zero_x = 0
zero_y = 0
def __init__(self, heur, fin, parent=None):
if parent is None:
self.heur = heur
fi = open(fin, 'r', encoding='utf-8')
self.tiles = [list(map(int, line.split())) for line in fi]
self.zero_x, self.zero_y = self.find()
fi.close()
elif parent is not None:
self.heur = deepcopy(parent.heur)
self.tiles = deepcopy(parent.tiles)
self.undo_move = deepcopy(parent.undo_move)
self.depth = deepcopy(parent.depth) + 1
self.previous_moves = deepcopy(parent.previous_moves)
self.zero_x = deepcopy(parent.zero_x)
self.zero_y = deepcopy(parent.zero_y)
def find(self, tile=0):
for y in range(len(self.tiles)):
for x in range(len(self.tiles[y])):
if self.tiles[y][x] == tile:
return x, y
raise NameError
def move_tile(self, direction):
x, y = self.zero_x, self.zero_y
if direction == 'u':
self.tiles[y][x], self.tiles[y - 1][x] = self.tiles[y - 1][x], self.tiles[y][x]
self.zero_y = self.zero_y - 1
self.previous_moves.append('u')
self.undo_move = 'd'
elif direction == 'd':
self.tiles[y][x], self.tiles[y + 1][x] = self.tiles[y + 1][x], self.tiles[y][x]
self.zero_y = self.zero_y + 1
self.previous_moves.append('d')
self.undo_move = 'u'
elif direction == 'l':
self.tiles[y][x], self.tiles[y][x - 1] = self.tiles[y][x - 1], self.tiles[y][x]
self.zero_x = self.zero_x - 1
self.previous_moves.append('l')
self.undo_move = 'r'
elif direction == 'r':
self.tiles[y][x], self.tiles[y][x + 1] = self.tiles[y][x + 1], self.tiles[y][x]
self.zero_x = self.zero_x + 1
self.previous_moves.append('r')
self.undo_move = 'l'
else:
raise NameError
def generate_next_states(self):
next_states = []
x, y = self.zero_x, self.zero_y
if y != 0 and self.undo_move != 'u':
child = Fifteen(None, None, self)
child.move_tile('u')
next_states.append(child)
if y != len(self.tiles) - 1 and self.undo_move != 'd':
child = Fifteen(None, None, self)
child.move_tile('d')
next_states.append(child)
if x != 0 and self.undo_move != 'l':
child = Fifteen(None, None, self)
child.move_tile('l')
next_states.append(child)
if x != len(self.tiles[y]) - 1 and self.undo_move != 'r':
child = Fifteen(None, None, self)
child.move_tile('r')
next_states.append(child)
return next_states
def heuristic(self):
if self.heur == 'hamm':
return self.hamming()
return self.manhattan()
def hamming(self):
diff = 0
for y in range(len(self.tiles)):
for x in range(len(self.tiles[y])):
if y == len(self.tiles) - 1 and x == len(self.tiles[y]) - 1:
if self.tiles[y][x] != 0:
diff += 1
elif self.tiles[y][x] != y * len(self.tiles) + x + 1:
diff += 1
return diff
def manhattan(self):
score = 0
value = 1
for y in range(len(self.tiles)):
for x in range(len(self.tiles[y])):
if value == 16:
value = 0
x_real, y_real = self.find(value)
dx = abs(x - x_real)
dy = abs(y - y_real)
score += dx + dy
value += 1
return score
def astar(self):
queue = [self]
closed_set = {}
while len(queue) > 0:
current_state = queue.pop(0)
closed_set[repr(current_state.tiles)] = current_state
if current_state.heuristic() == 0:
print(current_state.tiles)
print(current_state.previous_moves)
print(len(current_state.previous_moves))
return
for state in current_state.generate_next_states():
if repr(state.tiles) in closed_set:
continue
state.h_score = state.heuristic()
queue.append(state)
queue.sort(key=lambda x: x.h_score, reverse=False)
print(-1)
return
And this is how I run it:
from fifteen import Fifteen
f = Fifteen('manh', "start.txt")
f.astar()
The first argument can be either manh or hamm, depending on the heuristic used, second one is name of file containing initial puzzle setup.
There are ways to improve your code, but I will explain main problems (at least for me).
1- You are not using depth values of states while sorting states. This will prevent algorithm finding optimal solutions, or even finding a solution if the state space is large.
2- You should really decide how you represent a "state". I added a equality overload (__eq__ method) for a state which I think is correct for this problem. It compares tiles, heuristic scores and depth values. Although that was not the main problem I think that is something very important. Because naive implementation may slow down your algorithm a lot and make things hard to debug.
3- When things does not work, try visualizing your algorithm. I added a PrintState function and tried to observe what is wrong with the solving process.
from copy import deepcopy
class Fifteen:
heur = ''
tiles = []
undo_move = ''
h_score = 0 # calculated using heuristic
depth = 0
previous_moves = []
zero_x = 0
zero_y = 0
def __init__(self, heur, fin, parent=None):
if parent is None:
self.heur = heur
fi = open(fin, 'r', encoding='utf-8')
self.tiles = [list(map(int, line.split())) for line in fi]
self.zero_x, self.zero_y = self.find()
fi.close()
elif parent is not None:
self.heur = deepcopy(parent.heur)
self.tiles = deepcopy(parent.tiles)
self.undo_move = deepcopy(parent.undo_move)
self.depth = deepcopy(parent.depth) + 1
self.previous_moves = deepcopy(parent.previous_moves)
self.zero_x = deepcopy(parent.zero_x)
self.zero_y = deepcopy(parent.zero_y)
def find(self, tile=0):
for y in range(len(self.tiles)):
for x in range(len(self.tiles[y])):
if self.tiles[y][x] == tile:
return x, y
raise NameError
def move_tile(self, direction):
x, y = self.zero_x, self.zero_y
if direction == 'u':
self.tiles[y][x], self.tiles[y - 1][x] = self.tiles[y - 1][x], self.tiles[y][x]
self.zero_y = self.zero_y - 1
self.previous_moves.append('u')
self.undo_move = 'd'
elif direction == 'd':
self.tiles[y][x], self.tiles[y + 1][x] = self.tiles[y + 1][x], self.tiles[y][x]
self.zero_y = self.zero_y + 1
self.previous_moves.append('d')
self.undo_move = 'u'
elif direction == 'l':
self.tiles[y][x], self.tiles[y][x - 1] = self.tiles[y][x - 1], self.tiles[y][x]
self.zero_x = self.zero_x - 1
self.previous_moves.append('l')
self.undo_move = 'r'
elif direction == 'r':
self.tiles[y][x], self.tiles[y][x + 1] = self.tiles[y][x + 1], self.tiles[y][x]
self.zero_x = self.zero_x + 1
self.previous_moves.append('r')
self.undo_move = 'l'
else:
raise NameError
def generate_next_states(self):
next_states = []
x, y = self.zero_x, self.zero_y
if y != 0 and self.undo_move != 'u':
child = Fifteen(None, None, self)
child.move_tile('u')
next_states.append(child)
if y != len(self.tiles) - 1 and self.undo_move != 'd':
child = Fifteen(None, None, self)
child.move_tile('d')
next_states.append(child)
if x != 0 and self.undo_move != 'l':
child = Fifteen(None, None, self)
child.move_tile('l')
next_states.append(child)
if x != len(self.tiles[y]) - 1 and self.undo_move != 'r':
child = Fifteen(None, None, self)
child.move_tile('r')
next_states.append(child)
return next_states
def heuristic(self):
if self.heur == 'hamm':
return self.hamming()
return self.manhattan()
def hamming(self):
diff = 0
for y in range(len(self.tiles)):
for x in range(len(self.tiles[y])):
if y == len(self.tiles) - 1 and x == len(self.tiles[y]) - 1:
if self.tiles[y][x] != 0:
diff += 1
elif self.tiles[y][x] != y * len(self.tiles) + x + 1:
diff += 1
return diff
def manhattan(self):
score = 0
value = 1
for y in range(len(self.tiles)):
for x in range(len(self.tiles[y])):
if value == 16:
value = 0
x_real, y_real = self.find(value)
dx = abs(x - x_real)
dy = abs(y - y_real)
#print("dx + dy for {}: {}".format(value, dx+dy))
score += dx + dy
value += 1
#print("Score:{}".format(score))
return score
def PrintState(self):
for y in range(len(self.tiles)):
for x in range(len(self.tiles[y])):
cellValue = self.tiles[y][x]
print(cellValue, end=" ")
print("")
def __eq__(self, other):
return (self.tiles == other.tiles
and self.h_score == other.h_score
and self.depth == other.depth)
def astar(self):
queue = [self]
closed_set = {}
while len(queue) > 0:
print("---")
print("---")
current_state = queue.pop(0)
print("current state")
#print(current_state.tiles)
#print(repr(current_state.tiles))
current_state.PrintState()
print("current scores")
print("heuristic:{}".format(current_state.heuristic()))
print("depth:{}".format(current_state.depth))
print("total:{}".format(current_state.heuristic() + current_state.depth))
closed_set[repr(current_state.tiles)] = current_state
if current_state.heuristic() == 0:
print(current_state.tiles)
print(current_state.previous_moves)
print(len(current_state.previous_moves))
return
for state in current_state.generate_next_states():
if repr(state.tiles) in closed_set:
continue
state.h_score = state.heuristic()
queue.append(state)
queue.sort(key=lambda x: (x.h_score + x.depth), reverse=False)
print(-1)
return
Optionally, consider using priority queue based implementation.
Update: Beware unsolvable starting positions like:
1 2 3 4
5 6 10 8
9 7 11 12
15 13 14 0
I wasted a good time on this configuration :)
Hello ! I have a question guys.
I was writing my first serious python training project because I'm beginner but I encountered a problem that stops me from further development of my program.
I don't have idea how can I write function/module in my class that check if player X or player Y has won. I tried on so many different ways but it seems to not work. I know that the my code is looking awful. Thank you for your time spent.
import sys
class Tic_tac_toe():
def __init__(self):
self.board = {'top-L': ' ', 'top-M': ' ', 'top-R': ' ',
'mid-L': ' ', 'mid-M': ' ', 'mid-R': ' ',
'low-L': ' ', 'low-M': ' ', 'low-R': ' '}
self.move_X = None
self.move_0 = None
self.WINNING_MOVE = None
self.loop = None
self.nameX = None
self.nameO = None
self.choice = None
def welcome(self):
try:
print("Welcome ! :)\n\nWho is PLAYER X ? :")
self.nameX = input()
print("\nWho is PLAYER O ? :")
self.nameO = input()
print("\nHello {} and {}, ready to play? (Y/N) :".format(self.nameX.title(), self.nameO.title()))
self.choice = input()
if self.choice.title() == 'N' or '\n':
sys.exit()
print('\n{} is PLAYER X.\n{} is PLAYER Y.'.format(self.nameX.title(),self.nameO.title()))
except ValueError:
print('\nTry again:\n')
def printBoard(self):
print()
print(self.board['top-L'] + '|' + self.board['top-M'] + '|' + self.board['top-R'])
print('-+-+-')
print(self.board['mid-L'] + '|' + self.board['mid-M'] + '|' + self.board['mid-R'])
print('-+-+-')
print(self.board['low-L'] + '|' + self.board['low-M'] + '|' + self.board['low-R'])
print()
def moves_X(self):
try:
self.move_X = int(input("Player X :\nChoose field (1,9) : "))
self.write_on_boardX()
self.printBoard()
except ValueError:
print("\nYOU DIDN'T ENTER NUMBER !\n")
def moves_O(self):
try:
self.move_O = int(input("Player O :\nChoose field (1,9) : "))
self.write_on_boardO()
self.printBoard()
except ValueError:
print("\nYOU DIDN'T ENTER NUMBER!\n")
def mix_XO(self):
self.loop = 0
for x in range(1,10):
if self.loop % 2 == 0:
self.moves_X()
self.loop += 1
elif self.loop % 2 == 1:
self.moves_O()
self.loop += 1
def write_on_boardX(self):
if self.move_X == 1:
self.board['top-L'] = 'X'
elif self.move_X == 2:
self.board['top-M'] = 'X'
elif self.move_X == 3:
self.board['top-R'] = 'X'
elif self.move_X == 4:
self.board['mid-L'] = 'X'
elif self.move_X == 5:
self.board['mid-M'] = 'X'
elif self.move_X == 6:
self.board['mid-R'] = 'X'
elif self.move_X == 7:
self.board['low-L'] = 'X'
elif self.move_X == 8:
self.board['low-M'] = 'X'
elif self.move_X == 9:
self.board['low-R'] = 'X'
def write_on_boardO(self):
if self.move_O == 1:
self.board['top-L'] = 'O'
elif self.move_O == 2:
self.board['top-M'] = 'O'
elif self.move_O == 3:
self.board['top-R'] = 'O'
elif self.move_O == 4:
self.board['mid-L'] = 'O'
elif self.move_O == 5:
self.board['mid-M'] = 'O'
elif self.move_O == 6:
self.board['mid-R'] = 'O'
elif self.move_O == 7:
self.board['low-L'] = 'O'
elif self.move_O == 8:
self.board['low-M'] = 'O'
elif self.move_O == 9:
self.board['low-R'] = '0'
def winning_movesX(self):
pass
def main():
app = Tic_tac_toe()
app.welcome()
app.printBoard()
app.mix_XO()
main()
One way to achieve this is to first create a map of all the possible winning 'lines' and then see if the elements on that line are all the same, by creating a set and checking it contains only 1 item (X or O). For example:
lines = [
['top-L','top-M','top-R'],
['top-L', 'mid-L', 'low-L']
... etc ...
]
for line in lines:
if len(set(self.board[x] for x in line])) == 1:
print("Winner:", self.board[line[0]])
Different Approach might be easier...
A simpler way would be to use a 3x3 matrix, e.g. with:
0 as a default value
-1 for player 1
+1 for player 2
You can then calculate the sum of the rows/columns/diagonals. With -3 as a player 1 win, +3 as a player 2 win. For example by using numpy:
>>> import numpy as np
>>> np.zeros((3, 3), dtype=int)
array([[0, 0, 0],
[0, 0, 0],
[0, 0, 0]])
=> self.board = np.zeros((3,3), dtype=int)
and a win check would roughly look like:
d1,d2 = 0,0 #used to calculate sum of diagonal
for i in range(3):
#check row
if sum(self.board[i, :]) in (3,-3):
self.win = True
#check column
elif sum(self.board[:, i]) in (3,-3):
self.win = True
#check diagonal
d1 += self.board[i, i] #diagonal from top left corner to bottom right corner
d2 += self.board[i, 2-i] #diagonal from top right corner to bottom left corner
elif d1 in (3,-3) or d2 in (-3,3):
self.win = True
Note: You know which player has won since you know who's turn it was last.
Well, and since you seem to be rather new to python here a quick overview on how to access elements of an array:
>>> board = np.zeros((3,3), dtype=int)
>>> board[0][1] = 3
>>> board
array([[0, 3, 0],
[0, 0, 0],
[0, 0, 0]])
And in case you keep this board:
"""
[1] | [2] | [3]
-----------------
[4] | [5] | [6]
-----------------
[7] | [8] | [9]
"""
you could use the integer division // and the modulo function % instead of all the elif statements to determine what field/position on the board the user meant:
position = int(input("Choose position:"))
row = (position-1)//3
column = (position-1)%3
self.board[row][column] = 1 #or -1
P.S.:
If you want to implement a "player vs. computer" later on, you might change the value -1 to -3 to get unique sum values. (-1 +1 +0 = 0 +0 +0)
I didn't know what sort of title to give this post. I'm a new to python, and I'm 4 weeks into my first class. I wrote a Tic Tac Toe program with an AI, but the AI is weird. It behaves differently at my home PC than at my school PC. At school, the program just crashes once it become's the computers turn for a move. It doesn't even draw the boxes. At home the computer just doesn't move. My home computer is significantly better than my school computer by the way. Also it's running Windows 10 TP vs. Windows 7 at school. I showed my teacher and he couldn't tell me the problem. This is my code. Sorry it's all one file and it's all the code I have because I have no idea where the problem is. Also I'm using PyProcessing which is basically a python IDE that provides some simple ways for graphics. The setup() function runs automatically at the beginning and so does draw() but I'm not sure when or what causes the draw() function to run.
board = [[None, None, None],
[None, None, None],
[None, None, None]]
turn = 0
player_letter = ""
computer_letter = ""
game_ended = False
def setup():
global game_ended
global player_letter
global turn
global board
global computer_letter
size(300,300)
drawBoard(board)
drawLetters(board)
turn = 0
if turn == 0:
player_letter = "X"
computer_letter = "O"
else:
player_letter = "O"
computer_letter = "X"
def check_win(board, letter):
if board[0][0] == letter and board[0][1] == letter and board[0][2] == letter:
return True
elif board[1][0] == letter and board[1][1] == letter and board[1][2] == letter:
return True
elif board[2][0] == letter and board[2][1] == letter and board[2][2] == letter:
return True
elif board[0][0] == letter and board[1][0] == letter and board[2][0] == letter:
return True
elif board[0][1] == letter and board[1][1] == letter and board[2][1] == letter:
return True
elif board[0][2] == letter and board[1][2] == letter and board[2][2] == letter:
return True
elif board[0][0] == letter and board[1][1] == letter and board[2][2] == letter:
return True
elif board[2][0] == letter and board[1][1] == letter and board[0][2] == letter:
return True
else:
return False
def run_player_turn(player_letter):
global board
if mousePressed and board[mouseY//100][mouseX//100] == None:
board[mouseY//100][mouseX//100] = player_letter
return True
else:
return False
def getPotentialWin(computer_letter, player_letter):
global board
check1 = [board[0][0], board[0][1], board[0][2]]
check2 = [board[1][0], board[1][1], board[1][2]]
check3 = [board[2][0], board[2][1], board[2][2]]
check4 = [board[0][0], board[1][0], board[2][0]]
check5 = [board[0][1], board[1][1], board[2][1]]
check6 = [board[0][2], board[1][2], board[2][2]]
check7 = [board[0][0], board[1][1], board[2][2]]
check8 = [board[2][0], board[1][1], board[0][2]]
checks = [check1, check2, check3, check4, check5, check6, check7, check8]
cletters = 0
pletters = 0
letters = 0
for check in checks:
for letter in check:
if letter != None:
letters += 1
if letter == computer_letter:
cletters += 1
else:
pletters += 1
if cletters == 2 and letters == 2:
for letter in check:
if letter == None:
return letter
return None
def getPotentialLoss(computer_letter, player_letter):
global board
check1 = [board[0][0], board[0][1], board[0][2]]
check2 = [board[1][0], board[1][1], board[1][2]]
check3 = [board[2][0], board[2][1], board[2][2]]
check4 = [board[0][0], board[1][0], board[2][0]]
check5 = [board[0][1], board[1][1], board[2][1]]
check6 = [board[0][2], board[1][2], board[2][2]]
check7 = [board[0][0], board[1][1], board[2][2]]
check8 = [board[2][0], board[1][1], board[0][2]]
checks = [check1, check2, check3, check4, check5, check6, check7, check8]
cletters = 0
pletters = 0
letters = 0
for check in checks:
for letter in check:
if letter != None:
letters += 1
if letter == player_letter:
pletters += 1
else:
cletters += 1
if pletters == 2 and letters == 2:
for letter in check:
if letter == None:
return letter
return None
def draw():
global board
global turn
global player_letter
global computer_letter
if (not check_win(board, player_letter)) and (not check_win(board, computer_letter)):
if turn == 0:
if run_player_turn(player_letter):
turn = 1
else:
if run_computer_turn(computer_letter):
turn = 0
drawLetters(board)
def get_starting_player():
random_num = int(random(2))
return random_num
def drawLetters(board):
for row in range(len(board)):
for col in range(len(board[0])):
if board[row][col] != None:
textSize(32)
fill(0,0,0)
text(board[row][col], col*100+25, row*100+75)
def drawBoard(board):
for y in range(len(board)):
for x in range(len(board[0])):
rect(x * 100, y * 100, 100, 100)
def run_computer_turn(computer_letter):
global board
global turn
global cHasGone
global player_letter
potentialLoss = getPotentialLoss(computer_letter, player_letter)
potentialWin = getPotentialWin(computer_letter, player_letter)
if potentialLoss != None:
potentialLoss = computer_letter
return True
elif potentialWin != None:
potentialWin = computer_letter
return True
else:
found = False
while not found:
x = int(random(0, 3))
y = int(random(0, 3))
if board[x][y] == None:
board[x][y] == computer_letter
found = True
return True
return True
def checkAvailibleWin(row, col):
print("Hi")
def getAdjacents(row, col):
adjs = [[None, None, None, None, None],
[None, None, None, None, None],
[None, None, None, None, None],
[None, None, None, None, None],
[None, None, None, None, None]]
row += 1
col += 1
adjs[row - 1][col - 1] = True;
adjs[row - 1][col] = True;
adjs[row - 1][col + 1] = True;
adjs[row][col - 1] = True;
adjs[row][col] = True;
adjs[row][col + 1] = True;
adjs[row + 1][col - 1] = True;
adjs[row + 1][col] = True;
adjs[row + 1][col + 1] = True;
trueAdjs = [[None, None, None],
[None, None, None],
[None, None, None]]
for y in adjs:
for x in adjs:
if((x > 0 and x < 3) and (y > 0 and y < 1)):
trueAdjs[y-1][x-1] = True
return trueAdjs
I have coded a game of noughts and crosses, and am using a while loop to run the game. However, I must be doing something wrong as I cannot get it to print 'You win' or 'You lose' when a row/column/diagonal of X or O is on the board. I know the function that checks the board works as I have tested it on its own, by putting Xs in the board manually, but when playing the game normally it completely disregards any Xs or Os in 3. Here is the code, sorry it's abit long. Thanks
import random
board = [
['1','-','-','-'],
['2','-','-','-'],
['3','-','-','-'],
['#','1','2','3'],
[' ',' ',' ',' ']
]
rows = {
'top':
board[0][1:],
'mid':
board[1][1:],
'bottom':
board[2][1:]
}
cols = {
'left':
[board[0][1],
board[1][1],
board[2][1]],
'mid':
[board[0][2],
board[1][2],
board[2][2]],
'right':
[board[0][3],
board[1][3],
board[2][3]]
}
diags = {
'top-bottom':
[board[0][1],
board[1][2],
board[2][3]],
'bottom-top':
[board[2][1],
board[1][2],
board[0][3]]
}
gamestate = 1
def print_board(board):
for i in board:
print " ".join(i)
def win_check(rows,cols,diags):
plrWin = ['X','X','X']
cpuWin = ['O','O','O']
global gamestate
for i in rows.values():
if i == plrWin:
return True
gamestate = 0
elif i == cpuWin:
return False
gamestate = 0
for x in cols.values():
if x == plrWin:
return True
gamestate = 0
elif x == cpuWin:
return False
gamestate = 0
for y in diags.values():
if y == plrWin:
return True
gamestate = 0
elif y == cpuWin:
return False
gamestate = 0
def game_entry():
print "Your turn."
coordY = input("Guess column: ")
coordX = input("Guess row: ")
board[coordX - 1][coordY] = 'X'
def random_location():
while True:
cpuX = random.randint(1,3)
cpuY = random.randint(1,3)
if (board[cpuX - 1][cpuY] == 'X') or (board[cpuX - 1][cpuY] == 'O'):
continue
else:
board[cpuX - 1][cpuY] = 'O'
break
while gamestate == 1:
print_board(board)
game_entry()
random_location()
if win_check(rows,cols,diags) == True:
print "You win!"
gamestate = 0
break
elif win_check(rows,cols,diags) == False:
print "You lose."
gamestate = 0
break
else:
continue
Your problem is with all of the rows and cols dictionaries:
>>> l = [[1, 2, 3], [4, 5, 6]]
>>> x = l[0][1:]
>>> x
[2, 3]
>>> l[0][1] = 4
>>> x
[2, 3]
As you can see, they don't update when the board is changed. You'll have to find another way of doing this.
I would just use a few loops and check the diagonals manually:
def has_someone_won(board):
# Rows
for row in board:
if row[0] == row[1] == row[2] != '-':
return True
# Columns
for i in range(3):
if board[0][i] == board[1][i] == board[2][i] != '-':
return True
# Diagonal 1
if board[0][0] == board[1][1] == board[2][2] != '-':
return True
# Diagonal 2
if board[2][0] == board[1][1] == board[0][2] != '-':
return True
# There's no winner
return False