tginsberg/advent-2018-kotlin

Fetching contributors…
Cannot retrieve contributors at this time
125 lines (106 sloc) 3.75 KB
 /* * Copyright (c) 2018 by Todd Ginsberg */ /** * Advent of Code 2018, Day 17 - Reservoir Research * * Problem Description: http://adventofcode.com/2018/day/17 * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2018/day17/ */ package com.ginsberg.advent2018 class Day17(rawInput: List) { private val parsedData = createMap(rawInput) private val grid: Array = parsedData.first private val minY: Int = parsedData.second private val fountain: Point = Point(500, 0) fun solvePart1(): Int { flow(fountain) return grid.filterIndexed { idx, _ -> idx >= minY }.sumBy { row -> row.filter { it in flowOrStill }.count() } } fun solvePart2(): Int { flow(fountain) return grid.filterIndexed { idx, _ -> idx >= minY }.sumBy { row -> row.filter { it == '~' }.count() } } private fun flow(source: Point) { if (source.down !in grid) { return } if (grid[source.down] == '.') { grid[source.down] = '|' flow(source.down) } if (grid[source.down] in wallOrStill && source.right in grid && grid[source.right] == '.') { grid[source.right] = '|' flow(source.right) } if (grid[source.down] in wallOrStill && source.left in grid && grid[source.left] == '.') { grid[source.left] = '|' flow(source.left) } if (hasWalls(source)) { fillLeftAndRight(source) } } private fun hasWalls(source: Point): Boolean = hasWall(source, Point::right) && hasWall(source, Point::left) private fun hasWall(source: Point, nextPoint: (Point) -> Point): Boolean { var point = source while (point in grid) { when (grid[point]) { '#' -> return true '.' -> return false else -> point = nextPoint(point) } } return false } private fun fillLeftAndRight(source: Point) { fillUntilWall(source, Point::right) fillUntilWall(source, Point::left) } private fun fillUntilWall(source: Point, nextPoint: (Point) -> Point) { var point = source while (grid[point] != '#') { grid[point] = '~' point = nextPoint(point) } } private fun createMap(input: List): Pair, Int> { val spots = claySpotsFromInput(input) val minY = spots.minBy { it.y }!!.y val maxX = spots.maxBy { it.x }!!.x val maxY = spots.maxBy { it.y }!!.y // Generate based off of maximum sizes val grid: Array = (0..maxY).map { // Account for zero indexing and flowing off the right side of the map! CharArray(maxX + 2).apply { fill('.') } }.toTypedArray() // Add all clay spots to the grid spots.forEach { spot -> grid[spot] = '#' } // Add the fountain grid[0][500] = '+' return Pair(grid, minY) } private fun claySpotsFromInput(input: List): List = input.flatMap { row -> val digits = row.toIntArray() if (row.startsWith("y")) { (digits[1]..digits[2]).map { Point(it, digits[0]) } } else { (digits[1]..digits[2]).map { Point(digits[0], it) } } } companion object { private val nonDigits = """[xy=,]""".toRegex() private val wallOrStill = setOf('#', '~') private val flowOrStill = setOf('|', '~') private fun String.toIntArray(): IntArray = this.replace(nonDigits, "").replace("..", " ").split(" ").map { it.toInt() }.toIntArray() } }