Jesper Dramsch , , read in 3 minutes

Day 2 of Advent of Code in 2022 is all about playing Rock Paper Scissors.

We get a "strategy guide" and need to figure out how to win this tournament!

What is Advent of Code?

In this little series, I want to write about the thought processes I have behind solving the puzzles presented in Advent of Code.

During the Advent of Code small coding puzzles are presented with varying levels of difficulty. They're always Christmas-themed text puzzles where you help elves out of some mess to save the holidays. The puzzles are deliberately ambiguous to not bias puzzlers into a certain solution, they always have an example input in the text to explain some details and an input file for each day that comes in the form of a text file you can download. The solution is a simple number or a string you enter, which is checked by the website automatically. After you finish part 1, part 2 unlocks, which is a variation on part 2. This can be a little twist on part 1 or a large twist that changes the problem formulation into a problem that would take brute force solutions to compute longer than the heat death of the universe would take.

Find my solutions here: github.com/JesperDramsch/advent-of-code

These descriptions won't be a perfect narrative, but rather how I think about these problems and where I see different solutions. I apologise for the possibility of rambling!

The example input

The example input this time didn't give me all the info I would need:

A Y
B X
C Z

So back to the description!

ABC and XYZ map to rock, paper, and scissors and our final score will be calculated from the value of each choice and wins, draws, or losses.

So we need a scoring function for the games and a map of values.

The Implementation

I decided to map ABC and XYZ to rock, paper, and scissors respectively to have a common vocabulary I could use to evaluate games "naturally".

That makes the scorer and and winner much easier:

def selection_points(player):
    return {"rock": 1, "paper": 2, "scissors": 3}[player]

But more importantly, we can find the winner of a RPS game using a simple dictionary:

winner = {"scissors": "paper", "paper": "rock", "rock": "scissors"}

The points for winning are also simple to calculate:

def winner_points(outcome):
    return {"win": 6, "draw": 3, "lose": 0}[outcome]

Then we simply combine the parts of finding out who wins, and what points result from winning and choosing each turn and sum it up.

Part 2

Now part 2 throws us for a loop. It's the strategy guide!

We know what our opponent throws and we know the outcome we want.

That means we have to backtrack our solution instead. We still get the score in the same way, calculating the wins and our choice, however the choice isn't as easy to calculate as in part 1.

However, our winner little dictionary here turns out to be a good choice, since it's circular:

def strategic_play(player, outcome):
    if outcome == "win":
        play = winner(winner(player))
    elif outcome == "draw":
        play = player
    elif outcome == "lose":
        play = winner(player)
    return play

we know we'll lose, if we pick the winner for our opponent and we know we win, if we go another turn around the three-way game with winner(winner(player)).

Then we'll just take the sum from that selection and the outcome we simply got from XYZ and we have our solution for part 2.

Error Log

Still forgot, but tomorrow we're on!