From 49fc57029fbc4e5bde7b5f334208b8f8015f85e4 Mon Sep 17 00:00:00 2001 From: efim Date: Mon, 18 Dec 2023 09:41:22 +0000 Subject: [PATCH] day18, example --- day17/clumsyCrucible.go | 4 +- day18/example | 14 +++ day18/lagoon.go | 256 ++++++++++++++++++++++++++++++++++++++++ main.go | 6 +- 4 files changed, 275 insertions(+), 5 deletions(-) create mode 100644 day18/example create mode 100644 day18/lagoon.go diff --git a/day17/clumsyCrucible.go b/day17/clumsyCrucible.go index 049f655..540e76e 100644 --- a/day17/clumsyCrucible.go +++ b/day17/clumsyCrucible.go @@ -11,7 +11,7 @@ import ( func Run() int { fmt.Println("hello from day 17") - filename := "day17/example" + filename := "day17/input" field := NewField(filename) log.Printf("%+v\n", field) @@ -140,7 +140,7 @@ func (p *PathSegmentEnd) NextDirections2() (next []Direction) { next = append(next, p.lastDirection) } - log.Printf("getting directions from %+v they are %+v", p, next) + // log.Printf("getting directions from %+v they are %+v", p, next) return } diff --git a/day18/example b/day18/example new file mode 100644 index 0000000..fc7612e --- /dev/null +++ b/day18/example @@ -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) diff --git a/day18/lagoon.go b/day18/lagoon.go new file mode 100644 index 0000000..40a252f --- /dev/null +++ b/day18/lagoon.go @@ -0,0 +1,256 @@ +package day18 + +import ( + "fmt" + "log" + "os" + "slices" + "strconv" + "strings" +) + +func Run() int { + fmt.Println("hello day 18") + log.Println("problem of lagoon bgins") + filename := "day18/example" + instructions := ReadInstructionas(filename) + h, w := calcHeightWidth(instructions) + field := CreateField(h, w) + + fmt.Println(field.String()) + + field.digByInstructions(instructions) + + fmt.Println(field.String()) + // i'll start at (0,0), let's first just dig out the thing and check result + field.digInsides() + + fmt.Println(field.String()) + + return field.countDugOut() +} + +// determine size of field. max(sum(up), sum(down)) for height, +// same for left and right, +// translate (0,0) into center of the field +// +// have cells, with coord. and i guess four sides, with color. +// i guess have directions, map[direction]color +// and have 'opposite' on directoin. +// for each direction apply it to cell coord, get cell, get opposite directoin and color it +// +// then have method on field and cell that excavates cell and colors all neighbors +// +// last part is filling in isides, should be ok with horizontal scans from left by even crossings + +type Direction int +const (Upward Direction = iota +Downward +Leftward +Rightward) + +func (d Direction)opposite() Direction { + switch d { + case Upward: + return Downward + case Downward: + return Upward + case Leftward: + return Rightward + case Rightward: + return Leftward + } + panic("unaccounted direction") +} + +var DirectionNames []string = []string{"U", "D", "L", "R"} + +func (d Direction)String() string { + return DirectionNames[d] +} +func DirectionFromString(s string) Direction { + index := slices.Index(DirectionNames, s) + if index == -1 { + panic(fmt.Sprint("bad direction", s)) + } + return Direction(index) +} + +type Instruction struct { + Direction Direction + Steps int + Color string +} + +func ReadInstructionas(filename string) (result []Instruction) { + bytes, err := os.ReadFile(filename) + if err != nil { + panic(fmt.Sprint("error reading file: ", filename)) + } + text := strings.TrimSpace(string(bytes)) + for _, line := range strings.Split(text, "\n") { + result = append(result, ReadInstruction(line)) + } + + return +} + +func ReadInstruction(line string) Instruction { + fields := strings.Fields(line) + direction := DirectionFromString(fields[0]) + steps, err := strconv.Atoi(fields[1]) + if err != nil { + panic(fmt.Sprint("bad steps in line: ", line)) + } + color := fields[2][1 : len(fields[2])-1] + + return Instruction{Direction: direction, Steps: steps, Color: color} +} + +func calcHeightWidth(instructions []Instruction) (height, width int) { + movements := make(map[Direction]int) + for _, instr := range instructions { + movements[instr.Direction] += instr.Steps + } + if movements[Downward] > movements[Upward] { + height = 2 * movements[Downward] + } else { + height = 2 * movements[Upward] + } + + if movements[Leftward] > movements[Rightward] { + width = 2 * movements[Leftward] + } else { + width = 2 * movements[Rightward] + } + + height += 10 + width += 10 + + return +} + +type Coord struct { + X, Y int +} +func (c Coord)applyDirection(d Direction) Coord { + switch d { + case Upward: + c.Y -= 1 + case Downward: + c.Y += 1 + case Leftward: + c.X -= 1 + case Rightward: + c.X += 1 + } + + return c +} + +type Cell struct { + IsDug bool + Walls map[Direction]string + Coord Coord +} +type Field struct { + Height, Width int + Cells [][]*Cell +} + +func CreateField(height, width int) Field { + rows := make([][]*Cell, height) + for i := 0; i < height; i++ { + row := make([]*Cell, width) + rows[i] = row + for j := 0; j < width; j++ { + row[j] = &Cell{ + Walls: make(map[Direction]string), + } + } + } + return Field{ + Height: height, Width: width, + Cells: rows, + } +} + +func (f *Field)coordToIndices(c Coord) (row, col int) { + row = c.Y + (f.Height/2) + col = c.X + (f.Width/2) + return +} + +func (f *Field)digByInstructions(instructions []Instruction) { + runnerCoord := Coord{X: 0, Y: 0} + row, col := f.coordToIndices(runnerCoord) + f.Cells[row][col].IsDug = true + + for _, instruction := range instructions { + for i := 0; i < instruction.Steps; i++ { + runnerCoord = runnerCoord.applyDirection(instruction.Direction) + row, col := f.coordToIndices(runnerCoord) + f.Cells[row][col].IsDug = true + } + } + return +} + +func (f *Field)String() string { + s := "\n" + for _, row := range f.Cells { + for _, cell := range row { + if cell.IsDug { + s += "#" + } else { + s += "." + } + } + s += "\n" + } + return s +} + +func (f *Field)digInsides() { + for row := 0; row < f.Height; row++ { + isInside := false + seenUp, seenDown := false, false // for detecting L---7 walls + for col := 0; col < f.Width - 1; col++ { + cellPtr := f.Cells[row][col] + rightCell := f.Cells[row][col+1] + if cellPtr.IsDug { + upCell := f.Cells[row-1][col] + downCell := f.Cells[row+1][col] + if !rightCell.IsDug { + if (upCell.IsDug && seenDown) || (downCell.IsDug && seenUp) { + isInside = !isInside + } + seenUp, seenDown = false, false + } + } else { + // not a dug out cell, maybe inside and needs to be dug out + if isInside { + cellPtr.IsDug = true + } + if rightCell.IsDug { + nextUpCell := f.Cells[row-1][col+1] + nextDownCell := f.Cells[row+1][col+1] + seenUp = nextUpCell.IsDug + seenDown = nextDownCell.IsDug + } + + } + } + } +} + +func (f *Field)countDugOut() (result int) { + for _, row := range f.Cells { + for _, cell := range row { + if cell.IsDug { + result += 1 + } + } + } + return +} diff --git a/main.go b/main.go index 9d021e7..63538d1 100644 --- a/main.go +++ b/main.go @@ -3,12 +3,12 @@ package main import ( "log" - "sunshine.industries/aoc2023/day17" + "sunshine.industries/aoc2023/day18" ) func main() { log.Print("> starting run:") - result := day17.Run() - log.Printf("\n\nday17 result: %d\n****\n", result) + result := day18.Run() + log.Printf("\n\nday18 result: %d\n****\n", result) }