2017-04-06 8 views
0

私はScalaを学んでいます(関数型プログラミングの新人です)。 私はスードクチェッカーを作成しました(後で、あなたは実際にスードクで数字を設定できるゲーム、そしておそらく自動スドクソルバーです)。Scalaでのsudokuの解読

行と列が正しいかどうかを確認することは、機能的な方法でうまく機能します。

3x3の正方形が正しいかどうかをチェックしても、かなり醜い方法を書いています(下のコードを参照)。

どうすればこの簡単でより多くのScala'ishを解決できるかについてのヒントを教えてください。

私は、.slice(from、until)、.splitAt(until)、.sliding(size、step)のメソッドを見つけて、再び 'transpose'を使って何かをしようとしました。私は 'これを行うには働く(より)機能的な方法を思い付くことはできませんが。ここで

class Sudoku(){ 
    val sudoku = 
    Array(
     Array(0, 5, 0, 3, 0, 9, 0, 2, 6), 
     Array(3, 8, 9, 4, 2, 0, 1, 5, 7), 
     Array(4, 0, 6, 1, 0, 0, 0, 8, 9), 
     Array(0, 1, 3, 7, 9, 8, 0, 0, 4), 
     Array(0, 0, 8, 0, 0, 0, 5, 0, 0), 
     Array(0, 6, 0, 0, 0, 3, 0, 0, 0), 
     Array(0, 0, 1, 9, 3, 0, 0, 4, 0), 
     Array(9, 3, 5, 6, 4, 0, 8, 0, 1), 
     Array(0, 0, 2, 8, 7, 0, 0, 0, 5) 
) 

    def checkSudoku(): Unit ={ 
    println(check(sudoku)) 
    } 

    private def check(sudoku: Array[Array[Int]]): Boolean = checkRows(sudoku) && checkCols(sudoku) && checkSquars(sudoku) 
    private def checkCols(sudoku: Array[Array[Int]]) = checkRows(sudoku.transpose) 
    private def checkRows(sudoku: Array[Array[Int]]): Boolean = sudoku.forall(row => checkRow(row)) 
    private def checkRow(row: Array[Int]): Boolean = row.distinct.length == row.length 


    private def checkSquars(sudoku: Array[Array[Int]]): Boolean ={ 
    val squared : Array[Array[Int]] = Array.ofDim[Int](1,3) 

    for(i <- 0 to (sudoku.length-1)/3) { 
     for(o <- 0 to (sudoku(i).length-1)/3) { 
     squared((i*3)+o) = sudoku(0+(i*3)).slice(0+(o*3), 3+(o*3)) ++ sudoku(1+(i*3)).slice(0+(o*3), 3+(o*3)) ++ sudoku(2+(i*3)).slice(0+(o*3), 3+(o*3)) 
     } 
    } 
    squared.forall(row => checkRow(row)) 
    } 
} 

val sudoku = new Sudoku() 
sudoku.checkSudoku(); 
+0

checkRowメソッドはどこですか? – nmat

+0

以下のcheckRows()メソッド プライベートdef checkRow(row:Array [Int]):Boolean = row.distinct.length == row.length – Kevin

答えて

1

はcheckSquares方法を行うには(少しbrainfucky)の方法である:

val rowBlocks = sudoku.grouped(3).toArray 
def splitRow(row: Array[Int]) = row.grouped(3).toArray 

val squares = rowBlocks.map(block => block.map(splitRow).transpose) 

あなたはsquaresは、数独の正方形の3×3アレイであることを自分自身を納得させる必要があります。今度は条件を確認するだけです:

squares.forall(_.forall(sq => sq.flatten.distinct.length == sq.flatten.length)) 
1

ここでは、すべての四角形を線で表示する方法を示します。私はそれを読みやすくしてみました:あなたはあなたの方法でやっているよう

val squareSize = 3 
    val boardSize = sudoku.length 

    val squareLines = for { 
    rowStart <- List.range(0, boardSize, squareSize) 
    colStart <- List.range(0, boardSize, squareSize) 
    } yield { 
    List.range(0, squareSize).flatMap { 
     i => 
     sudoku(rowStart + i).slice(colStart, colStart + squareSize) 
    } 
    } 

あなたはその後、checkRowsquareLinesを確認することができます。

rowStartcolStartペアもList.rangecombinations(2)を使用して生成することができますが、私はそれがこのような場合のためにあまりにも冗長になり考え出し。

0

私はリスト/アレイを使ってパズルを管理していましたが、ずっと後で、マップを使う方が良いとわかりました。

次に、Array [Array]の代わりに[Set [Int]]を使用して、Setを使用してグループ内の重複を削除します。

私は競合をチェックするために関数conflict(...)を含んでいました。参照のために使用することができます。私は同じ目的を達成するために他の方法があるが、その目的を果たしていたので、私は変更を続けています(つまり、私はこの機能をもう使用していません)。私はあなたが助けを必要とする場合は、アイデアを得ることができ、私に叫びを与えることを願っています。

val digits = ('1' to '9').mkString 
val alphas = ('A' to 'I').mkString 

def cross(rows: String, cols: String) = for { 
    row <- rows 
    col <- cols 
} yield {"" + row + col} 

val verticals = digits.map(d => cross(alphas, d.toString)) 

val horizontals = alphas.map(a => cross(a.toString, digits)) 

val blocks = for { 
    rowBlk <- alphas.grouped(3) 
    colBlk <- digits.grouped(3) 
} yield (cross(rowBlk, colBlk)) 

val all = horizontals ++ verticals ++ blocks 

def everyone = cross(alphas, digits).foldLeft(Map.empty[String, Set[Set[Int]]])((m,a) => m + (a -> (all.filter(_.contains(a)).map(_.toSet).toSet))) 

def conflict(cell: String, solution: Map[String, Set[Int]]) = 
    if (everyone(cell) 
    .map(cells => cells.toList.foldLeft(List.empty[Int])((chars, c) => 
     if (solution(c).size > 1) chars else chars ++ solution(c).toList)) 
     .forall(xs => xs.size == xs.distinct.size)) solution else Map.empty