Skip to content

Commit

Permalink
Finished day 18... I always seem to have trouble with these ones
Browse files Browse the repository at this point in the history
  • Loading branch information
devries committed Dec 18, 2023
1 parent faaf00a commit 9bd0b05
Show file tree
Hide file tree
Showing 6 changed files with 465 additions and 2 deletions.
15 changes: 14 additions & 1 deletion 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: 34](https://img.shields.io/badge/⭐_Stars-34-yellow)](https://adventofcode.com/2023)
[![Stars: 36](https://img.shields.io/badge/⭐_Stars-36-yellow)](https://adventofcode.com/2023)

## Plan for This Year

Expand Down Expand Up @@ -282,3 +282,16 @@ the third run of my solution after compilation on my Raspberry Pi.
state to position and direction. For neighboring states, I assume I will turn
90 degrees and find all states 4 to 10 steps away in each direction. This runs
much faster as shown above.

- [Day 18: Lavaduct Lagoon](https://adventofcode.com/2023/day/18) - [⭐ part 1](day18p1/solution.go), [⭐ part 2](day18p2/solution.go)

For the first part I did a flood fill of points outside the trench and then
subtracted the area not filled from the surrounding rectangle. I should have
seen the second part coming, but essentially what I did was find all the
horizontal line segments in the trenches. I then worked up from the lowest
segment to the highest segment calculating the area of rectangles above the
existing segments until they intersect other segments. I did the accounting
in a complicated and error prone way which meant that I was able to only
finish the first part before work and had to wait to finish the second
part until after work. I think there has to be a more elegant way to express
what I was trying to express, but I didn't find it today.
142 changes: 142 additions & 0 deletions day18p1/solution.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
package day18p1

import (
"fmt"
"io"
"regexp"
"strconv"

"aoc/utils"
)

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

re := regexp.MustCompile(`([RDLU])\s+(\d+)\s+\(#([0-9a-f]+)\)`)

grid := make(map[utils.Point]bool)
pos := utils.Point{}
grid[pos] = true
xmin, ymin, xmax, ymax := 0, 0, 0, 0

for _, ln := range lines {
sm := re.FindStringSubmatch(ln)

inst := Instruction{}
switch sm[1] {
case "U":
inst.Direction = utils.North
case "D":
inst.Direction = utils.South
case "R":
inst.Direction = utils.East
case "L":
inst.Direction = utils.West
default:
panic("Direction not good")
}

var err error
inst.Distance, err = strconv.Atoi(sm[2])
if err != nil {
utils.Check(err, "Unable to convert %s to int", sm[2])
}

inst.Color = sm[3]

// dig out trenches
for i := 0; i < inst.Distance; i++ {
pos = pos.Add(inst.Direction)
if pos.X > xmax {
xmax = pos.X
}
if pos.Y > ymax {
ymax = pos.Y
}
if pos.X < xmin {
xmin = pos.X
}
if pos.Y < ymin {
ymin = pos.Y
}

grid[pos] = true
}
}

if utils.Verbose {
printGrid(grid, xmin, ymin, xmax, ymax)
}

g := &Grid{grid, xmin, ymin, xmax, ymax}

bfs := utils.NewBFS[utils.Point]()

_, err := bfs.Run(g)
if err != utils.BFSNotFound {
panic("did not exhaust grid")
}

outside := len(bfs.Visited)

if utils.Verbose {
printGrid(bfs.Visited, xmin-1, ymin-1, xmax+1, ymax+1)
}

area := (xmax - xmin + 3) * (ymax - ymin + 3)
return area - outside
}

type Instruction struct {
Direction utils.Point
Distance int
Color string
}

func printGrid(grid map[utils.Point]bool, xmin, ymin, xmax, ymax int) {
for j := ymax; j >= ymin; j-- {
for i := xmin; i <= xmax; i++ {
switch grid[utils.Point{X: i, Y: j}] {
case true:
fmt.Printf("#")
case false:
fmt.Printf(".")
}
}
fmt.Printf("\n")
}
fmt.Printf("\n")
}

type Grid struct {
Edges map[utils.Point]bool
Xmin int
Ymin int
Xmax int
Ymax int
}

func (g *Grid) GetInitial() utils.Point {
return utils.Point{X: g.Xmin - 1, Y: g.Ymin - 1}
}

func (g *Grid) GetNeighbors(p utils.Point) []utils.Point {
ret := []utils.Point{}

for _, dir := range utils.Directions {
np := p.Add(dir)

if np.X > g.Xmax+1 || np.X < g.Xmin-1 || np.Y < g.Ymin-1 || np.Y > g.Ymax+1 {
continue
}
if !g.Edges[np] {
ret = append(ret, np)
}
}

return ret
}

func (g *Grid) IsFinal(p utils.Point) bool {
return false
}
46 changes: 46 additions & 0 deletions day18p1/solution_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package day18p1

import (
"strings"
"testing"

"aoc/utils"
)

var testInput = `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)`

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

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)
}
}
}
Loading

0 comments on commit 9bd0b05

Please sign in to comment.