diff --git a/composeApp/src/commonMain/kotlin/domain/Game.kt b/composeApp/src/commonMain/kotlin/domain/Game.kt index 2e3b4a9..9816de7 100644 --- a/composeApp/src/commonMain/kotlin/domain/Game.kt +++ b/composeApp/src/commonMain/kotlin/domain/Game.kt @@ -1,5 +1,7 @@ package domain +const val PUZZLE_SIZE = 6 + class Game( val categories: List, val grid: Grid, diff --git a/composeApp/src/commonMain/kotlin/domain/generator.kt b/composeApp/src/commonMain/kotlin/domain/generator.kt new file mode 100644 index 0000000..595dee7 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/domain/generator.kt @@ -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() +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/domain/grid.kt b/composeApp/src/commonMain/kotlin/domain/grid.kt index aae466d..bea6955 100644 --- a/composeApp/src/commonMain/kotlin/domain/grid.kt +++ b/composeApp/src/commonMain/kotlin/domain/grid.kt @@ -8,14 +8,14 @@ class GameRow( class Grid( val rows: List ) : List by rows { - fun indexOf(element: Item): Int { + fun indexOf(element: ItemClass): Int { val row = rows.first { it.category == element.category } return row.indexOfFirst { it.selection == element } } } class GameCell( - var selection: Item?, - val solution: Item, - val options: List + var selection: ItemClass?, + val solution: ItemClass, + val options: List ) diff --git a/composeApp/src/commonMain/kotlin/domain/items.kt b/composeApp/src/commonMain/kotlin/domain/items.kt index d6a2294..fadc298 100644 --- a/composeApp/src/commonMain/kotlin/domain/items.kt +++ b/composeApp/src/commonMain/kotlin/domain/items.kt @@ -1,44 +1,105 @@ -@file:OptIn(ExperimentalResourceApi::class) - package domain -import org.jetbrains.compose.resources.DrawableResource -import org.jetbrains.compose.resources.ExperimentalResourceApi +enum class Animals(symbol: String) : ItemClass { + ZEBRA("šŸ¦“"), + OCTOPUS("šŸ™"), + GOAT("🐐"), + SLOTH("🦄"), + DOG("šŸ•"), + SNAIL("🐌"), + ANT("🐜"); -fun category(block: CategoryContext.() -> Unit): ItemCategory { - class CategoryImpl(val items: MutableList) : - ItemCategory, List 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 + override val symbols: Array = arrayOf(symbol) } -interface CategoryContext { - fun item(image: DrawableResource) +enum class Nationality(symbol: String) : ItemClass { + ENGLAND("šŸ‡¬šŸ‡§"), + UKRAINE("šŸ‡ŗšŸ‡¦"), + SPAIN("šŸ‡ŖšŸ‡ø"), + NORWAY("šŸ‡³šŸ‡“"), + JAPAN("šŸ‡ÆšŸ‡µ"), + SWITZERLAND("šŸ‡ØšŸ‡­"), + CANADA("šŸ‡ØšŸ‡¦"); + + override val symbols: Array = arrayOf(symbol) } -interface Item { - val category: ItemCategory +enum class Drink(symbol: String) : ItemClass { + MILK("šŸ„›"), + WINE("šŸ·"), + COCKTAIL("šŸø"), + COFFEE("ā˜•"), + TEA("šŸµ"), + BEER("šŸŗ"), + BEVERAGE("🧃"); - @OptIn(ExperimentalResourceApi::class) - val image: DrawableResource + override val symbols: Array = arrayOf(symbol) } -interface ItemCategory : List +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 = idic(symbol) +} + +enum class Fruit(symbol: String) : ItemClass { + GRAPES("šŸ‡"), + WATERMELON("šŸ‰"), + LEMON("šŸ‹"), + BANANA("šŸŒ"), + PINEAPPLE("šŸ"), + CHERRIES("šŸ’"), + STRAWBERRY("šŸ“"), + KIWI("šŸ„"), + PEAR("šŸ"), + MANGO("🄭"); + + override val symbols: Array = idic(symbol) +} + +enum class Dessert(symbol: String) : ItemClass { + ICE_CREAM("šŸØ"), + DOUGHNUT("šŸ©"), + COOKIE("šŸŖ"), + CAKE("šŸ°"), + CUPCAKE("🧁"), + PIE("🄧"), + CHOCOLATE("šŸ«"), + LOLLIPOP("šŸ­"), + CUSTARD("šŸ®"); + + override val symbols: Array = idic(symbol) +} + +enum class Transportation(symbol: String) : ItemClass { + BICYCLE("🚲"), + MOTOR_SCOOTER("šŸ›µ"), + SKATEBOARD("šŸ›¹"), + TAXI("šŸš•"), + LOCOMOTIVE("šŸš‚"), + TRAM_CAR("šŸš‹"), + BUS("🚌"); + + override val symbols: Array = 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(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 +} diff --git a/composeApp/src/commonMain/kotlin/domain/rules.kt b/composeApp/src/commonMain/kotlin/domain/rules.kt index 95ad9a9..768fa75 100644 --- a/composeApp/src/commonMain/kotlin/domain/rules.kt +++ b/composeApp/src/commonMain/kotlin/domain/rules.kt @@ -8,7 +8,7 @@ sealed class 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 { val ia = grid.indexOf(a) 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 { val il = grid.indexOf(left) 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 { if (ix == -1 || iy == -1) return false 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 { val ia = grid.indexOf(a) val ib = grid.indexOf(b) diff --git a/composeApp/src/commonMain/kotlin/ui/selector.kt b/composeApp/src/commonMain/kotlin/ui/selector.kt index e0072c6..c7e4801 100644 --- a/composeApp/src/commonMain/kotlin/ui/selector.kt +++ b/composeApp/src/commonMain/kotlin/ui/selector.kt @@ -3,11 +3,11 @@ package ui import androidx.compose.material3.OutlinedCard import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import domain.Item +import domain.ItemClass import domain.ItemCategory @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) { }