Improve domain (WIP)
This commit is contained in:
@@ -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,
|
||||||
|
|||||||
15
composeApp/src/commonMain/kotlin/domain/generator.kt
Normal file
15
composeApp/src/commonMain/kotlin/domain/generator.kt
Normal 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()
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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 {
|
enum class Nationality(symbol: String) : ItemClass {
|
||||||
val category = CategoryImpl(mutableListOf())
|
ENGLAND("🇬🇧"),
|
||||||
|
UKRAINE("🇺🇦"),
|
||||||
|
SPAIN("🇪🇸"),
|
||||||
|
NORWAY("🇳🇴"),
|
||||||
|
JAPAN("🇯🇵"),
|
||||||
|
SWITZERLAND("🇨🇭"),
|
||||||
|
CANADA("🇨🇦");
|
||||||
|
|
||||||
override fun item(image: DrawableResource) {
|
override val symbols: Array<String> = arrayOf(symbol)
|
||||||
category.ItemImpl(image)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ctx.block()
|
|
||||||
return ctx.category
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CategoryContext {
|
enum class Drink(symbol: String) : ItemClass {
|
||||||
fun item(image: DrawableResource)
|
MILK("🥛"),
|
||||||
|
WINE("🍷"),
|
||||||
|
COCKTAIL("🍸"),
|
||||||
|
COFFEE("☕"),
|
||||||
|
TEA("🍵"),
|
||||||
|
BEER("🍺"),
|
||||||
|
BEVERAGE("🧃");
|
||||||
|
|
||||||
|
override val symbols: Array<String> = arrayOf(symbol)
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Item {
|
enum class Profession(symbol: String) : ItemClass {
|
||||||
val category: ItemCategory
|
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");
|
||||||
|
|
||||||
@OptIn(ExperimentalResourceApi::class)
|
override val symbols: Array<String> = idic(symbol)
|
||||||
val image: DrawableResource
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ItemCategory : List<Item>
|
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>
|
||||||
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user