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…

Looping in the New World

The one where I learn about Iterators

Old style life saver ring with "save me" printed on it
Save me from old-style coding techniques

I finished the “Reverse” exercise in the last post with my old-style for loop. Turns out, the mentor on Exercism had the perfect level of help in his response to my submission. He pointed out there was a more “Rust-like/idiomatic and concise manner” for looping through the characters. I did some reading.

Rust Roots and Some Suggestions

I’ve never done any functional programming before, so I’ve never used languages like Lisp, Erlang, OCaml, or Haskell (though, I’ve heard those names before). The Rust book points out that inspiration for Rust syntax and technologies was taken from several existing languages – one technology they adopted (from functional programming languages) was Iterators.

I was actually using an iterator in my first solution, with the for in loop, but I didn’t know it. The .chars() method on a String is an Iterator – it implements the std::iter.::Iterator trait. In fact, in the code for i in 1..12, the expression 1..12 is a Range<i32> value and Range<i32> is simply an iterator that spits out the integers from the starting value (inclusive) to the ending value (exclusive). Similarly, the .chars() iterator spits out the UTF-8 characters that make up the string, from the first character through the last one.

BTW, let’s try to remember this inclusive/exclusive fact – I can see it coming back to bite me if I don’t remember that the Range<i32> 1..12 would enter the loop the first time with a value of 1 and the very last time with a value 11!

Anyway, an iterator does the work of knowing how to loop through a collection of items: where to start and when to end. So my solution could have been even more antiquated; I could have had a for 0..input.len() loop.




Also, it turns out I had stumbled onto the .rev() method – which is actually a method of an Iterator type, which technically “reverses an iterator’s direction” – so it will iterate from “right to left”. It’s what I wanted, I just didn’t understand how I got there.

One final step, we want to collect the individual (reversed) string of characters that we’ll be getting out of input.char().rev(). But we don’t need to manually push them into a new string, we can simply .collect them (didn’t I say that already?) A collection of Chars will, of course, .collect into a single String. AND, since that string is exactly what we want to return, our entire function can be the single expression (with no trailing ; so Rust knows to return this value):

input.chars().rev().collect()

Turbofish – One Really Fast Fast!

One final bit of advice from the mentor on Exercism. He explained that it is best to be explicit about the resulting type with generics like .collect() by using the Rust turbofish operator ::<>. This way, it is obvious from the .collect() what type will result (though it’s plain in this simple example). So finally, we get:

pub fn reverse(input: &str) -> String {
     input.chars().rev().collect::<String>()
 }

Throw it in Reverse

My old-guy approach to my first Rust Exercism exercise – and some Rust basics

Parked car upside down on roof
What!? I’m in my spot! Now lemme find some change for the meter!

Exercism starts me with one of many easy problems they have in their Rust track to solve: write a function that, provided a string, will return that string reversed. So, just flip it!

My ancient C upbringing shines at this point – my first inclination is to loop through the characters in the provided string, in reverse order, and append each char to a new string. So, how to do that in Rust? I end up with this:

pub fn reverse(input: &str) -> String {
     let mut rev_str = String::new();
     for byte in input.chars().rev() {
         rev_str.push(byte);
     }
     rev_str
}

Here, reverse is defined as a (public) function that will accept a string as a parameter (named input) and return a string to the caller. It creates a new string variable rev_str to hold the reversed string while we build it, and then iterates over a loop of the input string’s characters, in reverse order, and pushes each one onto our rev_str variable, and returns it at the end.




Strongly Typed – Really Slam Those Keys

Firstly, Rust is a statically and strongly typed language; if the compiler can’t figure out what type to make a variable, it requires you to specify the type. We also need to remember that all Rust variables are, by default, immutable – once their value is set (at instantiation) it cannot be changed. Anyway, we identify the variable type for our parameter coming in, our holding variable within the function, and our return value. But all three look different, you say?

The easiest is the return value, simply a String; a fancier version of the primitive str type. Our holding variable is the same type – it has to be, it is the variable we end up returning – String::new() just means we are asking for a new, empty String type to stuff our characters in (ALL variables in Rust must be initialized with a default value – this one starts “empty”). The mut you see here is telling the compiler we want a mutable variable – since we will be changing the value as we loop. The incoming parameter however, introduces us to Rust’s use of Ownership, Borrowing, and Lifetimes. Basically, our input param is “borrowing” the variable coming in (passed as a reference) and the borrow will go away once our variable goes out of scope.

Roller coaster with loop in the distance, on hill

Notice we didn’t specify a type for our looping variable byte. Rust forgives us – it can easily identify that byte needs to be a char type because that is what input.chars() will be returning (calling rev() just reverses the order).

Finally (pun intended), if Rust sees an expression with no trailing ; it uses that as the return value and ends the function. You can still specify return – for instance, if you are in the middle of a function and need to exit early.

What I will find out though, when I submit this as my answer to the Exercism problem, is that I’m Rusting wrong (and showing my age)!