this post was submitted on 16 Dec 2023
18 points (100.0% liked)

Advent Of Code

770 readers
1 users here now

An unofficial home for the advent of code community on programming.dev!

Advent of Code is an annual Advent calendar of small programming puzzles for a variety of skill sets and skill levels that can be solved in any programming language you like.

AoC 2023

Solution Threads

M T W T F S S
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25

Rules/Guidelines

Relevant Communities

Relevant Links

Credits

Icon base by Lorc under CC BY 3.0 with modifications to add a gradient

console.log('Hello World')

founded 1 year ago
MODERATORS
 

Day 16: The Floor Will Be Lava

Megathread guidelines

  • Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
  • You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://topaz.github.io/paste/ if you prefer sending it through a URL

FAQ

you are viewing a single comment's thread
view the rest of the comments
[โ€“] [email protected] 1 points 11 months ago

Golang

Avoided recursion by having an array of "pending paths". Whenever I hit a splitter, I follow one of the paths straight away, and push the starting point and direction of the other path to the array.

First time I ran it, hit an infinite loop. Handled it by skipping "|" and "-" if they have been visited already.

Part 2 is the same code as part 1 but I just check all the possible starting points.

Code

package main

import (
	"bufio"
	"fmt"
	"os"
)

type Direction int

const (
	UP    Direction = 0
	DOWN  Direction = 1
	LEFT  Direction = 2
	RIGHT Direction = 3
)

type LightPoint struct {
	row int
	col int
	dir Direction
}

func solve(A [][]rune, start LightPoint) int {
	m := len(A)
	n := len(A[0])
	visited := make([]bool, m*n)
	points := []LightPoint{}
	points = append(points, start)

	for len(points) > 0 {
		current := points[0]
		points = points[1:]
		i := current.row
		j := current.col
		dir := current.dir

		for {
			if i < 0 || i >= m || j < 0 || j >= n {
				break
			}
			if visited[i*n+j] && (A[i][j] == '-' || A[i][j] == '|') {
				break
			}

			visited[i*n+j] = true

			if A[i][j] == '.' ||
				(A[i][j] == '-' && (dir == LEFT || dir == RIGHT)) ||
				(A[i][j] == '|' && (dir == UP || dir == DOWN)) {
				switch dir {
				case UP:
					i--
				case DOWN:
					i++
				case LEFT:
					j--
				case RIGHT:
					j++
				}
				continue
			}

			if A[i][j] == '\\' {
				switch dir {
				case UP:
					dir = LEFT
					j--
				case DOWN:
					dir = RIGHT
					j++
				case LEFT:
					dir = UP
					i--
				case RIGHT:
					dir = DOWN
					i++
				}
				continue
			}

			if A[i][j] == '/' {
				switch dir {
				case UP:
					dir = RIGHT
					j++
				case DOWN:
					dir = LEFT
					j--
				case LEFT:
					dir = DOWN
					i++
				case RIGHT:
					dir = UP
					i--
				}
				continue
			}

			if A[i][j] == '-' && (dir == UP || dir == DOWN) {
				points = append(points, LightPoint{row: i, col: j + 1, dir: RIGHT})
				dir = LEFT
				j--
				continue
			}

			if A[i][j] == '|' && (dir == LEFT || dir == RIGHT) {
				points = append(points, LightPoint{row: i + 1, col: j, dir: DOWN})
				dir = UP
				i--
			}
		}
	}

	energized := 0
	for _, v := range visited {
		if v {
			energized++
		}
	}
	return energized
}

func part1(A [][]rune) {
	start := LightPoint{row: 0, col: 0, dir: RIGHT}
	energized := solve(A, start)
	fmt.Println(energized)
}

func part2(A [][]rune) {
	m := len(A)
	n := len(A[0])
	max := -1

	for i := 0; i < m; i++ {
		start := LightPoint{row: i, col: 0, dir: RIGHT}
		energized := solve(A, start)
		if energized > max {
			max = energized
		}
		start = LightPoint{row: 0, col: n - 1, dir: LEFT}
		energized = solve(A, start)
		if energized > max {
			max = energized
		}
	}

	for j := 0; j < n; j++ {
		start := LightPoint{row: 0, col: j, dir: DOWN}
		energized := solve(A, start)
		if energized > max {
			max = energized
		}
		start = LightPoint{row: m - 1, col: j, dir: UP}
		energized = solve(A, start)
		if energized > max {
			max = energized
		}
	}

	fmt.Println(max)
}

func main() {
	// file, _ := os.Open("sample.txt")
	file, _ := os.Open("input.txt")
	defer file.Close()

	scanner := bufio.NewScanner(file)

	var lines []string
	for scanner.Scan() {
		lines = append(lines, scanner.Text())
	}

	var A [][]rune
	for _, line := range lines {
		A = append(A, []rune(line))
	}

	// part1(A)
	part2(A)
}