Chess Engine (HackClub Project)

A chess engine i made in pygame then transitioned to c++ that includes puzzles support and a nature theme, this project was shipping in a ysws hackclub event (stardance)

Stack: Python → C++ / Raylib Compile: WebAssembly (WASM) Status: Shipped

Playable build — click to load

UPDATE #1

Core Rules

I have created using Pygame a chess engine complete with all of the rules of chess and fully playable for local 1v1, with the following features:

  • On piece hover, piece tilts a bit
  • Piece moves to next square instead of teleporting
  • Checkmate
  • Resign and draw buttons
  • Stalemate
  • Threefold repetition
  • 50-move rule
  • En passant
  • Castling
  • Captured pieces shown on the side that captured them
  • Captured piece zone aligned to the board
  • Pawn promotion

Future Ideas

  • SFX
  • Better GUI on loss/draw screens
  • Better GUI for promotion
  • Main menu
  • Variants (atomic, duck chess, giveaway chess, Horde, etc.)
  • Time control
  • Bots (pinging the chess.com API, not sure how to code one from scratch yet)
  • Board color themes
  • Better piece graphics
  • Move log
  • Legal move dots enlarge on hover
  • Click-and-drag pieces like chess.com

UPDATE #2

First Demo

Things added this update:

  • Created an itch.io page to demo the game by compiling Pygame with pygbag
  • Added a move log with the ability to look back in time
  • Legal move dots now enlarge on hover

I plan on actually making the itch.io page look good and adding a proper README to my GitHub repo, but that's for later. Next update will likely be GUI changes, then QOL changes, then feature additions like variants.

Fully functional game though and I did work on my laptop without WakaTime, so sad it wasn't tracked :c

UPDATE #3

UI Pass

Things added this update:

  • Added a subtle background
  • Added a sidebar
  • Added "Game Log" text
  • Moved the board and bar to the right a bit
  • Added a GitHub README
  • Rounded the corners of the chess board and other elements

Issues

I started to notice the rendering of my chess pieces moving was slightly lagging. After profiling my code with Python's profile tool, I found my legal-move logic was called 160k+ times and pieces were rendered 50k+ times. This made the engine run at 30–50 FPS, so I'll need to fix performance soon. Next update will probably address these issues plus more UI changes.

UPDATE #4

Performance

I fixed performance :D here's how:

  • The move log table was being drawn 3x per frame instead of once, now it draws once
  • Checkmate was being checked every single frame, which meant checking legal moves every frame. Changed it to check on clicks, i.e. every time a move is made
  • Static background elements that never change were being redrawn every frame. Now they're rendered once at the start and cached

(I accidentally changed the opacity of the background and don't feel like retaking the screenshot, and also accidentally moved the sidebar.)

FPS - My Machine

30–40 → 200+

FPS - itch.io

10 → 45

We still have a ways to go for a fully smooth experience, but going from 10 to 45 FPS on the web demo is a huge improvement, so I thought I'd get a devlog out. Next update I'll continue optimizing and polishing to get ready to ship!

UPDATE #5

Pre-ship Bugs

Fixed Bugs

  • Checkmate didn't work (again)
  • King in check didn't light the square red
  • Move log overflowed when full so added a scroll feature

Added / Changed

  • Promotion GUI is now vertical, like chess.com
  • Move log is striped, alternating row colors
  • Board markings for rows and columns

Needed Before Shipping

  • Optimization still ~45 FPS on itch.io
  • Sound effects
  • Maybe change fonts, currently using the default ugly ones
  • Draw/resign icons instead of text
  • Click-and-drag to move pieces
  • Better sprites for pieces
  • (Bug) Can't move a different piece after selecting one
  • (Bug) Draw conditions are broken
  • (Bug) Sidebar buttons are broken, even though they don't do anything yet
  • (Bug) Looking back in the move log while in check keeps the square red

UPDATE #6

Bug Squash + WASM

Fixed Bugs

  • All game-end conditions were broken
  • Move log scrollbar didn't appear
  • Pawn promotion didn't use proper notation in the move log
  • Canceling pawn promotion didn't undo the move log entry
  • Canceling a pawn promotion capture didn't undo the capture
  • Going back in the move log during a check didn't light the square red
  • Couldn't change which piece to move after selecting one

Added / Changed

  • Promotion menu is now an inline column
  • Added sound effects
  • Better sprites for pieces
  • Draw and resign buttons now use icons
  • Move log text now uses the Audiowide font
  • Massive code restructure

Web Build

Also got the game shippable on the web this round: changed some file formats for WebAssembly and turned down the resolution so it automatically scales and stays playable. I didn't track the exact time spent on this part, but it was mostly config, not code.

Needed for Shipping

  • Optimization, didn't optimize since the last devlog
  • Maybe learn what da hail bitboards are, to optimize
  • Click-and-drag to move pieces
  • Pieces flicker for a frame when transitioning from animation to static on the board

UPDATE #7

C++ Rewrite

I'm currently in the process of converting the game from Pygame to C++ / Raylib, since I already know C++ and it's better suited for WASM. That's about it for this one.

UPDATE #8

Pixel Art Port
Not live yet bugs remain

This version isn't live yet, as there are still a few bugs to fix, the port from Python introduced a lot of them. What I liked about porting from Python to C++: I could fine-tune things more, and I like using namespaces and enums.

Changed / Added

  • Updated graphics to use pieces from itch.io
  • 50-move rule counter under the game log (planning to make it toggleable)
  • Shows whose turn it is in the top right, above the highlighting
  • Changed the entire game to pixel art after finding assets on itch.io that I thought looked really nice

Needed for Next Ship

  • Move the sidebar to the left side instead of the right
  • Add sound effects back
  • Add a background
  • Click-and-drag to move pieces
  • Animation issues
  • Repetition counter under the move log
  • Make the itch.io page look better

Next devlog should be when I update the itch.io page and other stuff. Spent closer to 15–16 hours on this one, including the previous devlog's work.

UPDATE #9

Theme + Leaves

I presented my changes in the Stardance Slack and got some new ideas, like adding a theme switcher. I added leaves to the outside of the board for the theme, and once I saw them, they looked very interactable, so I made them interactable. That's about it.

Added / Changed

  • Leaves on the outside of the board
  • Leaves enlarge on hover for fidgeting, I guess, but it's fun
  • Narrowed the move log to fit a sidebar on the left
  • Added a threefold-repetition warning after 2x repetition (planning to make it toggleable)
  • Added a background sourced from itch.io
  • Brought back hover dots enlarging on hover
  • Fixed animation issues
  • Moved board markers back inside the board, like the original Python version
  • Updated the itch.io page

Before Next Ship

  • Add sound effects back
  • Click-and-drag to move pieces
  • Add a sidebar

UPDATE #10

Settings + Puzzles

Added / Changed

  • Added a sidebar
  • Added a settings page to toggle the 50-move counter, threefold counter, and board markings, with more settings planned (high contrast, animation speed)
  • Added a Makefile to compile and test instead of running commands back to back
  • Added puzzles to the puzzle tab pulls a random puzzle out of a CSV

Before Next Ship

  • More SFX
  • Click-and-drag to move pieces
  • SFX plays infinitely on hover
  • Randomize leaf placement
  • Menu transitions
  • Polish the puzzles page and fix bugs

General Ideas

  • Theme switcher
  • Animation speed control
  • Move clock

This update I messed up my codebase massively trying to refactor, so a lot of my time went into fixing the mess I made. One of the big bugs I had to squash before this: playing sound effects would just crash the game. Turned out I hadn't added the compile flag to my Makefile, which caused the audio mixer to crash the game. After fixing that, I added SFX back in and started on puzzles I took the Lichess puzzle database of 6M puzzles and condensed it to 100k for file size. A random row is pulled from that file to create each puzzle; it's still a work in progress.

UPDATE #11

Puzzle Mode + SmartBool

Added Features

  • Puzzle side menu
  • Puzzle streak counter
  • Skip, retry, and hint puzzle buttons
  • Puzzle success-rate counter
  • Sound effect for hovering buttons
  • Puzzles are basically done

Fixed Bugs

  • Threefold triggered in puzzle mode if you made the same wrong move three times
  • Same issue with the 50-move rule in puzzle mode
  • Puzzles started with the player instead of the computer
  • Turn didn't swap correctly on a failed move
  • Animations didn't play in puzzles
  • Could select the opponent's pieces during a puzzle animation
  • A frame-perfect click right as the puzzle animation finished, then switching to the game screen, would move a piece on the game board if one occupied the starting tile
  • Same bug affecting the "next puzzle" button
  • Leaf hover SFX looped infinitely

SmartBool

I added a new datatype to make my life easier, called a smartbool a boolean with a third state, NewTrue, which is only true for the first cycle after the boolean flips to true. This is handy for playing a sound effect on hover, since a regular boolean would trigger it every frame. It still behaves like a normal boolean too you can write smartbool = true; or if (smartbool) {} but the extra state makes the code easier for me to reason about.

struct smartbool {
    enum State {
        False,
        NewTrue,
        True
    };

    State state = False;

    void operator=(bool value) {this->set(value);}
    operator bool() const {return state != False; }
    bool is_new_true() const { return state == NewTrue; }

    void set(bool value) {
        if (value) {
            if (state == False) state = NewTrue;
        } else {
            state = False;
        }
    }
    void update() {
        if (state == NewTrue) {
            state = True;
        }
    }
};

Future Ideas

  • Clock
  • Bots
  • Variants
  • More moving graphics / SFX
  • Randomize leaves on the borders
  • Menu transitions (maybe)
  • Finish polishing puzzles (pretty much done)

UPDATE #12

Variants

Added Features

  • Added variants support
  • Added giveaway chess
  • Added duck chess (kinda)
  • Started a play screen still early, not much there yet
  • Added easing functions so some visuals ease in instead of popping in

Fixed Bugs / Cleanup (~50% of this devlog)

  • Split code back into multiple files
  • Fixed puzzle code that was living directly in the frame update loop
  • Tons of crash fixes related to variants and puzzles
  • Animation broke on variants
  • Legal-move drawing didn't work on custom pieces

Future Ideas

  • Clock
  • Bots
  • Particle system effects
  • Screen shake
  • Randomize leaves
  • Menu transitions

Mostly struggled with crash bugs this devlog several of them, most notably a crash when swapping between the game and puzzle menus, and one when loading a new ruleset for variants. Plan going forward: finish the create-game screen, fix the last duck chess bugs, program a bot, then variants + polish. I may ship again before finishing all of that though.

Screenshot shows duck chess in action the duck sprite was made using AI, just to be clear about that, since I'm bad at art.

UPDATE #13

Shipped

This is the last update before shipping. I've decided to start work on a different project, so this update is just about getting the game ready to ship and calling the project complete:

  • Removed the FPS counter
  • Removed the openings and play menu
  • Removed variants from selection, not polished enough yet
  • Removed miscellaneous debug features
  • Fixed an audio bug on button hovers
  • Fixed an audio bug on puzzle win