Convert "sl" Source Code from C to Rust

Add Jumping Jack

In the last tutorial, we Add[ed] a Little Train. In this one, we'll add a Jumping Jack.

Create a new blank file, "src/jack.txt", and fill it with your drawing of Jumping Jack, like so:

"src/jack.txt"
" \ 0 /   "
"  \|/    "
"   |     "
"  / \    "
"_/   \_  "
"         "

"         "
" __0__   "
"/  |  \  "
"  / \    "
" _\ /_   "
"         "

"         "
"   o     "
" /\ /\   "
" |/ \|   "
" _\ /_   "
"         "

Then edit "src/extras.rs", the "draw_image()" function, like so:

"src/extras.rs"
...
    let image = match kind.as_str() {
        // Which image are we supposed to draw?
        "D51" => get_d51(),
        "C51" => get_image("./c51.txt"),
        "LITTLE" => get_image("./little.txt"),
	"JACK" => get_image("./jack.txt"),
        &_ => {
            // If the user enters an unknown image name (say, "racecar") ...
            println!(
                "Invalid kind. You entered '{}'; the default was used instead.",
                kind
            );
            get_d51()
        }
...

Give it a try! You might find it's best at "slow" speed - cargo run -- --kind jack --speed s.

And if you'd like to make Jack jump even more smoothly, you can duplicate the second frame as the fourth frame, to increase the "resolution" of the artwork.

"src/jack.txt"
" \ 0 /   "
"  \|/    "
"   |     "
"  / \    "
"_/   \_  "
"         "

"         "
" __0__   "
"/  |  \  "
"  / \    "
" _\ /_   "
"         "

"         "
"   o     "
" /\ /\   "
" |/ \|   "
" _\ /_   "
"         "

"         "
" __0__   "
"/  |  \  "
"  / \    "
" _\ /_   "
"         "

Clean Up Code

You may have noticed by now that we are no longer needing "src/c51.rs", so we might as well delete that file, and the "mod c51;" and "use c51::*;" references in "src/main.rs", and the "use crate::c51::*;" reference in "src/extras.rs".

We also no longer need the "use d51::*" line in "main.rs", but we do need to keep the "mod d51;" line in that same file, in order to keep the d51 module known to the project/crate, because we need to access it in "extras.rs", via the "use crate::d51::*;" line therein.

Clean Up Code
$ rm src/c51.rs
main.rs
/* main.rs */

mod c51;
mod d51;
mod extras;

use c51::*;
use d51::*;
use extras::*;
...
extras.rs
/* extras.rs */

use crate::c51::*;
use crate::d51::*;
use ncurses::*;
use std::{thread, time::Duration};
...

A Problem...

I notice there seems to be a jerkiness to the animation of the image across the screen, no matter which image we use. But we'll look into that later.

For now, there's a problem with the way we have done things. In order for the program to work, the "get_image()" function must be able to find the "[image].txt" files. This means that the text files must both ship with the main program, and be findable by the main program. For example, say that the main program ("sl") and the various text files are installed into "/usr/local/bin"; if you're in your home directory, and run "/usr/local/bin", the way the program is currently written, the main program will look for the text files in "~/src", and won't find them. Whereas we can re-code around that, we're still going to have to ship the separate .txt files with the main program.

I think it might be better to use the method we used with the "D51" train, and hard-code the image into the main program, or one of its modules, rather than reading the image from a separate text file, as awesome as that capability is.

So let's now focus on refactoring our code to Include the Images Within the Main Program, instead of in separate text files.