diff --git a/composeApp/src/commonMain/composeResources/drawable/neighbour.xml b/composeApp/src/commonMain/composeResources/drawable/neighbour.xml
new file mode 100644
index 0000000..6231d05
--- /dev/null
+++ b/composeApp/src/commonMain/composeResources/drawable/neighbour.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/composeApp/src/commonMain/composeResources/drawable/order.xml b/composeApp/src/commonMain/composeResources/drawable/order.xml
new file mode 100644
index 0000000..1a72fd4
--- /dev/null
+++ b/composeApp/src/commonMain/composeResources/drawable/order.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/composeApp/src/commonMain/kotlin/App.kt b/composeApp/src/commonMain/kotlin/App.kt
index 4e821ee..049a38d 100644
--- a/composeApp/src/commonMain/kotlin/App.kt
+++ b/composeApp/src/commonMain/kotlin/App.kt
@@ -1,42 +1,163 @@
-import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.Image
+import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.material3.Button
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Text
-import androidx.compose.runtime.*
-import androidx.compose.ui.Alignment
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.wrapContentHeight
+import androidx.compose.foundation.lazy.grid.GridCells
+import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
+import androidx.compose.material3.OutlinedCard
+import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
-import domain.Animals
-import domain.Item
-import org.jetbrains.compose.resources.ExperimentalResourceApi
+import androidx.compose.ui.draw.alpha
+import androidx.compose.ui.unit.dp
+import domain.Grid
+import domain.HorizontalClue
+import domain.ItemClass
+import domain.NeighbourClue
+import domain.OrderClue
+import domain.SameRowClue
+import domain.TripletClue
+import domain.generateGame
import org.jetbrains.compose.resources.painterResource
-import org.jetbrains.compose.ui.tooling.preview.Preview
import ui.DrawItem
import ui.Selector
-
import yaep.composeapp.generated.resources.Res
-import yaep.composeapp.generated.resources.compose_multiplatform
+import yaep.composeapp.generated.resources.neighbour
+import yaep.composeapp.generated.resources.order
@Composable
-@Preview
fun App(modifier: Modifier = Modifier) {
- val size = 6
+ val game = generateGame()
+ Row(modifier = modifier) {
+ PuzzleGrid(modifier = Modifier.weight(1f), game.grid)
+ PuzzleClues(modifier = Modifier.weight(1f), game.horizontalClues, game.verticalClues)
+ }
+}
+
+@Composable
+fun PuzzleGrid(
+ modifier: Modifier = Modifier,
+ grid: Grid
+) {
Column(modifier = modifier) {
- Row {
- val options = remember { Animals.items.shuffled().take(size) }
- for (option in options) {
- var selectedItem by remember { mutableStateOf- ?>(Item(option)) }
- Selector(
- category = Animals,
- options = Animals.items.map { Item(it) },
- selectedItem = selectedItem,
- onSelectItem = { selectedItem = it },
- modifier = Modifier.weight(1f)
- )
+ for (row in grid.rows) {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .wrapContentHeight()
+ ) {
+ for (item in row) {
+ Selector(
+ modifier = Modifier
+ .padding(4.dp)
+ .weight(1f),
+ category = row.category,
+ options = item.options,
+ selectedItem = item.selection,
+ onSelectItem = { item.selection = it }
+ )
+ }
}
}
}
+}
+
+@Composable
+fun PuzzleClues(
+ modifier: Modifier = Modifier,
+ horizontalClues: List,
+ verticalClues: List>>
+) {
+ Column(modifier = modifier) {
+ LazyVerticalGrid(
+ modifier = Modifier.fillMaxWidth().weight(1f),
+ columns = GridCells.Adaptive(32.dp)
+ ) {
+ for (clue in horizontalClues.filter { it.isActive }) {
+ item {
+ HorizontalClue(
+ modifier = Modifier.clickable { clue.isActive = false },
+ clue = clue
+ )
+ }
+ }
+ for (clue in horizontalClues.filter { !it.isActive }) {
+ item {
+ HorizontalClue(
+ modifier = Modifier
+ .alpha(0.5f)
+ .clickable { clue.isActive = true },
+ clue = clue
+ )
+ }
+ }
+ }
+
+ LazyVerticalGrid(
+ modifier = Modifier.fillMaxWidth().weight(1f),
+ columns = GridCells.Adaptive(32.dp)
+ ) {
+ for (clue in verticalClues.filter { it.isActive }) {
+ item {
+ VerticalClue(
+ modifier = Modifier.clickable { clue.isActive = false },
+ clue = clue
+ )
+ }
+ }
+ for (clue in verticalClues.filter { !it.isActive }) {
+ item {
+ VerticalClue(
+ modifier = Modifier
+ .alpha(0.5f)
+ .clickable { clue.isActive = true },
+ clue = clue
+ )
+ }
+ }
+ }
+ }
+}
+
+@Composable
+fun HorizontalClue(modifier: Modifier = Modifier, clue: HorizontalClue) {
+ Column {
+ when (clue) {
+ is NeighbourClue<*> -> {
+ DrawItem(modifier = Modifier.weight(1f), clue.a)
+ OutlinedCard(modifier = modifier.aspectRatio(1f).weight(1f)) {
+ Image(
+ painter = painterResource(Res.drawable.neighbour),
+ contentDescription = null
+ )
+ }
+ DrawItem(modifier = Modifier.weight(1f), clue.b)
+ }
+
+ is OrderClue<*> -> {
+ DrawItem(modifier = Modifier.weight(1f), clue.left)
+ OutlinedCard(modifier = modifier.aspectRatio(1f).weight(1f)) {
+ Image(painter = painterResource(Res.drawable.order), contentDescription = null)
+ }
+ DrawItem(modifier = Modifier.weight(1f), clue.right)
+ }
+
+ is TripletClue<*> -> {
+ DrawItem(modifier = Modifier.weight(1f), clue.a)
+ DrawItem(modifier = Modifier.weight(1f), clue.b)
+ DrawItem(modifier = Modifier.weight(1f), clue.c)
+ }
+ }
+ }
+}
+
+@Composable
+fun VerticalClue(modifier: Modifier = Modifier, clue: SameRowClue<*>) {
+ Column(modifier = modifier) {
+ DrawItem(modifier = Modifier.weight(1f), clue.a)
+ DrawItem(modifier = Modifier.weight(1f), clue.b)
+ }
}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/domain/clues.kt b/composeApp/src/commonMain/kotlin/domain/clues.kt
index 615de14..0ffe13d 100644
--- a/composeApp/src/commonMain/kotlin/domain/clues.kt
+++ b/composeApp/src/commonMain/kotlin/domain/clues.kt
@@ -1,14 +1,18 @@
package domain
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
import kotlin.math.abs
sealed class Clue {
abstract fun isRuleViolated(grid: Grid): Boolean
+ var isActive: Boolean by mutableStateOf(true)
}
sealed class HorizontalClue : Clue()
-class NeighbourClue>(val a: Item, val b: Item) : HorizontalClue() {
+class NeighbourClue>(val a: Item, val b: Item) : HorizontalClue() {
private val aType = a.itemType
private val bType = b.itemType
@@ -22,7 +26,7 @@ class NeighbourClue>(val a: Item, val b: Item) : Horizontal
}
}
-class OrderClue>(val left: Item, val right: Item) : HorizontalClue() {
+class OrderClue>(val left: Item, val right: Item) : HorizontalClue() {
private val leftType = left.itemType
private val rightType = right.itemType
@@ -36,7 +40,8 @@ class OrderClue>(val left: Item, val right: Item) : Horizon
}
}
-class TripletClue>(val a: Item, val b: Item, val c: Item) : HorizontalClue() {
+class TripletClue>(val a: Item, val b: Item, val c: Item) :
+ HorizontalClue() {
private val aType = a.itemType
private val bType = b.itemType
private val cType = c.itemType
@@ -67,7 +72,7 @@ class TripletClue>(val a: Item, val b: Item, val c: Item
}
}
-class SameRowClue>(val a: Item, val b: Item) : Clue() {
+class SameRowClue>(val a: Item, val b: Item) : Clue() {
private val aType = a.itemType
private val bType = b.itemType
@@ -81,7 +86,7 @@ class SameRowClue>(val a: Item, val b: Item) : Clue() {
}
}
-class PositionClue>(val item: Item, val index: Int) : Clue() {
+class PositionClue>(val item: Item, val index: Int) : Clue() {
private val aType = item.itemType
override fun isRuleViolated(grid: Grid): Boolean {
diff --git a/composeApp/src/commonMain/kotlin/domain/grid.kt b/composeApp/src/commonMain/kotlin/domain/grid.kt
index 578cd17..2df5914 100644
--- a/composeApp/src/commonMain/kotlin/domain/grid.kt
+++ b/composeApp/src/commonMain/kotlin/domain/grid.kt
@@ -1,5 +1,10 @@
package domain
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.runtime.toMutableStateList
+
class GameRow>(
val category: ItemClassCompanion,
val options: List
- >,
@@ -10,12 +15,12 @@ class Grid(
val rows: List>>
) : List>> by rows {
- fun > indexOf(element: C): Int {
+ fun > indexOf(element: C): Int {
return this[element.companion]
.indexOfFirst { it.selection?.itemType == element }
}
- operator fun > get(itemType: ItemClassCompanion): GameRow {
+ operator fun > get(itemType: ItemClassCompanion): GameRow {
@Suppress("UNCHECKED_CAST")
return rows.first { it.category == itemType } as GameRow
}
@@ -33,10 +38,13 @@ fun List
>>>.toGrid() = Grid(
)
class GameCell>(
- var selection: Item?,
+ selection: Item?,
val solution: Item,
- val options: MutableList- >
-)
+ options: List
- >
+) {
+ val options = options.toMutableStateList()
+ var selection by mutableStateOf(selection)
+}
class Item>(
val itemType: C,
diff --git a/composeApp/src/commonMain/kotlin/domain/items.kt b/composeApp/src/commonMain/kotlin/domain/items.kt
index 5df4e3a..1514402 100644
--- a/composeApp/src/commonMain/kotlin/domain/items.kt
+++ b/composeApp/src/commonMain/kotlin/domain/items.kt
@@ -89,7 +89,7 @@ enum class Fruit(symbol: String) : ItemClass {
PEAR("🍐"),
MANGO("🥭");
- override val symbols: Array = idic(symbol)
+ override val symbols: Array = arrayOf(symbol)
override val companion
get() = Fruit
@@ -110,7 +110,7 @@ enum class Dessert(symbol: String) : ItemClass {
LOLLIPOP("🍭"),
CUSTARD("🍮");
- override val symbols: Array = idic(symbol)
+ override val symbols: Array = arrayOf(symbol)
override val companion
get() = Dessert
@@ -129,7 +129,7 @@ enum class Transportation(symbol: String) : ItemClass {
TRAM_CAR("🚋"),
BUS("🚌");
- override val symbols: Array = idic(symbol)
+ override val symbols: Array = arrayOf(symbol)
override val companion
get() = Transportation
diff --git a/composeApp/src/commonMain/kotlin/ui/selector.kt b/composeApp/src/commonMain/kotlin/ui/selector.kt
index ac0c1d4..ac7808b 100644
--- a/composeApp/src/commonMain/kotlin/ui/selector.kt
+++ b/composeApp/src/commonMain/kotlin/ui/selector.kt
@@ -2,10 +2,11 @@ package ui
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.lazy.grid.GridCells
-import androidx.compose.foundation.lazy.grid.LazyHorizontalGrid
+import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.material3.OutlinedCard
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
@@ -14,7 +15,6 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.drawText
import androidx.compose.ui.text.rememberTextMeasurer
@@ -37,7 +37,11 @@ fun > Selector(
DrawItem(item = selectedItem, modifier = modifier.clickable { onSelectItem(null) })
} else {
OutlinedCard(modifier = modifier.aspectRatio(1f)) {
- LazyHorizontalGrid(rows = GridCells.Fixed(3)) {
+ LazyVerticalGrid(
+ columns = GridCells.Fixed(3),
+ verticalArrangement = Arrangement.Center,
+ horizontalArrangement = Arrangement.Center
+ ) {
for (option in options) {
item {
DrawItem(
@@ -52,7 +56,10 @@ fun > Selector(
}
@Composable
-fun > DrawItem(item: Item, modifier: Modifier = Modifier) {
+fun > DrawItem(
+ modifier: Modifier = Modifier,
+ item: Item
+) {
OutlinedCard(modifier = modifier.aspectRatio(1f)) {
val emoji = item.symbol
@@ -61,7 +68,6 @@ fun > DrawItem(item: Item, modifier: Modifier = Modifier) {
Canvas(
modifier = Modifier.fillMaxSize(1f),
onDraw = {
- drawRect(Color.Red, size = size)
val textSize = textMeasurer.measure(text = emoji)
val minTextSizeDimension = min(
textSize.size.width,
@@ -87,19 +93,3 @@ fun > DrawItem(item: Item, modifier: Modifier = Modifier) {
)
}
}
-
-@Preview
-@Composable
-fun SelectorPreview() {
- val size = 6
- val options = remember { Animals.items.shuffled().take(size) }
- var selectedItem by remember { mutableStateOf
- ?>(Item(options.random())) }
-// var selectedItem by remember { mutableStateOf
- ?>(null) }
-// Selector(
-// category = Animals,
-// options = Animals.items.map { Item(it) },
-// selectedItem = selectedItem,
-// onSelectItem = { selectedItem = it }
-// )
- DrawItem(selectedItem!!)
-}
\ No newline at end of file