4
\$\begingroup\$

In a game of Connect4:

  • we start with an empty grid
  • two players place pieces X and O on the grid
  • the first player to achieve 4 pieces in a line wins!
  • this is a text based console game

Here is the code I wrote to print each cell in the grid:

def asText(grid: Grid) = {

      def asText(x:Int, y:Int) = {

        val isTop = y == 0 && x != grid.x + 1 && x != 0
        val newLine = x == grid.x + 1
        val isBottom = y == grid.y + 1 && x != 0
        val isLeft = x == 0
        val isX = grid.pieces.contains(Piece("X", x,y))
        val isY = grid.pieces.contains(Piece("O", x,y))

        List(isTop, newLine, isBottom, isLeft, isX, isY) match {
          case true::_ => "-"
          case _::true::_ => "|\n"
          case _::_::true::_ => "-"
          case _::_::_::true::_ => "|"
          case _::_::_::_::true::_ => "X"
          case _::_::_::_::_::true::_ => "O"
          case _ => "."
        }
      }

      val v = for {
        y  <- 0 to grid.y + 1
        x  <- 0 to grid.x + 1
        text = asText(x, y)
      } yield text

      v.mkString("")
    }

I don't like this _::_::_::_::_::true::_ but can't think of a way to improve it. Can this style be improved? Is there a more Scala idiomatic style to do this?

Example output:

|------|
|XO....|
|......|
|......|
|......|
|......|
|......|
|......|
|------|

Edit: As requested

case class Piece(symbol:String, x:Int, y:Int)
case class Grid(x:Int = 6, y:Int = 7, pieces:List[Piece] = List())
\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

Is the graphic representation of a data structure an integral part of that data structure (val gString = myGrid.asText) or separate and independent from the data structure (val gString = asText(myGrid))?

I tend to favor the former, but if the Grid API is solid and supplies everything needed for one or more graphic representations, then the latter is probably the better choice. It's a little hard to judge here as you haven't provided the Grid (or Piece) code.

I question the choice of iterating through coordinates that are known to be outside the Grid just for the purpose of drawing a border. Wouldn't it be easier to get the grid contents and simply "wrap" them with border characters?

def asText(grid :Grid) :String = {
  val border = "|" + "-"*grid.x + "|"
  (1 to grid.y).map{ y =>
    (1 to grid.x).map{ x =>
      if      (grid.pieces.contains(Piece("X", x, y))) "X"
      else if (grid.pieces.contains(Piece("O", x, y))) "O"
      else "."
    }.mkString("|", "", "|")
  }.mkString(s"$border\n", "\n", s"\n$border")
}
\$\endgroup\$
1
  • \$\begingroup\$ To answer your question: object Connect4Game { def asText(grid :Grid): String = { ... } \$\endgroup\$
    – jakstack
    Commented Jun 19, 2019 at 8:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.