Improvements
try to make it run on Android (still unsuccessful)
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
package ch.dissem.yaep.domain
|
||||
|
||||
abstract class ClueTest {
|
||||
protected val size = 6
|
||||
|
||||
protected fun createGrid(
|
||||
selection: (Item<ItemClass<*>>) -> Item<ItemClass<*>>? = { it }
|
||||
) = Grid(
|
||||
ItemClass.randomClasses(size)
|
||||
.map {
|
||||
it.randomItems(size).map { item -> Item(item) }
|
||||
}
|
||||
.map { row ->
|
||||
GameRow(
|
||||
category = row.first().itemType.companion,
|
||||
options = row,
|
||||
cells = row.map {
|
||||
GameCell(
|
||||
selection = selection(it),
|
||||
solution = it,
|
||||
options = mutableListOf()
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
169
domain/src/commonTest/kotlin/ch/dissem/yaep/domain/GameTest.kt
Normal file
169
domain/src/commonTest/kotlin/ch/dissem/yaep/domain/GameTest.kt
Normal file
@@ -0,0 +1,169 @@
|
||||
package ch.dissem.yaep.domain
|
||||
|
||||
import ch.dissem.yaep.domain.Animal.*
|
||||
import ch.dissem.yaep.domain.Nationality.*
|
||||
import ch.dissem.yaep.domain.Profession.*
|
||||
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.milliseconds
|
||||
import kotlin.time.measureTime
|
||||
|
||||
class GameTest {
|
||||
|
||||
@Test
|
||||
fun `ensure generated games are solvable`() {
|
||||
val tries = 2000
|
||||
var fastest = 500.milliseconds
|
||||
var slowest = 0.milliseconds
|
||||
var total = 0.milliseconds
|
||||
var most = 0
|
||||
var least = 1000
|
||||
var totalClues = 0
|
||||
for (i in 1..tries) {
|
||||
val game: Game
|
||||
val time = measureTime {
|
||||
game = generateGame()
|
||||
}
|
||||
println("Generated game #$i in ${time.inWholeMilliseconds}ms")
|
||||
val solvable = solve(game.grid, game.clues)
|
||||
if (solvable != SOLVABLE) {
|
||||
println("Puzzle:\n$game")
|
||||
}
|
||||
expect(solvable).toEqual(SOLVABLE)
|
||||
expect(time).toBeLessThan(500.milliseconds)
|
||||
if (time < fastest) {
|
||||
fastest = time
|
||||
}
|
||||
if (time > slowest) {
|
||||
slowest = time
|
||||
}
|
||||
total += time
|
||||
if (game.clues.size > most){
|
||||
most = game.clues.size
|
||||
}
|
||||
if (game.clues.size < least){
|
||||
least = game.clues.size
|
||||
}
|
||||
totalClues += game.clues.size
|
||||
}
|
||||
|
||||
println("Slowest: $slowest")
|
||||
println("Fastest: $fastest")
|
||||
println("Average: ${total / tries}")
|
||||
println("Clues:")
|
||||
println("Most: $most")
|
||||
println("Least: $least")
|
||||
println("Average: ${totalClues / tries}")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure generated game is valid`() {
|
||||
val game: Game
|
||||
val time = measureTime {
|
||||
game = generateGame()
|
||||
}
|
||||
expect(game) {
|
||||
feature(Game::areCategoriesValid).toEqual(true)
|
||||
feature(Game::isValid).toEqual(true)
|
||||
feature(Game::clues) {
|
||||
feature(Collection<Clue>::size).toBeGreaterThan(5)
|
||||
feature(Collection<Clue>::size).toBeLessThan(30)
|
||||
}
|
||||
}
|
||||
println("Clues: ${game.clues.size}")
|
||||
println("Time: $time")
|
||||
expect(solve(game.grid, game.clues)).toEqual(SOLVABLE)
|
||||
expect(time).toBeLessThan(500.milliseconds)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure game can be solved`() {
|
||||
val professions = listOf(
|
||||
Item(ASTRONAUT),
|
||||
Item(FARMER),
|
||||
Item(SOFTWARE_DEV)
|
||||
)
|
||||
val animals = listOf(
|
||||
Item(SNAIL),
|
||||
Item(ANT),
|
||||
Item(OCTOPUS)
|
||||
)
|
||||
val nationalities = listOf(
|
||||
Item(UKRAINE),
|
||||
Item(CANADA),
|
||||
Item(SWITZERLAND)
|
||||
)
|
||||
val game = Game(
|
||||
Grid(listOf(
|
||||
GameRow(
|
||||
Profession,
|
||||
professions,
|
||||
professions.map { GameCell(null, it, professions.toMutableList()) }
|
||||
),
|
||||
GameRow(
|
||||
Animal,
|
||||
animals,
|
||||
animals.map { GameCell(null, it, animals.toMutableList()) }
|
||||
),
|
||||
GameRow(
|
||||
Nationality,
|
||||
nationalities,
|
||||
nationalities.map { GameCell(null, it, nationalities.toMutableList()) }
|
||||
)
|
||||
)),
|
||||
listOf(
|
||||
TripletClue(professions[0], animals[1], nationalities[2]),
|
||||
OrderClue(professions[0], nationalities[1]),
|
||||
SameColumnClue(animals[1], nationalities[1]),
|
||||
NeighbourClue(professions[0], professions[1]),
|
||||
PositionClue(animals[0], 0)
|
||||
)
|
||||
)
|
||||
|
||||
expect(solve(game.grid, game.clues)).toEqual(SOLVABLE)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure specific game is solvable`() {
|
||||
val game = Game.parse("""
|
||||
👩🏿⚕️👨🏽🎤👩🏿⚕️ 👩🏾🚀🧑🏿🏫
|
||||
🐜🐕 🐐 🐐
|
||||
🍉🥭🍐🍇🍍
|
||||
🧁🍨🍩🍰🥧
|
||||
🇨🇭🇬🇧🇯🇵🇺🇦🇬🇧🇨🇦
|
||||
🍷🧃🍺🧃
|
||||
|
||||
* ZEBRA is between the neighbours PIE and PEAR to both sides
|
||||
* WINE is at position 0
|
||||
* SLOTH is between the neighbours ZEBRA and COFFEE to both sides
|
||||
* ICE_CREAM is left of MANGO
|
||||
* SWITZERLAND is at position 0
|
||||
* PIE is at position 4
|
||||
* SCIENTIST is between the neighbours ASTRONAUT and PEAR to both sides
|
||||
* ROCK_STAR is between the neighbours SNAIL and ANT to both sides
|
||||
* SNAIL is between the neighbours ROCK_STAR and TEA to both sides
|
||||
* SOFTWARE_DEV is left of SLOTH
|
||||
* SOFTWARE_DEV is left of HEALTH_WORKER
|
||||
* MILK is between the neighbours CUSTARD and ZEBRA to both sides
|
||||
* SLOTH is between the neighbours CUSTARD and CAKE to both sides
|
||||
* SPAIN is between the neighbours CUSTARD and GRAPES to both sides
|
||||
* SCIENTIST is between the neighbours SNAIL and SLOTH to both sides
|
||||
* DOG is between the neighbours CUPCAKE and BEER to both sides
|
||||
* SNAIL is between the neighbours BANANA and GRAPES to both sides
|
||||
* SLOTH is between the neighbours GRAPES and CANADA to both sides
|
||||
* UKRAINE and SCIENTIST are in the same column
|
||||
* DOG is between the neighbours JAPAN and SWITZERLAND to both sides
|
||||
* SLOTH is between the neighbours GOAT and TEA to both sides
|
||||
* ROCK_STAR and UNITED_KINGDOM are in the same column
|
||||
* ROCK_STAR is next to DOUGHNUT
|
||||
* PINEAPPLE is between the neighbours TEACHER and GRAPES to both sides
|
||||
""".trimIndent())
|
||||
|
||||
expect(solve(game.grid, game.clues)).toEqual(SOLVABLE)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package ch.dissem.yaep.domain
|
||||
|
||||
import ch.tutteli.atrium.api.fluent.en_GB.toEqual
|
||||
import ch.tutteli.atrium.api.verbs.expect
|
||||
import kotlin.test.Test
|
||||
|
||||
class NeighbourClueTest : ClueTest() {
|
||||
|
||||
@Test
|
||||
fun `ensure actual neighbours are valid`() {
|
||||
val grid = createGrid()
|
||||
for (ia in 0 until size) {
|
||||
for (ib in 0 until size) {
|
||||
for (j in 1 until size) {
|
||||
val a = grid[ia][j - 1]
|
||||
val b = grid[ib][j]
|
||||
|
||||
expect(NeighbourClue(a.solution!!, b.solution!!).isValid(grid)).toEqual(true)
|
||||
expect(NeighbourClue(b.solution!!, a.solution!!).isValid(grid)).toEqual(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure non-neighbours are invalid`() {
|
||||
val grid = createGrid()
|
||||
for (ia in 0 until size) {
|
||||
for (ib in 0 until size) {
|
||||
for (ja in 0 until size) {
|
||||
for (jb in 0 until size) {
|
||||
if (ja == jb + 1 || ja == jb - 1) {
|
||||
continue
|
||||
}
|
||||
val a = grid[ia][ja]
|
||||
val b = grid[ib][jb]
|
||||
|
||||
expect(NeighbourClue(a.solution!!, b.solution!!).isValid(grid)).toEqual(false)
|
||||
expect(NeighbourClue(b.solution!!, a.solution!!).isValid(grid)).toEqual(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure grid with one neighbour not set is considered valid if a neighbour is in the options`() {
|
||||
val grid = createGrid()
|
||||
for (ia in 0 until size) {
|
||||
for (ib in 0 until size) {
|
||||
for (j in 1 until size) {
|
||||
val rowA = grid[ia]
|
||||
val rowB = grid[ib]
|
||||
val a = rowA[j - 1]
|
||||
val b = rowB[j]
|
||||
|
||||
rowA.forEach { it.selection = null; it.options.clear() }
|
||||
rowB.forEach { it.selection = null; it.options.clear() }
|
||||
|
||||
a.selection = null
|
||||
a.options.add(a.solution!!)
|
||||
b.selection = b.solution
|
||||
b.options.clear()
|
||||
|
||||
expect(NeighbourClue(a.solution!!, b.solution!!).isValid(grid)).toEqual(true)
|
||||
expect(NeighbourClue(b.solution!!, a.solution!!).isValid(grid)).toEqual(true)
|
||||
|
||||
a.selection = a.solution
|
||||
a.options.clear()
|
||||
b.selection = null
|
||||
b.options.add(b.solution!!)
|
||||
|
||||
expect(NeighbourClue(a.solution!!, b.solution!!).isValid(grid)).toEqual(true)
|
||||
expect(NeighbourClue(b.solution!!, a.solution!!).isValid(grid)).toEqual(true)
|
||||
|
||||
if (j < size - 1) {
|
||||
val notA = rowA[j + 1]
|
||||
|
||||
a.selection = null
|
||||
a.options.clear()
|
||||
notA.options.add(a.solution!!)
|
||||
b.selection = b.solution
|
||||
b.options.clear()
|
||||
|
||||
expect(NeighbourClue(a.solution!!, b.solution!!).isValid(grid)).toEqual(true)
|
||||
expect(NeighbourClue(b.solution!!, a.solution!!).isValid(grid)).toEqual(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure grid with a and c more than one cell between is not considered valid`() {
|
||||
val grid = createGrid { null }
|
||||
val rowA = grid.random()
|
||||
val rowB = grid.random()
|
||||
val a = rowA[1]
|
||||
val b = rowB[2]
|
||||
|
||||
a.selection = a.solution
|
||||
|
||||
rowB[3].selection = b.solution
|
||||
|
||||
expect(NeighbourClue(a.solution!!, b.solution!!).isValid(grid)).toEqual(false)
|
||||
expect(NeighbourClue(b.solution!!, a.solution!!).isValid(grid)).toEqual(false)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package ch.dissem.yaep.domain
|
||||
|
||||
import ch.tutteli.atrium.api.fluent.en_GB.toEqual
|
||||
import ch.tutteli.atrium.api.verbs.expect
|
||||
import kotlin.test.Test
|
||||
|
||||
class OrderClueTest : ClueTest() {
|
||||
@Test
|
||||
fun `ensure items in correct order are valid`() {
|
||||
val grid = createGrid()
|
||||
for (ia in 0 until size) {
|
||||
for (ib in 0 until size) {
|
||||
for (ic in 0 until size) {
|
||||
for (ja in 0 until size - 1) {
|
||||
for (jb in ja + 1 until size) {
|
||||
val a = grid[ia][ja]
|
||||
val b = grid[ib][jb]
|
||||
|
||||
expect(OrderClue(a.solution!!, b.solution!!).isValid(grid)).toEqual(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure items in wrong order are valid`() {
|
||||
val grid = createGrid()
|
||||
for (ia in 0 until size) {
|
||||
for (ib in 0 until size) {
|
||||
for (ic in 0 until size) {
|
||||
for (ja in 0 until size - 1) {
|
||||
for (jb in ja until size) {
|
||||
val a = grid[ia][ja]
|
||||
val b = grid[ib][jb]
|
||||
|
||||
expect(OrderClue(b.solution!!, a.solution!!).isValid(grid)).toEqual(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure items in the same column are not valid`() {
|
||||
val grid = createGrid()
|
||||
for (rowA in grid.rows) {
|
||||
for (rowB in grid.rows) {
|
||||
for (i in 0 until size) {
|
||||
expect(OrderClue(rowA[i].solution!!, rowB[i].solution!!).isValid(grid)).toEqual(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package ch.dissem.yaep.domain
|
||||
|
||||
import ch.tutteli.atrium.api.fluent.en_GB.toEqual
|
||||
import ch.tutteli.atrium.api.verbs.expect
|
||||
import kotlin.test.Test
|
||||
|
||||
class SameColumnClueTest : ClueTest() {
|
||||
@Test
|
||||
fun `ensure fields in the same column are considered valid`() {
|
||||
val grid = createGrid()
|
||||
for (ia in 0 until size - 1) {
|
||||
for (ib in ia + 1 until size) {
|
||||
for (j in 0 until size) {
|
||||
val a = grid[ia][j]
|
||||
val b = grid[ib][j]
|
||||
|
||||
expect(SameColumnClue(a.solution!!, b.solution!!).isValid(grid)).toEqual(true)
|
||||
expect(SameColumnClue(b.solution!!, a.solution!!).isValid(grid)).toEqual(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure fields in different columns are considered invalid`() {
|
||||
val grid = createGrid()
|
||||
for (ia in 0 until size - 1) {
|
||||
for (ib in ia + 1 until size) {
|
||||
for (ja in 0 until size - 1) {
|
||||
for (jb in ja + 1 until size) {
|
||||
val a = grid[ia][ja]
|
||||
val b = grid[ib][jb]
|
||||
|
||||
expect(SameColumnClue(a.solution!!, b.solution!!).isValid(grid)).toEqual(false)
|
||||
expect(SameColumnClue(b.solution!!, a.solution!!).isValid(grid)).toEqual(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `if a is set, but b is set to a wrong value, it's considered invalid`() {
|
||||
val grid = createGrid { null }
|
||||
|
||||
for (ia in 0 until size - 1) {
|
||||
for (ib in ia + 1 until size) {
|
||||
for (ja in 0 until size - 1) {
|
||||
for (jb in ja + 1 until size) {
|
||||
val a = grid[ia][ja]
|
||||
val b = grid[ib][jb]
|
||||
|
||||
a.selection = a.solution
|
||||
b.selection = b.solution
|
||||
|
||||
expect(SameColumnClue(a.solution!!, b.solution!!).isValid(grid)).toEqual(false)
|
||||
expect(SameColumnClue(b.solution!!, a.solution!!).isValid(grid)).toEqual(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `if there are no options for a and b in the same column, it's considered invalid`() {
|
||||
val grid = createGrid { null }
|
||||
|
||||
val rowA = grid.random()
|
||||
val rowB = grid.filter { it != rowA }.random()
|
||||
|
||||
for (i in 0 until size) {
|
||||
val a = rowA[i]
|
||||
val b = rowB[i]
|
||||
rowA.forEachIndexed { index, gameCell ->
|
||||
if (index < i) {
|
||||
gameCell.selection = rowA.options.filter { it != a.solution }.random()
|
||||
} else {
|
||||
gameCell.selection = null
|
||||
}
|
||||
}
|
||||
rowB.forEachIndexed { index, gameCell ->
|
||||
if (index < i) {
|
||||
gameCell.selection = null
|
||||
} else {
|
||||
gameCell.selection = rowB.options.filter { it != b.solution }.random()
|
||||
}
|
||||
}
|
||||
|
||||
expect(SameColumnClue(a.solution!!, b.solution!!).isValid(grid)).toEqual(false)
|
||||
expect(SameColumnClue(b.solution!!, a.solution!!).isValid(grid)).toEqual(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
package ch.dissem.yaep.domain
|
||||
|
||||
import ch.tutteli.atrium.api.fluent.en_GB.toEqual
|
||||
import ch.tutteli.atrium.api.verbs.expect
|
||||
import kotlin.test.Test
|
||||
|
||||
class TripletClueTest : ClueTest() {
|
||||
|
||||
@Test
|
||||
fun `ensure actual triplets are valid`() {
|
||||
val grid = createGrid()
|
||||
for (ia in 0 until size) {
|
||||
for (ib in 0 until size) {
|
||||
for (ic in 0 until size) {
|
||||
for (j in 2 until size) {
|
||||
val a = grid[ia][j - 2]
|
||||
val b = grid[ib][j - 1]
|
||||
val c = grid[ic][j]
|
||||
|
||||
expect(TripletClue(a.solution!!, b.solution!!, c.solution!!).isValid(grid)).toEqual(true)
|
||||
expect(TripletClue(c.solution!!, b.solution!!, a.solution!!).isValid(grid)).toEqual(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure that middle might not be at the corners`() {
|
||||
val grid = createGrid { null }
|
||||
|
||||
val rowA = grid.random()
|
||||
val rowB = grid.random()
|
||||
val rowC = grid.random()
|
||||
val a = rowA[1]
|
||||
val b = rowB[2]
|
||||
val c = rowC[3]
|
||||
|
||||
rowB[0].selection = b.solution
|
||||
|
||||
expect(TripletClue(a.solution!!, b.solution!!, c.solution!!).isValid(grid)).toEqual(false)
|
||||
expect(TripletClue(c.solution!!, b.solution!!, a.solution!!).isValid(grid)).toEqual(false)
|
||||
|
||||
rowB[0].selection = null
|
||||
rowB[grid.size - 1].selection = b.solution
|
||||
|
||||
expect(TripletClue(a.solution!!, b.solution!!, c.solution!!).isValid(grid)).toEqual(false)
|
||||
expect(TripletClue(c.solution!!, b.solution!!, a.solution!!).isValid(grid)).toEqual(false)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure grid where a or c and b are not neighbours is invalid`() {
|
||||
val grid = createGrid { null }
|
||||
val ia = 1
|
||||
val rowA = grid[2]
|
||||
val a = rowA[ia]
|
||||
val ib = 2
|
||||
val rowB = grid[0]
|
||||
val b = rowB[ib]
|
||||
val ic = 3
|
||||
val rowC = grid[1]
|
||||
val c = rowC[ic]
|
||||
|
||||
val clue = TripletClue(a.solution!!, b.solution!!, c.solution!!)
|
||||
|
||||
b.selection = b.solution
|
||||
c.options.add(c.solution!!)
|
||||
|
||||
|
||||
rowA.forEachIndexed { index, notA ->
|
||||
notA.selection = a.solution
|
||||
when {
|
||||
notA == a -> {
|
||||
// ignore
|
||||
}
|
||||
|
||||
index == ic -> {
|
||||
rowC[ia].options.add(c.solution!!)
|
||||
expect(clue.isValid(grid)).toEqual(true)
|
||||
}
|
||||
|
||||
else -> {
|
||||
expect(clue.isValid(grid)).toEqual(false)
|
||||
}
|
||||
}
|
||||
notA.selection = null
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensure grid with a and c more than one cell between is considered invalid`() {
|
||||
val grid = createGrid { null }
|
||||
val a = grid[2][1]
|
||||
val b = grid[0][2]
|
||||
val c = grid[1][3]
|
||||
|
||||
a.selection = a.solution
|
||||
grid[1][4].selection = c.solution
|
||||
|
||||
expect(TripletClue(a.solution!!, b.solution!!, c.solution!!).isValid(grid)).toEqual(false)
|
||||
expect(TripletClue(c.solution!!, b.solution!!, a.solution!!).isValid(grid)).toEqual(false)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `grid with a set and b and c as option on the same side is considered valid`() {
|
||||
val grid = createGrid { null }
|
||||
val rowA = grid.random()
|
||||
val rowB = grid.random()
|
||||
val rowC = grid.random()
|
||||
val a = rowA[3]
|
||||
val b = rowB[2]
|
||||
val c = rowC[1]
|
||||
|
||||
a.selection = a.solution
|
||||
b.options.clear()
|
||||
c.options.clear()
|
||||
|
||||
rowB[4].options.add(b.solution!!)
|
||||
rowC[5].options.add(c.solution!!)
|
||||
|
||||
expect(TripletClue(a.solution!!, b.solution!!, c.solution!!).isValid(grid)).toEqual(true)
|
||||
expect(TripletClue(c.solution!!, b.solution!!, a.solution!!).isValid(grid)).toEqual(true)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `grid with a set and no b and c as option on the same side is considered invalid`() {
|
||||
val grid = createGrid { null }
|
||||
val rowA = grid[2]
|
||||
val rowB = grid[0]
|
||||
val rowC = grid[1]
|
||||
val a = rowA[3]
|
||||
val b = rowB[2]
|
||||
val c = rowC[1]
|
||||
|
||||
a.selection = a.solution
|
||||
rowB[4].selection = rowC[3].solution
|
||||
c.selection = rowC[3].solution
|
||||
|
||||
expect(TripletClue(a.solution!!, b.solution!!, c.solution!!).isValid(grid)).toEqual(false)
|
||||
expect(TripletClue(c.solution!!, b.solution!!, a.solution!!).isValid(grid)).toEqual(false)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user