Created
December 17, 2022 07:37
-
-
Save saidaspen/06c948893ece20f1d2e001b71ea26d58 to your computer and use it in GitHub Desktop.
Dag 17 ostädad :)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import se.saidaspen.aoc.util.* | |
import java.math.BigInteger | |
import kotlin.math.absoluteValue | |
fun main() = Dayxx.run() | |
object Dayxx : Day(2022, 17) { | |
var dash = toMap("####").map { it.key }.toSet() | |
var plus = toMap(".#.\n" + | |
"###\n" + | |
".#.").filter { it.value == '#' }.map { it.key }.toSet() | |
var lThing = toMap("..#\n" + | |
"..#\n" + | |
"###").filter { it.value == '#' }.map { it.key }.toSet() | |
var iThing = toMap("#\n" + | |
"#\n" + | |
"#\n" + | |
"#").filter { it.value == '#' }.map { it.key }.toSet() | |
var square = toMap("##\n" + | |
"##").filter { it.value == '#' }.map { it.key }.toSet() | |
val rocks = listOf(dash, plus, lThing, iThing, square) | |
var up = P(0, -1) | |
var down = P(0, 1) | |
var left = P(-1, 0) | |
var right = P(1, 0) | |
var leftWallX = -3 | |
var rightWallX = 5 | |
var bottom = 4 | |
override fun part1(): Any { | |
// input = ">>><<><>><<<>><>>><<<>>><<<><<<>><>><<>>" | |
println(input) | |
var vinds = input.e() | |
var vindI = 0 | |
val map = mutableMapOf<Point, Char>() | |
for (x in leftWallX..rightWallX) { | |
map[P(x, bottom)] = '-' | |
} | |
var top = bottom | |
var movingRock : Set<Point> = getRock(0, bottom) | |
var nextRock = 1 | |
var doVind = true | |
var stoppedRocks = 0 | |
while(stoppedRocks < 2023) { | |
if (doVind) { | |
val vind = vinds[vindI] | |
vindI = (vindI + 1) % vinds.size | |
val afterMoving = if (vind == '>') { | |
move(movingRock, 1, right) | |
} else { | |
move(movingRock, 1, left) | |
} | |
if (afterMoving.map { it.x }.max() >= rightWallX) { | |
} else if (afterMoving.map { it.x }.min() <= leftWallX) { | |
} else if (afterMoving.any { map.containsKey(it) }) { | |
} else { | |
movingRock = afterMoving | |
} | |
} else { | |
val afterMoving = move(movingRock, 1, down) | |
if (afterMoving.any { map.containsKey(it) }) { | |
movingRock.forEach{ map[it] = '#'} | |
val rockType = nextRock | |
nextRock = (nextRock + 1)%5 | |
// map.printArea() | |
// println("\n\n\n\n") | |
val top = map.keys.map { it.second }.min() | |
movingRock = getRock(rockType, top) | |
stoppedRocks += 1 | |
} else { | |
movingRock = afterMoving | |
} | |
} | |
doVind = !doVind | |
} | |
val topOfMap: Int = map.keys.map { it.second }.min() * -1 +2 | |
return topOfMap | |
} | |
private fun getRock(t: Int, bottom: Int): Set<P<Int, Int>> { | |
val rockType = t % 5 | |
var rock = rocks[rockType] | |
val yMax = rock.map { it.second }.max() | |
var bottomOfRockShouldBe = bottom - 4 | |
val distanceToFloor = (yMax - bottomOfRockShouldBe).absoluteValue | |
rock = if (bottomOfRockShouldBe < yMax) { | |
move(rock, distanceToFloor, up) | |
} else { | |
move(rock, distanceToFloor, down) | |
} | |
return rock | |
} | |
private fun move(rock: Set<Pair<Int, Int>>, distance: Int, dir: Pair<Int, Int>): Set<P<Int, Int>> { | |
return rock.map { it + (dir * distance) }.toSet() | |
} | |
override fun part2(): Any { | |
// input = ">>><<><>><<<>><>>><<<>>><<<><<<>><>><<>>" | |
var vinds = input.e() | |
var vindI = 0 | |
val map = mutableMapOf<Point, Char>() | |
for (x in leftWallX..rightWallX) { | |
map[P(x, bottom)] = '-' | |
} | |
var top = bottom | |
var movingRock : Set<Point> = getRock(0, bottom) | |
var nextRock = 1 | |
var doVind = true | |
var heightDiffs = "0" | |
while(true) { | |
if (doVind) { | |
val vind = vinds[vindI] | |
vindI = (vindI + 1) % vinds.size | |
val afterMoving = if (vind == '>') { | |
move(movingRock, 1, right) | |
} else { | |
move(movingRock, 1, left) | |
} | |
if (afterMoving.map { it.x }.max() >= rightWallX) { | |
} else if (afterMoving.map { it.x }.min() <= leftWallX) { | |
} else if (afterMoving.any { map.containsKey(it) }) { | |
} else { | |
movingRock = afterMoving | |
} | |
} else { | |
val afterMoving = move(movingRock, 1, down) | |
if (afterMoving.any { map.containsKey(it) }) { | |
val prevTop = map.keys.map { it.second }.min() | |
movingRock.forEach{ map[it] = '#'} | |
val rockType = nextRock | |
nextRock = (nextRock + 1)%5 | |
val top = map.keys.map { it.second }.min() | |
var heightDiff = (top - prevTop).absoluteValue | |
heightDiffs += heightDiff | |
if (heightDiffs.length == 5_001) { | |
var newHeightDiffs = heightDiffs.drop(1000) | |
var found = false | |
var len = 20 | |
var cycle = "" | |
while (!found) { | |
var needle = newHeightDiffs.substring(0, len) | |
if (newHeightDiffs.substring(len).startsWith(needle)) { | |
found = true | |
cycle = needle | |
continue | |
} | |
len += 1 | |
} | |
var lastIndex = heightDiffs.lastIndexOf(cycle) | |
println("Lastindex " + lastIndex) | |
println("heightDiffs.length " + heightDiffs.length) | |
var whereInCycle = heightDiffs.length - (cycle.length + lastIndex) | |
println("whereInCycle " + whereInCycle) | |
println("Found cycle $len") | |
var heightAt5000 = heightDiffs.substring(1, 5000+1).e().map { it.digitToInt() }.sum() | |
var heightIncreaseOneCycle = cycle.e().map { it.digitToInt() }.sum().toLong() | |
println("Size after 5000 rocks is " + heightAt5000 ) | |
println("One cycle increases " + heightIncreaseOneCycle ) | |
var cycleB = BigInteger.valueOf(len.toLong()) | |
var times = (BigInteger.valueOf(1000000000000L).minus(BigInteger.valueOf(5000))).divide(cycleB) | |
var getsUsTo = BigInteger.valueOf(5000).add(times.multiply(cycleB)) | |
var left = BigInteger.valueOf(1000000000000L).minus(getsUsTo) | |
var currHeight = heightAt5000.toLong().toBigInteger().add(heightIncreaseOneCycle.toBigInteger().multiply(times)) | |
println("Gets us to $getsUsTo, with $left left") | |
var heightAfter = (cycle+cycle).substring(whereInCycle, whereInCycle+left.toInt()).map { it.digitToInt() }.sum() | |
var missing = BigInteger.valueOf(1514285714288L).minus(currHeight) | |
println("missing $missing") | |
var totalHeight = currHeight + heightAfter.toLong().toBigInteger() | |
println("currHeight+heightAfter=totalHeight\t$currHeight+$heightAfter=$totalHeight") | |
println("here") | |
return totalHeight.toString() | |
} | |
movingRock = getRock(rockType, top) | |
} else { | |
movingRock = afterMoving | |
} | |
} | |
doVind = !doVind | |
} | |
// 1 000 000 000 000 | |
val topOfMap: Int = map.keys.map { it.second }.min() * -1 +2 | |
return topOfMap | |
} | |
} | |
private operator fun Pair<Int, Int>.times(fact: Int): Pair<Int, Int> { | |
return P(this.x * fact, this.y * fact) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment