Small terminal Tic Tac Toe gameOOP TictacToe with TkinterTic Tac Toe in JavaUltimate Tic Tac Toe A.K.A. Tic...
What is the white spray-pattern residue inside these Falcon Heavy nozzles?
Schwarzchild Radius of the Universe
Is Social Media Science Fiction?
least quadratic residue under GRH: an EXPLICIT bound
Example of a relative pronoun
Japan - Plan around max visa duration
Is there a minimum number of transactions in a block?
Why has Russell's definition of numbers using equivalence classes been finally abandoned? ( If it has actually been abandoned).
Why are 150k or 200k jobs considered good when there are 300k+ births a month?
Download, install and reboot computer at night if needed
TGV timetables / schedules?
Shell script can be run only with sh command
If Manufacturer spice model and Datasheet give different values which should I use?
Extreme, but not acceptable situation and I can't start the work tomorrow morning
Why did the Germans forbid the possession of pet pigeons in Rostov-on-Don in 1941?
What would happen to a modern skyscraper if it rains micro blackholes?
New order #4: World
I see my dog run
Do airline pilots ever risk not hearing communication directed to them specifically, from traffic controllers?
How can the DM most effectively choose 1 out of an odd number of players to be targeted by an attack or effect?
How do we improve the relationship with a client software team that performs poorly and is becoming less collaborative?
Patience, young "Padovan"
Why was the small council so happy for Tyrion to become the Master of Coin?
Motorized valve interfering with button?
Small terminal Tic Tac Toe game
OOP TictacToe with TkinterTic Tac Toe in JavaUltimate Tic Tac Toe A.K.A. Tic Tactics3D Tic Tac Toe/Connect Four game with AIConsole-based TicTacToe gameDesign Tic tac toe gameFirst Console Game: Tic-Tac-ToeA Tic-Tac-Toe game in MonoGameC++/SDL2 Tic-Tac-ToeDesign of a Tic Tac Toe program in Python
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ margin-bottom:0;
}
$begingroup$
I'm new to Python and I just finished a school assignment where I had to make a tictactoe game with focus on OOP. I would love to get some pointers on how I can clean up my code (especially my Tictactoe class) as it's pretty messy right now.
What I've done so far is comment as much as possible to make it understandable, but I feel like my tictactoe class is a mess and I would like to get some pointers on how I can optimize it.
The class below enforces the rules and draws the board:
import os
class Board:
board = [0,1,2,3,4,5,6,7,8,9]
win_combinations = [
(1,2,3),
(4,5,6),
(7,8,9),
(1,5,9),
(3,5,7),
(1,4,7),
(2,5,8),
(3,6,9),
]
GameOver = False
#Draws the board
def drawboard(self):
print('=========')
print(self.board[7], '|', self.board[8], '|', self.board[9])
print(self.board[4], '|', self.board[5], '|', self.board[6])
print(self.board[1], '|', self.board[2], '|', self.board[3])
print('=========')
#Checks if the move the player just made, made him/she win the game
def checkIfWon(self, choice):
for a, b, c in self.win_combinations:
if self.board[a] == self.board[b] == self.board[c]:
print('Game over, player ' + choice + ' won the game')
self.GameOver = True
#Update the current board
def update(self, input, choice):
self.board[input] = choice
os.system('clear')
self.drawboard()
self.checkIfWon(choice)
#Resets the board
def resetBoard(self):
self.board = [0,1,2,3,4,5,6,7,8,9]
#Stops the game if tie
def tie(self):
list = []
for x in self.board:
if type(x) != int:
list.append(x)
if len(list) == 9:
return True
The class below contains the runGame method which starts the game:
import os
from board import Board
class Tictactoe():
b = Board()
choicePlayer1 = ''
choucePlayer2 = ''
corretChoice = False
correctPlayer1 = False
correctPlayer2 = False
def runGame(self):
os.system('clear')
#Resets the game when a new game is started
#Is necessary if the players wish to play more than 1 game
resetGame(self)
#Makes sure the game only starts if player1 picks X or O
while self.corretChoice == False:
self.choicePlayer1 = input('Do you want to play X or O? ')
print()
if self.choicePlayer1 == 'X':
self.choicePlayer2 = 'O'
self.corretChoice = True
print('Starting player selected X')
elif self.choicePlayer1 == 'O':
self.choicePlayer2 = 'X'
self.corretChoice = True
print('Starting player selected O')
else:
print('ERROR - input has to be either X or O!')
continue
os.system('clear')
self.b.drawboard()
while self.b.GameOver == False:
self.correctPlayer1 = False
self.correctPlayer2 = False
#For player1
while self.correctPlayer1 == False:
while True:
try:
x = int(input(self.choicePlayer1 + ' Where do you want to place your piece? '))
break
except:
print('Input has to be a number, try again')
if x > 0 and x < 10 and type(self.b.board[x]) != str:
self.b.update(x, self.choicePlayer1)
self.correctPlayer1 = True
elif x == 10:
quit()
else:
print('Spot is taken, try again: ')
if self.b.GameOver == True:
self.correctPlayer2 = True
if self.b.tie() == True:
self.correctPlayer2 = True
self.b.GameOver = True
print('Game is a tie')
#For player2
while self.correctPlayer2 == False:
while True:
try:
x = int(input(self.choicePlayer2 + ' Where do you want to place your piece? '))
break
except:
print('Input has to be a number, try again')
if x > 0 and x < 10 and type(self.b.board[x]) != str:
self.b.update(x, self.choicePlayer2)
self.correctPlayer2 = True
elif x == 10:
quit()
else:
print('Spot is taken, try again: ')
if self.b.tie() == True:
self.b.gameOver = True
print('Game is a tie')
#Resets the game if the players wishes to play again
def resetGame(self):
self.b = Board()
self.choicePlayer1 = ''
self.choucePlayer2 = ''
self.corretChoice = False
self.correctPlayer1 = False
self.correctPlayer2 = False
self.b.resetBoard()
The script i run to start the game:
from tictac import Tictactoe
run = Tictactoe()
while True:
run.runGame()
if input("Play again? (y/n)") == "n":
quit()
python homework tic-tac-toe
New contributor
$endgroup$
add a comment |
$begingroup$
I'm new to Python and I just finished a school assignment where I had to make a tictactoe game with focus on OOP. I would love to get some pointers on how I can clean up my code (especially my Tictactoe class) as it's pretty messy right now.
What I've done so far is comment as much as possible to make it understandable, but I feel like my tictactoe class is a mess and I would like to get some pointers on how I can optimize it.
The class below enforces the rules and draws the board:
import os
class Board:
board = [0,1,2,3,4,5,6,7,8,9]
win_combinations = [
(1,2,3),
(4,5,6),
(7,8,9),
(1,5,9),
(3,5,7),
(1,4,7),
(2,5,8),
(3,6,9),
]
GameOver = False
#Draws the board
def drawboard(self):
print('=========')
print(self.board[7], '|', self.board[8], '|', self.board[9])
print(self.board[4], '|', self.board[5], '|', self.board[6])
print(self.board[1], '|', self.board[2], '|', self.board[3])
print('=========')
#Checks if the move the player just made, made him/she win the game
def checkIfWon(self, choice):
for a, b, c in self.win_combinations:
if self.board[a] == self.board[b] == self.board[c]:
print('Game over, player ' + choice + ' won the game')
self.GameOver = True
#Update the current board
def update(self, input, choice):
self.board[input] = choice
os.system('clear')
self.drawboard()
self.checkIfWon(choice)
#Resets the board
def resetBoard(self):
self.board = [0,1,2,3,4,5,6,7,8,9]
#Stops the game if tie
def tie(self):
list = []
for x in self.board:
if type(x) != int:
list.append(x)
if len(list) == 9:
return True
The class below contains the runGame method which starts the game:
import os
from board import Board
class Tictactoe():
b = Board()
choicePlayer1 = ''
choucePlayer2 = ''
corretChoice = False
correctPlayer1 = False
correctPlayer2 = False
def runGame(self):
os.system('clear')
#Resets the game when a new game is started
#Is necessary if the players wish to play more than 1 game
resetGame(self)
#Makes sure the game only starts if player1 picks X or O
while self.corretChoice == False:
self.choicePlayer1 = input('Do you want to play X or O? ')
print()
if self.choicePlayer1 == 'X':
self.choicePlayer2 = 'O'
self.corretChoice = True
print('Starting player selected X')
elif self.choicePlayer1 == 'O':
self.choicePlayer2 = 'X'
self.corretChoice = True
print('Starting player selected O')
else:
print('ERROR - input has to be either X or O!')
continue
os.system('clear')
self.b.drawboard()
while self.b.GameOver == False:
self.correctPlayer1 = False
self.correctPlayer2 = False
#For player1
while self.correctPlayer1 == False:
while True:
try:
x = int(input(self.choicePlayer1 + ' Where do you want to place your piece? '))
break
except:
print('Input has to be a number, try again')
if x > 0 and x < 10 and type(self.b.board[x]) != str:
self.b.update(x, self.choicePlayer1)
self.correctPlayer1 = True
elif x == 10:
quit()
else:
print('Spot is taken, try again: ')
if self.b.GameOver == True:
self.correctPlayer2 = True
if self.b.tie() == True:
self.correctPlayer2 = True
self.b.GameOver = True
print('Game is a tie')
#For player2
while self.correctPlayer2 == False:
while True:
try:
x = int(input(self.choicePlayer2 + ' Where do you want to place your piece? '))
break
except:
print('Input has to be a number, try again')
if x > 0 and x < 10 and type(self.b.board[x]) != str:
self.b.update(x, self.choicePlayer2)
self.correctPlayer2 = True
elif x == 10:
quit()
else:
print('Spot is taken, try again: ')
if self.b.tie() == True:
self.b.gameOver = True
print('Game is a tie')
#Resets the game if the players wishes to play again
def resetGame(self):
self.b = Board()
self.choicePlayer1 = ''
self.choucePlayer2 = ''
self.corretChoice = False
self.correctPlayer1 = False
self.correctPlayer2 = False
self.b.resetBoard()
The script i run to start the game:
from tictac import Tictactoe
run = Tictactoe()
while True:
run.runGame()
if input("Play again? (y/n)") == "n":
quit()
python homework tic-tac-toe
New contributor
$endgroup$
add a comment |
$begingroup$
I'm new to Python and I just finished a school assignment where I had to make a tictactoe game with focus on OOP. I would love to get some pointers on how I can clean up my code (especially my Tictactoe class) as it's pretty messy right now.
What I've done so far is comment as much as possible to make it understandable, but I feel like my tictactoe class is a mess and I would like to get some pointers on how I can optimize it.
The class below enforces the rules and draws the board:
import os
class Board:
board = [0,1,2,3,4,5,6,7,8,9]
win_combinations = [
(1,2,3),
(4,5,6),
(7,8,9),
(1,5,9),
(3,5,7),
(1,4,7),
(2,5,8),
(3,6,9),
]
GameOver = False
#Draws the board
def drawboard(self):
print('=========')
print(self.board[7], '|', self.board[8], '|', self.board[9])
print(self.board[4], '|', self.board[5], '|', self.board[6])
print(self.board[1], '|', self.board[2], '|', self.board[3])
print('=========')
#Checks if the move the player just made, made him/she win the game
def checkIfWon(self, choice):
for a, b, c in self.win_combinations:
if self.board[a] == self.board[b] == self.board[c]:
print('Game over, player ' + choice + ' won the game')
self.GameOver = True
#Update the current board
def update(self, input, choice):
self.board[input] = choice
os.system('clear')
self.drawboard()
self.checkIfWon(choice)
#Resets the board
def resetBoard(self):
self.board = [0,1,2,3,4,5,6,7,8,9]
#Stops the game if tie
def tie(self):
list = []
for x in self.board:
if type(x) != int:
list.append(x)
if len(list) == 9:
return True
The class below contains the runGame method which starts the game:
import os
from board import Board
class Tictactoe():
b = Board()
choicePlayer1 = ''
choucePlayer2 = ''
corretChoice = False
correctPlayer1 = False
correctPlayer2 = False
def runGame(self):
os.system('clear')
#Resets the game when a new game is started
#Is necessary if the players wish to play more than 1 game
resetGame(self)
#Makes sure the game only starts if player1 picks X or O
while self.corretChoice == False:
self.choicePlayer1 = input('Do you want to play X or O? ')
print()
if self.choicePlayer1 == 'X':
self.choicePlayer2 = 'O'
self.corretChoice = True
print('Starting player selected X')
elif self.choicePlayer1 == 'O':
self.choicePlayer2 = 'X'
self.corretChoice = True
print('Starting player selected O')
else:
print('ERROR - input has to be either X or O!')
continue
os.system('clear')
self.b.drawboard()
while self.b.GameOver == False:
self.correctPlayer1 = False
self.correctPlayer2 = False
#For player1
while self.correctPlayer1 == False:
while True:
try:
x = int(input(self.choicePlayer1 + ' Where do you want to place your piece? '))
break
except:
print('Input has to be a number, try again')
if x > 0 and x < 10 and type(self.b.board[x]) != str:
self.b.update(x, self.choicePlayer1)
self.correctPlayer1 = True
elif x == 10:
quit()
else:
print('Spot is taken, try again: ')
if self.b.GameOver == True:
self.correctPlayer2 = True
if self.b.tie() == True:
self.correctPlayer2 = True
self.b.GameOver = True
print('Game is a tie')
#For player2
while self.correctPlayer2 == False:
while True:
try:
x = int(input(self.choicePlayer2 + ' Where do you want to place your piece? '))
break
except:
print('Input has to be a number, try again')
if x > 0 and x < 10 and type(self.b.board[x]) != str:
self.b.update(x, self.choicePlayer2)
self.correctPlayer2 = True
elif x == 10:
quit()
else:
print('Spot is taken, try again: ')
if self.b.tie() == True:
self.b.gameOver = True
print('Game is a tie')
#Resets the game if the players wishes to play again
def resetGame(self):
self.b = Board()
self.choicePlayer1 = ''
self.choucePlayer2 = ''
self.corretChoice = False
self.correctPlayer1 = False
self.correctPlayer2 = False
self.b.resetBoard()
The script i run to start the game:
from tictac import Tictactoe
run = Tictactoe()
while True:
run.runGame()
if input("Play again? (y/n)") == "n":
quit()
python homework tic-tac-toe
New contributor
$endgroup$
I'm new to Python and I just finished a school assignment where I had to make a tictactoe game with focus on OOP. I would love to get some pointers on how I can clean up my code (especially my Tictactoe class) as it's pretty messy right now.
What I've done so far is comment as much as possible to make it understandable, but I feel like my tictactoe class is a mess and I would like to get some pointers on how I can optimize it.
The class below enforces the rules and draws the board:
import os
class Board:
board = [0,1,2,3,4,5,6,7,8,9]
win_combinations = [
(1,2,3),
(4,5,6),
(7,8,9),
(1,5,9),
(3,5,7),
(1,4,7),
(2,5,8),
(3,6,9),
]
GameOver = False
#Draws the board
def drawboard(self):
print('=========')
print(self.board[7], '|', self.board[8], '|', self.board[9])
print(self.board[4], '|', self.board[5], '|', self.board[6])
print(self.board[1], '|', self.board[2], '|', self.board[3])
print('=========')
#Checks if the move the player just made, made him/she win the game
def checkIfWon(self, choice):
for a, b, c in self.win_combinations:
if self.board[a] == self.board[b] == self.board[c]:
print('Game over, player ' + choice + ' won the game')
self.GameOver = True
#Update the current board
def update(self, input, choice):
self.board[input] = choice
os.system('clear')
self.drawboard()
self.checkIfWon(choice)
#Resets the board
def resetBoard(self):
self.board = [0,1,2,3,4,5,6,7,8,9]
#Stops the game if tie
def tie(self):
list = []
for x in self.board:
if type(x) != int:
list.append(x)
if len(list) == 9:
return True
The class below contains the runGame method which starts the game:
import os
from board import Board
class Tictactoe():
b = Board()
choicePlayer1 = ''
choucePlayer2 = ''
corretChoice = False
correctPlayer1 = False
correctPlayer2 = False
def runGame(self):
os.system('clear')
#Resets the game when a new game is started
#Is necessary if the players wish to play more than 1 game
resetGame(self)
#Makes sure the game only starts if player1 picks X or O
while self.corretChoice == False:
self.choicePlayer1 = input('Do you want to play X or O? ')
print()
if self.choicePlayer1 == 'X':
self.choicePlayer2 = 'O'
self.corretChoice = True
print('Starting player selected X')
elif self.choicePlayer1 == 'O':
self.choicePlayer2 = 'X'
self.corretChoice = True
print('Starting player selected O')
else:
print('ERROR - input has to be either X or O!')
continue
os.system('clear')
self.b.drawboard()
while self.b.GameOver == False:
self.correctPlayer1 = False
self.correctPlayer2 = False
#For player1
while self.correctPlayer1 == False:
while True:
try:
x = int(input(self.choicePlayer1 + ' Where do you want to place your piece? '))
break
except:
print('Input has to be a number, try again')
if x > 0 and x < 10 and type(self.b.board[x]) != str:
self.b.update(x, self.choicePlayer1)
self.correctPlayer1 = True
elif x == 10:
quit()
else:
print('Spot is taken, try again: ')
if self.b.GameOver == True:
self.correctPlayer2 = True
if self.b.tie() == True:
self.correctPlayer2 = True
self.b.GameOver = True
print('Game is a tie')
#For player2
while self.correctPlayer2 == False:
while True:
try:
x = int(input(self.choicePlayer2 + ' Where do you want to place your piece? '))
break
except:
print('Input has to be a number, try again')
if x > 0 and x < 10 and type(self.b.board[x]) != str:
self.b.update(x, self.choicePlayer2)
self.correctPlayer2 = True
elif x == 10:
quit()
else:
print('Spot is taken, try again: ')
if self.b.tie() == True:
self.b.gameOver = True
print('Game is a tie')
#Resets the game if the players wishes to play again
def resetGame(self):
self.b = Board()
self.choicePlayer1 = ''
self.choucePlayer2 = ''
self.corretChoice = False
self.correctPlayer1 = False
self.correctPlayer2 = False
self.b.resetBoard()
The script i run to start the game:
from tictac import Tictactoe
run = Tictactoe()
while True:
run.runGame()
if input("Play again? (y/n)") == "n":
quit()
python homework tic-tac-toe
python homework tic-tac-toe
New contributor
New contributor
edited Apr 1 at 16:21
200_success
131k17157422
131k17157422
New contributor
asked Apr 1 at 13:32
mikkelrævmikkelræv
183
183
New contributor
New contributor
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
$begingroup$
Now, as has been said before: this is more of a codereview than a question. Nevertheless:
- You're defining
class Board:
without parantheses andclass Tictactoe()
with. No big deal reall, but a bit of inconsistency. I personally just put parens on every declaration. Rids you of having to think about it. - The variables
board
,win_combinations
andGameOver
are defined as class variables since they're declared in the body of the class definition itself. This means that should you for some reason instantiate two games at once they'll mess with each other. It would be better to put them into a constructor__init__(self)
(the actual constructor is__new__
but you hardly need to edit that so init is generally refered to as constructor). That way every instance has their own instances of these variables. - The names of the variables and general format doesn't conform to PEP8. Some things here are: Docstrings for classes to describe what they do etc.; variables named snake_case (except for globals/constants) and classes CamelCase; two lines between top level classes, functions etc.; double quotes rather than single quotes. Also the variables probably aren't supposed to be manipulated from outside the class so you could tell other programmers so by prefixing them with an underscore "_".
- Maybe add some additional abstraction. The board in your case isn't only a board but also includes gamelogic like checking for a win etc.
- You're using + for string concatenation/interpolation which is deprecated
print('Game over, player ' + choice + ' won the game')
. The more modern and also more efficient way would be to use an f-string f"Game over, player {choice} won the game".
The block
def tie(self):
list = []
for x in self.board:
if type(x) != int:
list.append(x)
could be written as a list comprehension or generator expression:
list = [x for x in self.board if type(x) != int]
. Or using thefilter
method:list = list(filter(lambda x: type(x) != int, self.board))
. You should also renamelist
tolist_
or an actual expressive name saying what it represents here. And in the same function you could justreturn len(list) == 9
since that already is a boolean expression.
That's it for the board class. Most of the stuff like format, not using class variables etc also applies to the TicTacToe class.
resetGame(self)
should probably be a method on the class so you can doself.reset_game()
or similar.- Typo in
corretChoice
->correct_choice
.
b
is a really inexpressive variable name for the board. Why don't you name itboard
? Especially if it's used across the whole class (rather than being just a local variable) that would make the code a lot clearer.
You're catching everything here:
try:
x = int(input(self.choicePlayer1 + ' Where do you want to place your piece? '))
break
except:
print('Input has to be a number, try again')
which is really bad style. It will for example also catch stuff like keyboard interrupts. Since you want to catch errors in the conversion what you probably want is
except ValueError:
.
And lastly not really an error but: if the user inputs anything other than n
on the "play again?"-prompt it'll restart.
I also feel like the runGame method is way too large - I'll see if I can come up with a clearer solution and post it up here if I can.
EDIT:
I've tried my hand at refactoring you're code:
import os
class Board():
"""Represents the game-board"""
def __init__(self):
self.board = [i for i in range(10)]
self._win_combinations = [
(1, 2, 3),
(4, 5, 6),
(7, 8, 9),
(1, 5, 9),
(3, 5, 7),
(1, 4, 7),
(2, 5, 8),
(3, 6, 9)]
self.game_over = False
def draw_board(self):
"""Draws the board to the terminal"""
print("=========")
print(self.board[7], "|", self.board[8], "|", self.board[9])
print(self.board[4], "|", self.board[5], "|", self.board[6])
print(self.board[1], "|", self.board[2], "|", self.board[3])
print("=========")
def check_if_won(self, player):
"""Checks if the move the player just made, made him/her win the game"""
for a, b, c in self._win_combinations:
if self.board[a] == self.board[b] == self.board[c]:
print(f"Game over, player {player} won the game")
self.game_over = True
def update(self, input, choice):
"""Update the current board"""
self.board[input] = choice
os.system("clear")
self.draw_board()
self.check_if_won(choice)
def reset_board(self):
"""Resets the board"""
self.board = [i for i in range(10)]
def tie(self):
"""Stops the game if tie"""
list_ = list(filter(lambda x: type(x) != int, self.board))
return len(list_) == 9
class TicTacToe():
def __init__(self):
os.system("clear")
self.board = Board()
self.player_1_char = ""
self.player_2_char = ""
self.corret_choice = False
self.get_player_char()
def reset(self):
"""Resets the internal state to prepare for a new game"""
self.player_1_char = ""
self.player_2_char = ""
self.board.reset_board()
def get_player_char(self):
"""Ask the player what character he wants to use and verify choice"""
while True:
player_1_char = input("Do you want to play X or O? ")
print()
if player_1_char == "X":
self.player_1_char = "X"
self.player_2_char = "O"
print("Starting player selected X")
break
elif player_1_char == "O":
self.player_1_char = "O"
self.player_2_char = "X"
print("Starting player selected O")
break
else:
print("ERROR - input has to be either X or O!")
os.system("clear")
def get_player_input(self, player_char):
while True:
while True:
x = input(f"{player_char} Where do you want to place your piece?")
if x.isdigit():
x = int(x)
break
else:
print("Input has to be a number, try again")
if x > 0 and x < 10 and type(self.board.board[x]) != str:
self.board.update(x, player_char)
break
elif x == 10:
quit()
else:
print("Spot is taken, try again: ")
def check_tie(self):
if self.board.tie():
self.board.game_over = True
print("Game is a tie")
return True
return False
def run(self):
self.board.draw_board()
while not self.board.game_over:
self.correct_player_1 = False
self.correct_player_2 = False
self.get_player_input(self.player_1_char)
if self.board.game_over:
break
if self.check_tie():
break
self.get_player_input(self.player_2_char)
if self.board.game_over:
break
if self.check_tie():
break
while True:
TicTacToe().run()
user_input = "a"
while user_input not in "ny":
user_input = input("Play again? (y/n)").lower()
if user_input == "y":
continue
else:
break
New contributor
$endgroup$
1
$begingroup$
"class Board:
is Python 2 syntax" - nope. It's just Python. Parens are optional in either version.
$endgroup$
– Reinderien
Apr 1 at 13:58
$begingroup$
whoops, sorry. Don't know why I had that in mind like this. Still: He defines one class with and one without parens.
$endgroup$
– SV-97
Apr 1 at 14:04
$begingroup$
It's OK; edit your question to suit and I'll upvote it. Everything else looks good.
$endgroup$
– Reinderien
Apr 1 at 14:05
1
$begingroup$
@SV-97 Thank you for writing such a detailed response. Really helpful. I didn't know about PEP8, was a nice read.
$endgroup$
– mikkelræv
Apr 1 at 14:25
1
$begingroup$
No problem - I generally enjoy code reviews and profit from them too :D I've just added my version of your code if you want to have a look though I'd of course encourage you to try implementing some of the mentioned things yourself beforehand.
$endgroup$
– SV-97
Apr 1 at 14:42
|
show 1 more comment
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
mikkelræv is a new contributor. Be nice, and check out our Code of Conduct.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f216654%2fsmall-terminal-tic-tac-toe-game%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
$begingroup$
Now, as has been said before: this is more of a codereview than a question. Nevertheless:
- You're defining
class Board:
without parantheses andclass Tictactoe()
with. No big deal reall, but a bit of inconsistency. I personally just put parens on every declaration. Rids you of having to think about it. - The variables
board
,win_combinations
andGameOver
are defined as class variables since they're declared in the body of the class definition itself. This means that should you for some reason instantiate two games at once they'll mess with each other. It would be better to put them into a constructor__init__(self)
(the actual constructor is__new__
but you hardly need to edit that so init is generally refered to as constructor). That way every instance has their own instances of these variables. - The names of the variables and general format doesn't conform to PEP8. Some things here are: Docstrings for classes to describe what they do etc.; variables named snake_case (except for globals/constants) and classes CamelCase; two lines between top level classes, functions etc.; double quotes rather than single quotes. Also the variables probably aren't supposed to be manipulated from outside the class so you could tell other programmers so by prefixing them with an underscore "_".
- Maybe add some additional abstraction. The board in your case isn't only a board but also includes gamelogic like checking for a win etc.
- You're using + for string concatenation/interpolation which is deprecated
print('Game over, player ' + choice + ' won the game')
. The more modern and also more efficient way would be to use an f-string f"Game over, player {choice} won the game".
The block
def tie(self):
list = []
for x in self.board:
if type(x) != int:
list.append(x)
could be written as a list comprehension or generator expression:
list = [x for x in self.board if type(x) != int]
. Or using thefilter
method:list = list(filter(lambda x: type(x) != int, self.board))
. You should also renamelist
tolist_
or an actual expressive name saying what it represents here. And in the same function you could justreturn len(list) == 9
since that already is a boolean expression.
That's it for the board class. Most of the stuff like format, not using class variables etc also applies to the TicTacToe class.
resetGame(self)
should probably be a method on the class so you can doself.reset_game()
or similar.- Typo in
corretChoice
->correct_choice
.
b
is a really inexpressive variable name for the board. Why don't you name itboard
? Especially if it's used across the whole class (rather than being just a local variable) that would make the code a lot clearer.
You're catching everything here:
try:
x = int(input(self.choicePlayer1 + ' Where do you want to place your piece? '))
break
except:
print('Input has to be a number, try again')
which is really bad style. It will for example also catch stuff like keyboard interrupts. Since you want to catch errors in the conversion what you probably want is
except ValueError:
.
And lastly not really an error but: if the user inputs anything other than n
on the "play again?"-prompt it'll restart.
I also feel like the runGame method is way too large - I'll see if I can come up with a clearer solution and post it up here if I can.
EDIT:
I've tried my hand at refactoring you're code:
import os
class Board():
"""Represents the game-board"""
def __init__(self):
self.board = [i for i in range(10)]
self._win_combinations = [
(1, 2, 3),
(4, 5, 6),
(7, 8, 9),
(1, 5, 9),
(3, 5, 7),
(1, 4, 7),
(2, 5, 8),
(3, 6, 9)]
self.game_over = False
def draw_board(self):
"""Draws the board to the terminal"""
print("=========")
print(self.board[7], "|", self.board[8], "|", self.board[9])
print(self.board[4], "|", self.board[5], "|", self.board[6])
print(self.board[1], "|", self.board[2], "|", self.board[3])
print("=========")
def check_if_won(self, player):
"""Checks if the move the player just made, made him/her win the game"""
for a, b, c in self._win_combinations:
if self.board[a] == self.board[b] == self.board[c]:
print(f"Game over, player {player} won the game")
self.game_over = True
def update(self, input, choice):
"""Update the current board"""
self.board[input] = choice
os.system("clear")
self.draw_board()
self.check_if_won(choice)
def reset_board(self):
"""Resets the board"""
self.board = [i for i in range(10)]
def tie(self):
"""Stops the game if tie"""
list_ = list(filter(lambda x: type(x) != int, self.board))
return len(list_) == 9
class TicTacToe():
def __init__(self):
os.system("clear")
self.board = Board()
self.player_1_char = ""
self.player_2_char = ""
self.corret_choice = False
self.get_player_char()
def reset(self):
"""Resets the internal state to prepare for a new game"""
self.player_1_char = ""
self.player_2_char = ""
self.board.reset_board()
def get_player_char(self):
"""Ask the player what character he wants to use and verify choice"""
while True:
player_1_char = input("Do you want to play X or O? ")
print()
if player_1_char == "X":
self.player_1_char = "X"
self.player_2_char = "O"
print("Starting player selected X")
break
elif player_1_char == "O":
self.player_1_char = "O"
self.player_2_char = "X"
print("Starting player selected O")
break
else:
print("ERROR - input has to be either X or O!")
os.system("clear")
def get_player_input(self, player_char):
while True:
while True:
x = input(f"{player_char} Where do you want to place your piece?")
if x.isdigit():
x = int(x)
break
else:
print("Input has to be a number, try again")
if x > 0 and x < 10 and type(self.board.board[x]) != str:
self.board.update(x, player_char)
break
elif x == 10:
quit()
else:
print("Spot is taken, try again: ")
def check_tie(self):
if self.board.tie():
self.board.game_over = True
print("Game is a tie")
return True
return False
def run(self):
self.board.draw_board()
while not self.board.game_over:
self.correct_player_1 = False
self.correct_player_2 = False
self.get_player_input(self.player_1_char)
if self.board.game_over:
break
if self.check_tie():
break
self.get_player_input(self.player_2_char)
if self.board.game_over:
break
if self.check_tie():
break
while True:
TicTacToe().run()
user_input = "a"
while user_input not in "ny":
user_input = input("Play again? (y/n)").lower()
if user_input == "y":
continue
else:
break
New contributor
$endgroup$
1
$begingroup$
"class Board:
is Python 2 syntax" - nope. It's just Python. Parens are optional in either version.
$endgroup$
– Reinderien
Apr 1 at 13:58
$begingroup$
whoops, sorry. Don't know why I had that in mind like this. Still: He defines one class with and one without parens.
$endgroup$
– SV-97
Apr 1 at 14:04
$begingroup$
It's OK; edit your question to suit and I'll upvote it. Everything else looks good.
$endgroup$
– Reinderien
Apr 1 at 14:05
1
$begingroup$
@SV-97 Thank you for writing such a detailed response. Really helpful. I didn't know about PEP8, was a nice read.
$endgroup$
– mikkelræv
Apr 1 at 14:25
1
$begingroup$
No problem - I generally enjoy code reviews and profit from them too :D I've just added my version of your code if you want to have a look though I'd of course encourage you to try implementing some of the mentioned things yourself beforehand.
$endgroup$
– SV-97
Apr 1 at 14:42
|
show 1 more comment
$begingroup$
Now, as has been said before: this is more of a codereview than a question. Nevertheless:
- You're defining
class Board:
without parantheses andclass Tictactoe()
with. No big deal reall, but a bit of inconsistency. I personally just put parens on every declaration. Rids you of having to think about it. - The variables
board
,win_combinations
andGameOver
are defined as class variables since they're declared in the body of the class definition itself. This means that should you for some reason instantiate two games at once they'll mess with each other. It would be better to put them into a constructor__init__(self)
(the actual constructor is__new__
but you hardly need to edit that so init is generally refered to as constructor). That way every instance has their own instances of these variables. - The names of the variables and general format doesn't conform to PEP8. Some things here are: Docstrings for classes to describe what they do etc.; variables named snake_case (except for globals/constants) and classes CamelCase; two lines between top level classes, functions etc.; double quotes rather than single quotes. Also the variables probably aren't supposed to be manipulated from outside the class so you could tell other programmers so by prefixing them with an underscore "_".
- Maybe add some additional abstraction. The board in your case isn't only a board but also includes gamelogic like checking for a win etc.
- You're using + for string concatenation/interpolation which is deprecated
print('Game over, player ' + choice + ' won the game')
. The more modern and also more efficient way would be to use an f-string f"Game over, player {choice} won the game".
The block
def tie(self):
list = []
for x in self.board:
if type(x) != int:
list.append(x)
could be written as a list comprehension or generator expression:
list = [x for x in self.board if type(x) != int]
. Or using thefilter
method:list = list(filter(lambda x: type(x) != int, self.board))
. You should also renamelist
tolist_
or an actual expressive name saying what it represents here. And in the same function you could justreturn len(list) == 9
since that already is a boolean expression.
That's it for the board class. Most of the stuff like format, not using class variables etc also applies to the TicTacToe class.
resetGame(self)
should probably be a method on the class so you can doself.reset_game()
or similar.- Typo in
corretChoice
->correct_choice
.
b
is a really inexpressive variable name for the board. Why don't you name itboard
? Especially if it's used across the whole class (rather than being just a local variable) that would make the code a lot clearer.
You're catching everything here:
try:
x = int(input(self.choicePlayer1 + ' Where do you want to place your piece? '))
break
except:
print('Input has to be a number, try again')
which is really bad style. It will for example also catch stuff like keyboard interrupts. Since you want to catch errors in the conversion what you probably want is
except ValueError:
.
And lastly not really an error but: if the user inputs anything other than n
on the "play again?"-prompt it'll restart.
I also feel like the runGame method is way too large - I'll see if I can come up with a clearer solution and post it up here if I can.
EDIT:
I've tried my hand at refactoring you're code:
import os
class Board():
"""Represents the game-board"""
def __init__(self):
self.board = [i for i in range(10)]
self._win_combinations = [
(1, 2, 3),
(4, 5, 6),
(7, 8, 9),
(1, 5, 9),
(3, 5, 7),
(1, 4, 7),
(2, 5, 8),
(3, 6, 9)]
self.game_over = False
def draw_board(self):
"""Draws the board to the terminal"""
print("=========")
print(self.board[7], "|", self.board[8], "|", self.board[9])
print(self.board[4], "|", self.board[5], "|", self.board[6])
print(self.board[1], "|", self.board[2], "|", self.board[3])
print("=========")
def check_if_won(self, player):
"""Checks if the move the player just made, made him/her win the game"""
for a, b, c in self._win_combinations:
if self.board[a] == self.board[b] == self.board[c]:
print(f"Game over, player {player} won the game")
self.game_over = True
def update(self, input, choice):
"""Update the current board"""
self.board[input] = choice
os.system("clear")
self.draw_board()
self.check_if_won(choice)
def reset_board(self):
"""Resets the board"""
self.board = [i for i in range(10)]
def tie(self):
"""Stops the game if tie"""
list_ = list(filter(lambda x: type(x) != int, self.board))
return len(list_) == 9
class TicTacToe():
def __init__(self):
os.system("clear")
self.board = Board()
self.player_1_char = ""
self.player_2_char = ""
self.corret_choice = False
self.get_player_char()
def reset(self):
"""Resets the internal state to prepare for a new game"""
self.player_1_char = ""
self.player_2_char = ""
self.board.reset_board()
def get_player_char(self):
"""Ask the player what character he wants to use and verify choice"""
while True:
player_1_char = input("Do you want to play X or O? ")
print()
if player_1_char == "X":
self.player_1_char = "X"
self.player_2_char = "O"
print("Starting player selected X")
break
elif player_1_char == "O":
self.player_1_char = "O"
self.player_2_char = "X"
print("Starting player selected O")
break
else:
print("ERROR - input has to be either X or O!")
os.system("clear")
def get_player_input(self, player_char):
while True:
while True:
x = input(f"{player_char} Where do you want to place your piece?")
if x.isdigit():
x = int(x)
break
else:
print("Input has to be a number, try again")
if x > 0 and x < 10 and type(self.board.board[x]) != str:
self.board.update(x, player_char)
break
elif x == 10:
quit()
else:
print("Spot is taken, try again: ")
def check_tie(self):
if self.board.tie():
self.board.game_over = True
print("Game is a tie")
return True
return False
def run(self):
self.board.draw_board()
while not self.board.game_over:
self.correct_player_1 = False
self.correct_player_2 = False
self.get_player_input(self.player_1_char)
if self.board.game_over:
break
if self.check_tie():
break
self.get_player_input(self.player_2_char)
if self.board.game_over:
break
if self.check_tie():
break
while True:
TicTacToe().run()
user_input = "a"
while user_input not in "ny":
user_input = input("Play again? (y/n)").lower()
if user_input == "y":
continue
else:
break
New contributor
$endgroup$
1
$begingroup$
"class Board:
is Python 2 syntax" - nope. It's just Python. Parens are optional in either version.
$endgroup$
– Reinderien
Apr 1 at 13:58
$begingroup$
whoops, sorry. Don't know why I had that in mind like this. Still: He defines one class with and one without parens.
$endgroup$
– SV-97
Apr 1 at 14:04
$begingroup$
It's OK; edit your question to suit and I'll upvote it. Everything else looks good.
$endgroup$
– Reinderien
Apr 1 at 14:05
1
$begingroup$
@SV-97 Thank you for writing such a detailed response. Really helpful. I didn't know about PEP8, was a nice read.
$endgroup$
– mikkelræv
Apr 1 at 14:25
1
$begingroup$
No problem - I generally enjoy code reviews and profit from them too :D I've just added my version of your code if you want to have a look though I'd of course encourage you to try implementing some of the mentioned things yourself beforehand.
$endgroup$
– SV-97
Apr 1 at 14:42
|
show 1 more comment
$begingroup$
Now, as has been said before: this is more of a codereview than a question. Nevertheless:
- You're defining
class Board:
without parantheses andclass Tictactoe()
with. No big deal reall, but a bit of inconsistency. I personally just put parens on every declaration. Rids you of having to think about it. - The variables
board
,win_combinations
andGameOver
are defined as class variables since they're declared in the body of the class definition itself. This means that should you for some reason instantiate two games at once they'll mess with each other. It would be better to put them into a constructor__init__(self)
(the actual constructor is__new__
but you hardly need to edit that so init is generally refered to as constructor). That way every instance has their own instances of these variables. - The names of the variables and general format doesn't conform to PEP8. Some things here are: Docstrings for classes to describe what they do etc.; variables named snake_case (except for globals/constants) and classes CamelCase; two lines between top level classes, functions etc.; double quotes rather than single quotes. Also the variables probably aren't supposed to be manipulated from outside the class so you could tell other programmers so by prefixing them with an underscore "_".
- Maybe add some additional abstraction. The board in your case isn't only a board but also includes gamelogic like checking for a win etc.
- You're using + for string concatenation/interpolation which is deprecated
print('Game over, player ' + choice + ' won the game')
. The more modern and also more efficient way would be to use an f-string f"Game over, player {choice} won the game".
The block
def tie(self):
list = []
for x in self.board:
if type(x) != int:
list.append(x)
could be written as a list comprehension or generator expression:
list = [x for x in self.board if type(x) != int]
. Or using thefilter
method:list = list(filter(lambda x: type(x) != int, self.board))
. You should also renamelist
tolist_
or an actual expressive name saying what it represents here. And in the same function you could justreturn len(list) == 9
since that already is a boolean expression.
That's it for the board class. Most of the stuff like format, not using class variables etc also applies to the TicTacToe class.
resetGame(self)
should probably be a method on the class so you can doself.reset_game()
or similar.- Typo in
corretChoice
->correct_choice
.
b
is a really inexpressive variable name for the board. Why don't you name itboard
? Especially if it's used across the whole class (rather than being just a local variable) that would make the code a lot clearer.
You're catching everything here:
try:
x = int(input(self.choicePlayer1 + ' Where do you want to place your piece? '))
break
except:
print('Input has to be a number, try again')
which is really bad style. It will for example also catch stuff like keyboard interrupts. Since you want to catch errors in the conversion what you probably want is
except ValueError:
.
And lastly not really an error but: if the user inputs anything other than n
on the "play again?"-prompt it'll restart.
I also feel like the runGame method is way too large - I'll see if I can come up with a clearer solution and post it up here if I can.
EDIT:
I've tried my hand at refactoring you're code:
import os
class Board():
"""Represents the game-board"""
def __init__(self):
self.board = [i for i in range(10)]
self._win_combinations = [
(1, 2, 3),
(4, 5, 6),
(7, 8, 9),
(1, 5, 9),
(3, 5, 7),
(1, 4, 7),
(2, 5, 8),
(3, 6, 9)]
self.game_over = False
def draw_board(self):
"""Draws the board to the terminal"""
print("=========")
print(self.board[7], "|", self.board[8], "|", self.board[9])
print(self.board[4], "|", self.board[5], "|", self.board[6])
print(self.board[1], "|", self.board[2], "|", self.board[3])
print("=========")
def check_if_won(self, player):
"""Checks if the move the player just made, made him/her win the game"""
for a, b, c in self._win_combinations:
if self.board[a] == self.board[b] == self.board[c]:
print(f"Game over, player {player} won the game")
self.game_over = True
def update(self, input, choice):
"""Update the current board"""
self.board[input] = choice
os.system("clear")
self.draw_board()
self.check_if_won(choice)
def reset_board(self):
"""Resets the board"""
self.board = [i for i in range(10)]
def tie(self):
"""Stops the game if tie"""
list_ = list(filter(lambda x: type(x) != int, self.board))
return len(list_) == 9
class TicTacToe():
def __init__(self):
os.system("clear")
self.board = Board()
self.player_1_char = ""
self.player_2_char = ""
self.corret_choice = False
self.get_player_char()
def reset(self):
"""Resets the internal state to prepare for a new game"""
self.player_1_char = ""
self.player_2_char = ""
self.board.reset_board()
def get_player_char(self):
"""Ask the player what character he wants to use and verify choice"""
while True:
player_1_char = input("Do you want to play X or O? ")
print()
if player_1_char == "X":
self.player_1_char = "X"
self.player_2_char = "O"
print("Starting player selected X")
break
elif player_1_char == "O":
self.player_1_char = "O"
self.player_2_char = "X"
print("Starting player selected O")
break
else:
print("ERROR - input has to be either X or O!")
os.system("clear")
def get_player_input(self, player_char):
while True:
while True:
x = input(f"{player_char} Where do you want to place your piece?")
if x.isdigit():
x = int(x)
break
else:
print("Input has to be a number, try again")
if x > 0 and x < 10 and type(self.board.board[x]) != str:
self.board.update(x, player_char)
break
elif x == 10:
quit()
else:
print("Spot is taken, try again: ")
def check_tie(self):
if self.board.tie():
self.board.game_over = True
print("Game is a tie")
return True
return False
def run(self):
self.board.draw_board()
while not self.board.game_over:
self.correct_player_1 = False
self.correct_player_2 = False
self.get_player_input(self.player_1_char)
if self.board.game_over:
break
if self.check_tie():
break
self.get_player_input(self.player_2_char)
if self.board.game_over:
break
if self.check_tie():
break
while True:
TicTacToe().run()
user_input = "a"
while user_input not in "ny":
user_input = input("Play again? (y/n)").lower()
if user_input == "y":
continue
else:
break
New contributor
$endgroup$
Now, as has been said before: this is more of a codereview than a question. Nevertheless:
- You're defining
class Board:
without parantheses andclass Tictactoe()
with. No big deal reall, but a bit of inconsistency. I personally just put parens on every declaration. Rids you of having to think about it. - The variables
board
,win_combinations
andGameOver
are defined as class variables since they're declared in the body of the class definition itself. This means that should you for some reason instantiate two games at once they'll mess with each other. It would be better to put them into a constructor__init__(self)
(the actual constructor is__new__
but you hardly need to edit that so init is generally refered to as constructor). That way every instance has their own instances of these variables. - The names of the variables and general format doesn't conform to PEP8. Some things here are: Docstrings for classes to describe what they do etc.; variables named snake_case (except for globals/constants) and classes CamelCase; two lines between top level classes, functions etc.; double quotes rather than single quotes. Also the variables probably aren't supposed to be manipulated from outside the class so you could tell other programmers so by prefixing them with an underscore "_".
- Maybe add some additional abstraction. The board in your case isn't only a board but also includes gamelogic like checking for a win etc.
- You're using + for string concatenation/interpolation which is deprecated
print('Game over, player ' + choice + ' won the game')
. The more modern and also more efficient way would be to use an f-string f"Game over, player {choice} won the game".
The block
def tie(self):
list = []
for x in self.board:
if type(x) != int:
list.append(x)
could be written as a list comprehension or generator expression:
list = [x for x in self.board if type(x) != int]
. Or using thefilter
method:list = list(filter(lambda x: type(x) != int, self.board))
. You should also renamelist
tolist_
or an actual expressive name saying what it represents here. And in the same function you could justreturn len(list) == 9
since that already is a boolean expression.
That's it for the board class. Most of the stuff like format, not using class variables etc also applies to the TicTacToe class.
resetGame(self)
should probably be a method on the class so you can doself.reset_game()
or similar.- Typo in
corretChoice
->correct_choice
.
b
is a really inexpressive variable name for the board. Why don't you name itboard
? Especially if it's used across the whole class (rather than being just a local variable) that would make the code a lot clearer.
You're catching everything here:
try:
x = int(input(self.choicePlayer1 + ' Where do you want to place your piece? '))
break
except:
print('Input has to be a number, try again')
which is really bad style. It will for example also catch stuff like keyboard interrupts. Since you want to catch errors in the conversion what you probably want is
except ValueError:
.
And lastly not really an error but: if the user inputs anything other than n
on the "play again?"-prompt it'll restart.
I also feel like the runGame method is way too large - I'll see if I can come up with a clearer solution and post it up here if I can.
EDIT:
I've tried my hand at refactoring you're code:
import os
class Board():
"""Represents the game-board"""
def __init__(self):
self.board = [i for i in range(10)]
self._win_combinations = [
(1, 2, 3),
(4, 5, 6),
(7, 8, 9),
(1, 5, 9),
(3, 5, 7),
(1, 4, 7),
(2, 5, 8),
(3, 6, 9)]
self.game_over = False
def draw_board(self):
"""Draws the board to the terminal"""
print("=========")
print(self.board[7], "|", self.board[8], "|", self.board[9])
print(self.board[4], "|", self.board[5], "|", self.board[6])
print(self.board[1], "|", self.board[2], "|", self.board[3])
print("=========")
def check_if_won(self, player):
"""Checks if the move the player just made, made him/her win the game"""
for a, b, c in self._win_combinations:
if self.board[a] == self.board[b] == self.board[c]:
print(f"Game over, player {player} won the game")
self.game_over = True
def update(self, input, choice):
"""Update the current board"""
self.board[input] = choice
os.system("clear")
self.draw_board()
self.check_if_won(choice)
def reset_board(self):
"""Resets the board"""
self.board = [i for i in range(10)]
def tie(self):
"""Stops the game if tie"""
list_ = list(filter(lambda x: type(x) != int, self.board))
return len(list_) == 9
class TicTacToe():
def __init__(self):
os.system("clear")
self.board = Board()
self.player_1_char = ""
self.player_2_char = ""
self.corret_choice = False
self.get_player_char()
def reset(self):
"""Resets the internal state to prepare for a new game"""
self.player_1_char = ""
self.player_2_char = ""
self.board.reset_board()
def get_player_char(self):
"""Ask the player what character he wants to use and verify choice"""
while True:
player_1_char = input("Do you want to play X or O? ")
print()
if player_1_char == "X":
self.player_1_char = "X"
self.player_2_char = "O"
print("Starting player selected X")
break
elif player_1_char == "O":
self.player_1_char = "O"
self.player_2_char = "X"
print("Starting player selected O")
break
else:
print("ERROR - input has to be either X or O!")
os.system("clear")
def get_player_input(self, player_char):
while True:
while True:
x = input(f"{player_char} Where do you want to place your piece?")
if x.isdigit():
x = int(x)
break
else:
print("Input has to be a number, try again")
if x > 0 and x < 10 and type(self.board.board[x]) != str:
self.board.update(x, player_char)
break
elif x == 10:
quit()
else:
print("Spot is taken, try again: ")
def check_tie(self):
if self.board.tie():
self.board.game_over = True
print("Game is a tie")
return True
return False
def run(self):
self.board.draw_board()
while not self.board.game_over:
self.correct_player_1 = False
self.correct_player_2 = False
self.get_player_input(self.player_1_char)
if self.board.game_over:
break
if self.check_tie():
break
self.get_player_input(self.player_2_char)
if self.board.game_over:
break
if self.check_tie():
break
while True:
TicTacToe().run()
user_input = "a"
while user_input not in "ny":
user_input = input("Play again? (y/n)").lower()
if user_input == "y":
continue
else:
break
New contributor
edited Apr 1 at 14:41
New contributor
answered Apr 1 at 13:45
SV-97SV-97
463
463
New contributor
New contributor
1
$begingroup$
"class Board:
is Python 2 syntax" - nope. It's just Python. Parens are optional in either version.
$endgroup$
– Reinderien
Apr 1 at 13:58
$begingroup$
whoops, sorry. Don't know why I had that in mind like this. Still: He defines one class with and one without parens.
$endgroup$
– SV-97
Apr 1 at 14:04
$begingroup$
It's OK; edit your question to suit and I'll upvote it. Everything else looks good.
$endgroup$
– Reinderien
Apr 1 at 14:05
1
$begingroup$
@SV-97 Thank you for writing such a detailed response. Really helpful. I didn't know about PEP8, was a nice read.
$endgroup$
– mikkelræv
Apr 1 at 14:25
1
$begingroup$
No problem - I generally enjoy code reviews and profit from them too :D I've just added my version of your code if you want to have a look though I'd of course encourage you to try implementing some of the mentioned things yourself beforehand.
$endgroup$
– SV-97
Apr 1 at 14:42
|
show 1 more comment
1
$begingroup$
"class Board:
is Python 2 syntax" - nope. It's just Python. Parens are optional in either version.
$endgroup$
– Reinderien
Apr 1 at 13:58
$begingroup$
whoops, sorry. Don't know why I had that in mind like this. Still: He defines one class with and one without parens.
$endgroup$
– SV-97
Apr 1 at 14:04
$begingroup$
It's OK; edit your question to suit and I'll upvote it. Everything else looks good.
$endgroup$
– Reinderien
Apr 1 at 14:05
1
$begingroup$
@SV-97 Thank you for writing such a detailed response. Really helpful. I didn't know about PEP8, was a nice read.
$endgroup$
– mikkelræv
Apr 1 at 14:25
1
$begingroup$
No problem - I generally enjoy code reviews and profit from them too :D I've just added my version of your code if you want to have a look though I'd of course encourage you to try implementing some of the mentioned things yourself beforehand.
$endgroup$
– SV-97
Apr 1 at 14:42
1
1
$begingroup$
"
class Board:
is Python 2 syntax" - nope. It's just Python. Parens are optional in either version.$endgroup$
– Reinderien
Apr 1 at 13:58
$begingroup$
"
class Board:
is Python 2 syntax" - nope. It's just Python. Parens are optional in either version.$endgroup$
– Reinderien
Apr 1 at 13:58
$begingroup$
whoops, sorry. Don't know why I had that in mind like this. Still: He defines one class with and one without parens.
$endgroup$
– SV-97
Apr 1 at 14:04
$begingroup$
whoops, sorry. Don't know why I had that in mind like this. Still: He defines one class with and one without parens.
$endgroup$
– SV-97
Apr 1 at 14:04
$begingroup$
It's OK; edit your question to suit and I'll upvote it. Everything else looks good.
$endgroup$
– Reinderien
Apr 1 at 14:05
$begingroup$
It's OK; edit your question to suit and I'll upvote it. Everything else looks good.
$endgroup$
– Reinderien
Apr 1 at 14:05
1
1
$begingroup$
@SV-97 Thank you for writing such a detailed response. Really helpful. I didn't know about PEP8, was a nice read.
$endgroup$
– mikkelræv
Apr 1 at 14:25
$begingroup$
@SV-97 Thank you for writing such a detailed response. Really helpful. I didn't know about PEP8, was a nice read.
$endgroup$
– mikkelræv
Apr 1 at 14:25
1
1
$begingroup$
No problem - I generally enjoy code reviews and profit from them too :D I've just added my version of your code if you want to have a look though I'd of course encourage you to try implementing some of the mentioned things yourself beforehand.
$endgroup$
– SV-97
Apr 1 at 14:42
$begingroup$
No problem - I generally enjoy code reviews and profit from them too :D I've just added my version of your code if you want to have a look though I'd of course encourage you to try implementing some of the mentioned things yourself beforehand.
$endgroup$
– SV-97
Apr 1 at 14:42
|
show 1 more comment
mikkelræv is a new contributor. Be nice, and check out our Code of Conduct.
mikkelræv is a new contributor. Be nice, and check out our Code of Conduct.
mikkelræv is a new contributor. Be nice, and check out our Code of Conduct.
mikkelræv is a new contributor. Be nice, and check out our Code of Conduct.
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f216654%2fsmall-terminal-tic-tac-toe-game%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown