⭐ Finally created day 3 part 1 solution
This commit is contained in:
parent
7e6b0e3bba
commit
1a9e5b9206
|
@ -0,0 +1,41 @@
|
|||
package adventofcode_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"source.toby3d.me/toby3d/adventofcode/internal/day3/part1"
|
||||
)
|
||||
|
||||
/*
|
||||
You and the Elf eventually reach a gondola lift station; he says the gondola
|
||||
lift will take you up to the water source, but this is as far as he can bring
|
||||
you. You go inside.
|
||||
|
||||
It doesn't take long to find the gondolas, but there seems to be a problem:
|
||||
they're not moving.
|
||||
|
||||
"Aaah!"
|
||||
|
||||
You turn around to see a slightly-greasy Elf with a wrench and a look of
|
||||
surprise. "Sorry, I wasn't expecting anyone! The gondola lift isn't working
|
||||
right now; it'll still be a while before I can fix it." You offer to help.
|
||||
|
||||
The engineer explains that an engine part seems to be missing from the engine,
|
||||
but nobody can figure out which one. If you can add up all the part numbers in
|
||||
the engine schematic, it should be easy to work out which part is missing.
|
||||
*/
|
||||
func ExampleDay3() {
|
||||
input, err := os.ReadFile(filepath.Join("internal", "day3", "testdata", "input"))
|
||||
if err != nil {
|
||||
log.Fatalln("cannot open input file:", err)
|
||||
}
|
||||
|
||||
result := part1.GetPartNumbersSum(bytes.NewReader(input))
|
||||
|
||||
fmt.Println(result)
|
||||
// Output: 540025
|
||||
}
|
2
go.mod
2
go.mod
|
@ -2,4 +2,4 @@ module source.toby3d.me/toby3d/adventofcode
|
|||
|
||||
go 1.21.4
|
||||
|
||||
require github.com/google/go-cmp v0.6.0 // indirect
|
||||
require github.com/google/go-cmp v0.6.0
|
||||
|
|
|
@ -0,0 +1,180 @@
|
|||
package part1
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type (
|
||||
EngineMap [][]Point
|
||||
Point byte
|
||||
|
||||
Number struct {
|
||||
value []byte
|
||||
minX int
|
||||
maxX int
|
||||
y int
|
||||
}
|
||||
)
|
||||
|
||||
func NewNumber(y int) *Number {
|
||||
return &Number{
|
||||
minX: 0,
|
||||
maxX: 0,
|
||||
y: y,
|
||||
value: make([]byte, 0),
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Number) Write(x int, p Point) {
|
||||
n.value = append(n.value, byte(p))
|
||||
n.maxX = x
|
||||
}
|
||||
|
||||
func (n Number) IsZero() bool {
|
||||
return len(n.value) == 0
|
||||
}
|
||||
|
||||
func (n *Number) Move(x int) {
|
||||
n.minX = x
|
||||
n.maxX = x
|
||||
}
|
||||
|
||||
func (n Number) Uint() uint {
|
||||
result, _ := strconv.ParseUint(string(n.value), 10, 64)
|
||||
|
||||
return uint(result)
|
||||
}
|
||||
|
||||
func (p Point) IsDigit() bool {
|
||||
switch p {
|
||||
default:
|
||||
return false
|
||||
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func (p Point) IsSymbol() bool {
|
||||
switch p {
|
||||
default:
|
||||
return true
|
||||
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.':
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (p Point) IsEmpty() bool {
|
||||
return p == '.'
|
||||
}
|
||||
|
||||
func (em EngineMap) HasSymbolAround(n Number) bool {
|
||||
minx := n.minX - 1
|
||||
if minx < 0 {
|
||||
minx = 0
|
||||
}
|
||||
|
||||
maxx := n.maxX + 1
|
||||
if maxx >= len(em[0]) {
|
||||
maxx = len(em[0]) - 1
|
||||
}
|
||||
|
||||
miny := n.y - 1
|
||||
if miny < 0 {
|
||||
miny = 0
|
||||
}
|
||||
|
||||
maxy := n.y + 1
|
||||
if maxy >= len(em) {
|
||||
maxy = len(em) - 1
|
||||
}
|
||||
|
||||
for y := miny; y <= maxy; y++ {
|
||||
for x := minx; x <= maxx; x++ {
|
||||
if !em[y][x].IsSymbol() {
|
||||
continue
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func ParseEngineMap(r io.Reader) EngineMap {
|
||||
scanner := bufio.NewScanner(r)
|
||||
scanner.Split(bufio.ScanLines)
|
||||
|
||||
engineMap := make(EngineMap, 0)
|
||||
y := 0
|
||||
|
||||
for scanner.Scan() {
|
||||
line := scanner.Bytes()
|
||||
engineMap = append(engineMap, make([]Point, len(line)))
|
||||
|
||||
for x := range line {
|
||||
engineMap[y][x] = Point(line[x])
|
||||
}
|
||||
|
||||
y++
|
||||
}
|
||||
|
||||
return engineMap
|
||||
}
|
||||
|
||||
func GetPartNumbersSum(r io.Reader) uint {
|
||||
var result uint
|
||||
for _, number := range GetPartNumbers(r) {
|
||||
result += number.Uint()
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func GetPartNumbers(r io.Reader) []Number {
|
||||
engineMap := ParseEngineMap(r)
|
||||
numbers := make([]Number, 0)
|
||||
|
||||
for y := range engineMap {
|
||||
n := NewNumber(y)
|
||||
|
||||
for x := range engineMap[y] {
|
||||
p := engineMap[y][x]
|
||||
|
||||
if p.IsDigit() {
|
||||
if n.IsZero() {
|
||||
n.Move(x)
|
||||
}
|
||||
|
||||
n.Write(x, p)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if n.IsZero() {
|
||||
continue
|
||||
}
|
||||
|
||||
numbers = append(numbers, *n)
|
||||
n = NewNumber(y)
|
||||
}
|
||||
|
||||
if !n.IsZero() {
|
||||
numbers = append(numbers, *n)
|
||||
}
|
||||
}
|
||||
|
||||
result := make([]Number, 0, len(numbers))
|
||||
|
||||
for i := range numbers {
|
||||
if !engineMap.HasSymbolAround(numbers[i]) {
|
||||
continue
|
||||
}
|
||||
|
||||
result = append(result, numbers[i])
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
package part1_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"source.toby3d.me/toby3d/adventofcode/internal/day3/part1"
|
||||
)
|
||||
|
||||
func TestGetPartNumbersSum(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for name, tc := range map[string]struct {
|
||||
input string
|
||||
expect uint
|
||||
}{
|
||||
// NOTE(toby3d): thanks, Calcifer777!
|
||||
// https://old.reddit.com/r/adventofcode/comments/189m7uu/2023_day_3_part_1_okay_then/kbt4tae/
|
||||
"center": {
|
||||
input: "...12\n" +
|
||||
"12*..",
|
||||
expect: 24,
|
||||
},
|
||||
// NOTE(toby3d): thanks, i_have_no_biscuits!
|
||||
// https://old.reddit.com/r/adventofcode/comments/189q9wv/2023_day_3_another_sample_grid_to_use/
|
||||
"ultimate1": {
|
||||
input: "12.......*..\n" +
|
||||
"+.........34\n" +
|
||||
".......-12..\n" +
|
||||
"..78........\n" +
|
||||
"..*....60...\n" +
|
||||
"78..........\n" +
|
||||
".......23...\n" +
|
||||
"....90*12...\n" +
|
||||
"............\n" +
|
||||
"2.2......12.\n" +
|
||||
".*.........*\n" +
|
||||
"1.1.......56",
|
||||
expect: 413,
|
||||
},
|
||||
"ultimate2": {
|
||||
input: "12.......*..\n" +
|
||||
"+.........34\n" +
|
||||
".......-12..\n" +
|
||||
"..78........\n" +
|
||||
"..*....60...\n" +
|
||||
"78.........9\n" +
|
||||
".5.....23..$\n" +
|
||||
"8...90*12...\n" +
|
||||
"............\n" +
|
||||
"2.2......12.\n" +
|
||||
".*.........*\n" +
|
||||
"1.1..503+.56",
|
||||
expect: 925,
|
||||
},
|
||||
// NOTE(toby3d): thanks, IsatisCrucifer!
|
||||
// https://old.reddit.com/r/adventofcode/comments/189q9wv/2023_day_3_another_sample_grid_to_use/kbt0vh8/
|
||||
"search": {
|
||||
input: "........\n" +
|
||||
".24..4..\n" +
|
||||
"......*.",
|
||||
expect: 4,
|
||||
},
|
||||
// NOTE(toby3d): thanks, i_have_no_biscuits!
|
||||
// https://old.reddit.com/r/adventofcode/comments/189q9wv/2023_day_3_another_sample_grid_to_use/kbt2yp5/
|
||||
"same": {
|
||||
input: "....................\n" +
|
||||
"..-52..52-..52..52..\n" +
|
||||
"..................-.",
|
||||
expect: 156,
|
||||
},
|
||||
// NOTE(toby3d): thanks, musifter!
|
||||
// https://old.reddit.com/r/adventofcode/comments/189q9wv/2023_day_3_another_sample_grid_to_use/kbsrno0/
|
||||
"gears": {
|
||||
input: ".......5......\n" +
|
||||
"..7*..*.......\n" +
|
||||
"...*13*.......\n" +
|
||||
".......15.....",
|
||||
expect: 40,
|
||||
},
|
||||
// NOTE(toby3d): thanks, Martins31!
|
||||
// https://old.reddit.com/r/adventofcode/comments/189q9wv/2023_day_3_another_sample_grid_to_use/kbtiucy/
|
||||
"space": {
|
||||
input: ".......5......\n" +
|
||||
"..7*..*.....4*\n" +
|
||||
"...*13*......9\n" +
|
||||
".......15.....\n" +
|
||||
"..............\n" +
|
||||
"..............\n" +
|
||||
"..............\n" +
|
||||
"..............\n" +
|
||||
"..............\n" +
|
||||
"..............\n" +
|
||||
"21............\n" +
|
||||
"...*9.........",
|
||||
expect: 62,
|
||||
},
|
||||
// NOTE(toby3d): thanks, 1234abcdcba4321!
|
||||
// https://old.reddit.com/r/adventofcode/comments/18a9pnl/2023_day_3_part_1_go_need_a_fresh_pair_of_eyes/kbwicj0/
|
||||
"zero": {
|
||||
input: "...\n" +
|
||||
"1.*\n" +
|
||||
"...",
|
||||
expect: 0,
|
||||
},
|
||||
// NOTE(toby3d): thanks, 1234abcdcba4321!
|
||||
// https://old.reddit.com/r/adventofcode/comments/18a2yir/year_2023_day_3_part_1_are_part_numbers_mutually/kbv5q64/
|
||||
"ones": {
|
||||
input: "1..\n" +
|
||||
"*.1\n" +
|
||||
"1..",
|
||||
expect: 2,
|
||||
},
|
||||
} {
|
||||
name, tc := name, tc
|
||||
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if actual := part1.GetPartNumbersSum(strings.NewReader(tc.input)); actual != tc.expect {
|
||||
t.Errorf("want %d, got %d", tc.expect, actual)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Example() {
|
||||
// The engine schematic (your puzzle input) consists of a visual
|
||||
// representation of the engine. There are lots of numbers and symbols
|
||||
// you don't really understand, but apparently any number adjacent to a
|
||||
// symbol, even diagonally, is a "part number" and should be included in
|
||||
// your sum. (Periods (.) do not count as a symbol.)
|
||||
input := "467..114..\n" +
|
||||
"...*......\n" +
|
||||
"..35..633.\n" +
|
||||
"......#...\n" +
|
||||
"617*......\n" +
|
||||
".....+.58.\n" +
|
||||
"..592.....\n" +
|
||||
"......755.\n" +
|
||||
"...$.*....\n" +
|
||||
".664.598.."
|
||||
|
||||
fmt.Println(part1.GetPartNumbersSum(strings.NewReader(input)))
|
||||
// Output: 4361
|
||||
}
|
Loading…
Reference in New Issue