day21: saturation logic, but removing points to early

This commit is contained in:
efim 2023-12-21 12:13:01 +00:00
parent 840773fd16
commit 4cb35dca33
2 changed files with 164 additions and 22 deletions

View File

@ -39,3 +39,52 @@ my input is 131 chars of width.
so neighboring are necessarily of different phase. so neighboring are necessarily of different phase.
could compute phase of (0,0) could compute phase of (0,0)
and adjust from that 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)

View File

@ -7,12 +7,15 @@ import (
"strings" "strings"
) )
func Run() int { func Run() (result int) {
fmt.Print("hello day21") fmt.Print("hello day21")
filename := "day21/example" filename := "day21/example"
field := ReadField(filename) field := ReadField(filename)
log.Print(field) log.Print(field)
initialSaturatedFields := make(map[Coord]any)
log.Print(initialSaturatedFields)
// for i := 6; i <= 10; i++ { // for i := 6; i <= 10; i++ {
// reachableBySteps := field.ReachableBySteps(i, map[Coord]any{ // reachableBySteps := field.ReachableBySteps(i, map[Coord]any{
// Coord{Row: field.RowStart, Col: field.ColStart}: struct{}{}, // Coord{Row: field.RowStart, Col: field.ColStart}: struct{}{},
@ -22,14 +25,19 @@ func Run() int {
// field.PrintCoord(reachableBySteps, 1) // field.PrintCoord(reachableBySteps, 1)
// } // }
steps := 100 steps := 50
reachableBySteps := field.ReachableBySteps(steps, map[FieldPoint]any{ reachableBySteps := field.ReachableBySteps(
steps,
map[FieldPoint]any{
FieldPoint{ FieldPoint{
InField: Coord{Row: field.RowStart, Col: field.ColStart}, InField: Coord{Row: field.RowStart, Col: field.ColStart},
}: struct{}{}, }: struct{}{}},
}) make(map[Coord]any),
steps)
result = reachableBySteps
log.Print("reachable after steps : ", steps, result)
return len(reachableBySteps) return result
} }
// let's do dijkstra? // let's do dijkstra?
@ -40,6 +48,7 @@ func Run() int {
type Field struct { type Field struct {
RowStart, ColStart int RowStart, ColStart int
symbols [][]rune symbols [][]rune
SaturatedEvenCount, SaturatedOddCount int
} }
type Coord struct { type Coord struct {
@ -51,31 +60,86 @@ type FieldPoint struct {
MetaField Coord 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 { if n%100 == 0 {
log.Println("going step: ", n) log.Println("going step: ", n)
} }
if n == 0 { if n == 0 {
return startingAt 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 // else collect directly available
oneStepExpanded := make(map[FieldPoint]any) oneStepExpanded := make(map[FieldPoint]any)
for cur := range startingAt { for cur := range startingAt {
for _, neighbor := range f.Neighbors(cur) { for _, neighbor := range f.Neighbors(cur, saturatedFields) {
oneStepExpanded[neighbor] = struct{}{} oneStepExpanded[neighbor] = struct{}{}
} }
} }
if n < 4 { metaFields := make(map[Coord]int)
log.Print("reachable after steps : ", n, len(oneStepExpanded)) for next := range oneStepExpanded {
f.PrintCoord(oneStepExpanded, 5) 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{ 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},
{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 { for _, close := range closeCoords {
if f.ValidCoord(close.InField.Row, close.InField.Col) { if f.ValidCoord(close.InField.Row, close.InField.Col) {
symb := f.symbols[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) resut = append(resut, close)
} }
} }
} }
@ -163,6 +226,9 @@ func ReadField(filename string) (result Field) {
} }
} }
result.symbols = rows result.symbols = rows
odd, even := result.PointsInEachPhase()
result.SaturatedEvenCount = even
result.SaturatedOddCount = odd
return return
} }
@ -193,3 +259,30 @@ func (f Field) PrintCoord(coords map[FieldPoint]any, expandByField int) {
return 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
}