← back to home

projects

goldfinger 2025

a chess engine written in go that peaked at ~2000 lichess elo.

a chess engine needs chess. chess needs a board. my first approach was arrays, but i eventually found out about bitboards: twelve 64 bit integers that each represent a unique piece. 6 piece types * 2 colors = 12 integers. each bit is a square in the 8x8 board and flipping it adds and removes a piece at that square. the move generation for sliding pieces like bishops and rooks used magic bitboards, which means that all their moves are precomputed using bitmasks.

goldfinger uses PeSTO's eval, which scores each piece based on its position using piece-square tables. there are two tables for each piece (midgame + endgame) that get tapered as the game progresses. this is simple, but effective.

playing against itself with 100ms per move & no opening book

the search algorithm i used was negamax with alpha-beta pruning with iterative deepening and aspiration windows. each iteration searches a narrow score window and widens it on failure. earlier iterations will improve move ordering for deeper ones. i also used principal variation search which uses a full search window for the first move at every point. the remaining moves are searched with a null window and pruned if they don't improve alpha.

move ordering heavily affects how fast alpha-beta prunes, since a good move ordering can reduce the branching factor. goldfinger does move ordering with the mvv-lva, killer, and history heuristics. search results are cached inside a transposition table, where the board's state is saved with zobrist hashing. my late move reductions use a log-scaled formula based on depth and move index to reduce search depth for less promising moves. finally quiescence search is used for the leaf nodes and will continue searching captures and promotions until the position is quiet.

rustic 2025

a graphics engine written in rust with shading, textures, and a custom scripting language.

rustic is driven by mdl, a scripting language created by mr. dw which i implemented a handmade interpreter for. the lexer tokenizes the input with regex, the parser builds a command list from the token stream, and the evaluator runs those commands against a scene context.

example mdl code
sneak peek at a spinning james bond ~ scroll down!

rendering lines is the foundation of any graphics engine. rustic draws them using bresenham's line algorithm, then uses them to fill in triangles with scan-line rendering. triangles form the basis of every 3d object that's rendered. even spheres and tori can be made with triangles; more triangles make rounder surface. back-face culling and a z-buffer prevent drawing unseen surfaces. rustic can shade these triangles using flat shading, gouraud shading, or phong shading, which is controlled by changing the lighting constants.

different shading models
shading.mdl: wireframe, flat, gouraud, and phong shading

objects are moved, scaled, and rotated using transformation matrices on a stack controlled by push and pop operations. these transformations can be animated using a knob system. knobs hold values that change with time and act as multipliers for the transformations. the animation system also supports keyframe interpolation, easing, and gif exports.

rustic also supports parsing .obj and .stl mesh files allowing arbitrary 3d models to be rendered. support for .mtl files also allows for textured surfaces using uv texture mapping.

bond.mdl: dapper james bond minifigure

mypulse 2025

attendance dashboard for stuypulse made with astro + supabase with 200+ registered users.

mypulse was my first full-stack product that people actually used. it was a solution to a simple problem. that year, one of our mentors made a kiosk in the lab that you would scan in and out using your student id card. it would read your 9 digit id and save it in a database locally. the only way to get that data was through the mentor himself, and people were curious about their stats.

i knew i needed a database endpoint so i used supabase because it was free and i had used it in the past for another club in stuy. i also wanted something that could call the apis server side but next seemed overkill. i ended up picking astro because it was lightweight and simple while still providing that server side functionality.

user dashboard
user dashboard for alex wang

supabase was also helpful for the logins, but it doesn't natively support usernames. to work around this, i stored the users with a dummy email like "[email protected]." while a little silly, it worked for my purposes without needing users to provide valid emails.

finally, the data itself must be moved from the kiosk to the supabase. the way i did this was by setting up an endpoint on mypulse that listens for POST requests. when it receives a request with a special key (albeit plaintext), it will know that the kiosk is sending it. every hour, the kiosk is set up to send a request with three files: a meetings report, an attendance report, and a checkins report. mypulse's endpoint will parse all those files and sync everything to the supabase. the hourly POST setup was built in collaboration with the mentor behind the kiosk, who i worked with to configure the pipeline on his end. now that the data is online, it can also be pulled into google sheets automatically using google's app scripts feature.