Advent of Code 2022 - Day 2: Rock Paper Scissors

:: programming, puzzle, racket

1
2
#lang iracket/lang #:require racket
(require "../advent.rkt")

Day 2 - Part 1

Rock, Paper, Scissors

For example, suppose you were given the following strategy guide:

A Y
B X
C Z

We’re told that A=Rock, B=Paper and C=Scissors, and it’s proposed that X=Rock, Y=Paper and Z=Scissors.

We’re also told the score is computed as follows: add the score of the shape (1 for Rock, 2 for Paper and 3 for Scissors) to the outcome (0 if we lost, 3 if a draw and 6 if we won).

What would your total score be if everything goes exactly according to your strategy guide?

1
(define in (parse-aoc 2 chars))
----------------------------------------------------------------------------------------------------
day02.txt -> 10000 chars, 2500 lines; first 3 lines; last 2 lines:
----------------------------------------------------------------------------------------------------
B Z
C Z
B X
...
C Y
B Z
----------------------------------------------------------------------------------------------------
(parse 2) -> 2500 entries:
----------------------------------------------------------------------------------------------------
((#\B #\Z)
(#\C #\Z)
...
(#\B #\Z))
----------------------------------------------------------------------------------------------------

Parsing gives us a list of pairs of plays e.g. player 1 plays A=Rock, player 2 plays Y=Paper, etc. Let’s define a function that maps a letter to a shape:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
(define (char->shape c)
  (match c
    [ #\A 'rock     ]
    [ #\X 'rock     ]
    [ #\B 'paper    ]
    [ #\Y 'paper    ]
    [ #\C 'scissors ]
    [ #\Z 'scissors ]))

(char->shape #\Y)

’paper

Determine the score of a shape:

1
2
3
4
5
6
7
(define (shape-score shape)
  (match shape
    [ 'rock     1 ]
    [ 'paper    2 ]
    [ 'scissors 3 ]))

(shape-score 'scissors)

3

Determine an outcome:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
(define (outcome us them)
  (match (cons us them)
   [ '(rock     . scissors) 'win  ]
   [ '(rock     . rock)     'draw ]
   [ '(rock     . paper)    'loss ]
   [ '(paper    . rock)     'win  ]
   [ '(paper    . paper)    'draw ]
   [ '(paper    . scissors) 'loss ]
   [ '(scissors . paper)    'win  ]
   [ '(scissors . scissors) 'draw ]
   [ '(scissors . rock)     'loss ]))         

(outcome 'paper 'rock)          

’win

Determine the score of an outcome:

1
2
3
4
5
6
7
(define (outcome-score outcome)
  (match outcome
    [ 'loss 0 ]
    [ 'draw 3 ]
    [ 'win  6 ]))

(outcome-score 'win)

6

Let’s create a round function that accepts a list of characters from the input, e.g. (them us), and computes the score, given the outcome:

1
2
3
4
5
6
7
8
9
(define (round pair)
  (let ([ them (char->shape (first pair))  ]
        [ us   (char->shape (second pair)) ])
    (+ (shape-score us)
       (outcome-score (outcome us them)))))

(list (round '(#\A #\Y))
      (round '(#\B #\X))
      (round '(#\C #\Z)))

’(8 1 6)

The hard part is done, now all we have to do is fold the + and round functions over the list:

1
2
3
(foldl (λ (pair sum) (+ (round pair) sum)) ; function to fold
       0                                   ; initial value
       in)                                 ; list

12458

Part 2

The Elf finishes helping with the tent and sneaks back over to you. “Anyway, the second column says how the round needs to end: X means you need to lose, Y means you need to end the round in a draw, and Z means you need to win. Good luck!”

Ok, it looks like we’ll need a function to map the second column to an expected outcome:

1
2
3
4
5
6
7
(define (expected-outcome c)
  (match c
    [ #\X 'loss ]
    [ #\Y 'draw ]
    [ #\Z 'win  ]))

(expected-outcome #\Y)

’draw

And, we’ll need a function that returns a shape for us to play given the other player’s shape and the expected outcome. Since we already have a function to return an outcome given both players’ choices, we’ll just look through the list of 3 shapes to find the right one:

1
2
3
4
5
6
7
8
9
(define (expected-shape pair)
  (let ([ shapes  (map char->shape '(#\A #\B #\C)) ]
        [ them    (char->shape (first pair))       ]
        [ desired (expected-outcome (second pair)) ])
    (findf (λ (shape)
              (eq? desired (outcome shape them)))
           shapes)))

(expected-shape '(#\A #\Y))

’rock

We’ll redefine the round function with the new information from part 2:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
(define (round pair)
  (let ([ outcome (expected-outcome (second pair)) ]
        [ them    (char->shape (first pair))       ]
        [ us      (expected-shape pair)            ])
    (+ (shape-score us)
       (outcome-score outcome))))

(list (round '(#\A #\Y))
      (round '(#\B #\X))
      (round '(#\C #\Z)))

’(4 1 7)

The fold for part 2 is identical, given the new round:

1
2
3
(foldl (λ (pair sum) (+ (round pair) sum)) ; function to fold
       0                                   ; initial value
       in)                                 ; list

12683

A much simpler solution

Todd Ginsberg used a much simpler solution, and it was a good reminder for me to look for similar opportunities in the future days!

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
;; Part 1
(for/sum ([ pair in ])
  (match pair
    [ '(#\A #\X) 4 ]
    [ '(#\A #\Y) 8 ]
    [ '(#\A #\Z) 3 ]
    [ '(#\B #\X) 1 ]
    [ '(#\B #\Y) 5 ]
    [ '(#\B #\Z) 9 ]
    [ '(#\C #\X) 7 ]
    [ '(#\C #\Y) 2 ]
    [ '(#\C #\Z) 6 ]))

12458

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
;; Part 2
(for/sum ([ pair in ])
  (match pair
    [ '(#\A #\X) 3 ]
    [ '(#\A #\Y) 4 ]
    [ '(#\A #\Z) 8 ]
    [ '(#\B #\X) 1 ]
    [ '(#\B #\Y) 5 ]
    [ '(#\B #\Z) 9 ]
    [ '(#\C #\X) 2 ]
    [ '(#\C #\Y) 6 ]
    [ '(#\C #\Z) 7 ]))

12683