Convert "sl" Source Code from C to Rust

Full Code Listing up to this point.

Consolidate the Drawing Code

In a previous lesson, we Moved the Images to Separate Files, but in the last lesson, Use "curses" to Draw the Train, we realized that having duplicate code scattered about in several files made it hard to keep changes in the code synchronized across the various files and routines. So in this lesson, we'll consolidate as much of those functions as we can into one function.

Let's start by moving the "draw_d51()" function out of the "d51.rs" file and into the "main.rs" file, renaming it as we go. We'll put it at the bottom of the file.

d51.rs
    /* d51.rs */
use ncurses::*;

pub fn draw_d51(image_vecvecstring: Vec<Vec<String>>, screen_height: i32) {
    // How tall is the image? (How many lines are in the first inner vector?)
    let height = image_vecvecstring[0].len();

    // Display each frame, one at a time.
    for each_inner_vec in image_vecvecstring {
        // Put the image at the bottom of the screen.
        let mut row = screen_height - height as i32;
        let col = 2;
        for each_line in &each_inner_vec {
            mv(row, col);
            addstr(each_line);
            row = row + 1;
        }
        getch();
    }
} // end of draw_d51()

pub const D51: &str = r"
      ====        ________                ___________'
  _D _|  |_______/        \__I_I_____===__|_________|'
   |(_)---  |   H\________/ |   |        =|___ ___|  '
   /     |  |   H  |  |     |   |         ||_| |_||  '
...
main.rs
...
} // end of convert_to_vecvecstring()

use ncurses::*;
  
pub fn draw_d51image(image_vecvecstring: Vec<Vec<String>>, screen_height: i32) {
    // How tall is the image? (How many lines are in the first inner vector?)
    let height = image_vecvecstring[0].len();

    for each_inner_vec in image_vecvecstring {
        // Put the wheels at the bottom of the screen.
        let mut row = screen_height - height as i32;
        let col = 2;
        for each_line in &each_inner_vec {
            mv(row, col);
            addstr(each_line);
            row = row + 1;
        }
        getch();
    }
} // end of draw_d51image()

And we need to modify the call:

main.rs
// Convert the appropriate constant to a vec of String vecs, and draw it.
    match kind {
        "D51" => {
            // Convert constant into a vector of String vectors.
            let image_vecvecstring = convert_to_vecvecstring(D51);
            // Send that string to be animated.
            draw_d51image(image_vecvecstring, screen_height);
        }
        "JACK" => {
            // Convert constant into a vector of String vectors.
            let image_vecvecstring = convert_to_vecvecstring(JACK);
            // Send that string to be animated.
            draw_jack(image_vecvecstring);
        }
        "COALCAR" => {
            let image_vecvecstring = convert_to_vecvecstring(COALCAR);
            draw_coalcar(image_vecvecstring);
        }
        // What is done in two steps above is combined into one here. Either method is fine.
        _ => draw_d51image(convert_to_vecvecstring(D51), screen_height), // This is the default if no match is found.
    };

The program should function as it did before, but now we should be able to get rid of the drawing code from "jack.rs" and "coalcar.rs", and just use this one function for all the images.

jack.rs
/* jack.rs */
 
pub fn draw_jack(image_vecvecstring: Vec<Vec<String>>) {
    for each_inner_vec in image_vecvecstring {
        for each_line in &each_inner_vec {
            println!("{}", each_line);
        }
    }
} // end of draw_jack()

pub const JACK: &str = r"
 \ 0 /   '
  \|/    '
...
coalcar.rs
/* coalcar.rs */
 
pub fn draw_coalcar(image_vecvecstring: Vec<Vec<String>>) {
    for each_inner_vec in image_vecvecstring {
        for each_line in &each_inner_vec {
            println!("{}", each_line);
        }
    }
} // end of draw_coalcar()

pub const COALCAR: &str = r"
    _________________         
   _|                \_____A  
...
main.rs
...
        "JACK" => {
            // Convert constant into a vector of String vectors.
            let image_vecvecstring = convert_to_vecvecstring(JACK);
            // Send that string to be animated.
            draw_jackimage(image_vecvecstring, screen_height);
        }
        "COALCAR" => {
            let image_vecvecstring = convert_to_vecvecstring(COALCAR);
            draw_coalcarimage(image_vecvecstring, screen_height);
        }
...

Now, simply by changing out the commented line here:

main.rs
...
fn main() {
    // Which image-set will we be using today?
    // let kind = "D51";
    // let kind = "JACK";
    let kind = "COALCAR";
...

... you can choose to display the D51, or Jack, or the coalcar.

But wait! There's more! We can simplify the design even further!

main.rs
fn main() {
    // Which image-set will we be using today?
    // let kind = "D51";
    // let kind = "JACK";
    let kind = "COALCAR";

    /*
       Start ncurses, initializing the screen. Turn
       off keyboard echo to the screen. Turn off
       the display of the cursor. Get the dimensions
       of the terminal window.
    */
    initscr();
    noecho();
    curs_set(CURSOR_VISIBILITY::CURSOR_INVISIBLE);
    let mut screen_height = 0;
    let mut screen_width = 0;
    getmaxyx(stdscr(), &mut screen_height, &mut screen_width);

    // Convert the appropriate constant to a vec of String vecs, and draw it.
    let mut image_vecvecstring: Vec<Vec<String>> = Vec::new();
    match kind {
        "D51" => {
            // Convert constant into a vector of String vectors.
            let image_vecvecstring = convert_to_vecvecstring(D51);
            // Send that string to be animated.
            draw_image(image_vecvecstring, screen_height);
        }
        "JACK" => {
            // Convert constant into a vector of String vectors.
            let image_vecvecstring = convert_to_vecvecstring(JACK);
            // Send that string to be animated.
            draw_image(image_vecvecstring, screen_height);
        }
        "COALCAR" => {
            let image_vecvecstring = convert_to_vecvecstring(COALCAR);
            draw_image(image_vecvecstring, screen_height);
        }
        // What is done in two steps above is combined into one here. Either method is fine.
        _ => draw_image(convert_to_vecvecstring(D51), screen_height), // This is the default if no match is found.
    };

    // Send the vec of String vecs to be animated.
    draw_image(image_vecvecstring, screen_height);
    
    // Exit ncurses and restore screen to normal.
    endwin();
} // end of main()

If we had a way to map the constant name (e.g., "D51") to the string in the variable "kind" (e.g., "D51"), we could simplify even more, reducing the entire "match" section to a single line.

We can do that with a "hashmap", which maps a "key" to a value. Let's do that.

main.rs
/* main.rs */

mod coalcar;
mod d51;
mod jack;

use coalcar::*;
use d51::*;
use jack::*;
use ncurses::*;
use std::collections::HashMap;

fn main() {
    // Which image-set will we be using today?
    let kind = "D51";
    // let kind = "JACK";
    // let kind = "COALCAR";

    let mut image_map = HashMap::new();
    image_map.insert(String::from("D51"), String::from(D51));
    image_map.insert(String::from("JACK"), String::from(JACK));
    image_map.insert(String::from("COALCAR"), String::from(COALCAR));
...
    // Convert the appropriate constant to a vec of String vecs.
    let image_vecvecstring = convert_to_vecvecstring(image_map.get(kind).unwrap());    
    let mut image_vecvecstring: Vec<Vec<String>> = Vec::new();
    match kind {
        "D51" => {
            // Convert constant into a vector of String vectors.
            image_vecvecstring = convert_to_vecvecstring(D51);
        }
        "JACK" => {
            // Convert constant into a vector of String vectors.
            let image_vecvecstring = convert_to_vecvecstring(JACK);
        }
        "COALCAR" => {
            let image_vecvecstring = convert_to_vecvecstring(COALCAR);
        }
        // What is done in two steps above is combined into one here. Either method is fine.
        _ => draw_image(convert_to_vecvecstring(D51), screen_height), // This is the default if no match is found.
    };

    // Send the vec of String vecs to be animated.
    draw_image(image_vecvecstring, screen_height);
...

We create a new hashmap named "image_map", and then insert three key/value pairs. The first key is a String that contains the literal characters of "D51"; the matching value to that key is the ASCII-art String contents of the D51 constant.

You can kind of imagine a hashmap as a spreadsheet, with two columns. The first column is the key, in this case labeled "kind", and the second column is the value, in this case labeled "Drawing". The first column has text like "D51", "PLANE", "JACK", and so forth, and the second column has the matching ASCII-art drawings for each key.

Later we access the ASCII-art of the D51 constant by "get"ting from that hashmap the value that matches the String value in our "kind" variable. When "kind" = "D51", what gets returned is the ASCII-art contents of the D51 constant.

It might make a little more sense if we separate the one-liner into two lines:

let image_vecvecstring = convert_to_vecvecstring(image_map.get(kind).unwrap());
let image_data = image_map.get(kind).unwrap();
let image_vecvecstring = convert_to_vecvecstring(image_data);

Maybe this will make it even easier to understand:

let image_data = image_map.get("D51").unwrap();
let image_vecvecstring = convert_to_vecvecstring(image_data);

We have to "unwrap" the result of the hashmap's "get()" function, because it returns a type of data called, appropriately enough, "Result". A "Result" data type is like a Federal Express package marked "OK" or "Damaged". If the box is marked OK, you open it up and take out your good product. If the package is marked "Damaged" (or "Err" in Rust-speak), you open the package to find your broken product, maybe, along with a note explaining what went wrong. The proper thing to do wth a "Result"-type of data item is to properly handle the error condition, but the quick-and-dirty (e.g., easy) solution is just to unwrap it and take what you get. That's what we're doing here. If this were a professionl program, say a NASA program to control a rocket, or a medical program to calculate medicine dosage, we'd want to handle the error properly. But we don't care that much about this program; if there's an error, like not finding one of the ASCII-art images, the worst it'll do is crash the program. No big deal.

So to reiterate, the gist of a hashmap is that you input one data item as a key, and get a different data item out as the matching value.

Now that we've consolidated our drawing routines into one function, rather than having a dedicated drawing routine per image (which is completely opposite to what we decided a few lessons ago, in Move Images/Drawing to Separate Files), it doesn't make so much sense any more to keep the ASCII-art drawings in their own files either. Let's go ahead and delete those excess files, "d51.rs", "jack.rs", and "coalcar.rs", and consolidate all those drawings into one file, named "images.rs". We'll even add a few images (note that some have closing single-quotes, some don't).

src/images.rs
/* images.rs */

pub const D51: &str = r"
      ====        ________                ___________'
  _D _|  |_______/        \__I_I_____===__|_________|'
   |(_)---  |   H\________/ |   |        =|___ ___|  '
   /     |  |   H  |  |     |   |         ||_| |_||  '
  |      |  |   H  |__--------------------| [___] |  '
  | ________|___H__/__|_____/[][]~\_______|       |  '
  |/ |   |-----------I_____I [][] []  D   |=======|__'
__/ =| o |=-~~\  /~~\  /~~\  /~~\ ____Y___________|__'
 |/-=|___|=    ||    ||    ||    |_____/~\___/       '
  \_/      \O=====O=====O=====O_/      \_/           '

      ====        ________                ___________
  _D _|  |_______/        \__I_I_____===__|_________|
   |(_)---  |   H\________/ |   |        =|___ ___|  
   /     |  |   H  |  |     |   |         ||_| |_||  
  |      |  |   H  |__--------------------| [___] |  
  | ________|___H__/__|_____/[][]~\_______|       |  
  |/ |   |-----------I_____I [][] []  D   |=======|__
__/ =| o |=-~~\  /~~\  /~~\  /~~\ ____Y___________|__
 |/-=|___|=O=====O=====O=====O   |_____/~\___/       
  \_/      \__/  \__/  \__/  \__/      \_/           

      ====        ________                ___________'
  _D _|  |_______/        \__I_I_____===__|_________|'
   |(_)---  |   H\________/ |   |        =|___ ___|  '
   /     |  |   H  |  |     |   |         ||_| |_||  '
  |      |  |   H  |__--------------------| [___] |  '
  | ________|___H__/__|_____/[][]~\_______|       |  '
  |/ |   |-----------I_____I [][] []  D   |=======|__'
__/ =| o |=-O=====O=====O=====O \ ____Y___________|__'
 |/-=|___|=    ||    ||    ||    |_____/~\___/       '
  \_/      \__/  \__/  \__/  \__/      \_/           '

      ====        ________                ___________
  _D _|  |_______/        \__I_I_____===__|_________|
   |(_)---  |   H\________/ |   |        =|___ ___|  
   /     |  |   H  |  |     |   |         ||_| |_||  
  |      |  |   H  |__--------------------| [___] |  
  | ________|___H__/__|_____/[][]~\_______|       |  
  |/ |   |-----------I_____I [][] []  D   |=======|__
__/ =| o |=-~O=====O=====O=====O\ ____Y___________|__
 |/-=|___|=    ||    ||    ||    |_____/~\___/       
  \_/      \__/  \__/  \__/  \__/      \_/           

      ====        ________                ___________'
  _D _|  |_______/        \__I_I_____===__|_________|'
   |(_)---  |   H\________/ |   |        =|___ ___|  '
   /     |  |   H  |  |     |   |         ||_| |_||  '
  |      |  |   H  |__--------------------| [___] |  '
  | ________|___H__/__|_____/[][]~\_______|       |  '
  |/ |   |-----------I_____I [][] []  D   |=======|__'
__/ =| o |=-~~\  /~~\  /~~\  /~~\ ____Y___________|__'
 |/-=|___|=   O=====O=====O=====O|_____/~\___/       '
  \_/      \__/  \__/  \__/  \__/      \_/           '

      ====        ________                ___________
  _D _|  |_______/        \__I_I_____===__|_________|
   |(_)---  |   H\________/ |   |        =|___ ___|  
   /     |  |   H  |  |     |   |         ||_| |_||  
  |      |  |   H  |__--------------------| [___] |  
  | ________|___H__/__|_____/[][]~\_______|       |  
  |/ |   |-----------I_____I [][] []  D   |=======|__
__/ =| o |=-~~\  /~~\  /~~\  /~~\ ____Y___________|__
 |/-=|___|=    ||    ||    ||    |_____/~\___/       
  \_/      \_O=====O=====O=====O/      \_/           
";

pub const LITTLE: &str = r"
     ++      +------ ____                 ____________________ '
     ||      |+-+ |  |   \@@@@@@@@@@@     |  ___ ___ ___ ___ | '
   /---------|| | |  |    \@@@@@@@@@@@@@_ |  |_| |_| |_| |_| | '
  + ========  +-+ |  |                  | |__________________| '
 _|--O========O~\-+  |__________________| |__________________| '
//// \_/      \_/       (O)       (O)        (O)        (O)    '

     ++      +------ ____                 ____________________ ' 
     ||      |+-+ |  |   \@@@@@@@@@@@     |  ___ ___ ___ ___ | '
   /---------|| | |  |    \@@@@@@@@@@@@@_ |  |_| |_| |_| |_| | '
  + ========  +-+ |  |                  | |__________________| '
 _|--/O========O\-+  |__________________| |__________________| '
//// \_/      \_/       (O)       (O)        (O)        (O)    '

     ++      +------ ____                 ____________________ '
     ||      |+-+ |  |   \@@@@@@@@@@@     |  ___ ___ ___ ___ | '
   /---------|| | |  |    \@@@@@@@@@@@@@_ |  |_| |_| |_| |_| | '
  + ========  +-+ |  |                  | |__________________| '
 _|--/~O========O-+  |__________________| |__________________| '
//// \_/      \_/       (O)       (O)        (O)        (O)    '

     ++      +------ ____                 ____________________ '
     ||      |+-+ |  |   \@@@@@@@@@@@     |  ___ ___ ___ ___ | '
   /---------|| | |  |    \@@@@@@@@@@@@@_ |  |_| |_| |_| |_| | '
  + ========  +-+ |  |                  | |__________________| '
 _|--/~\------/~\-+  |__________________| |__________________| '
//// \_O========O       (O)       (O)        (O)        (O)    '

     ++      +------ ____                 ____________________ '
     ||      |+-+ |  |   \@@@@@@@@@@@     |  ___ ___ ___ ___ | '
   /---------|| | |  |    \@@@@@@@@@@@@@_ |  |_| |_| |_| |_| | '
  + ========  +-+ |  |                  | |__________________| '
 _|--/~\------/~\-+  |__________________| |__________________| '
//// \O========O/       (O)       (O)        (O)        (O)    '

     ++      +------ ____                 ____________________ '
     ||      |+-+ |  |   \@@@@@@@@@@@     |  ___ ___ ___ ___ | '
   /---------|| | |  |    \@@@@@@@@@@@@@_ |  |_| |_| |_| |_| | '
  + ========  +-+ |  |                  | |__________________| '
 _|--/~\------/~\-+  |__________________| |__________________| '
//// O========O_/       (O)       (O)        (O)        (O)    '

"; // end of LITTLE

pub const C51: &str = r"
        ___                                            '
       _|_|_  _     __       __             ___________'
    D__/   \_(_)___|  |__H__|  |_____I_Ii_()|_________|'
     | `---'   |:: `--'  H  `--'         |  |___ ___|  '
    +|~~~~~~~~++::~~~~~~~H~~+=====+~~~~~~|~~||_| |_||  '
    ||        | ::       H  +=====+      |  |::  ...|  '
|    | _______|_::-----------------[][]-----|       |  '
| /~~ ||   |-----/~~~~\  /[I_____I][][] --|||_______|__'
------'|oOo|==[]=-     ||      ||      |  ||=======_|__'
/~\____|___|/~\_|   O=======O=======O  |__|+-/~\_|     '
\_/         \_/  \____/  \____/  \____/      \_/       '

        ___                                            '
       _|_|_  _     __       __             ___________'
    D__/   \_(_)___|  |__H__|  |_____I_Ii_()|_________|'
     | `---'   |:: `--'  H  `--'         |  |___ ___|  '
    +|~~~~~~~~++::~~~~~~~H~~+=====+~~~~~~|~~||_| |_||  '
    ||        | ::       H  +=====+      |  |::  ...|  '
|    | _______|_::-----------------[][]-----|       |  '
| /~~ ||   |-----/~~~~\  /[I_____I][][] --|||_______|__'
------'|oOo|===[]=-    ||      ||      |  ||=======_|__'
/~\____|___|/~\_|    O=======O=======O |__|+-/~\_|     '
\_/         \_/  \____/  \____/  \____/      \_/       '

        ___                                            '
       _|_|_  _     __       __             ___________'
    D__/   \_(_)___|  |__H__|  |_____I_Ii_()|_________|'
     | `---'   |:: `--'  H  `--'         |  |___ ___|  '
    +|~~~~~~~~++::~~~~~~~H~~+=====+~~~~~~|~~||_| |_||  '
    ||        | ::       H  +=====+      |  |::  ...|  '
|    | _______|_::-----------------[][]-----|       |  '
| /~~ ||   |-----/~~~~\  /[I_____I][][] --|||_______|__'
------'|oOo|===[]=- O=======O=======O  |  ||=======_|__'
/~\____|___|/~\_|      ||      ||      |__|+-/~\_|     '
\_/         \_/  \____/  \____/  \____/      \_/       '

        ___                                            '
       _|_|_  _     __       __             ___________'
    D__/   \_(_)___|  |__H__|  |_____I_Ii_()|_________|'
     | `---'   |:: `--'  H  `--'         |  |___ ___|  '
    +|~~~~~~~~++::~~~~~~~H~~+=====+~~~~~~|~~||_| |_||  '
    ||        | ::       H  +=====+      |  |::  ...|  '
|    | _______|_::-----------------[][]-----|       |  '
| /~~ ||   |-----/~~~~\  /[I_____I][][] --|||_______|__'
------'|oOo|==[]=- O=======O=======O   |  ||=======_|__'
/~\____|___|/~\_|      ||      ||      |__|+-/~\_|     '
\_/         \_/  \____/  \____/  \____/      \_/       '

        ___                                            '
       _|_|_  _     __       __             ___________'
    D__/   \_(_)___|  |__H__|  |_____I_Ii_()|_________|'
     | `---'   |:: `--'  H  `--'         |  |___ ___|  '
    +|~~~~~~~~++::~~~~~~~H~~+=====+~~~~~~|~~||_| |_||  '
    ||        | ::       H  +=====+      |  |::  ...|  '
|    | _______|_::-----------------[][]-----|       |  '
| /~~ ||   |-----/~~~~\  /[I_____I][][] --|||_______|__'
------'|oOo|=[]=- O=======O=======O    |  ||=======_|__'
/~\____|___|/~\_|      ||      ||      |__|+-/~\_|     '
\_/         \_/  \____/  \____/  \____/      \_/       '

        ___                                            '
       _|_|_  _     __       __             ___________'
    D__/   \_(_)___|  |__H__|  |_____I_Ii_()|_________|'
     | `---'   |:: `--'  H  `--'         |  |___ ___|  '
    +|~~~~~~~~++::~~~~~~~H~~+=====+~~~~~~|~~||_| |_||  '
    ||        | ::       H  +=====+      |  |::  ...|  '
|    | _______|_::-----------------[][]-----|       |  '
| /~~ ||   |-----/~~~~\  /[I_____I][][] --|||_______|__'
------'|oOo|=[]=-      ||      ||      |  ||=======_|__'
/~\____|___|/~\_|  O=======O=======O   |__|+-/~\_|     '
\_/         \_/  \____/  \____/  \____/      \_/       '
"; // end of C51

pub const BOAT: &str = r"
   |\     '
   | \    '
   |  \   '
   |___\  '
\--|----/ '
 \_____/  '
"; // end of BOAT

pub const TWINENGINE: &str = r#"
                                                                .____   __ _      
   __o__   _______ _ _  _                                     /     /             
   \    ~\                                                  /      /              
     \     '\                                         ..../      .'               
      . ' ' . ~\                                      ' /       /                 
     .  |    .  ~ \  .+~\~ ~ ' ' " " ' ' ~ - - - - - -''_      /                  
    .  <#  .  - - -/' . ' \  __                          '~ - \                   
     .. -           ~-.._ / |__|  ( )  ( )  ( )  0  o    _ _    ~ .               
   .-'                                               .- ~    '-.    -.            
  <                      . ~ ' ' .             . - ~             ~ -.__~_. _ _    
    ~- .       N121PP  .       /  . . . . ,- ~                                    
          ' ~ - - - - =.   <#>    .         \.._                                  
                      .     ~      ____ _ .. ..  .- .                             
                       .  /      '        ~ -.        ~ -.                        
                         ' . . '               ~ - .       ~-.                    
                                                     ~ - .      ~ .               
                                                            ~ -...0..~. ____      

                                                                .____   __ _      
   __o__   _______ _ _  _                                     /     /             
   \    ~\                                                  /      /              
     \     '\                                         ..../      .'               
      . ' ' . ~\                                      ' /       /                 
     .  _    .  ~ \  .+~\~ ~ ' ' " " ' ' ~ - - - - - -''_      /                  
    .  <# -.  - - -/' . ' \  __                          '~ - \                   
     .. -           ~-.._ / |__|  ( )  ( )  ( )  0  o    _ _    ~ .               
   .-'                                               .- ~    '-.    -.            
  <                      . ~ ' ' .             . - ~             ~ -.__~_. _ _    
    ~- .       N121PP  .          . . . . ,- ~                                    
          ' ~ - - - - =. - <#> -  .         \.._                                  
                      .     ~      ____ _ .. ..  .- .                             
                       .         '        ~ -.        ~ -.                        
                         ' . . '               ~ - .       ~-.                    
                                                     ~ - .      ~ .               
                                                            ~ -...0..~. ____      

                                                                .____   __ _      
   __o__   _______ _ _  _                                     /     /             
   \    ~\                                                  /      /              
     \     '\                                         ..../      .'               
      . ' ' . ~\                                      ' /       /                 
     .    /  .  ~ \  .+~\~ ~ ' ' " " ' ' ~ - - - - - -''_      /                  
    . -<#  .  - - -/' . ' \  __                          '~ - \                   
     .. -           ~-.._ / |__|  ( )  ( )  ( )  0  o    _ _    ~ .               
   .-'                                               .- ~    '-.    -.            
  <                      . ~ ' ' .             . - ~             ~ -.__~_. _ _    
    ~- .       N121PP  . \        . . . . ,- ~                                    
          ' ~ - - - - =.   <#>    .         \.._                                  
                      .     ~      ____ _ .. ..  .- .                             
                       .      \  '        ~ -.        ~ -.                        
                         ' . . '               ~ - .       ~-.                    
                                                     ~ - .      ~ .               
                                                            ~ -...0..~. ____      

                                                                .____   __ _      
   __o__   _______ _ _  _                                     /     /             
   \    ~\                                                  /      /              
     \     '\                                         ..../      .'               
      . ' ' . ~\                                      ' /       /                 
     .  _    .  ~ \  .+~\~ ~ ' ' " " ' ' ~ - - - - - -''_      /                  
    .  <# -.  - - -/' . ' \  __                          '~ - \                   
     .. -           ~-.._ / |__|  ( )  ( )  ( )  0  o    _ _    ~ .               
   .-'                                               .- ~    '-.    -.            
  <                      . ~ ' ' .             . - ~             ~ -.__~_. _ _    
    ~- .       N121PP  .          . . . . ,- ~                                    
          ' ~ - - - - =. - <#> -  .         \.._                                  
                      .     ~      ____ _ .. ..  .- .                             
                       .         '        ~ -.        ~ -.                        
                         ' . . '               ~ - .       ~-.                    
                                                     ~ - .      ~ .               
                                                            ~ -...0..~. ____      
"#; // end of TWINENGINE

pub const PLANE: &str = r"
   ____       _  '
| __\_\_o____/_| '
<[___\_\_-----<  '
|  o'            '
                 '
                 '

   ____       _  '
/ __\_\_o____/_| '
<[___\_\_-----<  '
\  o'            '
                 '
                 '

   ____       _  '
| __\_\_o____/_| '
<[___\_\_-----<  '
|  o'            '
                 '
                 '

   ____       _  '
\ __\_\_o____/_| '
<[___\_\_-----<  '
/  o'            '
                 '
                 '
"; // end of PLANE

pub const MOTORCYCLE: &str = r#"
                        _
                       ,S/  .e.##ee
                     ,SS/_ /#####""
                   ,SSSSSS`|##|
                 ,'|SSSSSS/%##|
                 | ;SSSSS/%%%/ .-""-._                           __..ooo._.sSSSSSSSSS"7.
                 |/SSSSS/%%%/.'       `._ __               _.od888888888888"'  '"SSSSS"
             ___  `"SSS/%%%/"-.,sSSs._   8888o._    __.o888888888""SS""    `-._    `7Sb
      _.sssSSSSSSSSSSS/`%%/ ,sSSSSSSSSS-.888888888888888888888"'.S"         ,SSS""   `7b
   ,+""       ```""SS/%%./,sSSSSSSSS".   `"888888888888888"'.sSS"         ,SS"'        `S.
                    /%%%/sSSSSSSSS"   `s.   `"88888888"'.sSSSS"         ,S"'             7
                   /%%%/ `SSSSSSS$$,..sSS`-.   `"88'.sSSSSSSSS._     ,-'
                  /%%%/    `SSSS$$$$SSS",\\\`-.   `"SSSSSS"  8"""7.-'
                  /`%/      `SS$$$SSS,dP,s.\\//`-.   `SS" ,'`8       ,ee888888ee.
        ,oo8888oo/ /         `"""",d88Pd8888./,-'/`.  `,-._`d'    ,d88888888888888b.
     ,d888888888/ /8b.          d8888Pd8888888bd88b`.  :_._`8   ,888888"'    '""88888.
   ,888P'      / /"888b.       d88888`8888888Pd8888 :  :_`-.( ,d8888.__           7888b.
  d88P        / /   `788b     (88888:. `8888Pd88888 ;  ; `-._ 8888P_Z_.>-""--.._   `8888
 d88'     ,--/ /      `88b     `88888b`. `8P 78888";  ;      `"*88_,"   s88s.       `888b
d88'    ,',$/ /$$$$.   `88b      `8888b `. `"'88"_/_,'`-._         `-.d8"88"8P.      `888.
888    ; ,$$$$$$$$$'    888        `"8'   `---------------`-.._      8888888888       888'
888    : `$$$$$$$':     888                                 '888b`-._8s888888"P      .888'
788.   `  `$$$$'  ;     88P                                  8888.   "8878888P'      d888
 88b    `.  `"' ,'     d88'                                  '888b     '88s8"'     .d888'
 `88b.    `-..-'      d88'                                    '888b.             .dd888'
   788b.            ,888'                                       7888b._       _.d8888P
    `7888oo..__..oo888'                                          `"8888888888888888"'
      `"7888888888P"'                                               `"788 mGk 8P"'
"#; // end of MOTORCYCLE

pub const JACK: &str = r"
 \ 0 /   '
  \|/    '
   |     '
  / \    '
_/   \_  '

         '
 __0__   '
/  |  \  '
  / \    '
 _\ /_   '

         '
   o     '
 /\ /\   '
 |/ \|   '
 _\ /_   '

         '
 __0__   '
/  |  \  '
  / \    '
 _\ /_   '

"; // end of JACK

pub const COALCAR: &str = r"
    _________________         
   _|                \_____A  
 =|                        |  
 -|                        |  
__|________________________|_ 
|__________________________|_ 
   |_D__D__D_|  |_D__D__D_|   
    \_/   \_/    \_/   \_/ 
"; // end of COALCAR

And let's add these images to the hashmap, and let's adjust our "mod" and "use" lines:

main.rs
/* main.rs */

mod coalcar;
mod d51;
mod jack;
mod images
use coalcar::*;
use d51::*;
use jack::*;use images::*;
use ncurses::*;
use std::collections::HashMap;

fn main() {    
    // Which image-set will we be using today?
    let kind = "D51";
    // let kind = "JACK";
    // let kind = "COALCAR
    // let kind = "MOTORCYCLE";
    // let kind = "BOAT";
    // let kind = "PLANE";
    // let kind = "TWINENGINE";
    // let kind = "LITTLE";
    // let kind = "C51";

    let mut image_map = HashMap::new();
    image_map.insert(String::from("D51"), String::from(D51));
    image_map.insert(String::from("JACK"), String::from(JACK));
    image_map.insert(String::from("COALCAR"), String::from(COALCAR));
    image_map.insert(String::from("MOTORCYCLE"), String::from(MOTORCYCLE));
    image_map.insert(String::from("BOAT"), String::from(BOAT));
    image_map.insert(String::from("PLANE"), String::from(PLANE));
    image_map.insert(String::from("TWINENGINE"), String::from(TWINENGINE));
    image_map.insert(String::from("LITTLE"), String::from(LITTLE));
    image_map.insert(String::from("C51"), String::from(C51));    
...

Now, by changing which "kind"-line is commented out, you can draw any one of these images, some of which are "animated".

But, rather than hard-coding within the program the type of image we want to draw, let's use 'clap' to Get User-provided Options From the Command-line.