diff --git a/day25p1/solution.go b/day25p1/solution.go new file mode 100644 index 0000000..1e5859d --- /dev/null +++ b/day25p1/solution.go @@ -0,0 +1,79 @@ +package day25p1 + +import ( + "io" + + "aoc/utils" +) + +type Key [5]int +type Lock [5]int + +func (k Key) toLock() Lock { + var lock Lock + for i, v := range k { + lock[i] = v + } + return lock +} + +func Solve(r io.Reader) any { + blocks := utils.ReadBlocks(r) + + keys := make([]Key, 0) + locks := make([]Lock, 0) + + for _, block := range blocks { + isKey := checkKey(block) + if isKey { + keys = append(keys, parseKey(block)) + } else { + locks = append(locks, parseLock(block)) + } + } + + nonoverlapping := 0 + + for _, key := range keys { + for _, lock := range locks { + overlapping := false + for i := 0; i < 5; i++ { + if key[i]+lock[i] > 5 { + overlapping = true + break + } + } + if !overlapping { + nonoverlapping += 1 + } + } + } + + return nonoverlapping +} + +func checkKey(block []string) bool { + if block[0] == "....." { + return true + } else if block[0] == "#####" { + return false + } else { + panic("Invalid block") + } +} + +func parseKey(block []string) Key { + var key Key + for _, row := range block[1 : len(block)-1] { + for j, c := range row { + if c == '#' { + key[j] += 1 + } + } + } + return key +} + +func parseLock(block []string) Lock { + return parseKey(block).toLock() +} diff --git a/day25p1/solution_test.go b/day25p1/solution_test.go new file mode 100644 index 0000000..9d6d262 --- /dev/null +++ b/day25p1/solution_test.go @@ -0,0 +1,71 @@ +package day25p1 + +import ( + "strings" + "testing" + + "aoc/utils" +) + +var testInput = `##### +.#### +.#### +.#### +.#.#. +.#... +..... + +##### +##.## +.#.## +...## +...#. +...#. +..... + +..... +#.... +#.... +#...# +#.#.# +#.### +##### + +..... +..... +#.#.. +###.. +###.# +###.# +##### + +..... +..... +..... +#.... +#.#.. +#.#.# +#####` + +func TestSolve(t *testing.T) { + tests := []struct { + input string + answer int + }{ + {testInput, 3}, + } + + if testing.Verbose() { + utils.Verbose = true + } + + for _, test := range tests { + r := strings.NewReader(test.input) + + result := Solve(r).(int) + + if result != test.answer { + t.Errorf("Expected %d, got %d", test.answer, result) + } + } +} diff --git a/utils/functions.go b/utils/functions.go index 18d5c7a..5bd2c93 100644 --- a/utils/functions.go +++ b/utils/functions.go @@ -61,6 +61,31 @@ func ReadLines(r io.Reader) []string { return result } +// Read until \n\n and return blocks of lines +func ReadBlocks(r io.Reader) [][]string { + result := [][]string{} + + scanner := bufio.NewScanner(r) + block := []string{} + for scanner.Scan() { + line := scanner.Text() + if line == "" { + result = append(result, block) + block = []string{} + } else { + block = append(block, line) + } + } + err := scanner.Err() + Check(err, "error reading blocks") + + if len(block) > 0 { + result = append(result, block) + } + + return result +} + func GetInts(s string) []int { matches := intRegex.FindAllString(s, -1) result := make([]int, len(matches))