principlepythonMinor
Tic Tac Toe (Player vs Computer)
Viewed 0 times
toeplayertictaccomputer
Problem
I am looking on how I can improve my writing style and/or how to simplify how I write my code.
```
# USER: TCG
# Tic Tac Toe (User vs Computer)
import random
def place(num,x):
# Returns all the moves made
for i in range(len(x)):
if x[i] == num:
pos = x.index(num)
return x[(pos + 1)]
return str(num)
def print_grid(move,player,x):
pos_list.extend([move,player])
# Grid on which the player and computer play on
grid = ["","-------------\n",
"|",place(1,pos_list),"|",place(2,pos_list),"|",place(3,pos_list),"|\n",
"|---+---+---|\n",
"|",place(4,pos_list),"|",place(5,pos_list),"|",place(6,pos_list),"|\n",
"|---+---+---|\n",
"|",place(7,pos_list),"|",place(8,pos_list),"|",place(9,pos_list),"|\n",
"-------------\n"]
if x == 2:
# Only prints one the player has made a move
print '\n', ' '.join(grid)
def winner(x,player,xx):
# Checks if there is a winner (Really messy, could do with code simplifying)
if ((1 in x and 4 in x and 7 in x)or(1 in x and 2 in x and 3 in x)or(2 in x and 5 in x and 8 in x)or(3 in x and 6 in x and 9 in x)or
(4 in x and 5 in x and 6 in x)or(7 in x and 8 in x and 9 in x)or(1 in x and 5 in x and 9 in x)or(3 in x and 5 in x and 7 in x)):
# If prevents the A.I part from printing the statemnt
if xx <> 1:
print '\n'*5,"\'%s\'" %player, "HAS WON!"
return 1 == 1
def computer_AI_part(listx):
global computer_move
# Chceks all possible values which the player can and enter to win and blocks it
for x in range(1,10):
if x not in pos_list:
listx.append(x)
if (winner(listx,'Computer',1)) == True:
del listx[-1]
computer_move = x
return 1
del listx[-1]
def computer_and_player():
global computer_move,pos_list,player_list,computer_list
replay,draw = 0,0
while True:
```
# USER: TCG
# Tic Tac Toe (User vs Computer)
import random
def place(num,x):
# Returns all the moves made
for i in range(len(x)):
if x[i] == num:
pos = x.index(num)
return x[(pos + 1)]
return str(num)
def print_grid(move,player,x):
pos_list.extend([move,player])
# Grid on which the player and computer play on
grid = ["","-------------\n",
"|",place(1,pos_list),"|",place(2,pos_list),"|",place(3,pos_list),"|\n",
"|---+---+---|\n",
"|",place(4,pos_list),"|",place(5,pos_list),"|",place(6,pos_list),"|\n",
"|---+---+---|\n",
"|",place(7,pos_list),"|",place(8,pos_list),"|",place(9,pos_list),"|\n",
"-------------\n"]
if x == 2:
# Only prints one the player has made a move
print '\n', ' '.join(grid)
def winner(x,player,xx):
# Checks if there is a winner (Really messy, could do with code simplifying)
if ((1 in x and 4 in x and 7 in x)or(1 in x and 2 in x and 3 in x)or(2 in x and 5 in x and 8 in x)or(3 in x and 6 in x and 9 in x)or
(4 in x and 5 in x and 6 in x)or(7 in x and 8 in x and 9 in x)or(1 in x and 5 in x and 9 in x)or(3 in x and 5 in x and 7 in x)):
# If prevents the A.I part from printing the statemnt
if xx <> 1:
print '\n'*5,"\'%s\'" %player, "HAS WON!"
return 1 == 1
def computer_AI_part(listx):
global computer_move
# Chceks all possible values which the player can and enter to win and blocks it
for x in range(1,10):
if x not in pos_list:
listx.append(x)
if (winner(listx,'Computer',1)) == True:
del listx[-1]
computer_move = x
return 1
del listx[-1]
def computer_and_player():
global computer_move,pos_list,player_list,computer_list
replay,draw = 0,0
while True:
Solution
Here's a section of my game:
I was just trying to do a short test, and then go back to the code and make some more changes, but I couldn't get out of the program without finishing the game. It's good that you don't allow just anything, but
Your
Your naming could still be improved. How is one to know that
You have a function called
Global variables are almost never necessary. If you are tempted, you might be better off either passing them as arguments or defining a class. In this case, I think a class would be the better option.
Your grid is a little hard to follow. It would be better to have a template and fill it in:
To be frank, I agree with you comment in
I changed
Every function does its part. You never need the word
Since
It's only barely longer, and it is much more user-friendly.
That's hard to read. If you want to put them all together like that, you should at least add some whitespace and put the different types on different lines:
That's a lot easier to read.
Why not:
That's a little easier to understand.
'X' Enter a value from the grid to plot your move: exit
Enter a number
'X' Enter a value from the grid to plot your move: leave
Enter a number
'X' Enter a value from the grid to plot your move: quit
Enter a number
'X' Enter a value from the grid to plot your move: ^CEnter a numberI was just trying to do a short test, and then go back to the code and make some more changes, but I couldn't get out of the program without finishing the game. It's good that you don't allow just anything, but
^C at least should let me get out.Your
place() function could be a little better by using enumerate():def place(num,x):
# Returns the value in x at position num
for i, v in enumerate(x):
if v == num:
return x[(i + 1)]
return str(num)Your naming could still be improved. How is one to know that
x is a list of positions and values? There's more that I would change, but I'll get to that below.You have a function called
print_grid that makes a move, too. Either create a new function to make the move or rename the current function to show that it has side effects.Global variables are almost never necessary. If you are tempted, you might be better off either passing them as arguments or defining a class. In this case, I think a class would be the better option.
pos_list would be better off being a dictionary (of course with a different name). It would be {pos: value, pos: value, ...} instead of [pos, value, pos, value, ...]. That way, lookups are easier. For example, place() could be return x.get(num, str(num)) -- just one line!Your grid is a little hard to follow. It would be better to have a template and fill it in:
template = """
-------------
| {} | {} | {} |
|-----------|
| {} | {} | {} |
|-----------|
| {} | {} | {} |
--------------"""
if x == 2:
# Only prints if the player has made a move
print template.format(*(place(num + 1, pos_list) for num in range(9)))To be frank, I agree with you comment in
winner() that the code is messy. I would define tuples of valid moves and see if any of them is a match:def winner(x,player,xx):
wins = ((1, 2, 3), (4, 5, 6), (7, 8, 9), # Horizontal
(1, 4, 7), (2, 5, 8), (3, 6, 9), # Vertical
(1, 5, 9), (3, 5, 7)) # Diagonal
if any(all(pos in x for pos in win) for win in wins):
if xx != 1:
print '\n'*5, "'{}'".format(player), "HAS WON!"
return True
return FalseI changed
if xx <> 1: to if xx != 1: because it's a little more obvious what it means. In fact, Python 3 took out <> so you need to use !=. I also changed your print statement. You didn't need to escape ' because it was " that made it a string, so the ' wouldn't close the string. Also, while % is not officially deprecated, it is recommended to use .format(). While I was at it, I changed return 1 == 1 to return True. Why make Python evaluate an expression when you already know the answer?def computer_AI_part(listx):Every function does its part. You never need the word
part in its name. Also, listx isn't very descriptive. What sort of list is it? Is it a list of moves?while True:
# Replay's the game
if replay == 1:
restart = raw_input("Would you like to replay?: ")
if restart == "yes":
pass
else:
return
else:
print "\nTic Tac Toe - Computer vs You", '\n'*2,"Computer goes first\n"Since
replay is always either 0 or 1, and since 0 is False and 1 is True, you can simply say if replay:. I would also change the logic slightly. If I typed y or Yes, your program would just exit. I would do something more like:while True:
# Replay's the game
if replay:
restart = raw_input("Would you like to replay?: ").lower()
if restart in ("y", "yes"):
pass
elif restart in ("n", "no"):
return
else:
print "Say 'yes' or 'no'"
continue
else:
print "\nTic Tac Toe - Computer vs You", '\n'*2,"Computer goes first\n"It's only barely longer, and it is much more user-friendly.
replay,computer_move,players_move,loop_count,pos_list,player_list,computer_list = 0,0,0,0,[],[],[]That's hard to read. If you want to put them all together like that, you should at least add some whitespace and put the different types on different lines:
replay, computer_move, players_move, loop_count = 0, 0, 0, 0
pos_list, player_list, computer_list = [], [], []That's a lot easier to read.
if computer_move in pos_list:
continue
breakWhy not:
if computer_move not in pos_list:
breakThat's a little easier to understand.
if winner(computer_list,'Computer',2) == True:winner() already returns a boolean. Checking its equality with True is redunCode Snippets
'X' Enter a value from the grid to plot your move: exit
Enter a number
'X' Enter a value from the grid to plot your move: leave
Enter a number
'X' Enter a value from the grid to plot your move: quit
Enter a number
'X' Enter a value from the grid to plot your move: ^CEnter a numberdef place(num,x):
# Returns the value in x at position num
for i, v in enumerate(x):
if v == num:
return x[(i + 1)]
return str(num)template = """
-------------
| {} | {} | {} |
|-----------|
| {} | {} | {} |
|-----------|
| {} | {} | {} |
--------------"""
if x == 2:
# Only prints if the player has made a move
print template.format(*(place(num + 1, pos_list) for num in range(9)))def winner(x,player,xx):
wins = ((1, 2, 3), (4, 5, 6), (7, 8, 9), # Horizontal
(1, 4, 7), (2, 5, 8), (3, 6, 9), # Vertical
(1, 5, 9), (3, 5, 7)) # Diagonal
if any(all(pos in x for pos in win) for win in wins):
if xx != 1:
print '\n'*5, "'{}'".format(player), "HAS WON!"
return True
return Falsedef computer_AI_part(listx):Context
StackExchange Code Review Q#126794, answer score: 4
Revisions (0)
No revisions yet.