From 4cb35dca33664d78944f4a6d269be295e172aa84 Mon Sep 17 00:00:00 2001 From: efim Date: Thu, 21 Dec 2023 12:13:01 +0000 Subject: [PATCH] day21: saturation logic, but removing points to early --- day21/notes.org | 49 ++++++++++++++++ day21/stepCounter.go | 137 ++++++++++++++++++++++++++++++++++++------- 2 files changed, 164 insertions(+), 22 deletions(-) diff --git a/day21/notes.org b/day21/notes.org index 6a769b3..8a8d151 100644 --- a/day21/notes.org +++ b/day21/notes.org @@ -39,3 +39,52 @@ my input is 131 chars of width. so neighboring are necessarily of different phase. could compute phase of (0,0) and adjust from that +** TODO remake 'ReachableBySteps' into 'CountReachableBySteps' returning int +** TODO make it take 'isInitialCountOdd' - to know phase of {0,0} field +current phase can be determined by initial phase and current N + +if initial count is odd, and now it's odd number, we made even iterations, so (0,0) is in even state +if initial count is even, and now it's even number, we made even iterations, so (0,0) is in even state + +** DONE make neighbors take set of saturated fields +and not produce points on those fields +** DONE for field calculate what would be amount of points in each phase +........... +.....###.#. +.###.##..#. +..#.#...#.. +....#.#.... +.##..S####. +.##..#...#. +.......##.. +.##.#.####. +.##..##.##. +........... +*** getting 39 and 42 +let's check +42 is even? +*** hmmm +EOEOEOEOEOE +OEOEO###O#O +E###E##OE#E +OE#E#EOE#EO +EOEO#O#OEOE +O##EOE####O +E##OE#EOE#E +OEOEOEO##EO +E##O#O####E +O##EO##E##O +EOEOEOEOEOE +*** yes, sounds good + + +** TODO after getting all new points. get coords of all fields we're working on. +( there already should be no points in saturated fields ) +for each such field, check if it is saturated. + +- can be done by comparing the phase with amount of points on saturated + +if field saturated - add the coord into set +and remove all the points +** TODO on the last step, when n is 0 +return len(startingAt) + (all saturated fields) * (amount of elems in their phase) diff --git a/day21/stepCounter.go b/day21/stepCounter.go index 9c62b78..8d9764a 100644 --- a/day21/stepCounter.go +++ b/day21/stepCounter.go @@ -7,12 +7,15 @@ import ( "strings" ) -func Run() int { +func Run() (result int) { fmt.Print("hello day21") filename := "day21/example" field := ReadField(filename) log.Print(field) + initialSaturatedFields := make(map[Coord]any) + log.Print(initialSaturatedFields) + // for i := 6; i <= 10; i++ { // reachableBySteps := field.ReachableBySteps(i, map[Coord]any{ // Coord{Row: field.RowStart, Col: field.ColStart}: struct{}{}, @@ -22,14 +25,19 @@ func Run() int { // field.PrintCoord(reachableBySteps, 1) // } - steps := 100 - reachableBySteps := field.ReachableBySteps(steps, map[FieldPoint]any{ - FieldPoint{ - InField: Coord{Row: field.RowStart, Col: field.ColStart}, - }: struct{}{}, - }) + steps := 50 + reachableBySteps := field.ReachableBySteps( + steps, + map[FieldPoint]any{ + FieldPoint{ + InField: Coord{Row: field.RowStart, Col: field.ColStart}, + }: struct{}{}}, + make(map[Coord]any), + steps) + result = reachableBySteps + log.Print("reachable after steps : ", steps, result) - return len(reachableBySteps) + return result } // let's do dijkstra? @@ -38,8 +46,9 @@ func Run() int { // OR. just breath first traversal type Field struct { - RowStart, ColStart int - symbols [][]rune + RowStart, ColStart int + symbols [][]rune + SaturatedEvenCount, SaturatedOddCount int } type Coord struct { @@ -51,31 +60,86 @@ type FieldPoint struct { MetaField Coord } -func (f Field) ReachableBySteps(n int, startingAt map[FieldPoint]any) map[FieldPoint]any { +func (f Field) ReachableBySteps(n int, startingAt map[FieldPoint]any, saturatedFields map[Coord]any, initialSteps int) (countReachable int) { if n%100 == 0 { log.Println("going step: ", n) } - if n == 0 { - return startingAt + if n == 0 { + sizeOfUnsaturated := len(startingAt) + sizeOfSaturated := 0 + // log.Printf("> before adding saturated fields. central is in even %t\n", CentralFieldIsInEven(initialSteps, n)) + for saturatedField := range saturatedFields { + isEven := FieldIsInEven(initialSteps, n, saturatedField) + // log.Printf("> adding saturated field %+v. it is in even %t\n", saturatedField, isEven) + if isEven { + sizeOfSaturated += f.SaturatedEvenCount + } else { + sizeOfSaturated += f.SaturatedOddCount + } + } + + return sizeOfUnsaturated } // else collect directly available oneStepExpanded := make(map[FieldPoint]any) for cur := range startingAt { - for _, neighbor := range f.Neighbors(cur) { + for _, neighbor := range f.Neighbors(cur, saturatedFields) { oneStepExpanded[neighbor] = struct{}{} } } - if n < 4 { - log.Print("reachable after steps : ", n, len(oneStepExpanded)) - f.PrintCoord(oneStepExpanded, 5) + metaFields := make(map[Coord]int) + for next := range oneStepExpanded { + metaFields[next.MetaField] += 1 } - return f.ReachableBySteps(n-1, oneStepExpanded) + for workedUponFieldCoord, amount := range metaFields { + isEven := FieldIsInEven(initialSteps, n, workedUponFieldCoord) + if workedUponFieldCoord.Col == 0 && workedUponFieldCoord.Row == 0 { + log.Printf("checking %+v : %d as worked fields for saturation. isEven %t", workedUponFieldCoord, amount, isEven) + } + if isEven && amount == f.SaturatedEvenCount { + log.Printf(">>> adding %+v to saturated, with amount %d\n", workedUponFieldCoord, amount) + saturatedFields[workedUponFieldCoord] = struct{}{} + } + if !isEven && amount == f.SaturatedOddCount { + log.Printf(">>> adding %+v to saturated, with amount %d\n", workedUponFieldCoord, amount) + saturatedFields[workedUponFieldCoord] = struct{}{} + } + } + + for point := range oneStepExpanded { + _, fromSaturated := saturatedFields[point.MetaField] + if fromSaturated { + delete(oneStepExpanded, point) + } + } + + // if n < 4 { + // log.Print("reachable after steps : ", n, len(oneStepExpanded)) + // f.PrintCoord(oneStepExpanded, 5) + // } + + return f.ReachableBySteps(n-1, oneStepExpanded, saturatedFields, initialSteps) } -func (f Field) Neighbors(c FieldPoint) (resut []FieldPoint) { +func CentralFieldIsInEven(initialSteps, currentSteps int) bool { + // off by one here because on initial step we first do 'neighbors' then comparicons + return (initialSteps-currentSteps)%2 != 0 +} + +func FieldIsInEven(initialSteps, currentSteps int, metaCoord Coord) bool { + centralIsInEven := CentralFieldIsInEven(initialSteps, currentSteps) + fieldIsInSyncWithCentral := (metaCoord.Col+metaCoord.Row)%2 == 0 + if fieldIsInSyncWithCentral { + return centralIsInEven + } else { + return !centralIsInEven + } +} + +func (f Field) Neighbors(c FieldPoint, saturatedFields map[Coord]any) (resut []FieldPoint) { closeCoords := []FieldPoint{ {InField: Coord{Row: c.InField.Row + 1, Col: c.InField.Col}, MetaField: c.MetaField}, {InField: Coord{Row: c.InField.Row - 1, Col: c.InField.Col}, MetaField: c.MetaField}, @@ -111,11 +175,10 @@ func (f Field) Neighbors(c FieldPoint) (resut []FieldPoint) { for _, close := range closeCoords { if f.ValidCoord(close.InField.Row, close.InField.Col) { symb := f.symbols[close.InField.Row][close.InField.Col] - if symb == '.' || symb == 'S' { + _, fieldIsAlreadySaturated := saturatedFields[close.MetaField] + if (symb == '.' || symb == 'S') && !fieldIsAlreadySaturated { resut = append(resut, close) - } - } } @@ -163,6 +226,9 @@ func ReadField(filename string) (result Field) { } } result.symbols = rows + odd, even := result.PointsInEachPhase() + result.SaturatedEvenCount = even + result.SaturatedOddCount = odd return } @@ -193,3 +259,30 @@ func (f Field) PrintCoord(coords map[FieldPoint]any, expandByField int) { return } + +// if the field is fully saturated, what is amount of 'visited' points? +// odd - meaning one step around 'S', even - meaning with standing on 'S' +func (f Field) PointsInEachPhase() (pointsIfOddPhase, pointsIfEvenPhase int) { + remainderOfEvenPhase := (f.RowStart + f.ColStart) % 2 + text := "\n" + for i, row := range f.symbols { + for j, cell := range row { + if cell != '#' { + if (i+j)%2 == remainderOfEvenPhase { + pointsIfEvenPhase += 1 + text += "E" + } else { + pointsIfOddPhase += 1 + text += "O" + } + } else { + text += "#" + } + } + text += "\n" + } + fmt.Println(text) + log.Printf("calculating points in even and odd phases", pointsIfEvenPhase, pointsIfOddPhase) + + return +}