I promise I'll post my code eventually, I spent too long working on this animation of part1: gfycat.com/EasygoingMassiveHog
Oof, I played with this too long.
Here's it all.
private fun answer1(input: List<String>) = step(0, input.findCarts(), input) private fun answer2(input: List<String>) = demolitionStep(0, input.findCarts(), input) tailrec fun step( i: Int, carts: List<Cart>, tracks: List<String> ): Point { val (nextCarts, collisions) = moveCarts(carts = carts.sorted(), tracks = tracks) return when { collisions.isEmpty() -> step(i + 1, nextCarts, tracks) else -> collisions.first().loc } } tailrec fun moveCarts( carts: List<Cart>, moved: List<Cart> = emptyList(), collided: List<Cart> = emptyList(), tracks: List<String> ): Pair<List<Cart>, List<Cart>> { if (carts.isEmpty()) return moved to collided val h = carts.head.move(tracks) val (ucRem, cRem) = carts.tail.splitBy { it.loc == h.loc } val (ucMoved, cMoved) = moved.splitBy { it.loc == h.loc } return when { cRem.isEmpty() && cMoved.isEmpty() -> moveCarts(ucRem, ucMoved + h, collided, tracks) cRem.isEmpty() -> moveCarts(ucRem, ucMoved, collided + h + cMoved, tracks) cMoved.isEmpty() -> moveCarts(ucRem, ucMoved, collided + h + cRem, tracks) else -> moveCarts(ucRem, ucMoved, collided + h + cRem + cMoved, tracks) } } tailrec fun demolitionStep( i: Int, carts: List<Cart>, tracks: List<String> ): Point { val (nextCarts, collisions) = moveCarts( carts = carts.sorted(), tracks = tracks ) return when { carts.count() == 1 -> carts.first().loc else -> demolitionStep(i + 1, nextCarts, tracks) } } enum class Choice { LEFT { override fun makeChoice(cart: Cart) = when (cart.direction) { Direction.RIGHT -> cart.nextPosition(Direction.UP, Choice.LEFT) Direction.LEFT -> cart.nextPosition(Direction.DOWN, Choice.LEFT) Direction.UP -> cart.nextPosition(Direction.LEFT, Choice.LEFT) Direction.DOWN -> cart.nextPosition(Direction.RIGHT, Choice.LEFT) } }, RIGHT { override fun makeChoice(cart: Cart) = when (cart.direction) { Direction.LEFT -> cart.nextPosition(Direction.UP, Choice.RIGHT) Direction.RIGHT -> cart.nextPosition(Direction.DOWN, Choice.RIGHT) Direction.UP -> cart.nextPosition(Direction.RIGHT, Choice.RIGHT) Direction.DOWN -> cart.nextPosition(Direction.LEFT, Choice.RIGHT) } }, STRAIGHT { override fun makeChoice(cart: Cart) = when (cart.direction) { Direction.RIGHT, Direction.LEFT -> cart.nextPosition(cart.direction, Choice.STRAIGHT) Direction.DOWN, Direction.UP -> cart.nextPosition(cart.direction, Choice.STRAIGHT) } }; abstract fun makeChoice(cart: Cart): Cart } enum class Direction(val char: Char) { UP('^') { override fun turnBack() = LEFT override fun turnForward() = RIGHT override fun move(loc: Point) = Point(loc.x, loc.y - 1) }, DOWN('v') { override fun turnBack() = RIGHT override fun turnForward() = LEFT override fun move(loc: Point) = Point(loc.x, loc.y + 1) }, LEFT('<') { override fun turnBack() = UP override fun turnForward() = DOWN override fun move(loc: Point) = Point(loc.x - 1, loc.y) }, RIGHT('>') { override fun turnBack() = DOWN override fun turnForward() = UP override fun move(loc: Point) = Point(loc.x + 1, loc.y) }; abstract fun move(loc: Point): Point abstract fun turnBack(): Direction abstract fun turnForward(): Direction override fun toString(): String = this.char.toString() } fun Char.toDirection(): Direction? { return Direction.values().find { it.char == this } } fun <E> Direction?.whenNotNull(function: (Direction) -> E): E? = when { this != null -> function(this) else -> null } class OffTheRailsException(cart: Point) : Exception("Off the rails! $cart") data class Cart( val loc: Point, val direction: Direction, val lastChoice: Choice?, val id: Int ) : Comparable<Cart> { override fun compareTo(other: Cart) = when (val ycomp = y.compareTo(other.y)) { 0 -> x.compareTo(other.x) else -> ycomp } constructor(loc: Point, direction: Direction, lastChoice: Choice?) : this( loc, direction, lastChoice, loc.hashCode() + direction.hashCode() ) } fun Cart.nextPosition(direction: Direction, lastChoice: Choice?) = Cart(direction.move(loc), direction, lastChoice, id) fun Cart.nextPosition(direction: Direction) = Cart(direction.move(loc), direction, lastChoice, id) // '\' fun Cart.turnBackCorner() = nextPosition(direction.turnBack()) // '/' fun Cart.turnForwardCorner() = nextPosition(direction.turnForward()) val Cart.x: Int get() = loc.x val Cart.y: Int get() = loc.y fun Cart.move(tracks: List<String>) = when (tracks[y][x]) { '|', '^', 'v' -> nextPosition( direction ) '-', '<', '>' -> nextPosition( direction ) '\\' -> turnBackCorner() '/' -> turnForwardCorner() '+' -> intersection() else -> throw OffTheRailsException(loc) } fun Cart.intersection() = when (lastChoice) { null, Choice.RIGHT -> Choice.LEFT.makeChoice(this) Choice.STRAIGHT -> Choice.RIGHT.makeChoice(this) Choice.LEFT -> Choice.STRAIGHT.makeChoice(this) } fun <E> List<E>.splitBy(predicate: (E) -> Boolean) = groupBy(predicate).let { (it[false] ?: emptyList()) to (it[true] ?: emptyList()) } fun List<String>.findCarts() = mapIndexed { y, xl -> xl.mapIndexedNotNull { x, c -> c.toDirection().whenNotNull { Cart(Point(x, y), it, null) } } }.flatten()
Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink.
Hide child comments as well
Confirm
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
I promise I'll post my code eventually, I spent too long working on this animation of part1: gfycat.com/EasygoingMassiveHog
Oof, I played with this too long.
Here's it all.
Kotlin Solution