2022 Day 17 Complete

This commit is contained in:
2022-12-27 14:55:45 -06:00
parent 147602a52f
commit 48f30b8e42
2 changed files with 122 additions and 295 deletions

View File

@@ -2,8 +2,7 @@ package main
import (
"fmt"
"os"
"time"
"image"
h "git.bullercodeworks.com/brian/adventofcode/helpers"
)
@@ -26,269 +25,62 @@ var (
func main() {
inp := h.StdinToString()
//fmt.Println("# Part 1")
//simulate(inp, 2022)
fmt.Println("# Part 2")
simulate(inp, 1000000000000)
}
func stateAndSleep(m *h.GrowUpCoordByteMap) {
if !debug {
return
rocks := [][]image.Point{
{{0, 0}, {1, 0}, {2, 0}, {3, 0}},
{{1, 2}, {0, 1}, {1, 1}, {2, 1}, {1, 0}},
{{2, 2}, {2, 1}, {0, 0}, {1, 0}, {2, 0}},
{{0, 3}, {0, 2}, {0, 1}, {0, 0}},
{{0, 1}, {1, 1}, {0, 0}, {1, 0}},
}
fmt.Print(h.CLEAR_SCREEN)
//fmt.Println()
fmt.Println(m)
time.Sleep(time.Second / 10)
}
var cache map[string][]int
func simulate(jets string, numRocks int) {
cache = make(map[string][]int)
m := h.NewGrowUpCoordByteMap()
m.PutBytes([][]byte{
bottomRow, emptyRow, emptyRow, emptyRow, emptyRow,
emptyRow, emptyRow, emptyRow,
}, h.Coordinate{X: 0, Y: 0})
m.StringEmptyIsSpace = true
jetIdx := 0
rockType := 0
var state string
var height int
var turboHeight int
var cacheDisabled bool
for rockNum := 1; rockNum <= numRocks; rockNum++ {
fmt.Println(h.CLEAR_SCREEN)
fmt.Println("Simulating:", rockNum, "/", numRocks)
h.PrintProgress(rockNum, numRocks)
fmt.Println("\nHeight:", height)
if !cacheDisabled {
state, height = GetState(rockType, jetIdx, m)
if v, ok := cache[state]; !cacheDisabled && ok {
// Ok, we've got a duplicate. Go full turbo.
//addHeight := height
mult := numRocks / rockNum
newRockNum := rockNum * mult
turboHeight = height * mult
/*
for rockNum+v[1] <= numRocks {
rockNum = rockNum + v[1]
height = height + addHeight
fmt.Println(h.CLEAR_SCREEN)
fmt.Println("Simulating:", rockNum, "/", numRocks)
h.PrintProgress(rockNum, numRocks)
fmt.Println("\nHeight:", height)
}
*/
fmt.Println(h.CLEAR_SCREEN)
fmt.Println("Simulating:", rockNum, "/", numRocks)
h.PrintProgress(rockNum, numRocks)
fmt.Println("\nHeight:", height)
fmt.Println("State", state, "\nV:", v, "\nMult:", mult, "\nRockNum:", rockNum, "\nNewRockNum:", newRockNum, "\nTurboHeight:", turboHeight)
cacheDisabled = true
os.Exit(0)
} else {
cache[state] = []int{rockNum, height}
grid := map[image.Point]struct{}{}
move := func(rock []image.Point, delta image.Point) bool {
nrock := make([]image.Point, len(rock))
for i, p := range rock {
p = p.Add(delta)
if _, ok := grid[p]; ok || p.X < 0 || p.X >= 7 || p.Y < 0 {
return false
}
} else {
fmt.Println("\nHeight:", turboHeight+GetHeight(m))
nrock[i] = p
}
copy(rock, nrock)
return true
}
cache := map[[2]int][]int{}
height, jet := 0, 0
for i := 0; i < 1000000000000; i++ {
if i == 2022 {
fmt.Println("# Part 1")
fmt.Println(height)
fmt.Println()
}
k := [2]int{i % len(rocks), jet}
if c, ok := cache[k]; ok {
if n, d := 1000000000000-i, i-c[0]; n%d == 0 {
fmt.Println("# Part 2")
fmt.Println(height + n/d*(height-c[1]))
break
}
}
cache[k] = []int{i, height}
rock := []image.Point{}
for _, p := range rocks[i%len(rocks)] {
rock = append(rock, p.Add(image.Point{2, height + 3}))
}
AddFallingRock(rockType, m)
stateAndSleep(m)
doJet := true
for {
if !doJet && AtRest(m) {
break
}
shiftDir := dirD
if doJet {
switch jets[jetIdx] {
case '>':
shiftDir = dirR
case '<':
shiftDir = dirL
move(rock, image.Point{int(inp[jet]) - int('='), 0})
jet = (jet + 1) % len(inp)
if !move(rock, image.Point{0, -1}) {
for _, p := range rock {
grid[p] = struct{}{}
if p.Y+1 > height {
height = p.Y + 1
}
}
jetIdx = (jetIdx + 1) % len(jets)
}
ShiftRock(shiftDir, m)
stateAndSleep(m)
doJet = !doJet
}
// The falling rock has stopped
StopRock(m)
stateAndSleep(m)
rockType = (rockType + 1) % rocks
}
fmt.Println("After", numRocks, "the tower is", GetHeight(m), "blocks tall")
}
func GetState(r, j int, m *h.GrowUpCoordByteMap) (string, int) {
ret := fmt.Sprintf("%d;%d;", r, j)
for x := 1; x < 7; x++ {
for y := m.TLY; y > 1; y-- {
if m.Get(h.Coordinate{X: x, Y: y}) == '#' {
ret = fmt.Sprintf("%s-%d", ret, m.TLY-y)
break
}
}
}
return ret, GetHeight(m)
}
func GetHeight(m *h.GrowUpCoordByteMap) int {
return h.GetHighestY(m.FindAll('#')...)
}
func FindTopAtRestY(m *h.GrowUpCoordByteMap) int {
rockSpots := m.FindAll('#')
if len(rockSpots) != 0 {
return h.GetHighestY(rockSpots...)
}
return 0
}
func StopRock(m *h.GrowUpCoordByteMap) {
rockSpots := m.FindAll('@')
for i := range rockSpots {
m.Put(rockSpots[i], '#')
}
}
func ShiftRock(dir int, m *h.GrowUpCoordByteMap) {
if !CanShift(dir, m) {
return
}
rockSpots := m.FindAll('@')
for i := range rockSpots {
m.Put(rockSpots[i], ' ')
}
for i := range rockSpots {
switch dir {
case dirU:
m.Put(GetUp(rockSpots[i]), '@')
case dirR:
m.Put(GetRight(rockSpots[i]), '@')
case dirD:
m.Put(GetDown(rockSpots[i]), '@')
case dirL:
m.Put(GetLeft(rockSpots[i]), '@')
}
}
}
func CanShift(dir int, m *h.GrowUpCoordByteMap) bool {
rockSpots := m.FindAll('@')
switch dir {
case dirU: // Shouldn't need to, though.
return true
case dirR:
for i := range rockSpots {
tst := m.Get(GetRight(rockSpots[i]))
if tst != '@' && tst != ' ' {
return false
}
}
return true
case dirD:
for i := range rockSpots {
tst := m.Get(GetDown(rockSpots[i]))
if tst != '@' && tst != ' ' {
return false
}
}
return true
case dirL:
for i := range rockSpots {
tst := m.Get(GetLeft(rockSpots[i]))
if tst != '@' && tst != ' ' {
return false
}
}
return true
}
return false
}
func AddFallingRock(tp int, m *h.GrowUpCoordByteMap) {
rock := GetRockBytes(tp)
pos := h.Coordinate{X: 3, Y: FindTopAtRestY(m) + 4}
for pos.Y+3 > m.TLY {
m.PutBytes([][]byte{emptyRow}, h.Coordinate{X: 0, Y: m.TLY + 1})
}
m.PutBytes(rock, pos)
}
func AtRest(m *h.GrowUpCoordByteMap) bool {
rockSpots := m.FindAll('@')
if len(rockSpots) == 0 {
return true
}
for i := range rockSpots {
pos := GetDown(rockSpots[i])
wrk := m.Get(pos)
if pos.Y == m.BRY {
return true
}
if wrk != ' ' && wrk != '@' {
return true
}
}
return false
}
func GetRockBytes(tp int) [][]byte {
switch tp {
case 0:
return [][]byte{{'@', '@', '@', '@'}}
case 1:
return [][]byte{
{' ', '@', ' '},
{'@', '@', '@'},
{' ', '@', ' '},
}
case 2:
return [][]byte{
{'@', '@', '@'},
{' ', ' ', '@'},
{' ', ' ', '@'},
}
case 3:
return [][]byte{
{'@'},
{'@'},
{'@'},
{'@'},
}
case 4:
return [][]byte{
{'@', '@'},
{'@', '@'},
}
}
return [][]byte{}
}
func GetLeft(c h.Coordinate) h.Coordinate {
return h.Coordinate{X: c.X - 1, Y: c.Y}
}
func GetRight(c h.Coordinate) h.Coordinate {
return h.Coordinate{X: c.X + 1, Y: c.Y}
}
func GetUp(c h.Coordinate) h.Coordinate {
return h.Coordinate{X: c.X, Y: c.Y + 1}
}
func GetDown(c h.Coordinate) h.Coordinate {
return h.Coordinate{X: c.X, Y: c.Y - 1}
}
func DirToString(shiftDir int) string {
switch shiftDir {
case dirU:
return "^"
case dirR:
return ">"
case dirD:
return "v"
case dirL:
return "<"
}
return " "
}