Jerome Palayoor

Contact
A short sequence of chess moves, including a capture and the piece slide animation

Chess

A chess game built in pygame, where every piece calculates its own legal moves and animates smoothly to its next position.

Every piece is its own class

There's no shared "chess engine" computing legal moves centrally, each piece type (Pawn, Rook, Bishop, Knight, Queen, King) is its own class that figures out its own valid moves every frame, by scanning the full list of pieces on the board.

The chess board in its starting position

Sliding pieces: Rooks, Bishops, and the Queen

Rooks move in straight lines, Bishops move diagonally, and the Queen just combines both. Each direction is checked independently by walking outward one square at a time until it hits the edge of the board or another piece.

for i in range(1,9):
    if not self.tf:
        if self.y - i == -1:
            self.t = i
            self.tf = True
            break
        for piece in pieces:
            if piece.y == self.y - i and self.x == piece.x:
                self.t = i
                if piece.c != self.c:
                    self.tcap = i
                self.tf = True
                break

This is the "top" direction check for a Rook. It counts outward until it either falls off the board (self.y - i == -1) or bumps into another piece, at which point it stops and records whether that piece was an enemy worth capturing (piece.c != self.c).

A selected Bishop showing its legal moves as yellow dots and a capturable pawn circled in yellow

The Bishop does the same thing along diagonals, and the Queen just runs both the Rook's four directions and the Bishop's four diagonals.

Fixed position pieces: Knights and the King

Knights and Kings don't need to scan outward, they only ever consider a small fixed set of offset squares.

if piece.x == self.x-1 and piece.y == self.y-2:
    self.tl = False
    if piece.c != self.c:
        self.tlcap = True

Each of the Knight's 8 possible L shaped jumps is just checked directly against the board, is that square empty, occupied by a friendly piece, or capturable. The King works almost identically, just with its 8 adjacent squares instead of L shapes.

Pawns are the odd one out

Pawns move differently depending on direction (light pieces move up the board, dark pieces move down), can move two squares only on their first move, and capture diagonally instead of forward, all special cases none of the other pieces need.

if not self.moved and not self.blocked and not self.dblocked:
    self.movable.append((self.x,self.y-1))
    self.movable.append((self.x,self.y-2))
elif not self.blocked:
    self.movable.append((self.x,self.y-1))

self.moved tracks whether this specific pawn has ever moved before, once it has, the two square opening move is disabled.

The sliding animation

Pieces don't teleport to their destination, they glide there over a fixed number of frames.

if self.moving and self.count != speed:
    self.xcoor += self.toxcoorval
    self.ycoor += self.toycoorval
    self.count += 1

When a piece moves, the code calculates a fixed per frame pixel step (toxcoorval/toycoorval) and adds it to the piece's position every frame for speed (10) frames straight, at that point it's snapped exactly onto its true destination.

A short sequence of chess moves, including a capture and the piece slide animation

What's not here

This is piece movement, not a full legal chess engine. There's no turn enforcement (either side can move any piece at any time), no check or checkmate detection, no castling, en passant, or pawn promotion. Every piece correctly computes where it's allowed to move on its own, but nothing stops you from walking your King into check.

Contact Me