7 Commits

Author SHA1 Message Date
8f156616f0 pawns have their legal move list
Some checks failed
pre-release / Pre Release (push) Waiting to run
tagged-release / Tagged Release (push) Has been cancelled
2025-01-29 12:08:03 +01:00
a2ebb314eb pieces now know if they are white or black 2025-01-29 12:07:26 +01:00
2363b39484 github workflow should work now...
Some checks are pending
pre-release / Pre Release (push) Waiting to run
2025-01-29 11:57:33 +01:00
60abfc794f updated gitbuh workflow (again)
Some checks are pending
pre-release / Pre Release (push) Waiting to run
2025-01-29 11:54:36 +01:00
4b3be20749 updated github action
Some checks are pending
pre-release / Pre Release (push) Waiting to run
2025-01-29 11:52:27 +01:00
455fae8ad1 added .github for automatic releases
Some checks are pending
pre-release / Pre Release (push) Waiting to run
2025-01-29 11:49:44 +01:00
e2f6b5c8d8 basic blocks + baisc view 2025-01-28 14:45:23 +01:00
14 changed files with 262 additions and 0 deletions

View File

@ -0,0 +1,19 @@
---
name: "pre-release"
on:
push:
branches:
- "main"
jobs:
pre-release:
name: "Pre Release"
runs-on: "ubuntu-latest"
steps:
- uses: "marvinpinto/action-automatic-releases@latest"
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
prerelease: true
automatic_release_tag: "latest"

18
.github/workflows/tagged-release.yml vendored Normal file
View File

@ -0,0 +1,18 @@
---
name: "tagged-release"
on:
push:
tags:
- "v*"
jobs:
tagged-release:
name: "Tagged Release"
runs-on: "ubuntu-latest"
steps:
- uses: "marvinpinto/action-automatic-releases@latest"
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
prerelease: false

52
src/logic/board.py Normal file
View File

@ -0,0 +1,52 @@
from logic.pieces.bishop import Bishop
from logic.pieces.king import King
from logic.pieces.knight import Knight
from logic.pieces.queen import Queen
from logic.pieces.rook import Rook
from logic.pieces.pawn import Pawn
from logic.pieces.piece import Piece
from logic.position import Position
class Board:
def __init__(self) -> None:
self._white: dict[Position, Piece] = {}
self._black: dict[Position, Piece] = {}
for x in range(8):
pos_w_pawn = Position(x, 1)
pos_b_pawn = Position(x, 6)
self._white[pos_w_pawn] = Pawn(pos_w_pawn, Piece.WHITE)
self._black[pos_b_pawn] = Pawn(pos_b_pawn, Piece.BLACK)
pos_w_piece = Position(x, 0)
pos_b_piece = Position(x, 7)
piece = None
if x == 0 or x == 7:
piece = Rook
elif x == 1 or x == 6:
piece = Knight
elif x == 2 or x == 5:
piece = Bishop
elif x == 3:
piece = Queen
elif x == 4:
piece = King
assert piece != None, f"Didn't know which piece to assign for {x = }"
self._white[pos_w_piece] = piece(pos_w_piece, Piece.WHITE)
self._black[pos_b_piece] = piece(pos_b_piece, Piece.BLACK)
def piece_at(self, x: int, y: int) -> Piece | None:
pos = Position(x, y)
white_piece = self._white.get(pos, None)
black_piece = self._black.get(pos, None)
assert white_piece == None or black_piece == None, f"There are two pieces at the same position {pos}, this shouldn't happen!"
if white_piece != None:
return white_piece
return black_piece
def create_board():
return Board()

View File

@ -0,0 +1,4 @@
from .piece import Piece
class Bishop(Piece):
pass

5
src/logic/pieces/king.py Normal file
View File

@ -0,0 +1,5 @@
from .piece import Piece
class King(Piece):
pass

View File

@ -0,0 +1,5 @@
from .piece import Piece
class Knight(Piece):
pass

31
src/logic/pieces/pawn.py Normal file
View File

@ -0,0 +1,31 @@
from logic.position import Position
from logic.pieces.piece import Piece
class Pawn(Piece):
def legal_moves(self, board) -> list[Position]:
ret = []
# can we capture to the left?
if self.pos.x > 0 and (
(self.colour == self.WHITE and (capturable_piece := board.piece_at(self.pos.x - 1, self.pos.y + 1)))
or
(self.colour == self.BLACK and (capturable_piece := board.piece_at(self.pos.x - 1, self.pos.y - 1)))
):
if capturable_piece.colour != self.colour:
ret.append(capturable_piece.pos)
# can we capture to the right?
if self.pos.x < 7 and (
(self.colour == self.WHITE and (capturable_piece := board.piece_at(self.pos.x + 1, self.pos.y + 1)))
or
(self.colour == self.BLACK and (capturable_piece := board.piece_at(self.pos.x + 1, self.pos.y - 1)))
):
if capturable_piece.colour != self.colour:
ret.append(capturable_piece.pos)
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):
break
ret.append(Position(self.pos.x, self.pos.y + dy))
return ret

17
src/logic/pieces/piece.py Normal file
View File

@ -0,0 +1,17 @@
from logic.position import Position
class Piece:
WHITE = 0
BLACK = 1
def __init__(self, pos, colour) -> None:
self.pos = pos
assert colour == self.WHITE or colour == self.BLACK, "The colour of the piece must be either Piece.WHITE or Piece.BLACK"
self.colour = colour
def position(self) -> Position:
return self.pos
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")

View File

@ -0,0 +1,5 @@
from .piece import Piece
class Queen(Piece):
pass

5
src/logic/pieces/rook.py Normal file
View File

@ -0,0 +1,5 @@
from .piece import Piece
class Rook(Piece):
pass

25
src/logic/position.py Normal file
View File

@ -0,0 +1,25 @@
class Position:
_MIN_POS = 0
_MAX_POS = 7
def __init__(self, x, y) -> None:
assert x >= self._MIN_POS and x <= self._MAX_POS, f"Invalid argument: x should be between {self._MIN_POS} and {self._MAX_POS}, but is {x}"
assert y >= self._MIN_POS and y <= self._MAX_POS, f"Invalid argument: y should be between {self._MIN_POS} and {self._MAX_POS}, but is {y}"
self.x = x
self.y = y
def __eq__(self, value: object, /) -> bool:
if type(value) != type(self):
return False
return value.x == self.x and value.y == self.y
def __hash__(self) -> int:
return hash((self.x, self.y))
def __str__(self) -> str:
return f"{self.x, self.y}"
def __repr__(self) -> str:
return str(self)

9
src/main.py Normal file
View File

@ -0,0 +1,9 @@
from logic.board import create_board
from view.tui import TUI
if __name__ == "__main__":
board = create_board()
view = TUI(board)
view.show()

57
src/view/tui.py Normal file
View File

@ -0,0 +1,57 @@
from logic.board import Board
from logic.pieces.bishop import Bishop
from logic.pieces.king import King
from logic.pieces.knight import Knight
from logic.pieces.pawn import Pawn
from logic.pieces.piece import Piece
from logic.pieces.queen import Queen
from logic.pieces.rook import Rook
from view.view import View
class TUI(View):
def __init__(self, board: Board) -> None:
super().__init__(board)
def show(self) -> None:
board_view = [
[" " for _ in range(0, 8)]
for _ in range(0, 8)
]
for pos, piece in self.board._white.items():
board_view[pos.y][pos.x] = self.string_of(piece).upper()
for pos, piece in self.board._black.items():
board_view[pos.y][pos.x] = self.string_of(piece)
# we reverse the board because (0, 0) in in the bottom left, not top left
board_view.reverse()
print(self.to_string(board_view))
def to_string(self, board_view: list[list[str]]) -> str:
VER_SEP = "|"
HOR_SEP = "-"
ROW_SEP = HOR_SEP * (2*len(board_view[0]) + 1)
ret = ROW_SEP + "\n"
for row_view in board_view:
row_str = VER_SEP + VER_SEP.join(row_view) + VER_SEP
ret += row_str + "\n"
ret += ROW_SEP + "\n"
return ret
def string_of(self, piece: Piece) -> str:
type_ = type(piece)
if type_ == Pawn:
return "p"
if type_ == Queen:
return "q"
if type_ == Bishop:
return "b"
if type_ == Knight:
return "n"
if type_ == Rook:
return "r"
if type_ == King:
return "k"
raise ValueError(f"Unknown piece type {type(piece)}")

10
src/view/view.py Normal file
View File

@ -0,0 +1,10 @@
from logic.board import Board
class View:
def __init__(self, board: Board) -> None:
self.board: Board = board
def show(self) -> None:
raise NotImplementedError(f"Can't show the board, the show() method of {type(self)} is not implemented")