Files
cis163/chess/move.py
cutsweettea bbd55f48a0 gooo
2025-10-29 10:36:33 -04:00

145 lines
5.3 KiB
Python

from enum import Enum
class Move:
def __init__(self, from_row, from_col, to_row, to_col):
self.from_row = from_row
self.from_col = from_col
self.to_row = to_row
self.to_col = to_col
def __str__(self):
output = f'Move [from_row={self.from_row}, from_col={self.from_col}'
output += f', to_row={self.to_row}, to_col={self.to_col}]'
return output
# kinda just guessing, but on prarielearn it only showed the file names included in the project and the
# ones we need to create for the submission, i was gonna put all these in their own files, but now i'm
# just putting it here because i dont wanna risk not being able to submit
class PieceType:
# piece type for each piece
PAWN = 0
ROOK = 1
KING = 2
QUEEN = 3
KNIGHT = 4
BISHOP = 5
# check if something is a valid move set element ( (y, x) tuple )
def valid_move_set_element(move_set: tuple[int, int]) -> bool:
# check if move set is a tuple
if not isinstance(move_set, tuple):
raise TypeError(f'each move set in move sets must be a tuple ({move_set})')
# check if the length of the tuple is 2, because it needs to have a y and x
ms_len = len(move_set)
if ms_len != 2:
raise ValueError(f'length of move set ({move_set}) is {ms_len}, must be 2 (y and x)')
# check if each element is an int
for i in range(ms_len):
p = move_set[i]
if not isinstance(p, int):
raise TypeError(f'tuple element at index {i} ({p}) must be an int')
return True
# general move set list class for each piece type
class MoveSets:
def __init__(self, *move_sets: tuple[int, int]):
# loop over indices of move_sets, checking if each element at index i is valid, exception thrown by valid_move_set if not
for i in range(len(move_sets)):
valid_move_set_element(move_sets[i])
# set all the stuff equal
self.__move_sets = move_sets
@property
def move_sets(self):
return self.__move_sets
def is_valid_move(self, move: Move) -> bool:
# is the move valid, i dunno
raise NotImplementedError('u gotta implement me bruh')
def valid_range(max: int) -> list[int]:
return [-i if max < 0 else i for i in range(1, abs(max)+1)]
# class for static move sets
class StaticMoveSet(MoveSets):
def is_valid_move(self, move: Move) -> bool:
# get the difference between the to and from row / column
from_to_row_diff = move.to_row - move.from_row
from_to_col_diff = move.to_col - move.from_col
# iterate over each move set, checking if it follows any of the move sets passed to the method
for ms in self.move_sets:
# checks if the difference in y and x is equal to any available options
if from_to_col_diff == ms[0] and from_to_row_diff == ms[1]:
return True
return False
# in these lists, the move sets are static, so the y and x are a set of combo's of ways to move
"""
pawn move sets are mostly static, but there will be an override for the is_valid_move method,
checking to see if the pawn can move 1 up 1 left / right to take another enemy piece
these values simulate these move sets, with x being the pawn, m being a possible static move,
and p being possible moves (such as the case i explained)
##########
# x #
# pmp #
# m #
# #
# #
# m #
# pmp #
# x #
##########
"""
pawn_valid_move_sets = [(1, 0), (2, 0)]
# in these lists, the move sets are dynamic, so the y and x are a range of times they can move on the x and y
rook_valid_move_sets = [(0, 8), (8, 0), (0, -8), (-8, 0)]
# class for dynamic move sets
class DynamicMoveSet(MoveSets):
def is_valid_move(self, move: Move) -> bool:
from_to_row_diff = move.to_row - move.from_row
from_to_col_diff = move.to_col - move.from_col
# check if the to and from actually moved
if from_to_row_diff == 0 and from_to_col_diff == 0:
return False
for ms in self.move_sets:
possible_valid_row_moves, possible_valid_col_moves = [valid_range(mse) for mse in ms]
# check if move in row is possible, only if there are valid moves for row movement
if len(possible_valid_row_moves) > 0:
if from_to_row_diff not in possible_valid_row_moves:
continue
else:
# if theres no valid moves for rows, make sure theres no change in the from to row difference
if from_to_row_diff != 0:
continue
# check if move in column is possible, only if there are valid moves for column movement
if len(possible_valid_col_moves) > 0:
if from_to_col_diff not in possible_valid_col_moves:
continue
else:
# if theres no valid moves for columns, make sure theres no change in the from to column difference
if from_to_col_diff != 0:
continue
return True
return False
# create move sets
# static move sets
pawn_move_sets = StaticMoveSet(*pawn_valid_move_sets)
# dynamic move sets