Improve test and data structure

This commit is contained in:
2024-07-14 07:46:32 +02:00
parent 7ad0b69933
commit fbf6e466c7
4 changed files with 21 additions and 13 deletions

View File

@@ -5,6 +5,9 @@ class Grid(
val rows: List<GameRow<*>> val rows: List<GameRow<*>>
) : List<GameRow<ItemClass<*>>> by rows as List<GameRow<ItemClass<*>>> { ) : 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 { fun <C : ItemClass<C>> indexOf(element: C): Int {
return this[element.companion] return this[element.companion]
.indexOfFirst { it.selection?.itemType == element } .indexOfFirst { it.selection?.itemType == element }
@@ -19,14 +22,6 @@ class Grid(
return this[item.itemType.companion].first { it.selection == item } 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 { override fun toString(): String {
return joinToString("\n") { row -> return joinToString("\n") { row ->
row.joinToString("") { it.selection?.symbol ?: " " } row.joinToString("") { it.selection?.symbol ?: " " }

View File

@@ -107,8 +107,10 @@ class TripletClue<A : ItemClass<A>, B : ItemClass<B>, C : ItemClass<C>>(
ia + 1 -> { ia + 1 -> {
return if (ic != -1) { return if (ic != -1) {
ic != ia + 2 ic != ia + 2
} else { } else if (ia + 2 < grid.size) {
!rowC[ia + 2].mayBe(c) !rowC[ia + 2].mayBe(c)
} else {
true
} }
} }

View File

@@ -62,10 +62,10 @@ internal fun solve(
} while (removedOptions) } while (removedOptions)
// If any cell has no items left, the puzzle has no solution. // 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 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. // 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) { for (i in 0 until grid.size) {

View File

@@ -9,24 +9,35 @@ import ch.dissem.yaep.domain.Nationality.UKRAINE
import ch.dissem.yaep.domain.Profession.ASTRONAUT import ch.dissem.yaep.domain.Profession.ASTRONAUT
import ch.dissem.yaep.domain.Profession.FARMER import ch.dissem.yaep.domain.Profession.FARMER
import ch.dissem.yaep.domain.Profession.SOFTWARE_DEV 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.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.toBeLessThan
import ch.tutteli.atrium.api.fluent.en_GB.toEqual import ch.tutteli.atrium.api.fluent.en_GB.toEqual
import ch.tutteli.atrium.api.verbs.expect import ch.tutteli.atrium.api.verbs.expect
import kotlin.test.Test import kotlin.test.Test
import kotlin.time.Duration.Companion.seconds
import kotlin.time.measureTime
class GameTest { class GameTest {
@Test @Test
fun `ensure generated game is valid`() { fun `ensure generated game is valid`() {
val game = generateGame() val game: Game
val time = measureTime {
game = generateGame()
}
expect(game) { expect(game) {
feature(Game::areCategoriesValid).toEqual(true) feature(Game::areCategoriesValid).toEqual(true)
feature(Game::areRulesViolated).toEqual(false) feature(Game::areRulesViolated).toEqual(false)
feature(Game::clues) { feature(Game::clues) {
feature(List<Clue>::size).toBeGreaterThan(5)
feature(List<Clue>::size).toBeLessThan(30) 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 @Test
@@ -73,7 +84,7 @@ class GameTest {
) )
) )
expect(solve(game.grid, game.clues)).toEqual(PuzzleSolution.SOLVABLE) expect(solve(game.grid, game.clues)).toEqual(SOLVABLE)
} }
} }