kartoffels v0.6: Personal Roomba, Simplified API, Compression
kartoffels is a game where you're given a potato and your job is to implement a firmware for it:
 
          
          ssh kartoffels.pwy.io |
            source code
          Today I'm releasing v0.6, which spans 120 commits and brings:
- > New challenges
- > Simplified radar functions
- 
            >
            
              arm_pick()andarm_drop()
- > Em Dashes
- 
            >
            
              inspect-botcommand
- > Smooth camera movements
- > Compression
- > Plans
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)