Reputation: 127
Good day. I'm currently reading Michael Dawson's book Python for the Absolute Beginner. I have this code for Chapter 6 and when I ran the code and got the straight "X" in the board, it won't return the winner. The program continues until all the spaces are mark with either "X" or "O". Here is my code:
#!/usr/bin/python3
X = "X"
O = "O"
EMPTY = " "
TIE = "TIE"
NUM_SQUARES = 9
def display_instruct():
print(
"""
Welcome to the greatest intellectual challenge of all time: Tic-Tac-Toe.
This will be a showdown between your human brain and my silicon processor.
You will make your move known by entering a number, 0 - 8. The number
will correspond to the board position as illustrated:
0 | 1 | 2
-----------
3 | 4 | 5
-----------
6 | 7 | 8
Prepare your self, human. The ultimate battle is about to begin. \n
""")
def ask_yes_no(question):
response = None
while response not in ("y", "n"):
response = input(question).lower()
return response
def ask_number(question, low, high):
response = None
while response not in range(low, high):
response = int(input(question))
return response
def pieces():
go_first = ask_yes_no("Do you require the first move? (y/n): ")
if go_first == "y":
print( "\nThen take the first move. You will need it. ")
human = X
computer = O
else:
print("\nYour bravery will be your undoing... I will go first.")
computer = X
human = O
return computer, human
def new_board():
board = []
for square in range(NUM_SQUARES):
board.append(EMPTY)
return board
def display_board(board):
print("\n\t", board[0], "|", board[1], "|", board[2])
print("\t", "---------")
print("\t", board[3], "|", board[4], "|", board[5])
print("\t", "---------")
print("\t", board[6], "|", board[7], "|", board[8], "\n")
def legal_moves(board):
moves = []
for square in range(NUM_SQUARES):
if board[square] == EMPTY:
moves.append(square)
return moves
def winner(board):
WAYS_TO_WIN = ((0, 1, 2),
(3, 4, 5),
(6, 7, 8),
(0, 3, 6),
(1, 4, 7),
(2, 5, 8),
(0, 4, 8),
(2, 4, 6))
for row in WAYS_TO_WIN:
if board[row[0]] == board[row[1]] == board[row[2]] != EMPTY:
winner = board[row[0]]
return winner
if EMPTY not in board:
return TIE
return None
def human_move(board, human):
"""Get human move."""
legal = legal_moves(board)
move = None
while move not in legal:
move = ask_number("Where will you move? (0 - 8): ", 0, NUM_SQUARES)
if move not in legal:
print("\nThat square is already occupied, foolish human. Choose another.\n")
print("Fine....")
return move
def computer_move(board, computer, human):
"""Make computer move."""
#make a copy to work with since function will be changing list.
board = board[:]
BEST_MOVES = (4, 0, 2, 6, 8, 1, 3, 5, 7)
print("I shall take square number")
# if computer can win, take that move
for move in legal_moves(board):
board[move] = computer
if winner(board) == computer:
print(move)
return move
board[move] = EMPTY
# if human can win, block that move
for move in legal_moves(board):
board[move] = human
if winner(board) == human:
print(move)
return move
# done checking this move, undo it
board[move] = EMPTY
# since no one ca win on next move, pick best open square
for move in BEST_MOVES:
if move in legal_moves(board):
print(move)
return move
def next_turn(turn):
if turn == X:
return 0
else:
return X
def congrat_winner(the_winner, computer, human):
if the_winner != TIE:
print(the_winner, "won!\n")
else:
print("It's a tie!\n")
if the_winner == computer:
print("As I predicted, human, I am triumphant once more. \n" \
"Proof that computers are superior to humans in all regards.\n")
elif the_winner == human:
print("No, no! It cannot be! Somehow you tricked me, human. \n" \
"But never again! I, the computer, so swears it\n!")
elif the_winner == TIE:
print("You were most lucky, human, and somehow managed to tie me. \n" \
"Celebrate today... for this is the best you will ever achieve.\n")
def main():
display_instruct()
computer, human = pieces()
turn = X
board = new_board()
display_board(board)
while not winner(board):
if turn == human:
move = human_move(board, human)
board[move] = human
else:
move = computer_move(board, computer, human)
board[move] = computer
display_board(board)
turn = next_turn(turn)
the_winner = winner(board)
congrat_winner(the_winner, computer, human)
main()
input("Press enter to exit")
Upvotes: 2
Views: 1052
Reputation: 2625
Understand you already have your answer, but a piece of advice - try to test your functions in isolation.
In your case, you already had a hunch that there was an issue with your winner
function. I've taken this directly from your question, where you mentioned "it won't return the winner".
There are plenty of approaches to testing but let's keep it simple and grab that function, copy it to a new python program, throw some game boards at it, and see what happens. I mean "see" literally - your best friend when it comes to testing is print
. Say we modify your function like so:
def winner(board):
print("winner function entered")
WAYS_TO_WIN = ((0, 1, 2),
(3, 4, 5),
(6, 7, 8),
(0, 3, 6),
(1, 4, 7),
(2, 5, 8),
(0, 4, 8),
(2, 4, 6))
for row in WAYS_TO_WIN:
print("for loop entered")
if board[row[0]] == board[row[1]] == board[row[2]] != EMPTY:
winner = board[row[0]]
return winner
if EMPTY not in board:
return TIE
return None
It may seem all too easy, but immediately we notice that in all cases the for loop is only ever entered once. Having a small section of code to focus on, it won't be too long before the indentation error is found.
Upvotes: 0
Reputation: 12239
The function that checks for a win or tie is incorrect. Currently you have this:
def winner(board):
WAYS_TO_WIN = ((0, 1, 2),
(3, 4, 5),
(6, 7, 8),
(0, 3, 6),
(1, 4, 7),
(2, 5, 8),
(0, 4, 8),
(2, 4, 6))
for row in WAYS_TO_WIN:
if board[row[0]] == board[row[1]] == board[row[2]] != EMPTY:
winner = board[row[0]]
return winner
if EMPTY not in board:
return TIE
return None
Notice that return None
is inside the loop, so you return None
when the first row fails to match. That's unless the board is full, in which case you correctly return TIE
, except you could have checked for a full board before trying to match any rows.
We can make the function correct by reindenting return None
so that it gets executed after the loop. In addition, it makes sense to move the TIE
check before the loop.
def winner(board):
if EMPTY not in board:
return TIE
WAYS_TO_WIN = ((0, 1, 2),
(3, 4, 5),
(6, 7, 8),
(0, 3, 6),
(1, 4, 7),
(2, 5, 8),
(0, 4, 8),
(2, 4, 6))
for row in WAYS_TO_WIN:
if board[row[0]] == board[row[1]] == board[row[2]] != EMPTY:
winner = board[row[0]]
return winner
return None
Let's review what this function does. We start by checking for a full board. Then we go on to consider the ways to win. If none of them match, we return None
.
There's one more problem in your code:
def next_turn(turn):
if turn == X:
return 0
else:
return X
In order for the later test if turn == human:
to work correctly in all cases, the value of turn
must be either X
or O
, not X
or 0
. This is the quick fix:
def next_turn(turn):
if turn == X:
return O
else:
return X
The better way to fix this problem is to avoid having a variable named O
.
Upvotes: 3
Reputation: 273
You also made an indention error in def(congrat_winner)
The correct way is:
def congrat_winner(the_winner, computer, human):
if the_winner != TIE:
print(the_winner, "won!\n")
else:
print("It's a tie!\n")
if the_winner == computer:
print("As I predicted, human, I am triumphant once more. \n" \
"Proof that computers are superior to humans in all regards.\n")
elif the_winner == human:
print("No, no! It cannot be! Somehow you tricked me, human. \n" \
"But never again! I, the computer, so swears it\n!")
elif the_winner == TIE:
print("You were most lucky, human, and somehow managed to tie me. \n" \
"Celebrate today... for this is the best you will ever achieve.\n")
Moreover the last elif
should be replaced with else
:
def congrat_winner(the_winner, computer, human):
if the_winner != TIE:
print(the_winner, "won!\n")
else:
print("It's a tie!\n")
if the_winner == computer:
print("As I predicted, human, I am triumphant once more. \n" \
"Proof that computers are superior to humans in all regards.\n")
elif the_winner == human:
print("No, no! It cannot be! Somehow you tricked me, human. \n" \
"But never again! I, the computer, so swears it\n!")
else:
print("You were most lucky, human, and somehow managed to tie me. \n" \
"Celebrate today... for this is the best you will ever achieve.\n")
Upvotes: 0