Cleanup
This commit is contained in:
@@ -1,276 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
h "git.bullercodeworks.com/brian/adventofcode/helpers"
|
||||
)
|
||||
|
||||
func main() {
|
||||
inp := h.StdinToStringSlice()
|
||||
part1(inp)
|
||||
// fmt.Println()
|
||||
// part2(inp)
|
||||
}
|
||||
|
||||
var (
|
||||
N = h.Coordinate{X: 0, Y: -1}
|
||||
E = h.Coordinate{X: 1, Y: 0}
|
||||
S = h.Coordinate{X: 0, Y: 1}
|
||||
W = h.Coordinate{X: -1, Y: 0}
|
||||
)
|
||||
|
||||
var (
|
||||
scoreTrack map[h.Coordinate]int
|
||||
bestCostToEnd map[h.Coordinate]int
|
||||
)
|
||||
|
||||
func part1(inpS []string) {
|
||||
inp := h.StringSliceToCoordByteMap(inpS)
|
||||
scoreTrack = make(map[h.Coordinate]int)
|
||||
bestCostToEnd = make(map[h.Coordinate]int)
|
||||
|
||||
start, _ := inp.FindFirst('S')
|
||||
end, _ := inp.FindFirst('E')
|
||||
inp.Put(start, '.')
|
||||
bestCostToEnd[end] = 0
|
||||
|
||||
cd := CD{c: start, d: E}
|
||||
solve(inp, cd, end, 0, []h.Coordinate{cd.c})
|
||||
best, ok := scoreTrack[end]
|
||||
if !ok {
|
||||
panic(errors.New("no path to end found"))
|
||||
}
|
||||
fmt.Println("Best Score:", best)
|
||||
|
||||
bestSeats := make(map[h.Coordinate]byte)
|
||||
for i := range bestPaths {
|
||||
for j := range bestPaths[i] {
|
||||
bestSeats[bestPaths[i][j]] = byte('0' + i)
|
||||
}
|
||||
}
|
||||
printBestSeats(inp, bestSeats)
|
||||
fmt.Println("Seats:", len(bestSeats))
|
||||
}
|
||||
|
||||
var bestPaths [][]h.Coordinate
|
||||
|
||||
func solve(inp h.CoordByteMap, start CD, end h.Coordinate, score int, currPath []h.Coordinate) int {
|
||||
// tryMove takes the cd that we're moving to and the cost to move there
|
||||
// and returns the cost to get from that cd to the end
|
||||
tryMove := func(c CD, cost int) int {
|
||||
if inp.ContainsCoord(c.c) && inp.Get(c.c) != '#' {
|
||||
// printPathMap(inp, c, end, currPath)
|
||||
// poi := h.Coordinate{X: 3, Y: 10}
|
||||
// time.Sleep(time.Second / 20)
|
||||
nextScore := score + cost
|
||||
v, ok := bestCostToEnd[c.c]
|
||||
//if c.c.Equals(poi) {
|
||||
// fmt.Println("Current Scoretrack[poi] =", v)
|
||||
// fmt.Println("Next Score =", nextScore)
|
||||
// time.Sleep(time.Second * 5)
|
||||
//}
|
||||
if !ok || v >= nextScore {
|
||||
nxtPath := make([]h.Coordinate, len(currPath))
|
||||
copy(nxtPath, currPath)
|
||||
nxtPath = append(nxtPath, c.c)
|
||||
|
||||
// Check end conditions
|
||||
if c.c.Equals(end) {
|
||||
if !ok || v > nextScore { // New Best
|
||||
fmt.Println("New Best Path")
|
||||
scoreTrack[end] = nextScore
|
||||
bestPaths = [][]h.Coordinate{nxtPath}
|
||||
} else if v == nextScore { // Another Best Path
|
||||
fmt.Println("Adding path to best paths")
|
||||
bestPaths = append(bestPaths, nxtPath)
|
||||
}
|
||||
return cost
|
||||
}
|
||||
// Not the end, but keep going
|
||||
scoreTrack[c.c] = nextScore
|
||||
solve(inp, c, end, nextScore, nxtPath)
|
||||
}
|
||||
}
|
||||
return h.MAX_INT
|
||||
}
|
||||
// Test forward
|
||||
cost := tryMove(start.move(), 1)
|
||||
// Test CW
|
||||
if wrk := tryMove(start.turnCW().move(), 1001); wrk < cost {
|
||||
cost = wrk
|
||||
}
|
||||
// Test CCW
|
||||
if wrk := tryMove(start.turnCCW().move(), 1001); wrk < cost {
|
||||
cost = wrk
|
||||
}
|
||||
bestCostToEnd[start.c] = cost
|
||||
return cost
|
||||
}
|
||||
|
||||
func printPathMap(inp h.CoordByteMap, loc CD, end h.Coordinate, path []h.Coordinate) {
|
||||
fmt.Print(h.CLEAR_SCREEN)
|
||||
wrk := inp.Copy()
|
||||
wrk.ReplaceAll('.', ' ')
|
||||
for i := range path {
|
||||
wrk.Put(path[i], 'o')
|
||||
}
|
||||
wrk.Put(loc.c, loc.Byte())
|
||||
fmt.Println(wrk)
|
||||
if v, ok := scoreTrack[end]; ok {
|
||||
fmt.Printf("Best Score: %v (Paths: %d)\n", v, len(bestPaths))
|
||||
} else {
|
||||
fmt.Println("Waiting on best score...")
|
||||
}
|
||||
}
|
||||
|
||||
func printBestSeats(inp h.CoordByteMap, seats map[h.Coordinate]byte) {
|
||||
fmt.Print(h.CLEAR_SCREEN)
|
||||
wrk := inp.Copy()
|
||||
wrk.ReplaceAll('.', ' ')
|
||||
for k, v := range seats {
|
||||
wrk.Put(k, byte(0+v))
|
||||
}
|
||||
fmt.Println(wrk)
|
||||
}
|
||||
|
||||
/*
|
||||
func part2(inpS []string) {
|
||||
inp := h.StringSliceToCoordByteMap(inpS)
|
||||
scoreTrack = make(map[h.Coordinate]int)
|
||||
start, _ := inp.FindFirst('S')
|
||||
end, _ := inp.FindFirst('E')
|
||||
inp.Put(start, '.')
|
||||
cd := CD{c: start, d: E}
|
||||
lookForSeats(inp, cd, end, 0, []h.Coordinate{cd.c})
|
||||
_, ok := scoreTrack[end]
|
||||
if !ok {
|
||||
panic(errors.New("no path to end found"))
|
||||
}
|
||||
bestSeats := make(map[h.Coordinate]int)
|
||||
for i := range bestPaths {
|
||||
for j := range bestPaths[i] {
|
||||
bestSeats[bestPaths[i][j]] = i
|
||||
}
|
||||
}
|
||||
fmt.Println("Number of Seats:", len(bestSeats))
|
||||
}
|
||||
|
||||
|
||||
|
||||
func coordInPath(c h.Coordinate, path []h.Coordinate) bool {
|
||||
for i := range path {
|
||||
if path[i].Equals(c) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func lookForSeats(inp h.CoordByteMap, start CD, end h.Coordinate, score int, path []h.Coordinate) int {
|
||||
// Check for finished:
|
||||
if start.c.Equals(end) {
|
||||
v, ok := scoreTrack[end]
|
||||
if !ok || v > score {
|
||||
// We have a new best path
|
||||
bestPaths = [][]h.Coordinate{path}
|
||||
scoreTrack[end] = score
|
||||
} else if scoreTrack[end] == score {
|
||||
bestPaths = append(bestPaths, path)
|
||||
}
|
||||
return score
|
||||
}
|
||||
|
||||
// Helper func
|
||||
canMoveTo := func(p h.Coordinate) bool {
|
||||
return inp.ContainsCoord(p) && inp.Get(p) != '#'
|
||||
}
|
||||
// Keep moving:
|
||||
tryMove := func(c CD, cost int) {
|
||||
if canMoveTo(c.c) {
|
||||
// Check if this path has alread gone through this spot
|
||||
nxtPath := make([]h.Coordinate, len(path))
|
||||
copy(nxtPath, path)
|
||||
if coordInPath(c.c, nxtPath) {
|
||||
return
|
||||
}
|
||||
// Ok, now what's the best score we end up if we make this move?
|
||||
nextScore := score + cost
|
||||
n, ok := scoreTrack[c.c]
|
||||
if !ok || n > nextScore {
|
||||
lookForSeats(inp, c, end, nextScore, append(nxtPath, c.c))
|
||||
}
|
||||
}
|
||||
}
|
||||
// Test forward
|
||||
tryMove(start.move(), 1)
|
||||
// Test CW
|
||||
tryMove(start.turnCW().move(), 1001)
|
||||
// Test CCW
|
||||
tryMove(start.turnCCW().move(), 1001)
|
||||
return scoreTrack[start.c]
|
||||
}
|
||||
*/
|
||||
|
||||
type CD struct {
|
||||
c h.Coordinate
|
||||
d h.Coordinate
|
||||
}
|
||||
|
||||
func (cd CD) move() CD {
|
||||
return CD{
|
||||
c: cd.c.Add(cd.d),
|
||||
d: cd.d,
|
||||
}
|
||||
}
|
||||
|
||||
func (cd CD) turnCW() CD {
|
||||
var newD h.Coordinate
|
||||
switch cd.d {
|
||||
case N:
|
||||
newD = E
|
||||
case E:
|
||||
newD = S
|
||||
case S:
|
||||
newD = W
|
||||
case W:
|
||||
newD = N
|
||||
}
|
||||
return CD{
|
||||
c: cd.c,
|
||||
d: newD,
|
||||
}
|
||||
}
|
||||
|
||||
func (cd CD) turnCCW() CD {
|
||||
var newD h.Coordinate
|
||||
switch cd.d {
|
||||
case N:
|
||||
newD = W
|
||||
case E:
|
||||
newD = N
|
||||
case S:
|
||||
newD = E
|
||||
case W:
|
||||
newD = S
|
||||
}
|
||||
return CD{
|
||||
c: cd.c,
|
||||
d: newD,
|
||||
}
|
||||
}
|
||||
|
||||
func (cd CD) Byte() byte {
|
||||
switch cd.d {
|
||||
case N:
|
||||
return '^'
|
||||
case E:
|
||||
return '>'
|
||||
case S:
|
||||
return 'v'
|
||||
case W:
|
||||
return '<'
|
||||
}
|
||||
return '?'
|
||||
}
|
190
2024/day16/problem
Normal file
190
2024/day16/problem
Normal file
@@ -0,0 +1,190 @@
|
||||
Advent of Code
|
||||
|
||||
--- Day 16: Reindeer Maze ---
|
||||
|
||||
It's time again for the [16]Reindeer Olympics! This year, the big event is
|
||||
the Reindeer Maze, where the Reindeer compete for the lowest score.
|
||||
|
||||
You and The Historians arrive to search for the Chief right as the event
|
||||
is about to start. It wouldn't hurt to watch a little, right?
|
||||
|
||||
The Reindeer start on the Start Tile (marked S) facing East and need to
|
||||
reach the End Tile (marked E). They can move forward one tile at a time
|
||||
(increasing their score by 1 point), but never into a wall (#). They can
|
||||
also rotate clockwise or counterclockwise 90 degrees at a time (increasing
|
||||
their score by 1000 points).
|
||||
|
||||
To figure out the best place to sit, you start by grabbing a map (your
|
||||
puzzle input) from a nearby kiosk. For example:
|
||||
|
||||
###############
|
||||
#.......#....E#
|
||||
#.#.###.#.###.#
|
||||
#.....#.#...#.#
|
||||
#.###.#####.#.#
|
||||
#.#.#.......#.#
|
||||
#.#.#####.###.#
|
||||
#...........#.#
|
||||
###.#.#####.#.#
|
||||
#...#.....#.#.#
|
||||
#.#.#.###.#.#.#
|
||||
#.....#...#.#.#
|
||||
#.###.#.#.#.#.#
|
||||
#S..#.....#...#
|
||||
###############
|
||||
|
||||
There are many paths through this maze, but taking any of the best paths
|
||||
would incur a score of only 7036. This can be achieved by taking a total
|
||||
of 36 steps forward and turning 90 degrees a total of 7 times:
|
||||
|
||||
###############
|
||||
#.......#....E#
|
||||
#.#.###.#.###^#
|
||||
#.....#.#...#^#
|
||||
#.###.#####.#^#
|
||||
#.#.#.......#^#
|
||||
#.#.#####.###^#
|
||||
#..>>>>>>>>v#^#
|
||||
###^#.#####v#^#
|
||||
#>>^#.....#v#^#
|
||||
#^#.#.###.#v#^#
|
||||
#^....#...#v#^#
|
||||
#^###.#.#.#v#^#
|
||||
#S..#.....#>>^#
|
||||
###############
|
||||
|
||||
Here's a second example:
|
||||
|
||||
#################
|
||||
#...#...#...#..E#
|
||||
#.#.#.#.#.#.#.#.#
|
||||
#.#.#.#...#...#.#
|
||||
#.#.#.#.###.#.#.#
|
||||
#...#.#.#.....#.#
|
||||
#.#.#.#.#.#####.#
|
||||
#.#...#.#.#.....#
|
||||
#.#.#####.#.###.#
|
||||
#.#.#.......#...#
|
||||
#.#.###.#####.###
|
||||
#.#.#...#.....#.#
|
||||
#.#.#.#####.###.#
|
||||
#.#.#.........#.#
|
||||
#.#.#.#########.#
|
||||
#S#.............#
|
||||
#################
|
||||
|
||||
In this maze, the best paths cost 11048 points; following one such path
|
||||
would look like this:
|
||||
|
||||
#################
|
||||
#...#...#...#..E#
|
||||
#.#.#.#.#.#.#.#^#
|
||||
#.#.#.#...#...#^#
|
||||
#.#.#.#.###.#.#^#
|
||||
#>>v#.#.#.....#^#
|
||||
#^#v#.#.#.#####^#
|
||||
#^#v..#.#.#>>>>^#
|
||||
#^#v#####.#^###.#
|
||||
#^#v#..>>>>^#...#
|
||||
#^#v###^#####.###
|
||||
#^#v#>>^#.....#.#
|
||||
#^#v#^#####.###.#
|
||||
#^#v#^........#.#
|
||||
#^#v#^#########.#
|
||||
#S#>>^..........#
|
||||
#################
|
||||
|
||||
Note that the path shown above includes one 90 degree turn as the very
|
||||
first move, rotating the Reindeer from facing East to facing North.
|
||||
|
||||
Analyze your map carefully. What is the lowest score a Reindeer could
|
||||
possibly get?
|
||||
|
||||
Your puzzle answer was 72400.
|
||||
|
||||
--- Part Two ---
|
||||
|
||||
Now that you know what the best paths look like, you can figure out the
|
||||
best spot to sit.
|
||||
|
||||
Every non-wall tile (S, ., or E) is equipped with places to sit along the
|
||||
edges of the tile. While determining which of these tiles would be the
|
||||
best spot to sit depends on a whole bunch of factors (how comfortable the
|
||||
seats are, how far away the bathrooms are, whether there's a pillar
|
||||
blocking your view, etc.), the most important factor is whether the tile
|
||||
is on one of the best paths through the maze. If you sit somewhere else,
|
||||
you'd miss all the action!
|
||||
|
||||
So, you'll need to determine which tiles are part of any best path through
|
||||
the maze, including the S and E tiles.
|
||||
|
||||
In the first example, there are 45 tiles (marked O) that are part of at
|
||||
least one of the various best paths through the maze:
|
||||
|
||||
###############
|
||||
#.......#....O#
|
||||
#.#.###.#.###O#
|
||||
#.....#.#...#O#
|
||||
#.###.#####.#O#
|
||||
#.#.#.......#O#
|
||||
#.#.#####.###O#
|
||||
#..OOOOOOOOO#O#
|
||||
###O#O#####O#O#
|
||||
#OOO#O....#O#O#
|
||||
#O#O#O###.#O#O#
|
||||
#OOOOO#...#O#O#
|
||||
#O###.#.#.#O#O#
|
||||
#O..#.....#OOO#
|
||||
###############
|
||||
|
||||
In the second example, there are 64 tiles that are part of at least one of
|
||||
the best paths:
|
||||
|
||||
#################
|
||||
#...#...#...#..O#
|
||||
#.#.#.#.#.#.#.#O#
|
||||
#.#.#.#...#...#O#
|
||||
#.#.#.#.###.#.#O#
|
||||
#OOO#.#.#.....#O#
|
||||
#O#O#.#.#.#####O#
|
||||
#O#O..#.#.#OOOOO#
|
||||
#O#O#####.#O###O#
|
||||
#O#O#..OOOOO#OOO#
|
||||
#O#O###O#####O###
|
||||
#O#O#OOO#..OOO#.#
|
||||
#O#O#O#####O###.#
|
||||
#O#O#OOOOOOO..#.#
|
||||
#O#O#O#########.#
|
||||
#O#OOO..........#
|
||||
#################
|
||||
|
||||
Analyze your map further. How many tiles are part of at least one of the
|
||||
best paths through the maze?
|
||||
|
||||
Your puzzle answer was 435.
|
||||
|
||||
Both parts of this puzzle are complete! They provide two gold stars: **
|
||||
|
||||
At this point, you should [17]return to your Advent calendar and try
|
||||
another puzzle.
|
||||
|
||||
If you still want to see it, you can [18]get your puzzle input.
|
||||
|
||||
References
|
||||
|
||||
Visible links
|
||||
1. https://adventofcode.com/
|
||||
2. https://adventofcode.com/2024/about
|
||||
3. https://adventofcode.com/2024/events
|
||||
5. https://adventofcode.com/2024/settings
|
||||
6. https://adventofcode.com/2024/auth/logout
|
||||
7. Advent of Code Supporter
|
||||
https://adventofcode.com/2024/support
|
||||
8. https://adventofcode.com/2024
|
||||
9. https://adventofcode.com/2024
|
||||
10. https://adventofcode.com/2024/support
|
||||
12. https://adventofcode.com/2024/leaderboard
|
||||
13. https://adventofcode.com/2024/stats
|
||||
16. https://adventofcode.com/2015/day/14
|
||||
17. https://adventofcode.com/2024
|
||||
18. https://adventofcode.com/2024/day/16/input
|
Reference in New Issue
Block a user