Crazy (En) code and decode

Where I fiddle with a crazy encoding scheme

laptop in dark room with green code on screen
The 0s and 1s have me…

Encoding with Rust code – sounds fun! Pulling from a different “programming exercise” site this time: CodeWars. One of the very first exercises there is a crazy encoding which looks like:

++++++++++++++++++++++++++++
++++++++++++++++++++++++++++
++++++++++++++++.++++++++++++
+++++++++++++++++.+++++++..+++.

Starting at ASCII value 0 when we begin decoding, we start processing the string:
+ means we add 1 to the ASCII value we are holding
. means we print the character based on the current ASCII value

If you add 1 to get 256, that would loop back to 0.

So, that mess above equates to the string “Hello” (you can probably find the two ‘l’s in the encoded string).

So, lets whip up a function to decode that:

Coding Time

fn decode(code: &str) -> String {
    let mut str = String::new();
    let mut cur: u8 = 0;

    for c in code.chars() {
        match c {
            '+' => cur = cur.wrapping_add(1),
            '.' => str.push(cur as char),
            _ => {},
        }
    }
    str
}

Simple enough, we get an encoded string as a parameter, we start our cur variable at 0 and loop thru the characters of the string. A simple match lets us choose what to do. BTW, wrapping_add means we don’t have to check for 256 ourselves, it will wrap back to 0 automatically. Anything other than a + or . we simply ignore.

So, for fun, lets write an encode function as well:

fn encode(orig: &str) -> String {
    let mut str = String::new();
    let mut cur: u8 = 0;

    for c in orig.chars() {
        while c != cur as char {
            cur = cur.wrapping_add(1);
            str.push('+');
        }
        str.push('.');
    }
    str
}

Just slightly different, but still quick and easy. Ok, we can setup a simple main() to test these:

fn main() {
     let original = "Hello, World!";

     let encoded = encode(&original);
     println!("'{}' encodes as '{}'", &original, &encoded);

     let decoded = decode(&encoded);
     println!("which then decodes to '{}'", &decoded);
     assert_eq!(original, decoded);
 }



Command Line Args

Well, that was fun. Hey, lets change it to take what we’d like encoded from the command line. There a built-in library to help with that and, of course, we only need to change main()

fn main() {
     for arg in std::env::args().skip(1) {
       let encoded = encode(&arg);
       let decoded = decode(&encoded);
       assert_eq!(arg, decoded);
       println!("'{}' encodes as '{}' and decode works",
           &arg, &encoded);
     }
 }

So, std::env::args will give us all the args a program was called with, including the program name itself which is always in [0] and why we want to skip(1) to avoid encoding it. So now:

cargo run “Please sir, may I have some more soup”

runs just fine – I’ll avoid showing you the encoded version! Also:

cargo run What in the world

runs, and encodes each word separately, since they are individual parameters to the program.

Ok, more fun, what if we changed the + to 1 and the . to 0 and made this encoding look like binary, lol! Now, “Hello” encodes as:

11111111111111111111111111111111111111111111111111111111111111111111111101111111111111111111111111111101111111001110

I have more ideas of ways to play with this, so more to come next post…

Author: Jeff Culverhouse

I am a remote Sr Software Engineer for ZipRecruiter.com, mainly perl. Learning Rust in my spare time. Plus taking classes at James Madison University. Culverhouse - English: from Old English culfrehūs ‘dovecote’, hence a topographic name for someone living near a dovecote, or possibly a metonymic occupational name for the keeper of a dovecote. ISTP, occasionally INTP.