Improve domain (WIP)

This commit is contained in:
2024-06-11 23:41:39 +02:00
parent f891dea885
commit 60204f3b04
6 changed files with 122 additions and 44 deletions

View File

@@ -1,5 +1,7 @@
package domain package domain
const val PUZZLE_SIZE = 6
class Game( class Game(
val categories: List<ItemCategory>, val categories: List<ItemCategory>,
val grid: Grid, val grid: Grid,

View File

@@ -0,0 +1,15 @@
package domain
fun generateGame(): Game {
// Here's a simple algorithm making use of your solver:
// 1. Generate a random puzzle instance.
// 2. Build a set C of all possible clues that pertain to this puzzle instance. (There are a finite and in fact quite small number of possible clues: for example 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.)
// 3. Pick a random permutation c1, c2, ..., cn of the clues in C.
// 4. Set i = 1.
// 5. If i > n, we are done. The set C of clues is minimal.
// 6. Let D = C { ci }. Run your solver on the set D of clues and count the number of possible solutions.
// 7. If there is exactly one solution, set C = D.
// 8. Set i = i + 1 and go back to step 5.
// (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.)
TODO()
}

View File

@@ -8,14 +8,14 @@ class GameRow(
class Grid( class Grid(
val rows: List<GameRow> val rows: List<GameRow>
) : List<GameRow> by rows { ) : List<GameRow> by rows {
fun indexOf(element: Item): Int { fun indexOf(element: ItemClass): Int {
val row = rows.first { it.category == element.category } val row = rows.first { it.category == element.category }
return row.indexOfFirst { it.selection == element } return row.indexOfFirst { it.selection == element }
} }
} }
class GameCell( class GameCell(
var selection: Item?, var selection: ItemClass?,
val solution: Item, val solution: ItemClass,
val options: List<Item> val options: List<ItemClass>
) )

View File

@@ -1,44 +1,105 @@
@file:OptIn(ExperimentalResourceApi::class)
package domain package domain
import org.jetbrains.compose.resources.DrawableResource enum class Animals(symbol: String) : ItemClass {
import org.jetbrains.compose.resources.ExperimentalResourceApi ZEBRA("🦓"),
OCTOPUS("🐙"),
GOAT("🐐"),
SLOTH("🦥"),
DOG("🐕"),
SNAIL("🐌"),
ANT("🐜");
fun category(block: CategoryContext.() -> Unit): ItemCategory { override val symbols: Array<String> = arrayOf(symbol)
class CategoryImpl(val items: MutableList<ItemImpl>) :
ItemCategory, List<Item> by items {
inner class ItemImpl(
override val image: DrawableResource
) : Item {
override val category: CategoryImpl = this@CategoryImpl
init {
items.add(this)
}
}
}
val ctx = object : CategoryContext {
val category = CategoryImpl(mutableListOf())
override fun item(image: DrawableResource) {
category.ItemImpl(image)
}
}
ctx.block()
return ctx.category
} }
interface CategoryContext { enum class Nationality(symbol: String) : ItemClass {
fun item(image: DrawableResource) ENGLAND("🇬🇧"),
UKRAINE("🇺🇦"),
SPAIN("🇪🇸"),
NORWAY("🇳🇴"),
JAPAN("🇯🇵"),
SWITZERLAND("🇨🇭"),
CANADA("🇨🇦");
override val symbols: Array<String> = arrayOf(symbol)
} }
interface Item { enum class Drink(symbol: String) : ItemClass {
val category: ItemCategory MILK("🥛"),
WINE("🍷"),
COCKTAIL("🍸"),
COFFEE(""),
TEA("🍵"),
BEER("🍺"),
BEVERAGE("🧃");
@OptIn(ExperimentalResourceApi::class) override val symbols: Array<String> = arrayOf(symbol)
val image: DrawableResource
} }
interface ItemCategory : List<Item> enum class Profession(symbol: String) : ItemClass {
ASTRONAUT("\u200D\uD83D\uDE80"),
HEALTH_WORKER("\u200D\uFE0F"),
FARMER("\u200D\uD83C\uDF3E"),
ROCK_STAR("\u200D\uD83C\uDFA4"),
SCIENTIST("\u200D\uD83D\uDD2C"),
SOFTWARE_DEV("\u200D\uD83D\uDCBB"),
FIREFIGHTER("\u200D\uD83D\uDE92"),
TEACHER("\u200D\uD83C\uDFEB");
override val symbols: Array<String> = idic(symbol)
}
enum class Fruit(symbol: String) : ItemClass {
GRAPES("🍇"),
WATERMELON("🍉"),
LEMON("🍋"),
BANANA("🍌"),
PINEAPPLE("🍍"),
CHERRIES("🍒"),
STRAWBERRY("🍓"),
KIWI("🥝"),
PEAR("🍐"),
MANGO("🥭");
override val symbols: Array<String> = idic(symbol)
}
enum class Dessert(symbol: String) : ItemClass {
ICE_CREAM("🍨"),
DOUGHNUT("🍩"),
COOKIE("🍪"),
CAKE("🍰"),
CUPCAKE("🧁"),
PIE("🥧"),
CHOCOLATE("🍫"),
LOLLIPOP("🍭"),
CUSTARD("🍮");
override val symbols: Array<String> = idic(symbol)
}
enum class Transportation(symbol: String) : ItemClass {
BICYCLE("🚲"),
MOTOR_SCOOTER("🛵"),
SKATEBOARD("🛹"),
TAXI("🚕"),
LOCOMOTIVE("🚂"),
TRAM_CAR("🚋"),
BUS("🚌");
override val symbols: Array<String> = idic(symbol)
}
private val GENDERS = arrayOf("\uD83E\uDDD1", "\uD83D\uDC68", "\uD83D\uDC69")
private val SKIN_TONES =
arrayOf("\uD83C\uDFFB", "\uD83C\uDFFC", "\uD83C\uDFFD", "\uD83C\uDFFE", "\uD83C\uDFFF")
private fun idic(symbol: String) = Array<String>(GENDERS.size * SKIN_TONES.size) { i ->
val g = GENDERS[i % GENDERS.size]
val t = SKIN_TONES[i / GENDERS.size]
g + t + symbol
}
sealed interface ItemClass {
val symbols: Array<String>
}

View File

@@ -8,7 +8,7 @@ sealed class GameRule {
sealed class HorizontalRule : GameRule() sealed class HorizontalRule : GameRule()
class NeighbourRule(val a: Item, val b: Item) : HorizontalRule() { class NeighbourRule(val a: ItemClass, val b: ItemClass) : HorizontalRule() {
override fun isRuleViolated(grid: Grid): Boolean { override fun isRuleViolated(grid: Grid): Boolean {
val ia = grid.indexOf(a) val ia = grid.indexOf(a)
val ib = grid.indexOf(b) val ib = grid.indexOf(b)
@@ -19,7 +19,7 @@ class NeighbourRule(val a: Item, val b: Item) : HorizontalRule() {
} }
} }
class OrderRule(val left: Item, val right: Item) : HorizontalRule() { class OrderRule(val left: ItemClass, val right: ItemClass) : HorizontalRule() {
override fun isRuleViolated(grid: Grid): Boolean { override fun isRuleViolated(grid: Grid): Boolean {
val il = grid.indexOf(left) val il = grid.indexOf(left)
val ir = grid.indexOf(right) val ir = grid.indexOf(right)
@@ -30,7 +30,7 @@ class OrderRule(val left: Item, val right: Item) : HorizontalRule() {
} }
} }
class TripletRule(val a: Item, val b: Item, val c: Item) : HorizontalRule() { class TripletRule(val a: ItemClass, val b: ItemClass, val c: ItemClass) : HorizontalRule() {
private fun isNeighbourRuleViolated(ix: Int, iy: Int): Boolean { private fun isNeighbourRuleViolated(ix: Int, iy: Int): Boolean {
if (ix == -1 || iy == -1) return false if (ix == -1 || iy == -1) return false
return abs(ix - iy) != 1 return abs(ix - iy) != 1
@@ -57,7 +57,7 @@ class TripletRule(val a: Item, val b: Item, val c: Item) : HorizontalRule() {
} }
} }
class VerticalRule(val a: Item, val b: Item) : GameRule() { class VerticalRule(val a: ItemClass, val b: ItemClass) : GameRule() {
override fun isRuleViolated(grid: Grid): Boolean { override fun isRuleViolated(grid: Grid): Boolean {
val ia = grid.indexOf(a) val ia = grid.indexOf(a)
val ib = grid.indexOf(b) val ib = grid.indexOf(b)

View File

@@ -3,11 +3,11 @@ package ui
import androidx.compose.material3.OutlinedCard import androidx.compose.material3.OutlinedCard
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import domain.Item import domain.ItemClass
import domain.ItemCategory import domain.ItemCategory
@Composable @Composable
fun Selector(modifier: Modifier = Modifier, category: ItemCategory, selectedItem: Item, onSelectItem: (Item) -> Unit) { fun Selector(modifier: Modifier = Modifier, category: ItemCategory, selectedItem: ItemClass, onSelectItem: (ItemClass) -> Unit) {
OutlinedCard(modifier = modifier) { OutlinedCard(modifier = modifier) {
} }