diff --git a/domain/src/main/kotlin/ch/dissem/yaep/domain/Grid.kt b/domain/src/main/kotlin/ch/dissem/yaep/domain/Grid.kt index 1406973..c59287c 100644 --- a/domain/src/main/kotlin/ch/dissem/yaep/domain/Grid.kt +++ b/domain/src/main/kotlin/ch/dissem/yaep/domain/Grid.kt @@ -5,6 +5,9 @@ class Grid( val rows: List> ) : List>> by rows as List>> { + val cells: List> + get() = rows.flatten() as List> + fun > indexOf(element: C): Int { return this[element.companion] .indexOfFirst { it.selection?.itemType == element } @@ -19,14 +22,6 @@ class Grid( return this[item.itemType.companion].first { it.selection == item } } - fun anyCell(predicate: (GameCell>) -> Boolean): Boolean { - return flatMap { it }.any(predicate) - } - - fun allCells(predicate: (GameCell>) -> Boolean): Boolean { - return flatMap { it }.all(predicate) - } - override fun toString(): String { return joinToString("\n") { row -> row.joinToString("") { it.selection?.symbol ?: " " } diff --git a/domain/src/main/kotlin/ch/dissem/yaep/domain/clues.kt b/domain/src/main/kotlin/ch/dissem/yaep/domain/clues.kt index 35d8202..5b7ce01 100644 --- a/domain/src/main/kotlin/ch/dissem/yaep/domain/clues.kt +++ b/domain/src/main/kotlin/ch/dissem/yaep/domain/clues.kt @@ -107,8 +107,10 @@ class TripletClue, B : ItemClass, C : ItemClass>( ia + 1 -> { return if (ic != -1) { ic != ia + 2 - } else { + } else if (ia + 2 < grid.size) { !rowC[ia + 2].mayBe(c) + } else { + true } } diff --git a/domain/src/main/kotlin/ch/dissem/yaep/domain/generator.kt b/domain/src/main/kotlin/ch/dissem/yaep/domain/generator.kt index d7f7a84..ba7b6ef 100644 --- a/domain/src/main/kotlin/ch/dissem/yaep/domain/generator.kt +++ b/domain/src/main/kotlin/ch/dissem/yaep/domain/generator.kt @@ -62,10 +62,10 @@ internal fun solve( } while (removedOptions) // If any cell has no items left, the puzzle has no solution. - if (grid.anyCell { cell -> cell.options.isEmpty() }) return NO_SOLUTION + if (grid.cells.any { cell -> cell.options.isEmpty() }) return NO_SOLUTION // If all cells have exactly one item left, the puzzle is solved. - if (grid.allCells { it.selection != null }) return SOLVABLE + if (grid.cells.all { it.selection != null }) return SOLVABLE // If there are still cells with multiple items, pick one and try each item in turn, then go back to step 2. for (i in 0 until grid.size) { diff --git a/domain/src/test/kotlin/ch/dissem/yaep/domain/GameTest.kt b/domain/src/test/kotlin/ch/dissem/yaep/domain/GameTest.kt index fd4840d..6488806 100644 --- a/domain/src/test/kotlin/ch/dissem/yaep/domain/GameTest.kt +++ b/domain/src/test/kotlin/ch/dissem/yaep/domain/GameTest.kt @@ -9,24 +9,35 @@ import ch.dissem.yaep.domain.Nationality.UKRAINE import ch.dissem.yaep.domain.Profession.ASTRONAUT import ch.dissem.yaep.domain.Profession.FARMER import ch.dissem.yaep.domain.Profession.SOFTWARE_DEV +import ch.dissem.yaep.domain.PuzzleSolution.SOLVABLE import ch.tutteli.atrium.api.fluent.en_GB.feature +import ch.tutteli.atrium.api.fluent.en_GB.toBeGreaterThan import ch.tutteli.atrium.api.fluent.en_GB.toBeLessThan import ch.tutteli.atrium.api.fluent.en_GB.toEqual import ch.tutteli.atrium.api.verbs.expect import kotlin.test.Test +import kotlin.time.Duration.Companion.seconds +import kotlin.time.measureTime class GameTest { @Test fun `ensure generated game is valid`() { - val game = generateGame() + val game: Game + val time = measureTime { + game = generateGame() + } expect(game) { feature(Game::areCategoriesValid).toEqual(true) feature(Game::areRulesViolated).toEqual(false) feature(Game::clues) { + feature(List::size).toBeGreaterThan(5) feature(List::size).toBeLessThan(30) } } + println("Clues: ${game.clues.size}") + expect(solve(game.grid, game.clues)).toEqual(SOLVABLE) + expect(time).toBeLessThan(1.seconds) } @Test @@ -73,7 +84,7 @@ class GameTest { ) ) - expect(solve(game.grid, game.clues)).toEqual(PuzzleSolution.SOLVABLE) + expect(solve(game.grid, game.clues)).toEqual(SOLVABLE) } } \ No newline at end of file