218 lines
4.7 KiB
Go
218 lines
4.7 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"log"
|
|
"math"
|
|
"os"
|
|
"sort"
|
|
"strconv"
|
|
)
|
|
|
|
func processLines(path string, f func(string) (stop bool, err error)) error {
|
|
file, err := os.Open(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer file.Close()
|
|
scanner := bufio.NewScanner(file)
|
|
for scanner.Scan() {
|
|
stop, err := f(scanner.Text())
|
|
if stop || err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if err := scanner.Err(); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func part1() {
|
|
values := []int{}
|
|
if err := processLines("input.txt", func(line string) (bool, error) {
|
|
v, err := strconv.Atoi(line)
|
|
values = append(values, v)
|
|
return false, err
|
|
}); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
sort.Ints(values)
|
|
|
|
lastVal := 0
|
|
ones := 0
|
|
threes := 0
|
|
for _, v := range values {
|
|
diff := v - lastVal
|
|
switch diff {
|
|
case 1:
|
|
ones++
|
|
case 2:
|
|
case 3:
|
|
threes++
|
|
default:
|
|
log.Fatalf("unsupported distance: %d-%d=%d", v, lastVal, diff)
|
|
return
|
|
}
|
|
lastVal = v
|
|
}
|
|
// Final devices is a 3 jolt diff
|
|
threes++
|
|
|
|
fmt.Printf("Total ones %d total threes %d. Product %d\n", ones, threes, ones*threes)
|
|
}
|
|
|
|
var memoized = map[int][][]int{}
|
|
|
|
func searchSlice(s []int, start int) [][]int {
|
|
// Check for memoized results
|
|
if memResults, ok := memoized[start]; ok {
|
|
fmt.Printf("Cached value for index %d", start)
|
|
return memResults
|
|
}
|
|
// Check for a memoized result
|
|
// If at the end, return an empty array
|
|
lastVal := s[start]
|
|
if start == len(s)-1 {
|
|
// fmt.Println("At end! Yay!")
|
|
return [][]int{[]int{lastVal}}
|
|
}
|
|
fmt.Printf("Checking index %d value %d\n", start, lastVal)
|
|
results := [][]int{}
|
|
for i := 1; i <= 3 && start+i < len(s); i++ {
|
|
v := s[start+i]
|
|
if v-lastVal > 3 {
|
|
// Not valid, skip this
|
|
continue
|
|
}
|
|
subResults := searchSlice(s, start+i)
|
|
for _, subResult := range subResults {
|
|
subResult = append([]int{lastVal}, subResult...)
|
|
results = append(results, subResult)
|
|
}
|
|
}
|
|
// memoize the results
|
|
memoized[start] = results
|
|
return results
|
|
}
|
|
|
|
var memoizedC = map[int]int{}
|
|
|
|
func searchSliceC(s *[]int, start int) int {
|
|
// Check for memoized results
|
|
if memResultsC, ok := memoizedC[start]; ok {
|
|
// fmt.Printf("Cached value for index %d", start)
|
|
return memResultsC
|
|
}
|
|
// Check for a memoized result
|
|
// If at the end, return an empty array
|
|
lastVal := (*s)[start]
|
|
if start == len(*s)-1 {
|
|
// fmt.Println("At end! Yay!")
|
|
return 1
|
|
}
|
|
fmt.Printf("Checking index %d value %d\n", start, lastVal)
|
|
results := 0
|
|
for i := 1; i <= 3 && start+i < len(*s); i++ {
|
|
v := (*s)[start+i]
|
|
if v-lastVal > 3 {
|
|
// Not valid, skip this
|
|
continue
|
|
}
|
|
results += searchSliceC(s, start+i)
|
|
|
|
}
|
|
// memoize the results
|
|
memoizedC[start] = results
|
|
return results
|
|
}
|
|
|
|
func part2() {
|
|
values := []int{}
|
|
if err := processLines("input.txt", func(line string) (bool, error) {
|
|
v, err := strconv.Atoi(line)
|
|
values = append(values, v)
|
|
return false, err
|
|
}); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
values = append([]int{0}, values...)
|
|
sort.Ints(values)
|
|
deviceJolts := values[len(values)-1] + 3
|
|
values = append(values, deviceJolts)
|
|
fmt.Println("Total values", len(values))
|
|
|
|
/*
|
|
* paths := []int{}
|
|
* i := 0
|
|
* for i < len(values) {
|
|
* // look ahead
|
|
* for l := 3; l > 1; l-- {
|
|
* if i+l < len(values) && values[i+l]-values[i] <= 3 {
|
|
* // Look ahead is valid
|
|
* paths = append([]int{l}, paths...)
|
|
* // We only want max, so break out if we found it
|
|
* i = i + l
|
|
* break
|
|
* }
|
|
* }
|
|
* i++
|
|
* }
|
|
* fmt.Println("Paths", paths)
|
|
* powTotal := 1.0
|
|
* for _, num := range paths {
|
|
* if powTotal == 1.0 {
|
|
* powTotal = float64(num)
|
|
* } else {
|
|
* powTotal = math.Pow(float64(powTotal), float64(num))
|
|
* }
|
|
* }
|
|
* fmt.Println("Total pow paths", powTotal)
|
|
* productTotal := 1
|
|
* for _, num := range paths {
|
|
* productTotal = productTotal * num
|
|
* }
|
|
* fmt.Println("Total product paths", productTotal)
|
|
*
|
|
* totalOptions := 0
|
|
* i = 0
|
|
* options := []int{}
|
|
* for i < len(values) {
|
|
* // look ahead
|
|
* for l := 3; l >= 1; l-- {
|
|
* if i+l < len(values) && values[i+l]-values[i] <= 3 {
|
|
* // Look ahead is valid
|
|
* totalOptions++
|
|
* options = append(options, l)
|
|
* break
|
|
* }
|
|
* }
|
|
* i++
|
|
* }
|
|
* fmt.Println("Options", options)
|
|
* fmt.Println("Total sum options *2=", totalOptions*2)
|
|
* totalProdOptions := 1
|
|
* for _, num := range options {
|
|
* totalProdOptions = totalProdOptions * num
|
|
* }
|
|
* fmt.Println("Total prod options", totalProdOptions)
|
|
*/
|
|
|
|
fmt.Printf("Looking for device jolts %d\n", deviceJolts)
|
|
countResults := searchSliceC(&values, 0)
|
|
fmt.Printf("Search found %d results\n", countResults)
|
|
|
|
/*
|
|
* results := searchSlice(values, 0)
|
|
* fmt.Printf("Search found %d results\n", len(results))
|
|
*/
|
|
}
|
|
|
|
func main() {
|
|
part1()
|
|
part2()
|
|
}
|