patternpythonMinor
TicTacToe in Python3 w/ Simple AI
Viewed 0 times
tictactoepython3simple
Problem
Here is my version of TicTacToe on python 3.x
I'm learning python for a several weeks and I will be very appretiated if you take a look on my script and review it!
P.S. I've used NumPad to input move to make game more user-friendly. So 5 means center, 7 means right-upper corner, 6 means right side etc.
```
from random import randint, choice
from os import system as bash
from time import time
def intInput(StringToDisplay):
# Simply checks that input is valid integer
while True:
try:
x = int(input(StringToDisplay))
return x
break
except ValueError:
print('Input integer number, please')
except Exception:
print('Unexpected error or keyboard interrupt')
def drawBoard():
print('\
╔═══╦═══╦═══╗\n\
║ {0} ║ {1} ║ {2} ║\n\
╠═══╬═══╬═══╣\n\
║ {3} ║ {4} ║ {5} ║\n\
╠═══╬═══╬═══╣\n\
║ {6} ║ {7} ║ {8} ║\n\
╚═══╩═══╩═══╝ '.format(
board_status[7], board_status[8], board_status[9],
board_status[4], board_status[5], board_status[6],
board_status[1], board_status[2], board_status[3]))
def askPlayerLetter():
# Function that asks which letter player wants to use
print('Do you want to be X or O?')
Letter = input().upper()
while Letter != 'X' and Letter != 'O':
print('Please type appropriate symbol')
Letter = input('Prompt: ').upper()
if Letter == 'X': # then X will be used by player; O by computer
return ['X', 'O']
else:
return ['O', 'X']
def whoGoesFirst():
# Timer used to count 0.75 seconds while displaying who goes first
if randint(0, 1) == 0:
CurrentTime, Timer = time(), time() + 0.75
print('You go first')
while Timer > CurrentTime:
CurrentTime = time()
return 'player'
else:
CurrentTime, Timer = time(), time() + 0.75
print('Computer goes first')
while Timer > CurrentTime:
Current
I'm learning python for a several weeks and I will be very appretiated if you take a look on my script and review it!
P.S. I've used NumPad to input move to make game more user-friendly. So 5 means center, 7 means right-upper corner, 6 means right side etc.
```
from random import randint, choice
from os import system as bash
from time import time
def intInput(StringToDisplay):
# Simply checks that input is valid integer
while True:
try:
x = int(input(StringToDisplay))
return x
break
except ValueError:
print('Input integer number, please')
except Exception:
print('Unexpected error or keyboard interrupt')
def drawBoard():
print('\
╔═══╦═══╦═══╗\n\
║ {0} ║ {1} ║ {2} ║\n\
╠═══╬═══╬═══╣\n\
║ {3} ║ {4} ║ {5} ║\n\
╠═══╬═══╬═══╣\n\
║ {6} ║ {7} ║ {8} ║\n\
╚═══╩═══╩═══╝ '.format(
board_status[7], board_status[8], board_status[9],
board_status[4], board_status[5], board_status[6],
board_status[1], board_status[2], board_status[3]))
def askPlayerLetter():
# Function that asks which letter player wants to use
print('Do you want to be X or O?')
Letter = input().upper()
while Letter != 'X' and Letter != 'O':
print('Please type appropriate symbol')
Letter = input('Prompt: ').upper()
if Letter == 'X': # then X will be used by player; O by computer
return ['X', 'O']
else:
return ['O', 'X']
def whoGoesFirst():
# Timer used to count 0.75 seconds while displaying who goes first
if randint(0, 1) == 0:
CurrentTime, Timer = time(), time() + 0.75
print('You go first')
while Timer > CurrentTime:
CurrentTime = time()
return 'player'
else:
CurrentTime, Timer = time(), time() + 0.75
print('Computer goes first')
while Timer > CurrentTime:
Current
Solution
-
First of all, nice ingenuity on displaying an almost graphical board, that's good for a beginner.
-
The
-
Also in
Like this:
Like this:
-
You have a lot of numbers, like
-
You use a copy of your board to make the move and then check the winning condition. That's all good and fine because this is a tiny program, but you should keep scalability in mind. A copy is an expensive operation, so if some day you want to optimize you can keep two "boards" in memory and doing/undoing the operation in the "off-screen" board and putting it in the "on-screen" board if that's the move you want. That way you'll only set/unset one element at a time instead of copying back everything every cycle of the loop.
-
In
Like this:
-
You could consider using a generator, so that you could have a function like
-
In
-
To check victory you could think about some tricks. For example, you could still show the
First of all, nice ingenuity on displaying an almost graphical board, that's good for a beginner.
-
The
intInput function should follow PEP8 and be something like 'get_int_input'. Also, since you want the number to be between 1 and 9, you can add optional parameters to make the function more generic and decouple the check. StringToDisplay should also be more like displayed_prompt. The same goes for all the variable/function names.-
Also in
intInput you have a break after the return which is useless, since you're going to return anyway. You also don't need a variable for the input, since the exception is going to be caught anyway.Like this:
def get_int_input(displayed_prompt='', min_value=1, max_value=9):
while True:
try:
input_value = int(input(displayed_prompt))
if (input_value >= min_value and input_value <= max_value):
return input_value
else:
raise ValueError
except ValueError:
print('Input an integer number between {0} and {1}, please'.format(min_value, max_value))
except Exception:
print('Unexpected error or keyboard interrupt')- In
askPlayerLetteryou don't need toprintand theninput, you caninputwith a prompt. Also, you can use an array or tuple for the allowed values.
Like this:
def ask_player_letter():
allowed_letters = ['X', 'O']
letter = input('Do you want to be X or O?').upper()
while letter not in allowed_letters:
letter = input('Please choose between {} and {}: '.format(
*allowed_letters)).upper()
if letter == 'X':
return allowed_letters
else:
return allowed_letters[::-1]-
You have a lot of numbers, like
0.75 that should be defined somewhere in a variable, so you can fine-tune what you need in one place instead of hunting around the code for places where you use those values.-
You use a copy of your board to make the move and then check the winning condition. That's all good and fine because this is a tiny program, but you should keep scalability in mind. A copy is an expensive operation, so if some day you want to optimize you can keep two "boards" in memory and doing/undoing the operation in the "off-screen" board and putting it in the "on-screen" board if that's the move you want. That way you'll only set/unset one element at a time instead of copying back everything every cycle of the loop.
-
In
randomMoveFromList you can use a list comprehension.Like this:
def random_move_from_list(moves_list):
PossibleMoves = [move for move in moves_list if isSpaceFree(board_status, move)]
if len(PossibleMoves) != 0:
return choice(PossibleMoves)
return None-
You could consider using a generator, so that you could have a function like
get_next_move and yield a value, but in this specific case that would probably be a bit of overkill.-
In
isBoardFull you go through the board just to count how many cells are occupied. Since your code is the only thing occupying the cells, you can keep a counter every time a cell is occupied and use that, avoiding the loop.-
To check victory you could think about some tricks. For example, you could still show the
X and the O, but internally you could save them as -1 and 1, so if the sum of one of the rows or columns is -3 or 3, someone has won. Keep in mind that you can do something like if (sum(brd[4:6]) in [-3, 3]).Code Snippets
def get_int_input(displayed_prompt='', min_value=1, max_value=9):
while True:
try:
input_value = int(input(displayed_prompt))
if (input_value >= min_value and input_value <= max_value):
return input_value
else:
raise ValueError
except ValueError:
print('Input an integer number between {0} and {1}, please'.format(min_value, max_value))
except Exception:
print('Unexpected error or keyboard interrupt')def ask_player_letter():
allowed_letters = ['X', 'O']
letter = input('Do you want to be X or O?').upper()
while letter not in allowed_letters:
letter = input('Please choose between {} and {}: '.format(
*allowed_letters)).upper()
if letter == 'X':
return allowed_letters
else:
return allowed_letters[::-1]def random_move_from_list(moves_list):
PossibleMoves = [move for move in moves_list if isSpaceFree(board_status, move)]
if len(PossibleMoves) != 0:
return choice(PossibleMoves)
return NoneContext
StackExchange Code Review Q#151871, answer score: 4
Revisions (0)
No revisions yet.