package day10 import ( "fmt" "log" ) const ( EAST = 'E' SOUTH = 'S' WEST = 'W' NORTH = 'N' ) type Move struct { row int col int origin rune count int } //var checked = map[Move]bool{} func findStart(lines []string) (*Move, *Move, *Move) { var start *Move OuterLoop: for row, l := range lines { for col, c := range l { if c == 'S' { start = &Move{row, col, 0, 0} break OuterLoop } } } m := make([]*Move, 2) i := 0 if start.row >= 1 && (lines[start.row-1][start.col] == '7' || lines[start.row-1][start.col] == '|' || lines[start.row-1][start.col] == 'F') { m[i] = &Move{start.row - 1, start.col, 'S', 1} i++ } if start.row <= len(lines)-2 && (lines[start.row+1][start.col] == 'L' || lines[start.row+1][start.col] == '|' || lines[start.row+1][start.col] == 'J') { m[i] = &Move{start.row + 1, start.col, 'N', 1} i++ } if start.col >= 1 && (lines[start.row][start.col-1] == '-' || lines[start.row][start.col-1] == 'L' || lines[start.row][start.col-1] == 'F') { m[i] = &Move{start.row, start.col - 1, 'E', 1} i++ } width := len(lines[start.row]) if start.col <= width-2 && (lines[start.row][start.col+1] == '-' || lines[start.row][start.col+1] == 'J' || lines[start.row][start.col+1] == '7') { m[i] = &Move{start.row, start.col + 1, 'W', 1} i++ } return start, m[0], m[1] } func nextMove(m *Move, lines []string) *Move { switch lines[m.row][m.col] { case '|': // vertical pipe connecting north and south. if m.origin == 'N' { return &Move{m.row + 1, m.col, 'N', m.count + 1} } else { return &Move{m.row - 1, m.col, 'S', m.count + 1} } case '-': // horizontal pipe connecting east and west. if m.origin == 'W' { return &Move{m.row, m.col + 1, 'W', m.count + 1} } else { return &Move{m.row, m.col - 1, 'E', m.count + 1} } case 'L': // 90-degree bend connecting north and east. if m.origin == 'N' { return &Move{m.row, m.col + 1, 'W', m.count + 1} } else { return &Move{m.row - 1, m.col, 'S', m.count + 1} } case 'J': // 90-degree bend connecting north and west. if m.origin == 'N' { return &Move{m.row, m.col - 1, 'E', m.count + 1} } else { return &Move{m.row - 1, m.col, 'S', m.count + 1} } case '7': // 90-degree bend connecting south and west. if m.origin == 'S' { return &Move{m.row, m.col - 1, 'E', m.count + 1} } else { return &Move{m.row + 1, m.col, 'N', m.count + 1} } case 'F': // a 90-degree bend connecting south and east. if m.origin == 'S' { return &Move{m.row, m.col + 1, 'W', m.count + 1} } else { return &Move{m.row + 1, m.col, 'N', m.count + 1} } case 'S': // is ground; there is no pipe in this tile. return m case '.': // is ground; there is no pipe in this tile. log.Fatalf("Should not find ground %v : ", m) default: log.Fatalf("Impossible move %v : ", m) } return nil } func FindDistance(lines []string) int { /* Iterative DFS ------------- let S be a stack S.push(v) while S is not empty do v = S.pop() if v is not labeled as discovered then label v as discovered for all edges from v to w in G.adjacentEdges(v) do S.push(w) stack := utils.NewStack[*Move](140 * 140) stack.Push(findStart(lines)) for stack.HasElement() { lastMove := stack.Pop() } */ start, m1, m2 := findStart(lines) fmt.Println("Starting at ", *start) for { if m1.col == m2.col && m1.row == m2.row { fmt.Println("Finished at ", *m1) return m1.count } else { m1 = nextMove(m1, lines) m2 = nextMove(m2, lines) } } } func isInPolygon(row int, col int, lines [][]rune) bool { count := 0 last := rune(0) for i := col; i < len(lines[row]); i++ { c := lines[row][i] switch c { case 'S', '|', 'L', 'J', '7', 'F': // skip '-' and do not count it as part of the polygon border if last == 'F' && c == 'J' || last == 'L' && c == '7' { // count these as a single border of the polygon last = c continue } last = c count++ } } return count%2 == 1 } func CountInPolygon(lines []string) int { writeableLines := make([][]rune, len(lines)) for i := range lines { writeableLines[i] = []rune(lines[i]) } // delimit the loop with a specific rune different from the ones used in the problem ('*') start, m1, m2 := findStart(lines) fmt.Println("Starting at ", *start) writeableLines[start.row][start.col] = '*' writeableLines[m1.row][m1.col] = '*' writeableLines[m2.row][m2.col] = '*' for { if m1.col == m2.col && m1.row == m2.row { fmt.Println("Finished at ", *m1) break } else { m1 = nextMove(m1, lines) m2 = nextMove(m2, lines) writeableLines[m1.row][m1.col] = '*' writeableLines[m2.row][m2.col] = '*' } } // mark all tile that are not part of the loop as a tile that can count in the total with rune '.' for row, l := range writeableLines { for col, c := range l { if c != '*' { writeableLines[row][col] = '.' } } } // reproduce the original loop in the grid with the '.' correctly set up for row, l := range writeableLines { for col, c := range l { if c == '*' { writeableLines[row][col] = []rune(lines[row])[col] } } } result := 0 for row, l := range writeableLines { for col, c := range l { if c == '.' { if isInPolygon(row, col, writeableLines) { result++ } } } } return result }