-
Notifications
You must be signed in to change notification settings - Fork 1
The Defs Module
The Defs module contains all the Constants, Custom Errors and Values repeating throughout the program. It contains two python files and one directory containing three enums.
The enum directory contains three Enum
classes, for Colors, GameModes and MoveType.
Colors.py
class Color(Enum):
WHITE = 1
BLACK = -1
EMPTY = 0
GameModes.py
class GameModes(Enum):
PLAYER_VS_PLAYER = 22
PLAYER_VS_AI = 21
AI_VS_PLAYER = 12
AI_VS_AI = 11
MoveType.py
class MoveType(Enum):
NORMAL = 2
CASTLE = 3
EN_PASSANT = 4
PROMOTION = 5
NONE = -2
There are broadly two reasons for using Enum
instead of Strings
for representing these values.
-
The first one comes from PEP 435.
The properties of an enumeration are useful for defining an immutable, related set of constant values that may or may not have a semantic meaning.
-
The second reason, which is more specific for my use case, is by creating a pre-defined set of constant values, there will be a lesser chance for typos and case-sensitive comparisons.
The reason for using Integer
values for Enum
and not String
takes its roots to this answer on StackOverflow.
- String comparison: You have to compare each of the digits one by one. This is 10 comparisons, since the integers only differ by the last digit.
- Integer comparison: You can do this in one comparison, saving 9 comparisons as compared to the String comparison.
(considering a 10 character String and 10 digit Integer)
Even though the above quote is specific to C++, broadly it applies to every programming language, including Python.
The program as a whole is dependent on project-specific objects and data types, so Python is not able to detect project-specific errors. An example of this would be:
piece.set_color("Gray")
Python would never know if the above code has an error, because neither it checks for data types, not does it know that there exists no Gray color in Chess. So, this would remain unnoticed until appropriate checks are performed in error prone areas. Whenever an unknown object/data type gets passed as a parameter in a method, the checks catch that and show custom errors specific to the situation. An example of one of those checks is in the fen_to_board()
method in the GameState
class.
if ('K' not in fen_list[0]) or ('k' not in fen_list[0]):
raise ChessErrors.NoKingError(Constants.no_king_error)
If the provided FEN string does not contain either the White or the Black King, NoKingError
is raised with the appropriate message.
All the custom errors inherit from the ChessErrors
class.
class ChessErrors(Exception):
"""Base class for exceptions in this module."""
pass
The program accesses some constant values repeatedly, so instead of declaring them everytime when needed, they are declared in a Constants.py
file and are accessed wherever necessary. This also helps in customization and testing with certain specific values fairly easy, as the values have to be edited only once, and once saved, they get applied project-wide.
The Constants.py
file can also be addressed as Game Settings when you have a proper knowledge on how to change the values without disturbing the program execution.
The first line of the Constants.py
file contains the FEN string for the initial board.
initial_board = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
This FEN string is rendered to a playable board by the fen_to_board()
method in the GameState
class.
The next block of the Constants.py
file looks like this:
WIDTH = HEIGHT = 720
DIMENSION = 8
SQ_SIZE = HEIGHT // DIMENSION
MAX_FPS = 60
IMAGES = {}
PIECE_VALUES = {'K': 20000, 'Q': 900, 'R': 500, 'B': 330, 'N': 320, 'P': 100}
CHECKMATE = 100000
STALEMATE = -100000
DEPTH = 2
GAME_MODE = GameModes.AI_VS_AI
Here the WIDTH
, HEIGHT
, DIMENSION
, SQ_SIZE
(square size), MAX_FPS
(maximum frames rendered per second), IMAGES
(images for the pieces) and GAME_MODE
are defined, which can be treated as customizations for the board.