mirror of
https://github.com/Threnklyn/advent-of-code-go.git
synced 2026-05-18 19:13:27 +02:00
134 lines
2.7 KiB
Go
134 lines
2.7 KiB
Go
package main
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
|
|
"github.com/alexchao26/advent-of-code-go/cast"
|
|
"github.com/alexchao26/advent-of-code-go/mathy"
|
|
"github.com/alexchao26/advent-of-code-go/util"
|
|
)
|
|
|
|
func main() {
|
|
var part int
|
|
flag.IntVar(&part, "part", 1, "part 1 or 2")
|
|
flag.Parse()
|
|
fmt.Println("Running part", part)
|
|
|
|
if part == 1 {
|
|
ans := part1(util.ReadFile("./input.txt"))
|
|
util.CopyToClipboard(fmt.Sprintf("%v", ans))
|
|
fmt.Println("Output:", ans)
|
|
} else {
|
|
ans := part2(util.ReadFile("./input.txt"))
|
|
util.CopyToClipboard(fmt.Sprintf("%v", ans))
|
|
fmt.Println("Output:", ans)
|
|
}
|
|
}
|
|
|
|
func part1(input string) int {
|
|
nums := parseInput(input)
|
|
nums = append(nums, mathy.MaxInt(nums...)+3)
|
|
sort.Ints(nums)
|
|
|
|
var oneDiff, threeDiff int
|
|
var currentJoltage int
|
|
for _, v := range nums {
|
|
switch v - currentJoltage {
|
|
case 1: // check for 1 diff first, so no adapters are skipped
|
|
oneDiff++
|
|
case 3:
|
|
threeDiff++
|
|
default:
|
|
panic("adpaters not connected by 3 or 1")
|
|
}
|
|
currentJoltage = v
|
|
}
|
|
|
|
return oneDiff * threeDiff
|
|
}
|
|
|
|
func part2(input string) int {
|
|
nums := parseInput(input)
|
|
nums = append(nums, mathy.MaxInt(nums...)+3)
|
|
sort.Ints(nums)
|
|
|
|
// return dynamicProgramming(input)
|
|
return memoCountPossibilities(nums, 0)
|
|
}
|
|
|
|
func parseInput(input string) []int {
|
|
var ans []int
|
|
|
|
lines := strings.Split(input, "\n")
|
|
for _, l := range lines {
|
|
ans = append(ans, cast.ToInt(l))
|
|
}
|
|
|
|
return ans
|
|
}
|
|
|
|
// storing memo in global state isn't ideal... but it's fastser to code
|
|
var memo = map[string]int{}
|
|
|
|
func memoCountPossibilities(nums []int, lastJolt int) int {
|
|
// if in memo, return that value
|
|
str := makeMemoKey(nums, lastJolt)
|
|
if v, ok := memo[str]; ok {
|
|
return v
|
|
}
|
|
|
|
// if all adapters used up, return 1
|
|
if len(nums) == 0 {
|
|
return 1
|
|
}
|
|
|
|
// create a recursive call for each adapter within 3 of the lastJoltage
|
|
var count int
|
|
for i, v := range nums {
|
|
if v-lastJolt <= 3 {
|
|
count += memoCountPossibilities(nums[i+1:], v)
|
|
} else { // stop counting if the joltage diff is too larger (>3)
|
|
break
|
|
}
|
|
}
|
|
|
|
// update memo
|
|
memo[str] = count
|
|
|
|
return count
|
|
}
|
|
func makeMemoKey(nums []int, lastJolt int) string {
|
|
ans := cast.ToString(lastJolt) + "x"
|
|
for _, v := range nums {
|
|
ans += cast.ToString(v)
|
|
}
|
|
return ans
|
|
}
|
|
|
|
func dynamicProgramming(input string) int {
|
|
nums := parseInput(input)
|
|
nums = append(nums, mathy.MaxInt(nums...)+3, 0)
|
|
sort.Ints(nums)
|
|
|
|
// initialize table with "1 way" to get to zero jolts
|
|
table := make([]int, len(nums))
|
|
table[0] = 1
|
|
|
|
for i := 1; i < len(nums); i++ {
|
|
currentJolts := nums[i]
|
|
for j := i - 1; j >= 0; j-- {
|
|
// add the ways to get to currentJolts that are within 3 jolts
|
|
if currentJolts-nums[j] <= 3 {
|
|
table[i] += table[j]
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
return table[len(table)-1]
|
|
}
|