186 lines
3.7 KiB
Go
186 lines
3.7 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"os"
|
|
"strconv"
|
|
"time"
|
|
)
|
|
|
|
const FILE_PATH = "./input.txt"
|
|
|
|
//const FILE_PATH = "./sample.txt"
|
|
|
|
func LoadInput(filename string) ([]string, error) {
|
|
file, err := os.Open(filename)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer file.Close()
|
|
|
|
var lines []string
|
|
scanner := bufio.NewScanner(file)
|
|
for scanner.Scan() {
|
|
lines = append(lines, scanner.Text())
|
|
}
|
|
|
|
if err := scanner.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return lines, nil
|
|
}
|
|
|
|
type structuredInput = [][]int
|
|
|
|
func TransformInput(lines []string) structuredInput {
|
|
var result = make([][]int, len(lines))
|
|
|
|
for i := 0; i < len(lines); i++ {
|
|
result[i] = make([]int, len(lines[i]))
|
|
for j := 0; j < len(lines[i]); j++ {
|
|
result[i][j] = int(lines[i][j] - '0')
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func isInBounds(position Vector2, bounds Vector2) bool {
|
|
return position.x >= 0 && position.x < bounds.x && position.y >= 0 && position.y < bounds.y
|
|
}
|
|
|
|
func print2DIntArray(input [][]int, padding int, sep string) {
|
|
var numb string
|
|
for y := 0; y < len(input); y++ {
|
|
for x := 0; x < len(input[y]); x++ {
|
|
numb = strconv.Itoa(input[y][x])
|
|
for len(numb) < padding {
|
|
numb = "0" + numb
|
|
}
|
|
fmt.Print(numb, sep)
|
|
}
|
|
fmt.Println()
|
|
}
|
|
fmt.Println()
|
|
}
|
|
|
|
type Vector2 struct {
|
|
x int
|
|
y int
|
|
}
|
|
|
|
func add(a Vector2, b Vector2) Vector2 {
|
|
return Vector2{a.x + b.x, a.y + b.y}
|
|
}
|
|
|
|
var MOVEMENTS = []Vector2{
|
|
{0, -1},
|
|
{1, 0},
|
|
{0, 1},
|
|
{-1, 0},
|
|
}
|
|
|
|
func calcPossibleEndPoints(input structuredInput, startPost Vector2) int {
|
|
var possiblePoints map[Vector2]bool = make(map[Vector2]bool)
|
|
var nextPoints map[Vector2]bool
|
|
var bounds = Vector2{len(input[0]), len(input)}
|
|
var nextPoint Vector2
|
|
|
|
possiblePoints[startPost] = true
|
|
|
|
for i := 1; i <= 9; i++ {
|
|
nextPoints = make(map[Vector2]bool)
|
|
|
|
for point := range possiblePoints {
|
|
for j := 0; j < len(MOVEMENTS); j++ {
|
|
nextPoint = add(point, MOVEMENTS[j])
|
|
if isInBounds(nextPoint, bounds) && input[nextPoint.y][nextPoint.x] == i {
|
|
nextPoints[nextPoint] = true
|
|
}
|
|
}
|
|
}
|
|
|
|
possiblePoints = nextPoints
|
|
}
|
|
|
|
return len(possiblePoints)
|
|
}
|
|
|
|
func calcTrailRating(input structuredInput, startPost Vector2) int {
|
|
var possiblePoints []Vector2 = make([]Vector2, 0)
|
|
var nextPoints []Vector2
|
|
var bounds = Vector2{len(input[0]), len(input)}
|
|
var nextPoint Vector2
|
|
|
|
possiblePoints = append(possiblePoints, startPost)
|
|
|
|
for i := 1; i <= 9; i++ {
|
|
nextPoints = make([]Vector2, 0)
|
|
|
|
for _, point := range possiblePoints {
|
|
for j := 0; j < len(MOVEMENTS); j++ {
|
|
nextPoint = add(point, MOVEMENTS[j])
|
|
if isInBounds(nextPoint, bounds) && input[nextPoint.y][nextPoint.x] == i {
|
|
nextPoints = append(nextPoints, nextPoint)
|
|
}
|
|
}
|
|
}
|
|
|
|
possiblePoints = nextPoints
|
|
}
|
|
|
|
return len(possiblePoints)
|
|
}
|
|
|
|
func Part1(input structuredInput) int {
|
|
var result = 0
|
|
|
|
for y := 0; y < len(input); y++ {
|
|
for x := 0; x < len(input[y]); x++ {
|
|
if input[y][x] == 0 {
|
|
result += calcPossibleEndPoints(input, Vector2{x, y})
|
|
}
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func Part2(input structuredInput) int {
|
|
var result = 0
|
|
|
|
for y := 0; y < len(input); y++ {
|
|
for x := 0; x < len(input[y]); x++ {
|
|
if input[y][x] == 0 {
|
|
result += calcTrailRating(input, Vector2{x, y})
|
|
}
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func main() {
|
|
var start time.Time
|
|
var elapsed time.Duration = 0
|
|
input, err := LoadInput(FILE_PATH)
|
|
if err != nil {
|
|
fmt.Println("Error loading input:", err)
|
|
return
|
|
}
|
|
|
|
structuredInput := TransformInput(input)
|
|
fmt.Println("Structured Input:", structuredInput)
|
|
|
|
start = time.Now()
|
|
fmt.Println("Solution Part 1: ", Part1(structuredInput))
|
|
elapsed = time.Since(start)
|
|
fmt.Printf("Part 1 took %s\n", elapsed)
|
|
|
|
start = time.Now()
|
|
fmt.Println("Solution Part 2: ", Part2(structuredInput))
|
|
elapsed = time.Since(start)
|
|
fmt.Printf("Part 2 took %s\n", elapsed)
|
|
}
|