Skip to content

Commit

Permalink
Some changes
Browse files Browse the repository at this point in the history
Signed-off-by: Efeturi Money <[email protected]>
  • Loading branch information
efemoney committed Apr 10, 2024
1 parent 9c237f2 commit a693238
Show file tree
Hide file tree
Showing 28 changed files with 179 additions and 268 deletions.
5 changes: 5 additions & 0 deletions .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions engine/api/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
plugins {
alias(libs.plugins.kotlin.jvm)
}

dependencies {
implementation(libs.kotlin.stdlib)
implementation(libs.kotlinx.immutable)
implementation(libs.kotlinx.coroutines.core)
implementation(libs.jetbrains.compose.runtime)
implementation(libs.jetbrains.compose.ui.util)
}
23 changes: 23 additions & 0 deletions engine/api/src/dev/efemoney/lexiko/engine/api/bag.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package dev.efemoney.lexiko.engine.api

import androidx.compose.runtime.Stable
import androidx.compose.ui.util.fastForEach

@Stable
interface BagOfTiles {
val remainingTilesCount: Int
val isEmpty get() = remainingTilesCount == 0

fun pickRandomTile(): Tile?
fun pickRandomTiles(max: Int): List<Tile> =
if (isEmpty) emptyList() else buildList { for (i in 0..<max) add(pickRandomTile() ?: break) }

fun returnTile(tile: Tile)
fun returnTiles(tiles: List<Tile>) = tiles.fastForEach(::returnTile)
}

interface InitialBagOfTiles : BagOfTiles {
fun pickTile(char: TileChar): Tile?
fun pickTiles(chars: List<TileChar>): List<Tile> =
chars.mapNotNull(::pickTile).also { require(it.size == chars.size) { "Some tiles are not available" } }
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package dev.efemoney.lexiko.engine.api

import androidx.compose.runtime.Stable
import dev.efemoney.lexiko.engine.impl.BoardImpl

@Stable
interface Board {
Expand All @@ -20,16 +19,6 @@ interface MutableBoard : Board {
override operator fun get(position: TilePosition): MutableTileSlot = get(position.row, position.col)
}

fun Board(tilePlacement: TilePlacement = TilePlacement.None): Board =
BoardImpl(initialTilePlacement = tilePlacement)

fun Board(placeTiles: MutableBoard.() -> Unit): Board =
BoardImpl().also(placeTiles)

context(MutableBoard)
fun Tile.placeAt(position: TilePosition) = internal.place(tile = this, at = position)


@Stable
interface TileSlot {
val position: TilePosition
Expand All @@ -42,14 +31,12 @@ interface MutableTileSlot : TileSlot {
}

operator fun TileSlot.component1() = position

operator fun TileSlot.component2() = multiplier

operator fun TileSlot.component3() = tile


@JvmInline
value class TilePlacement private constructor(private val tiles: Map<TilePosition, Tile> = emptyMap()) {
value class TilePlacement private constructor(private val tiles: Map<TilePosition, Tile>) {

constructor(build: Builder.() -> Unit) : this(buildMap { Builder(this).apply(build) })

Expand All @@ -62,25 +49,6 @@ value class TilePlacement private constructor(private val tiles: Map<TilePositio
}

companion object {
val None = TilePlacement()
}
}

// region Internal

internal interface BoardInternal : MutableBoard {
fun place(tile: Tile, at: TilePosition)
fun place(tiles: List<Tile>, startAt: TilePosition, direction: Direction)
}

internal fun interface OnConflict {
operator fun invoke(slot: TileSlot, old: Tile, new: Tile)

companion object {
val DoNothing = OnConflict { _, _, _ -> }
val None = TilePlacement(emptyMap())
}
}

internal val MutableBoard.internal get() = this as BoardInternal

// endregion
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@

package dev.efemoney.lexiko.engine.api

import dev.efemoney.lexiko.engine.impl.packInts
import dev.efemoney.lexiko.engine.impl.requireIn
import dev.efemoney.lexiko.engine.impl.unpackInt1
import dev.efemoney.lexiko.engine.impl.unpackInt2
import androidx.compose.ui.util.packInts
import androidx.compose.ui.util.unpackInt1
import androidx.compose.ui.util.unpackInt2

@JvmInline
value class TilePosition private constructor(private val packed: Long) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,20 @@
package dev.efemoney.lexiko.engine.api

import dev.efemoney.lexiko.engine.impl.DoubleLetterMultiplier
import dev.efemoney.lexiko.engine.impl.DoubleWordMultiplier
import dev.efemoney.lexiko.engine.impl.Multiplier
import dev.efemoney.lexiko.engine.impl.TripleLetterMultiplier
import dev.efemoney.lexiko.engine.impl.TripleWordMultiplier
import dev.efemoney.lexiko.engine.impl.hasMultiplier

class Tile internal constructor(
val char: TileChar,
val point: TilePoint,
) : Comparable<Tile> {

override fun compareTo(other: Tile) = char.compareTo(other.char)

override fun hashCode() = 31 * char.hashCode() + point.hashCode()
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Tile) return false
return char != other.char && point == other.point
}

override fun hashCode() = 31 * char.hashCode() + point.hashCode()
}

@JvmInline
value class TileChar(private val char: Char) {

val value get() = char.uppercaseChar()

init {
Expand All @@ -46,16 +35,28 @@ value class TilePoint(val value: Int) {
}
}

enum class TileMultiplier(internal val value: Multiplier, val string: String) {
sealed interface TileMultiplier {
val string: String

data class Word(private val multiplier: Int) : TileMultiplier {
override val string = "${multiplier}W"
}

data class Letter(private val multiplier: Int) : TileMultiplier {
override val string = "${multiplier}L"
}
}

/*enum class TileMultiplier(internal val value: Multiplier, val string: String) {
TripleWord(TripleWordMultiplier, "3W"),
TripleLetter(TripleLetterMultiplier, "3L"),
DoubleWord(DoubleWordMultiplier, "2W"),
DoubleLetter(DoubleLetterMultiplier, "2L"),
;
internal companion object {
fun forPosition(position: TilePosition) =
fun of(position: TilePosition) =
TileMultiplier.entries.firstOrNull { position.hasMultiplier(it.value) }
}
}
}*/

6 changes: 6 additions & 0 deletions engine/api/src/dev/efemoney/lexiko/engine/api/util.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package dev.efemoney.lexiko.engine.api

internal inline fun Int.requireIn(range: IntRange, lazyMessage: () -> Any): Int {
require(this in range, lazyMessage)
return this
}
7 changes: 7 additions & 0 deletions engine/api/src/dev/efemoney/lexiko/engine/api/word.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package dev.efemoney.lexiko.engine.api

@JvmInline
value class Word(private val tiles: Sequence<Tile>)

@JvmInline
value class Letter(private val tile: Tile)
6 changes: 1 addition & 5 deletions engine/build.gradle.kts → engine/impl/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,12 @@ dependencies {
kotlinCompilerPluginClasspath(libs.androidx.compose.compiler)
ksp(libs.kotlinInject.compiler)

implementation(projects.engine.api)
implementation(libs.kotlin.stdlib)
implementation(libs.kotlinx.immutable)
implementation(libs.kotlinx.coroutines.core)
implementation(libs.jetbrains.compose.runtime)
implementation(libs.jetbrains.compose.ui.util)
implementation(libs.molecule.runtime)
implementation(libs.kotlinInject.runtime)

testImplementation(libs.kotlin.test)
testImplementation(libs.kotlinx.coroutines.test)
testImplementation(libs.turbine)
testImplementation(libs.junit)
}
5 changes: 5 additions & 0 deletions engine/impl/src/dev/efemoney/lexiko/engine/api/bag.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package dev.efemoney.lexiko.engine.api

import dev.efemoney.lexiko.engine.impl.DefaultBagOfTiles

fun BagOfTiles(): BagOfTiles = DefaultBagOfTiles()
53 changes: 53 additions & 0 deletions engine/impl/src/dev/efemoney/lexiko/engine/api/board.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package dev.efemoney.lexiko.engine.api

import dev.efemoney.lexiko.engine.impl.BoardImpl

fun Board(tilePlacement: TilePlacement = TilePlacement.None): Board =
BoardImpl(initialTilePlacement = tilePlacement)

context(InitialBagOfTiles)
fun Board(placeTiles: context(InitialBagOfTiles) MutableBoard.() -> Unit): Board {
return BoardImpl().also { placeTiles(self, it) }
}

context(MutableBoard)
fun Tile.placeAt(position: TilePosition) = internal.place(this, at = position)

@JvmInline
value class TilePlacement private constructor(private val placement: Map<TilePosition, Tile>) {

constructor(build: Builder.() -> Unit) : this(buildMap { Builder(this).apply(build) })

operator fun get(position: TilePosition) = placement[position]

@JvmInline
value class Builder internal constructor(private val map: MutableMap<TilePosition, Tile>) {

infix fun Tile.at(position: TilePosition) = map.put(position, this)
}

companion object {
val None = TilePlacement(emptyMap())
}
}

// region Implementation

private val InitialBagOfTiles.self get() = this

internal interface BoardInternal : MutableBoard {
fun place(tile: Tile, at: TilePosition)
fun place(tiles: List<Tile>, startAt: TilePosition, direction: Direction)
}

internal val Board.internal get() = this as BoardInternal

internal fun interface OnConflict {
operator fun invoke(slot: TileSlot, old: Tile, new: Tile)

companion object {
val DoNothing = OnConflict { _, _, _ -> }
}
}

// endregion
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import dev.efemoney.lexiko.engine.api.Board
import dev.efemoney.lexiko.engine.api.PlayerId
import dev.efemoney.lexiko.engine.events.GameEvent
import dev.efemoney.lexiko.engine.events.GameEventHandlers
import dev.efemoney.lexiko.engine.impl.BagOfTilesImpl
import dev.efemoney.lexiko.engine.impl.BoardImpl
import dev.efemoney.lexiko.engine.impl.DefaultBagOfTiles
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.Channel
Expand All @@ -25,7 +25,7 @@ internal class GameContext(
val host: PlayerId,
val players: SnapshotStateList<PlayerId>,
val board: BoardImpl,
val bag: BagOfTilesImpl,
val bag: DefaultBagOfTiles,
) {
fun send(event: GameEvent) = scope.launch { events.send(event) }
}
Expand All @@ -47,7 +47,7 @@ class Game internal constructor(private val eventHandlers: GameEventHandlers) {
host = host,
players = mutableStateListOf(host),
board = BoardImpl(),
bag = BagOfTilesImpl(),
bag = DefaultBagOfTiles(),
)
}
LaunchedEffect(context) {
Expand Down
Loading

0 comments on commit a693238

Please sign in to comment.