Advent of Code 2019 - Day 1 (an aside, in Rust!)
Tags: rust, adventofcode
Published: 2019-12-13 20:31:39

# Introduction

Since I'm dabbling with Rust, I wanted to see if I could do some of the Advent of Code using it. I'm nowhere near as proficient in Rust as I am in Clojure, so I don't expect to do some of the later challenges, but Day 1 is relatively friendly.

# Day 1.1

I did one very simple approach and one that used functions implemented on a custom type. The latter is overkill for this, but it scales well when inputs are used multiple times. Implementing functions on the type reduces boilerplate later.

Anyway, here's the simple:

```rust
fn main() {
    let day1: Vec<u32> = vec![88093, 102524, ***SHORTEN*** 54128, 111698, 84299];
    let total_fuel_reqs: u32 = day1.into_iter()
                                   .map(|x| ((x / 3) as u32) - 2)
                                   .sum();
    println!("{:?}", total_fuel_reqs);
}
```

And here's the over-complicated version:

```rust
pub struct Day1Inputs{
    day1_input: Vec<u32>
}

impl Day1Inputs {
    fn day1_1(self) -> u32 {
        let total_fuel_reqs: u32 = self.day1_input
                                       .into_iter()
                                       .map(|x| ((x / 3) as u32) - 2)
                                       .sum();
        total_fuel_reqs
        }
    }

fn main() {
    let day1 = Day1Inputs {day1_input: vec![88093, 102524, ***SHORTEN*** 54128, 111698, 84299]};
    let fuel_req = day1.day1_1();
    (println!("Day 1: {:?}", fuel_req));
}
```

# Day 1.2

I stuck with the implementation approach for this part. Recursion is a little less easy in Rust than Clojure (mainly because Clojure lets you stick a `recur` at the end of your loop and does everything else for you). As such, I built a recursion into `day1_2`.
One copy event to create a local version of the object mass that can be reduced with each loop as the new fuel mass is returned: `fuel_req`
One variable to catch the aggregating mass for the individual object and its fuel: `total_fuel_mass_for_object`
One variable to catch the aggregating mass for all objects: `total_fuel_mass`

An extra function was needed to hold the fuel calculation this time: `day1_2_fuel_calc`.
You'll notice that this function can't be called with `self` as it doesn't use `self` as an argument. This means it must be accessed via the double-colon approach: `Day1Inputs::day1_2_fuel_calc`

All previous `u32` values were switched to `i32` as the recursive fuel calculation can produce negative integers causing the code to panic if it is dealing with `u32`.

Then I create a new instance of the type since `Vec` can't implement `Copy`, preventing me from passing it to the `day1_2` code after using it in `day1_1`.

```rust
pub struct Day1Inputs{
    day1_input: Vec<i32>
}

impl Day1Inputs {
   fn day1_1(self) -> i32 {
        let total_fuel_reqs: i32 = self.day1_input.iter().map(|x| ((x / 3) as i32) - 2).sum();
        total_fuel_reqs
        }

    fn day1_2_fuel_calc(mass: i32) -> i32 {
        let new_mass = ((mass / 3) as i32) -2;
        new_mass
    }

    fn day1_2(self) -> i32 {
        let mut total_fuel_mass: i32 = 0;
        for mass in self.day1_input {
            let mut total_fuel_mass_for_object: i32 = 0;
            let mut fuel_req = mass;
            loop {
                fuel_req = Day1Inputs::day1_2_fuel_calc(fuel_req);
                if fuel_req <= 0 {
                    break;
                }
                total_fuel_mass_for_object = total_fuel_mass_for_object + fuel_req;
            }
            total_fuel_mass = total_fuel_mass + total_fuel_mass_for_object;
        }
        total_fuel_mass
    }
}
    

fn main() {
    let day1_1 = Day1Inputs {day1_input: vec![88093, 102524, ***SHORTEN*** 54128, 111698, 84299]};
    let fuel_req = day1_1.day1_1();
    (println!("Day 1.1: {:?}", fuel_req));

    let day1_2 = Day1Inputs {day1_input: vec![88093, 102524, ***SHORTEN*** 54128, 111698, 84299]};
    let total_fuel_req = day1_2.day1_2();
    (println!("Day 1.2: {:?}", total_fuel_req));
}
```

# Update

I noticed that my repeating the creation of inputs was necessary because I wasn't being smart about ownership. I needed to derive the Clone trait for my new type and then clone it:

```rust
// Derive the Clone trait for the new type
#[derive(Clone)]
pub struct Day1Inputs{
    day1_input: Vec<i32>
}

impl Day1Inputs {
   fn day1_1(self) -> i32 {
        let total_fuel_reqs: i32 = self.day1_input.iter().map(|x| ((x / 3) as i32) - 2).sum();
        total_fuel_reqs
        }

    fn day1_2_fuel_calc(mass: i32) -> i32 {
        let new_mass = ((mass / 3) as i32) -2;
        new_mass
    }

    fn day1_2(self) -> i32 {
        let mut total_fuel_mass: i32 = 0;
        for mass in self.day1_input {
            let mut total_fuel_mass_for_object: i32 = 0;
            let mut fuel_req = mass;
            loop {
                fuel_req = Day1Inputs::day1_2_fuel_calc(fuel_req);
                if fuel_req <= 0 {
                    break;
                }
                total_fuel_mass_for_object = total_fuel_mass_for_object + fuel_req;
            }
            total_fuel_mass = total_fuel_mass + total_fuel_mass_for_object;
        }
        total_fuel_mass
    }
}
    

fn main() {
    let day1 = Day1Inputs {day1_input: vec![88093, 102524, ***SHORTEN*** 54128, 111698, 84299]};
// Add a clone() to this line, moving a clone, not the original
    let fuel_req = day1.clone().day1_1();
    (println!("Day 1.1: {:?}", fuel_req));

// Allowing this line to move the original day1 without errors
    let total_fuel_req = day1.day1_2();
    (println!("Day 1.2: {:?}", total_fuel_req));
}
```