Compare commits

..

No commits in common. "e95caa00154a105d8a2706a3453228e26951c8e1" and "06f78487d9140ba2a83db233c6f4e269cab6260c" have entirely different histories.

8 changed files with 31 additions and 125 deletions

View File

@ -4,12 +4,14 @@ from logic.pieces.knight import Knight
from logic.pieces.queen import Queen from logic.pieces.queen import Queen
from logic.pieces.rook import Rook from logic.pieces.rook import Rook
from logic.pieces.pawn import Pawn from logic.pieces.pawn import Pawn
from logic.pieces.piece import Colour, Piece from logic.pieces.piece import Piece
from logic.position import Position from logic.position import Position
from typing import Type from typing import Type
class Board: class Board:
KING_SIDE_CASTLE = "king side castle"
QUEEN_SIDE_CASTLE = "queen side castle"
def __init__(self) -> None: def __init__(self) -> None:
self._white: dict[Position, Piece] = {} self._white: dict[Position, Piece] = {}
self._black: dict[Position, Piece] = {} self._black: dict[Position, Piece] = {}
@ -39,7 +41,6 @@ class Board:
@staticmethod @staticmethod
def setup_FEN_position(position: str) -> "Board": def setup_FEN_position(position: str) -> "Board":
ret = Board() ret = Board()
index = 0
# -- Pieces # -- Pieces
pieces = "prnbqk" # possible pieces pieces = "prnbqk" # possible pieces
@ -48,16 +49,15 @@ class Board:
x = 0 x = 0
y = 7 # FEN starts from the top left, so 8th rank y = 7 # FEN starts from the top left, so 8th rank
for c in position: for c in position:
index += 1
if c == " ": if c == " ":
break break
if c in pieces or c in pieces.upper(): if c in pieces or c in pieces.upper():
pos = Position(x, y) pos = Position(x, y)
piece = Board._piece_class_from_char(c) piece = Board._piece_class_from_char(c)
if c.isupper(): if c.isupper():
ret._white[pos] = piece(pos, Colour.WHITE) ret._white[pos] = piece(pos, Piece.WHITE)
else: else:
ret._black[pos] = piece(pos, Colour.BLACK) ret._black[pos] = piece(pos, Piece.BLACK)
x += 1 x += 1
continue continue
@ -69,18 +69,18 @@ class Board:
# -- Active colour # -- Active colour
index = position.find(" ") # find the first space
index += 1
if position[index] == "w": if position[index] == "w":
ret._turn = Colour.WHITE ret._turn = Piece.WHITE
elif position[index] == "b": elif position[index] == "b":
ret._turn = Colour.BLACK ret._turn = Piece.BLACK
else: else:
raise ValueError(f"The FEN position is malformed, the active colour should be either 'w' or 'b', but is '{position[index]}'") raise ValueError(f"The FEN position is malformed, the active colour should be either 'w' or 'b', but is '{position[index]}'")
index += 1
# -- Castling Rights # -- Castling Rights
for c in position[index:]: for c in position:
index += 1
if c == "-" or c == " ": if c == "-" or c == " ":
break break
@ -96,6 +96,7 @@ class Board:
ret._black_castling_write.add(Board.QUEEN_SIDE_CASTLE) ret._black_castling_write.add(Board.QUEEN_SIDE_CASTLE)
# -- En passant target # -- En passant target
index = position.find(" ", index + 1)
if position[index] != "-": if position[index] != "-":
ret._en_passant_target = position[index:index+2] ret._en_passant_target = position[index:index+2]

View File

@ -1,25 +0,0 @@
from logic.pieces.piece import Piece
from logic.position import Position
from enum import Enum
class Move:
def __init__(self, is_capturing: bool) -> None:
self.is_capturing = is_capturing
def to_algebraic(self) -> str:
raise NotImplementedError("The move can't be translated to algbraic notation, as it was not implemented")
@staticmethod
def from_algebraic(move: str) -> "Move":
raise NotImplementedError("The move can't be translated from algbraic notation, as it was not implemented")
class PieceMove(Move):
def __init__(self, piece: Piece, pos: Position,/, is_capturing: bool = False) -> None:
super().__init__(is_capturing)
self.piece = piece
self.pos = pos
class Castle(Move, Enum):
KING_SIDE_CASTLE = False
QUEEN_SIDE_CASTLE = False

View File

@ -1,52 +1,4 @@
from logic.move import Move, PieceMove
from logic.position import Position
from .piece import Piece from .piece import Piece
class Bishop(Piece): class Bishop(Piece):
def _move_for_position(self, board: "Board", x: int, y: int) -> Move | None: pass
if not Position.is_within_bounds(x, y):
return None
piece = board.piece_at(x, y)
if piece is None:
return PieceMove(self, Position(x, y))
if piece.colour != self.colour:
return PieceMove(self, Position(x, y), is_capturing=True)
return None
def _look_direction(self, board: "Board", mult_dx: int, mult_dy: int):
ret = []
for d in range(1, 8):
dx = mult_dx * d
dy = mult_dy * d
move = self._move_for_position(board, self.pos.x + dx, self.pos.y + dy)
if move is None:
break
ret.append(move)
if move.is_capturing:
break
return ret
def legal_moves(self, board: "Board") -> list[Move]:
ret = []
# looking north east
ret.extend(self._look_direction(board, 1, 1))
# looking south east
ret.extend(self._look_direction(board, 1, -1))
# looking south west
ret.extend(self._look_direction(board, -1, -1))
# looking north west
ret.extend(self._look_direction(board, -1, 1))
return ret

View File

@ -1,9 +1,8 @@
from logic.move import Move, PieceMove
from logic.pieces.piece import Piece
from logic.position import Position from logic.position import Position
from logic.pieces.piece import Piece
class Pawn(Piece): class Pawn(Piece):
def legal_moves(self, board) -> list[Move]: def legal_moves(self, board) -> list[Position]:
ret = [] ret = []
# can we capture to the left? # can we capture to the left?
@ -13,7 +12,7 @@ class Pawn(Piece):
(self.colour == self.BLACK and (capturable_piece := board.piece_at(self.pos.x - 1, self.pos.y - 1))) (self.colour == self.BLACK and (capturable_piece := board.piece_at(self.pos.x - 1, self.pos.y - 1)))
): ):
if capturable_piece.colour != self.colour: if capturable_piece.colour != self.colour:
ret.append(PieceMove(self, capturable_piece.pos, is_capturing = True)) ret.append(capturable_piece.pos)
# can we capture to the right? # can we capture to the right?
if self.pos.x < 7 and ( if self.pos.x < 7 and (
@ -22,21 +21,11 @@ class Pawn(Piece):
(self.colour == self.BLACK and (capturable_piece := board.piece_at(self.pos.x + 1, self.pos.y - 1))) (self.colour == self.BLACK and (capturable_piece := board.piece_at(self.pos.x + 1, self.pos.y - 1)))
): ):
if capturable_piece.colour != self.colour: if capturable_piece.colour != self.colour:
ret.append(PieceMove(self, capturable_piece.pos, is_capturing = True)) ret.append(capturable_piece.pos)
if self.colour == Piece.WHITE:
for dy in range(1, 3 if self.pos.y == 1 else 2): for dy in range(1, 3 if self.pos.y == 1 else 2):
if self.pos.y + dy > 7 or board.piece_at(self.pos.x, self.pos.y + dy): if self.pos.y + dy > 7 or board.piece_at(self.pos.x, self.pos.y + dy):
break break
pos = Position(self.pos.x, self.pos.y + dy) ret.append(Position(self.pos.x, self.pos.y + dy))
ret.append(PieceMove(self, pos))
else:
for dy in range(1, 3 if self.pos.y == 6 else 2):
if self.pos.y - dy < 0 or board.piece_at(self.pos.x, self.pos.y - dy):
break
pos = Position(self.pos.x, self.pos.y - dy)
ret.append(PieceMove(self, pos))
print(ret)
return ret return ret

View File

@ -1,19 +1,17 @@
from logic.position import Position from logic.position import Position
from enum import Enum
class Colour(Enum): class Piece:
WHITE = "white" WHITE = "white"
BLACK = "black" BLACK = "black"
class Piece: def __init__(self, pos, colour) -> None:
def __init__(self, pos: Position, colour: Colour) -> None:
self.pos = pos self.pos = pos
assert colour == Colour.WHITE or colour == Colour.BLACK, "The colour of the piece must be either Piece.WHITE or Piece.BLACK" assert colour == self.WHITE or colour == self.BLACK, "The colour of the piece must be either Piece.WHITE or Piece.BLACK"
self.colour = colour self.colour = colour
def position(self) -> Position: def position(self) -> Position:
return self.pos return self.pos
def legal_moves(self, board: "Board") -> list["Move"]: def legal_moves(self, board) -> list[Position]:
raise NotImplementedError(f"Can't say what the legal moves are for {type(self).__name__}, the method hasn't been implemented yet") raise NotImplementedError(f"Can't say what the legal moves are for {type(self).__name__}, the method hasn't been implemented yet")

View File

@ -9,12 +9,6 @@ class Position:
self.x = x self.x = x
self.y = y self.y = y
@staticmethod
def is_within_bounds(x: int, y: int) -> bool:
return x >= Position._MIN_POS and x <= Position._MAX_POS \
and y >= Position._MIN_POS and y <= Position._MAX_POS
def __eq__(self, value: object, /) -> bool: def __eq__(self, value: object, /) -> bool:
if type(value) != type(self): if type(value) != type(self):
return False return False

View File

@ -1,9 +1,9 @@
from logic.board import Board from logic.board import Board, create_board
from view.gui import GUI from view.gui import GUI
from view.tui import TUI from view.tui import TUI
if __name__ == "__main__": if __name__ == "__main__":
initial_board_position = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" initial_board_position = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w"
board = Board.setup_FEN_position(initial_board_position) board = Board.setup_FEN_position(initial_board_position)
view = GUI(board) view = GUI(board)

View File

@ -1,7 +1,7 @@
import tkinter as tk import tkinter as tk
from logic.board import Board from logic.board import Board
from logic.pieces.piece import Colour, Piece from logic.pieces.piece import Piece
from logic.position import Position from logic.position import Position
from view.view import View from view.view import View
@ -30,9 +30,7 @@ class GUI(View):
for y in range(8): for y in range(8):
for x in range(8): for x in range(8):
colour = colours[(x + y) % 2] colour = colours[(x + y) % 2]
if self.state["selected_piece"]: if self.state["selected_piece"] and Position(x, 7-y) in self.state["legal_moves"]:
possible_positions = [move.pos for move in self.state["legal_moves"]]
if Position(x, 7-y) in possible_positions:
colour = "#ADD8E6" # Highlight legal moves colour = "#ADD8E6" # Highlight legal moves
self.canvas.create_rectangle( self.canvas.create_rectangle(
@ -40,14 +38,13 @@ class GUI(View):
y * self.tile_size, y * self.tile_size,
(x + 1) * self.tile_size, (x + 1) * self.tile_size,
(y + 1) * self.tile_size, (y + 1) * self.tile_size,
fill=colour, fill=colour
outline=colour,
) )
piece = self.board.piece_at(x, 7-y) piece = self.board.piece_at(x, 7-y)
if piece: if piece:
text_colour = "white" if piece.colour == Colour.WHITE else "black" text_colour = "white" if piece.colour == Piece.WHITE else "black"
self.canvas.create_text( self.canvas.create_text(
(x + 0.5) * self.tile_size, (x + 0.5) * self.tile_size,
(y + 0.5) * self.tile_size, (y + 0.5) * self.tile_size,