Python debugging advice needed - python

I am trying to make a tic tac toe program, I set the user to be X and the computer to be Y. Once a winner is
declared it is
supposed
to start the game to play again. It runs perfectly through the loop the first time, but on the following game it
changes the user to O and the computer to O, also only the user has a turn the computer never goes,
but the program
registers the computer as winning because the computer is O . If the program chooses the computer to go first,
it will make
the first move, but it wont get a turn again. I think there is something wrong with the loop but I cant figure out
where.
import random
winningCombinations=[]
userhistory=[]
secondchance=[]
def drawBoard(board):
# This function prints out the board that it was passed.
# "board" is a list of 10 strings representing the board (ignore index 0)
print('')
print('')
print(' | |')
print(' ' + board[7] + ' | ' + board[8] + ' | ' + board[9])
print(' | |')
print('-----------')
print(' | |')
print(' ' + board[4] + ' | ' + board[5] + ' | ' + board[6])
print(' | |')
print('-----------')
print(' | |')
print(' ' + board[1] + ' | ' + board[2] + ' | ' + board[3])
print(' | |')
print('')
print('')
def getComputerMove():
# Here is our algorithm for our Tic Tac Toe AI:
if userhistory in winningCombinations:
#try to beat it
blockingMove = secondchance[len(secondchance)-1]
return blockingMove
else:
#make a rando move
move = random.randint(1, 9)
while theBoard[move] != ' ': #if the move is invalid or occupied
move = random.randint(1, 9)
return move
print('Welcome to Tic Tac Toe!')
#First ask the user if it wants to be X or 0
userin = ''
#while not (userin == 'X' or userin == 'O'):
# userin = raw_input('Do you want to be X or O?').upper()
# the first element in the tuple is the player's letter, the second is the computer's letter.
#if userin == 'X':
# playerLetter, computerLetter = ['X', 'O']
#elif userin =="O":
# computerLetter, playerLetter = ['O', 'X']
numGames = 1 #to keep track of the user history
#computergenerates who gets to go first
if random.randint(0, 1) == 0:
turn = 'computer'
else:
turn = 'player'
print('The ' + turn + ' will go first.')
while True:
# Reset the board
theBoard = [' '] * 10
del userhistory[:]
gameIsPlaying = True
while gameIsPlaying:
playerLetter = 'X'
computerLetter = 'O'
if turn == 'player':
# Player's turn.
drawBoard(theBoard)
umove = int(raw_input('What is your next move? (1-9)'))
while theBoard[umove] != ' ': #if the move is invalid or occupied
umove = int(raw_input('What is your next move? (1-9)'))
theBoard[umove]=playerLetter #places move onto board
userhistory.append(umove) #records users moves
secondchance.append(umove)#records users moves
#Check to see if its a winner
if ((theBoard[7] == playerLetter and theBoard[8] == playerLetter and theBoard[9] == playerLetter) or # across the top
(theBoard[4] == playerLetter and theBoard[5] == playerLetter and theBoard[6] == playerLetter) or # across the middle
(theBoard[1] == playerLetter and theBoard[2] == playerLetter and theBoard[3] == playerLetter) or # across the bottom
(theBoard[7] == playerLetter and theBoard[4] == playerLetter and theBoard[1] == playerLetter) or # down the left side
(theBoard[8] == playerLetter and theBoard[5] == playerLetter and theBoard[2] == playerLetter) or # down the middle
(theBoard[9] == playerLetter and theBoard[6] == playerLetter and theBoard[3] == playerLetter) or # down the right side
(theBoard[7] == playerLetter and theBoard[5] == playerLetter and theBoard[3] == playerLetter) or # diagonal
(theBoard[9] == playerLetter and theBoard[5] == playerLetter and theBoard[1] == playerLetter)):
drawBoard(theBoard)
print('Hooray! You have won the game!')
del userhistory[len(userhistory)-1] #deleting last element to find the combination just before losing
winningCombinations.append(userhistory) #stores the winning combination into another list
numGames+=1
gameIsPlaying = False
else:
empty = ' '
if empty not in theBoard:
print('The game is a tie!')
break
else:
turn = 'computer'
else:
# Computer's turn.
cmove = getComputerMove()
theBoard[cmove] = computerLetter
if ((theBoard[7] == computerLetter and theBoard[8] == computerLetter and theBoard[9] == computerLetter) or # across the top
(theBoard[4] == computerLetter and theBoard[5] == computerLetter and theBoard[6] == computerLetter) or # across the middle
(theBoard[1] == computerLetter and theBoard[2] == computerLetter and theBoard[3] == computerLetter) or # across the bottom
(theBoard[7] == computerLetter and theBoard[4] == computerLetter and theBoard[1] == computerLetter) or # down the left side
(theBoard[8] == computerLetter and theBoard[5] == computerLetter and theBoard[2] == computerLetter) or # down the middle
(theBoard[9] == computerLetter and theBoard[6] == computerLetter and theBoard[3] == computerLetter) or # down the right side
(theBoard[7] == computerLetter and theBoard[5] == computerLetter and theBoard[3] == computerLetter) or # diagonal
(theBoard[9] == computerLetter and theBoard[5] == computerLetter and theBoard[1] == computerLetter)):
drawBoard(theBoard)
print('Aw! You have lost the game, the computer has beaten you!')
gameIsPlaying = False
else:
empty = ' '
if empty not in theBoard:
print('The game is a tie!')
break
else:
turn = 'player'

Since you're asking for debugging advice, I'll answer at that level.
When you have a sick patient, ask where it hurts. The print command is a blunt, but effective weapon. At critical points in your code, stick in a statement such as
print "CHECKPOINT A", "turn =", turn
In other words, trace both logic flow and useful values. These statements are especially useful at the top or bottom of a block (loop or function).
Next, when you have a long block of code, consider moving some of the logic into a function. In this program, your code to detect a win would be a good candidate: you have 8 long lines of identical code you could isolate and replace with a function call.
I expect that these two will be enough to track down the problem; they handle almost all of my own failures. Rather than repeating long-standing advice, one point after another, I commend to you the blog post how to debug for further suggestions.

Related

List not defined in a function in Python

I am working on one of my first codes (Tic Tac Toe), and I cannot figure out why I'm getting a name error.
First I have a list (board).
Then I have a function (possible_victory_for() ) that I define. It is supposed to to something with a list (temp_board) that will be defined later, within the next function.
The next function (computer_move() ) says temp_board = board and then calls the possible_victory_for().
In my understanding, seeing as "board" seems to work fine, the temp_board = board should be enough of a definition for temp_board. But Python disagrees.
I tried to recreate the error on a simple example, like this:
board = [1, 2, 3]
temp_board = board
if temp_board[0] == 1:
print("it works")
But this works fine and doesn't produce the error. So maybe it's something related to communication between functions (or simply a typo somewhere)?
As I fail to shorten the code and get the same error, I am attaching everything I made for now. Sorry for a long post.
(if you decide to run the code, go for Medium difficulty, that's where the error happens).
# I need these functions to make everything work
# clear_output was imported by Google Colab, not sure if it's standard
# all mentions of clear_output can be deleted if needed, the code will work
# but it will show every turn made by computer/human, not just the current board
from IPython.core.display import clear_output
from random import randrange
# Sets the board at the beginning
board = [1, 2, 3, 4, 5, 6, 7, 8, 9]
# Just displays the current board
def display_board():
print(
"\n+-------+-------+-------+",
"\n| | | |",
"\n| ",board[0]," | ",board[1]," | ",board[2]," |",
"\n| | | |",
"\n+-------+-------+-------+",
"\n| | | |",
"\n| ",board[3]," | ",board[4]," | ",board[5]," |",
"\n| | | |",
"\n+-------+-------+-------+",
"\n| | | |",
"\n| ",board[6]," | ",board[7]," | ",board[8]," |",
"\n| | | |",
"\n+-------+-------+-------+"
)
# Asks player to define who plays first (human or computer). Impacts the order of turns.
def who_plays_first():
global first_player
while True:
first_player = int(input("Choose who plays first: 1 for human, 2 for computer"))
if first_player == 1 or first_player == 2:
break
print("invalid input, read the instruction")
if first_player == 1:
first_player = "human"
else:
first_player = "computer"
return(first_player)
# Asks player to set difficulty. Impacts how computer decides on its move.
def choose_difficulty():
global difficulty
while True:
difficulty = int(input("Choose difficulty: 1 = easy, 2 = medium, 3 = hard"))
if difficulty == 1 or difficulty == 2 or difficulty == 3:
break
print("invalid input, read the instruction")
if difficulty == 1:
difficulty = "easy"
elif difficulty == 2:
difficulty = "medium"
else:
difficulty = "hard"
return(difficulty)
# Makes a list of free fields. Used in other functions.
def make_list_of_free_fields():
list_of_free_fields = []
for field in range(1,10):
if field in board:
list_of_free_fields.append(field)
return(list_of_free_fields)
# Checks whether the player (defined by the sign) won.
def victory_for(sign):
if (board[0] == sign and board[1] == sign and board[2] == sign or
board[3] == sign and board[4] == sign and board[5] == sign or
board[6] == sign and board[7] == sign and board[8] == sign or
board[0] == sign and board[3] == sign and board[6] == sign or
board[1] == sign and board[4] == sign and board[7] == sign or
board[2] == sign and board[5] == sign and board[8] == sign or
board[0] == sign and board[4] == sign and board[8] == sign or
board[2] == sign and board[4] == sign and board[6] == sign):
return True
else:
return False
# Same as victory_for, but only used to help computer make its move on medium/hard.
def possible_victory_for(sign):
if (temp_board[0] == sign and temp_board[1] == sign and temp_board[2] == sign or
temp_board[3] == sign and temp_board[4] == sign and temp_board[5] == sign or
temp_board[6] == sign and temp_board[7] == sign and temp_board[8] == sign or
temp_board[0] == sign and temp_board[3] == sign and temp_board[6] == sign or
temp_board[1] == sign and temp_board[4] == sign and temp_board[7] == sign or
temp_board[2] == sign and temp_board[5] == sign and temp_board[8] == sign or
temp_board[0] == sign and temp_board[4] == sign and temp_board[8] == sign or
temp_board[2] == sign and temp_board[4] == sign and temp_board[6] == sign):
return True
else:
return False
# Asks the human player to make their move.
def human_move():
while True:
human_input = int(input("Choose a field"))
if human_input in make_list_of_free_fields():
break
print("You must choose one of the free fields on the board by typing 1-9")
board[human_input-1] = "O"
# This is how the computer makes its move.
# Depends on the difficulty.
# Easy is completely random.
# Medium checks whether:
# a) there's a (list of) move(s) that could guarantee computer's victory
# b) there's a (list of) move(s) that could guarantee human's victory
# - then play a random move out of that list (computer victory has priority)
# Hard is yet to be defined.
def computer_move():
if difficulty == "easy":
while True:
computer_input = randrange(10)
if computer_input in make_list_of_free_fields():
break
board[computer_input-1] = "X"
# elif difficulty == "medium":
else:
brings_computer_victory = []
brings_human_victory = []
for field in make_list_of_free_fields():
temp_board = board
temp_move = field
temp_board[temp_move-1] = "X"
if possible_victory_for("X") == True:
brings_computer_victory.append(temp_move)
if brings_computer_victory != []:
computer_input = randrange(1, len(brings_computer_victory) + 1)
board[computer_input-1] = "X"
for field in make_list_of_free_fields():
temp_board = board
temp_move = field
temp_board[temp_move-1] = "O"
if possible_victory_for("O") == True:
brings_human_victory.append(temp_move)
if brings_human_victory != []:
computer_input = randrange(1, len(brings_human_victory) + 1)
board[computer_input-1] = "X"
# This is the final piece of code that connects all the functions.
who_plays_first()
choose_difficulty()
clear_output()
if first_player == "human":
display_board()
while True:
human_move()
clear_output()
display_board()
if victory_for("O") == True:
print("You won!")
break
if len(make_list_of_free_fields()) == 0:
print("it's a tie")
break
computer_move()
clear_output()
display_board()
if victory_for("X") == True:
print("You lost!")
break
else:
while True:
computer_move()
clear_output()
display_board()
if victory_for("X") == True:
print("You lost!")
break
if len(make_list_of_free_fields()) == 0:
print("it's a tie")
break
human_move()
clear_output()
display_board()
if victory_for("O") == True:
print("You won!")
break
Here's the error traceback:
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-11-322daee905b6> in <module>
28
29 while True:
---> 30 computer_move()
31 clear_output()
32 display_board()
1 frames
<ipython-input-10-6530342ed281> in computer_move()
24 temp_move = field
25 temp_board[temp_move-1] = "X"
---> 26 if possible_victory_for("X") == True:
27 brings_computer_victory.append(temp_move)
28 if brings_computer_victory != []:
<ipython-input-8-bd71fed33fb4> in possible_victory_for(sign)
1 # Same as victory_for, but only used to help computer make its move on medium/hard.
2 def possible_victory_for(sign):
----> 3 if (temp_board[0] == sign and temp_board[1] == sign and temp_board[2] == sign or
4 temp_board[3] == sign and temp_board[4] == sign and temp_board[5] == sign or
5 temp_board[6] == sign and temp_board[7] == sign and temp_board[8] == sign or
NameError: name 'temp_board' is not defined
temp_board is local to computer_move, but you're treating it as if it were a global. You should make it a parameter to possible_victory_for:
def possible_victory_for(sign, temp_board):
# if (temp_board[0] ...
and then pass it from computer_move as an argument:
if possible_victory_for("X", temp_board) == True:
In general I'd recommend passing variables to your functions as arguments rather than relying on pulling them implicitly from an outer scope; it makes the dependencies between different parts of your code more obvious (in this case possible_victory_for depends on not only sign but the current values of temp_board), which makes it easier to change and extend.

Tic-Tac-Toe with Single and Multiplayer in Python

So basically I am trying to build a Tic-Tac-Toe game with both single and multiplayer difficulty levels but I am stuck on what code should I write for player vs computer and I am stuck in a forever loop in the def play_game() function. I can't keep the previous stats of the game as well. I really need help with this.
# --------- Global Variables -----------
# Will hold our game board data
board = ["-", "-", "-",
"-", "-", "-",
"-", "-", "-"]
# Lets us know if the game is over yet
game_still_going = True
# Tells us who the winner is
winner = None
# Tells us who the current player is (X goes first)
current_player = "X"
# ------------- Functions ---------------
# Play a game of tic tac toe
def play_game():
# Show the initial game board
display_board()
game_on = True
while True:
print("1.Single Player")
print("2.Multiplayer")
print("3.Game Stats")
print("4.Quit")
input_1 = int(input("Please Select An Option"))
if input_1 == "3" :
print('reading database...')
read_log()
elif input_1 == "4" :
exit()
elif input_1 == "2" :
Player_1 = input("Enter First Player Name:")
Player_2 = input("Enter Second Player Name:")
display_board()
while game_on:
position = input("Choose a position from 1-9: ")
check_for_winner()
display_board()
# Loop until the game stops (winner or tie)
while game_still_going:
# Handle a turn
handle_turn(current_player)
# Check if the game is over
check_if_game_over()
# Flip to the other player
flip_player()
# Since the game is over, print the winner or tie
if winner == "X" or winner == "O":
print(winner + " won.")
elif winner == None:
print("Tie.")
# Display the game board to the screen
def display_board():
print("\n")
print(board[0] + " | " + board[1] + " | " + board[2] + " 1 | 2 | 3")
print(board[3] + " | " + board[4] + " | " + board[5] + " 4 | 5 | 6")
print(board[6] + " | " + board[7] + " | " + board[8] + " 7 | 8 | 9")
print("\n")
# Handle a turn for an arbitrary player
def handle_turn(player):
# Get position from player
print(player + "'s turn.")
position = input("Choose a position from 1-9: ")
# Whatever the user inputs, make sure it is a valid input, and the spot is open
valid = False
while not valid:
# Make sure the input is valid
while position not in ["1", "2", "3", "4", "5", "6", "7", "8", "9"]:
position = input("Choose a position from 1-9: ")
# Get correct index in our board list
position = int(position) - 1
# Then also make sure the spot is available on the board
if board[position] == "-":
valid = True
else:
print("You can't go there. Go again.")
# Put the game piece on the board
board[position] = player
# Show the game board
display_board()
# Check if the game is over
def check_if_game_over():
check_for_winner()
check_for_tie()
# Check to see if somebody has won
def check_for_winner():
# Set global variables
global winner
# Check if there was a winner anywhere
row_winner = check_rows()
column_winner = check_columns()
diagonal_winner = check_diagonals()
# Get the winner
if row_winner:
winner = row_winner
elif column_winner:
winner = column_winner
elif diagonal_winner:
winner = diagonal_winner
else:
winner = None
# Check the rows for a win
def check_rows():
# Set global variables
global game_still_going
# Check if any of the rows have all the same value (and is not empty)
row_1 = board[0] == board[1] == board[2] != "-"
row_2 = board[3] == board[4] == board[5] != "-"
row_3 = board[6] == board[7] == board[8] != "-"
# If any row does have a match, flag that there is a win
if row_1 or row_2 or row_3:
game_still_going = False
# Return the winner
if row_1:
return board[0]
elif row_2:
return board[3]
elif row_3:
return board[6]
# Or return None if there was no winner
else:
return None
# Check the columns for a win
def check_columns():
# Set global variables
global game_still_going
# Check if any of the columns have all the same value (and is not empty)
column_1 = board[0] == board[3] == board[6] != "-"
column_2 = board[1] == board[4] == board[7] != "-"
column_3 = board[2] == board[5] == board[8] != "-"
# If any row does have a match, flag that there is a win
if column_1 or column_2 or column_3:
game_still_going = False
# Return the winner
if column_1:
return board[0]
elif column_2:
return board[1]
elif column_3:
return board[2]
# Or return None if there was no winner
else:
return None
# Check the diagonals for a win
def check_diagonals():
# Set global variables
global game_still_going
# Check if any of the columns have all the same value (and is not empty)
diagonal_1 = board[0] == board[4] == board[8] != "-"
diagonal_2 = board[2] == board[4] == board[6] != "-"
# If any row does have a match, flag that there is a win
if diagonal_1 or diagonal_2:
game_still_going = False
# Return the winner
if diagonal_1:
return board[0]
elif diagonal_2:
return board[2]
# Or return None if there was no winner
else:
return None
# Check if there is a tie
def check_for_tie():
# Set global variables
global game_still_going
# If board is full
if "-" not in board:
game_still_going = False
return True
# Else there is no tie
else:
return False
# Flip the current player from X to O, or O to X
def flip_player():
# Global variables we need
global current_player
# If the current player was X, make it O
if current_player == "X":
current_player = "O"
# Or if the current player was O, make it X
elif current_player == "O":
current_player = "X"
def read_log():
log = open('log.txt', 'r')
log.seek(0)
print('\n\n')
print(log.read(),'\n\n')
# ------------ Start Execution -------------
# Play a game of tic tac toe
play_game()
If I understood correctly You can do it like this:
Define functions:
handle_player_move()
handle_computer_move()
as names suggests when you call the function either human player or computer will make a move (make sure that it's certain or add some Errorcodes/Exceptions when player do something unexpected and you want to end program)
Define function:
game_is_over() # returns True if it's the end of game False other wise
Then Your game is just:
Human vs Human:
whos_move = 0 # number of player ( 0 or 1 )
while not game_is_over():
if whos_move == 0:
handle_player_move(player1)
if whos_move == 1:
handle_player_move(player2)
whos_move = (whos_move + 1) % 2
Quite similarly Human vs Bot:
whos_move = 0 # number of player ( 0 or 1 )
while not game_is_over():
if whos_move == 0:
handle_player_move(player1)
if whos_move == 1:
handle_computer_move(player2)
whos_move = (whos_move + 1) % 2
Instead of this you can also check for end of game with your function, and do:
whos_move = 0 # number of player ( 0 or 1 )
while game_still_going:
if whos_move == 0:
handle_player_move(player1)
if whos_move == 1:
handle_computer_move(player2)
whos_move = (whos_move + 1) % 2
check_if_game_over()
if statement: # your ending statement here
game_is_still_going = False
Your method with flip_player() is also good I just put if statements to both so that they are familiar in truth if you would are able to distinguish in handle_turn() between bot and human player you can do it for both cases ;)
As implementing computer moves can be hard here are some tips:
Easiest way you can just randomly choose number between 1 and 9 check if it's unoccupied if it's free computer makes move there if it is not you pick again. Maybe it sounds like being potentially endless loop but statisticly computer shouldn't have any problems with making a move.
You can also create list of free squares and then randomly choose an index (probably better way)
You can also try to add some logic f.e. if there are two in a row block third square.
too choose random integer from given interval you can use:
import random
random.randint(1,9) # choose integer x such that: 1 <= x <= 9
Of course you can and even maybe should use your own function names (name them as you wish!)
Hope that helps, good luck!

Tic Tac Toe in Python: Problem with indentation or code?

I am a complete beginner with Python and coding in general. I am making a Tic Tac Toe game in Python as part of the online course I am studying.
I've struggled with getting my head around the nitty gritty of how functions work and can be utilised. I have had to follow the course notes quite closely to try and understand what is happening once the code starts fitting together. Can't find similar problems on here so it can't be an issue with the course notes!
When I run the programme, it skips my position_choice() function, displays the empty board and then asks to replay. I feel I'm missing some basic issue like indentation, but would really appreciate if anyone is able to spot a problem with the function itself or the code set up? It follows the course notes structure almost identically and I'm at a loss!
Here are the functions:
from IPython.display import clear_output
import random
def display_board(board):
clear_output()
print(' ' + board[7] + ' ' + '|' + ' ' + board[8] + ' ' + '|' + ' ' + board[9] + ' ')
print('- - - - - -')
print(' ' + board[4] + ' ' + '|' + ' ' + board[5] + ' ' + '|' + ' ' + board[6] + ' ')
print('- - - - - -')
print(' ' + board[1] + ' ' + '|' + ' ' + board[2] + ' ' + '|' + ' ' + board[3] + ' ')
def player_choice():
player1 = input('Choose your marker: '.upper())
while True:
if player1.upper() == 'X':
player2 = 'O'
print('\nPlayer 1 is ' + player1.upper() + '\nPlayer 2 is ' + player2 + '.')
return player1.upper(), player2
elif player1.upper() == 'O':
player2 = 'X'
print('\nPlayer 1 is ' + player1.upper() + '\nPlayer 2 is ' + player2 + '.')
return player1.upper(), player2
else:
print('Sorry, that is not a valid marker. Please choose either O or X.')
player1 = input('Choose your marker: '.upper())
def place_marker(board, marker, position):
board[position] = marker
def win_check(position, mark):
return ((position[7] == position[8] == position[9] == mark)
or (position[4] == position[5] == position[6] == mark)
or (position[1] == position[2] == position[3] == mark)
or (position[1] == position[5] == position[9] == mark)
or (position[7] == position[5] == position[3] == mark)
or (position[7] == position[4] == position[1] == mark)
or (position[8] == position[5] == position[2] == mark)
or (position[9] == position[6] == position[3] == mark))
def choose_first():
rand_int = random.randint(1,2)
if rand_int == 1:
print('Player 1 goes first')
return '1'
if rand_int == 2:
print('Player 2 goes first')
return '2'
def space_check(board, position):
return board[position] == ' '
def full_board_check(board):
for position in range(1,10):
if space_check(board, position):
return False
return True
def position_choice(board):
position = 0
while position not in [1,2,3,4,5,6,7,8,9] and not space_check(board, position):
position = int(input('Please choose your position: '))
return position
def replay():
return input('Do you want to play again?').lower().startswith('y')
def play_game():
play_game = input('Do you want to play?')
if play_game.lower()[0] == 'y':
return True
else:
return False
And here's the programme code. Why does it just display the empty board, skip asking for the position, and ask for the replay? Any help would keep up my stalling motivation!!
print('Welcome to Tic Tac Toe!')
while play_game():
theboard = [' '] * 10
player1_marker, player2_marker = player_choice()
turn = choose_first()
if turn == 1:
display_board(theboard)
position = position_choice(theboard)
place_marker(theboard, player1_marker, position)
if win_check(theboard, player1_marker):
display_board(theboard)
print('Player 1 is the winner!')
replay()
else:
if full_board_check(theboard):
display_board(theboard)
print('The game is a tie!')
replay()
else:
turn == 2
else:
display_board(theboard)
position = position_choice(theboard)
place_marker(theboard, player2_marker, position)
if win_check(theboard, player2_marker):
display_board(theboard)
print('Player 2 is the winner!')
replay()
else:
if full_board_check(theboard):
display_board(theboard)
print('The game is a tie!')
replay()
else:
turn == 1
if not replay():
break
There are several problems :
The choose_first returns a String instead of an integer.
The method called in the while, always ask if you want to play.
You recreate a new board on each loop, you have to declare it before the loop if you don't want to lose it.
At the end of each loop you ask each times if you want to replay
to change the turn variable you should do turn = 2 instead of using double equals witch is comparing equality.
And when you want to "replay", don't forget to reset the board.
To debug this, you should comment a part of your code. And run it step by step. By doing this, you will find were are the errors.
Here is the code, the game will works but you may still want to ad some improvements.
theboard = [' '] * 10
if play_game():
player1_marker, player2_marker = player_choice()
turn = choose_first()
while not full_board_check(theboard):
display_board(theboard)
position = position_choice(theboard)
if turn == 1:
place_marker(theboard, player1_marker, position)
if win_check(theboard, player1_marker):
display_board(theboard)
print('Player 1 is the winner!')
if replay():
theboard = [' '] * 10
else:
break
turn = 2
else:
place_marker(theboard, player2_marker, position)
if win_check(theboard, player2_marker):
display_board(theboard)
print('Player 2 is the winner!')
if replay():
theboard = [' '] * 10
else:
break
turn = 1
if full_board_check(theboard):
display_board(theboard)
print('The game is a tie!')
if replay():
theboard = [' '] * 10
else:
break
Why does it just display the empty board, skip asking for the position, and ask for the replay?
position not in [1,2,3,4,5,6,7,8,9] and not space_check(board, position) - this condition isn't working, the logic is wrong.
>>> theboard = [' '] * 10
>>> theboard
[' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']
>>> position = 0
>>> position not in [1,2,3,4,5,6,7,8,9] and not space_check(theboard, position)
False
>>>
Here is one way to refactor position_choice
def position_choice(board):
#print(board)
#position = 0
valid = False
# keep asking till thay give a valid answer
while not valid:
position = int(input('Please choose your position (1-9): '))
valid = position in [1,2,3,4,5,6,7,8,9]
valid = valid and space_check(board, position)
return position
## OLD STUFF
## while position not in [1,2,3,4,5,6,7,8,9] and not space_check(board, position):
## position = int(input('Please choose your position: '))
##
## return position
Asking the user for input until they give a valid response
How to debug small programs

How can I resolve this loop that asks to duplicate input?

I'm still struggling with Python but it's been a good time. I keep running into this problem and unsure of how to get past it. The issue is that when I run the program, every time I make an input for the game it prompts me with another input asking if I want to play again. When I input yes, it goes forward with the program but after every line after it keeps asking me if I want to play again while I'm already in the process of playing the game. Is there something I've missed because when I compare it to the original code I have it matched in the same way as far as I'm aware. If someone has seen something I've missed or have run into the error before please let me know. Thank you!
import random
def drawBoard(board):
# This function prints out the board that it was passed
# "board" is a list of 10 strings representing the board (ignore index 0)
print(' | |')
print(' ' + board[7] + ' | ' + board[8] + ' | ' + board[9])
print(' | |')
print('-----------')
print(' | |')
print(' ' + board[4] + ' | ' + board[5] + ' | ' + board[6])
print(' | |')
print('-----------')
print(' | |')
print(' ' + board[1] + ' | ' + board[2] + ' | ' + board[3])
print(' | |')
def inputPlayerLetter():
# Lets the player type which letter they want to be.
# Returns a list with the player's letter as the first item, and the computer's letter as the second
letter = ''
while not (letter == 'X' or letter == 'O'):
print('Do you want to be X or O?')
letter = input().upper()
# the first element in the list is the player's letter, the second is the compiuter's letter.
if letter == 'X':
return ['X', 'O']
else:
return ['O', 'X']
def whoGoesFirst():
# Randomly choose the player who goes first.
if random.randint(0, 1) == 0:
return 'computer'
else:
return 'player'
def playAgain():
# This function returns True if the player wants to play again, otherwise it returns False.
print('Do you want to play again? (yes or no)')
return input().lower().startswith('y')
def makeMove (board, letter, move):
board[move] = letter
def isWinner(bo, le):
# Given a board and the player's letter, this function returns True if that player has won.
# We use bo instead of board and le instead of letter so we don't have to type as much.
return ((bo[7] == le and bo[8] == le and bo[9] == le) or # across the top
(bo[4] == le and bo[5] == le and bo[6] == le) or # across the middle
(bo[1] == le and bo[2] == le and bo[3] == le) or # across the bottom
(bo[7] == le and bo[4] == le and bo[1] == le) or # down the left side
(bo[8] == le and bo[5] == le and bo[2] == le) or # down the middle
(bo[9] == le and bo[6] == le and bo[3] == le) or # down the right side
(bo[7] == le and bo[5] == le and bo[3] == le) or # diagonal
(bo[9] == le and bo[5] == le and bo[1] == le)) # diagonal
def getBoardCopy(board):
# Make a duplicate of the board list and return it the duplicate.
dupeBoard = []
for i in board:
dupeBoard.append(i)
return dupeBoard
def isSpaceFree(board, move):
# Return true if the passed move is free on the passed board.
return board[move] == ' '
def getPlayerMove(board):
# Let the player type in their move.
move = ' '
while move not in '1 2 3 4 5 6 7 8 9'.split() or not isSpaceFree(board, int(move)):
print('What is your next move? (1-9)')
move = input()
return int(move)
def chooseRandomMoveFromList(board, movesList):
# Returns a valid move from the passed list on the passed board.
#Returns None if there is no valid move.
possibleMoves = []
for i in movesList:
if isSpaceFree(board, i):
possibleMoves.append(i)
if len(possibleMoves) != 0:
return random.choice(possibleMoves)
else:
return None
def getComputerMove(board, computerLetter):
# Given a board and the computer's letter, determine where to move and return that move.
if computerLetter == 'X':
playerLetter = 'O'
else:
playerLetter = 'X'
# Here is our algorithm for the Tic Tac Toe AI:
# First, check if we can win in the next move
for i in range(1, 10):
copy = getBoardCopy (board)
if isSpaceFree(copy, i):
makeMove(copy, computerLetter, i)
if isWinner(copy, computerLetter):
return i
# Check if the player could win on their next move, and block them.
for i in range(1, 10):
copy = getBoardCopy(board)
if isSpaceFree(copy, i):
makeMove(copy, playerLetter, i)
if isWinner(copy, playerLetter):
return i
# Try to take one of the corners, if they are free.
move = chooseRandomMoveFromList(board, [1, 3, 7, 9])
if move != None:
return move
# Try to take the center, if it is free.
if isSpaceFree(board, 5):
return 5
# Move on one of the sides.
return chooseRandomMoveFromList(board, [2, 4, 6, 8])
def isBoardFull(board):
# Return True if every space on the board has been taken. Otherwise return False.
for i in range(1, 10):
if isSpaceFree(board, i):
return False
return True
print('Welcome to Tic Tac Toe!')
while True:
# Reset the board
theBoard = [' '] * 10
playerLetter, computerLetter = inputPlayerLetter()
turn = whoGoesFirst()
print('The ' + turn + ' will go first.')
gameIsPlaying = True
while gameIsPlaying:
if turn == 'player':
# Player's turn.
drawBoard(theBoard)
move = getPlayerMove(theBoard)
makeMove(theBoard, playerLetter, move)
if isWinner(theBoard, playerLetter):
drawBoard(theBoard)
print('Hooray! You have won the game!')
gameIsPlaying = False
else:
if isBoardFull(theBoard):
drawBoard(theBoard)
print('The game is a tie!')
break
else:
turn = 'computer'
else:
# Computer's turn.
move = getComputerMove(theBoard, computerLetter)
makeMove(theBoard, computerLetter, move)
if isWinner(theBoard, computerLetter):
drawBoard(theBoard)
print('The computer has beaten you! You lose.')
gameisPlaying = False
else:
if isBoardFull(theBoard):
drawBoard(theBoard)
print('The game is a tie!')
break
else:
turn = 'player'
if not playAgain():
break```
The problem lies in the second while loop.
while gameIsPlaying:
if turn == 'player':
# Player's turn.
drawBoard(theBoard)
move = getPlayerMove(theBoard)
makeMove(theBoard, playerLetter, move)
if isWinner(theBoard, playerLetter):
drawBoard(theBoard)
print('Hooray! You have won the game!')
gameIsPlaying = False
else:
if isBoardFull(theBoard):
drawBoard(theBoard)
print('The game is a tie!')
break
else:
turn = 'computer'
else:
# Computer's turn.
move = getComputerMove(theBoard, computerLetter)
makeMove(theBoard, computerLetter, move)
if isWinner(theBoard, computerLetter):
drawBoard(theBoard)
print('The computer has beaten you! You lose.')
gameisPlaying = False
else:
if isBoardFull(theBoard):
drawBoard(theBoard)
print('The game is a tie!')
break
else:
turn = 'player'
if not playAgain():
break
The loop will first call the first if statement if turn == 'player':. If this is false then the else statment will be run. Then if not playAgain() will be run. This will happen for every iteration of the loop.
Changing the indentation so that the final if statement is not included in the while gameIsPlaying loop should fix the problem.

Python How to keep score in a tic tac toe game

I need help figuring out how to calculate the record for wins, losses, and ties. Right now, the code returns the string "loss" when the player loses. I want it to return 1, for one loss. Can anyone help? Here is the code I have so far.
# Tic Tac Toe
import random
def score():
wins = 0
losses = 0
ties = 0
def result(wins, losses, ties):
if result =='win':
wins += 1
if result == 'loss':
losses += 1
else:
ties += 1
def drawBoard(board):
# This function prints out the board that it was passed.
# "board" is a list of 10 strings representing the board (ignore index 0)
print(' | |')
print(' ' + board[7] + ' | ' + board[8] + ' | ' + board[9])
print(' | |')
print('-----------')
print(' | |')
print(' ' + board[4] + ' | ' + board[5] + ' | ' + board[6])
print(' | |')
print('-----------')
print(' | |')
print(' ' + board[1] + ' | ' + board[2] + ' | ' + board[3])
print(' | |')
def inputPlayerLetter():
# Let's the player type which letter they want to be.
# Returns a list with the player's letter as the first item, and the computer's letter as the second.
letter = ''
while not (letter == 'X' or letter == 'O'):
print('Do you want to be X or O?')
letter = input().upper()
# the first element in the tuple is the player's letter, the second is the computer's letter.
if letter == 'X':
return ['X', 'O']
else:
return ['O', 'X']
def whoGoesFirst():
# Randomly choose the player who goes first.
if random.randint(0, 1) == 0:
return 'computer'
else:
return 'player'
def playAgain():
# This function returns True if the player wants to play again, otherwise it returns False.
print('Do you want to play again? (yes or no)')
return input().lower().startswith('y')
def makeMove(board, letter, move):
board[move] = letter
def isWinner(bo, le):
# Given a board and a player's letter, this function returns True if that player has won.
# We use bo instead of board and le instead of letter so we don't have to type as much.
return ((bo[7] == le and bo[8] == le and bo[9] == le) or # across the top
(bo[4] == le and bo[5] == le and bo[6] == le) or # across the middle
(bo[1] == le and bo[2] == le and bo[3] == le) or # across the bottom
(bo[7] == le and bo[4] == le and bo[1] == le) or # down the left side
(bo[8] == le and bo[5] == le and bo[2] == le) or # down the middle
(bo[9] == le and bo[6] == le and bo[3] == le) or # down the right side
(bo[7] == le and bo[5] == le and bo[3] == le) or # diagonal
(bo[9] == le and bo[5] == le and bo[1] == le)) # diagonal
def getBoardCopy(board):
# Make a duplicate of the board list and return it the duplicate.
dupeBoard = []
for i in board:
dupeBoard.append(i)
return dupeBoard
def isSpaceFree(board, move):
# Return true if the passed move is free on the passed board.
return board[move] == ' '
def getPlayerMove(board):
# Let the player type in his move.
move = ' '
while move not in '1 2 3 4 5 6 7 8 9'.split() or not isSpaceFree(board, int(move)):
print('What is your next move? (1-9)')
move = input()
return int(move)
def chooseRandomMoveFromList(board, movesList):
# Returns a valid move from the passed list on the passed board.
# Returns None if there is no valid move.
possibleMoves = []
for i in movesList:
if isSpaceFree(board, i):
possibleMoves.append(i)
if len(possibleMoves) != 0:
return random.choice(possibleMoves)
else:
return None
def getComputerMove(board, computerLetter):
# Given a board and the computer's letter, determine where to move and return that move.
if computerLetter == 'X':
playerLetter = 'O'
else:
playerLetter = 'X'
# Here is our algorithm for our Tic Tac Toe AI:
# First, check if we can win in the next move
for i in range(1, 10):
copy = getBoardCopy(board)
if isSpaceFree(copy, i):
makeMove(copy, computerLetter, i)
if isWinner(copy, computerLetter):
return i
# Check if the player could win on his next move, and block them.
for i in range(1, 10):
copy = getBoardCopy(board)
if isSpaceFree(copy, i):
makeMove(copy, playerLetter, i)
if isWinner(copy, playerLetter):
return i
# Try to take one of the corners, if they are free.
move = chooseRandomMoveFromList(board, [1, 3, 7, 9])
if move != None:
return move
# Try to take the center, if it is free.
if isSpaceFree(board, 5):
return 5
# Move on one of the sides.
return chooseRandomMoveFromList(board, [2, 4, 6, 8])
def isBoardFull(board):
# Return True if every space on the board has been taken. Otherwise return False.
for i in range(1, 10):
if isSpaceFree(board, i):
return False
return True
print('Welcome to Tic Tac Toe!')
while True:
# Reset the board
theBoard = [' '] * 10
playerLetter, computerLetter = inputPlayerLetter()
turn = whoGoesFirst()
print('The ' + turn + ' will go first.')
gameIsPlaying = True
while gameIsPlaying:
if turn == 'player':
# Player's turn.
drawBoard(theBoard)
move = getPlayerMove(theBoard)
makeMove(theBoard, playerLetter, move)
if isWinner(theBoard, playerLetter):
drawBoard(theBoard)
result = 'win'
print('Hooray! You have won the game!')
isWinner = True
gameIsPlaying = False
else:
if isBoardFull(theBoard):
drawBoard(theBoard)
result = 'tie'
print('The game is a tie!')
break
else:
turn = 'computer'
else:
# Computer's turn.
move = getComputerMove(theBoard, computerLetter)
makeMove(theBoard, computerLetter, move)
if isWinner(theBoard, computerLetter):
drawBoard(theBoard)
print('The computer has beaten you! You lose.')
result = 'loss'
isWinner = False
gameIsPlaying = False
else:
if isBoardFull(theBoard):
drawBoard(theBoard)
result = 'tie'
print('The game is a tie!')
break
else:
turn = 'player'
if not playAgain():
print(result)
break
Instead of doing result = 'win' you could set wins = 0 at the start and when resetting, and when the player wins just do wins += 1. Do the same for ties and losses and then you can extract the complete record from a function which takes wins,losses and ties as arguments.
Your functions score() and result(wins, loses, ties) are definitely not working good.
All variables in function are local variables and because of that this code will print 10 instead of 11:
def make_bigger(x):
x += 1
X = 10
make_bigger(X)
print(x)
Instead of using that functions you may need some function like this:
def pr_score(win, lose, tie):
print('Score:')
print('\twin:', win)
print('\tlose:', lose)
print('\ttie:', tie)
For win / lose / tie counting you need to add:
win = 0
lose = 0
tie = 0
before while True:.
You should also add win += 1 in if isWinner(theBoard, playerLetter): statement and tie += 1 in if isBoardFull(theBoard): statement.
Also code about computer turns should look like this:
if isBoardFull(theBoard):
drawBoard(theBoard)
result = 'tie'
print('The game is a tie!')
else:
# Computer's turn.
move = getComputerMove(theBoard, computerLetter)
makeMove(theBoard, computerLetter, move)
turn = 'player'
if isWinner(theBoard, computerLetter):
drawBoard(theBoard)
print('The computer has beaten you! You lose.')
result = 'loss'
lose += 1
isWinner = False
gameIsPlaying = False
if isBoardFull(theBoard):
drawBoard(theBoard)
result = 'tie'
print('The game is a tie!')
break
For printing result you should add pr_score(win, lose, tie) in if not playAgain():.
If you want ability for another round last break should be more indented.
Also if you add these lines in getPlayerMove(board) after move = input():
if move not in '1 2 3 4 5 6 7 8 9'.split(): #input is incorrect
print('Input is incorrect.\nPlease write nuber!')
elif not isSpaceFree(board, int(move)): #that place isn't free
print('That place is already taken.\nPlease take free place!')
and these lines before while True:
exampleBoard = [' ']
for x in range(1, 10):
exampleBoard.append(str(x))
drawBoard(exampleBoard)
it would be helpful for user.

Categories

Resources