kartoffels v0.6 released!
kartoffels is a game where you're given a potato and your job is to implement a firmware for it:
Today I'm releasing v0.6, which spans 120 commits and brings:
New challenges
kartoffels strives to be both a multiplayer and a singleplayer game - to achieve that, the game provides challenges where you're tasked with implementing a robot that solves a specific problem, kinda like Advent of Code or Project Euler.
This version brings two new challenges, diamond-heist
and
personal-roomba
:
I think personal-roomba
is my favorite challenge so far -
you're thrown into a randomly generated maze (with cycles!) and your
job is to implement a robot that scans the territory and collects all
four flags located at the maze's corners:
It's a perfect opportunity to play with Dijkstra, CPU and memory optimizations, and what have you.
Simplified radar functions
Radar allows for a robot to scan its surrounding area, making it a
critical component to get right for robot to work. In the previous
version the
radar_scan_*
functions returned a 2d array containing the
entire scan:
pub fn radar_scan_3x3() -> [[char; 3]; 3];
This design proved a bit awkward to use due to its untypical indexing:
let scan = radar_scan_3x3(); // e.g.: // scan = [ // ['.', '.', '.'], // ['.', '@', '.'], // ['.', '.', '.'], // ] // // ... which gives us: // // scan[1][1] -> center of the scan (i.e. the robot iself) // scan[0][1] -> tile in front of the robot // scan[2][1] -> tile behind the robot // scan[1][0] -> tile to the left of the robot // scan[1][2] -> tile to the right of the robot
... and so the radar_scan_*
functions were redesigned to
return a struct with a convenient accessor:
let scan = radar_scan_3x3(); // scan.at(0, 0) -> center of the scan (i.e. the robot iself) // scan.at(0, -1) -> tile in front of the robot // scan.at(0, 1) -> tile behind the robot // scan.at(-1, 0) -> tile to the left of the robot // scan.at(1, 0) -> tile to the right of the robot
Seizing the day, the radar got extra data - you can now use it to check which specific robot is at given location:
if let Some(bot_id) = scan.bot_at(0, -1) { if !friends.contains(&bot_id) { arm_stab(); } }
arm_pick()
and arm_drop()
Robots can now pick objects from the ground and drop them.
Currently this comes handy only for the two new challenges, since objects are not spawned in the multiplayer mode (and robots can't create objects out of thin air themselves).
I'm thinking of using this feature to introduce a new game mode, capture the flag.
Em Dashes
A friend said it's illegal to use -
when I really mean
—
- I've read a bit about it, got anxious, drank coffee,
got more anxious, and went through all of the texts to
s/-/—
where applicable:
I'm still a bit on the fence on this, mostly because writing
—
is kinda annoying, but I see the merit.
inspect-bot
command
You can now inspect the history of each bot:
Currently the times are always displayed in UTC+0 and you can't search through the history, but it still comes handy e.g. to see why your bot is dead (it might've gotten killed, the firmware might've crashed etc.).
Smooth camera movements
Camera now interpolates between current and target position, making for a smoother experience:
Compression
As it turns out, a text interface can generate a lot of data!
This issue stems mostly from ANSI escape codes, used by kartoffels (and so indirectly via Ratatui) to render colorful text, change background colors etc.
For instance, if you'd like for the terminal to print something using
an arbitrary RGB color of, say, rgb(123, 250, 33)
, you'd
have to send \x1b[38;2;123;250;33m
- that's 18 bytes just
to change the color!
(\x1b
is a single byte with hex code 0x1b
-
it's a special "character" that informs the terminal that the
following bytes encode an instruction such as
pls change foreground color
)
For instance, when the camera is moving, a 125x60 x 30 FPS session generates about 0.8 MB/s of traffic. It's nothing for an application running locally, but sending 0.8 MB/s over the internet for each session would quickly add up on my Hetzner VPS.
To remedy the issue, the backend - both for SSH and WebSockets
connections - now compresses the frames using the
flate2
crate before sending them out. The CPU impact is
minimal, while the network traffic is greatly reduced.
Plans
For the next release, I'm planning to continue implementing more challenges - I've also got !36 on my list, gotta give more love to the multiplayer mode.
If you have any ideas yourself, I'd love to hear them!
The v0.7 release will most likely happen some time next year, since I've gotta focus on a couple of other things that have piled up that are important to me as well.
Anyway, come and play! (or
ssh kartoffels.pwy.io
)