Skip to main content
Post Reopened by Jamal
added 116 characters in body
Source Link
Jamal
  • 35.2k
  • 13
  • 134
  • 238

I always have enormous difficulty working out 2D grid addresses, so for me it is easier to work with the ListList functions. All tests pass and I'm looking for feedback on clarity, functional programming concepts, or extra edge cases.

Tests:Source:

import org.scalatest.{FlatSpec, Matchers}

class TestSolver extends FlatSpec with Matchers {

    "Sudoku board" should "instantiate with a literal" in {
        val newBoard = new Board(
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9
       values: Int*) {

        newBoard.isSolved() should equal (false)
        newBoard.row(0) should equal (Listrequire(1,2,3,4,5,6,7,8,9))
        newBoardvalues.column(0) shouldlength equal== (List(1,1,1,1,1,1,1,181,1))
       "Board newBoard.square(0)(0).flattenmust shouldcontain equal81 (List(1,2,3,1,2,3,1,2,3)cells")
    }

    it should "fail if instantiated with wrong numberdef ofisSolved(): args"Boolean in= {

        intercept[IllegalArgumentException]val rowsSolved: Seq[Boolean] = (0 until 9).map(i => row(i)).map(Board.solvedSeq)
        val colsSolved: Seq[Boolean] = (0 until 9).map(i => column(i)).map(Board.solvedSeq)
        val squaresSolved: Seq[Boolean] = {
            newval pairs = for (x <- 0 until 3; y <- 0 until 3) yield (x, y)
            pairs.map(p => {
                Board.solvedSeq(1square(p._1)(p._2).flatten)   
            })
        }

    }

    it should "always return the correct row" in {

        val newBoard = new Board(
            1,1,1,1,1,1,1,1,1,
            2,2,2,2,2,2,2,2,2,
            3,3,3,3,3,3,3,3,3,
            4,4,4,4,4,4,4,4,4,
            5,5,5,5,5,5,5,5,5,
            6,6,6,6,6,6,6,6,6,
            7,7,7,7,7,7,7,7,7,
            8,8,8,8,8,8,8,8,8,
            9,9,9,9,9,9,9,9,9
        )

        newBoard.row(0) should equal (Seq(1,1,1,1,1,1,1,1,1))
        newBoard.row(1) should equal (Seq(2,2,2,2,2,2,2,2,2))
        newBoard.row(2) should equal (Seq(3,3,3,3,3,3,3,3,3))
        newBoard.row(3) should equal (Seq(4,4,4,4,4,4,4,4,4))
        newBoard.row(4) should equal (Seq(5,5,5,5,5,5,5,5,5))
        newBoard.row(5) should equal (Seq(6,6,6,6,6,6,6,6,6))
        newBoard.row(6) should equal (Seq(7,7,7,7,7,7,7,7,7))
       rowsSolved newBoard.row(7)++ shouldcolsSolved equal++ (Seq(8,8,8,8,8,8,8,8,8)squaresSolved)
        newBoard.row(8) shoulddistinct equal== (SeqVector(9,9,9,9,9,9,9,9,9)true)

    }

    it should "always return the correct column" in {

        val newBoard = new Board(
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9
        )

        newBoard.column(0) should equal (Seq(1,1,1,1,1,1,1,1,1))
        newBoard.column(1) should equal (Seq(2,2,2,2,2,2,2,2,2))
        newBoard.column(2) should equal (Seq(3,3,3,3,3,3,3,3,3))
        newBoard.column(3) should equal (Seq(4,4,4,4,4,4,4,4,4))
        newBoard.column(4) should equal (Seq(5,5,5,5,5,5,5,5,5))
        newBoard.column(5) should equal (Seq(6,6,6,6,6,6,6,6,6))
        newBoard.column(6) should equal (Seq(7,7,7,7,7,7,7,7,7))
       def newBoard.columnrow(7) should equali: (Seq(8,8,8,8,8,8,8,8,8)Int)
     : Seq[Int] = newBoardvalues.columnslice(8) shouldi equal* (Seq(9,9,9,9,9,9,9,9,9))
    }

    it should "always return the correct square" in {

        val newBoard = new Board(
            1,1,1,4,4,4,7,7,7,
            1,1,1,4,4,4,7,7,7,
            1,1,1,4,4,4,7,7,7,
            2,2,2,5,5,5,8,8,8,
            2,2,2,5,5,5,8,8,8,
            2,2,2,5,5,5,8,8,8,
            3,3,3,6,6,6,9,9,9,
            3,3,3,6,6,6,9,9,9,
          i * 3,3,3,6,6,6,9,9,9
        )

        newBoard.square(0)(0).flatten should equal (Seq(1,1,1,1,1,1,1,1,1))
        newBoard.square(0)(1).flatten should equal (Seq(2,2,2,2,2,2,2,2,2))
        newBoard.square(0)(2).flatten should equal (Seq(3,3,3,3,3,3,3,3,3))
        newBoard.square(1)(0).flatten should equal (Seq(4,4,4,4,4,4,4,4,4))
        newBoard.square(1)(1).flatten should equal (Seq(5,5,5,5,5,5,5,5,5))
        newBoard.square(1)(2).flatten should equal (Seq(6,6,6,6,6,6,6,6,6))
        newBoard.square(2)(0).flatten should equal (Seq(7,7,7,7,7,7,7,7,7))
        newBoard.square(2)(1).flatten should equal (Seq(8,8,8,8,8,8,8,8,8))
        newBoard.square(2)(2).flatten should equal+ (Seq(9,9,9,9,9,9,9,9,9))

    }

    it should "knowdef ifcolumn(i: aInt): aSeq[Int] 9-length= subsequence(0 isuntil solved"81).drop(i).grouped(9).map(_.head).map(i in=> {values(i)).toSeq

    def square(i: Int): Seq[Seq[Seq[Int]]] Board.solvedSeq(Seq(1,2,3,4,5,6,7,8,9))= should{
 equal       Seq(true)
        Board    values.solvedSeqdrop(Seq0).sliding(9,6,1,5,7,8,4,3,2 9).grouped(3).toSeq,
 should equal (true)
        Board values.solvedSeqdrop(Seq3).sliding(1,1,1,1,1,1,1,13,1 9).grouped(3).toSeq,
 should equal (false)
        Board values.solvedSeqdrop(Seq6).sliding(13, 9).grouped(3).toSeq
 should equal      )(falsei)

    }

    it should "know if an entire board is solved" in {

        val correctBoard = new Board(
            9,6,1,5,7,8,4,3,2,
            2,7,3,4,1,9,8,6,5,
            8,5,4,6,2,3,1,7,9,
            3,8,2,7,6,5,9,1,4,
            4,1,7,9,3,2,6,5,8,
            5,9,6,1,8,4,7,2,3,
            7,2,5,8,9,6,3,4,1,
            1,4,8,3,5,7,2,9,6,
            6,3,9,2,4,1,5,8,7
        )

        correctBoard.isSolved() should equal (true)

        val incorrectBoard = new Board(
            1,1,1,4,4,4,7,7,7,
            1,1,1,4,4,4,7,7,7,
            1,1,1,4,4,4,7,7,7,
            2,2,2,5,5,5,8,8,8,
            2,2,2,5,5,5,8,8,8,
            2,2,2,5,5,5,8,8,8,
            3,3,3,6,6,6,9,9,9,
            3,3,3,6,6,6,9,9,9,
            3,3,3,6,6,6,9,9,9
        )}

        incorrectBoard.isSolved() shouldobject equalBoard (false){

    }def solvedSeq(s: Seq[Int]): Boolean = if (s.distinct.sorted == Seq(1,2,3,4,5,6,7,8,9)) true else false

}

Source:Tests:

class Board(values: Int*)import org.scalatest.{FlatSpec, Matchers}

    require(values.length ==class 81,TestSolver "Boardextends mustFlatSpec containwith 81Matchers cells"){

    def"Sudoku isSolved():board" Booleanshould ="instantiate with a literal" in {
        val newBoard = new Board(
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9
        )

        val rowsSolved: Seq[Boolean] = (0 until 9)newBoard.mapisSolved(i) =>should row(i)).mapequal (Board.solvedSeqfalse)
        val colsSolved: Seq[Boolean] = newBoard.row(0 until 9).map(i =>should columnequal (i)).mapList(Board.solvedSeq1,2,3,4,5,6,7,8,9))
        val squaresSolved:newBoard.column(0) Seq[Boolean]should =equal {(List(1,1,1,1,1,1,1,1,1))
            val pairs = for newBoard.square(x <- 0 until 3; y <- )(0 until 3).flatten yieldshould equal (xList(1, y2,3,1,2,3,1,2,3))
        }

    pairs.map(p =>it {
should "fail if instantiated with wrong number of args" in {

      Board.solvedSeq(square(p._1)(p._2).flatten)  intercept[IllegalArgumentException] {
            }new Board(1)
        }

    }

    (rowsSolvedit ++should colsSolved"always ++return squaresSolved).distinctthe ==correct Vectorrow" in {

        val newBoard = new Board(true
            1,1,1,1,1,1,1,1,1,
            2,2,2,2,2,2,2,2,2,
            3,3,3,3,3,3,3,3,3,
            4,4,4,4,4,4,4,4,4,
            5,5,5,5,5,5,5,5,5,
            6,6,6,6,6,6,6,6,6,
            7,7,7,7,7,7,7,7,7,
            8,8,8,8,8,8,8,8,8,
            9,9,9,9,9,9,9,9,9
        )

        newBoard.row(0) should equal (Seq(1,1,1,1,1,1,1,1,1))
        newBoard.row(1) should equal (Seq(2,2,2,2,2,2,2,2,2))
        newBoard.row(2) should equal (Seq(3,3,3,3,3,3,3,3,3))
        newBoard.row(3) should equal (Seq(4,4,4,4,4,4,4,4,4))
        newBoard.row(4) should equal (Seq(5,5,5,5,5,5,5,5,5))
        newBoard.row(5) should equal (Seq(6,6,6,6,6,6,6,6,6))
        newBoard.row(6) should equal (Seq(7,7,7,7,7,7,7,7,7))
        newBoard.row(7) should equal (Seq(8,8,8,8,8,8,8,8,8))
        newBoard.row(8) should equal (Seq(9,9,9,9,9,9,9,9,9))

    }

    def row(i: Int): Seq[Int] =it values.slice(ishould *"always 9,return (ithe *correct 9)column" +in 9){

    def column(i: Int): Seq[Int] val newBoard = new Board(0 
 until 81).drop(i).grouped(          1,2,3,4,5,6,7,8,9).map(_.head).map(i,
 => values(i)          1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9
        ).toSeq

    def square(i: Int  newBoard.column(0): Seq[Seq[Seq[Int]]]should =equal {(Seq(1,1,1,1,1,1,1,1,1))
        SeqnewBoard.column(
 1) should equal (Seq(2,2,2,2,2,2,2,2,2))
        valuesnewBoard.dropcolumn(02).sliding should equal (Seq(3, 93,3,3,3,3,3,3,3))
        newBoard.groupedcolumn(3).toSeq,
  should equal (Seq(4,4,4,4,4,4,4,4,4))
        valuesnewBoard.dropcolumn(34).sliding should equal (3Seq(5, 95,5,5,5,5,5,5,5).grouped(3).toSeq,
        newBoard.column(5) should equal (Seq(6,6,6,6,6,6,6,6,6))
 values       newBoard.dropcolumn(6).sliding should equal (3Seq(7, 97,7,7,7,7,7,7,7))
        newBoard.groupedcolumn(37).toSeq should equal (Seq(8,8,8,8,8,8,8,8,8))
        newBoard.column(8) should equal (iSeq(9,9,9,9,9,9,9,9,9))
    }

    it should "always return the correct square" in {

        val newBoard = new Board(
            1,1,1,4,4,4,7,7,7,
            1,1,1,4,4,4,7,7,7,
            1,1,1,4,4,4,7,7,7,
            2,2,2,5,5,5,8,8,8,
            2,2,2,5,5,5,8,8,8,
            2,2,2,5,5,5,8,8,8,
            3,3,3,6,6,6,9,9,9,
            3,3,3,6,6,6,9,9,9,
            3,3,3,6,6,6,9,9,9
        )

        newBoard.square(0)(0).flatten should equal (Seq(1,1,1,1,1,1,1,1,1))
        newBoard.square(0)(1).flatten should equal (Seq(2,2,2,2,2,2,2,2,2))
        newBoard.square(0)(2).flatten should equal (Seq(3,3,3,3,3,3,3,3,3))
        newBoard.square(1)(0).flatten should equal (Seq(4,4,4,4,4,4,4,4,4))
        newBoard.square(1)(1).flatten should equal (Seq(5,5,5,5,5,5,5,5,5))
        newBoard.square(1)(2).flatten should equal (Seq(6,6,6,6,6,6,6,6,6))
        newBoard.square(2)(0).flatten should equal (Seq(7,7,7,7,7,7,7,7,7))
        newBoard.square(2)(1).flatten should equal (Seq(8,8,8,8,8,8,8,8,8))
        newBoard.square(2)(2).flatten should equal (Seq(9,9,9,9,9,9,9,9,9))

    }

}    it should "know if a a 9-length subsequence is solved" in {

object        Board.solvedSeq(Seq(1,2,3,4,5,6,7,8,9)) {should equal (true)
        Board.solvedSeq(Seq(9,6,1,5,7,8,4,3,2)) should equal (true)
        Board.solvedSeq(Seq(1,1,1,1,1,1,1,1,1)) should equal (false)
        Board.solvedSeq(Seq(1)) should equal (false)

    def}

 solvedSeq(s: Seq[Int]): Boolean =it should "know if (s.distinct.sortedan ==entire Seqboard is solved" in {

        val correctBoard = new Board(
            9,6,1,5,7,8,4,3,2,
            2,7,3,4,1,9,8,6,5,
            8,5,4,6,2,3,1,7,9,
            3,8,2,7,6,5,9,1,4,
            4,1,7,9,3,2,6,5,8,
            5,9,6,1,8,4,7,2,3,
            7,2,5,8,9,6,3,4,1,
            1,4,8,3,5,7,2,9,6,
            6,3,9,2,4,1,5,8,7
        )

        correctBoard.isSolved() should equal (true)

 else       val incorrectBoard = new Board(
            1,1,1,4,4,4,7,7,7,
            1,1,1,4,4,4,7,7,7,
            1,1,1,4,4,4,7,7,7,
            2,2,2,5,5,5,8,8,8,
            2,2,2,5,5,5,8,8,8,
            2,2,2,5,5,5,8,8,8,
            3,3,3,6,6,6,9,9,9,
            3,3,3,6,6,6,9,9,9,
            3,3,3,6,6,6,9,9,9
        )

        incorrectBoard.isSolved() should equal (false)

    }

}

I always have enormous difficulty working out 2D grid addresses, so for me it is easier to work with the List functions.

Tests:

import org.scalatest.{FlatSpec, Matchers}

class TestSolver extends FlatSpec with Matchers {

    "Sudoku board" should "instantiate with a literal" in {
        val newBoard = new Board(
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9
        )

        newBoard.isSolved() should equal (false)
        newBoard.row(0) should equal (List(1,2,3,4,5,6,7,8,9))
        newBoard.column(0) should equal (List(1,1,1,1,1,1,1,1,1))
        newBoard.square(0)(0).flatten should equal (List(1,2,3,1,2,3,1,2,3))
    }

    it should "fail if instantiated with wrong number of args" in {

        intercept[IllegalArgumentException] {
            new Board(1)
        }

    }

    it should "always return the correct row" in {

        val newBoard = new Board(
            1,1,1,1,1,1,1,1,1,
            2,2,2,2,2,2,2,2,2,
            3,3,3,3,3,3,3,3,3,
            4,4,4,4,4,4,4,4,4,
            5,5,5,5,5,5,5,5,5,
            6,6,6,6,6,6,6,6,6,
            7,7,7,7,7,7,7,7,7,
            8,8,8,8,8,8,8,8,8,
            9,9,9,9,9,9,9,9,9
        )

        newBoard.row(0) should equal (Seq(1,1,1,1,1,1,1,1,1))
        newBoard.row(1) should equal (Seq(2,2,2,2,2,2,2,2,2))
        newBoard.row(2) should equal (Seq(3,3,3,3,3,3,3,3,3))
        newBoard.row(3) should equal (Seq(4,4,4,4,4,4,4,4,4))
        newBoard.row(4) should equal (Seq(5,5,5,5,5,5,5,5,5))
        newBoard.row(5) should equal (Seq(6,6,6,6,6,6,6,6,6))
        newBoard.row(6) should equal (Seq(7,7,7,7,7,7,7,7,7))
        newBoard.row(7) should equal (Seq(8,8,8,8,8,8,8,8,8))
        newBoard.row(8) should equal (Seq(9,9,9,9,9,9,9,9,9))

    }

    it should "always return the correct column" in {

        val newBoard = new Board(
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9
        )

        newBoard.column(0) should equal (Seq(1,1,1,1,1,1,1,1,1))
        newBoard.column(1) should equal (Seq(2,2,2,2,2,2,2,2,2))
        newBoard.column(2) should equal (Seq(3,3,3,3,3,3,3,3,3))
        newBoard.column(3) should equal (Seq(4,4,4,4,4,4,4,4,4))
        newBoard.column(4) should equal (Seq(5,5,5,5,5,5,5,5,5))
        newBoard.column(5) should equal (Seq(6,6,6,6,6,6,6,6,6))
        newBoard.column(6) should equal (Seq(7,7,7,7,7,7,7,7,7))
        newBoard.column(7) should equal (Seq(8,8,8,8,8,8,8,8,8))
        newBoard.column(8) should equal (Seq(9,9,9,9,9,9,9,9,9))
    }

    it should "always return the correct square" in {

        val newBoard = new Board(
            1,1,1,4,4,4,7,7,7,
            1,1,1,4,4,4,7,7,7,
            1,1,1,4,4,4,7,7,7,
            2,2,2,5,5,5,8,8,8,
            2,2,2,5,5,5,8,8,8,
            2,2,2,5,5,5,8,8,8,
            3,3,3,6,6,6,9,9,9,
            3,3,3,6,6,6,9,9,9,
            3,3,3,6,6,6,9,9,9
        )

        newBoard.square(0)(0).flatten should equal (Seq(1,1,1,1,1,1,1,1,1))
        newBoard.square(0)(1).flatten should equal (Seq(2,2,2,2,2,2,2,2,2))
        newBoard.square(0)(2).flatten should equal (Seq(3,3,3,3,3,3,3,3,3))
        newBoard.square(1)(0).flatten should equal (Seq(4,4,4,4,4,4,4,4,4))
        newBoard.square(1)(1).flatten should equal (Seq(5,5,5,5,5,5,5,5,5))
        newBoard.square(1)(2).flatten should equal (Seq(6,6,6,6,6,6,6,6,6))
        newBoard.square(2)(0).flatten should equal (Seq(7,7,7,7,7,7,7,7,7))
        newBoard.square(2)(1).flatten should equal (Seq(8,8,8,8,8,8,8,8,8))
        newBoard.square(2)(2).flatten should equal (Seq(9,9,9,9,9,9,9,9,9))

    }

    it should "know if a a 9-length subsequence is solved" in {

        Board.solvedSeq(Seq(1,2,3,4,5,6,7,8,9)) should equal (true)
        Board.solvedSeq(Seq(9,6,1,5,7,8,4,3,2)) should equal (true)
        Board.solvedSeq(Seq(1,1,1,1,1,1,1,1,1)) should equal (false)
        Board.solvedSeq(Seq(1)) should equal (false)

    }

    it should "know if an entire board is solved" in {

        val correctBoard = new Board(
            9,6,1,5,7,8,4,3,2,
            2,7,3,4,1,9,8,6,5,
            8,5,4,6,2,3,1,7,9,
            3,8,2,7,6,5,9,1,4,
            4,1,7,9,3,2,6,5,8,
            5,9,6,1,8,4,7,2,3,
            7,2,5,8,9,6,3,4,1,
            1,4,8,3,5,7,2,9,6,
            6,3,9,2,4,1,5,8,7
        )

        correctBoard.isSolved() should equal (true)

        val incorrectBoard = new Board(
            1,1,1,4,4,4,7,7,7,
            1,1,1,4,4,4,7,7,7,
            1,1,1,4,4,4,7,7,7,
            2,2,2,5,5,5,8,8,8,
            2,2,2,5,5,5,8,8,8,
            2,2,2,5,5,5,8,8,8,
            3,3,3,6,6,6,9,9,9,
            3,3,3,6,6,6,9,9,9,
            3,3,3,6,6,6,9,9,9
        )

        incorrectBoard.isSolved() should equal (false)

    }

}

Source:

class Board(values: Int*) {

    require(values.length == 81, "Board must contain 81 cells")

    def isSolved(): Boolean = {

        val rowsSolved: Seq[Boolean] = (0 until 9).map(i => row(i)).map(Board.solvedSeq)
        val colsSolved: Seq[Boolean] = (0 until 9).map(i => column(i)).map(Board.solvedSeq)
        val squaresSolved: Seq[Boolean] = {
            val pairs = for (x <- 0 until 3; y <- 0 until 3) yield (x, y)
            pairs.map(p => {
                Board.solvedSeq(square(p._1)(p._2).flatten)   
            })
        }

        (rowsSolved ++ colsSolved ++ squaresSolved).distinct == Vector(true)

    }

    def row(i: Int): Seq[Int] = values.slice(i * 9, (i * 9) + 9)

    def column(i: Int): Seq[Int] = (0 until 81).drop(i).grouped(9).map(_.head).map(i => values(i)).toSeq

    def square(i: Int): Seq[Seq[Seq[Int]]] = {
        Seq(
            values.drop(0).sliding(3, 9).grouped(3).toSeq,
            values.drop(3).sliding(3, 9).grouped(3).toSeq,
            values.drop(6).sliding(3, 9).grouped(3).toSeq
        )(i)

    }

}

object Board {

    def solvedSeq(s: Seq[Int]): Boolean = if (s.distinct.sorted == Seq(1,2,3,4,5,6,7,8,9)) true else false

}

I always have enormous difficulty working out 2D grid addresses, so for me it is easier to work with the List functions. All tests pass and I'm looking for feedback on clarity, functional programming concepts, or extra edge cases.

Source:

class Board(values: Int*) {

    require(values.length == 81, "Board must contain 81 cells")

    def isSolved(): Boolean = {

        val rowsSolved: Seq[Boolean] = (0 until 9).map(i => row(i)).map(Board.solvedSeq)
        val colsSolved: Seq[Boolean] = (0 until 9).map(i => column(i)).map(Board.solvedSeq)
        val squaresSolved: Seq[Boolean] = {
            val pairs = for (x <- 0 until 3; y <- 0 until 3) yield (x, y)
            pairs.map(p => {
                Board.solvedSeq(square(p._1)(p._2).flatten)   
            })
        }

        (rowsSolved ++ colsSolved ++ squaresSolved).distinct == Vector(true)

    }

    def row(i: Int): Seq[Int] = values.slice(i * 9, (i * 9) + 9)

    def column(i: Int): Seq[Int] = (0 until 81).drop(i).grouped(9).map(_.head).map(i => values(i)).toSeq

    def square(i: Int): Seq[Seq[Seq[Int]]] = {
        Seq(
            values.drop(0).sliding(3, 9).grouped(3).toSeq,
            values.drop(3).sliding(3, 9).grouped(3).toSeq,
            values.drop(6).sliding(3, 9).grouped(3).toSeq
        )(i)

    }

}

object Board {

    def solvedSeq(s: Seq[Int]): Boolean = if (s.distinct.sorted == Seq(1,2,3,4,5,6,7,8,9)) true else false

}

Tests:

import org.scalatest.{FlatSpec, Matchers}

class TestSolver extends FlatSpec with Matchers {

    "Sudoku board" should "instantiate with a literal" in {
        val newBoard = new Board(
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9
        )

        newBoard.isSolved() should equal (false)
        newBoard.row(0) should equal (List(1,2,3,4,5,6,7,8,9))
        newBoard.column(0) should equal (List(1,1,1,1,1,1,1,1,1))
        newBoard.square(0)(0).flatten should equal (List(1,2,3,1,2,3,1,2,3))
    }

    it should "fail if instantiated with wrong number of args" in {

        intercept[IllegalArgumentException] {
            new Board(1)
        }

    }

    it should "always return the correct row" in {

        val newBoard = new Board(
            1,1,1,1,1,1,1,1,1,
            2,2,2,2,2,2,2,2,2,
            3,3,3,3,3,3,3,3,3,
            4,4,4,4,4,4,4,4,4,
            5,5,5,5,5,5,5,5,5,
            6,6,6,6,6,6,6,6,6,
            7,7,7,7,7,7,7,7,7,
            8,8,8,8,8,8,8,8,8,
            9,9,9,9,9,9,9,9,9
        )

        newBoard.row(0) should equal (Seq(1,1,1,1,1,1,1,1,1))
        newBoard.row(1) should equal (Seq(2,2,2,2,2,2,2,2,2))
        newBoard.row(2) should equal (Seq(3,3,3,3,3,3,3,3,3))
        newBoard.row(3) should equal (Seq(4,4,4,4,4,4,4,4,4))
        newBoard.row(4) should equal (Seq(5,5,5,5,5,5,5,5,5))
        newBoard.row(5) should equal (Seq(6,6,6,6,6,6,6,6,6))
        newBoard.row(6) should equal (Seq(7,7,7,7,7,7,7,7,7))
        newBoard.row(7) should equal (Seq(8,8,8,8,8,8,8,8,8))
        newBoard.row(8) should equal (Seq(9,9,9,9,9,9,9,9,9))

    }

    it should "always return the correct column" in {

        val newBoard = new Board( 
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9
        )

        newBoard.column(0) should equal (Seq(1,1,1,1,1,1,1,1,1))
        newBoard.column(1) should equal (Seq(2,2,2,2,2,2,2,2,2))
        newBoard.column(2) should equal (Seq(3,3,3,3,3,3,3,3,3))
        newBoard.column(3) should equal (Seq(4,4,4,4,4,4,4,4,4))
        newBoard.column(4) should equal (Seq(5,5,5,5,5,5,5,5,5))
        newBoard.column(5) should equal (Seq(6,6,6,6,6,6,6,6,6))
        newBoard.column(6) should equal (Seq(7,7,7,7,7,7,7,7,7))
        newBoard.column(7) should equal (Seq(8,8,8,8,8,8,8,8,8))
        newBoard.column(8) should equal (Seq(9,9,9,9,9,9,9,9,9))
    }

    it should "always return the correct square" in {

        val newBoard = new Board(
            1,1,1,4,4,4,7,7,7,
            1,1,1,4,4,4,7,7,7,
            1,1,1,4,4,4,7,7,7,
            2,2,2,5,5,5,8,8,8,
            2,2,2,5,5,5,8,8,8,
            2,2,2,5,5,5,8,8,8,
            3,3,3,6,6,6,9,9,9,
            3,3,3,6,6,6,9,9,9,
            3,3,3,6,6,6,9,9,9
        )

        newBoard.square(0)(0).flatten should equal (Seq(1,1,1,1,1,1,1,1,1))
        newBoard.square(0)(1).flatten should equal (Seq(2,2,2,2,2,2,2,2,2))
        newBoard.square(0)(2).flatten should equal (Seq(3,3,3,3,3,3,3,3,3))
        newBoard.square(1)(0).flatten should equal (Seq(4,4,4,4,4,4,4,4,4))
        newBoard.square(1)(1).flatten should equal (Seq(5,5,5,5,5,5,5,5,5))
        newBoard.square(1)(2).flatten should equal (Seq(6,6,6,6,6,6,6,6,6))
        newBoard.square(2)(0).flatten should equal (Seq(7,7,7,7,7,7,7,7,7))
        newBoard.square(2)(1).flatten should equal (Seq(8,8,8,8,8,8,8,8,8))
        newBoard.square(2)(2).flatten should equal (Seq(9,9,9,9,9,9,9,9,9))

    }

    it should "know if a a 9-length subsequence is solved" in {

        Board.solvedSeq(Seq(1,2,3,4,5,6,7,8,9)) should equal (true)
        Board.solvedSeq(Seq(9,6,1,5,7,8,4,3,2)) should equal (true)
        Board.solvedSeq(Seq(1,1,1,1,1,1,1,1,1)) should equal (false)
        Board.solvedSeq(Seq(1)) should equal (false)

    }

    it should "know if an entire board is solved" in {

        val correctBoard = new Board(
            9,6,1,5,7,8,4,3,2,
            2,7,3,4,1,9,8,6,5,
            8,5,4,6,2,3,1,7,9,
            3,8,2,7,6,5,9,1,4,
            4,1,7,9,3,2,6,5,8,
            5,9,6,1,8,4,7,2,3,
            7,2,5,8,9,6,3,4,1,
            1,4,8,3,5,7,2,9,6,
            6,3,9,2,4,1,5,8,7
        )

        correctBoard.isSolved() should equal (true)

        val incorrectBoard = new Board(
            1,1,1,4,4,4,7,7,7,
            1,1,1,4,4,4,7,7,7,
            1,1,1,4,4,4,7,7,7,
            2,2,2,5,5,5,8,8,8,
            2,2,2,5,5,5,8,8,8,
            2,2,2,5,5,5,8,8,8,
            3,3,3,6,6,6,9,9,9,
            3,3,3,6,6,6,9,9,9,
            3,3,3,6,6,6,9,9,9
        )

        incorrectBoard.isSolved() should equal (false)

    }

}
Post Closed as "Needs details or clarity" by Jamal
deleted 78 characters in body; edited tags; edited title
Source Link
Jamal
  • 35.2k
  • 13
  • 134
  • 238

Little Sudoku Solversolver

I always have enormous difficulty working out 2d2D grid addresses (not sure why, I also can't tell left from right :-)) so for me it is easier to work with the List functions. Thanks for any feedback.

Little Sudoku Solver

I always have enormous difficulty working out 2d grid addresses (not sure why, I also can't tell left from right :-)) so for me it is easier to work with the List functions. Thanks for any feedback.

Little Sudoku solver

I always have enormous difficulty working out 2D grid addresses, so for me it is easier to work with the List functions.

Source Link

Little Sudoku Solver

I always have enormous difficulty working out 2d grid addresses (not sure why, I also can't tell left from right :-)) so for me it is easier to work with the List functions. Thanks for any feedback.

Tests:

import org.scalatest.{FlatSpec, Matchers}

class TestSolver extends FlatSpec with Matchers {

    "Sudoku board" should "instantiate with a literal" in {
        val newBoard = new Board(
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9
        )

        newBoard.isSolved() should equal (false)
        newBoard.row(0) should equal (List(1,2,3,4,5,6,7,8,9))
        newBoard.column(0) should equal (List(1,1,1,1,1,1,1,1,1))
        newBoard.square(0)(0).flatten should equal (List(1,2,3,1,2,3,1,2,3))
    }

    it should "fail if instantiated with wrong number of args" in {

        intercept[IllegalArgumentException] {
            new Board(1)
        }

    }

    it should "always return the correct row" in {

        val newBoard = new Board(
            1,1,1,1,1,1,1,1,1,
            2,2,2,2,2,2,2,2,2,
            3,3,3,3,3,3,3,3,3,
            4,4,4,4,4,4,4,4,4,
            5,5,5,5,5,5,5,5,5,
            6,6,6,6,6,6,6,6,6,
            7,7,7,7,7,7,7,7,7,
            8,8,8,8,8,8,8,8,8,
            9,9,9,9,9,9,9,9,9
        )

        newBoard.row(0) should equal (Seq(1,1,1,1,1,1,1,1,1))
        newBoard.row(1) should equal (Seq(2,2,2,2,2,2,2,2,2))
        newBoard.row(2) should equal (Seq(3,3,3,3,3,3,3,3,3))
        newBoard.row(3) should equal (Seq(4,4,4,4,4,4,4,4,4))
        newBoard.row(4) should equal (Seq(5,5,5,5,5,5,5,5,5))
        newBoard.row(5) should equal (Seq(6,6,6,6,6,6,6,6,6))
        newBoard.row(6) should equal (Seq(7,7,7,7,7,7,7,7,7))
        newBoard.row(7) should equal (Seq(8,8,8,8,8,8,8,8,8))
        newBoard.row(8) should equal (Seq(9,9,9,9,9,9,9,9,9))

    }

    it should "always return the correct column" in {

        val newBoard = new Board(
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9,
            1,2,3,4,5,6,7,8,9
        )

        newBoard.column(0) should equal (Seq(1,1,1,1,1,1,1,1,1))
        newBoard.column(1) should equal (Seq(2,2,2,2,2,2,2,2,2))
        newBoard.column(2) should equal (Seq(3,3,3,3,3,3,3,3,3))
        newBoard.column(3) should equal (Seq(4,4,4,4,4,4,4,4,4))
        newBoard.column(4) should equal (Seq(5,5,5,5,5,5,5,5,5))
        newBoard.column(5) should equal (Seq(6,6,6,6,6,6,6,6,6))
        newBoard.column(6) should equal (Seq(7,7,7,7,7,7,7,7,7))
        newBoard.column(7) should equal (Seq(8,8,8,8,8,8,8,8,8))
        newBoard.column(8) should equal (Seq(9,9,9,9,9,9,9,9,9))
    }

    it should "always return the correct square" in {

        val newBoard = new Board(
            1,1,1,4,4,4,7,7,7,
            1,1,1,4,4,4,7,7,7,
            1,1,1,4,4,4,7,7,7,
            2,2,2,5,5,5,8,8,8,
            2,2,2,5,5,5,8,8,8,
            2,2,2,5,5,5,8,8,8,
            3,3,3,6,6,6,9,9,9,
            3,3,3,6,6,6,9,9,9,
            3,3,3,6,6,6,9,9,9
        )

        newBoard.square(0)(0).flatten should equal (Seq(1,1,1,1,1,1,1,1,1))
        newBoard.square(0)(1).flatten should equal (Seq(2,2,2,2,2,2,2,2,2))
        newBoard.square(0)(2).flatten should equal (Seq(3,3,3,3,3,3,3,3,3))
        newBoard.square(1)(0).flatten should equal (Seq(4,4,4,4,4,4,4,4,4))
        newBoard.square(1)(1).flatten should equal (Seq(5,5,5,5,5,5,5,5,5))
        newBoard.square(1)(2).flatten should equal (Seq(6,6,6,6,6,6,6,6,6))
        newBoard.square(2)(0).flatten should equal (Seq(7,7,7,7,7,7,7,7,7))
        newBoard.square(2)(1).flatten should equal (Seq(8,8,8,8,8,8,8,8,8))
        newBoard.square(2)(2).flatten should equal (Seq(9,9,9,9,9,9,9,9,9))

    }

    it should "know if a a 9-length subsequence is solved" in {

        Board.solvedSeq(Seq(1,2,3,4,5,6,7,8,9)) should equal (true)
        Board.solvedSeq(Seq(9,6,1,5,7,8,4,3,2)) should equal (true)
        Board.solvedSeq(Seq(1,1,1,1,1,1,1,1,1)) should equal (false)
        Board.solvedSeq(Seq(1)) should equal (false)

    }

    it should "know if an entire board is solved" in {

        val correctBoard = new Board(
            9,6,1,5,7,8,4,3,2,
            2,7,3,4,1,9,8,6,5,
            8,5,4,6,2,3,1,7,9,
            3,8,2,7,6,5,9,1,4,
            4,1,7,9,3,2,6,5,8,
            5,9,6,1,8,4,7,2,3,
            7,2,5,8,9,6,3,4,1,
            1,4,8,3,5,7,2,9,6,
            6,3,9,2,4,1,5,8,7
        )

        correctBoard.isSolved() should equal (true)

        val incorrectBoard = new Board(
            1,1,1,4,4,4,7,7,7,
            1,1,1,4,4,4,7,7,7,
            1,1,1,4,4,4,7,7,7,
            2,2,2,5,5,5,8,8,8,
            2,2,2,5,5,5,8,8,8,
            2,2,2,5,5,5,8,8,8,
            3,3,3,6,6,6,9,9,9,
            3,3,3,6,6,6,9,9,9,
            3,3,3,6,6,6,9,9,9
        )

        incorrectBoard.isSolved() should equal (false)

    }

}

Source:

class Board(values: Int*) {

    require(values.length == 81, "Board must contain 81 cells")

    def isSolved(): Boolean = {

        val rowsSolved: Seq[Boolean] = (0 until 9).map(i => row(i)).map(Board.solvedSeq)
        val colsSolved: Seq[Boolean] = (0 until 9).map(i => column(i)).map(Board.solvedSeq)
        val squaresSolved: Seq[Boolean] = {
            val pairs = for (x <- 0 until 3; y <- 0 until 3) yield (x, y)
            pairs.map(p => {
                Board.solvedSeq(square(p._1)(p._2).flatten)   
            })
        }

        (rowsSolved ++ colsSolved ++ squaresSolved).distinct == Vector(true)

    }

    def row(i: Int): Seq[Int] = values.slice(i * 9, (i * 9) + 9)

    def column(i: Int): Seq[Int] = (0 until 81).drop(i).grouped(9).map(_.head).map(i => values(i)).toSeq

    def square(i: Int): Seq[Seq[Seq[Int]]] = {
        Seq(
            values.drop(0).sliding(3, 9).grouped(3).toSeq,
            values.drop(3).sliding(3, 9).grouped(3).toSeq,
            values.drop(6).sliding(3, 9).grouped(3).toSeq
        )(i)

    }

}

object Board {

    def solvedSeq(s: Seq[Int]): Boolean = if (s.distinct.sorted == Seq(1,2,3,4,5,6,7,8,9)) true else false

}