patternpythonMinor
Game of Quarto in Python
Viewed 0 times
quartogamepython
Problem
Does anyone have suggestions for how to make this code for playing a game of Quarto cleaner and more robust (beyond input error checking, which hasn't been fully fleshed out yet)?
```
# Enums for quarto.
DRAW = "D"
WIN = "W"
UNDECIDED = "U"
LOSE = "L"
TIE = "T"
class Piece():
"""
This is the piece class.
"""
attributes = None
full_name = ""
abbreviation = ""
def __init__(self, attributes):
"""
Constructor for our piece class with support for
the various pieces in the game of Quarto.
"""
self.attributes = attributes
if attributes & 0b0001:
self.full_name += "Tall"
self.abbreviation += "T"
else:
self.full_name += "Short"
self.abbreviation += "S"
if attributes & 0b0010:
self.full_name += " black"
self.abbreviation += "B"
else:
self.full_name += " white"
self.abbreviation += "W"
if attributes & 0b0100:
self.full_name += " circle"
self.abbreviation += "C"
else:
self.full_name += " square"
self.abbreviation += "Q"
if attributes & 0b1000:
self.full_name += " solid-top"
self.abbreviation += "D"
else:
self.full_name += " hollow-top"
self.abbreviation += "H"
def get_attributes(self):
"""
Returns a list of attributes.
"""
return self.attributes
def get_piece_name(self):
"""
Returns the name of the piece.
"""
return self.full_name
def get_piece_abbr(self):
"""
Returns the abbreviation of the piece.
"""
return self.abbreviation
class Board():
"""
This is the board class.
"""
pieces = []
cols_count = 4
rows_count = 4
board = None
def __init__(self):
"""
Constructor for our board class.
Ap
```
# Enums for quarto.
DRAW = "D"
WIN = "W"
UNDECIDED = "U"
LOSE = "L"
TIE = "T"
class Piece():
"""
This is the piece class.
"""
attributes = None
full_name = ""
abbreviation = ""
def __init__(self, attributes):
"""
Constructor for our piece class with support for
the various pieces in the game of Quarto.
"""
self.attributes = attributes
if attributes & 0b0001:
self.full_name += "Tall"
self.abbreviation += "T"
else:
self.full_name += "Short"
self.abbreviation += "S"
if attributes & 0b0010:
self.full_name += " black"
self.abbreviation += "B"
else:
self.full_name += " white"
self.abbreviation += "W"
if attributes & 0b0100:
self.full_name += " circle"
self.abbreviation += "C"
else:
self.full_name += " square"
self.abbreviation += "Q"
if attributes & 0b1000:
self.full_name += " solid-top"
self.abbreviation += "D"
else:
self.full_name += " hollow-top"
self.abbreviation += "H"
def get_attributes(self):
"""
Returns a list of attributes.
"""
return self.attributes
def get_piece_name(self):
"""
Returns the name of the piece.
"""
return self.full_name
def get_piece_abbr(self):
"""
Returns the abbreviation of the piece.
"""
return self.abbreviation
class Board():
"""
This is the board class.
"""
pieces = []
cols_count = 4
rows_count = 4
board = None
def __init__(self):
"""
Constructor for our board class.
Ap
Solution
You do not need getters, remove all of them
You can just access an attribute of a class directly:
When you want to verify that "at least one" condition is True,
One example:
Becomes:
Much shorter and more abstract.
Repetition
Some logic is shared between
Columns
The columns can be obtained with
Repetition
You can use a loop to make it clear that only the number changes and to avoid code bloat. Even better would be to generate this numbers programmatically to avoid the human error of forgetting/getting wrong one of them.
Confusing / weird aliases
These functions are pretty much just aliases of other functions, and in my opinion they only produce code bloat (a lot of lines of code represent no logic at all, just other names for already stated logic).
Even more confusing is that you throw away the return value of
Just remove these and use the originals.
Good: separation of (input and output) from logic
This is the best feature of your code. Separating the user interaction from the logic makes everything simpler and neater.
You can just access an attribute of a class directly:
class.attribite_name. Using @property allows adding operations before retrieving the value. (See link above for more information).anyWhen you want to verify that "at least one" condition is True,
any is the best way to do it.One example:
for lst in attr_list:
if self.shared_attributes(lst):
return True
return FalseBecomes:
return any(self.shared_attributes(lst) for lst in attr_list)Much shorter and more abstract.
Repetition
Some logic is shared between
check_win_horizontal and check_win_vertical . I suggest factoring it out to a function to reduce repetition.Columns
The columns can be obtained with
zip(* board) so you can avoid writing the logic yourself.Repetition
self.pieces.append(Piece(0b0000))
# ...... Many more similar linesYou can use a loop to make it clear that only the number changes and to avoid code bloat. Even better would be to generate this numbers programmatically to avoid the human error of forgetting/getting wrong one of them.
Confusing / weird aliases
def gen_moves(state): return state.get_pieces_names()
def do_move(move, state): state.place_piece(move[0], move[1], move[2]); return state
def solve(state): return primitive(state)These functions are pretty much just aliases of other functions, and in my opinion they only produce code bloat (a lot of lines of code represent no logic at all, just other names for already stated logic).
Even more confusing is that you throw away the return value of
do_move when you call it, so the return statement can easily be removed so the function becomes even more similar to place_pieceJust remove these and use the originals.
Good: separation of (input and output) from logic
This is the best feature of your code. Separating the user interaction from the logic makes everything simpler and neater.
Code Snippets
for lst in attr_list:
if self.shared_attributes(lst):
return True
return Falsereturn any(self.shared_attributes(lst) for lst in attr_list)self.pieces.append(Piece(0b0000))
# ...... Many more similar linesdef gen_moves(state): return state.get_pieces_names()
def do_move(move, state): state.place_piece(move[0], move[1], move[2]); return state
def solve(state): return primitive(state)Context
StackExchange Code Review Q#146973, answer score: 4
Revisions (0)
No revisions yet.