moved everything related to python in the python
folder
This commit is contained in:
155
src/view/gui.py
155
src/view/gui.py
@ -1,155 +0,0 @@
|
||||
import tkinter as tk
|
||||
from tkinter import messagebox
|
||||
from typing import Type
|
||||
from PIL import ImageTk, Image
|
||||
import os
|
||||
|
||||
from logic.board import Board
|
||||
from logic.move import Move
|
||||
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 Colour, Piece
|
||||
from logic.pieces.queen import Queen
|
||||
from logic.pieces.rook import Rook
|
||||
from logic.position import Position
|
||||
from view.view import View
|
||||
|
||||
class GUI(View):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
|
||||
self.root = tk.Tk()
|
||||
self.root.title("Chess Board")
|
||||
|
||||
self.tile_size = 80
|
||||
board_size = self.tile_size * 8
|
||||
|
||||
self.canvas = tk.Canvas(self.root, width=board_size, height=board_size)
|
||||
self.canvas.pack()
|
||||
|
||||
self.canvas.bind("<Button-1>", self._on_canvas_click)
|
||||
|
||||
self._piece_images = self._load_piece_images("res/")
|
||||
|
||||
def _piece_svg(self, root: str, piece: Type[Piece], colour: Colour) -> ImageTk.PhotoImage:
|
||||
piece_name = piece.__name__.lower()
|
||||
|
||||
path = os.path.join(root, f"{"white" if colour == Colour.WHITE else "black"}-{piece_name}.png")
|
||||
img = Image.open(path)
|
||||
|
||||
if img.mode == "LA":
|
||||
img = img.convert(mode="RGBA")
|
||||
img.save(path)
|
||||
|
||||
return ImageTk.PhotoImage(img)
|
||||
|
||||
def _load_piece_images(self, root: str) -> dict[Type[Piece], dict[Colour, ImageTk.PhotoImage]]:
|
||||
ret = {}
|
||||
for piece in [Pawn, Rook, Knight, Bishop, Queen, King]:
|
||||
if piece not in ret:
|
||||
ret[piece] = {}
|
||||
ret[piece][Colour.WHITE] = self._piece_svg(root, piece, Colour.WHITE)
|
||||
ret[piece][Colour.BLACK] = self._piece_svg(root, piece, Colour.BLACK)
|
||||
|
||||
return ret
|
||||
|
||||
def _on_canvas_click(self, event):
|
||||
x, y = event.x // self.tile_size, event.y // self.tile_size
|
||||
y = 7 - y
|
||||
|
||||
self._controller.on_tile_selected(x, y)
|
||||
|
||||
def notify_checkmate(self, colour: Colour) -> None:
|
||||
messagebox.showinfo("Checkmate", f"{colour} is currently checkmated")
|
||||
|
||||
def notify_stalemate(self, colour: Colour) -> None:
|
||||
messagebox.showinfo("Stalemate", f"{colour} is currently stalemated")
|
||||
|
||||
|
||||
def update_board(self, board: Board, selected_piece: Piece, legal_moves: list[Move]) -> None:
|
||||
self.canvas.delete("all")
|
||||
self._draw_chess_board(board, selected_piece, legal_moves)
|
||||
|
||||
|
||||
def _draw_chess_board(self, board: Board, selected_piece = None, legal_moves = []):
|
||||
colours = ["#EDD6B0", "#B88762"] # Light and dark squares
|
||||
alt_colours = ["#F6EB72", "#DCC34B"] # Light and dark squares, when selected
|
||||
circle_colours = ["#CCB897", "#9E7454"] # circles to show legal moves
|
||||
|
||||
for y in range(8):
|
||||
for x in range(8):
|
||||
colour = colours[(x + y) % 2]
|
||||
pos = Position(x, 7-y)
|
||||
if selected_piece is not None and pos == selected_piece.pos:
|
||||
colour = alt_colours[(x + y) % 2]
|
||||
|
||||
self.canvas.create_rectangle(
|
||||
x * self.tile_size,
|
||||
y * self.tile_size,
|
||||
(x + 1) * self.tile_size,
|
||||
(y + 1) * self.tile_size,
|
||||
fill=colour,
|
||||
outline=colour,
|
||||
)
|
||||
|
||||
if selected_piece is not None:
|
||||
possible_positions = [move.pos for move in legal_moves]
|
||||
if pos in possible_positions:
|
||||
colour = circle_colours[(x + y) % 2]
|
||||
move = [move for move in legal_moves if move.pos == pos][0]
|
||||
if move.is_capturing:
|
||||
radius = .40 * self.tile_size
|
||||
self.canvas.create_oval(
|
||||
(x + .5) * self.tile_size - radius,
|
||||
(y + .5) * self.tile_size - radius,
|
||||
(x + .5) * self.tile_size + radius,
|
||||
(y + .5) * self.tile_size + radius,
|
||||
fill="",
|
||||
outline=colour,
|
||||
width=.075 * self.tile_size,
|
||||
)
|
||||
else:
|
||||
radius = .15 * self.tile_size
|
||||
self.canvas.create_oval(
|
||||
(x + .5) * self.tile_size - radius,
|
||||
(y + .5) * self.tile_size - radius,
|
||||
(x + .5) * self.tile_size + radius,
|
||||
(y + .5) * self.tile_size + radius,
|
||||
fill=colour,
|
||||
outline=colour,
|
||||
)
|
||||
|
||||
piece = board.piece_at(x, 7-y)
|
||||
|
||||
if piece:
|
||||
self.canvas.create_image(
|
||||
(x + 0.5) * self.tile_size,
|
||||
(y + 0.9) * self.tile_size,
|
||||
image=self._piece_images[type(piece)][piece.colour],
|
||||
anchor=tk.S,
|
||||
)
|
||||
|
||||
# Cell annotations
|
||||
text_colour = colours[(x + y + 1) % 2] # the other colour
|
||||
|
||||
if x == 0: # numbers in the top left of the first column
|
||||
self.canvas.create_text(
|
||||
(x + .15) * self.tile_size,
|
||||
(y + .15) * self.tile_size,
|
||||
text=8-y,
|
||||
fill=text_colour,
|
||||
font=("Arial", 12, "bold")
|
||||
)
|
||||
if y == 7: # numbers in the top left of the first column
|
||||
self.canvas.create_text(
|
||||
(x + .85) * self.tile_size,
|
||||
(y + .85) * self.tile_size,
|
||||
text="abcdefgh"[x],
|
||||
fill=text_colour,
|
||||
font=("Arial", 12, "bold")
|
||||
)
|
||||
|
||||
def show(self) -> None:
|
||||
self.root.mainloop()
|
@ -1,57 +0,0 @@
|
||||
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)}")
|
@ -1,24 +0,0 @@
|
||||
from logic.board import Board
|
||||
from logic.move import Move
|
||||
from logic.pieces.piece import Colour, Piece
|
||||
|
||||
|
||||
class View:
|
||||
def __init__(self) -> None:
|
||||
self._controller: "Controller" = None
|
||||
|
||||
def show(self) -> None:
|
||||
raise NotImplementedError(f"Can't show the board, the show() method of {type(self)} is not implemented")
|
||||
|
||||
def update_board(self, board: Board, selected_piece: Piece, legal_moves: list[Move]) -> None:
|
||||
raise NotImplementedError(f"Can't update the board, the update_board() method of {type(self)} is not implemented")
|
||||
|
||||
def notify_checkmate(self, colour: Colour) -> None:
|
||||
raise NotImplementedError(f"Can't notify of the checkmate, the notify_checkmate() method of {type(self)} is not implemented")
|
||||
|
||||
def notify_stalemate(self, colour: Colour) -> None:
|
||||
raise NotImplementedError(f"Can't notify of the stalemate, the notify_stalemate() method of {type(self)} is not implemented")
|
||||
|
||||
def set_controller(self, controller: "Controller") -> None:
|
||||
self._controller = controller
|
||||
|
Reference in New Issue
Block a user