Render puzzle (WIP)

This commit is contained in:
Christian Basler
2024-06-20 17:37:06 +02:00
parent fcbebe802f
commit 1248288e98
10 changed files with 70 additions and 23 deletions

View File

@@ -9,7 +9,7 @@ fun generateGame(size: Int = 6): Game {
// Generate a random puzzle instance.
val classes = ItemClass.randomClasses(size)
val grid: List<List<Item<ItemClass<*>>>> = classes.map { it ->
val grid: List<List<Item<ItemClass<*>>>> = classes.map {
it.randomItems(size).map { item -> Item(item) }
}
@@ -18,6 +18,10 @@ fun generateGame(size: Int = 6): Game {
// if there are 5 houses, there are 5 possible clues of the form "Person A lives in
// house B", 8 possible clues of the form "Person A lives next to house B", and so on.)
var clues = getAllClues(grid).shuffled()
// var positionClues: MutableSet<PositionClue<out ItemClass<*>>> = grid.flatMap { row ->
// row.mapIndexed { i, item -> PositionClue(item, i) }
// }.toMutableSet()
var i = 0
@@ -37,12 +41,14 @@ fun generateGame(size: Int = 6): Game {
// (You can speed this up by removing clues in batches rather than one at a time, but it makes the algorithm more complicated to describe.)
}
private fun solve(grid: Grid, clues: List<Clue>): PuzzleSolution {
private fun solve(
grid: Grid,
clues: Collection<Clue>
): PuzzleSolution {
// Start with a grid where each cell is a list of all possible items.
// First, set the positions of the items that are already known.
val positionClues = clues.filterIsInstance<PositionClue<ItemClass<*>>>().toSet()
positionClues.forEach { position ->
clues.filterIsInstance<PositionClue<ItemClass<*>>>().forEach { position ->
val row = grid[position.item.itemType.companion]
row.forEachIndexed { index, gameCell ->
if (index == position.index) {
@@ -56,9 +62,10 @@ private fun solve(grid: Grid, clues: List<Clue>): PuzzleSolution {
// For each clue, remove any items that violate the clue.
// If any cell has only one item left, remove that item from all other cells.
// Repeat until no more items can be removed.
val otherClues = clues - positionClues
var removedOptions = false
val otherClues = clues.filter { it !is PositionClue<*> }
var removedOptions: Boolean
do {
removedOptions = false
grid.forEach { row ->
removedOptions = row.tryOptionsForClues(grid, otherClues) || removedOptions
}
@@ -112,15 +119,17 @@ fun <C : ItemClass<C>> GameRow<C>.cleanupOptions(cell: GameCell<C>) {
}
}
private fun getAllClues(rows: List<List<Item<ItemClass<*>>>>): MutableList<Clue> {
val clues = mutableListOf<Clue>()
// For optimization reasons we want the positional clues first
rows.forEach { row ->
row.forEachIndexed { i, item ->
clues.add(PositionClue(item, i))
}
}
rows.forEachIndexed { i, columns ->
private fun getAllClues(rows: List<List<Item<ItemClass<*>>>>): MutableSet<Clue> {
val clues = mutableSetOf<Clue>()
// rows.forEach { row ->
// row.forEachIndexed { i, item ->
// clues.add(PositionClue(item, i))
// }
// }
clues.add(PositionClue(rows.random().first(), 0))
clues.add(PositionClue(rows.random()[3], 3))
rows.forEach { columns ->
columns.forEachIndexed { j, item ->
// Clue: Neighbours
if (j > 0) {