Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- object Solution {
- import scala.io.StdIn._
- def main(args: Array[String]): Unit = {
- val params = readLine().split("\\s").toList
- params match {
- case r :: c :: n :: Nil if r.toInt > 0 && c.toInt > 0 && c.toInt <= 200 && n.toInt > 0 && n.toInt < 1000000000 =>
- //Define regex matcher to validate input
- val fmt = s"""^[O.]{$c}""".r
- val inputOption = (0 until r.toInt).foldLeft(Option("")) { (str, _) =>
- val line = readLine()
- if(fmt.pattern.matcher(line).matches)
- str.map(_ + line)
- else None
- }
- val input = inputOption.getOrElse {
- throw new IllegalArgumentException("Input was not in the expected format")
- }
- val grid = Grid(r.toInt, c.toInt, input.map((_, 0)).toVector)
- //Print grid after N ticks
- println(gridAtN(grid, n.toInt))
- case _ => throw new IllegalArgumentException("Input was not in expected format")
- }
- }
- type Time = Int
- case class Grid(numRows: Int, numColumns: Int, cells: Vector[(Char, Time)]) {
- override def toString: String = cells.grouped(numColumns).foldLeft("") { (str, line) =>
- str + line.map(_._1).mkString("") + sys.props("line.separator")
- }
- }
- val tick = (previousGrid: Grid, time: Time) => {
- if (time == 1)
- previousGrid
- else if (time % 2 == 0) {
- //Every second tick, fill entire grid with bombs
- //Par as an optimisation here, but is likely to be worse on small vectors so put in a threshold
- previousGrid.copy(cells = previousGrid.cells.map(cell => if (cell._1 != 'O') ('O', time) else cell))
- } else {
- //Otherwise we're on a tick which is "odd", corresponding to step 4: Kaboom!
- previousGrid.cells.zipWithIndex.foldLeft(previousGrid) { case (g, (cell, idx)) =>
- if(cell._1 == 'O' && time - cell._2 == 3) detonate(g, idx / g.numColumns, idx % g.numColumns, time) else g
- }
- }
- }
- def getCellOption(grid: Grid, i: Int, j: Int) = {
- if(i < 0 || i >= grid.numRows || j < 0 || j >= grid.numColumns)
- None
- else
- Some((i * grid.numColumns) + j)
- }
- def detonate(grid: Grid, i: Int, j: Int, t: Time): Grid = getCellOption(grid, i, j).fold(grid) { cellIdx =>
- grid.cells.lift(cellIdx).fold(grid) {
- case ('O', age) =>
- //There is a bomb
- //Is the bomb exactly 3 seconds old?
- val newGrid = grid.copy(cells = grid.cells.updated(cellIdx, ('.', t)))
- if (t - age == 3) {
- //If so then spread to bomb's neighbours after updating this cell
- //Multiple vals chaining dependency on new grid created after each detonation. Would use for comprehension and
- //flatmap over cells vector in a redesign
- val n = detonate(newGrid, i-1, j, t)
- val e = detonate(n, i, j+1, t)
- val s = detonate(e, i+1, j, t)
- detonate(s, i, j-1, t) //w
- } else {
- newGrid
- }
- case _ => grid //There was no bomb in that slot.
- }
- }
- def gridAtN(grid: Grid, n: Time): Grid = Iterator.from(1).take(n).foldLeft(grid)(tick)
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement