why are my winning conditions not respected (tictactoe) - python

total begginner here.
I am trying to write a complete tic-tac-toe program based on the automate boring stuff exercise. I got it working before like this:
theBoard = {'top-L': ' ', 'top-M': ' ', 'top-R': ' ',
'mid-L': ' ', 'mid-M': ' ', 'mid-R': ' ',
'low-L': ' ', 'low-M': ' ', 'low-R': ' '}
def printBoard(board): #function to print board
print(board['top-L'] + '|' + board['top-M'] + '|' + board['top-R'])
print('-+-+-')
print(board['mid-L'] + '|' + board['mid-M'] + '|' + board['mid-R'])
print('-+-+-')
print(board['low-L'] + '|' + board['low-M'] + '|' + board['low-R'])
print('''
Hi! This is my tic-tac-toe text based game.
To make your move, write where you want to play:
top-L top-M top-R
mid-L mid-M mid-R
low-L low-M low-R
''')
turn= 'X' #starting
while True:
printBoard(theBoard)
print(f'Turn for {turn}. Where will you play?')
try:
move = input()
if theBoard[move] == ' ':
theBoard[move] = turn
if turn == 'X':
turn = 'O'
else:
turn = 'X'
else:
print('That move is not possible!')
continue
except KeyError:
print('''Wrong input.
To make your move, write where you want to play:
top-L top-M top-R
mid-L mid-M mid-R
low-L low-M low-R
''')
continue
if ((theBoard['top-L']==theBoard['top-M']==theBoard['top-R']) and theBoard['top-L']!=' ')\
or ((theBoard['mid-L']==theBoard['mid-M']==theBoard['mid-R']) and theBoard['mid-R']!=' ')\
or ((theBoard['low-L']==theBoard['low-M']==theBoard['low-R']) and theBoard['low-L']!=' ')\
or ((theBoard['top-L']==theBoard['mid-M']==theBoard['low-R']) and theBoard['top-L']!=' ')\
or ((theBoard['low-L']==theBoard['mid-M']==theBoard['top-R']) and theBoard['low-L']!=' ')\
or ((theBoard['top-L']==theBoard['mid-L']==theBoard['low-L']) and theBoard['top-L']!=' ')\
or ((theBoard['top-M']==theBoard['mid-M']==theBoard['low-M']) and theBoard['top-M']!=' ')\
or ((theBoard['top-R']==theBoard['mid-R']==theBoard['low-R']) and theBoard['top-R']!=' '):
break
if turn == 'X':
turn = 'O'
else:
turn = 'X'
print(f'Good Job {turn}, you won!')
This worked well and i turned to codereview for some improvements.
I stored the strings 'X' and 'O' as I discovered that those were considered magic strings and make my code less clean.
Next, I wanted to store all the win conditions in a variable called conditions. But when I do this my program will now not get out of the loop when I get a winning move. Why could this be?
theBoard = {'top-L': ' ', 'top-M': ' ', 'top-R': ' ',
'mid-L': ' ', 'mid-M': ' ', 'mid-R': ' ',
'low-L': ' ', 'low-M': ' ', 'low-R': ' '}
def printBoard(board):
print(board['top-L'] + '|' + board['top-M'] + '|' + board['top-R'])
print('-+-+-')
print(board['mid-L'] + '|' + board['mid-M'] + '|' + board['mid-R'])
print('-+-+-')
print(board['low-L'] + '|' + board['low-M'] + '|' + board['low-R'])
conditions = (((theBoard['top-L'] == theBoard['top-M'] == theBoard['top-R']) and theBoard['top-L'] != ' ') \
or ((theBoard['mid-L'] == theBoard['mid-M'] == theBoard['mid-R']) and theBoard['mid-R'] != ' ') \
or ((theBoard['low-L'] == theBoard['low-M'] == theBoard['low-R']) and theBoard['low-L'] != ' ') \
or ((theBoard['top-L'] == theBoard['mid-M'] == theBoard['low-R']) and theBoard['top-L'] != ' ') \
or ((theBoard['low-L'] == theBoard['mid-M'] == theBoard['top-R']) and theBoard['low-L'] != ' ') \
or ((theBoard['top-L'] == theBoard['mid-L'] == theBoard['low-L']) and theBoard['top-L'] != ' ') \
or ((theBoard['top-M'] == theBoard['mid-M'] == theBoard['low-M']) and theBoard['top-M'] != ' ') \
or ((theBoard['top-R'] == theBoard['mid-R'] == theBoard['low-R']) and theBoard['top-R'] != ' '))
print('''
Hi! This is my tic-tac-toe text based game.
To make your move, write where you want to play:
top-L top-M top-R
mid-L mid-M mid-R
low-L low-M low-R
''')
playerX = 'X'
playerO = 'O'
turn= playerX
while True:
printBoard(theBoard)
print(f'Turn for {turn}. Where will you play?')
try:
move = input()
if theBoard[move] == ' ':
theBoard[move] = turn
if turn == playerX:
turn = player0
else:
turn = playerX
else:
print('That move is not possible!')
continue
except KeyError:
print('''Wrong input.
To make your move, write where you want to play:
top-L top-M top-R
mid-L mid-M mid-R
low-L low-M low-R
''')
continue
if conditions == True:
printBoard(theBoard)
break
if turn == playerX:
turn = player0
else:
turn = playerX
print(f'Good Job {turn}, you won!')

That is because conditions is a bool value. It is calculated when it is set. That is to say - it not a function that makes its computations when it is called. In your case conditions is set to False and it will remain to be False. It is a constant.
Wrap it in a function like this:
def check():
conditions = (((theBoard['top-L'] == theBoard['top-M'] == theBoard['top-R']) and theBoard['top-L'] != ' ') \
or ((theBoard['mid-L'] == theBoard['mid-M'] == theBoard['mid-R']) and theBoard['mid-R'] != ' ') \
or ((theBoard['low-L'] == theBoard['low-M'] == theBoard['low-R']) and theBoard['low-L'] != ' ') \
or ((theBoard['top-L'] == theBoard['mid-M'] == theBoard['low-R']) and theBoard['top-L'] != ' ') \
or ((theBoard['low-L'] == theBoard['mid-M'] == theBoard['top-R']) and theBoard['low-L'] != ' ') \
or ((theBoard['top-L'] == theBoard['mid-L'] == theBoard['low-L']) and theBoard['top-L'] != ' ') \
or ((theBoard['top-M'] == theBoard['mid-M'] == theBoard['low-M']) and theBoard['top-M'] != ' ') \
or ((theBoard['top-R'] == theBoard['mid-R'] == theBoard['low-R']) and theBoard['top-R'] != ' '))
return conditions
And call this function instead of conditions in the if statement:
if check() == True:
printBoard(theBoard)
break

Related

python - how to print Tic Tac Toe game board using for loop

I am new to python. Would like to print the game board for the tic tac toe. May I know how to print using for loop?
Here is my code:
`
board = {
1: ' ', 2: ' ', 3: ' ',
4: ' ', 5: ' ', 6: ' ',
7: ' ', 8: ' ', 9: ' '
}
def printBoard():
print(board[1] + '|'+ board[2]+'|'+board[3])
print('-----')
print(board[4] + '|'+board[5]+'|' + board[6])
print('-----')
print(board[7] + '|'+board[8]+'|' + board[9])
return
`
Your code is fine. You just need to call the function at the end of the script so that it actually gets executed. And the return keyword is not needed as the function doesn't return any value, only prints the board.
board = {
1: ' ', 2: ' ', 3: ' ',
4: ' ', 5: ' ', 6: ' ',
7: ' ', 8: ' ', 9: ' '
}
def printBoard():
print(board[1] + '|'+ board[2]+'|'+board[3])
print('-----')
print(board[4] + '|'+board[5]+'|' + board[6])
print('-----')
print(board[7] + '|'+board[8]+'|' + board[9])
printBoard()
You can make a Tic Tac Toe game using the folowing code :
import random
class TicTacToe:
def __init__(self):
self.board = []
def create_board(self):
for i in range(3):
row = []
for j in range(3):
row.append('-')
self.board.append(row)
def get_random_first_player(self):
return random.randint(0, 1)
def fix_spot(self, row, col, player):
self.board[row][col] = player
def is_player_win(self, player):
win = None
n = len(self.board)
# checking rows
for i in range(n):
win = True
for j in range(n):
if self.board[i][j] != player:
win = False
break
if win:
return win
# checking columns
for i in range(n):
win = True
for j in range(n):
if self.board[j][i] != player:
win = False
break
if win:
return win
# checking diagonals
win = True
for i in range(n):
if self.board[i][i] != player:
win = False
break
if win:
return win
win = True
for i in range(n):
if self.board[i][n - 1 - i] != player:
win = False
break
if win:
return win
return False
for row in self.board:
for item in row:
if item == '-':
return False
return True
def is_board_filled(self):
for row in self.board:
for item in row:
if item == '-':
return False
return True
def swap_player_turn(self, player):
return 'X' if player == 'O' else 'O'
def show_board(self):
for row in self.board:
for item in row:
print(item, end=" ")
print()
def start(self):
self.create_board()
player = 'X' if self.get_random_first_player() == 1 else 'O'
while True:
print(f"Player {player} turn")
self.show_board()
# taking user input
row, col = list(
map(int, input("Enter row and column numbers to fix spot: ").split()))
print()
# fixing the spot
self.fix_spot(row - 1, col - 1, player)
# checking whether current player is won or not
if self.is_player_win(player):
print(f"Player {player} wins the game!")
break
# checking whether the game is draw or not
if self.is_board_filled():
print("Match Draw!")
break
# swapping the turn
player = self.swap_player_turn(player)
# showing the final view of board
print()
self.show_board()
# starting the game
tic_tac_toe = TicTacToe()
tic_tac_toe.start()
You can use two generator expression, one for row and one for each cell. You can add the separators by using the generators in join()
def print_board():
print('\n-----\n'.join(('|'.join(board[i + j] for i in range(1, 4)) for j in range(0, len(board), 3))))

Unexpected NameError ONLY when using Atom editor

I wrote some code for a Python homework assignment and it's running fine in Mu-editor and other IDE's, but not in the Atom editor (using the Hydrogen package to run it), where it gives me an unexpected NameError. I've already posted this issue in the Atom Github, but I'm not getting a response. The code:
theBoard = {'top-L': ' ', 'top-M': ' ', 'top-R': ' ',
'mid-L': ' ', 'mid-M': ' ', 'mid-R': ' ',
'low-L': ' ', 'low-M': ' ', 'low-R': ' '}
def printBoard(board):
print(board['top-L'] + '|' + board['top-M'] + '|' + board['top-R'])
print('-+-+-')
print(board['mid-L'] + '|' + board['mid-M'] + '|' + board['mid-R'])
print('-+-+-')
print(board['low-L'] + '|' + board['low-M'] + '|' + board['low-R'])
turn = 'X'
for i in range(9):
printBoard(theBoard)
print('Turn for ' + turn + '. Move on which space?')
move = input()
theBoard[move] = turn
if turn == 'X':
turn = 'O'
else:
turn = 'X'
printBoard(theBoard)
The NameError I get when trying to run this code:
----> 1 printBoard(theBoard)
NameError: name 'theBoard' is not defined
It throws this error in line 1 of the for loop printBoard(theBoard)
I've played around with formatting and shortening theBoard in case the formatting of the dictionary was the problem, but that did not change anything. theBoard is stored in the global scope (right?), so printBoard should be able to call it in the for loop.
Does anybody have an idea why this is happening?

putting in a loop and how to repeat

I've just started learning and I've only learnt the basics but this is my current code. I need to put it in a loop and ask the user to place the number for up to 8 times.
num_list = ['1','2','3','4','5',]
import random
num = random.choice(num_list)
table = [[' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' ']]
ss = {"W1":[0,0],
"W2":[1,0],
"W3":[2,0],
"W4":[3,0],
"X1":[0,1],
"X2":[1,1],
"X3":[2,1],
"X4":[3,1],
"Y1":[0,2],
"Y2":[1,2],
"Y3":[2,2],
"Y4":[3,2],
"Z1":[0,3],
"Z2":[1,3],
"Z3":[2,3],
"Z4":[3,3]}
ans = input('where would you like to place it: ')
index_ = ss[ans][0]
columns_ = ss[ans][1]
table[index_][columns_] = num
print(table)
This code below here is supposed to make sure the user is placing the number adjacent to another number.
How do I make sure it only starts to check on the 2nd turn onwards? And how do I get it to repeat the turn if it is not adjacent? I also wanted to put the code above into functions and call it at the end to make it neater but I'm not sure what to put in and what to not.
def moveandclip(n, x, y):
n[0] = max(0, min(n[0] + x, 3))
n[1] = max(0, min(n[1] + y, 3))
return n
above = moveandclip(ss[ans], 0 ,1)
below = moveandclip(ss[ans], 0 ,-1)
left = moveandclip(ss[ans], -1 ,0)
right = moveandclip(ss[ans], 1 ,0)
if above == '' and below == '' and left == '' and right == '':
print('It must be placed adjacent to another number.')
repeat the turn
else:
continue to next turn
If you want to run the code 8 times, you can do like this:
def moveandclip(n, x, y):
n[0] = max(0, min(n[0] + x, 3))
n[1] = max(0, min(n[1] + y, 3))
return n
above = moveandclip(ss[ans], 0 ,1)
below = moveandclip(ss[ans], 0 ,-1)
left = moveandclip(ss[ans], -1 ,0)
right = moveandclip(ss[ans], 1 ,0)
for _ in range(8):
if above == '' and below == '' and left == '' and right == '':
print('It must be placed adjacent to another number.')
else:
# Do whatever you want to
# Add more code if you want to run some more statements regardless of the condition
while True:
# Turn code
if above == '' and below == '' and left == '' and right == '':
print('It must be placed adjacent to another number.')
else:
break

How to implement a grid using arrays with a given size?

I am trying to create a simple board in a draw_board definition that will use size and several coordinates where I will place 1 character length characters in specified coordinates. I am in the beginning stages and want to just simply create the board itself using a 2d array.
This method below works when I change individual elements :
board = [['','','',''], ['','','',''], ['', '', '', ''], ['','','','']]
board[0][0] = 'a'
print(' 0 1 2 3')
print('0 ' + board[0][0] + ' ' + board[0][1] + ' ' + board[0][2] + ' ' + board[0][3])
print('1 ' + board[1][0] + ' ' + board[1][1] + ' ' + board[1][2] + ' ' + board[1][3])
print('2 ' + board[2][0] + ' ' + board[2][1] + ' ' + board[2][2] + ' ' + board[2][3])
print('3 ' + board[3][0] + ' ' + board[3][1] + ' ' + board[3][2] + ' ' + board[3][3])
However, I would not be able to change the size by just a variable and would need to edit the initialization of the board myself.
This method below is better and would work because I could easily change the size variable and get any size board I want...
size = 4
board = [['']*size]*size
board[0][0] = 'a'
print(' 0 1 2 3')
print('0 ' + board[0][0] + ' ' + board[0][1] + ' ' + board[0][2] + ' ' + board[0][3])
print('1 ' + board[1][0] + ' ' + board[1][1] + ' ' + board[1][2] + ' ' + board[1][3])
print('2 ' + board[2][0] + ' ' + board[2][1] + ' ' + board[2][2] + ' ' + board[2][3])
print('3 ' + board[3][0] + ' ' + board[3][1] + ' ' + board[3][2] + ' ' + board[3][3])
However, when I implement board[0][0] = 'a', it changes the entire column to 'a', which is not what I want. Any suggestions of how I could change this second method to make it work for just the desired coordinate?
Use
board = [['' for i in range(size)] for j in range(size)]
this is because when you use the * operator, you're creating more references to the same object, not more copies.
Here's more in depth information about the strategy used above, called list comprehensions

B-ship game: X's and O's are just screwing up. (Python)

I am making a game of B-ship, and I am unable to get the placements to work out.
The hits don't stay there after i call another hit.
So far this is user side only.
Here's my code.
def drawboard(hitboard):
print('| | | |')
print('| ' + hitboard[7] + ' | ' + hitboard[8] + ' | ' + hitboard[9] + ' |')
print('| | | |')
print('-------------')
print('| | | |')
print('| ' + hitboard[4] + ' | ' + hitboard[5] + ' | ' + hitboard[6] + ' |')
print('| | | |')
print('-------------')
print('| | | |')
print('| ' + hitboard[1] + ' | ' + hitboard[2] + ' | ' + hitboard[3] + ' |')
print('| | | |')
def aiships(hitboard):
hitboard[1], hitboard[2], hitboard[3] = ' ',' ',' '
#One of the AI's ships
def aicorners(hitboard,spot_hit):
if hitboard[spot_hit] == hitboard[1] or hitboard[spot_hit] == hitboard[2] or hitboard[spot_hit] == hitboard[3]:
hitboard[spot_hit] = 'x'
else:
hitboard[spot_hit] = 'o'
print(drawboard(hitboard))
def aiedges(hitboard,spot_hit):
if hitboard[spot_hit] == hitboard[1] or hitboard[spot_hit] == hitboard[2] or hitboard[spot_hit] == hitboard[3]:
hitboard[spot_hit] = 'x'
else:
hitboard[spot_hit] = 'o'
print(drawboard(hitboard))
def aimiddle(hitboard,spot_hit):
if hitboard[spot_hit] == hitboard[1] or hitboard[spot_hit] == hitboard[2] or hitboard[spot_hit] == hitboard[3]:
hitboard[spot_hit] = 'x'
else:
hitboard[spot_hit] = 'o'
print(drawboard(hitboard))
def main():
gameisplaying = True
while gameisplaying:
hitboard = [' ']* 10
userready = input('Place your ships. Type done when you finished placing it.')
while not userready == 'done':
userready = input('Type done when you locate your ship. ')
shipissunk = False
while shipissunk == False:
spot_hit = input('Where\'s the hit?: 1-9 ')
while not (spot_hit in '1 2 3 4 5 6 7 8 9'.split()):
spot_hit = input ('Please tell me where the hit is: 1-9 ')
spot_hit = int(spot_hit)
x = aiships(hitboard)
if (spot_hit in [1,3,7,9]):
aicorners(hitboard,spot_hit)
elif (spot_hit in [2,4,6,8]):
aiedges(hitboard,spot_hit)
else:
aimiddle(hitboard,spot_hit)
main()
You are supposed to get your own piece of paper. When you place your ships on your IRL paper, you type 'done' and then you guess the computer's ships.
I put in 2 and it showed up as X, which is good. Putting in 3 erases the previous X and puts an X in 3, so there's still only 1 X. That is not good. However, when I put it in 4,5,6,7,8 or 9, it stays, but Some are X's (not good) and some are O's (good). X = hit O = miss
Help is appreciated!
One mistake (maybe there are others) is declaring:
hitboard = [' ']* 10
by doing so, you create "10 cells" which all point to the same place " ". When "one" changes - so will all the others.
Use instead:
hitboard = [' ' for i in range(10)]
Another mistake is the function aiships(), it's messing with places 1,2 and 3. simply remove the following lines:
def aiships(hitboard):
hitboard[1], hitboard[2], hitboard[3] = ' ',' ',' '
#One of the AI's ships
and:
x = aiships(hitboard)

Categories