package day21 import ( "fmt" "log" "os" "strings" ) func Run() int { fmt.Print("hello day21") filename := "day21/input" field := ReadField(filename) log.Print(field) // for i := 6; i <= 10; i++ { // reachableBySteps := field.ReachableBySteps(i, map[Coord]any{ // Coord{Row: field.RowStart, Col: field.ColStart}: struct{}{}, // }) // log.Print("reachable after steps : ", i, len(reachableBySteps)) // field.PrintCoord(reachableBySteps, 1) // } // initialSolutions := make(map[int]int) // for fullIter := 0; fullIter < 4; fullIter++ { // steps := 65 + fullIter * 131 // reachableBySteps := field.ReachableBySteps(steps, map[FieldPoint]any{ // FieldPoint{ // InField: Coord{Row: field.RowStart, Col: field.ColStart}, // }: struct{}{}, // }) // log.Printf("after steps %d. full iter %d. got count %d", steps, fullIter, len(reachableBySteps)) // initialSolutions[fullIter] = len(reachableBySteps) // } log.Println("will try to use the values to get coeff of Ax^2 + Bx + C = 0") log.Println("then solve for x == 202300") // f(x) = 14714x^2 + 14603x + 3791 // no. // 14669x^2 + 14738*x+3701 x := 202300 result := 14669*x*x + 14738*x+3701 return result } // let's do dijkstra? // i would need lots of space for edges? // let's use a map with minimal distances? // OR. just breath first traversal type Field struct { RowStart, ColStart int symbols [][]rune } type Coord struct { Row, Col int } type FieldPoint struct { InField Coord MetaField Coord } func (f Field) ReachableBySteps(n int, startingAt map[FieldPoint]any) map[FieldPoint]any { if n%100 == 0 { log.Println("going step: ", n) } if n == 0 { return startingAt } // else collect directly available oneStepExpanded := make(map[FieldPoint]any) for cur := range startingAt { for _, neighbor := range f.Neighbors(cur) { oneStepExpanded[neighbor] = struct{}{} } } // if n < 4 { // log.Print("reachable after steps : ", n, len(oneStepExpanded)) // f.PrintCoord(oneStepExpanded, 5) // } return f.ReachableBySteps(n-1, oneStepExpanded) } func (f Field) Neighbors(c FieldPoint) (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}, {InField: Coord{Row: c.InField.Row, Col: c.InField.Col + 1}, MetaField: c.MetaField}, {InField: Coord{Row: c.InField.Row, Col: c.InField.Col - 1}, MetaField: c.MetaField}, } for i, close := range closeCoords { height := len(f.symbols) width := len(f.symbols[0]) if close.InField.Row == height { close.InField.Row = 0 close.MetaField.Row += 1 } if close.InField.Row == -1 { close.InField.Row = height - 1 close.MetaField.Row -= 1 } if close.InField.Col == width { close.InField.Col = 0 close.MetaField.Col += 1 } if close.InField.Col == -1 { // log.Printf("moving COL to lefter field from %d to %d", close.Col, width-1) close.InField.Col = width - 1 close.MetaField.Col -= 1 } closeCoords[i] = close // but this is not it. i need to store the XX and YY // so that points in other 'fields' would count separately. yuk } 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' { resut = append(resut, close) } } } // log.Print("getting neighbors for ", c, resut) return } func (f Field) ValidCoord(row, col int) bool { // log.Print("check valid ", row, col, row >= 0 && row < len(f.symbols) && col >= 0 && col < len(f.symbols[0])) valid := row >= 0 && row < len(f.symbols) && col >= 0 && col < len(f.symbols[0]) if !valid { panic(fmt.Sprint("getting invalid coord: ", row, col)) } return valid } func (f Field) String() (result string) { result += "\n" for _, line := range f.symbols { result += string(line) result += "\n" } return } func ReadField(filename string) (result Field) { bytes, err := os.ReadFile(filename) if err != nil { panic(err) } text := strings.TrimSpace(string(bytes)) lines := strings.Split(text, "\n") rows := make([][]rune, len(lines)) for rowNum, line := range lines { rows[rowNum] = []rune(line) for colNum, symb := range line { if symb == 'S' { result.RowStart = rowNum result.ColStart = colNum } } } result.symbols = rows return } func (f Field) PrintCoord(coords map[FieldPoint]any, expandByField int) { for fieldRow := -expandByField; fieldRow <= expandByField; fieldRow++ { lines := make([]string, len(f.symbols)) for fieldCol := -expandByField; fieldCol <= expandByField; fieldCol++ { for rowNum, row := range f.symbols { for colNum, col := range row { _, marked := coords[FieldPoint{InField: Coord{Row: rowNum, Col: colNum}, MetaField: Coord{Row: fieldRow, Col: fieldCol}}] if marked { lines[rowNum] += "O" } else { lines[rowNum] += string(col) } } } } for _, line := range lines { fmt.Println(line) } } return }