Skip to content

Commit

Permalink
Added day 3
Browse files Browse the repository at this point in the history
  • Loading branch information
devries committed Dec 3, 2023
1 parent 8b100a0 commit b4c1118
Show file tree
Hide file tree
Showing 6 changed files with 274 additions and 3 deletions.
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Advent of Code 2023

[![Tests](https://github.com/devries/advent_of_code_2023/actions/workflows/main.yml/badge.svg)](https://github.com/devries/advent_of_code_2023/actions/workflows/main.yml)
[![Stars: 4](https://img.shields.io/badge/⭐_Stars-4-yellow)](https://adventofcode.com/2023)
[![Stars: 6](https://img.shields.io/badge/⭐_Stars-6-yellow)](https://adventofcode.com/2023)

## Plan for This Year

Expand Down Expand Up @@ -38,10 +38,21 @@ opportunity to experiment a bit with code generation.
have some indexing issues which I had to debug. I later realized I could use
`strings.LastIndex` to make this much easier.

- [Day 2:Cube Conundrum ](https://adventofcode.com/2023/day/2) - [part 1](day02p1/solution.go), [part 2](day02p2/solution.go)
- [Day 2: Cube Conundrum ](https://adventofcode.com/2023/day/2) - [part 1](day02p1/solution.go), [part 2](day02p2/solution.go)

Most of this problem was parsing. I just did a lot of splitting on substrings.
First I split on ": " to separate the game id from the draws, then I split on
"; " to separate the individual draws, then on ", " to split to the colors.
After that it was straightforward. I missed an opportunity to use the debugger
to check my parsing and instead put in a `Println`.

- [Day 3: Gear Ratios ](https://adventofcode.com/2023/day/3) - [part 1](day03p1/solution.go), [part 2](day03p2/solution.go)

The key here was just figuring out how to store the schematic data so it would
be useful for answering the questions. During parsing I recorded the positions
of the symbols in a map indexed by position. I recorded the numbers as an
array of structs including the value and the start and end position. Then I
could interate over all the numbers, find the surrounding points, and see what
symbols were around them. I created an array of numbers for each gear object
I found and then could iterate through those arrays to find gears with
exactly two adjacent numbers.
84 changes: 84 additions & 0 deletions day03p1/solution.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package day03p1

import (
"io"

"aoc/utils"
)

func Solve(r io.Reader) any {
lines := utils.ReadLines(r)

symbols := make(map[utils.Point]rune)

numbers := []Number{}

for j, ln := range lines {
innumber := false

for i, r := range ln {
switch {
case r == '.':
// do nothing
innumber = false
case r >= '0' && r <= '9':
// number
switch innumber {
case false:
innumber = true
var newNumber Number
newNumber.Start = utils.Point{X: i, Y: j}
newNumber.End = newNumber.Start
newNumber.Value = int64(r - '0')
numbers = append(numbers, newNumber)
case true:
idx := len(numbers) - 1
numbers[idx].End = utils.Point{X: i, Y: j}
numbers[idx].Value = numbers[idx].Value*10 + int64(r-'0')
}
default:
// symbol
symbols[utils.Point{X: i, Y: j}] = r
innumber = false
}
}
}

var sum int64

for _, n := range numbers {
surroundingPoints := pointsAround(n.Start, n.End)
for _, p := range surroundingPoints {
if symbols[p] != 0 {
sum += n.Value
break
}
}
}

return sum
}

type Number struct {
Value int64
Start utils.Point
End utils.Point
}

func pointsAround(start utils.Point, end utils.Point) []utils.Point {
yupper := start.Y - 1
ylower := start.Y + 1
yline := start.Y

xmin := start.X - 1
xmax := end.X + 1

result := []utils.Point{{X: xmin, Y: yline}, {X: xmax, Y: yline}}

for i := xmin; i <= xmax; i++ {
result = append(result, utils.Point{X: i, Y: yupper})
result = append(result, utils.Point{X: i, Y: ylower})
}

return result
}
42 changes: 42 additions & 0 deletions day03p1/solution_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package day03p1

import (
"strings"
"testing"

"aoc/utils"
)

var testInput = `467..114..
...*......
..35..633.
......#...
617*......
.....+.58.
..592.....
......755.
...$.*....
.664.598..`

func TestSolve(t *testing.T) {
tests := []struct {
input string
answer int64
}{
{testInput, 4361},
}

if testing.Verbose() {
utils.Verbose = true
}

for _, test := range tests {
r := strings.NewReader(test.input)

result := Solve(r).(int64)

if result != test.answer {
t.Errorf("Expected %d, got %d", test.answer, result)
}
}
}
92 changes: 92 additions & 0 deletions day03p2/solution.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package day03p2

import (
"io"

"aoc/utils"
)

func Solve(r io.Reader) any {
lines := utils.ReadLines(r)

symbols := make(map[utils.Point]rune)

numbers := []Number{}

for j, ln := range lines {
innumber := false

for i, r := range ln {
switch {
case r == '.':
// do nothing
innumber = false
case r >= '0' && r <= '9':
// number
switch innumber {
case false:
innumber = true
var newNumber Number
newNumber.Start = utils.Point{X: i, Y: j}
newNumber.End = newNumber.Start
newNumber.Value = int64(r - '0')
numbers = append(numbers, newNumber)
case true:
idx := len(numbers) - 1
numbers[idx].End = utils.Point{X: i, Y: j}
numbers[idx].Value = numbers[idx].Value*10 + int64(r-'0')
}
default:
// symbol
symbols[utils.Point{X: i, Y: j}] = r
innumber = false
}
}
}

var sum int64

gearAdjacents := make(map[utils.Point][]int64)

for _, n := range numbers {
surroundingPoints := pointsAround(n.Start, n.End)
for _, p := range surroundingPoints {
if symbols[p] == '*' {
gearAdjacents[p] = append(gearAdjacents[p], n.Value)
break
}
}
}

for _, nums := range gearAdjacents {
if len(nums) == 2 {
sum += nums[0] * nums[1]
}
}

return sum
}

type Number struct {
Value int64
Start utils.Point
End utils.Point
}

func pointsAround(start utils.Point, end utils.Point) []utils.Point {
yupper := start.Y - 1
ylower := start.Y + 1
yline := start.Y

xmin := start.X - 1
xmax := end.X + 1

result := []utils.Point{{X: xmin, Y: yline}, {X: xmax, Y: yline}}

for i := xmin; i <= xmax; i++ {
result = append(result, utils.Point{X: i, Y: yupper})
result = append(result, utils.Point{X: i, Y: ylower})
}

return result
}
42 changes: 42 additions & 0 deletions day03p2/solution_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package day03p2

import (
"strings"
"testing"

"aoc/utils"
)

var testInput = `467..114..
...*......
..35..633.
......#...
617*......
.....+.58.
..592.....
......755.
...$.*....
.664.598..`

func TestSolve(t *testing.T) {
tests := []struct {
input string
answer int64
}{
{testInput, 467835},
}

if testing.Verbose() {
utils.Verbose = true
}

for _, test := range tests {
r := strings.NewReader(test.input)

result := Solve(r).(int64)

if result != test.answer {
t.Errorf("Expected %d, got %d", test.answer, result)
}
}
}
2 changes: 1 addition & 1 deletion inputs

0 comments on commit b4c1118

Please sign in to comment.