DEV Community

Denys Séguret
Denys Séguret

Posted on • Updated on

Lapin, a terminal game in Rust

My kids (4yo and 6yo) are fan of the command line since the first time I showed them sl.

One month ago, my youngest one asked for a game with a rabbit and a pink knight.

In such a case, you can either postpone indefinitely or you can rush to finish it in the evenings of a few weeks so that he's still young enough to appreciate it.

So here it is, a game with a rabbit chased by foxes, wolves, and riffle armed hunters.

the game

A turn by turn game where invulnerable pink knights fight all your foes.

Rules so simple your kids will remember them after you've told them once.

help

And an editor, because the best game for a kid is to draw (more so if the inks are made of foxes and pink knights and grass and mud...).

editor

And campaigns in which you can pack sequences of levels you or your kids made.

If you're more than 6yo, you won't be impressed by the graphics.

As a developer you might find a few interesting things in this small and hopefully clear program:

  • to start with, it's in Rust and I try to keep it clean. As usual in Rust, this was a delightful coding experience, almost bug-free from start to finish. An exemple of the zero cost abstractions and the sanity it brings is the use of separate types for the position on screen and the position in the game's world, I know I usually have confusion in code dealing with several reference systems in the same unit and there was none this time.
  • a sane and safe state+transition based application architecture
  • a crossterm based terminal UI with support for mouse, resize (and support for any size starting at 20*5), etc.
  • pathfinding (Dijkstra and A*)
  • hundreds of independent actors acting according to their own goals
  • parallel computation of actor moves using rayon
  • unbounded maps
  • sub-character move animation (try the game to understand)
  • undo/redo stack
  • serialization in user chosen format using serde
  • resource (default campaign) packed in the executable
  • no excessive optimization (I considered a bitset based map and decided it wasn't worth the pain and stuck to sane and easy to read and change data structures)

And I'd welcome any help or advice to improve the program!

(or levels for my kids)

The code is almost a kid's game too:

impl ActorKind {
    pub fn eats(self, other: Self) -> bool {
        use ActorKind::*;
        match (self, other) {
            (Fox, Lapin) => true,
            (Knight, Fox) => true,
            (Knight, Hunter) => true,
            (Knight, Wolf) => true,
            (Wolf, Hunter) => true,
            (Wolf, Sheep) => true,
            (Wolf, Lapin) => true,
            _ => false,
        }
    }
}

Here's the repository: https://github.com/Canop/lapin

I'll be happy to answer your questions about the game or the code!

Discussion (2)

Collapse
rhymes profile image
rhymes

Love the idea, well done Denys!

Collapse
jeikabu profile image
jeikabu

I grew up with ASCII games. This warms my heart