HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Expandable Tic-Tac-Toe Console Game in Python

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
toeticexpandabletacgamepythonconsole

Problem

I've created a console based Tic-Tac-Toe game in python that has the ability to be expanded to a 9x9 playing field or more if you wanted to. By default it's 3x3.

Github link: https://github.com/Weffe/TicTacToe

Current Issues:

[Minor] Misalignment when printing a playing field of 4x4 or greater

Tried to keep the TicTac and Player class separated as possible so that there's no direct interaction between them. Don't know if this is a good thing or not. Also, I know some might question the use of Errors raised so I'm open to other ways of implementing things differently.

Lastly, is there a cleaner way of populating/initializing a 2D array with values related to their index?

For example,

def populate_playing_field():
    field = []
    value = (num_rows * num_cols)
    for row in range(num_rows):
        field.append([])
        for col in range(num_cols):
            field[row].insert(0, value)
            value = value - 1
    return field


Gets me this for a 3x3:

-------------
| 7 | 8 | 9 | 
-------------
| 4 | 5 | 6 | 
-------------
| 1 | 2 | 3 | 
-------------


The main reason why the values are backwards is to represent a numpad on a keyboard. This way the index value corresponds to the position on a numpad!

TicTac.py

```
class TicTac:
def __init__(self, num_rows, num_cols):
#self.playing_field = [ [7,8,9], [4,5,6], [1,2,3] ] #init the playing field to their respective nums on the numpad: 3x3

self.winner_found = False
self.is_full = False
self.possible_moves_left = num_cols * num_rows
self.num_rows = num_rows

def populate_playing_field():
field = []
value = (num_rows * num_cols)
for row in range(num_rows):
field.append([])
for col in range(num_cols):
field[row].insert(0, value)
value = value - 1
return field

self.playing_field = populate_playing_field()

Solution

My first thought is that you don't really need to split TicTac and Player into separate files. I'd at least put the two of them into one file, if not put all the code into one file as it's not an incredibly long file.

Next, you have some errant comments lingering around in the file. This is just old code that you're no longer using. If it's needed, it should be uncommented. Otherwise you can remove it. Unless it's meant to demonstrate how the actual code works.

Also, I don't see why you define populate_playing_field inside of __init__ rather than just have it a function on the class that is called within __init__. That would also allow you to call it again if you wanted to restart the game, or set up a new empty board. This would also mean storing num_cols in the object, but this is good practice anyway as it may be needed for other reasons and you currently throw it away.

print_playing_field should also adjust based on the size of the board, rather than just hard coding the sizes you have now. You could also use str.join to simplify out one of your loops:

def print_playing_field(self):
    print('-' + '----' * self.num_cols)
    for row in self.playing_field:
        print('| ' + ' | '.join(str(item) for item in row) + ' |')
        print('-' + '----' * self.num_cols)


Raising an EnvironmentError to show that the game is over is a strange practice. If you want to use exceptions to control flow, at least define your own custom one rather than confusing a user with an exception that means something else. It's very easy to define an exception, it just takes this:

class GameOver(BaseException):
    pass


Now you can just raise it, and pass a message as before.

if self.possible_moves_left == 0:
    self.is_full = True
    raise GameOver('All index posistions filled.\nGame Over. Nobody won.')

Code Snippets

def print_playing_field(self):
    print('-' + '----' * self.num_cols)
    for row in self.playing_field:
        print('| ' + ' | '.join(str(item) for item in row) + ' |')
        print('-' + '----' * self.num_cols)
class GameOver(BaseException):
    pass
if self.possible_moves_left == 0:
    self.is_full = True
    raise GameOver('All index posistions filled.\nGame Over. Nobody won.')

Context

StackExchange Code Review Q#138409, answer score: 3

Revisions (0)

No revisions yet.