I am really new to programming, and I made this simple tic tac toe app in python and C++. Please tell me what can be improved
Code:
import os
toDraw = ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
turnsPlayed = 0
playerTurn = 1
def reset():
global turnsPlayed
turnsPlayed = 0
global toDraw
toDraw = ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
global playerTurn
playerTurn = 1
def reDrawBoard(gameOver):
print(f"TIC TAC TOE\nPlayer one in X and Player two is O\n"
f"\n | | \n "
f"{toDraw[0]} | {toDraw[1]} | {toDraw[2]} "
f"\n___|___|___\n | | \n "
f"{toDraw[3]} | {toDraw[4]} | {toDraw[5]} "
f"\n___|___|___\n | | \n "
f"{toDraw[6]} | {toDraw[7]} | {toDraw[8]} "
f"\n | | \n\n")
if not gameOver:
print(f"Player {str(playerTurn)}, Enter a number: ")
#
# This prints (something similar to) -
#
# TIC TAC TOE
# Player one is X and Player two is O
#
# | |
# 1 | 2 | 3
# ___|___|___
# | |
# 4 | 5 | 6
# ___|___|___
# | |
# 7 | 8 | 9
# | |
#
# Player <1 or 2>, Enter a number:
#
def checkIfWin(): # 0 - Game in progress; 1 - Player 1 wins; 2 - Player 2 wins
one = toDraw[0]
two = toDraw[1]
three = toDraw[2]
four = toDraw[3]
five = toDraw[4]
six = toDraw[5]
seven = toDraw[6]
eight = toDraw[7]
nine = toDraw[8]
if ((one == "X" and two == "X" and three == "X") or
(one == "X" and four == "X" and seven == "X") or
(one == "X" and five == "X" and nine == "X") or
(seven == "X" and five == "X" and three == "X") or
(seven == "X" and eight == "X" and nine == "X") or
(three == "X" and six == "X" and nine == "X") or
(four == "X" and five == "X" and six == "X") or
(two == "X" and five == "X" and six == "X")):
return 1
elif ((one == "Y" and two == "Y" and three == "Y") or
(one == "Y" and four == "Y" and seven == "Y") or
(one == "Y" and five == "Y" and nine == "Y") or
(seven == "Y" and five == "Y" and three == "Y") or
(seven == "Y" and eight == "Y" and nine == "Y") or
(three == "Y" and six == "Y" and nine == "Y") or
(four == "Y" and five == "Y" and six == "Y") or
(two == "Y" and five == "Y" and six == "Y")):
return 2
else:
return 0
while True:
clear = lambda : os.system('clear')
reDrawBoard(False)
toPlay = ""
while True:
try:
toPlay = int(input())
if toPlay > 9:
print(f"\nInvalid Value. Try again.\nPlayer {str(playerTurn)}, Enter a number: ")
continue
except ValueError:
print(f"\nInvalid Value. Try again.\nPlayer {str(playerTurn)}, Enter a number: ")
continue
try:
if toPlay == int(toDraw[toPlay - 1]):
break
except ValueError:
print(f"Position already occupied. Please try again.\nPlayer {str(playerTurn)}, Enter a number: ")
continue
if playerTurn == 1:
toDraw[toPlay -1] = "X"
turnsPlayed += 1
playerTurn = 2
else:
toDraw[toPlay - 1] = "O"
turnsPlayed += 1
playerTurn = 1
result = checkIfWin()
if result == 1:
reDrawBoard(True)
response = input("PLAYER ONE WINS!!\nWould you like to play again? (Y/N): ").lower()
if response != "y":
#clear the screen
exit()
reset()
continue
if result == 2:
reDrawBoard(True)
response = input("PLAYER TWO WINS!!\nWould you like to play again? (Y/N): ").lower()
if response != "y":
#clear the screen
exit()
reset()
continue
if turnsPlayed == 9:
reDrawBoard(True)
response = input("DRAW!!\nWould you like to play again? (Y/N): ").lower()
if response != "y":
#clear the screen
exit()
reset()
continue
-
\$\begingroup\$ search for tic tac toe python on code review, and you will already find tens of tips on improving the code \$\endgroup\$Maarten Fabré– Maarten Fabré2019年03月06日 08:49:19 +00:00Commented Mar 6, 2019 at 8:49
-
\$\begingroup\$ @MaartenFabré Thanks, but I don't really understand all of the code in the other questions :) . Will try to improve what I can. \$\endgroup\$user191336– user1913362019年03月06日 08:54:51 +00:00Commented Mar 6, 2019 at 8:54
1 Answer 1
One improvement I suggest is that in the beginning of your code, you could create a list of sets, in which each set would be a winning board configuration and then create two sets to record the players moves, like this:
winningMoves = [{1,2,3}, {1,4,7}, {1,5,9}, {7,5,3}, {7,8,9}, {3,6,9}, {4, 5, 6}, {2, 5, 8}]
playerOneMoves = set()
playerTwoMoves = set()
In the part that you check which player made the move, you would insert an "add(toPlay)" for both players, like this:
if playerTurn == 1:
toDraw[toPlay -1] = "X"
playerOneMoves.add(toPlay)
turnsPlayed += 1
playerTurn = 2
If I'm right, if you make things like this, you could reduce that great amount of code in checkIfWin() function to just:
def checkIfWin(): # 0 - Game in progress; 1 - Player 1 wins; 2 - Player 2 wins
for move in winningMoves:
if move.issubset(playerOneMoves):
return 1
elif move.issubset(playerTwoMoves):
return 2
return 0
The issubset() method will return True if move is a subset of the set that contains the player's moves. Which means it will return True if all elements in move are also in playerOneMoves or playerTwoMoves.
Also, instead of printing the board with format, you could develop a way of printing each part of the board individually inside a loop, for example:
for num in range(1,10):
if num in list(playerOneMoves):
print("[{}]".format('X'), end = '')
elif num in list(playerTwoMoves):
print("[{}]".format('O'), end = '')
else:
print("[{}]".format(num), end = '')
if num%3 ==0:
print("")
(Of course you could improve the style!)
The reason for that is that it would allow you to suppress toDraw completely and simplify your code even more.