# Learning Python with Advent of Code Walkthroughs

Dazbo's Advent of Code solutions, written in Python # Advent of Code 2022 - Day 2

## Problem Intro

We’re told we’re going to play Rock, Paper, Scissors with the elves. But we’ve been given a piece of paper that tells us what our opponent will do, and what we should do!

Our input data contains many lines, with each line having two columns.

• Column 1 is what our opponent will do. A=Rock, B=Paper, C=Scissors
• Column 2 is what we should do. But how we interpret this instruction depends on whether we’re in Part 1 or Part 2, of course!

The input data looks something like this:

``````A Y
B X
C Z
``````

For each hand we play, our score is the sum of the following:

• 0 for lose, 3 for draw, 6 for win
• 1 if we play Rock, 2 if we play Paper, 3 if we play Scissors:

Our total score is the sum of the scores for all the hands we play.

## Part 1

Treat the second column as what we must play. X=Rock, Y=Paper, Z=Scissors

What is our final score?

To be honest, the code is so trivial it hardly needs explaining. Must of how it works is documented in the code itself.

Here it is…

``````from pathlib import Path
import time

HAND = {
"ROCK": "A",
"PAPER": "B",
"SCISSORS": "C"
}

SCORES = {
HAND["ROCK"]: 1,
HAND["PAPER"]: 2,
HAND["SCISSORS"]: 3,
"LOSE": 0,
"DRAW": 3,
"WIN": 6
}

RULES = {
# (Their hand, my hand)
(HAND["ROCK"], HAND["SCISSORS"]): SCORES["LOSE"],
(HAND["ROCK"], HAND["ROCK"]): SCORES["DRAW"],
(HAND["ROCK"], HAND["PAPER"]): SCORES["WIN"],
(HAND["PAPER"], HAND["ROCK"]): SCORES["LOSE"],
(HAND["PAPER"], HAND["PAPER"]): SCORES["DRAW"],
(HAND["PAPER"], HAND["SCISSORS"]): SCORES["WIN"],
(HAND["SCISSORS"], HAND["PAPER"]): SCORES["LOSE"],
(HAND["SCISSORS"], HAND["SCISSORS"]): SCORES["DRAW"],
(HAND["SCISSORS"], HAND["ROCK"]): SCORES["WIN"]
}

SCRIPT_DIR = Path(__file__).parent
INPUT_FILE = Path(SCRIPT_DIR, "input/input.txt")

def main():
with open(INPUT_FILE, mode="rt") as f:

# Part 1
rounds = play_rounds(data)
scores = play_part_1(rounds)
print(f"Part 1: Your score = {sum(scores)}")

def play_part_1(rounds: list):
""" Here we treat X, Y, Z as whether we play Rock, Paper, Scissors, respectively.
Calculate our score for each hand based on what hand we play, and whether we win, lose or draw. """
scores = []
zyz_to_rps = {"X": HAND["ROCK"], "Y": HAND["PAPER"], "Z": HAND["SCISSORS"]}
for this_round in rounds:
their_hand, my_hand = this_round
my_hand = zyz_to_rps[my_hand]

this_score = 0
this_score += SCORES[my_hand]
this_score += RULES[(their_hand, my_hand)]
scores.append(this_score)

return scores

def play_rounds(data: list[str]) -> list:
""" Returns a list. Each element in the list is a pair as a list, e.g. ["A", "X"] """
rounds = []
for this_round in data:
rounds.append(this_round.split())

return rounds

if __name__ == "__main__":
t1 = time.perf_counter()
main()
t2 = time.perf_counter()
print(f"Execution time: {t2 - t1:0.4f} seconds")
``````
• When I read in the input data, I create a new `list`, where each list item is itself a pair of items. The first item in the pair - i.e. `this_round` - is what our opponent did. The second item - i.e. `this_round` - is what we must do.
• I’ve extracted all the game rules - e.g. rock beats scissors, paper beats rock, etc - into a separate dictionary. This avoids the need for lots of `if... elif... else` statements.

## Part 2

Now, we must treat the second column as the outcome required. X=Lose, Y=Draw, Z=Win

What is our final score?

Okay, so we need to extend our rules…

``````REQUIRED = {
"LOSE": "X",
"DRAW": "Y",
"WIN": "Z"
}

RULES = {
# (Their hand, my hand): score
(HAND["ROCK"], HAND["SCISSORS"]): SCORES["LOSE"],
(HAND["ROCK"], HAND["ROCK"]): SCORES["DRAW"],
(HAND["ROCK"], HAND["PAPER"]): SCORES["WIN"],
(HAND["PAPER"], HAND["ROCK"]): SCORES["LOSE"],
(HAND["PAPER"], HAND["PAPER"]): SCORES["DRAW"],
(HAND["PAPER"], HAND["SCISSORS"]): SCORES["WIN"],
(HAND["SCISSORS"], HAND["PAPER"]): SCORES["LOSE"],
(HAND["SCISSORS"], HAND["SCISSORS"]): SCORES["DRAW"],
(HAND["SCISSORS"], HAND["ROCK"]): SCORES["WIN"],

# (Their hand, my goal): score-for-my-hand
(HAND["ROCK"], REQUIRED["LOSE"]): SCORES[HAND["SCISSORS"]],
(HAND["ROCK"], REQUIRED["DRAW"]): SCORES[HAND["ROCK"]],
(HAND["ROCK"], REQUIRED["WIN"]): SCORES[HAND["PAPER"]],
(HAND["PAPER"], REQUIRED["LOSE"]): SCORES[HAND["ROCK"]],
(HAND["PAPER"], REQUIRED["DRAW"]): SCORES[HAND["PAPER"]],
(HAND["PAPER"], REQUIRED["WIN"]): SCORES[HAND["SCISSORS"]],
(HAND["SCISSORS"], REQUIRED["LOSE"]): SCORES[HAND["PAPER"]],
(HAND["SCISSORS"], REQUIRED["DRAW"]): SCORES[HAND["SCISSORS"]],
(HAND["SCISSORS"], REQUIRED["WIN"]): SCORES[HAND["ROCK"]]
}
``````

And then we just add a new function to apply the new rules:

``````def play_part_2(rounds: list):
""" Here we treat X, Y, Z as whether we play Lose, Draw, or Win, respectively.
Determine what hand we should play to achieve that outcome.
Then calculate our score for each hand based on what hand we chose, and whether we win, lose or draw. """
scores = []
xyz_to_ldw = {"X": SCORES["LOSE"], "Y": SCORES["DRAW"], "Z": SCORES["WIN"]}
for this_round in rounds:
their_hand, my_goal = this_round
this_score = 0
this_score += xyz_to_ldw[my_goal]
this_score += RULES[(their_hand, my_goal)]
scores.append(this_score)

return scores
``````

And then add this to our `main` method:

``````    scores = play_part_2(rounds)
print(f"Part 2: Your score = {sum(scores)}")
``````

## Results

The output looks like this:

``````Part 1: Your score = 13221
Part 2: Your score = 13131
Execution time: 0.0017 seconds
``````