Friday, October 16, 2015

Separation of data and logic: Scala in Clojure style

Here is a data-centric/data-focused implementation of the same “text spiral” example that I have posted before:

import java.io.{File, PrintWriter}
import javax.swing.JSpinner.NumberEditor
import scala.io.Source

object SpiralObj1 {
  type TextLayout = Array[String]

  def textLayout(s: String): TextLayout = Array(s)

  // fill by width and height
  def textLayout(s: String, w: Int, h: Int) = Array.fill(h)(s * w)

  def padString(s: String, n: Int): String = {
    val n1 = s.length
    val diff = n - n1
    if (diff <= 0) s
    else {
      val halfDiff = diff / 2
      List.fill(halfDiff)(" ").mkString("") + s + List.fill(n - halfDiff)(" ").mkString("")
    }
  }

  def width(t: TextLayout): Int = if(t.isEmpty) 0 else t(0).length

  def height(t: TextLayout): Int = t.length

  def above(t1: TextLayout, t2: TextLayout): TextLayout = {
    val t3 = widen(t1, width(t2))
    val t4 = widen(t2, width(t1))
    val res = t3 ++ t4
    res
  }

  def beside(t1: TextLayout, t2: TextLayout): TextLayout = {
    val t3 = heighten(t1, height(t2))
    val t4 = heighten(t2, height(t1))
    for ((s1, s2) <- t3.zip(t4)) yield s1 + s2
  }


  def widen(t: TextLayout, n: Int): TextLayout = {
    val n1 = width(t)
    if (n <= n1) t
    else {
      val halfDiff = (n - n1) / 2
      val h = height(t)
      val left = textLayout(" ", halfDiff, h)
      val right = textLayout(
        " ",
        n - halfDiff - width(t),
        h
      )
      beside(beside(left, t), right)
    }
  }

  def heighten(t: TextLayout, n: Int): TextLayout = {
    val h = height(t)
    if (n <= h) t
    else {
      val w = width(t)
      val halfDiff = (n - h) / 2
      val top = textLayout(" ", w, halfDiff)
      val bottom = textLayout(" ", w, n - halfDiff - h)
      above(
        above(top, t),
        bottom
      )
    }
  }

  def stringify(t: TextLayout): String = {
    t.mkString("\n")
  }

  val corner = textLayout("+")
  val space = textLayout(" ")

  def spiral(nEdges: Int, direction: Int): TextLayout = {
    if(nEdges == 0) corner
    else {
      val sp = spiral(nEdges - 1, (direction + 3) % 4)
      val verticalBar = textLayout("|", 1, height(sp))
      val horizontalBar = textLayout("-", width(sp), 1)
      if(direction == 0)
        above(
          beside(corner, horizontalBar),
          beside(sp, space)
        )
      else if(direction == 1)
        beside(
          above(sp, space),
          above(corner, verticalBar)
        )
      else if(direction == 2)
        above(
          beside(space, sp),
          beside(horizontalBar, corner)
        )
      else
        beside(
          above(verticalBar, corner),
          above(space, sp)
        )
    }
  }

  def spiral(nEdge: Int): TextLayout = {
    spiral(nEdge, nEdge % 4)
  }
}


object Main {
  def main(args: Array[String]) {
    import SpiralObj1._
    (0 to 10).foreach(
      x => {
        println()
        println(stringify(spiral(x)))
      }
    )
  }
}

0 comments: