# Cracking Challenges: Strategies for Advent of Code 2022 and Hackerrank

## Discover the prowess of Rust as we dive into challenges. Uncover the magic of Rust's regex engine for time conversion and master matrix calculations

## Prologue

Embarking on the #100DaysOfCodeChallenge has been an incredible experience so far. Every day brings new learning opportunities, and I'm thrilled to share my journey with you. Today, I'll be diving into days 2-17 of my challenge, where I tackled the Advent of Code 2022 day 2 puzzle and ventured into the world of hackerrank. I will break the post into two parts, so jump to whatever section interests you:-

Advent of Code 2022 Day 02

Hackerranks

Hope you enjoy the read, let's gooooo.

## AoC 2022: 02

You can find the advent puzzle here:-

The summary is very simple. You have a list of tuples--each with 2 elements-- to indicate what an opponent would take for Rock-Paper-Scissors(RPS) and the other, yup we don't what the other thing is in the first half. So we assume it is what we should take. Now, the **task is to find the sum of scores if nothing goes south**.

So, first, we see that we need scores for each `Y`

and the outcome *encoded* into our program. Thank god, *rust*'s `Enums`

are powerful. For more information, please have a look at this video.

From the task, we can get the score details for the play:

```
enum Points {
Rock = 1,
Paper = 2,
Scissors = 3,
}
```

Now, for each tuple, we could...

```
Points::Paper + outcome_value
```

but wait, rustc is not happy, it seems like, it couldn't figure out how to add `i32`

with `Points`

. But rustc being *rustc,* the error message just tells us what to do.

```
impl std::ops::Add<i32> for Points {
type Output = i32;
fn add(self, other: i32) -> i32 {
self as i32 + other
}
}
```

We could encode the `outcome_value`

, but since I am just learning the rust, I decided not to as this would overcomplicate the codebase. That would be too much because I encoded other **magic values** into the Rust's type system.

```
// this is to see what the first column of the tuple is,
// i.e. what the opponent will take.
enum Opponent {
Rock,
Paper,
Scissors,
}
// this is same as Opponent above, but for me, the second column.
enum Me {
Rock,
Paper,
Scissors,
}
```

Note that I could have done this with a single

`enum Play`

but the duo of columns contain different presentations for the values, so encoding would be harder.

Let's also create 2 helper functions to convert our input `A|Y`

into our internal representation `Opponent::Rock|Me::Paper`

.

```
fn parse_opp(h: &str) -> Option<Opponent> {
match h {
"A" => Some(Opponent::Rock),
"B" => Some(Opponent::Paper),
"C" => Some(Opponent::Scissors),
_ => None,
}
}
fn parse_me(h: &str) -> Option<Me> {
match h {
"X" => Some(Me::Rock),
"Y" => Some(Me::Paper),
"Z" => Some(Me::Scissors),
_ => None,
}
}
```

I decided to return an `Option<Opponent|Me>`

as the input contains a blank line at the EOF. I discovered a solution lately to eliminate a bunch of boilerplate from the codebase, so stick around till the end.

Now all we have to do is to

iterate over the tuples,

determine the scores,

sum up,

then, finally sum up the whole rounds.

```
let sum = vec_with_each_line.iter()
.map(|l| {
let split: Vec<&str> = l.split(" ").collect();
if split.len() > 1 {
match parse_opp(split[0]) {
Some(Opponent::Rock) => match parse_me(split[1]) {
Some(Me::Rock) => Points::Rock + 3,
Some(Me::Paper) => Points::Paper + 6,
Some(Me::Scissors) => Points::Scissors + 0,
_ => 0,
}
// --snip-- for brevity
}
}else {
// because of that EOF line.
0
}
}).sum::<i32>();
```

The essence is `match parse_opp(split[0])`

and the `parse_me()`

. Then as trivial, I check what I have and then return the appropriate score. The tricky part is to think when we win or lose and it is a draw. Wrap your brain around and patiently figure it out.

Keep in mind, that we cannot just consider what the Opponent would take, as winning every round might raise suspicion!

Well in the next half, it turns out the second column is how that round should end. This may sound like we need to rewrite the program, but we only have to change the `match`

statements.

Since this is just like the above, here is the code. Have a look at it.

```
let second_sum: i32 = rounds
.iter()
.map(|s| {
let split: Vec<&str> = s.split(" ").collect();
if split.len() > 1 {
match parse_opp(split[0]) {
Some(Opponent::Rock) => match parse_outcome(split[1]) {
Some(Outcome::Lose) => Points::Scissors + 0,
Some(Outcome::Draw) => Points::Rock + 3,
Some(Outcome::Win) => Points::Paper + 6,
_ => 0,
},
Some(Opponent::Paper) => match parse_outcome(split[1]) {
Some(Outcome::Lose) => Points::Rock + 0,
Some(Outcome::Draw) => Points::Paper + 3,
Some(Outcome::Win) => Points::Scissors + 6,
_ => 0,
},
Some(Opponent::Scissors) => match parse_outcome(split[1]) {
Some(Outcome::Lose) => Points::Paper + 0,
Some(Outcome::Draw) => Points::Scissors + 3,
Some(Outcome::Win) => Points::Rock + 6,
_ => 0,
},
_ => 0,
}
} else {
0
}
})
.sum();
```

That's it for AoC 2022 Day 02. See you with another one.

## Hackerrank

Meanwhile, I also checked out the hackerrank warmup challenges. For a beginner, I recommend these. These challenges helped me figure out a much in the rust `std`

library. Here are some challenges, I think are worth going for.

### Diagonal Difference

Please check this link for the challenge. The task is to find the **absolute difference of sums of diagonals of a square matrix**. With a little bit of *math* background, we can achieve this as...

```
let n = arr.len();
let (x,y) = (0..n)
.fold((0,0), |(x,y), i| {
(x + arr[i][i], y + arr[i][n-1-i])
});
(x-y).abs() // the answer
```

The trick up the sleeve is, `arr[i][i]`

gives the `i`

th **primary** diagonal value in a **square** matrix. And the `arr[i][n-(i+1)]`

gives the `i`

th **secondary** diagonal value of a **square** matrix.

The code above achieves this algorithm by-

creating a range from

`0`

to`array length, n`

:`(0..n)`

(note that this is exclusive of`n`

)using the

`fold`

iterator. Starting from`(0,0)`

each representing each sum of diagonals.Then after, indexing the correct value in the 2D array (

*the*square matrix),*closure*given to`fold`

updates the folding values using`(x + arr[i][i], y + arr[i][n-1-i])`

, here`x`

is the sum of the**primary**and`y`

is the sum of**secondary**diagonals.When all is done, returned value due to folding is then extracted as

`x`

and`y`

using*pattern matching.*Finally, the ab

**solute**value is calculated using,`(x-y).abs()`

.

Even though there are many challenges in the warmup sequence, I decided to write about this one, because it took me a great deal of time to properly get the sums of the diagonals. I then asked ChatGPT to give me a solution. After a few trials of asking it to reduce the loops, we both arrived at this handy-dainty trick.

I don't know where ChatGPT trained this technique, but a salute to whoever posted it online first.

### Time Conversion

This one also stays in my heart, as this was my first encounter of the **regex** in Rust. I could have only used the `String`

methods, but I decided to give **regex** a go because Rust is known for its state-of-art SIMD regular expression engine.

According to the challenge statement, I decided this...

```
Regex::new(
r"(\d{2}):(\d{2}):(\d{2})([AP])"
).unwrap();
```

...expression would capture what I need. If you want to know more about **regex** or are a beginner to it, please check out my comprehensive **regex post****.**

One can easily spot out, I used *capture groups*. Since of this, I can easily reuse the input string and also determine what to do. Apart from the *expression* and the *captured groups indexing;* nothing special going on. All else is trivial clock logic we learned in primary schools.

```
fn timeConversion(s: &str) -> String {
let r = Regex::new(
r"(\d{2}):(\d{2}):(\d{2})([AP])M"
).unwrap();
let c = r.captures_iter(s).next().unwrap();
match &c[4] {
"A" => match &c[1] {
"12" => format!("{}:{}:{}", "00", &c[2], &c[3]),
_ => format!("{}:{}:{}", &c[1], &c[2], &c[3])
},
"P" => match &c[1] {
"12" => format!("{}:{}:{}", &c[1], &c[2], &c[3]),
_ => format!("{}:{}:{}", (12 + atoi(&c[1])), &c[2], &c[3])
},
_ => panic!("invalid string passed in")
}
}
```

That's all I have got. See you in another one.

## Wrap up

Hope you enjoyed the time being. Catch you up on the next report. Wish it wouldn't be much later as after 17 days next time. Till then this is *meTheBE* signing off, bye.