Day 22 solution
Part 1 was very straightforward. I believe there are ways to calculate this answer without the complicated maths from part 2 and without actually applying each of the instructions, but I'm not concerned with finding it. Part 2 was a big "nope" from me. I went out and found this answer and I don't understand it. I'm okay with that.
This commit is contained in:
155
days/22.go
Normal file
155
days/22.go
Normal file
@ -0,0 +1,155 @@
|
||||
package days
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
u "parnic.com/aoc2019/utilities"
|
||||
)
|
||||
|
||||
type day22Instruction int
|
||||
|
||||
const (
|
||||
day22InstructionNewStack day22Instruction = iota
|
||||
day22InstructionCut
|
||||
day22InstructionDealIncrement
|
||||
)
|
||||
|
||||
type day22Shuffle struct {
|
||||
instruction day22Instruction
|
||||
arg int
|
||||
}
|
||||
|
||||
type Day22 struct {
|
||||
shuffles []day22Shuffle
|
||||
}
|
||||
|
||||
func (d *Day22) Parse() {
|
||||
lines := u.GetStringLines("22p")
|
||||
d.shuffles = make([]day22Shuffle, len(lines))
|
||||
|
||||
for idx, line := range lines {
|
||||
split := strings.Split(line, " ")
|
||||
if split[0] == "deal" {
|
||||
if split[1] == "into" {
|
||||
d.shuffles[idx] = day22Shuffle{instruction: day22InstructionNewStack}
|
||||
} else if split[1] == "with" {
|
||||
arg, err := strconv.Atoi(split[3])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
d.shuffles[idx] = day22Shuffle{
|
||||
instruction: day22InstructionDealIncrement,
|
||||
arg: arg,
|
||||
}
|
||||
}
|
||||
} else if split[0] == "cut" {
|
||||
arg, err := strconv.Atoi(split[1])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
d.shuffles[idx] = day22Shuffle{
|
||||
instruction: day22InstructionCut,
|
||||
arg: arg,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d Day22) Num() int {
|
||||
return 22
|
||||
}
|
||||
|
||||
func (d Day22) applyShuffle(s day22Shuffle, stack, scratch []int) {
|
||||
switch s.instruction {
|
||||
case day22InstructionNewStack:
|
||||
for i := 0; i < len(stack)/2; i++ {
|
||||
stack[i], stack[len(stack)-1-i] = stack[len(stack)-1-i], stack[i]
|
||||
}
|
||||
|
||||
// there's probably a way to do these two in place...
|
||||
case day22InstructionCut:
|
||||
absArg := int(math.Abs(float64(s.arg)))
|
||||
for i, v := range stack {
|
||||
if s.arg > 0 {
|
||||
if i < absArg {
|
||||
scratch[len(scratch)-absArg+i] = v
|
||||
} else {
|
||||
scratch[i-absArg] = v
|
||||
}
|
||||
} else {
|
||||
if i < absArg {
|
||||
scratch[i] = stack[len(stack)-absArg+i]
|
||||
} else {
|
||||
scratch[i] = stack[i-absArg]
|
||||
}
|
||||
}
|
||||
}
|
||||
copy(stack, scratch)
|
||||
|
||||
case day22InstructionDealIncrement:
|
||||
for i, v := range stack {
|
||||
scratch[(i*s.arg)%len(stack)] = v
|
||||
}
|
||||
copy(stack, scratch)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Day22) Part1() string {
|
||||
deckSize := 10007
|
||||
// deckSize := 10
|
||||
|
||||
stack := make([]int, deckSize)
|
||||
for i := range stack {
|
||||
stack[i] = i
|
||||
}
|
||||
|
||||
scratch := make([]int, len(stack))
|
||||
|
||||
for _, s := range d.shuffles {
|
||||
d.applyShuffle(s, stack, scratch)
|
||||
}
|
||||
|
||||
pos := -1
|
||||
for i, v := range stack {
|
||||
if v == 2019 {
|
||||
pos = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf("Card 2019 is at position %s%d%s", u.TextBold, pos, u.TextReset)
|
||||
}
|
||||
|
||||
func (d *Day22) Part2() string {
|
||||
n, iter := big.NewInt(119315717514047), big.NewInt(101741582076661)
|
||||
offset, increment := big.NewInt(0), big.NewInt(1)
|
||||
for _, s := range d.shuffles {
|
||||
switch s.instruction {
|
||||
case day22InstructionNewStack:
|
||||
increment.Mul(increment, big.NewInt(-1))
|
||||
offset.Add(offset, increment)
|
||||
case day22InstructionCut:
|
||||
offset.Add(offset, big.NewInt(0).Mul(big.NewInt(int64(s.arg)), increment))
|
||||
case day22InstructionDealIncrement:
|
||||
increment.Mul(increment, big.NewInt(0).Exp(big.NewInt(int64(s.arg)), big.NewInt(0).Sub(n, big.NewInt(2)), n))
|
||||
}
|
||||
}
|
||||
|
||||
finalIncr := big.NewInt(0).Exp(increment, iter, n)
|
||||
|
||||
finalOffs := big.NewInt(0).Exp(increment, iter, n)
|
||||
finalOffs.Sub(big.NewInt(1), finalOffs)
|
||||
invmod := big.NewInt(0).Exp(big.NewInt(0).Sub(big.NewInt(1), increment), big.NewInt(0).Sub(n, big.NewInt(2)), n)
|
||||
finalOffs.Mul(finalOffs, invmod)
|
||||
finalOffs.Mul(finalOffs, offset)
|
||||
|
||||
answer := big.NewInt(0).Mul(big.NewInt(2020), finalIncr)
|
||||
answer.Add(answer, finalOffs)
|
||||
answer.Mod(answer, n)
|
||||
|
||||
return fmt.Sprintf("Card at position 2020: %s%d%s", u.TextBold, answer, u.TextReset)
|
||||
}
|
100
inputs/22p.txt
Normal file
100
inputs/22p.txt
Normal file
@ -0,0 +1,100 @@
|
||||
deal into new stack
|
||||
cut -2732
|
||||
deal into new stack
|
||||
deal with increment 57
|
||||
cut 5974
|
||||
deal into new stack
|
||||
deal with increment 32
|
||||
cut -1725
|
||||
deal with increment 24
|
||||
cut 6093
|
||||
deal with increment 6
|
||||
cut -2842
|
||||
deal with increment 14
|
||||
cut 2609
|
||||
deal with increment 12
|
||||
cut -6860
|
||||
deal with increment 51
|
||||
cut -6230
|
||||
deal with increment 61
|
||||
cut 3152
|
||||
deal with increment 28
|
||||
cut 2202
|
||||
deal into new stack
|
||||
deal with increment 60
|
||||
cut 433
|
||||
deal into new stack
|
||||
cut -6256
|
||||
deal with increment 13
|
||||
deal into new stack
|
||||
cut 8379
|
||||
deal into new stack
|
||||
deal with increment 54
|
||||
cut 1120
|
||||
deal with increment 16
|
||||
cut -5214
|
||||
deal with increment 63
|
||||
deal into new stack
|
||||
cut -8473
|
||||
deal with increment 11
|
||||
cut 228
|
||||
deal with increment 45
|
||||
cut -6755
|
||||
deal with increment 50
|
||||
cut -3391
|
||||
deal with increment 44
|
||||
cut -1341
|
||||
deal with increment 28
|
||||
cut -6788
|
||||
deal with increment 52
|
||||
cut 3062
|
||||
deal with increment 41
|
||||
cut 4541
|
||||
deal with increment 57
|
||||
cut -7962
|
||||
deal with increment 56
|
||||
cut 9621
|
||||
deal with increment 57
|
||||
cut 3881
|
||||
deal with increment 36
|
||||
deal into new stack
|
||||
deal with increment 45
|
||||
cut 522
|
||||
deal with increment 9
|
||||
deal into new stack
|
||||
deal with increment 60
|
||||
deal into new stack
|
||||
deal with increment 12
|
||||
cut -9181
|
||||
deal with increment 63
|
||||
deal into new stack
|
||||
deal with increment 14
|
||||
cut -2906
|
||||
deal with increment 10
|
||||
cut 848
|
||||
deal with increment 75
|
||||
cut 798
|
||||
deal with increment 29
|
||||
cut 1412
|
||||
deal with increment 10
|
||||
deal into new stack
|
||||
cut -5295
|
||||
deal into new stack
|
||||
cut 4432
|
||||
deal with increment 72
|
||||
cut -7831
|
||||
deal into new stack
|
||||
cut 6216
|
||||
deal into new stack
|
||||
deal with increment 7
|
||||
cut -1720
|
||||
deal into new stack
|
||||
cut -5465
|
||||
deal with increment 70
|
||||
cut -5173
|
||||
deal with increment 7
|
||||
cut 3874
|
||||
deal with increment 65
|
||||
cut 921
|
||||
deal with increment 8
|
||||
cut -3094
|
3
inputs/22s1.txt
Normal file
3
inputs/22s1.txt
Normal file
@ -0,0 +1,3 @@
|
||||
deal with increment 7
|
||||
deal into new stack
|
||||
deal into new stack
|
3
inputs/22s2.txt
Normal file
3
inputs/22s2.txt
Normal file
@ -0,0 +1,3 @@
|
||||
cut 6
|
||||
deal with increment 7
|
||||
deal into new stack
|
3
inputs/22s3.txt
Normal file
3
inputs/22s3.txt
Normal file
@ -0,0 +1,3 @@
|
||||
deal with increment 7
|
||||
deal with increment 9
|
||||
cut -2
|
10
inputs/22s4.txt
Normal file
10
inputs/22s4.txt
Normal file
@ -0,0 +1,10 @@
|
||||
deal into new stack
|
||||
cut -2
|
||||
deal with increment 7
|
||||
cut 8
|
||||
cut -4
|
||||
deal with increment 7
|
||||
cut 3
|
||||
deal with increment 9
|
||||
deal with increment 3
|
||||
cut -1
|
Reference in New Issue
Block a user