DEV Community

Discussion on: Challenge - Print Spiral

Collapse
 
tobias_salzmann profile image
Tobias Salzmann • Edited

A O(1) (or rather O(log log n), because numbers need space) solution in spirit, but I was not in the mood for side effects. Essentially doing recursion per row. I chose to index rows such that 0 is in row 0.

object Spiral extends App {

  type Row = Seq[Int]
  type Matrix = Seq[Row]

  sealed trait Parity
  case object Even extends Parity
  case object Odd extends Parity

  def parity(n: Int) = if(n % 2 == 0) Even else Odd

  def spiralRow(n: Int)(rowIndex: Int): Row = {

    def lastRow(n: Int) = (n * n - n) to (n * n - 1)
    def firstRow(n: Int) = (n * n - 1) to (n * n - n) by -1

    val first = -n / 2
    val last = n / 2

    (parity(n), rowIndex) match {
      case (Even, `first`)  => firstRow(n)
      case (Even, _) => spiralRow(n - 1)(rowIndex) :+ ((n * n) - n - (n / 2) - rowIndex)
      case (Odd, `last`) => lastRow(n)
      case (Odd, _) => ((n - 1) * (n - 1) + rowIndex + (n / 2)) +: spiralRow(n - 1)(rowIndex)
    }
  }


  def spiral(n: Int): Matrix = {
    (0 until n)
      .map(_ - n / 2)
      .map(spiralRow(n))
  }

  def padTo(length: Int)(k: Int) = s"${" " * (length - k.toString.length)}${k.toString}"

  def printSpiral(n: Int): Unit = {
    val maxDigits = (n * n - 1).toString.length
    spiral(n: Int)
      .map(_.map(padTo(maxDigits)).mkString(" "))
        .foreach(println)
  }

  printSpiral(10)
}