Last active
April 18, 2019 08:13
-
-
Save warmuuh/39f3aeba3e371b9f0c3a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package scala.dsl | |
sealed class Level(val emptyCount: Int) | |
case object Full extends Level(-1); | |
case object Easy extends Level(30); | |
case object Medium extends Level(50); | |
case object Hard extends Level(70); | |
object Sudoku { | |
def generate(level: Level) = { | |
val container = generateSolution().get; | |
removeRandomFields(level.emptyCount, container); | |
container | |
} | |
def generateSolution(y: Int = 0, x: Int = 0, c: SudokuContainer = new SudokuContainer()): Option[SudokuContainer] = { | |
if (y == 9) return Some(c); | |
for (value <- util.Random.shuffle(1 to 9)) { | |
val nc = c.modify(x, y, CellValue(value)) | |
if (nc.validate()) { | |
val (ny, nx) = (y + ((x + 1) / 9), (x + 1) % 9) | |
generateSolution(ny, nx, nc) match { | |
case None => | |
case x @ _ => return x | |
} | |
} | |
} | |
return None; | |
} | |
def removeRandomFields(count: Int, c: SudokuContainer) = { | |
for (i <- 0 to count) { | |
val (y, x) = (util.Random.nextInt(9), util.Random.nextInt(9)) | |
c.matrix(y)(x) = EmptyCell | |
} | |
} | |
//DSL stuff: | |
def apply(e: SudokuEntry*) = { | |
val cells = e.filter { _.curRow.length == 9 } | |
.map(_.curRow) | |
new SudokuContainer(Array.tabulate(9, 9)((x, y) => cells(x)(y))) | |
} | |
implicit def intToSudoku(i: Int): SudokuEntry = new SudokuEntry(CellValue(i)) | |
val ● = new SudokuEntry(EmptyCell) | |
val ----------|-----------|---------- = new SudokuEntry(EmptyCell) | |
} | |
sealed trait Cell; | |
case class CellValue(val i: Int) extends Cell; | |
case object EmptyCell extends Cell; | |
class SudokuContainer(val matrix: Array[Array[Cell]] = Array.fill[Cell](9,9)(EmptyCell)) { | |
def validate(): Boolean = { | |
def containsDuplicatesInRows = (m: Array[Array[Cell]]) => { | |
m.map { row => row.filterNot(_ == EmptyCell).groupBy(identity).collect { case (x, ys) if ys.size > 1 => true } }.filter(_.size > 0).size > 0 | |
} | |
lazy val duplicateRows = containsDuplicatesInRows(matrix) | |
lazy val duplicateCols = containsDuplicatesInRows(matrix.transpose) | |
lazy val cells = matrix.flatMap(_.grouped(3)).grouped(3).toArray.transpose.map(_.grouped(3).toArray).flatten.map(_.flatten) | |
lazy val duplicateCells = containsDuplicatesInRows(cells) | |
!duplicateRows && !duplicateCols && !duplicateCells; | |
} | |
def modify(x: Int, y: Int, nv: Cell) = { | |
val newMatrix = matrix map { _.clone } | |
newMatrix(y)(x) = nv | |
new SudokuContainer(newMatrix) | |
} | |
def complete(): Boolean = { | |
val elementCount: Int = matrix.map({ row => row filterNot { _ == EmptyCell } length }).foldLeft(0)(_ + _); | |
elementCount == 81 && validate() | |
} | |
override def toString() = { | |
matrix.map({ r => | |
r.map( _ match { | |
case EmptyCell => "●" | |
case CellValue(v) => v.toString() | |
} | |
).grouped(3).map({ block: Array[String] => block.mkString(" ∙ ") }).mkString(" | ") | |
}).grouped(3).map({ block: Array[String] => block.mkString(",\n") }) | |
.mkString(",\n----------|-----------|----------,\n") | |
} | |
} | |
class SudokuEntry(val v: Cell) { | |
var curRow: List[Cell] = List(v) | |
def ∙(o: SudokuEntry) = { | |
curRow = curRow ++ o.curRow | |
this; | |
} | |
def |(o: SudokuEntry) = { | |
curRow = curRow ++ o.curRow | |
this; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package scala.dsl | |
object Test extends App { | |
import Sudoku._; | |
val sudoku = Sudoku( | |
1 ∙ 2 ∙ 3 | 4 ∙ ● ∙ ● | 7 ∙ 8 ∙ 9, | |
4 ∙ 5 ∙ 6 | 7 ∙ 8 ∙ 9 | 1 ∙ 2 ∙ 3, | |
7 ∙ 8 ∙ 9 | 1 ∙ 2 ∙ 3 | 4 ∙ 5 ∙ 6, | |
----------|-----------|----------, | |
2 ∙ 3 ∙ 4 | 5 ∙ 6 ∙ 7 | 8 ∙ 9 ∙ 1, | |
5 ∙ 6 ∙ 7 | 8 ∙ 9 ∙ 1 | 2 ∙ 3 ∙ 4, | |
8 ∙ 9 ∙ 1 | 2 ∙ 3 ∙ 4 | 5 ∙ 6 ∙ 7, | |
----------|-----------|----------, | |
3 ∙ 4 ∙ 5 | 6 ∙ 7 ∙ 8 | 9 ∙ 1 ∙ 2, | |
6 ∙ 7 ∙ 8 | 9 ∙ 1 ∙ 2 | 3 ∙ 4 ∙ 5, | |
9 ∙ 1 ∙ 2 | 3 ∙ 4 ∙ 5 | 6 ∙ 7 ∙ 8) | |
println("manual sudoku:") | |
println(sudoku) | |
println(s"is valid: ${sudoku.validate()}") | |
println(s"is complete: ${sudoku.complete()}") | |
val gsudoku = Sudoku.generate(Full) | |
println("generated sudoku:") | |
println(gsudoku) | |
println(s"is valid: ${gsudoku.validate()}") | |
println(s"is complete: ${gsudoku.complete()}") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment