From 6dabe8bc66d42479063c1a34bbf315146bef8f6d Mon Sep 17 00:00:00 2001 From: efim Date: Mon, 18 Dec 2023 19:37:17 +0000 Subject: [PATCH] day18, another example working --- day18/lagoon.go | 178 ++++++++++++++++++++++++++++++++++++++++-------- day18/notes.org | 5 +- 2 files changed, 152 insertions(+), 31 deletions(-) diff --git a/day18/lagoon.go b/day18/lagoon.go index 1b58d72..464622f 100644 --- a/day18/lagoon.go +++ b/day18/lagoon.go @@ -12,8 +12,8 @@ import ( func Run() int { log.Println("hello day 18") log.Println("problem of lagoon bgins") - filename := "day18/example2" - instructions := ReadInstructionas2(filename) + filename := "day18/example" + instructions := ReadInstructionas(filename) h, w := calcHeightWidth(instructions) log.Printf("read %+v instructions", instructions) @@ -21,7 +21,7 @@ func Run() int { fmt.Println(field.String()) borderAmount := field.digByInstructions(instructions) - // log.Println("created field", field.BorderCellCols) + log.Println(">>> created field", field.BordersFromLeft) fmt.Println(field.String()) // WriteToFile("borders.txt", field.String()) @@ -208,17 +208,25 @@ type Cell struct { ToBeDug bool Coord Coord } + +type BorderSymbol rune +// '' always left to right +const (Vertical BorderSymbol = '|' + ToDown BorderSymbol = '7' + ToUp BorderSymbol = 'J' + FromUp BorderSymbol = 'F' + FromDown BorderSymbol = 'L' +) + type Field struct { Height, Width int // Cells [][]*Cell Cells map[Coord]*Cell MinRow, MaxRow, MinCol, MaxCol int - // TODO - make this map[int]map[int]any (for the set) - BorderCellCols map[int][]int // known row -> col + BordersFromLeft map[int]map[int]BorderSymbol } func (f *Field)confirmCoord(c Coord) { // log.Printf("configming coord %+v", c) - f.BorderCellCols[c.Row] = append(f.BorderCellCols[c.Row], c.Col) if c.Row - 3 < f.MinRow { f.MinRow = c.Row - 3 @@ -238,11 +246,25 @@ func CreateField(height, width int) Field { return Field{ Height: height, Width: width, Cells: make(map[Coord]*Cell), - BorderCellCols: make(map[int][]int), + BordersFromLeft: make(map[int]map[int]BorderSymbol), } } +func PutSymbIntoMMMMap(mmmap map[int]map[int]BorderSymbol, row, col int, symb BorderSymbol) { + rowMap := mmmap[row] + if rowMap == nil { + rowMap = make(map[int]BorderSymbol) + mmmap[row] = rowMap + } + rowMap[col] = symb +} + func (f *Field) digByInstructions(instructions []Instruction) (borderAmount int) { + // for the last turn + instructions = append(instructions, instructions[0]) + // but also don't overcount the border + borderAmount -= instructions[0].Steps + runnerCoord := Coord{Col: 0, Row: 0} f.Cells[runnerCoord] = &Cell{ IsDug: true, @@ -250,8 +272,19 @@ func (f *Field) digByInstructions(instructions []Instruction) (borderAmount int) // f.confirmCoord(runnerCoord) // should be confirmed when the cycle is closed on last step // borderAmount += 1 + var prevInstruction Instruction + firstInstruction := true for _, instruction := range instructions { - fmt.Printf("starting instruction %+v", instruction) + log.Printf("starting new instruction %+v", instruction) + if !firstInstruction { + turn := getTurnAsIfGoingFromLeft(prevInstruction.Direction, instruction.Direction) + for _, theTurn := range turn { + log.Printf(">> putting turn %s", string(turn)) + PutSymbIntoMMMMap(f.BordersFromLeft, runnerCoord.Row, runnerCoord.Col, theTurn) + } + } + firstInstruction = false + log.Printf("starting instruction %+v", instruction) for i := 0; i < instruction.Steps; i++ { runnerCoord = runnerCoord.applyDirection(instruction.Direction) f.Cells[runnerCoord] = &Cell{ @@ -259,22 +292,77 @@ func (f *Field) digByInstructions(instructions []Instruction) (borderAmount int) } f.confirmCoord(runnerCoord) borderAmount += 1 + log.Printf("inside %+v updated border amount to %d", instruction, borderAmount) + + if instruction.Direction == Upward || instruction.Direction == Downward { + _, alreadyCountedTurn := f.BordersFromLeft[runnerCoord.Row][runnerCoord.Col] + if !alreadyCountedTurn { + PutSymbIntoMMMMap(f.BordersFromLeft, runnerCoord.Row, runnerCoord.Col, Vertical) + } + } + } + prevInstruction = instruction } return } +func getTurnAsIfGoingFromLeft(directionFrom, directionTo Direction) []BorderSymbol { + log.Printf("getTurnAsIfGoingFromLeft from %s to %s", directionFrom.String(), directionTo.String()) + + var symbol BorderSymbol + if directionTo == Rightward && directionFrom == Upward { + symbol = FromUp + } + if directionTo == Rightward && directionFrom == Downward { + symbol = FromDown + } + if directionTo == Leftward && directionFrom == Upward { + symbol = ToDown + } + if directionTo == Leftward && directionFrom == Downward { + symbol = ToUp + } + + if directionFrom == Rightward && directionTo == Upward { + symbol = ToUp + } + if directionFrom == Rightward && directionTo == Downward { + symbol = ToDown + } + if directionFrom == Leftward && directionTo == Upward { + symbol = FromDown + } + if directionFrom == Leftward && directionTo == Downward { + symbol = FromUp + } + + + // panic(fmt.Sprint("got strange from %s to %s", directionFrom.String(), directionTo.String())) + return []BorderSymbol{symbol} +} + func (f *Field) String() string { s := "text 15,15 \"" for row := f.MinRow; row <= f.MaxRow; row++ { rowChars := make([]rune, f.MaxCol - f.MinCol + 1) for col := f.MinCol; col <= f.MaxCol; col++ { + + rowBords := f.BordersFromLeft[row] + if rowBords != nil { + bord, exists := rowBords[col] + if exists { + rowChars[col - f.MinCol] = rune(bord) + continue + } + } cell := f.Cells[Coord{col, row}] if cell != nil && cell.ToBeDug { rowChars[col - f.MinCol] = '@' continue } + if f.isCellDug(row, col) { rowChars[col - f.MinCol] = '#' } else { @@ -293,34 +381,64 @@ func (f *Field) digInsides() (countInside int) { if row % 10000 == 0 { log.Printf("processed rows %d out of %d", row, f.MaxRow) } - thisRowBorderCols := f.BorderCellCols[row] - slices.Sort(thisRowBorderCols) - // log.Printf("cols for row %d are %+v", row, thisRowBorderCols) - if len(thisRowBorderCols) == 0 { + specialBorders := f.BordersFromLeft[row] + if len(specialBorders) == 0 { continue } - isInside := true - prevCol := thisRowBorderCols[0] - for _, col := range thisRowBorderCols[1:] { - gap := (col - prevCol - 1) - if gap == 0 { - prevCol = col + type BorderItem struct { + border BorderSymbol + col int + } + rowBorders := make([]BorderItem, 0) + for col, borderSymbol := range specialBorders { + rowBorders = append(rowBorders, BorderItem{borderSymbol, col}) + } + slices.SortFunc(rowBorders, func(a BorderItem, b BorderItem) int { + return a.col - b.col + }) + + // log.Printf(">>>>>>> for row %d sorted %+v", row, rowBorders) + prevBorder := rowBorders[0] + bordersCrossed := 0 + if prevBorder.border == Vertical { + bordersCrossed += 1 + } + for _, specialBorder := range rowBorders[1:] { + diff := specialBorder.col - prevBorder.col - 1 + + if specialBorder.border == ToUp && prevBorder.border == FromUp { + bordersCrossed += 1 + prevBorder = specialBorder continue } - // log.Printf("found gap in row %d. is inside %t. between col %d and %d of length %d", - // row, isInside, col, prevCol, gap) - if isInside { - for coll := prevCol+1; coll < col; coll++ { - f.Cells[Coord{Col: coll, Row: row}] = &Cell{ - ToBeDug: true, - } - - } - countInside += gap + if specialBorder.border == ToDown && prevBorder.border == FromDown { + bordersCrossed += 1 + prevBorder = specialBorder + continue + } + if specialBorder.border == ToUp && prevBorder.border == FromDown { + prevBorder = specialBorder + continue + } + if specialBorder.border == ToDown && prevBorder.border == FromUp { + prevBorder = specialBorder + continue } - isInside = !isInside - prevCol = col + if bordersCrossed % 2 == 1 { // is in + for col := prevBorder.col+1; col < specialBorder.col; col++ { + f.Cells[Coord{Col: col, Row: row}] = &Cell{ + ToBeDug: true, + } + } + countInside += diff + } + + if specialBorder.border == Vertical { + bordersCrossed += 1 + } + + prevBorder = specialBorder } } return diff --git a/day18/notes.org b/day18/notes.org index a29e128..0fa45d9 100644 --- a/day18/notes.org +++ b/day18/notes.org @@ -19,9 +19,12 @@ when there's a jump - compare counts, to make decision on whether to switch 'isI ** no. just because they are long doesn't mean they won't ever get one near another * another idea is to save | and corners, as if we're going from left to right this seems reasonable. -** TODO i guess []SpecialSymbol which has Col and Symbol +** DONE i guess []SpecialSymbol which has Col and Symbol +** DONE no, let's make it map. yes will have to init, but yuck anyway ** TODO then different logic on border building. if U \ D - on all but last add '|' on last - calc with the next turn, what should be saved 'as if traversing from the left' for L \ R - on last - calc what the turn was +** TODO !! between last and first movement the corner is unknown. +so, copy the first instruction to the end?