mirror of
https://github.com/onyx-and-iris/aoc2023.git
synced 2024-11-21 18:00:47 +00:00
day-3
This commit is contained in:
parent
4593c171d8
commit
c9ea61c7f4
5
day-3/go.mod
Normal file
5
day-3/go.mod
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
module github.com/onyx-and-iris/aoc2023/day-3
|
||||||
|
|
||||||
|
go 1.20
|
||||||
|
|
||||||
|
require github.com/go-playground/assert/v2 v2.2.0
|
2
day-3/go.sum
Normal file
2
day-3/go.sum
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||||
|
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
117
day-3/one.go
Normal file
117
day-3/one.go
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"unicode"
|
||||||
|
)
|
||||||
|
|
||||||
|
var symbols = [][]bool{}
|
||||||
|
|
||||||
|
// enginePart represents a single engine part
|
||||||
|
type enginePart struct {
|
||||||
|
digits []digit
|
||||||
|
}
|
||||||
|
|
||||||
|
// realValue returns the numeric value of all digits combined
|
||||||
|
func (e *enginePart) realValue() (int, error) {
|
||||||
|
var numStr string
|
||||||
|
for _, digit := range e.digits {
|
||||||
|
numStr += fmt.Sprintf("%d", digit.raw)
|
||||||
|
}
|
||||||
|
n, err := strconv.Atoi(numStr)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// digit represents a single digit in an engine part
|
||||||
|
type digit struct {
|
||||||
|
row int
|
||||||
|
col int
|
||||||
|
raw int
|
||||||
|
pass bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkDigit checks if any neighbouring characters are true (in symbol matrix)
|
||||||
|
func checkDigit(d digit) digit {
|
||||||
|
i := d.col - 1
|
||||||
|
for ; i < len(symbols[d.row]) && i <= d.col+1; i += 1 {
|
||||||
|
if i < 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if d.row != 0 {
|
||||||
|
if symbols[d.row-1][i] {
|
||||||
|
d.pass = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if symbols[d.row][i] {
|
||||||
|
d.pass = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if d.row != len(symbols)-1 {
|
||||||
|
if symbols[d.row+1][i] {
|
||||||
|
d.pass = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkDigits runs each digit in an engine part through checkDigit()
|
||||||
|
func checkDigits(i, j int, line string) (int, int, error) {
|
||||||
|
enginePart := enginePart{}
|
||||||
|
for ; j < len(line); j += 1 {
|
||||||
|
if !unicode.IsNumber(rune(line[j])) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
enginePart.digits = append(enginePart.digits, checkDigit(digit{row: i, col: j, raw: int(line[j]) - '0', pass: false}))
|
||||||
|
}
|
||||||
|
|
||||||
|
if anyTrue(enginePart.digits) {
|
||||||
|
engineParts[i] = append(engineParts[i], enginePart)
|
||||||
|
n, err := enginePart.realValue()
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, err
|
||||||
|
}
|
||||||
|
return j, n, nil
|
||||||
|
}
|
||||||
|
return j, 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// symbolToBool generates a boolean matrix that represents the placement of symbols
|
||||||
|
func symbolToBool(line string) []bool {
|
||||||
|
bool_arr := []bool{}
|
||||||
|
for _, c := range line {
|
||||||
|
bool_arr = append(bool_arr, !(unicode.IsNumber(c) || c == '.'))
|
||||||
|
}
|
||||||
|
return bool_arr
|
||||||
|
}
|
||||||
|
|
||||||
|
// one deciphers which numbers represent engine parts
|
||||||
|
// it returns the sum of all engine parts
|
||||||
|
func one(lines []string) (int, error) {
|
||||||
|
for _, line := range lines {
|
||||||
|
symbols = append(symbols, symbolToBool(line))
|
||||||
|
}
|
||||||
|
engineParts = make([][]enginePart, len(lines))
|
||||||
|
|
||||||
|
sum := 0
|
||||||
|
for i, line := range lines {
|
||||||
|
for j := 0; j < len(line); j += 1 {
|
||||||
|
if unicode.IsNumber(rune(line[j])) {
|
||||||
|
next, n, err := checkDigits(i, j, line)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
sum += n
|
||||||
|
j = next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sum, nil
|
||||||
|
}
|
37
day-3/one_test.go
Normal file
37
day-3/one_test.go
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/go-playground/assert/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSymbolToBool(t *testing.T) {
|
||||||
|
//t.Skip("skipping test")
|
||||||
|
input := []string{
|
||||||
|
"467..114..",
|
||||||
|
"...*......",
|
||||||
|
"..35..633.",
|
||||||
|
"......#...",
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := [][]bool{
|
||||||
|
{false, false, false, false, false, false, false, false, false, false},
|
||||||
|
{false, false, false, true, false, false, false, false, false, false},
|
||||||
|
{false, false, false, false, false, false, false, false, false, false},
|
||||||
|
{false, false, false, false, false, false, true, false, false, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
bool_matrix := [][]bool{}
|
||||||
|
for _, line := range input {
|
||||||
|
bool_matrix = append(bool_matrix, symbolToBool(line))
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("Should produce equal boolean matrices", func(t *testing.T) {
|
||||||
|
assert.Equal(t, expected, bool_matrix)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCheckDigit(t *testing.T) {
|
||||||
|
//t.Skip("skipping test")
|
||||||
|
}
|
5
day-3/run.sh
Executable file
5
day-3/run.sh
Executable file
@ -0,0 +1,5 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
INPUT="input.txt"
|
||||||
|
|
||||||
|
cat $INPUT | go run .
|
22
day-3/solution.go
Normal file
22
day-3/solution.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
lines := readlines()
|
||||||
|
|
||||||
|
ans, err := one(lines)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
fmt.Printf("solution one: %d\n", ans)
|
||||||
|
|
||||||
|
ans, err = two(lines)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
fmt.Printf("solution two: %d\n", ans)
|
||||||
|
}
|
55
day-3/two.go
Normal file
55
day-3/two.go
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
var engineParts [][]enginePart
|
||||||
|
|
||||||
|
// getGearRatio returns the product of engine parts if exactly two neighbour a gear
|
||||||
|
func getGearRatio(row, col int) (int, error) {
|
||||||
|
partsConsidered := []enginePart{}
|
||||||
|
|
||||||
|
i := row - 1
|
||||||
|
for ; i < len(engineParts) && i <= row+1; i += 1 {
|
||||||
|
if i < 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, enginePart := range engineParts[i] {
|
||||||
|
for _, part := range enginePart.digits {
|
||||||
|
if part.col == col-1 || part.col == col || part.col == col+1 {
|
||||||
|
if anyTrue(enginePart.digits) {
|
||||||
|
partsConsidered = append(partsConsidered, enginePart)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(partsConsidered) == 2 {
|
||||||
|
n1, err := partsConsidered[0].realValue()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
n2, err := partsConsidered[1].realValue()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return n1 * n2, nil
|
||||||
|
}
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// two returns the sum of all gear ratios
|
||||||
|
func two(lines []string) (int, error) {
|
||||||
|
sum := 0
|
||||||
|
for i, line := range lines {
|
||||||
|
for j, c := range line {
|
||||||
|
if rune(c) == '*' {
|
||||||
|
n, err := getGearRatio(i, j)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
sum += n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sum, nil
|
||||||
|
}
|
34
day-3/util.go
Normal file
34
day-3/util.go
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// readlines reads lines from stdin.
|
||||||
|
// Then it returns them as an array of strings
|
||||||
|
func readlines() []string {
|
||||||
|
lines := []string{}
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(os.Stdin)
|
||||||
|
for scanner.Scan() {
|
||||||
|
lines = append(lines, scanner.Text())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
// anyTrue checks if any digits passed
|
||||||
|
func anyTrue(digits []digit) bool {
|
||||||
|
for _, digit := range digits {
|
||||||
|
if digit.pass {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user