so_long — building a tiny maze, getting stuck, and getting through

TL;DR

I built a tiny 2D maze game in C using MiniLibX. You “clear” every C (Stormtrooper) by touching it, then reach E (R2-D2) to win—while an enemy chases you. The full source is here: koi-ama/so_long.

What the game looks like

Game clear screen
Made it to R2-D2 after clearing the board.

Game over screen
…and this is what happened the first few tries.

Two short clips (why I tweaked the map)

First try (too difficult)
Too difficult map demo
Second try (friendlier layout, finally clear)
Friendlier map demo

I initially built a map that looked clever in my head and felt miserable under my fingers. After a few “boom” moments, I simplified the corridors and spacing. Practicing on a friendlier layout helped me learn the feel of movement and timing—then I could come back to harder maps with less panic.

The rules (my flavor)

Under the hood it’s standard so_long, just with my playful theme. (Icons are my custom XPMs for personal learning use.)

A tiny slice of code

The enemy is greedy: each step it picks the direction that reduces the Manhattan distance to the player. I also added a tiny throttle so it doesn’t move every time you do, which buys you a beat to route around it.

// Trimmed for the article; see repo for full version.
void enemy_controller(t_game *g) {
  static const int dx[] = {0, 0, 1, -1};
  static const int dy[] = {1, -1, 0, 0};

  // cheap throttle: skip sometimes so the chase has rhythm
  if ((g->moving * g->player_x) % 5 == 0) return;

  int best = 0, bestDist = INT_MAX;
  for (int d = 0; d < 4; d++) {
    int ny = (g->enemy_y + dy[d] + g->map_height) % g->map_height;
    int nx = (g->enemy_x + dx[d] + g->map_width)  % g->map_width;
    int dist = abs(ny - g->player_y) + abs(nx - g->player_x);
    if (dist < bestDist) { bestDist = dist; best = d; }
  }
  g->enemy_y = (g->enemy_y + dy[best] + g->map_height) % g->map_height;
  g->enemy_x = (g->enemy_x + dx[best] + g->map_width)  % g->map_width;
}

That % wraparound creates fun edge teleports on some layouts—one more little thing to plan around.

Pixel art & animation: small loops, big feel

I drew six XPMs (player/enemy/wall/floor/item/exit). Each sprite sheet is 32×32 tiles; the player and enemy have 4 frames. I blit a 32-pixel window across the sheet as the frame counter advances, and skip a sentinel color (e.g., 0xFF000000) when writing to the frame buffer so sprites blend over the floor.

Short version: tiny frames + consistent timing = surprisingly lively motion, even with four frames.

A peek at the assets

R2-D2 exit sprite sheet (XPM)
Exit (R2-D2) XPM
Stormtrooper/Enemy concept pixels
Stormtrooper / chaser
Player cat / BB-8 study pixels
Player studies & tiles

My build setup

Inside a Linux Dev Container so compilers and X11 deps are consistent:

Linux Dev Container

Run it like this:

# Clone and build MLX + libft + game
git clone https://github.com/koi-ama/so_long
cd so_long
make mlx
make

# Play one of the maps
./so_long ./map.ber

What I’d like to try next

Repo & credits