Skip to content

Commit

Permalink
Updated the Automatch to the new OGS design.
Browse files Browse the repository at this point in the history
  • Loading branch information
acristescu committed Jan 24, 2025
1 parent e5a09f5 commit aa8195d
Show file tree
Hide file tree
Showing 9 changed files with 159 additions and 76 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ data class OGSAutomatch(
val game_id: Long?,
val size_speed_options: List<SizeSpeedOption>?
) {
val liveOrBlitz: Boolean
get() = size_speed_options?.find { it.speed == "blitz" || it.speed == "live" } != null
val liveOrBlitzOrRapid: Boolean
get() = size_speed_options?.find { it.speed == "blitz" || it.speed == "live" || it.speed == "rapid" } != null
}

data class SizeSpeedOption(
Expand All @@ -24,10 +24,11 @@ enum class Size {
}
}
enum class Speed {
BLITZ, NORMAL, LONG;
BLITZ, RAPID, LIVE, LONG;
fun getText() = when(this) {
BLITZ -> "blitz"
NORMAL -> "live"
RAPID -> "rapid"
LIVE -> "live"
LONG -> "correspondence"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -306,33 +306,35 @@ class OGSWebSocketService(
, BackpressureStrategy.BUFFER)
}

fun startAutomatch(sizes: List<Size>, speed: Speed) : String {
fun startAutomatch(sizes: List<Size>, speeds: List<Speed>) : String {
val uuid = UUID.randomUUID().toString()

emit("automatch/find_match"){
"uuid" - uuid
"size_speed_options" - createJsonArray {
sizes.forEach { size ->
put(json {
"size" - size.getText()
"speed" - speed.getText()
})
speeds.forEach { speed ->
sizes.forEach { size ->
put(json {
"size" - size.getText()
"speed" - speed.getText()
"system" - "byoyomi"
})
put(json {
"size" - size.getText()
"speed" - speed.getText()
"system" - "fischer"
})
}
}
}
"lower_rank_diff" - 6
"upper_rank_diff" - 6
"rules" - json {
"condition" - "no-preference"
"condition" - "required"
"value" - "japanese"
}
"time_control" - json {
"condition" - "no-preference"
"value" - json {
"system" - "byoyomi"
}
}
"handicap" - json {
"condition" - "no-preference"
"condition" - "preferred"
"value" - "enabled"
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ class AutomatchRepository(

override fun onSocketDisconnected() {
automatches = automatches.builder().apply {
removeAll { it.liveOrBlitz }
removeAll { it.liveOrBlitzOrRapid }
}.build()
automatchesSubject.onNext(automatches)
subscriptions.clear()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
Expand Down Expand Up @@ -75,7 +76,7 @@ class NewAutomatchChallengeBottomSheet : BottomSheetDialogFragment() {
onSmallCheckChanged = { viewModel.onSmallCheckChanged(it) },
onMediumCheckChanged = { viewModel.onMediumCheckChanged(it) },
onLargeCheckChanged = { viewModel.onLargeCheckChanged(it) },
onSpeedChanged = { viewModel.onSpeedChanged(it) },
onSpeedChanged = viewModel::onSpeedChanged,
onSearchClicked = {
dismiss()
val selectedSizes = mutableListOf<Size>()
Expand All @@ -88,7 +89,7 @@ class NewAutomatchChallengeBottomSheet : BottomSheetDialogFragment() {
if (state.large) {
selectedSizes.add(Size.LARGE)
}
(activity as? MainActivity)?.onAutomatchSearchClicked(state.speed, selectedSizes)
(activity as? MainActivity)?.onAutomatchSearchClicked(state.speeds, selectedSizes)
}
)
}
Expand All @@ -103,7 +104,7 @@ private fun NewAutomatchChallengeBottomSheetContent(
onSmallCheckChanged: (Boolean) -> Unit,
onMediumCheckChanged: (Boolean) -> Unit,
onLargeCheckChanged: (Boolean) -> Unit,
onSpeedChanged: (Speed) -> Unit,
onSpeedChanged: (Speed, Boolean) -> Unit,
onSearchClicked: () -> Unit,
modifier: Modifier = Modifier
) {
Expand All @@ -112,6 +113,11 @@ private fun NewAutomatchChallengeBottomSheetContent(
modifier
.padding(16.dp)
) {
Text(
text = "Auto-match",
fontWeight = FontWeight.Bold,
modifier = Modifier.padding(vertical = 4.dp)
)
Text(text = "Try your hand at a game against a human opponent of similar rating to you.")
Text(
text = "Game size",
Expand All @@ -130,40 +136,33 @@ private fun NewAutomatchChallengeBottomSheetContent(
fontWeight = FontWeight.Bold,
modifier = Modifier.padding(top = 16.dp)
)
Box {
var expanded by remember { mutableStateOf(false) }
Text(
text = state.speed.getText()
.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.ENGLISH) else it.toString() },
color = MaterialTheme.colors.primary,
modifier = Modifier
.clickable {
expanded = true
}
.padding(top = 4.dp)
.fillMaxWidth()
)
DropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false },
modifier = Modifier.fillMaxWidth()
) {
Speed.entries.forEach {
DropdownMenuItem(onClick = {
expanded = false
onSpeedChanged(it)
}) {
Text(text = it.getText()
.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.ENGLISH) else it.toString() })
}
}
}
Row {
SizeCheckbox(checked = state.speeds.contains(Speed.BLITZ), text = "Blitz", onClick = {onSpeedChanged(Speed.BLITZ, it)})
Spacer(modifier = Modifier.weight(1f))
SizeCheckbox(checked = state.speeds.contains(Speed.RAPID), text = "Rapid", onClick = {onSpeedChanged(Speed.RAPID, it)})
Spacer(modifier = Modifier.weight(1f))
SizeCheckbox(checked = state.speeds.contains(Speed.LIVE), text = "Live", onClick = {onSpeedChanged(Speed.LIVE, it)})
}
Text(
text = "or",
fontStyle = FontStyle.Italic,
modifier = Modifier
.padding(top = 4.dp)
.align(Alignment.CenterHorizontally)
)
Row {
SizeCheckbox(checked = state.speeds.contains(Speed.LONG), text = "Correspondence", onClick = {onSpeedChanged(Speed.LONG, it)})
}
Text(
text = "Expected duration: ${state.duration}",
fontStyle = FontStyle.Italic,
modifier = Modifier.padding(top = 16.dp).align(Alignment.CenterHorizontally)
)
Button(
modifier = Modifier
.fillMaxWidth()
.padding(top = 16.dp),
enabled = state.isAnySizeSelected,
enabled = state.isAnySizeSelected && state.speeds.isNotEmpty(),
onClick = onSearchClicked
) {
Text("Search")
Expand Down Expand Up @@ -197,6 +196,6 @@ private fun RowScope.SizeCheckbox(checked: Boolean, text: String, onClick: (Bool
private fun NewAutomatchChallengeBottomSheetPreview() {
OnlineGoTheme {
Box(modifier = Modifier.fillMaxSize())
NewAutomatchChallengeBottomSheetContent(AutomatchState(), {}, {}, {}, {}, {})
NewAutomatchChallengeBottomSheetContent(AutomatchState(), {}, {}, {}, {_,_ -> }, {})
}
}
Original file line number Diff line number Diff line change
@@ -1,57 +1,138 @@
package io.zenandroid.onlinego.ui.screens.automatch

import android.preference.PreferenceManager
import androidx.compose.runtime.Immutable
import androidx.lifecycle.ViewModel
import io.zenandroid.onlinego.OnlineGoApplication
import io.zenandroid.onlinego.data.model.ogs.Speed
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.update

private val durationsSmall = arrayOf(5, 10, 15)
private val durationsMedium = arrayOf(10, 20, 30)
private val durationsLarge = arrayOf(15, 25, 40)

class NewAutomatchChallengeViewModel : ViewModel() {
companion object {
private const val SEARCH_GAME_SMALL = "SEARCH_GAME_SMALL"
private const val SEARCH_GAME_MEDIUM = "SEARCH_GAME_MEDIUM"
private const val SEARCH_GAME_LARGE = "SEARCH_GAME_LARGE"
private const val SEARCH_GAME_SPEED = "SEARCH_GAME_SPEED"
private const val SEARCH_GAME_SPEEDS = "SEARCH_GAME_SPEEDS"
}

private val prefs = PreferenceManager.getDefaultSharedPreferences(OnlineGoApplication.instance)
val state = MutableStateFlow(
AutomatchState(
small = prefs.getBoolean(SEARCH_GAME_SMALL, true),
medium = prefs.getBoolean(SEARCH_GAME_MEDIUM, false),
large = prefs.getBoolean(SEARCH_GAME_LARGE, false),
speed = Speed.valueOf(prefs.getString(SEARCH_GAME_SPEED, Speed.NORMAL.name)!!)
val state: MutableStateFlow<AutomatchState> =
MutableStateFlow(
AutomatchState(
small = prefs.getBoolean(SEARCH_GAME_SMALL, true),
medium = prefs.getBoolean(SEARCH_GAME_MEDIUM, false),
large = prefs.getBoolean(SEARCH_GAME_LARGE, false),
speeds = prefs.getString(SEARCH_GAME_SPEEDS, "BLITZ,RAPID,LIVE")!!
.split(",")
.filter { it.isNotBlank() }
.map {
Speed.valueOf(it.trim())
},
).let { it.copy(duration = calculateDuration(it)) }
)
)


fun onSmallCheckChanged(checked: Boolean) {
state.update { it.copy(small = checked) }
state.update {
it.copy(
small = checked,
).let { it.copy(duration = calculateDuration(it)) }
}
prefs.edit().putBoolean(SEARCH_GAME_SMALL, checked).apply()
}

fun onMediumCheckChanged(checked: Boolean) {
state.update { it.copy(medium = checked) }
state.update {
it.copy(
medium = checked,
).let { it.copy(duration = calculateDuration(it)) }
}
prefs.edit().putBoolean(SEARCH_GAME_MEDIUM, checked).apply()
}

fun onLargeCheckChanged(checked: Boolean) {
state.update { it.copy(large = checked) }
state.update {
it.copy(
large = checked,
).let { it.copy(duration = calculateDuration(it)) }
}
prefs.edit().putBoolean(SEARCH_GAME_LARGE, checked).apply()
}

fun onSpeedChanged(speed: Speed) {
state.update { it.copy(speed = speed) }
prefs.edit().putString(SEARCH_GAME_SPEED, speed.toString()).apply()
fun onSpeedChanged(speed: Speed, checked: Boolean) {
val speeds = state.value.speeds.toMutableList()
if (checked) {
speeds.add(speed)
} else {
speeds.remove(speed)
}
if (speed in arrayOf(Speed.LIVE, Speed.RAPID, Speed.BLITZ) && checked) {
speeds.remove(Speed.LONG)
}
if (speed == Speed.LONG && checked) {
speeds.remove(Speed.LIVE)
speeds.remove(Speed.RAPID)
speeds.remove(Speed.BLITZ)
}
state.update {
it.copy(
speeds = speeds,
).let { it.copy(duration = calculateDuration(it)) }
}
prefs.edit().putString(SEARCH_GAME_SPEEDS, speeds.joinToString { it.toString() }).apply()
}

private fun calculateDuration(state: AutomatchState): String {
if (state.speeds.isEmpty() || !state.isAnySizeSelected) {
return ""
}
if (state.speeds.contains(Speed.LONG)) {
return "several days"
}
val durationsMin = when {
state.small -> durationsSmall
state.medium -> durationsMedium
state.large -> durationsLarge
else -> durationsSmall
}
val durationsMax = when {
state.large -> durationsLarge
state.medium -> durationsMedium
state.small -> durationsSmall
else -> durationsSmall
}
val minDuration = when {
state.speeds.contains(Speed.BLITZ) -> durationsMin[0]
state.speeds.contains(Speed.RAPID) -> durationsMin[1]
state.speeds.contains(Speed.LIVE) -> durationsMin[2]
else -> durationsMin[0]
}
val maxDuration = when {
state.speeds.contains(Speed.LIVE) -> durationsMax[2]
state.speeds.contains(Speed.RAPID) -> durationsMax[1]
state.speeds.contains(Speed.BLITZ) -> durationsMax[0]
else -> durationsMax[0]
}
return if (minDuration == maxDuration) {
"$minDuration minutes"
} else {
"$minDuration to $maxDuration minutes"
}
}
}

@Immutable
data class AutomatchState(
val small: Boolean = true,
val medium: Boolean = false,
val large: Boolean = false,
val speed: Speed = Speed.NORMAL,
val speeds: List<Speed> = listOf(Speed.LIVE, Speed.RAPID, Speed.BLITZ),
val duration: String = ""
) {
val isAnySizeSelected: Boolean
get() = small || medium || large
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -270,13 +270,13 @@ class MainActivity : AppCompatActivity(), MainContract.View {
Toast.makeText(this, msg, Toast.LENGTH_LONG).show()
}

fun onAutomatchSearchClicked(speed: Speed, sizes: List<Size>) {
fun onAutomatchSearchClicked(speeds: List<Speed>, sizes: List<Size>) {
val params = Bundle().apply {
putString("SPEED", speed.toString())
putString("SPEED", speeds.joinToString { it.toString() })
putString("SIZE", sizes.joinToString { it.toString() })
}
analytics.logEvent("new_game_search", params)
presenter.onStartSearch(sizes, speed)
presenter.onStartSearch(sizes, speeds)
}

fun onAutoMatchSearch() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ interface MainContract {
interface Presenter {
fun subscribe()
fun unsubscribe()
fun onStartSearch(sizes: List<Size>, speed: Speed)
fun onStartSearch(sizes: List<Size>, speed: List<Speed>)
fun onNewBotChallenge(challengeParams: ChallengeParams)
fun onNewFriendChallenge(challengeParams: ChallengeParams)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,11 @@ class MainPresenter (
socketService.disconnect()
}

override fun onStartSearch(sizes: List<Size>, speed: Speed) {
if(speed in arrayOf(Speed.NORMAL, Speed.BLITZ) && automatchRepository.automatches.find { it.liveOrBlitz } != null) {
view.showError("Can only search for one live or blitz game at a time.")
override fun onStartSearch(sizes: List<Size>, speeds: List<Speed>) {
if((speeds.contains(Speed.LIVE) || speeds.contains(Speed.RAPID) || speeds.contains(Speed.BLITZ)) && automatchRepository.automatches.find { it.liveOrBlitzOrRapid } != null) {
view.showError("Can only search for one live, rapid or blitz game at a time.")
} else {
socketService.startAutomatch(sizes, speed)
socketService.startAutomatch(sizes, speeds)
}
}

Expand Down
Loading

0 comments on commit aa8195d

Please sign in to comment.