Lapin, a terminal game in Rust
Denys Séguret
Posted on March 12, 2020
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.
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.
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...).
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!
Posted on March 12, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.