What I learned by solving 50 Advent of Code challenges in Rust

Luciano Mammino (@loige)

2023-02-15

What I learned by solving 50 Advent of Code challenges in Rust

Luciano Mammino (@loige)

2023-02-15

What I learned by solving 50 Advent of Code challenges in Rust

Luciano Mammino (@loige)

2023-02-15

😅

👋 I'm Luciano (🇮🇹🍕🍝🤌)

👨‍💻 Senior Architect @ fourTheorem

📔 Co-Author of Node.js Design Patterns  👉

Let's connect!

  loige.co (blog)

  @loige (twitter)

  loige (twitch)

  lmammino (github)

Grab the slides

Always re-imagining

We are a pioneering technology consultancy focused on AWS and serverless

 

Accelerated Serverless | AI as a Service | Platform Modernisation

✉️ Reach out to us at  hello@fourTheorem.com

😇 We are always looking for talent: fth.link/careers

awsbites.com podcast

How do you write Lambda Functions in Rust?

Why am I learning Rust 🦀

Full-stack Web Developer turning Cloud Architect

Experience with dynamic scripting languages (JavaScript, Python, Php)

Looked into Go for performance-sensitive applications

Rust seemed like the natural next step

... and it's fun!

How it is going

error[E0382]: borrow of moved value: `v`
 --> src/main.rs:6:19
  |
4 |     let v = vec![2, 3, 5, 7, 11, 13, 17];
  |         - move occurs because `v` has type `Vec<i32>`, which does not implement the `Copy` trait
5 |     hold_my_vec(v);
  |                 - value moved here
6 |     let element = v.get(3);
  |                   ^^^^^^^^ value borrowed here after move
  |
#[stable(feature = "future_poll_fn", since = "1.64.0")]
impl<T, F> Future for PollFn<F>
where
    F: FnMut(&mut Context<'_>) -> Poll<T>,
{
    type Output = T;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T> {
        // SAFETY: We are not moving out of the pinned field.
        (unsafe { &mut self.get_unchecked_mut().f })(cx)
    }
}

How it started

How it started -> How it is going

2019: Ported some JS code to Rust (resulted in jwtinfo)

2020-2022: Live streamed solving Advent of Code in Rust

+ some other small side-projects and coding challenges

Nothing "production ready" as of today 🤷

Excited about Serverless Rust on AWS

Yeah,
but it's not really about tech...

It's about people

It's about people

It's about people

🔥 Hot take

If you are struggling to learn Rust
(or anything else, really)...
Find a learning buddy!

Advent of Code . com

Valve NV has flow rate=5; tunnels lead to valves ZV, CG, YB, HX, OY
Valve NU has flow rate=6; tunnels lead to valves DA, MA, OA, DK
Valve VU has flow rate=0; tunnels lead to valves PS, FX
Valve JW has flow rate=0; tunnels lead to valves AA, MD
Valve RI has flow rate=0; tunnels lead to valves OY, DG
Valve DG has flow rate=9; tunnels lead to valves TG, RI, DF, EV, KW
Valve PH has flow rate=7; tunnels lead to valves KW, OW, LT, LZ
Valve KZ has flow rate=12; tunnels lead to valves ET, QV, CK, MS
Valve IX has flow rate=0; tunnels lead to valves TS, DO
Valve MS has flow rate=0; tunnels lead to valves LZ, KZ
Valve IL has flow rate=0; tunnels lead to valves DO, ET
Valve EJ has flow rate=20; tunnels lead to valves AV, JY
Valve DK has flow rate=0; tunnels lead to valves NU, CG
Valve YB has flow rate=0; tunnels lead to valves NV, PS
Valve OA has flow rate=0; tunnels lead to valves YA, NU
Valve DA has flow rate=0; tunnels lead to valves NU, RG
Valve KO has flow rate=0; tunnels lead to valves AA, TG
Valve RG has flow rate=4; tunnels lead to valves DF, DA, ZV, MD, LB
Valve MA has flow rate=0; tunnels lead to valves AA, NU
Valve OW has flow rate=0; tunnels lead to valves DO, PH
Valve KW has flow rate=0; tunnels lead to valves DG, PH
Valve DO has flow rate=14; tunnels lead to valves IX, IL, CZ, OW
Valve DF has flow rate=0; tunnels lead to valves RG, DG
Valve TG has flow rate=0; tunnels lead to valves DG, KO
Valve LB has flow rate=0; tunnels lead to valves RG, FX
Valve HX has flow rate=0; tunnels lead to valves AA, NV
Valve GB has flow rate=0; tunnels lead to valves AV, XK
Valve CG has flow rate=0; tunnels lead to valves DK, NV
Valve LT has flow rate=0; tunnels lead to valves AO, PH
Valve FX has flow rate=23; tunnels lead to valves LB, HY, VU
Valve ET has flow rate=0; tunnels lead to valves IL, KZ
Valve CK has flow rate=0; tunnels lead to valves UX, KZ
Valve LZ has flow rate=0; tunnels lead to valves PH, MS
Valve YA has flow rate=17; tunnels lead to valves JY, OA
Valve TS has flow rate=0; tunnels lead to valves NO, IX
Valve NO has flow rate=8; tunnel leads to valve TS
Valve XK has flow rate=24; tunnel leads to valve GB

1. Read & understand the puzzle

2. Parse the input

3. Write some code

4. Find solution

5. Submit your solution (unlocks part 2)

6. Repeat from point 1 for part 2

Iterator combinators

y2022 - Day 1: Calorie Counting



1000
2000
3000

4000

5000
6000

7000
8000
9000

10000

sum

sum

sum

sum

sum

max

6000
4000
11000
24000
10000
24000

Classic noob approach

fn classic(input: &str) -> u64 {
    let mut max = 0;
    let batches = input.split("\n\n");
    for batch in batches {
        let lines = batch.lines();
        let mut total = 0;
        for line in lines {
            let value = line.parse::<u64>().unwrap();
            total += value;
        }
        if total > max {
            max = total;
        }
    }
    max
}

Combinators approach

fn combinators(input: &str) -> u64 {
    input
        .split("\n\n")
        .map(|batch| {
            batch
                .lines()
                .map(|line| line.parse::<u64>().unwrap())
                .sum::<u64>()
        })
        .max()
        .unwrap()
}

Nice, but the classic noob version must be much faster, right? 🤔

⚡️ NOT REALLY!

Yeah, but I am sure that
iterator combinators are
not always flexible enough, right? 🤔

y2022 Day 1: Calorie Counting (part 2)



1000
2000
3000

4000

5000
6000

7000
8000
9000

10000

sum

sum

sum

sum

sum

top 3

6000
4000
11000
24000
10000
24000
11000
10000

sum

45000
fn combinators(input: &str) -> u64 {
    input
        .split("\n\n")
        .map(|batch| {
            batch
                .lines()
                .map(|line| line.parse::<u64>().unwrap())
                .sum::<u64>()
        })
        .sort_descending()
        .take(3)
        .sum()
}
fn combinators(input: &str) -> u64 {
    input
        .split("\n\n")
        .map(|batch| {
            batch
                .lines()
                .map(|line| line.parse::<u64>().unwrap())
                .sum::<u64>()
        })
        .sort_descending()
        .take(3)
        .sum()
}

🤷

But iterator combinators can be "extended" 🤫

$ cargo add itertools
use itertools::Itertools;

fn combinators(input: &str) -> u64 {
    input
        .split("\n\n")
        .map(|batch| {
            batch
                .lines()
                .map(|line| line.parse::<u64>().unwrap())
                .sum::<u64>()
        })
        .sorted()
        .rev()
        .take(3)
        .sum()
}
use itertools::Itertools;

fn combinators(input: &str) -> u64 {
    input
        .split("\n\n")
        .map(|batch| {
            batch
                .lines()
                .map(|line| line.parse::<u64>().unwrap())
                .sum::<u64>()
        })
        .sorted()
        .rev()
        .take(3)
        .sum()
}

🤩

added by itertools

But... Do we really want to sort? 😕

💡IDEA:

Consume the iterator and, as you go, keep the current top 3 in a vec...

💡IDEA:

Consume the iterator and, as you go, keep the current top 3 in a vec...

100
22
44
1
120
top3 = []
100
22
44
1
120
top3 = []

👉

💡IDEA:

Consume the iterator and, as you go, keep the current top 3 in a vec...

100
22
44
1
120
top3 = [100]

👉

💡IDEA:

Consume the iterator and, as you go, keep the current top 3 in a vec...

100
22
44
1
120
top3 = [100]

👉

💡IDEA:

Consume the iterator and, as you go, keep the current top 3 in a vec...

100
22
44
1
120
top3 = [100,22]

👉

💡IDEA:

Consume the iterator and, as you go, keep the current top 3 in a vec...

100
22
44
1
120
top3 = [100,22]

👉

💡IDEA:

Consume the iterator and, as you go, keep the current top 3 in a vec...

100
22
44
1
120
top3 = [100,44,22]

👉

💡IDEA:

Consume the iterator and, as you go, keep the current top 3 in a vec...

100
22
44
1
120
top3 = [100,44,22]

👉

💡IDEA:

Consume the iterator and, as you go, keep the current top 3 in a vec...

100
22
44
1
120
top3 = [100,44,22]

👉

💡IDEA:

Consume the iterator and, as you go, keep the current top 3 in a vec...

100
22
44
1
120
top3 = [120,100,44]

👉

💡IDEA:

Consume the iterator and, as you go, keep the current top 3 in a vec...

100
22
44
1
120
top3 = [120,100,44]

This is O(n*m) vs sorting O(n*logn) ⚡️

* indulge me and let's ignore we could have used radix sort here...

** O(n) for very small m, top100 would be expensive!

💡IDEA:

Consume the iterator and, as you go, keep the current top 3 in a vec...

trait TopN {
    fn top_n(self, n: usize) -> Vec<u64>;
}

That's what we want for now, but can it be more "generic"? 🧐

trait TopN<T> {
    fn top_n(self, n: usize) -> Vec<T>;
}

Makes the trait "generic" over any type T

T is used as part of the return type of the function

That's a cool trait indeed... but I am sure we cannot implement it for "all" iterators, right?! 🤷

Of course, we can! 💪

It's called a "blanket implementation".

impl<T, U: Iterator<Item = T>> TopN<T> for U {
    fn top_n(self, n: usize) -> Vec<T> {
        // TODO:
        unimplemented!();
    }
}

When you implement traits with generics, you can restrict for which types the implementation is relevant

All types U that implements the Iterator trait producing Items of type T

We implement TopN<T> for all types U (iterators producing T)!

impl<T, U: Iterator<Item = T>> TopN<T> for U {
    fn top_n(self, n: usize) -> Vec<T> {
        let mut top = Vec::with_capacity(n);
        for value in self {
            for i in 0..n {
                if let Some(top_value) = top.get(i) {
                    if value > *top_value {
                        top[i..].rotate_right(1);
                        top[i] = value;
                        break;
                    }
                } else {
                    top.push(value);
                    break;
                }
            }
        }
        top
    }
}
impl<T, U: Iterator<Item = T>> TopN<T> for U {
    fn top_n(self, n: usize) -> Vec<T> {
        let mut top = Vec::with_capacity(n);
        for value in self {
            for i in 0..n {
                if let Some(top_value) = top.get(i) {
                    if value > *top_value {
                        top[i..].rotate_right(1);
                        top[i] = value;
                        break;
                    }
                } else {
                    top.push(value);
                    break;
                }
            }
        }
        top
    }
}
impl<T: PartialOrd, U: Iterator<Item = T>> TopN<T> for U {
    fn top_n(self, n: usize) -> Vec<T> {
        let mut top = Vec::with_capacity(n);
        for value in self {
            for i in 0..n {
                if let Some(top_value) = top.get(i) {
                    if value > *top_value {
                        top[i..].rotate_right(1);
                        top[i] = value;
                        break;
                    }
                } else {
                    top.push(value);
                    break;
                }
            }
        }
        top
    }
}

Restricting T only to types that can be compared!

👍

fn combinators_no_sort(input: &str) -> u64 {
    input
        .split("\n\n")
        .map(|batch| {
            batch
                .lines()
                .map(|line| line.parse::<u64>().unwrap())
                .sum::<u64>()
        })
        .top_n(3)
        .iter()
        .sum()
}
fn combinators_no_sort(input: &str) -> u64 {
    input
        .split("\n\n")
        .map(|batch| {
            batch
                .lines()
                .map(|line| line.parse::<u64>().unwrap())
                .sum::<u64>()
        })
        .top_n(3)
        .iter()
        .sum()
}

😍

OMG, we added this!

OK, but you used a Vec there...
I heard rustaceans don't like unnecessary allocations, right?! 🤷

trait Top<T> {
    fn top(self, n: usize) -> Vec<T>;
}

impl<T: PartialOrd, U: Iterator<Item = T>> Top<T> for U {
    fn top(self, n: usize) -> Vec<T> {
        let mut top = Vec::with_capacity(n);
        // ...
        top
    }
}

We want to replace these with an array...

trait Top<T> {
    fn top(self, n: usize) -> [T;n];
}

impl<T: PartialOrd, U: Iterator<Item = T>> Top<T> for U {
    fn top(self, n: usize) -> [T;n] {
        let mut top = [T;n];
        // ...
        top
    }
}
trait Top<T> {
    fn top<const N: usize>(self) -> [T; N];
}

impl<T: PartialOrd, U: Iterator<Item = T>> Top<T> for U {
    fn top<const N: usize>(self) -> [T; N] {
        let mut top = [T;N];
        // ...
        top
    }
}

const generics syntax

trait Top<T> {
    fn top<const N: usize>(self) -> [T; N];
}

impl<T: PartialOrd, U: Iterator<Item = T>> Top<T> for U {
    fn top<const N: usize>(self) -> [T; N] {
        let mut top = [T;N];
        // ...
        top
    }
}
trait Top<T> {
    fn top<const N: usize>(self) -> [T; N];
}

impl<T: PartialOrd, U: Iterator<Item = T>> Top<T> for U {
    fn top<const N: usize>(self) -> [T; N] {
        let mut top = [Default::default(); N];
        // ...
        top
    }
}
trait Top<T> {
    fn top<const N: usize>(self) -> [T; N];
}

impl<T: Default + Copy + PartialOrd, U: Iterator<Item = T>> Top<T> for U {
    fn top<const N: usize>(self) -> [T; N] {
        let mut top = [Default::default(); N];
        // ...
        top
    }
}
trait Top<T> {
    fn top<const N: usize>(self) -> [T; N];
}

impl<T: Default + Copy + PartialOrd, U: Iterator<Item = T>> Top<T> for U {
    fn top<const N: usize>(self) -> [T; N] {
        let mut top = [Default::default(); N];
        // ...
        top
    }
}

Do we really need this?

trait Top<T> {
    fn top<const N: usize>(self) -> [T; N];
}

impl<T: Default + PartialOrd, U: Iterator<Item = T>> Top<T> for U {
    fn top<const N: usize>(self) -> [T; N] {
        let mut top = core::array::from_fn(|_| Default::default());
        // ...
        top
    }
}

Allows us to avoid Copy

trait Top<T> {
    fn top<const N: usize>(self) -> [T; N];
}

impl<T: Default + PartialOrd, U: Iterator<Item = T>> Top<T> for U {
    fn top<const N: usize>(self) -> [T; N] {
        let mut top = core::array::from_fn(|_| Default::default());
        // ...
        top
    }
}

Note: This works for now, but it's not a perfect solution 😥

(e.g. what if there are fewer than N items?)

fn combinators_no_sort_const(input: &str) -> u64 {
    input
        .split("\n\n")
        .map(|batch| {
            batch
                .lines()
                .map(|line| line.parse::<u64>().unwrap())
                .sum::<u64>()
        })
        .top::<3>()
        .iter()
        .sum()
}
fn combinators_no_sort_const(input: &str) -> u64 {
    input
        .split("\n\n")
        .map(|batch| {
            batch
                .lines()
                .map(|line| line.parse::<u64>().unwrap())
                .sum::<u64>()
        })
        .top::<3>()
        .iter()
        .sum()
}

Slightly different syntax 🐟

Phew... we did it!

😮‍💨

Which one do you think is faster? 🧐

Itertools

no_sort_vec

no_sort_array

1.

2.

3.

Which one do you think is faster? 🧐

Itertools

no_sort_vec

no_sort_array

1.

2.

3.

37.517 µs

33.284 µs

32.957 µs

BTW, cargo bench is awesome!

⭐️

But let's talk more about
const generics, what else can you do with them?

y2020 - Day 17: Conway Cubes

struct Point<const D: usize>([i32; D]);

fn make_2d_point(x: i32, y: i32) -> Point<2> {
    Point([x, y])
}

fn make_3d_point(x: i32, y: i32, z: i32) -> Point<3> {
    Point([x, y, z])
}

fn make_4d_point(x: i32, y: i32, z: i32, w: i32) -> Point<4> {
    Point([x, y, z, w])
}

y2020 - Day 17: Conway Cubes

fn some_func() {
    // ...
    let p5d = Point([1, 2, 3, 4, 5]);
    // ...
}

No need to specify the type, Rust will infer Point<5> based on the length of the passed array!

y2021 - Day 25: Sea Cucumber

v...>>.vv>
.vv>>.vv..
>>.>v>...v
>>v>>.>.v.
v>v.vv.v..
>.>>..v...
.vv..>.>v.
v.v..>>v.v
....v..v.>

Sometimes you have to handle grids of variable sizes.

README example (10x9)

y2021 - Day 25: Sea Cucumber

.v.v.v>...>vv>v>>>.v>..v>.v.>.>v>.v.v.>>v...>.>....>.>vv>>>.....>>...v.>>v..>..vvv.>v...vv...>..>....>.>.>.>vvv....>..vv>v....>v...>>....v.
>.v>..v.>>vv.>>v...v.>.>..v.>.>.>vvv..>>>.>...>v>.>>v....>>>>...>v.v>.v>....>>>v.>>>....vv.....vvv.v.v..>.>..v>>.>.v>.>v>.vvvv.v..v>>..>>vv
.vv>>...v>..v..v>v.>vvv.v.v>>.....v>>.......>...v>.v>.v.vv.v.>v>v.v......>>......>.v...v........v.v........>.v.vv.>>.v.>>.>.>...v....v>>>..
.>.>v.>vv.v...v.>>v>.>v..vv>..v.v.>...v....>vvvvvv>>>v..vv.v.v>>.>>.>>v>v>>..>.v...v.v.>v..>...v.>.>>.v...v>..v...vv.>v.....vvv.v>.v>..>>v.
..>.....v.>>..>>.v>v.>.>>.>..vv.v>>.>..>.>..v>>...>.>>.vv>>>..>>>>.v.>....>>.>..v>>vv>.>>v>vvvv>vv..v.v.>.v>..v>.vvv>>.v.......>>.>...>>.>.
v...>..>..v>.vv.>>.>...>>....v.......v>...v.vvvvv>..v...>.v.>.>>v>v.>....v>...>...v.>.vv>......vv>.v>vv>>....v>.v>.>..>v.v..>>>.>>>..v..>vv
v>v>.v>..v..v.>..>...>v.>..>.>vvvv...v.v>v....>.>v.vvvv....>...v.v..vvvvvv..v.v..v>v....>v....>v.>>.v>.>v..>...v.vv...>v>>..>.>.....v.v..v.
.......v.....v>v.vv.>.v>.>>.>v.....>>..v.v.v>v>.....v...>v.vv>>.vv>>>>.>>.v.>v>..v.v..>v.vv....>>.vv.>v...>>v....v.v.>.vvvv.v....>v>>>>v.>.
v>.v>..v...vv.>vv.v...v.v>.>........>.vv>>..........v...>vv....>.>v>v..>..>>>v.>>..v.>.>...v.v.>..v>>>..>v.....v.>>>>...v>>v...vv>..>>.v.>>
.v>>>>>>v.>.>...>.>>.>.>>v>.........v..>.v>>>v>.....>...>>.>.v..>.vvv.>..v.v..>.>..>v>v.>v......>>...>>v.vv.....>.>...>.....>v.v..>>v.vvvv.
v......>.......>>..>.v.>..v..>>v..>>......v>v.vvv.>...>>>...v..v>vv.....v.v>v>>v..v.v..v.......v.>v>.v.v..>.>..>v.v>>>v..v.>.>.>>v.>..v.v>.
>.v..>>....>.v.>...>>>..>.v..v>v..>>>.v..v....vv>vv.v.v..v...>>..>......>>..v.....v.v>>.v....v>>....>..>v.vv.>.>..v...v>>.>.>v.v.vv>.v..v.>
..v...>...v..v.v...>...>.v..>...v...vv>..v....v>>>v.v..v.v>v..>v..v..v>>vv.v>..v..v...>.......>..>.>v>v..>...>v.....v..>v>v...v>..>.>...vvv
.vv>.>.v...>>...v.>.>v.v.>>v..v.>v.>>vv.v>.>..>....v.>v>vv>..v>v>v.>>v>v.>...v>vvv..>>.v.>v.>vv.>..v>...>.v..>.>>>v>>...v>.>>v..v....v>v..v
..>.>>>...>........>.vvv>>.>v..v.>v..v..>v.>>.>.v..>.v...v>>.>v..vv...v.v>.vvv...vv>vv>v>.>vv>.>v.vv..v.v...v.>>..v...v>...v..vv..v..>.>>>>
..>.>.>v.v.>.....>vv.vvv>.>..v>>>v.>vv.>.v.>.....v>>.....>v..vvv....v.>.v>.v.vv>v.>vv.v..>v>>...v>v....v>>v>....v..>vvvv>..>v>.v..v.....>..
.vv>.....v>.>>>.>>v>>>v>>>v>.v>>.>v..>>v.vvv...>vv.v.v.v.....>>vv..v.>>>>v.>....v>v.>..>..vv>>>....vv.vvvvv>v....v...>.>.vv...v...>vv...>..
>...v.vv.vv.vvv..>v.>.......v...v.>v.>..>.v>..v...>v..>..>v.v..>.v>.>>.v>.>v...v>>.>v.v.v.v>.>..v.>vv.v>>>.>vv.vvv.>vv>>v>..v>>.vvv>v..v.v>
>v.>...>v.vv..vv>..v.v..>..v.>v>>>..vv...>.>.v.v...>>.>v.vv..>.v.>>.>.>.v>..>.>..v>..v>>.v.v.v>.>...v.v.vv.>>>.v>...v.v>..>>..v.v>vv>vv>>vv
vv.vv>....>..>...>>..v.v..v..v....v.>.vvv>>.v.v>.>.vv.>v......>vv>>.>>.....>>....>..v.v..v.v...>>v.>>>v.....v.>......v>v>v>>.v.vv...>.v....
.>v>....vv.v>>...>>....>>>.>.v>...vv.v.>vv>.....v>v.v....v..v.>v>.....>...>v>>....v.vv.v>>.>..v>.v.v...v..>..>>v.v>....v.>....v>......>v...
..vvvv>.>.>.v.>.vv....>>>v..>..v..v>vvv.>v.>>.>v.>.vv>vv.>......v...vv>v..v.v.vv>v.v..vvv>v..>>...>..>.>....>>v>....v.>vvv>>..>>>..v..v.>..
>.....>>..v>.vv.v>..>..v.>vv>>vv>.v>v..vv......>....>.....>.>v.vv.vvv.v..>.vv..>>...>vvvv>..>..>.>>.>v.vv>...>>vvvv.>.v.v...>...>v>..>v....
.v.>v..>vv.>v...>vv.v..vv>.>>.......>v>.vv..v.vv>v..>.>vv.v>>>.>>v>.>...v...vv.>>>v...>>..v>v>v.v.v>..>.v....>.v.v.>vvv.v.vv.>.v..vv.>>v>>.
....v...vvv>>>.>>.>v>...>.>v.v.>.vv>...v...>>v.v.>.v>..>...vvv....v..vv>vv>>>..>.>.>v....>..v.vv.v..v...>>>v..v.>.....v>>v>vvvv.>.>.v.>vv..
.>.>v..v>.v.v.v>v.>.vv...vv.>.>v>....v>>v..>....>>>.v>v.v>>..>.>vv..>.>..>.>>.........>>>>..>...vvv>.>.v.>v.v>...v.>vv..>.>v.>>vv.>>>v>.vvv
>..>>..>.>>>vvv.>....>>v.>..v>v>v....vv.>.>>>v..v..v>.v....v>>...>>v...vvvv>>>>.>.....v>v.v.v..>v.v..>.v.>v>>....>>>v>.v>v.>.v...>>>.>vv.>>
...>>..>..>.>v.v..vv>.>.>vv.v>>.>....>.v>..>.v>>.....v.v.v.v..>...>>v.>.v.v.>>.>v....>..v..v>>..>>.>.v..>>..>vv..vv>v.v.v..v.vv.vv>....vv..
.v.v>..>.>.v..v>>....v>....>v>>>....>......v..v.......>vvvv.vvv.v..>.>..>.>>v.v..>...>>vv>.v..v.v..>vv>..>>.>v.>.v...vvv>>..>.vv..v.>v.v>v>
v>.>.>.v>>v.>>v>.>.vv>.>>...>..>>>.v....>>>v>.v>v.>.v.>..>vvv>.v.>>....>v....v.vvv>..>.>.vv>>..>>v...vv.>.>>.v..v>.v.>.v..>.v>.v....v...>.>
>vvv>.v>..>>..>.vv>>>...>>v.>v..>v....v>vv.>..>.v.>....vv....v....>....vv.v...vv>>>.>..>>>.v....>>vv.vv>vv>>.v...>>>v.v...v.vv..v>.vv..>v>.
v.>...>>..>>v>..v.vvvv..>>.v>.v.>.vvvvv>v..v.v>....v..>>.>>..v.>.v>..v.>.v.vv>.>.>v.v....>v.vvv>>>.v>>.vvv..v..>.>...>.>..>.>...v..>>v.....
.>v.>>v>..vv.>.vv.>>...v.v....>>>v....vvv>.v.>v.>v.vv.>.....>..>>.vv.v.v.>..v.>...>>.>.....>>.>........v>...>.>>>.>v.>.v.>>.....vvvv.v.>v>.
>..v..>.>>>..>vv..v..>.v.v....v>...v>....>>...>v.>v...v..v...>.v>.>.>.vv...v....>>....vv.v>>....v.v.v....>v.....>.v.v...v>..>>..>..>>..>>v>
.>vvv.v>.>vvv>>vv>v>v..>...>vv.>..v>.....>.vv....>>...>>.>>>v..vv.>>.....>>.v..v.v>>.vv>..v.vvv...>>.>..v.v>.v......v...>.>..>..>v....vv>.v
.>v>...>...v..v>.v..v>v.v.>>.>vvv...v.>..............vv..vvvv>.>....>.>>..v.vv.>>.>.vv>...>>v.>.>.v..v>..v..>v...>.>..v.......>.>v.....>...
..v.>v>vv....v>>.v>vv....>.v>.>v.vvv>vv>>vv>..v>.vvv>.v.>v.>....v.>..v>v........v.>>>v..>>.>v>v...>>vv.>.v.>>.>..>..>vvv>.v.>vvvv.v>v.>v..>
.vv>>v......>...v>.vv>..v>>.v>v>>v>...>.>>.>.>...v...>>>>>vv>.>v....>v..v>>.>.vv>..v>>v>.v..v.v..v>......>.vv>....>v>..v>>.>.>>.v>v>v>>>v..
>v.v>.>...vv.>..>.v.>>.vv....>.....>v.v..v.>..>...>.v>v.......vv.v>.>vvv...>..>.>....>v...>..v...>v.......vv..>....v...>v.....>>v.>vv>.v.v>
v>..vv>.vv.v...vv...>......>v..>>.v>vv.v>>v..>v>..vvvv..>.>>.v..vv>.v>.>......>......>vv.v..vv>>..>..v..>v..>..>...>...>.>.........v.vv>v.v
.v>.>.......>.v.>.v..>>.>.v>...>..vv......v.v...>..v>>v..v..v...>>vv..v.v...v.v...v>vv>..v.>>>v.v.v>v..>vv>..v..>>>>...>.>..>.>>>.>>vv>>..v
.>..vvv.v>.v..>..v>>..v>v>>.>.>..v.>vv>.v.>>v>v.vv.....v.>v.>>>>vv>>>..>>...vv>v..vvvv>>>..v.v.>...v.....>>...>>..>.>.>v..>..>...>..v.v>..>
vv..v>.v....v..v>.......>vv..>vv>...vv...v>>vvv>v...v.>v.v>v.>.v.v.>.>.>....v.>>>..>.v.......vv..v.vv>.v...v...>....vvvv>....>.v..v.>v..v..
>.vvv.>v....vv>>v.>..>.vv.>v>.v.>..>>v......vv>>>vv.v..vv.v.vvvvv>>.>>.>>v...v..v.>..>...>v>.v.v>vv>>.v.vv>>..v.>>>...>>.>v.v.>>..vv>..>.v.
..v.v>..>v>..>.......>>.>>>v..v.>....>.v..v>...>v>v.>.v.>.v...>....vv..>..v.>......v...>vvv>..v..v....v>...v.>.v......v>vv..>.vv...vvv.>vv.
vv......vvvv.>>.>v>.>.v>.vv>v>.vv>....v....v.v.>vv>vv.>>.>.v>v...v.....v.>..>....v.>..>..v.....v.v>>v>.v.>..v>..vv.v.>>...>.vv>....>v.v>>..
v>.>>.>.....vv.>v>>.v>..>v.>..>>.v..v.>.>.>>.vv>..v..vv.>>v..>.>........v....v>>v.v.>v..>.>v......>..>.>.v.>...v>..>v>..v.>v>v..>vv>..v.>>>
v..v..>...>.v..>>...>.>v..>v.v.vv.v..>..v..>.v.>>v.>..v.>..v>..>.>vvv..v.>.>>.v.v..v>.>v.>..>v..v>>v>>......vv.>.>.v.>>v......>v...>v...>>.
.>..>...>...v.....>.....vv.v.>v.>.>..v....v>>...>.>.v..>>>...>v.v..>...>vv>..>v>.v.>>.vvv>>v>v.......v.vv...>>>..v...v.>v..v.>..>vv>..>.v>.
....>vv.>..>.>>.v..>.v.>..v..>..v.>>.>v..vv.v>>>v.....>>...>v>......>.>v>.v.>.vv>.vv>.v.>>..v>..>vv.v..v...>vvvv>>..>..v......v>..v.v.v>.>.
....vv>....v....>...v>..v>.>.>.>v..>.v>.......v>..v.vvv.v.>..v.>v>.>vv.v.>vv>.>>v.v..v.v...>vvv.......>v>v.v..>.v>.v>vvvv.>.>>>.>..vv.>v..>
..>.vvv>.>vvv>>>vv.>..>v.v.vvv>..vv.....>v>>..vv>.....>...>.v>.v>>.>.>vv..v...v..>.>>..>>.>.vv>v>>>vv....v>.>>..>..vv>.>>..>v>.v.v.v..>...v
.>.v>............v>v.v......vvv>.vvv>v.v.>vv..>>....v.>.vv.vv..>..>>>>v.....>.>.>..v.>.>..>.vv.v.v......>>.>>>.>>.v..>v>v...v...v>...vv>.>.
>>.v....v..>..v>>v....>...v.v....v.>..>.v>v.>v>.>>v.....>.v.>>.>>>..>.v.v.>>vv>>.>..>>v...>.>.v.vvv>>vv.vv>.v.>.>.>vv.v..>v>.>.vv>>>v..v>.v
>v..v.v.>..>>>>..>>v.v>.v>..>>....v.....>..>.>v>...>>.v>....vvv>....>v.>.v.>.>v>.>v>>.>v>v..>.....v>.vv..v>>...>>v....>v..v>....>...vvv.v>.
.>.v.....>..>.>vvv.>v.>vv.>..v..v.v.>vv>.>..>.>>>.....>v......>v.>....v..>.>..v>v.>..>.>v..>.v.>v>v>...v.v.>.v.>vvv>vv..>.v..v>..vv..>..v>.
.v>.v>v>.v..v>.v..v.>............>v.>..>..>>.v..v>v>vv>>.>v.>>.v..v...v....>.v..>vv.>.....>.>>.vvv..>>..vv>>v>.....>>.v>...v.vvv>>..>..v.v>
v...>..>...v.>>.v...>..v>v...>vv.v..>vv>..vv>>.v..vv.v>v.>>..v>v.v..>.......v...v.v>...>v.v......v.vv>...v.>..>vv>v.v....v.v.vv.vv.vvvv.>v.
.>.v>>....>....vv..>vv>.>..vv.>>...>....>vv.vv...>.vv>v...>>..v...>..v....>v.vvv...v>>.>>>>>v>..v>>vv>vv.>vv..v...v.vv..v>v.>.v.v>..v..v.>v
.>.v.v...v.....>..v>..v>.vv.v>...vv.....>v..>..>..>v.>.v...>.vv.....>.>.v.v>v....>..>>.vv.>vvvv..>>>.v...v...>v.vv>>.v..>v..>..>>.>..v>v..>
>..vv>>v..>.v>>>v>>.v..vv>....v.>vvvv.>...vv...>.v..>v.>v>.>v>v>>v.>.>...>>>.....v.v....v>...>..>.>v.>.vv.....>.>>vv.....>......>.v..>v>.>.
v.......>>.>..v>.v.>.>v..>>.>.>vv..>v.v...>.v>..v....v..v..>.>>...v..v>.vv.>v>>.>....>vv>.v.v.>..vvv.v.>.v>.v>v..>.>>.>.>..>.>...vvvvv.v>..
>..v.v>.>>v.>>...v.>v.....>.v.>.v>v.>v>.vvv>.>>..>v..v.v.>...>v....>v.v.v>>...>.vv>.>v.vv....v>..v>>v.>.>..v>v..>v>..>.>>.v>.>..>..>..v....
.>vv.>.v>>>.>.>.v>v.>..vv>..>>>.>>...v.....>v.v..>.>.>>.v.>.>v>.>v.v..vvvv>.....v.v..vv....v.>...>.vv.>>v.....>.>vv>...v....>v..>v..vv.>>>v
v..>>>v.>..v>.v.v.>.>..>..>>..vv.vv.>.v.v..>v>v.>>>.>.>>.>>.vvv..>...>>..>.>..vvv>.>..v.>.>.v>v>.>v..>.>.v>....v..>..v.>v.>>.v.v..v>v..>v..
....>v...>....>.v>>vv.....vv>..vv.v....vvv>>...vv.v.v.>......v.v>>v..>.v>..v>v.v..>....>....v.vvvv>v..v>v>v>v.>>v....v.>vv>>v>vv>>>.>..>.v>
...>>>.v.v.....v>vv>>v>.>..v.v>v>....v>>vv..vv>v>..vv...>.>v>.>v..v...>.>vv..v.>.v..v...>...v>...v.vv>vv>..v....>.v....v.v>..>.....v..v..v.
.>vv.v..v>..vv....>.>>>>..>>>>..v....>.>v.vv.v.>>.>vvv..vv..>vv.>>v>>v.v..>.....>>v>..v..>>v>vvvv...>.>v>..v..>v>...>>.>vvv.v.>vv.>..v>>...
>>.>...>v.>vv>v>.>.....>.vv.>.vv>.>>.>.>...........v>.>..>>.>.>>..v.v>>v.vv>v>.>v.>..v>vv>.>>.v>>.>.v>v.v..>v.v>.v>v>>.v.>v.>>vv...vv.vv...
>vv>>.>...>v.>v>...>v>.v.>...vv....vv>v>.>..>.v.v.vv.v.>v......>..>.vv..v>.>>.>v>...v.vv..v...>vv.v.v...>>.>.>.v..v..>.vvvvv>>>>v>vv.v.v...
>v>>>.v>..vvvv..vv>...>.>.v>>>..v.v>>.v..v>.v.....>v>>.v..>..>.....>v....>.>..>......>v>.>.v.>..v..vvv>>v.v..v>..v.v.>>>>>>>vvvv.vv.>vv..v>
..v..vv>v>v...v...>.vvvv.v.....v..>.>..>....v.....v>.>>..v.v.vv..>....vv>vv>v>>.>>v>>.>.vv.>..>>v.v>...v>.v...vv.>v....v.>>...>v.>.vv.>.vv.
.v>v..>vvv.vv>v>>>..v..>v>.vvvv.>.>.vvv>.>..vv.>v...>...>v..>..>......v...>.v..v>>.>v...>>>>.....>>>..>vv.>>>v.>v..v>>vv.>....>..>>vv.>.>..
v.>...>vvv>...>.>.v>.v..v..v>.v.>.v>.v...vvv..>.>>v>...>.>>v>>.v.>v...>>.v.v..vv..vv.>.>v.>.v.>>>.>.vv...v.v>.v.>>>>>>..vvvv..>....>..>.v..
>v..>v....v.v....>vv.>.>.>v>.>v>v.v>>>.>v...>>>.v..v.v.v>v......>vv.v..>......>v>.v>>.vv>>>...vvv.v..>.>.........v.vv>.>vv.vv>v.v.>.>vv..v.
>.v>.v.v>v..vv.v>v>.>>....vv..>.vvv>v..>>>>vv.v>....>.vv.>...>>>...>v>.>...v..v>v...>..v...>.v..v>.v...v.....>vv........>....v>v..v.>..>v..
>...>v......v>.>v...>.v...>>v.v>..>v...v.v..v>.>.v>.>...>vv.v>vvv.>..>..>...v...>>..>.>v.>vv.v..>>.v.v.v..>.v>..v.>..v...>>v.>v>v.v.v.>..>.
..v>.>>v>>..>..vv>>..>.>>vv..>..vv....v.>v>.....>v>..v.v>.v..>...vv..v.>>vvv...v>v>.>.v.>>>.v>...v>.>v.v>v>..>...>....>>>v..v..>>...>.v....
....>...vv.>...vvv>v..>vvv>>..>>>>......>>>.v..v>vv>v>.>....>.....v.v..v.v.....v.v..v.v..v>.>v>v>.>.v.>v>....vv.v..>.vv..>..vv>.>v.>.......
vv.>.>...>vvv.>v.>v>.>.>.v..v>..>.>>.v>.v>.v.v..v>v...v..>>.>>.>.>....v.>..>>vv>....>..>>...>>v.>.v>>..>>...vv.v.v.>>..v.v...v.v>..v.v..vv.
.>v.v..v.v.>.v.....>.v...>.vv>.>....vv.v.v..v>.v>v>>>.v..vv.>vv.v....vv..vv.>>>v>.v.......>.vv.v..>v>v...v...>..>vv....>.>.>.>>v...v..v>>.v
...>v.>>.vv...>v.v.v>...v.>vv..v.v...>>>>..>.....>.>v.v.v>.v.v>.>>.>...vv..v....v>.v.vv..>.v>...>>..v.v.v.v>.v.v>v.>..v.>v..>>..>vv.......v
>....v..>..vv.>.v>..>.>.>.>>v..vv.>vv...>>v.>.vv.v.>.v..>vvv>.v...vvvv>vv.>>>.>>..v.>v>>>..>>.>.v>>>v>>>..v>>.>.v.>...v.....v..>..>>.>v>..v
>..vvvv>>..v>v>......>...v>...>>>...>.v>.>.v>.>>....vv..v>>>vv..>>>v.v>.>.v..>.v>..v>....vv>.>.v.....>v>.>.>.v>v.>.>v>v....v.>...>.v.......
.v...v.....>>v.>vv.>v.>>.>.v>>.v...>>.v..v.vv>>.v...>>>v.>v>>..>>...vv.v>v.>..>v>.>v>>..>>.v...>..>.>..vv.....>>.>.vv>v>>.>..vv>.v.>v.>.v>v
.vv>...v.>.vv.>>...v..>.vv...>.v.....>>..v..>v.>.>...v>..>v.v>.v.>v....>..>..>..>.>.>.>.>..>.>.>.>..v..v>>v.>.v>>.....v..>.v.....v>..v....v
.....v>v..vvvv...v>..>.v.vv.>.>.......v.>..v..vvv.....vvv..>...>.v.>v.>v..>....v>.>>...v>...v>..v>v....v...v.v.>.>v>...v.vv.>...v.>>v>v>..>
>v...>...>..>.v.>>>>.>v.vv>vv>.>.>.......v>>v.>vv...>>.>..v..v>vv..>.>..>v..>v>>>.v>>v.>.>..>...>>..v..v>>v.>vv>>.vvv>..v.>vvv..>..v>vv..vv
..vv.>v...>>........v.....>>..>>..>........>>vv.>.>.....vvv.vvvv>>.>..v.>v>...v.v..vv...v.v..v..>>v...v.>>>>...vvv>>>v>...>vv>v>.vvv..>v..>
..>.........vv.>....v>>.>>vv....>>vv....>..>.>...v..vv.v>..>v>.>v>>.>>>...vv>.......v..v>v>.>.>vvv.>...>.v.>>v>.v>>....v..v........vv.>>.vv
..v.>>v.v..>..>>.v..>.v>>>...>..vv>v.>...>...v.vv>.>.v>..>v.vv.......v...vv>.>vvv.>...>>.v.vv...>..vv..v>...v...>>>....>.>v.>.v...v......vv
>vvv>.vv..>>.>....v..v>>>>v.>.>v....v.v...>>>..v.>..>v..>.vvv..v>.v>.v......>.v.v>>v.v.>.v...>.v.>vv.v>v..>..>>>.>v>>.vvv>>vv>.>v.>..vv.vvv
>>>..>v.v>.vv.v>v>vv...v........v>.>.....v>v..v.>>>.>v..vv..>....vv.v>..v....>>>>vv...>v..v>.v.vv.>..>vv.vv...>>..>>.....vv..v>>..>....vvvv
v>......vv>>.vv..v>v.v>>..v...>.v.>...>>..vv.>...vvvv.>v.>...>v.vvvvv..>>.....>v.>....>....>.>.>v..>.v.vvvvv..v..>vv.v>.v.v...>v.>..v>..>..
.v>>>>..vvv>v.vv>.v>vv..vv.v.vv.>>v>.>..>.v>v....>....v>>>.>.v.vvv.>>...v..>v>...v.v>>v>>v.v...v.v...vvv>>v.>.>...>v..>....>>.>..>.vvv>.v>.
>>.v...>.v>...v>v..v.vv.v..v.v.>...v>v.>.>>.v.>.v>>>.>>.>..>....v..v>>>.v>>.>..>>.>.vv.>>.vv.>>>v>.>>.>.v....v>....>..vvvv....v....v.v.v>vv
>..v>vv>.>v.>.....v.>vvv>..>.>.vv>>>..>.....>..>v>.v...>v..>...v...vv..v>>>v.>>..vv>>..>.>>>v.>..>v...v.v..>.>..>.>>..>.v.v>....>...v...v..
>.>.v...v..vv.>>>vv.vvv..>...vv.vv>...v.v>>>>.>.>>v.>..vv...>v>>v>..>..>vv..vv>>.v>>...>.>v...>..>.>>>.......>.>>.>.>....v.v.............>v
...v>.vv..vv...>v>..>>.v..vv.>.v..v..>..>>.>vvvv.vvv.>>vv>v>.>>v>..>...v>...v...v>>.>..>.>.>v>.v..>>......>v...>v>v.>>.....v>..>.>>>>v.v.>>
.v..vv>....>>...v>.v.v.>.>>....>..v>>.v>v..>......>v...v.>.v......v..>v..>....v.vvv.v..>vv..v.>..v..>>>....>>>>v.>.....v>>.>..v..v>v.v..>..
v>......v..v..v>.....>v>>.>v>v>.>>v>v>v>>...>.....v>.v>...v...v.....>>...v...>.vv..vv..>.>>...>v.>.vv>..v.v>..vv..vvvv.>v..>....v>.>..vv.>>
>.>..v>v..>.vv>>.v>>>>>v>....v.v.>vv..>>...v>v>v.vv>.>>>..>.>v.>>v......>>.>v..v>.vv...vv.v.vv>.>....>.>v...>.v..>.>..vv>..>.vvv.>>>v.v....
>.>.vvv.v>.>vvv...v.>..>.v.>.......>.>....v..>..>...>v..>v....v..>v.v>v.v.>..v.vvvv>>v>.>>.>>>...>..>v>..>v.>v.v..v>>vv.>..v.v>vv...vv>..v.
.v>v.v..>...v>v>.>vvv.>.v.....v.>.>>..v>v>.v.>.>....>.v..v.>v.v>.>.v.vv..v>>v>vv....>>....>vv>v>v>>.v..>.vv..>>>......>>>>..v>v>v>.>>..v..v
..>v.vv..>>v>v.v.......vvvv>vv.v>.v...v>v>>.v>.>.v>..vv...>v.>...v.>v>..v>.vv>....>>..v.>.>vv.vvv.>....v...v>.>..vvv>.>>vvvv>>v....>..>>.>.
.v.v.>vv>.>...v...vv.....v...v>>.>v.>vv>.>>....>>...v.vvv..>>..v.>vvvvv>..v.>....>v.>.......v.>.v.v.>..>>v>vv>>vv.>v.>v>>..>.v>.vv..v..vv.>
...vv.v...vv....>..>..v.>>v>v.>.v...>...v>...v>>v...>v.>>.v...v>>v...>..>v..v>..v..>.v>.>.>..v...vv>v.>.vv>>>..>>>vv.>..vvv..v.>.>..vvv>.v.
.>>.v.>.>..v>..>v>..v>.v.v>>.vvv..vv.>v.>>.>.v.vv.v.vv>.>.vv>.>..v>>.>.v.>v..>>v...v..v>>.>.v>.>.>v..v.v.>>>vv.v.>...v..>v.....>vv..v>.>>>>
.>.....>v>>>>....v..>>>vv...v.>>>v..v>vv>>.>.v.>.>v>.v>v..>..v.v...v..v.>.>>...v.>>v.v>vv.v..>.v>.>>vv...v.v...>>....v.>..vv..vv....v>.....
..v>.>v..v>...v>.>..>...vv>v>vv.>...vv>>..v>.v.>....>....v..>v>.>...v>>vvv....v.v..v>.vv.v.vv.v..>v>>..>...>v>>....v.>>..v.>v.>v.>>v.v.v.v.
.>.v>>>v>.v.vvv...v>....vvvvv>>v.vv>>>>>....>.....>>...vv.>vvv..>.v..vvv.vv>vv>..vv>>vvv...>.>.>.>...vv>.>v.v.v..v>v..v.>.v>>.>vv.>...v.v.>
.>....>>vv.>>>>.>v.>.v..>.>>.vvv>..v..v>..>>.v>.>>>.v.v>>vvv>v...vv.vv..>....>.v..v.>.v>..v....v..vv>v>.>..>..>>>.>>>.v.vvv.v..v......vv.vv
.v.v>>>v.>v.>....>..>.>v.......v>>........vv.v>>>...vvv.>>.>.v.>v.v.>...>v.v.....v.v.>vv>.>>v>>..v>>>..v.v..v......>.v>.>.>>v.v.v.vvv>vv.>.
.>..>....>>.....>.>...v.v....>v>>>v.>.v>.>vv..>v>v>v.>>>>>>v.>>>>>.>.>>.v>......v.v.v.v...>.v..v...>..>>>>>.>.>..>.vv..v>.>..v>.v.v....v.>.
..v>>>>.>>>>....v>v..>>vv.>>..>..v>..vvv>.>..v.>...v>>..>.>>>..vvv.v..>.>.vv>...>vvvv>vv>>>vv..>...>v.>vv....>v.v>..>vv....>v>..v>.v.>v>>v>
.>>.>>>v.>.v>.>.v>.v.>......v...>.v.>..>.vv.>v..v>.v>.v..v...>.vv.v>>.>v.v..>v.>...>>...v.>>v.>>..>v...v.>...v>.>.v..v.>.>....v.>>>>v.>v.>.
>vvv..v.v>>..>..v.>vv.vv>..>vv.v.>...>v..v>>....>>...>>.>>....>...>v>..>>>..>...v.>v.v>.....>..v...>vvv.vv.>>.>v>v.v>v..v>...v..>>.>..v...>
>>.>>...>.>>>..v>>..>v..vv>>>>.v.>>v..vv..>.>..vv.....v.v.v.>..>>>....v.v.>v>>vv....>.....v>v..v>..vv...>..>>v..vv...v.....>vv..v>.>..>.>..
..vv>.v>.....v..>.vv>>...>v...>.v.v>>>........>vvvvv>>.>...>.v.v..v....>.>v>>.v.vv.v..v.vv.>.>v>.>v.>..vv...>>..>.....v...>>>v..v..>.v>>v>.
.vvvv>.>...>>.v..>...vvv>vvv..vv>.>v>.....vv.v..v...v.....>>>v.v>v>>.>v..>>>..>.>v..vv...>vv>.v.>.v..v.>>.....>v.>v>>.vv..v..>..>.>.v....v.
>v>>v...>..>.>>..v..vvv>...>>....>.>>....vv>...>......>..>>v...vv..>>>>>.>v.>.>.vv>>.>>vv....>.v>>..v>>...>v..>...vv..>.>..vvv...>.....>.v.
>..v>.>..vv...v.>>>.v>>.>....v.vv.>..>...>..v..>v.>vv.>..v..>.v.>...vv...v>>..>>vvv...>.>v.>.vv.>v..vv.>>vv.>>..>vv>.v.....>>...v..v.vvv.>>
v.v..vvv>...>v......v....>..>>>.....v>v>>>..v.v..vv.>.>>>>.>.v.>....v.>.>v>vv>vv>v..>.>.v.v>.....>..v>>v...v.....v...v.v.vv>>........v.>.v>
.v>>...>>v>.>...v.>>>....>v>>v.>.v.>>v.v>.>>...>.v.v...vv>v....v>v..>>.>v>.>..>vv.v>>.>..v>>v...>v>>>..v..>v>vv.vv>............>v..>vv.v.vv
>.....>vv.>...v>vvvv>vvv..vvv>.v.>...>v..vv>vv.>>>.v..v>v.>..vv.v.>>v....v...v.....>.v.>.>..>.v>..>v..>>>>>>>v..vv>.v.v>v.v>..>....>>>v>.vv
v.>.v>v.v>...>>>..v>..>>.>..v.v....>.>....v.>..>>>.>v.>.>.>vv..>.>...v.>.....>vv>.>..vv.vvv.>>.vv.>.....vvvv>..v.>.>>v..v..>.>>.>...v>>v..>
v..v>v>..vvv>...v..>.>>...v.v..v..>v..>>.>>.v..>>v...v.vv..v..>...v...v....>v.v.v.v.>.v>vvv.v.v>...>v>.>..>v.v>v>v..v..>>>>...>v.....v.>..v
v>v..v..>..v>.....>>>.v..>v>v..>..>v>...v..>....v...v>>vv.....v.vv...v>....v>..v>>.v.>.>>..>v>..>>>vv.>>>...>...v>vv>v>...>..v.v..>.....>>.
vv..>>v..>>>.>...v..v.>v>..v.>>>>>v..v>v>..>v>>>v.....v..>.>.>>vv.v....v.....>v......>.>vv..vv>.vv..vv...vv.v...>.v..>.>.v>v...v>..vv...>vv
.>...vv>>>.v.....v....>.v......vvvv>.>..>vv>v..vv..>v>>.>v.v>.v>v.vvvvv.v>v......v.>v>vv..>v..>vv.v.v.vvv..>.>.>>v.v.......>vv..v.vv>.>.v..
....v...v.>.v>>>v.>.....>>v>..v>.v.>.v.>..>v.>vv>>vv.>........v..>v>.v>>v>>v.>....>.>...>.>.v.......v....v>vvv..v>..>..v>....v...>.v.>.v...
..vvv.v>.>...>>.vvv>...v...>..>..>...v>v>..>>.vv....>.v.v.>.v>vv.>>v..v>.v.v..v.>.>>.v.....>.v...v>.....v....v.v.v.>>....v.v>>>.......>vv.v
...v>v>..v.v.v...>v>.vvv.vv..>..v.>v.>vv.>.>>..v....>.v.....>.v>..>..v>>vv..vv.>....v>>.v>...>.>vv....v>>.>>v>....>.v.v>v>>>>...>....>.>..v
.>>..v.>v..>>>v.v.v>>...>>v...v>....>.v>>...v.>.v.>...v>>vv.vvv>v....v>.v.>v......v.v.>>.>v...v...>vv.v.....>...>.>..vv.v..>..>.v>..>.v>.vv
>..>.>.>>.v.v.>.v.vvv....>.v>v.v..v.v...>...vv..>>.>..>>>...v>.>.v..v.>>.......v.....>.v>vv.>.v..vv>>>>>>v...vvv..vvv>>>.v.>.v..v.v>v>v>..>
v..>.v.vv>>vvvvv.....v>>v...vv....v>.>>v.v.>.>>v.vv....vv..v.>>.v.v.>v>....>....v.v>>>.>v.v.>v>v.v.v..>.>v>v......v.v>...>v.vvv...v>...vv..
>>vv.....v...v......>v.v..v>..v.v>..>>>.>>..>v>.v>>>.>v..>>>>v.>..vvvv.v>...v..vv.>.>v....>v.>>.....v>v....v..>.>.v>v.>.>.>v.v..>v.........

Sometimes you have to handle grids of variable sizes.

Actual input (139x137)

y2021 - Day 25: Sea Cucumber

struct Grid<const W: usize, const H: usize> {
    cells: [[Option<Cell>; W]; H],
}

You can use const generics to define a matrix
with configurable dimensions

y2021 - Day 25: Sea Cucumber

struct Grid<const W: usize, const H: usize> {
    cells: [[Option<Cell>; W]; H],
}

pub fn test_readme(input: &str) -> usize {
    let mut grid1: Grid<10, 9> = input.parse().unwrap();
    // ...
}

pub fn part1(input: &str) -> usize {
    let mut grid1: Grid<139, 137> = input.parse().unwrap();
    // ...
}

Parsing

(Ergo, extracting data from text)

y2020 - Day 14: Docking Data

mask = 000000000000000000000000000000X1001X
mem[42] = 100
mask = 00000000000000000000000000000000X0XX
mem[26] = 1
...
enum Instr {
    Mask(String),
    Mem(u64, u64),
}
use std::str::FromStr;

impl FromStr for Instr {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if s.starts_with("mask") {
            Ok(Instr::Mask(s[7..].to_string()))
        } else if s.starts_with("mem") {
            let addr_value = &mut s[4..].split("] = ");
            let addr: u64 = addr_value.next().unwrap().parse().unwrap();
            let value: u64 = addr_value.next().unwrap().parse().unwrap();
            Ok(Instr::Mem(addr, value))
        } else {
            Err(format!("Invalid line found: {s}"))
        }
    }
}
let mask: Instr = "mask = 00000000000000X1001X".parse().unwrap();
assert_eq!(mask, Instr::Mask("00000000000000X1001X".to_string()));

let mem: Instr = "mem[42] = 100".parse().unwrap();
assert_eq!(mem, Instr::Mem(42, 100));
let mask: Instr = "mask = 00000000000000X1001X".parse().unwrap();
assert_eq!(mask, Instr::Mask("00000000000000X1001X".to_string()));

let mem: Instr = "mem[42] = 100".parse().unwrap();
assert_eq!(mem, Instr::Mem(42, 100));

Implementing the FromStr trait, will make the parse() method available!

oops, I did it again:
unnecessary allocations! 🤷

Why don't you just take a slice from the input rather than allocating a String?

enum Instr<'a> {
    Mask(&'a str),
    Mem(u64, u64),
}


impl<'a> FromStr for Instr<'a> {
    type Err = String;

    fn from_str(s: &'a str) -> Result<Self, Self::Err> {
        if s.starts_with("mask") {
            Ok(Instr::Mask(&s[7..]))
        } else if s.starts_with("mem") {
            let addr_value = &mut s[4..].split("] = ");
            let addr: u64 = addr_value.next().unwrap().parse().unwrap();
            let value: u64 = addr_value.next().unwrap().parse().unwrap();
            Ok(Instr::Mem(addr, value))
        } else {
            Err(format!("Invalid line found: {s}"))
        }
    }
}
enum Instr<'a> {
    Mask(&'a str),
    Mem(u64, u64),
}


impl<'a> FromStr for Instr<'a> {
    type Err = String;

    fn from_str(s: &'a str) -> Result<Self, Self::Err> {
        if s.starts_with("mask") {
            Ok(Instr::Mask(&s[7..]))
        } else if s.starts_with("mem") {
            let addr_value = &mut s[4..].split("] = ");
            let addr: u64 = addr_value.next().unwrap().parse().unwrap();
            let value: u64 = addr_value.next().unwrap().parse().unwrap();
            Ok(Instr::Mem(addr, value))
        } else {
            Err(format!("Invalid line found: {s}"))
        }
    }
}
enum Instr<'a> {
    Mask(&'a str),
    Mem(u64, u64),
}


impl<'a> From<&'a str> for Instr<'a> {
    fn from(s: &'a str) -> Self {
        if s.starts_with("mask") {
            Instr::Mask(&s[7..])
        } else if s.starts_with("mem") {
            let addr_value = &mut s[4..].split("] = ");
            let addr: u64 = addr_value.next().unwrap().parse().unwrap();
            let value: u64 = addr_value.next().unwrap().parse().unwrap();
            Instr::Mem(addr, value)
        } else {
            panic!("Invalid line found: {s}")
        }
    }
}
enum Instr<'a> {
    Mask(&'a str),
    Mem(u64, u64),
}


impl<'a> From<&'a str> for Instr<'a> {
    fn from(s: &'a str) -> Self {
        if s.starts_with("mask") {
            Instr::Mask(&s[7..])
        } else if s.starts_with("mem") {
            let addr_value = &mut s[4..].split("] = ");
            let addr: u64 = addr_value.next().unwrap().parse().unwrap();
            let value: u64 = addr_value.next().unwrap().parse().unwrap();
            Instr::Mem(addr, value)
        } else {
            panic!("Invalid line found: {s}")
        }
    }
}

This panic gives me anxiety 😰

use std::convert::{TryFrom, TryInto};

enum Instr<'a> {
    Mask(&'a str),
    Mem(u64, u64),
}

impl<'a> TryFrom<&'a str> for Instr<'a> {
    type Error = String;

    fn try_from(s: &'a str) -> Result<Self, Self::Error> {
        if s.starts_with("mask") {
            Ok(Instr::Mask(&s[7..]))
        } else if s.starts_with("mem") {
            let addr_value = &mut s[4..].split("] = ");
            let addr: u64 = addr_value.next().unwrap().parse().unwrap();
            let value: u64 = addr_value.next().unwrap().parse().unwrap();
            Ok(Instr::Mem(addr, value))
        } else {
            Err(format!("Invalid line found: {s}"))
        }
    }
}
let mask: Instr = "mask = 00000000000000X1001X".try_into().unwrap();
assert_eq!(mask, Instr::Mask("00000000000000X1001X"));

let mem: Instr = "mem[42] = 100".try_into().unwrap();
assert_eq!(mem, Instr::Mem(42, 100));

Implementing the TryFrom trait, will make the try_into() method available!

y2022 - Day 15: Beacon Exclusion Zone

Sensor at x=2, y=18: closest beacon is at x=-2, y=15
Sensor at x=9, y=16: closest beacon is at x=10, y=16
Sensor at x=13, y=2: closest beacon is at x=15, y=3
Sensor at x=12, y=14: closest beacon is at x=10, y=16
...
struct Pos {
    x: i64,
    y: i64,
}
let sensor = Pos {
    x: 13,
    y: 2,
}
let beacon = Pos {
    x: 15,
    y: 3,
}

😱

use regex::Regex;

fn parse_line_regex(line: &str) -> (Pos, Pos) {
    let re = Regex::new(
        r"Sensor at x=(?P<x1>[-]?\d+), y=(?P<y1>[-]?\d+): closest beacon is at x=(?P<x2>[-]?\d+), y=(?P<y2>[-]?\d+)",
    )
    .unwrap();

    let captures = re.captures(line).unwrap();
    let sensor = Pos {
        x: captures["x1"].parse().unwrap(),
        y: captures["y1"].parse().unwrap(),
    };
    let beacon = Pos {
        x: captures["x2"].parse().unwrap(),
        y: captures["y2"].parse().unwrap(),
    };
    (sensor, beacon)
}
use regex::Regex;

fn parse_line_regex(line: &str) -> (Pos, Pos) {
    let re = Regex::new(
        r"Sensor at x=(?P<x1>[-]?\d+), y=(?P<y1>[-]?\d+): closest beacon is at x=(?P<x2>[-]?\d+), y=(?P<y2>[-]?\d+)",
    )
    .unwrap();

    // ...
    (sensor, beacon)
}

pub fn parse_regex(input: &str) -> impl Iterator<Item = (Pos, Pos)> + '_ {
    input.lines().map(parse_line_regex)
}

Aren't we re-istantiating the Regex over and over? 🤷

How can we initialize the regex globally?

$ cargo add lazy_static
#[macro_use]
extern crate lazy_static;
use regex::Regex;

lazy_static! {
    static ref LINE_REGEX: Regex = Regex::new(r"Sensor at x=(?P<x1>[-]?\d+), y=(?P<y1>[-]?\d+): closest beacon is at x=(?P<x2>[-]?\d+), y=(?P<y2>[-]?\d+)")
        .unwrap();
}

fn parse_line_regex(line: &str) -> (Pos, Pos) {
    let captures = LINE_REGEX.captures(line).unwrap();

    // ...
    (sensor, beacon)
}

pub fn parse_regex(input: &str) -> impl Iterator<Item = (Pos, Pos)> + '_ {
    input.lines().map(parse_line_regex)
}

🤷 BTW,

should I tell you that when you solve a problem with a Regex... BLAH BLAH BLAH?!

Ok, let's do proper parsing with nom! 💪

$ cargo add nom
fn parse_i64(input: &str) -> IResult<&str, i64> {
    let (input, sign) = opt(tag("-"))(input)?;
    let (input, value) = digit1(input)?;
    let mut value = value.parse::<i64>().unwrap();
    if sign.is_some() {
        value *= -1;
    }
    Ok((input, value))
}
fn parse_line(input: &str) -> IResult<&str, (Pos, Pos)> {
    let (input, (s_x, s_y, b_x, b_y)) = all_consuming(tuple((
        preceded(tag("Sensor at x="), parse_i64),
        preceded(tag(", y="), parse_i64),
        preceded(tag(": closest beacon is at x="), parse_i64),
        preceded(tag(", y="), parse_i64),
    )))(input)?;
    let p1 = Pos { x: s_x, y: s_y };
    let p2 = Pos { x: b_x, y: b_y };
    Ok((input, (p1, p2)))
}

Which one do you think is faster? 🧐

regex

regex_lazy

nom

1.

2.

3.

Which one do you think is faster? 🧐

regex

regex_lazy

nom

1.

2.

3.

Which one do you think is faster? 🧐

regex

regex_lazy

nom

1.

2.

3.

3063.9 µs

9.3 µs

1.8 µs

⭐️

+170117%

+417%

  • The Iterator & the FromIterator traits
  • Destructuring with if let Some(x) / while let Some(x)...
  • Powerful pattern-matching syntax and the matches!() macro
  • Newtype pattern + Deref & DerefMut trait
  • The Display & Debug traits
  • unreachable!() & todo!() macros
  • defaultdict a-la-python using HashMap and the entry API
  • Copy On Write (CoW)
  • Helper methods of the Result and the Option types

I would have also loved to tell you about... 🤯

  • Started with a very imperative style and ended up with a more functional style
    • "if you look back at your code from 2 years ago and you are not ashamed you are not growing"
  • Noticed that rust has been improving a lot in these 3 years
    • Often needed helpers but they were in nightly (Vec::retain)
    • Rust Analyser & Clippy have been suggesting new improvements over time!
  • Rust is fantastic for Advent of Code!

🦀 In conclusion...

Photo by Nathan Dumlao on Unsplash

Never stop learning!

Huge thanks to @gbinside, @AlleviTommaso, @giufus
Cover photo by Redaviqui Davilli on Unsplash

TNX

Sorry, I have a contractual obligation to put this here 😛

What I learned by solving 50 Advent of Code challenges in Rust - RustNation UK 2023

By Luciano Mammino

What I learned by solving 50 Advent of Code challenges in Rust - RustNation UK 2023

In 2020 I started to be a bit more serious about learning Rust. After having read a few books and having done some coding challenges, I decided to start live-streaming my attempts to solve Advent of Code challenges using Rust. Fast forward to 2022 I completed 50 challenges and learned a lot about how to use Rust to solve specific programming challenges. In this talk, I’ll be sharing some common tips and tricks that I discovered while live-coding also thanks to the beautiful Rust community that gave me tons of suggestions! Some topics I’ll be covering in this talk: parsing input, data structures, error handling, iterators, performance, allocating and manipulating 2d matrices, etc.

  • 3,024