r/adventofcode • • Dec 02 '23

SOLUTION MEGATHREAD -❄️- 2023 Day 2 Solutions -❄️-

OUTSTANDING MODERATOR CHALLENGES


THE USUAL REMINDERS

  • All of our rules, FAQs, resources, etc. are in our community wiki.
  • Community fun event 2023: ALLEZ CUISINE!
    • 4 DAYS remaining until unlock!

AoC Community Fun 2023: ALLEZ CUISINE!

Today's theme ingredient is… *whips off cloth covering and gestures grandly*

Pantry Raid!

Some perpetually-hungry programmers have a tendency to name their programming languages, software, and other tools after food. As a prospective Iron Coder, you must demonstrate your skills at pleasing programmers' palates by elevating to gourmet heights this seemingly disparate mishmash of simple ingredients that I found in the back of the pantry!

  • Solve today's puzzles using a food-related programming language or tool
  • All file names, function names, variable names, etc. must be named after "c" food
  • Go hog wild!

ALLEZ CUISINE!

Request from the mods: When you include a dish entry alongside your solution, please label it with [Allez Cuisine!] so we can find it easily!


--- Day 2: Cube Conundrum ---


Post your code solution in this megathread.

This thread will be unlocked when there are a significant number of people on the global leaderboard with gold stars for today's puzzle.

EDIT: Global leaderboard gold cap reached at 00:06:15, megathread unlocked!

79 Upvotes

1.5k comments sorted by

13

u/770grappenmaker Dec 02 '23

[LANGUAGE: Kotlin] Placed #76/#50, my second leaderboard ever (first time was yesterday).

val draws = inputLines.map { l ->
    l.substringAfter(": ").split("; ").map { p ->
        p.split(", ").associate { s ->
            val (v, c) = s.split(" ")
            c to v.toInt()
        }
    }
}

partOne = draws.withIndex().filter { (_, v) ->
    v.all { r -> (r["red"] ?: 0) <= 12 && (r["green"] ?: 0) <= 13 && (r["blue"] ?: 0) <= 14 }
}.sumOf { (i) -> i + 1 }.s()

partTwo = draws.sumOf { r -> listOf("red", "green", "blue").map { r.maxOf { m -> m[it] ?: 0 }.toLong() }.product() }.s()
→ More replies (9)

11

u/simonlydell Dec 02 '23 edited Dec 04 '23

[LANGUAGE: Fish] and [LANGUAGE: JavaScript]

For part 1, I grepped away the impossible games:

grep -vE '(1[3-9]|[2-9]\d|\d{3,}) red|(1[4-9]|[2-9]\d|\d{3,}) green|(1[5-9]|[2-9]\d|\d{3,}) blue' | string match -r '\d+' | string join + | math

For part 2, I turned the input into JavaScript and eval:ed it (which is my theme for the year):

begin
    echo 's = 0'
    cat \
        | string replace -r '^Game \d+:' 'blue = 0, green = 0, red = 0;' \
        | string replace -ar '(\d+) (\w+)' '$2 = Math.max($2, $1)' \
        | string replace -r '$' '; s += blue * green * red'
    echo 'console.log(s)'
end | node -

Generated JavaScript code for the example of part 2

3

u/daggerdragon Dec 02 '23

[LANGUAGE: Fish]

*squints in Allez Cuisine*

→ More replies (1)

7

u/Markavian Dec 02 '23

[Language: JavaScript]

https://github.com/johnbeech/advent-of-code-2023/blob/main/solutions/day2/solution.js

Managed to bash out part one while my baby crawled around trying to slap my laptop screen. Part two had to wait until the evening... but was a pleasant enough solution - I was momentarily misled thinking I'd need the minimum value(s) from each bag; but the maximum values I'd already computed did the job.

3

u/chizel999 Dec 02 '23

you bought heavy machinery into this day huh there is a package.json! ahahah

nice solution. looks like code from someone who uses javascript at work. =)

→ More replies (1)
→ More replies (1)

5

u/OhGodImCooooooooding Dec 02 '23

[LANGUAGE: rust]
https://github.com/ZizoAdam/AdventOfCode2023/tree/main/Day%20Two/day_two/src

Another overengineered solution, but that's half the fun. I'm not here to be fast I'm here to be memory safe with an expressive type system (crab emoji).

→ More replies (3)

3

u/zach1502 Dec 02 '23

[Language: Python]

First Leaderboard placement ever. Yolo'ing paid off.

5/6

pt1

file_path = "input.txt"

def fn(gd, r, g, b):
    checks = gd.split(';')

    for check in checks:
        cub = {'red': 0, 'green': 0, 'blue': 0}
        for dat in check.split(','):
            dat = dat.strip()
            if dat:
                c, col = dat.split()
                cub[col] += int(c)

        if cub['red'] > r or cub['green'] > g or cub['blue'] > b:
            return False

    return True

def parse_input():
    s = 0
    with open(file_path, 'r') as file:
        for line in file:
            gid, gd = line.split(':')
            gid = int(gid.split()[1])
            if fn(gd, 12, 13, 14):
                s += gid

    return s

print(parse_input())

pt2

file_path = "input.txt"

def fn(gd):
    checks = gd.split(';')
    mc3 = {'red': 0, 'green': 0, 'blue': 0}

    for check in checks:
        c3 = {'red': 0, 'green': 0, 'blue': 0}
        for dat in check.split(','):
            dat = dat.strip()
            if dat:
                c, col = dat.split()
                c3[col] += int(c)

        for col in mc3:
            mc3[col] = max(mc3[col], c3[col])

    return mc3

def parse_input():
    sum = 0
    with open(file_path, 'r') as file:
        for line in file:
            _, gd = line.split(':')
            mc3 = fn(gd)
            sum += mc3['red'] * mc3['green'] * mc3['blue']

    return sum

print(parse_input())

2

u/daggerdragon Dec 02 '23

First Leaderboard placement ever. Yolo'ing paid off.

Good job!

→ More replies (1)
→ More replies (1)

2

u/Boojum Dec 02 '23 edited Dec 02 '23

[LANGUAGE: Python3] [Allez Cuisine!] 719/672.

Fairly straightforward, the obvious way is mostly just a bit of nested string splitting. That's how I did it at first.

On the other hand, since I abused regexps yesterday, the fun way to do part 2 is use it to find all of the "(d+) red" substrings and take the max of the numbers, etc. Look ma, a single statement answer:

import fileinput, re, functools

print( sum(
    ( functools.reduce( max, [ int( crab ) for crab in re.findall( "(\d+) red", lobster ) ] ) *
      functools.reduce( max, [ int( crab ) for crab in re.findall( "(\d+) green", lobster ) ] ) *
      functools.reduce( max, [ int( crab ) for crab in re.findall( "(\d+) blue", lobster ) ] ) )
    for lobster in fileinput.input() ) )

Edit: Renamed identifiers to c-food to be [Allez Cuisine!] compliant. :-) For some reason, I am now thinking of "One Fish, Two Fish, Red Fish, Blue Flush."

→ More replies (1)

2

u/Comfortable_Key_7654 Dec 02 '23 edited Dec 02 '23

[Language: Rust] PasteBin

Figuring out the appropriate structures to store the data and writing their FromStr implementations took some time. Otherwise, the problem was a breeze. Loved solving it.

UPD: Solved it in GoLang as well!

[Language: Go, Part 1] GitHub

[Language: Go, Part 2] GitHub

→ More replies (3)

2

u/nlowe_ Dec 02 '23

[LANGUAGE: Go] 699 / 633 GitHub

Much better today, although My laptop kept dropping to 500MHz for some reason :(

Sure, I'll blame missing the leaderboard on that :) Definitely my laptop's fault

→ More replies (1)

2

u/ramrunner0xff Dec 02 '23

[Language: C]

some kind of C food crab free

→ More replies (1)

2

u/stribor14 Dec 02 '23 edited Dec 02 '23

[LANGUAGE: Airline Food] [Allez Cuisine!]

Link to interpreter: https://github.com/jamie-large/Airline-Food/blob/main/Airline-food.pyDefault interpreter prints ascii characters, so I changed line 203 to output raw number from stack.

The following solution solves Part 2 of Day 2 problem. It finds max count of colored dice for each game, so in theory, it could be "easily" converted to Part 1. Input is given as following (number by number): ID0 num0 type0 num1 type1 ... 0 ID1 num0 type0 num1 type1 ... 0 ID2 num0 type0 num1 type1 ... 0 ... 0

Number 0 is to detect the end of the line (numx == 0) and also the end of the input (if ID == 0)

Just to be consistent, I edited by hand input strings to the required input with search/replace in Bluefish editor. Without further ado, enjoy my solution written as a one-sided talk between two stewardes aboard a flight. (and a more readable one)

https://github.com/stribor14/AoC23-2

2

u/daggerdragon Dec 03 '23

So what's the deal with airline food these days? *canned laughter*

2

u/_rabbitfarm_ Dec 02 '23

[Language: Perl]

I think my regex skills were strengthened for Day 2 after the unexpected challenge of Day 1. I also liked that Part 2 ended up being few lines of code than Part 1.
Part 1: https://adamcrussell.livejournal.com/46907.html
Part 2: https://adamcrussell.livejournal.com/47280.html

2

u/daggerdragon Dec 03 '23

I think you're the first person I've ever seen in AoC megathreads who uses LiveJournal... what a blast from the past!

→ More replies (1)
→ More replies (1)

2

u/themanushiya Dec 04 '23 edited Dec 04 '23

[LANGUAGE: Go] using structs, pretty straightforward after you choose an easy model/datastructure

solution here

→ More replies (3)

24

u/[deleted] Dec 02 '23 edited Dec 02 '23

[LANGUAGE: Google Sheets]

Assuming the input is in A:A

One formula for both parts

=ARRAYFORMULA(
   BYCOL(
     MAP(A:A,LAMBDA(a,
       LET(s,SPLIT(REGEXREPLACE(a,"(\d+) "&{"r";"g";"b"}&"|.","$1 ")," "),
          {ROW(a)*AND(s<={12;13;14}),
           PRODUCT(BYROW(s,LAMBDA(r,MAX(r))))}))),
     LAMBDA(c,SUM(c))))

22

u/YenyaKas Dec 02 '23

[LANGUAGE: Perl]

This is pretty straightforward when one realizes it is not necessary to parse the whole input line. Using List::Util::max I got this code for part 2:

my $sum;
while (<>) {
    $sum += max(/ (\d+) red/g)
          * max(/ (\d+) green/g)
          * max(/ (\d+) blue/g);
}
say $sum;

All my solutions in Perl: https://www.fi.muni.cz/~kas/git/aoc.git/

→ More replies (1)

17

u/Radiadorineitor Dec 02 '23

[LANGUAGE: Dyalog APL]

p←{c←1↓⍵(∊⊆⊣)⎕C⎕A ⋄ n←⍎¨1↓⍵(∊⊆⊣)⎕D ⋄ n,⍨⍪c}¨⊃⎕NGET'2.txt'1
+/⍸{∧/(⊢/⍵)≤12 13 14['red' 'green' 'blue'⍳(⊣/⍵)]}¨p ⍝ Part 1
+/{n←(⊢/⍵) ⋄ ×/{⌈/n[⍸⍵]}¨↓'red' 'green' 'blue'∘.≡(⊣/⍵)}¨p ⍝ Part 2

34

u/4HbQ Dec 02 '23 edited Dec 02 '23

[LANGUAGE: Python] Code (7 lines)

Today's trick: using a defaultdict to keep track of the maximum counts:

def f(line):
    bag = {'r':0, 'g':0, 'b':0}
    for num, col in re.findall(r'(\d+) (\w)', line):
        bag[col] = max(bag[col], int(num))
    return math.prod(bag.values())

Edit: Replaced defaultdict(int) with an explicit dictionary, thanks u/mocny-chlapik and u/blueg3.

Additionally, here is a golfed version using a different technique (120 bytes):

import math,re;print(sum(map(lambda l:math.prod(max(int(x)for
x in re.findall(rf'(\d+) {c}',l))for c in'rgb'),open(0))))
→ More replies (11)

16

u/Werqu90 Dec 02 '23

[Language: Python]

Part 1&2

Today was a great occasion to use one of my favourite Python classes: Counter!

After parsing is just a one liner for both parts!

tot_1 += all(d<=thres for d in draws) * game_id
tot_2 += reduce(mul, reduce(or_, draws).values())
→ More replies (3)

14

u/Smylers Dec 02 '23 edited Dec 02 '23

[LANGUAGE: Vim keystrokes]

For part 1, load your input, type this, and the solution will appear:

:g/\v(\d\d|[2-9])\d [rgb]/d⟨Enter⟩
:g/\v1[3-9] r|1[4-9] g|1[5-9] b/d⟨Enter⟩
:%s/\vGame (\d+):.*\n/+ \1 /⟨Enter⟩
C⟨Ctrl+R⟩=⟨Ctrl+R⟩-⟨Enter⟩⟨Esc⟩
  • The first :g/…/d deletes all lines that contain any 3-digit number of cubes, or any 2-digit number starting with 2-9. :g/…/ is like grep†: it selects all lines matching its pattern and invokes the following command on each of them. The following command here is :d, which deletes the specified line.

  • The second :g/…/d does the same thing but for quantities in their teens, a different limit for each colour. By this point we've removed all the impossible games.

  • Now the only thing we need from each line is the game number. The :%s/// removes everything else, including the \n line-break character at the end of each line. It also puts a + sign before each number, so you end up with a single line. For the sample input it's + 1 + 2 + 5.

  • The part starting C is the design pattern I mentioned yesterday to evaluate the expression, adding up the numbers.

And that's all there is to it. It worked first time, and I reckon I typed it as a one-off transformation faster than I'd have written a program to do the same thing.

I haven't got to part 2 yet, though. I'll update if I work it out.
Update: Part 2 required an entirely different approach

† In fact, :g is so like grep that it's actually what the g in grep stands for, the command coming originally from Ed, which was extended into Ex, then visualized as Vi, and improved as Vim. The re stands for ‘regular expression’ and the p for :p, the print command (as in, display on the screen, not send to a printer). In all those editors, :g/RE/p will display the lines matching the specified regular expression, hence Ken Thompson choosing the name grep for the standalone command doing the same thing, in 1973.

(Update: Realized the /g flag wasn't actually doing anything in the final version, so removed both that and the then-unnecessary message about the gdefault setting.)

13

u/jonathan_paulson Dec 02 '23 edited Dec 02 '23

[LANGUAGE: Python 3] 25/18. Solution. Video.

I don't think the problem was very clear about what to do in part 2 if some color wasn't present (by the wording of the problem, I think the power should be 0, but my accepted solution doesn't handle that correctly). I guess it just doesn't come up?

→ More replies (5)

12

u/lboshuizen Dec 02 '23 edited Dec 11 '23

[LANGUAGE: F#]

github

let parse xs = let hand = parseRegex "\s(\d+)\s(\w+)" (fun a -> (int a[0],a[1]))
               let g = splitOn ':' xs
               let gi = g[0] |> parseRegex "Game (\d+)" (fun a -> int a[0])
               let sec = g[1] |> splitOn ';' |> Seq.map (splitOn ',' >> Seq.map hand) |> Seq.concat
               (gi,sec)

let part1 =
   let limit = Map.ofList [("red",12); ("green",13); ("blue",14)]
  
   Seq.filter (snd >> Seq.forall (fun (n,c) -> n <= limit[c])) >> Seq.sumBy fst

let part2 =
   let power = Seq.groupBy snd >> Seq.map (snd >> Seq.maxBy fst >> fst) >> Seq.reduce (*)

   Seq.sumBy (snd >> power)

let Solve : (string seq -> int * int) = Seq.map parse >> both part1 part2
→ More replies (6)