ceran
ceran

Reputation: 1412

Obtaining the correct result using recursion in Scala

I've created a data structure to represent an n * n * n cube, in this specific case it's a 4*4*4 cube. For the purpose of debugging, I'd like to implement a method which prints the cube to stdout. The result should be 4 layers, each of them consisting of a 4x4 area.

Since I'm learning Scala, I want to do it in a "functional manner" and came up with a recursive solution. The drawCube method "loops" over all layers, the drawLayer method loops over the lines of a layer and the drawLine method is responsible for a single line.

The code:

    def drawCube = {
     val n = cube.sidelength
     val nl = sys.props("line.separator")
     val border = " -" * (n * 2 -1)

     def drawLine(acc: String, x: Int, y: Int, z: Int): String = {
      if(x < n) drawLine(acc + getField(x, y, z), x + 1, y, z) else <PosA> + acc + "/" + nl
     }
     def drawLayer(acc: String, y: Int, z: Int): String = {
      if(z >= 0) drawLayer(<PosB> + drawLine(acc, 0, y, z), y, z - 1) else acc + border + nl
     }
     def drawCube(acc: String, y: Int): String = {
      if(y < n) drawCube(drawLayer(acc, y, n - 1), y + 1) else border + nl + acc
     }
     def getField(x: Int, y: Int, z: Int) = {
      // returns a string representation of a specific field from the cube
      // in the following example, it's just a dot for the sake of simplicity
      // in a 4x4x4 cube, the range of x, y and z is from 0 to 3
     }
     println(drawCube("", 0))
    }

Regardless of whether I'm putting an additional "/" into Position A or Position B (see placeholders above), I'm always getting the following result:

 - - - - - - -
//////////////// .  .  .  . /
 .  .  .  . /
 .  .  .  . /
 .  .  .  . /
 - - - - - - -
 .  .  .  . /
 .  .  .  . /
 .  .  .  . /
 .  .  .  . /
 - - - - - - -
 .  .  .  . /
 .  .  .  . /
 .  .  .  . /
 .  .  .  . /
 - - - - - - -
 .  .  .  . /
 .  .  .  . /
 .  .  .  . /
 .  .  .  . /
 - - - - - - -

As you can see, everything works fine, except of the the leading slashes, which are all printed at once instead of the beginning of a line. Why is that? What would be the correct position? Perhaps I spent too much time with it, but I can't see the problem right now.Thanks.

edit: you may have noticed that the stop condition of the drawLayer method looks slightly different compared to the other two. That has to do with a transformation of the coordinate system, the origin should be displayed at the top left front corner. But I don't think that's the issue here, the fields are displayed at the correct positions.

Upvotes: 0

Views: 72

Answers (1)

lmm
lmm

Reputation: 17431

The great advantage of the functional style is that you can test the smaller methods individually. Try testing drawLine on its own, or replacing drawLine with something simpler and testing drawLayer. I would recommend avoiding the accumulator until you have the basic functionality working - a simple 0 until n map {drawLine(_, y, z)} mkString has less to go wrong.

To answer your specific question, the accumulator is always the complete current drawing of the cube, as is the return value from any of your functions. So you can't ever do "/" + acc or "/" + drawSomething() as this will always add the "/" onto the very start. Instead you need to add the "/" onto the end of acc, before calling drawLine. i.e. drawLayer should be defined as:

def drawLayer(acc: String, y: Int, z: Int): String =
  if(z >= 0) drawLayer(drawLine(acc + "/", 0, y, z), y, z - 1) else acc + "-" + "\n"

Upvotes: 1

Related Questions