Skip to content

Commit

Permalink
2023 Day 18
Browse files Browse the repository at this point in the history
  • Loading branch information
ictrobot committed Dec 18, 2023
1 parent d2b22ae commit b023ea0
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 0 deletions.
93 changes: 93 additions & 0 deletions internal/aoc2023/day18/day18.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package day18

import (
_ "embed"
"github.com/ictrobot/aoc/internal/util/numbers"
"github.com/ictrobot/aoc/internal/util/parse"
"github.com/ictrobot/aoc/internal/util/vec"
"strconv"
"strings"
)

//go:embed example
var Example string

type Day18 struct {
steps1 []vec.I2[int64]
steps2 []vec.I2[int64]
}

func (d *Day18) Parse(input string) {
input = strings.NewReplacer("(", "", ")", "", "#", "").Replace(input)
lines := parse.Lines(input)

d.steps1 = make([]vec.I2[int64], len(lines))
d.steps2 = make([]vec.I2[int64], len(lines))
for i, l := range lines {
s := strings.SplitN(l, " ", 3)

// part 1 uses first 2 fields
switch s[0] {
case "U":
d.steps1[i].Y = 1
case "D":
d.steps1[i].Y = -1
case "L":
d.steps1[i].X = -1
case "R":
d.steps1[i].X = 1
default:
panic("unknown dir")
}
d.steps1[i] = d.steps1[i].Mul(parse.Int64(s[1]))

// part 2 uses last field
switch s[2][5] {
case '3':
d.steps2[i].Y = 1
case '1':
d.steps2[i].Y = -1
case '2':
d.steps2[i].X = -1
case '0':
d.steps2[i].X = 1
default:
panic("unknown dir")
}

c, err := strconv.ParseUint(s[2][:5], 16, 20)
if err != nil {
panic(err)
}
d.steps2[i] = d.steps2[i].Mul(int64(c))
}
}

func (d *Day18) ParseExample() {
d.Parse(Example)
}

func (d *Day18) Part1() any {
return shapeArea(d.steps1)
}

func (d *Day18) Part2() any {
return shapeArea(d.steps2)
}

func shapeArea(steps []vec.I2[int64]) int64 {
// See 2023 Day 10 - Pick's theorem & shoelace formula
var pos vec.I2[int64]

var twiceArea, perimeter int64
for _, s := range steps {
next := pos.Add(s)

twiceArea += pos.X*next.Y - next.X*pos.Y
perimeter += s.Abs().MaxComponent()

pos = next
}

return numbers.IntAbs(twiceArea)/2 + (perimeter / 2) + 1
}
61 changes: 61 additions & 0 deletions internal/aoc2023/day18/day18_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package day18

import (
"github.com/stretchr/testify/assert"
"testing"
)

const Part1 = 62
const Part2 int64 = 952408144115

func TestDay18_ParseExample(t *testing.T) {
d1 := Day18{}
d1.ParseExample()

d2 := Day18{}
d2.ParseExample()
d2.ParseExample()

assert.Equal(t, d1, d2, "should be idempotent")
}

func BenchmarkDay18_ParseExample(b *testing.B) {
d := Day18{}
for i := 0; i < b.N; i++ {
d.ParseExample()
}
}

func TestDay18_Part1(t *testing.T) {
d := Day18{}
d.ParseExample()

assert.EqualValues(t, Part1, d.Part1())
}

func BenchmarkDay18_Part1(b *testing.B) {
d := Day18{}
d.ParseExample()

b.ResetTimer()
for i := 0; i < b.N; i++ {
assert.EqualValues(b, Part1, d.Part1())
}
}

func TestDay18_Part2(t *testing.T) {
d := Day18{}
d.ParseExample()

assert.EqualValues(t, Part2, d.Part2())
}

func BenchmarkDay18_Part2(b *testing.B) {
d := Day18{}
d.ParseExample()

b.ResetTimer()
for i := 0; i < b.N; i++ {
assert.EqualValues(b, Part2, d.Part2())
}
}
14 changes: 14 additions & 0 deletions internal/aoc2023/day18/example
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
R 6 (#70c710)
D 5 (#0dc571)
L 2 (#5713f0)
D 2 (#d2c081)
R 2 (#59c680)
D 2 (#411b91)
L 5 (#8ceee2)
U 2 (#caa173)
L 1 (#1b58a2)
U 2 (#caa171)
R 2 (#7807d2)
U 3 (#a77fa3)
L 2 (#015232)
U 2 (#7a21e3)
4 changes: 4 additions & 0 deletions internal/solution/solution_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions internal/util/vec/integer.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ func (i I3[T]) Sub(j I3[T]) I3[T] {
return I3[T]{i.X - j.X, i.Y - j.Y, i.Z - j.Z}
}

func (i I2[T]) Mul(c T) I2[T] {
return I2[T]{i.X * c, i.Y * c}
}

func (i I3[T]) Mul(c T) I3[T] {
return I3[T]{i.X * c, i.Y * c, i.Z * c}
}

func (i I2[T]) EuclideanDist2(j I2[T]) int64 {
dX := int64(i.X) - int64(j.X)
dY := int64(i.Y) - int64(j.Y)
Expand Down

0 comments on commit b023ea0

Please sign in to comment.