Files
advent-of-code-go/2020/day10/main.go
T

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]
}