patternpythonMinor
Console-based TicTacToe game
Viewed 0 times
tictactoeconsolegamebased
Problem
Recently I have been wanting to get better with Python, in particular with Python 3.x features and Python OOP, so I wrote what I thought at first would be pretty simple, a TicTacToe game, which turned out to become pretty complex after adding all that I wanted.
Some of the features I added, besides the basic game logic:
-
Player names and cumulative scores
-
Ability to play multiple games without restarting the program
-
Informative game messages throughout the application
Brief overview of the different sections:
-
Player Section: Basic player classes
-
Board Section: Game board with multiple methods, including a
-
Messages Section: I did not want the game logic code to get polluted with a bunch of
-
Game Section: The
The whole program if self-contained in one single file at the moment. Here is a working demo on repl.it
```
from typing import Dict
from enum import Enum
from string import Template
from random import randrange
# Note: The ttt/TTT acronym is used for TicTacToe throughout this code.
### Player Section
class PlayerNum(Enum):
one = 1
two = 2
class Token(Enum):
X = 'X'
O = 'O'
class Player:
def __init__(self, player_num: PlayerNum, token: Token, name: str):
self.player_num = player_num
self.token = token
self.name = name
self.s
Some of the features I added, besides the basic game logic:
-
Player names and cumulative scores
-
Ability to play multiple games without restarting the program
-
Informative game messages throughout the application
Brief overview of the different sections:
-
Player Section: Basic player classes
-
Board Section: Game board with multiple methods, including a
play method with certain conditions that must be met for a move/play to be valid. -
Messages Section: I did not want the game logic code to get polluted with a bunch of
print statements and such, so I made a GameMessages class to handle all these. I used Template with a good number of the messages. They are mostly very simple, aside from display_scores method which has some comparison logic to build the text.-
Game Section: The
Game class contains the bulk of the game logic. The start method is responsible for setting up the board, the players, and the logic for playing multiple games in one session while keeping cumulative score. The play_game method contains all the logic used in actually playing games, and is called in a loop within start. The whole program if self-contained in one single file at the moment. Here is a working demo on repl.it
```
from typing import Dict
from enum import Enum
from string import Template
from random import randrange
# Note: The ttt/TTT acronym is used for TicTacToe throughout this code.
### Player Section
class PlayerNum(Enum):
one = 1
two = 2
class Token(Enum):
X = 'X'
O = 'O'
class Player:
def __init__(self, player_num: PlayerNum, token: Token, name: str):
self.player_num = player_num
self.token = token
self.name = name
self.s
Solution
On the whole, I found your code very easy to read and follow. Your division of work is sensible and easy to understand. There's a couple of things I noticed whilst reading the code:
Line length
You have a few lines that go over the common target of 79 characters. Most of these are under 100 though, which seems reasonable to me, but you do have one that is over 130 characters.
GameMessages
In your
while continue_selection.upper() != 'Y' or continue_selection.upper() != 'N':
This line is checking a condition that's always going to be true (you break out of the loop before getting there). I'd consider reworking the loop so that it only contains the retry logic. Something like this:
Line length
You have a few lines that go over the common target of 79 characters. Most of these are under 100 though, which seems reasonable to me, but you do have one that is over 130 characters.
GameMessages
In your
Game class, you've got several methods that start by instantiating an instance of GameMessages. This makes me wonder if it should really be a member variable of the Game class so that it can be shared between methods.while continue_selection.upper() != 'Y' or continue_selection.upper() != 'N':
This line is checking a condition that's always going to be true (you break out of the loop before getting there). I'd consider reworking the loop so that it only contains the retry logic. Something like this:
YES_NO = {'Y','N'} # constant for acceptable selections
while continue_selection not in YES_NO:
msg.ask_to_play_again()
continue_selection = input().upper()
if continue_selection not in YES_NO:
print('Invalid selection: ', continue_selection)
if continue_selection == 'Y':
self.game_number += 1
else:
msg.final_scores(player1, player2)
continue_playing = FalseCode Snippets
YES_NO = {'Y','N'} # constant for acceptable selections
while continue_selection not in YES_NO:
msg.ask_to_play_again()
continue_selection = input().upper()
if continue_selection not in YES_NO:
print('Invalid selection: ', continue_selection)
if continue_selection == 'Y':
self.game_number += 1
else:
msg.final_scores(player1, player2)
continue_playing = FalseContext
StackExchange Code Review Q#141232, answer score: 4
Revisions (0)
No revisions yet.