DEV Community

Nicky Meuleman
Nicky Meuleman

Posted on • Originally published at nickymeuleman.netlify.app

Advent of Code 2022 Day 2

Day 2: Rock Paper Scissors

https://adventofcode.com/2022/day/2

TL;DR: my solution in Rust

We're playing a Rock, Paper, Scissors tournament with the elves.
The input represents an encryped strategy guide.

Each line has 2 letters seperated by a space.

  • The first letter is A, B, or C.
  • The second letter is X, Y, or Z.

An example input looks like this:

A Y
B X
C Z
Enter fullscreen mode Exit fullscreen mode

Each round is worth some points, all scores get summed up, and whoever has the highest total at the end of the tournament wins.

Your score for a single round is the sum of the score for the shape you played, and the score for the outcome of the round.

Shape scores:

  • Rock: 1
  • Paper: 2
  • Scissors: 3

Outcome scores:

  • Loss: 0
  • Draw: 3
  • Win: 6

The first letter in the input is what your opponent is going to play.
Afor Rock, B for Paper, and C for Scissors.

Before the elf can tell you what the second letter means, they leave.

Part 1

Winning every round would be suspicious, so whatever that second letter is, it has to be important.

You assume the second letter is the shape you should play.
Xfor Rock, Y for Paper, and Z for Scissors.

If "Rock", "Paper", and "Scissors" have positions in a list.

  • To win, move 1 position to the right (and wrap around from "Scissors" to "Rock"!)
  • To draw, keep the same position
  • To lose, move 1 position to the left (and wrap around from "Rock" to "Scissors"!)

So I translated both A, B, C, and X, Y, Z to 0, 1, and 2 respectively.
Thankfully, both ABC and XYZ are sequences where the ASCII value of a letter increases by 1 each step.

  • The value for the shape the opponent plays is known.
  • The value for the shape I play is known.
  • To calculate the score for this round, we need to know the outcome of the round.

With those two pieces of information a game of Rock, Paper, Scissors can be expressed as the following equation:

outcome = my_shape - opponent_shape + 1 (mod 3)

This expresses outcome as a number from 0 to 2:

  • 0 for loss
  • 1 for draw
  • 2 for win

The mod 3 handles the wrapping around logic.

pub fn part_1() -> String {
    let input = std::fs::read_to_string("src/day02.txt").unwrap();

    input
        .lines()
        // map every line to the score for that round
        .map(|line| {
            // transform A B C and X Y Z to 0 1 2 respectively by using their ASCII order
            let bytes = line.as_bytes();
            let left = (bytes[0] - b'A') as i8;
            let right = (bytes[2] - b'X') as i8;

            // 0 for rock, 1 for paper, 2 for scissors
            // 0 for loss, 1 for draw, 2 for win
            let opponent_shape = left;
            let my_shape = right;
            let outcome = (my_shape - opponent_shape + 1).rem_euclid(3);

            let shape_score = my_shape + 1;
            let outcome_score = 3 * outcome;
            (shape_score + outcome_score) as u32
        })
        .sum::<u32>()
        .to_string()
}
Enter fullscreen mode Exit fullscreen mode

Part 2

The elf returns and tells you that the second letter in the input is the desired outcome.
X for loss, Y for draw, Z for win.

  • The value for the shape the opponent plays is known.
  • The value for the outcome of the round is known.
  • To calculate the score for this round, we need to know the shape we need to play.

We rearrange the equation from part1 to solve for my_shape instead of outcome:

my_shape = opponent_shape - 1 + outcome (mod 3)

The mod 3 handles the wrapping around logic.

pub fn part_2() -> String {
    let input = std::fs::read_to_string("src/day02.txt").unwrap();

    input
        .lines()
        // map every line to the score for that round
        .map(|line| {
            // transform A B C and X Y Z to 0 1 2 respectively by using their ASCII order
            let bytes = line.as_bytes();
            let left = (bytes[0] - b'A') as i8;
            let right = (bytes[2] - b'X') as i8;

            // 0 for rock, 1 for paper, 2 for scissors
            // 0 for loss, 1 for draw, 2 for win
            let opponent_shape = left;
            let outcome = right;
            let my_shape = (opponent_shape - 1 + outcome).rem_euclid(3);

            let shape_score = my_shape + 1;
            let outcome_score = 3 * outcome;
            (shape_score + outcome_score) as u32
        })
        .sum::<u32>()
        .to_string()
}
Enter fullscreen mode Exit fullscreen mode

Top comments (3)

Collapse
 
liftoffstudios profile image
Liftoff Studios

Awesome Article!!
I also tried doing these challenges in Rust
What's your opinion on this => github.com/Liftoff-Studios/AdventO...
I'd love feedback on mine (although mine is beginner-level code)

Collapse
 
nickymeuleman profile image
Nicky Meuleman

Thank you!
Awesome, Advent of Code is great to learn new patterns and ways of doing things in a different language.
Have fun!

Had a quick look and I can only think of minor things for different ways to do the same thing in Rust.

For example in github.com/Liftoff-Studios/AdventO... you could also loop over a range instead of an array.
It doesn't matter for such a small loop, both ways are perfectly fine.

with the array:

    for i in [0, 1, 2] {
       //
    }
Enter fullscreen mode Exit fullscreen mode

with an inclusive range:

    for i in 0..=2 {
       //
    }
Enter fullscreen mode Exit fullscreen mode
Collapse
 
liftoffstudios profile image
Liftoff Studios

Ah, thank you so much 'bout that tip. I had totally forgotten about using ranges lol
I'll use it from next time :D