Skip to content

Commit

Permalink
Solutions for 15, 16
Browse files Browse the repository at this point in the history
  • Loading branch information
Joel Smith committed Mar 8, 2019
1 parent 21a1412 commit e2ad97a
Show file tree
Hide file tree
Showing 4 changed files with 207 additions and 1 deletion.
6 changes: 6 additions & 0 deletions 15/input.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Disc #1 has 17 positions; at time=0, it is at position 5.
Disc #2 has 19 positions; at time=0, it is at position 8.
Disc #3 has 7 positions; at time=0, it is at position 1.
Disc #4 has 13 positions; at time=0, it is at position 7.
Disc #5 has 5 positions; at time=0, it is at position 1.
Disc #6 has 3 positions; at time=0, it is at position 0.
115 changes: 115 additions & 0 deletions 15/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package main

import "fmt"

type Disc struct {
CurrentPosition int
TotalPositions int
ClearPosition int
}

func (d *Disc) advance(amt int) {
d.CurrentPosition = (d.CurrentPosition + amt) % d.TotalPositions
}

func main() {
logic()
}

func logic() {
// discs := puzzleTestInput()
discs := puzzleInput()
t := 0
for ; ; t++ {
clear, _, _ := isClear(discs, t)
if clear {
break
}
// advancement := 1
// if collidedDisc > 0 {
// advancement = fakeLCM(discs[:collidedDisc])
// }

// fmt.Println(colidedDiscIndex, discPosition)
// guess next number:
// Position + lcm(passed discs) +

}
fmt.Println("Drop in at t =", t)
}

func deepCopyDiscs(discs []Disc) []Disc {
copy := make([]Disc, len(discs))
for i := range discs {
copy[i] = Disc{discs[i].CurrentPosition, discs[i].TotalPositions, discs[i].ClearPosition }
}
return copy
}

func isClear(discs []Disc, t int) (bool, int, int) {
copy := deepCopyDiscs(discs)

for i := range copy {
copy[i].advance(t)
}
for i := 0; i < len(copy); i++ {
if copy[i].CurrentPosition != copy[i].ClearPosition {
// fmt.Println("Will stop on disc", i+1)
return false, i, copy[i].CurrentPosition
}
}
return true, 0, 0
}

// All of my numbers are prime, so the LCM of prime number is going to be their product
func fakeLCM(nums []int) int {
product := 1

for _, v := range nums {
product *= v
}
return product
}

// Opting to hard code here, as parsing is pointless for such a small dataset
func puzzleInput() []Disc {
discs := []Disc{
{CurrentPosition: 5, TotalPositions: 17},
{CurrentPosition: 8, TotalPositions: 19},
{CurrentPosition: 1, TotalPositions: 7},
{CurrentPosition: 7, TotalPositions: 13},
{CurrentPosition: 1, TotalPositions: 5},
{CurrentPosition: 0, TotalPositions: 3},
{CurrentPosition: 0, TotalPositions: 11},
}
for i := range discs {
discs[i].ClearPosition = mod(discs[i].TotalPositions-1-i, discs[i].TotalPositions)
}

return discs
}

func puzzleTestInput() []Disc {
discs := []Disc{
{CurrentPosition: 4, TotalPositions: 5},
{CurrentPosition: 1, TotalPositions: 2},
}
for i := range discs {
discs[i].ClearPosition = mod(discs[i].TotalPositions-1-i, discs[i].TotalPositions)
}
return discs
}

func mod(n int, modulo int) int {
if n >= modulo {
return n % modulo
} else if n < 0 {
offset := (-n) % modulo
answer := modulo - offset
if answer == modulo { // we could end up in a situation where offset is 0, then modulo - 0 = modulo = 0
return 0
}
return answer
}
return n
}
76 changes: 76 additions & 0 deletions 16/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package main

import (
"fmt"
"strings"
)

func main() {
logic()
}

func logic() {
// input := puzzleTestInput()
// stopAt := 20
input := puzzleInput()
// stopAt := 272 // problem 1
stopAt := 35651584 // problem 2

for len(input) < stopAt {
input = step(input)
}
input = input[:stopAt]

fmt.Println(Checksum(input))
}

func step(data string) string {
copy := strings.Map(func(letter rune) rune { return letter }, data)
reversed := Reverse(copy)
notted := strings.Map(func(letter rune) rune {
if letter == '0' {
return '1'
}
return '0'
}, reversed)
return fmt.Sprintf("%v0%v", data, notted)
}

func Checksum(data string) string {
checksum := make([]rune, len(data)/2)
recurse := true
if (len(checksum) % 2) == 1 {
recurse = false
}
for i := 0; i < len(checksum); i++ {
if data[2*i] == data[2*i+1] {
checksum[i] = '1'
} else {
checksum[i] = '0'
}
}

if recurse {
return Checksum(string(checksum))
} else {
return string(checksum)
}
}

// borrowed from https://stackoverflow.com/questions/1752414/how-to-reverse-a-string-in-go
func Reverse(s string) string {
r := []rune(s)
for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
r[i], r[j] = r[j], r[i]
}
return string(r)
}

// Opting to hard code here, as parsing is pointless for such a small dataset
func puzzleInput() string {
return "01000100010010111"
}

func puzzleTestInput() string {
return "10000"
}
11 changes: 10 additions & 1 deletion Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,13 @@ I ended up doing two things to make this work faster:
1. Cheat the number identification. I originally used a regular expression (not even a compiled one), but figured it would be faster to simply check to see that the first character looked like it could be a number, and not worry about if it was error prone. I didn't test, but this had a large impact on performance. it could probably be further optimized here as well
2. Pre-pare out the steps. Initially I split the inputs on each pass, which ended up being needless.

A 3rd improvement would be to memoize the relative results from a (or maybe each) cell, up until a jump. This one is more complicated, but could maybe save a number of iterations through the loop, and focus only on the parts that matter (namely, jumps)
A 3rd improvement would be to memoize the relative results from a (or maybe each) cell, up until a jump. This one is more complicated, but could maybe save a number of iterations through the loop, and focus only on the parts that matter (namely, jumps)

## Day 15

I think there's a faster way to do this, possibly having to use the LCM of the discs. The idea of the quicker way is this:

1. You've figured out how to drop it through n holes. You can repeat this by only choosing LCMs of the n discs, with each multiple being the number of positions in contains (in my example, the first 3 discs: `17 * 19 * 7`).
2. When you use multiples of the LCM, you are guarenteed to pass through the same n discs.
3. Each LCM is going to advance the next disc some number of values. You need to figure out what that next number is. Once you have that, you can advance the guess count until you find a match
4. once you find that match, you should now be able to drop the capsule n+1 steps (the first n pass, because we always increment by lcms, the next, because the modulous finally works)

0 comments on commit e2ad97a

Please sign in to comment.