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 }