Improve test and data structure
This commit is contained in:
@@ -5,6 +5,9 @@ class Grid(
|
||||
val rows: List<GameRow<*>>
|
||||
) : List<GameRow<ItemClass<*>>> by rows as List<GameRow<ItemClass<*>>> {
|
||||
|
||||
val cells: List<GameCell<*>>
|
||||
get() = rows.flatten() as List<GameCell<*>>
|
||||
|
||||
fun <C : ItemClass<C>> 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<ItemClass<*>>) -> Boolean): Boolean {
|
||||
return flatMap { it }.any(predicate)
|
||||
}
|
||||
|
||||
fun allCells(predicate: (GameCell<ItemClass<*>>) -> Boolean): Boolean {
|
||||
return flatMap { it }.all(predicate)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return joinToString("\n") { row ->
|
||||
row.joinToString("") { it.selection?.symbol ?: " " }
|
||||
|
||||
@@ -107,8 +107,10 @@ class TripletClue<A : ItemClass<A>, B : ItemClass<B>, C : ItemClass<C>>(
|
||||
ia + 1 -> {
|
||||
return if (ic != -1) {
|
||||
ic != ia + 2
|
||||
} else {
|
||||
} else if (ia + 2 < grid.size) {
|
||||
!rowC[ia + 2].mayBe(c)
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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<Clue>::size).toBeGreaterThan(5)
|
||||
feature(List<Clue>::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)
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user