Related
My tic-tac-toe doesn't seem to work properly. I have tried various things, but nothing changes.
You can run the script yourself, just to see that every time after asking the player's move the game makes a vertical line of X's at the desired column and ends there.
It's probably a problem with my implementation of minimax or the computedMove function, although i cannot locate any errors in there.
# Boardsize initialization
boardSize = 0
# Board initialization
board = []
person = 'X'
ai = 'O'
#This variable indicates the player who has their turn at the moment.
currentPlayer = ''
# This shows the board.
for n in range (boardSize):
for m in range (boardSize):
print (" - "),
print ("\n")
#Checking if somebody won (only horizontal or vertical)
def winLine(line, letter):
return all(n == letter for n in line)
#New list from diagonals
def winDiagonal(board):
return (board[n][n] for n in range (boardSize))
#The function universally checks whether somebody has won, or not.
def checkWinner (board):
#Liczenie wolnych pol
openSpots = 0
for n in range(boardSize):
for m in range(boardSize):
if board[n][m] == '0':
openSpots += 1
#Transposition of the board, so it's possible to use winline() here
for letter in (person, ai):
transPos = list(zip(*board))
#Horizontal check
if any(winLine(row, letter) for row in board):
return letter
#Vertical check
elif any (winLine(col, letter) for col in transPos):
return letter
#Diagonal check
elif any (winLine(winDiagonal(dummy), letter) for dummy in (board, transPos)):
return letter
elif openSpots == 0: return 'tie'
else: return 'N/A'
#This function returns the player's move
def playerMove (row, col):
#Checking if the field is clear
if board[row][col] == '0':
board[row-1][col-1] = person
else:
print('You cannot make that move.')
#Minimax constants
plusInf = float('inf')
minusInf = float('-inf')
#Lookup table for minimax scores
scores = {
'X': 10,
'O': -10,
'None': 0
}
#Minimax itself
def minimax(baord, depth, maximizes):
#Checking whether anybody has won
res = checkWinner(board)
if (res != 'N/A'):
return scores[res]
#Maximizing player
if maximizes:
minmaxBoard = board.copy()
maxTarget = minusInf
for n in range(boardSize):
for m in range(boardSize):
if minmaxBoard[n][m] == '0':
minmaxBoard[n][m] = ai
score = minimax(minmaxBoard, depth + 1, False)
maxTarget = max(score, maxTarget)
return maxTarget
#Minimizing player
else:
minTarget = plusInf
minmaxBoard = board.copy()
for n in range(boardSize):
for m in range(boardSize):
if minmaxBoard[n][m] == '0':
minmaxBoard[n][m] = person
score = minimax(minmaxBoard, depth + 1, True)
minTarget = min(score, minTarget)
return minTarget
#The computer uses this function to make its move
def computedMove():
computedTarget = minusInf
for n in range(boardSize):
for m in range(boardSize):
newBoard = board.copy()
if newBoard[n][m] == '0':
newBoard[n][m] = ai
score = minimax(newBoard, 0, False)
if score > computedTarget:
computedTarget = score
move = (n,m)
board[move[0]][move[1]] = ai
# Getting input for the player's move
def getPlayerMove():
res = input('Please type in your move on the form \"x y\", x being the number of the column and y the number of the row of your choosing.\n')
col, row = res.split(" ")
row = int(row)
col = int(col)
move = (row, col)
return move
# Drawing the board
def drawBoard():
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')
# Current state of the game, False at first
playing = False
#The game loop
while True:
currentPlayer = person
boardSize = int(input("Please enter the size of the board. (one sie)\n"))
board = [['0']*boardSize]*boardSize
print("You go first.")
playing = True
while playing:
if currentPlayer == person:
drawBoard()
move = getPlayerMove()
playerMove(move[0]-1, move[1]-1)
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
if 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
Check out this statement:
board = [['0']*boardSize]*boardSize
You're essentially creating a list of references to the same list boardSize times. That's why when you're assigning something to board[i][j] element, it gets assigned to j-th elements of all rows (from board[0] to board[len(board)]), because all rows are referencing the same list.
Use this instead:
board = [['0'] * boardSize for _ in range(boardSize)]
There are other issues with this code though. I'm sure you're decrementing your (x, y) indexes multiple times, for example. I didn't check it further.
So for a school project we need to make Tic Tac Toe in Python. This is currently where i'm at. It semi works, yet without win detection. It is very long winded, and I am trying to condense all the if statements into loops, but I dont really know how to get it into a nice loop. Each if statement within the main function is ran depending on the input, which results in different items in the 2D list (board) being changed.
row1 = ["-","-","-"]
row2 = ["-","-","-"]
row3 = ["-","-","-"]
board = [row1, row2, row3]
rows = 3
for each in range(0,3):
print(*board[each])
A1 = board[0][0]
A2 = board[0][1]
A3 = board[0][2]
B1 = board[1][0]
B2 = board[1][1]
B3 = board[1][2]
C1 = board[2][0]
C2 = board[2][1]
C3 = board[2][2]
X = True
game = True
def main(game, X):
while game == True:
if X == True:
value = input("Position in Grid for X: ")
if X == False:
value = input("Position in Grid for O: ")
if value == "A1":
if X == True:
board[0][0]="X"
X = False
elif X == False:
board[0][0]="O"
X = True
for each in range(0,3):
print(*board[each])
game = True
if value == "A2":
if X == True:
board[0][1]="X"
X = False
elif X == False:
board[0][1]="O"
X = True
for each in range(0,3):
print(*board[each])
game = True
if value == "A3":
if X == True:
board[0][2]="X"
X = False
elif X == False:
board[0][2]="O"
X = True
for each in range(0,3):
print(*board[each])
game = True
if value == "B1":
if X == True:
board[1][0]="X"
X = False
elif X == False:
board[1][0]="O"
X = True
for each in range(0,3):
print(*board[each])
game = True
if value == "B2":
if X == True:
board[1][1]="X"
X = False
elif X == False:
board[1][1]="O"
X = True
for each in range(0,3):
print(*board[each])
game = True
if value == "B3":
if X == True:
board[1][2]="X"
X = False
elif X == False:
board[1][2]="O"
X = True
for each in range(0,3):
print(*board[each])
game = True
if value == "C1":
if X == True:
board[2][0]="X"
X = False
elif X == False:
board[2][0]="O"
X = True
for each in range(0,3):
print(*board[each])
game = True
if value == "C2":
if X == True:
board[2][1]="X"
X = False
elif X == False:
board[2][1]="O"
X = True
for each in range(0,3):
print(*board[each])
game = True
if value == "C3":
if X == True:
board[2][2]="X"
X = False
elif X == False:
board[2][2]="O"
X = True
for each in range(0,3):
print(*board[each])
game = True
Use functions, at least one that converts an input to a tuple of indices (row and column).
This function should split the input into two characters. The letter can then be converted to the row, the digit to column. These conversions can be done independently and with a few tricks (using ord() on the letter and int() on the digit plus some math) very short. The function then returns an index tuple to use on board.
One way to shorten this code is to get a method to turn a string, like "B3" into the corresponding indices of the 2D array, [1][2].
The method can look like this:
def indices_of_string(s):
letters = ["A", "B", "C"]
numbers = ["1", "2", "3"]
return (letters.index(s[0]), numbers.index(s[1]))
Then you can use it like this:
(x, y) = indices_of_string(value)
if X == True:
board[x][y]="X"
X = False
elif X == False:
board[x][y]="O"
X = True
for each in range(0,3):
print(*board[each])
game = True
Your control loops aren't properly indented beneath while game == True right at the start of your main method. Try fixing that to see if the game works then?
EDIT:
If you want to shorten, you could try using a dictionary to map your grid like follows. I modified your code a bit. As for win conditions etc., you should be able to add further conditionals for those.
X = True
game = True
def main(game, X):
#Initialize the gameboard.
row1 = ["-","-","-"]
row2 = ["-","-","-"]
row3 = ["-","-","-"]
board = [row1, row2, row3]
for each in range(0,3):
print(*board[each])
table = {'A1': board[0][0], 'A2': board[0][1], 'A3': board[0][2],
'B1': board[1][0], 'B2': board[1][1], 'B3': board[1][2],
'C1': board[2][0], 'C2': board[2][1], 'C3': board[2][2]}
while game == True:
if X == True:
value = input("Position in Grid for X: ")
if X == False:
value = input("Position in Grid for O: ")
if value in table.keys():
if X == True:
table[value]="X"
X = False
elif X == False:
table[value]="O"
X = True
rows = list(table.values())
board = [rows[0:3],rows[3:6],rows[6:9]]
for each in range(0,3):
print(*board[each])
game = True
There are still problems with overwriting positions etc., but you only have one main if elif loop to worry about now when generating player moves. Good luck!
You can shorten your code by applying the DRY principle. In this case not only are you using a lot of if statements, they're also all very similar. If you analyse what the differences are, you can often generalize what going on by adding or computing variables that can then be used in place of hardcoded literal values like "A1" and [0][1].
I've partially done this to your code, and ended-up with the following. You could easily take it a little further by create a display_board() function and calling it instead of repeating the for each in range(0, 3): loop in more than one place.
row1 = ["-","-","-"]
row2 = ["-","-","-"]
row3 = ["-","-","-"]
board = [row1, row2, row3]
rows = 3
for each in range(0, 3):
print(*board[each])
X = True
game = True
def main(game, X):
while game == True:
if X == True:
value = input("Position in Grid for X: ")
if X == False:
value = input("Position in Grid for O: ")
## Convert two-letter value string to integer column and row indices.
col, row = ord(value[0])-ord("A"), int(value[1])-1
if X == True:
board[col][row]="X"
X = False
elif X == False:
board[col][row]="O"
X = True
for each in range(0, 3):
print(*board[each])
main(game, X)
Note Both this and your code are infinite-loops because nothing ever sets game = False. I assume you'll eventually add something that checks and determines if the game is over and which player, if any, won.
I am making a tic tac toe game and trying to create a function that checks if 3 of the same spots in a row have the same input 'x' or '0'. I am having trouble with the three_in_row function I am trying to make to trigger game over. I am trying to figure out how to do this in a simple way so all rows or columns will be triggers if 3 X's or 0's are played... Here's what I have so far. This is in python 2.7.13
(this is only part of the code I think should be relevant)
def setup_board(size):
board = []
for row in range(size):
board.append([])
for col in range(size):
board[row].append(empty)
return board
def three_in_row(b):
b[0][0] and b[0][1] and b[0][2] == 'x'
def game_over(b):
if three_in_row(b) == True:
print "Congratulations You Win!"
else:
return False
def tic_tac_toe():
b = setup_board(3)
run_game(b)
In my opinion, it might make more sense to store X's as +1 and O's as -1, so that you can easily do arithmetic to check if the game is over.
For example:
def three_in_row(b):
xWin = check_winner(b,3)
oWin = check_winner(b,-3)
return xWin | oWin
def check_winner(b, valToCheck):
foundWin = any(sum(r) in {valToCheck} for r in b) # check rows
# now check columns
for i in range(3):
foundWin = foundWin | (sum([b[j][i] for j in range(3)]) == valToCheck)
# now check diagonals
foundWin = foundWin | (sum([b[i][i] for i in range(3)]) == valToCheck)
foundWin = foundWin | (sum([b[i][2-i] for i in range(3)]) == valToCheck)
return foundWin
Thanks to Blender for the following more succinct method:
def three_in_row(b):
return any(sum(r) in {3, -3} for r in b)
def line_match(game):
for i in range(3):
set_r = set(game[i])
if len(set_r) == 1 and game[i][0] != 0:
return game[i][0]
return 0
#transposed column function for future use
#def column(game):
# trans = numpy.transpose(game)
# for i in range(3):
# set_r = set(trans[i])
# if len(set_r) == 1 and trans[i][0] != 0:
# return list(set_r)[0]
def diagonal_match(game):
if game[1][1] != 0:
if game[1][1] == game[0][0] == game[2][2]:
return game[1][1]
elif game[1][1] == game[0][2] == game[2][0]:
return game[1][1]
return 0
The correct syntax for the checks is either:
b[0][0] == 'x' and b[0][1] == 'x' and b[0][2] == 'x'
or (more succinctly):
b[0][0] == b[0][1] == b[0][2] == 'x'
You are also missing a return just before your check, like:
return b[0][0] == b[0][1] == b[0][2] == 'x'
Anyways, your code does not iterate over all the rows. A possible correction would be:
def three_in_row(b):
for row in rage(0, 3):
if b[row][0] == b[row][1] == b[row][2] == 'x':
return True
return False
Doing a three_in_column(b) should be fairly easy (changing b[row][n] in b[n][column]), so is also manually checking the two diagonals.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I'm very new to Python and I have to create a tic tac toe game with 3 players, 'X', 'O' and 'Y'. The grid has to be 6x6 instead of the normal 3x3. I have been having a lot of trouble with this and I'm very unsure how to do it. I have a 2 player 3x3 game working but implementing another player and validating the wins is becoming more tedious than I previously expected. I need help with validating a win. I haven't written the code to check for a diagonal win because I want to get everything else working before I do that. This is what I have so far but it's not correct. It's not printing out the values entered and when I do enter a value it says X has won straight away. I'd really appreciate it if you could help me. Thanks!
grid = [[0,0,0,0,0,0,0],[0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0],[0,0,0,0,0,0,0]]
def get_state(grid, row, col):
occupant = grid[col-1][row-1]
if occupant == 1:
return 'X'
if occupant == 2:
return 'O'
if occupant == 3:
return 'Y'
return ' '
def set_state(grid, row, col, player):
if player == 'X':
occupant = 1
elif player == 'O':
occupant = 2
elif player == 'Y':
occupant = 3
grid[col-1][row-1] = occupant
def is_winner(grid):
if grid[0][0] == grid[0][1] == grid [0][2]:
return True
if grid[0][1] == grid[0][2] == grid [0][3]:
return True
if grid[0][2] == grid[0][3] == grid [0][4]:
return True
if grid[0][3] == grid[0][4] == grid [0][5]:
return True
if grid[1][0] == grid[1][1] == grid [1][2]:
return True
if grid[1][1] == grid[1][2] == grid [1][3]:
return True
if grid[1][2] == grid[1][3] == grid [1][4]:
return True
if grid[1][3] == grid[1][4] == grid [1][5]:
return True
if grid[2][0] == grid[2][1] == grid [2][2]:
return True
if grid[2][1] == grid[2][2] == grid [2][3]:
return True
if grid[2][2] == grid[2][3] == grid [2][4]:
return True
if grid[2][3] == grid[2][4] == grid [2][5]:
return True
if grid[3][0] == grid[3][1] == grid [3][2]:
return True
if grid[3][1] == grid[3][2] == grid [3][3]:
return True
if grid[3][2] == grid[3][3] == grid [3][4]:
return True
if grid[3][3] == grid[3][4] == grid [3][5]:
return True
if grid[4][0] == grid[4][1] == grid [4][2]:
return True
if grid[4][1] == grid[4][2] == grid [4][3]:
return True
if grid[4][2] == grid[4][3] == grid [4][4]:
return True
if grid[4][3] == grid[4][4] == grid [4][5]:
return True
if grid[5][0] == grid[5][1] == grid [5][2]:
return True
if grid[5][1] == grid[5][2] == grid [5][3]:
return True
if grid[5][2] == grid[5][3] == grid [5][4]:
return True
if grid[5][3] == grid[5][4] == grid [5][5]:
return True
if grid[0][0] == grid[1][0] == grid [2][0]:
return True
if grid[1][0] == grid[2][0] == grid [3][0]:
return True
if grid[2][0] == grid[3][0] == grid [4][0]:
return True
if grid[3][0] == grid[4][0] == grid [5][0]:
return True
if grid[0][1] == grid[1][1] == grid [2][1]:
return True
if grid[1][1] == grid[2][1] == grid [3][1]:
return True
if grid[2][1] == grid[3][1] == grid [4][1]:
return True
if grid[3][1] == grid[4][1] == grid [5][1]:
return True
if grid[0][2] == grid[1][2] == grid [2][2]:
return True
if grid[1][2] == grid[2][2] == grid [3][2]:
return True
if grid[2][2] == grid[3][2] == grid [4][2]:
return True
if grid[3][2] == grid[4][2] == grid [5][2]:
return True
if grid[0][3] == grid[1][3] == grid [2][3]:
return True
if grid[1][3] == grid[2][3] == grid [3][3]:
return True
if grid[2][3] == grid[3][3] == grid [4][3]:
return True
if grid[3][3] == grid[4][3] == grid [5][3]:
return True
if grid[0][4] == grid[1][4] == grid [2][4]:
return True
if grid[1][4] == grid[2][4] == grid [3][4]:
return True
if grid[2][4] == grid[3][4] == grid [4][4]:
return True
if grid[3][4] == grid[4][4] == grid [5][4]:
return True
if grid[0][5] == grid[1][5] == grid [2][5]:
return True
if grid[1][5] == grid[2][5] == grid [3][5]:
return True
if grid[2][5] == grid[3][5] == grid [4][5]:
return True
if grid[3][5] == grid[4][5] == grid [5][5]:
return True
return False
def print_grid(grid):
print_row(grid,1)
print('-----------')
print_row(grid,2)
print('-----------')
print_row(grid,4)
print('-----------')
print_row(grid,4)
print('-----------')
print_row(grid,5)
print('-----------')
print_row(grid,6)
def print_row(grid, row):
output = get_state(grid,row,1)
output += '|' + get_state(grid, row, 2)
output += '|' + get_state(grid, row, 3)
output += '|' + get_state(grid, row, 4)
output += '|' + get_state(grid, row, 5)
output += '|' + get_state(grid, row, 5)
print (output)
ongoing = True
currentPlayer = 'X'
spaces = 36
while ongoing:
print_grid(grid)
print (currentPlayer + "'s turn")
print("Column?")
col = int(input())
print("Row?")
row = int(input())
current = get_state(grid,row,col)
if current != ' ':
print ("That spot is taken!")
else:
set_state(grid, row, col, currentPlayer)
spaces -= 1
if is_winner(grid):
print (currentPlayer + "'s wins!")
ongoing = False
else:
if currentPlayer == 'X':
currentPlayer = 'O'
elif currentPlayer == 'O':
curentPlayer = 'Y'
elif currentPlayer == 'Y':
currentPlayer = 'X'
if spaces == 0:
print("Stalemate!")
ongong = False
The is_winner(grid) function checks if 3 of the grid cells are the same. You initialized the grid to be 0, so the first player would always 'win'. One fix I suggest would be to initialize the list with different values. Another one would be to check (after finding that 3 cells are same) the values of the grid:
if grid[0][0] == grid[0][1] == grid[0][2]:
return grid[0][0] in ['X', 'O', 'Y']
The answer given by chucksys is good, although I would do it in a slightly different way. You need to determine that the 3 cells are the same, and not empty - so just check against your default value.
if grid[0][0] == grid[0][1] == grid[0][2] != 0:
return True
good luck with your game it's fun !!!! You can leave the code as it is. just make a different grid. one that contains a different value in every cell. That will prevent you from rewriting a lot of the game. At the beginning add the following code:grid = []
inner = []
b = 10
for i in xrange(6):
for ii in xrange(6):
inner.append(b)
b += 1
grid.append(inner)
inner = list()
This will make your grid, error proof from your checker function is_winner
There is also one small bug. curentPlayer = 'Y' change to currentPlayer = 'Y' near the end of the code
Hey everyone im new here and im trying to make a game called HiQ now i got the board drawn and everything and i can click on one of the pieces, but when i do the piece does change color and i get an error in the shell as well (listed below) im not sure why im getting this and i was hoping you guys could give me better insight. Ill provide my code below as well and it is coded in python 3, thank you
builtins.IndexError: list index out of range
boardcirc =[[0,0,0,1,1,1,0,0,0],
[0,0,0,1,1,1,0,0,0],
[0,0,0,1,1,1,0,0,0],
[1,1,1,1,1,1,1,1,1],
[1,1,1,1,2,1,1,1,1],
[1,1,1,1,1,1,1,1,1],
[0,0,0,1,1,1,0,0,0],
[0,0,0,1,1,1,0,0,0],
[0,0,0,1,1,1,0,0,0]]
def HiQ():
splash_screen()
make_board()
def make_board():
make_sqr()
make_circ()
get_click()
def get_click():
global count, boardcirc
while 1!=0:
count = count - 1
displaymessage("Pieces: " + str(count))
where = win.getMouse()
col = where.x//90
row = where.y//90
valid_move(row,col)
make_move(row,col)
def valid_move(row,col):
if boardcirc[row][col] == 0:
return False
if boardcirc[row-1][col] == 1 and boardcirc[row-2][col] == 1:
return True
if boardcirc[row+1][col] == 1 and boardcirc[row+2][col] == 1:
return True
if boardcirc[row][col-1] == 1 and boardcirc[row][col-2] == 1:
return True
if boardcirc[row][col+1] == 1 and boardcirc[row][col+2] == 1:
return True
def make_move(row,col):
while valid_move(row,col) == True:
col = (col*85)+42
row = (row*85)+42
circ = Circle(Point(col,row),35)
circ.setFill("white")
circ.draw(win)
thats everything that applies to the error
For your valid_move(row,col), you can't have all those if statements.
Instead of doing this, use elif's after the initial if statement, and don't forget to write an else statement
if boardcirc[row][col] == 0:
return False
if boardcirc[row-1][col] == 1 and boardcirc[row-2][col] == 1:
return True
elif boardcirc[row+1][col] == 1 and boardcirc[row+2][col] == 1:
return True
elif boardcirc[row][col-1] == 1 and boardcirc[row][col-2] == 1:
return True
elif boardcirc[row][col+1] == 1 and boardcirc[row][col+2] == 1:
return True
else:
return False