we have nice looing gui now
BIN
res/black-bishop.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
res/black-king.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
res/black-knight.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
res/black-pawn.png
Normal file
After Width: | Height: | Size: 734 B |
BIN
res/black-queen.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
res/black-rook.png
Normal file
After Width: | Height: | Size: 1014 B |
BIN
res/trimmed.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
res/white-bishop.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
res/white-king.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
res/white-knight.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
res/white-pawn.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
res/white-queen.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
res/white-rook.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
@ -1,8 +1,17 @@
|
||||
import tkinter as tk
|
||||
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
|
||||
|
||||
@ -21,26 +30,55 @@ class GUI(View):
|
||||
|
||||
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)
|
||||
size = int(self.tile_size * .85)
|
||||
# img = img.resize((size, size))
|
||||
|
||||
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 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, selected_piece = None, legal_moves = []):
|
||||
colours = ["#F0D9B5", "#B58863"] # Light and dark squares
|
||||
|
||||
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]
|
||||
if selected_piece is not None:
|
||||
possible_positions = [move.pos for move in legal_moves]
|
||||
if Position(x, 7-y) in possible_positions:
|
||||
colour = "#ADD8E6" # Highlight legal moves
|
||||
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,
|
||||
@ -51,16 +89,29 @@ class GUI(View):
|
||||
outline=colour,
|
||||
)
|
||||
|
||||
if selected_piece is not None:
|
||||
possible_positions = [move.pos for move in legal_moves]
|
||||
if pos in possible_positions:
|
||||
radius = .15 * self.tile_size
|
||||
colour = circle_colours[(x + y) % 2]
|
||||
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:
|
||||
text_colour = "white" if piece.colour == Colour.WHITE else "black"
|
||||
self.canvas.create_text(
|
||||
self.canvas.create_image(
|
||||
(x + 0.5) * self.tile_size,
|
||||
(y + 0.5) * self.tile_size,
|
||||
text=piece.__class__.__name__[0],
|
||||
fill=text_colour,
|
||||
font=("Arial", 32, "bold")
|
||||
(y + 0.9) * self.tile_size,
|
||||
image=self._piece_images[type(piece)][piece.colour],
|
||||
anchor=tk.S,
|
||||
)
|
||||
|
||||
# Cell annotations
|
||||
@ -68,19 +119,19 @@ class GUI(View):
|
||||
|
||||
if x == 0: # numbers in the top left of the first column
|
||||
self.canvas.create_text(
|
||||
(x + 0.15) * self.tile_size,
|
||||
(y + 0.15) * self.tile_size,
|
||||
(x + .15) * self.tile_size,
|
||||
(y + .15) * self.tile_size,
|
||||
text=8-y,
|
||||
fill=text_colour,
|
||||
font=("Arial", 10, "bold")
|
||||
font=("Arial", 12, "bold")
|
||||
)
|
||||
if y == 7: # numbers in the top left of the first column
|
||||
self.canvas.create_text(
|
||||
(x + 0.85) * self.tile_size,
|
||||
(y + 0.85) * self.tile_size,
|
||||
(x + .85) * self.tile_size,
|
||||
(y + .85) * self.tile_size,
|
||||
text="abcdefgh"[x],
|
||||
fill=text_colour,
|
||||
font=("Arial", 10, "bold")
|
||||
font=("Arial", 12, "bold")
|
||||
)
|
||||
|
||||
def show(self) -> None:
|
||||
|