andreiz / advent-of-code-2023-swift

Copilot and ChatGPT assisted Advent of Code 2023 to learn Swift.
0 stars 0 forks source link

Day 2: Cube Conundrum #2

Open andreiz opened 11 months ago

andreiz commented 11 months ago

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

Puzzle input: https://adventofcode.com/2023/day/2/input

andreiz commented 11 months ago

Part 1 is pretty simple. Loop through games, then for each try in the game check if any red/green/blue exceeds the max.

Didn't have Copilot working yet, so started with GPT prompting again.

andreiz commented 11 months ago

After a bit of back and forth about passing the data and structuring the counts it produced this function that checks each game's validity:

let CUBE_LIMITS: [String: Int] = ["red": 12, "green": 13, "blue": 14]

func isGamePossible(gameData: String) -> (isPossible: Bool, violatingCube: String?, count: Int?) {
    let tries = gameData.split(separator: ";")
    for tryData in tries {
        // Initialize cube counts for each try.
        var cubeCounts = ["red": 0, "green": 0, "blue": 0]

        let colorDataArray = tryData.split(separator: ",")
        for colorData in colorDataArray {
            let parts = colorData.split(separator: " ")
            let count = Int(parts[0].trimmingCharacters(in: .whitespaces)) ?? 0
            let color = String(parts[1].trimmingCharacters(in: .whitespaces))

            cubeCounts[color, default: 0] += count
            if let limit = CUBE_LIMITS[color], cubeCounts[color, default: 0] > limit {
                return (false, color, cubeCounts[color]) // Return false, violating cube color, and count
            }
        }
    }

    return (true, nil, nil) // Return true with no violations
}
andreiz commented 11 months ago

I pointed out that it's trying to sum the per-color counts for all the tries, instead of treating them independently. That, and that the cubeCounts is unnecessary if we check against the limits directly. Updated result:

func isGamePossible(gameData: String) -> (isPossible: Bool, violatingCube: String?, count: Int?) {
    let tries = gameData.split(separator: ";")
    for tryData in tries {
        let colorDataArray = tryData.split(separator: ",")
        for colorData in colorDataArray {
            let parts = colorData.split(separator: " ")
            let count = Int(parts[0].trimmingCharacters(in: .whitespaces)) ?? 0
            let color = String(parts[1].trimmingCharacters(in: .whitespaces))

            // Check if the count exceeds the limit for each color.
            if let limit = CUBE_LIMITS[color], count > limit {
                return (false, color, count) // Return false, violating cube color, and count
            }
        }
    }

    return (true, nil, nil) // Return true with no violations
}
andreiz commented 11 months ago

I wasn't sure what ?? was, so I asked.

In Swift, the ?? operator is known as the "nil coalescing operator." It is used to provide a default value for an optional in case the optional is nil.

andreiz commented 11 months ago

Now we just need to read in a file, iterate over the lines, and sum the game IDs that don't violate the constraints.

https://github.com/andreiz/advent-of-code-2023-swift/blob/f9e732ac17bfef6c0888cf8f5671a127959757f3/day-02/cubes.swift#L30-L58

andreiz commented 11 months ago

I do like how you can return multiple (and optional) values from a func and then unwrap them.

andreiz commented 11 months ago

Ran this on the test input and the result was:

Game 1 [3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green]: possible
Game 2 [1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue]: possible
Game 3 [8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red]: impossible due to red cube count 20 exceeding limit
Game 4 [1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red]: impossible due to blue cube count 15 exceeding limit
Game 5 [6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green]: possible
Sum of possible game numbers: 8

Which is correct.

andreiz commented 11 months ago

Ok, part 2. Need to keep track of max count of each try and return it along with the game result (whether it's possible or impossible).

https://github.com/andreiz/advent-of-code-2023-swift/blob/368233e7d2a11ad7617f3b06e0bc00c74ee0580a/day-02/cubes-min.swift#L6-L37

andreiz commented 11 months ago

I wondered how to easily multiply the values of an array and ChatGPT suggested:

let (isPossible, fewestCubes) = analyzeGame(gameData: gameData)
let cubeProduct = fewestCubes.values.reduce(1, *)
cubeProductSum += cubeProduct

Neat. I like that operators are first-class entities.

andreiz commented 11 months ago

Printing out cubeProductSum now and... it's passed.