diff options
| author | omagdy <omar.professional8777@gmail.com> | 2024-12-16 19:36:22 +0200 |
|---|---|---|
| committer | omagdy <omar.professional8777@gmail.com> | 2024-12-16 19:36:22 +0200 |
| commit | 93f5880f6a4c629a280f4ce2c75e148ca935177e (patch) | |
| tree | 36881bee22e80cfe0bfe585080f11c67b630d9af /2024/go/src/day16/main.go | |
| parent | 4ed10852e1d03f3c932ebaec6df2094da42ff9a6 (diff) | |
| download | aoc-93f5880f6a4c629a280f4ce2c75e148ca935177e.tar.xz aoc-93f5880f6a4c629a280f4ce2c75e148ca935177e.zip | |
Day 16 part 1 done.
Diffstat (limited to '2024/go/src/day16/main.go')
| -rw-r--r-- | 2024/go/src/day16/main.go | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/2024/go/src/day16/main.go b/2024/go/src/day16/main.go new file mode 100644 index 0000000..a2deaa2 --- /dev/null +++ b/2024/go/src/day16/main.go @@ -0,0 +1,205 @@ +package main + +import ( + "container/heap" + "fmt" + "os" + "strings" +) + +func FileRead(path string) string { + file, err := os.ReadFile(path) + if err != nil { + fmt.Println("Couldn't Read file: ", err) + } + return string(file) +} + +type Grid = [][]byte + +type Point struct { + x int + y int +} + +func parseInput(data string) Grid { + lines := strings.Split(data, "\n") + + var grid Grid + for _, line := range lines { + if len(line) > 0 { + bytes := []byte(line) + grid = append(grid, bytes) + } + } + return grid +} + +func printGrid(grid [][]byte) { + for _, row := range grid { + for _, cell := range row { + fmt.Printf(string(cell)) + } + fmt.Println() + } +} + +func copySlice(src []Point) []Point { + dest := make([]Point, len(src)) + copy(dest, src) + return dest +} + +func findMin(arr []int) int { + min := arr[0] + for _, v := range arr[1:] { + if v < min { + min = v + } + } + return min +} + +type Direction struct { + dx, dy int +} + +type State struct { + cost int + stepCount int + pos Point + dir Direction +} + +type PriorityQueue []*State + +func (pq PriorityQueue) Len() int { return len(pq) } + +func (pq PriorityQueue) Less(i, j int) bool { + return pq[i].cost < pq[j].cost +} + +func (pq PriorityQueue) Swap(i, j int) { + pq[i], pq[j] = pq[j], pq[i] +} + +func (pq *PriorityQueue) Push(x interface{}) { + item := x.(*State) + *pq = append(*pq, item) +} + +func (pq *PriorityQueue) Pop() interface{} { + old := *pq + n := len(old) + item := old[n-1] + *pq = old[0 : n-1] + return item +} + +func inBounds(x, y, rows, cols int, grid [][]byte) bool { + return x >= 0 && x < rows && y >= 0 && y < cols && grid[x][y] != '#' +} + +func findPosition(grid [][]byte, target byte) (Point, bool) { + for i := range grid { + for j := range grid[i] { + if grid[i][j] == target { + return Point{i, j}, true + } + } + } + return Point{}, false +} + +func dijkstra(grid [][]byte) (int, int) { // Returns cost and step count + start, found := findPosition(grid, 'E') + if !found { + return -1, -1 // 'E' not found + } + + if grid[start.x][start.y] == 'S' { + return 0, 0 // Start is the end + } + + var directions = [4]Direction{ + {1, 0}, // Down + {0, 1}, // Right + {-1, 0}, // Up + {0, -1}, // Left + } + + pq := &PriorityQueue{} + heap.Init(pq) + + type Key struct { + x, y, dx, dy int + } + + minCost := make(map[Key]int) + stepCounts := make(map[Key]int) + + heap.Push(pq, &State{cost: 0, stepCount: 0, pos: start, dir: Direction{0, 0}}) + + for pq.Len() > 0 { + current := heap.Pop(pq).(*State) + cost := current.cost + stepCount := current.stepCount + pos := current.pos + dir := current.dir + + key := Key{pos.x, pos.y, dir.dx, dir.dy} + + if existingCost, exists := minCost[key]; exists && cost >= existingCost { + continue + } + minCost[key] = cost + stepCounts[key] = stepCount + + if grid[pos.x][pos.y] == 'S' { + return cost, stepCount + } + + for _, d := range directions { + nx, ny := pos.x+d.dx, pos.y+d.dy + if inBounds(nx, ny, len(grid), len(grid[0]), grid) { + var newCost int + if dir == (Direction{0, 0}) || d == dir { + newCost = cost + 1 + } else { + newCost = cost + 1001 + } + newStepCount := stepCount + 1 + + newKey := Key{nx, ny, d.dx, d.dy} + + if existingCost, exists := minCost[newKey]; !exists || newCost < existingCost { + heap.Push(pq, &State{cost: newCost, stepCount: newStepCount, pos: Point{nx, ny}, dir: d}) + } + } + } + } + + return -1, -1 // 'S' is not reachable +} + +func solve_part_one(data string) int { + maze := parseInput(data) + cost, _ := dijkstra(maze) + return cost +} + +func solve_part_two(data string) int { + maze := parseInput(data) + _, lenPath := dijkstra(maze) + return lenPath +} + +func main() { + test := FileRead("../input/day16_1.test") + // test := FileRead("../input/day16_2.test") + prod := FileRead("../input/day16.prod") + fmt.Println("Part_1 test: ", solve_part_one(test)) + fmt.Println("Part_1 prod: ", solve_part_one(prod)) + fmt.Println("Part_2 test: ", solve_part_two(test)) + // fmt.Println("Part_2 prod: ", solve_part_two(prod)) +} |
