Skip to content

Commit

Permalink
engine settings
Browse files Browse the repository at this point in the history
  • Loading branch information
bqv committed Oct 14, 2023
1 parent ce4f526 commit 0f635a1
Show file tree
Hide file tree
Showing 11 changed files with 123 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ import io.zenandroid.onlinego.data.model.katago.Query
import io.zenandroid.onlinego.data.repositories.SettingsRepository
import io.zenandroid.onlinego.gamelogic.Util
import io.zenandroid.onlinego.utils.recordException
import org.koin.core.context.GlobalContext
import java.io.*
import java.util.*
import java.util.concurrent.atomic.AtomicLong
import org.koin.core.context.GlobalContext.get

object KataGoAnalysisEngine {
var started = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@ import androidx.compose.ui.res.imageResource
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
import io.zenandroid.onlinego.OnlineGoApplication
import io.zenandroid.onlinego.data.model.BoardTheme
import io.zenandroid.onlinego.data.model.Cell
import io.zenandroid.onlinego.data.model.Position
import io.zenandroid.onlinego.data.model.StoneType
import io.zenandroid.onlinego.data.model.ogs.PlayCategory
import io.zenandroid.onlinego.data.repositories.SettingsRepository
import io.zenandroid.onlinego.gamelogic.RulesManager.isPass
import io.zenandroid.onlinego.utils.recordException
import org.koin.core.context.GlobalContext
import kotlin.math.ceil
import kotlin.math.roundToInt
Expand Down Expand Up @@ -68,6 +70,12 @@ fun Board(

// Board background image, it is either a jpg or a svg
val backgroundImage: ImageBitmap? = boardTheme.backgroundImage?.let {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
boardTheme.backgroundImage.run {
Exception("blep: $this, ${OnlineGoApplication.instance.getDrawable(this)}")
.let(::recordException)
}
}
ImageBitmap.imageResource(id = boardTheme.backgroundImage)
}
val backgroundColor: Color? = boardTheme.backgroundColor?.let {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package io.zenandroid.onlinego.ui.screens.localai
import android.app.Activity.RESULT_OK
import android.content.Intent
import android.graphics.Color
import android.graphics.Point
import android.Manifest.permission
import android.net.Uri
import android.os.Bundle
Expand All @@ -21,7 +20,6 @@ import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.transition.DrawableCrossFadeFactory
import com.jakewharton.rxbinding2.view.RxView
import com.jakewharton.rxbinding3.view.clicks
import com.toomasr.sgf4j.Sgf
import com.toomasr.sgf4j.parser.Game
Expand All @@ -30,6 +28,7 @@ import com.vmadalin.easypermissions.*
import io.reactivex.Observable
import io.reactivex.subjects.PublishSubject
import io.zenandroid.onlinego.R
import io.zenandroid.onlinego.data.model.Cell
import io.zenandroid.onlinego.data.model.local.SgfData
import io.zenandroid.onlinego.data.model.Position
import io.zenandroid.onlinego.data.model.StoneType
Expand Down Expand Up @@ -153,6 +152,7 @@ class AiGameFragment : Fragment(), MviView<AiGameState, AiGameAction> {
fadeOutRemovedStones = state.showFinalTerritory
drawAiEstimatedOwnership = state.showAiEstimatedTerritory
ownership = state.aiAnalysis?.ownership
hintBasis = if(state.showHints) state.aiAnalysis?.rootInfo else null
hints = if(state.showHints) state.aiAnalysis?.moveInfos else null
state.position?.let {
position = it
Expand Down Expand Up @@ -262,7 +262,7 @@ class AiGameFragment : Fragment(), MviView<AiGameState, AiGameAction> {

val size = sgf?.getProperty("SZ")?.split(":")?.let { it.plus(it) }?.take(2)
var pos = Position(size!![0].toInt(), size!![1].toInt())
sgf?.getProperty("KM")?.toFloat()?.let { pos.komi = it }
sgf?.getProperty("KM")?.toFloat()?.let { pos = pos.copy(komi = it) }
var handi = sgf?.getProperty("HA")?.toInt()
var name = sgf?.getProperty("GN") ?: data.getPath()
var move = sgf?.getRootNode()?.getNextNode()
Expand All @@ -274,19 +274,22 @@ class AiGameFragment : Fragment(), MviView<AiGameState, AiGameAction> {
else -> null
}!!
if (pos.nextToMove != colour) {
pos = RulesManager.makeMove(pos, pos.nextToMove, Point(-1, -1))!!
pos.nextToMove = pos.nextToMove.opponent
pos = RulesManager.makeMove(pos, pos.nextToMove, Cell(-1, -1))!!.let {
it.copy(
nextToMove = it.nextToMove.opponent
)
}
}
pos = RulesManager.makeMove(pos, colour,
if (move.getMoveString().isNullOrBlank()) {
Point(-1, -1)
Cell(-1, -1)
} else {
move.getCoords().let {
Point(it[0], it[1])
Cell(it[0], it[1])
}
}
)!!
pos.nextToMove = pos.nextToMove.opponent
pos = pos.copy(nextToMove = pos.nextToMove.opponent)
move = move.getNextNode()
}
Log.d("AiGameFragment", "loadPosition(\"${pos}\")")
Expand All @@ -309,10 +312,7 @@ class AiGameFragment : Fragment(), MviView<AiGameState, AiGameAction> {
}
it.komi?.let { game.addProperty("KM", it.toString()) }

var positions = listOf(it)
while (positions.last()!!.parentPosition != null) {
positions = positions.plus(positions.last()!!.parentPosition!!)
}
val positions = state.history
Log.d("AiGameFragment", "Serializing ${positions.size} moves")

var cursor = game.getRootNode()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,13 @@ import io.zenandroid.onlinego.ui.screens.localai.AiGameAction.GenerateAiMove
import io.zenandroid.onlinego.ui.screens.localai.AiGameAction.HideOwnership
import io.zenandroid.onlinego.ui.screens.localai.AiGameAction.NewGame
import io.zenandroid.onlinego.ui.screens.localai.AiGameAction.NewPosition
import io.zenandroid.onlinego.ui.screens.localai.AiGameAction.NextPlayerChanged
import io.zenandroid.onlinego.ui.screens.localai.AiGameAction.PromptUserForMove
import io.zenandroid.onlinego.ui.screens.localai.AiGameAction.RestoredState
import io.zenandroid.onlinego.ui.screens.localai.AiGameAction.ScoreComputed
import io.zenandroid.onlinego.ui.screens.localai.AiGameAction.ShowNewGameDialog
import io.zenandroid.onlinego.ui.screens.localai.AiGameAction.ToggleAIBlack
import io.zenandroid.onlinego.ui.screens.localai.AiGameAction.ToggleAIWhite
import io.zenandroid.onlinego.ui.screens.localai.AiGameAction.UserAskedForHint
import io.zenandroid.onlinego.ui.screens.localai.AiGameAction.UserAskedForOwnership
import io.zenandroid.onlinego.ui.screens.localai.AiGameAction.UserHotTrackedCoordinate
Expand Down Expand Up @@ -176,7 +179,7 @@ class AiGameReducer : Reducer<AiGameState, AiGameAction> {
chatText = "An error occurred communicating with the AI"
)
UserPressedPrevious -> {
val newPosition = if(aiMovedLast(state) && !aiOnlyGame(state)) state.history.dropLast(2)
val newHistory = if(aiMovedLast(state) && !aiOnlyGame(state)) state.history.dropLast(2)
else state.history.dropLast(1)
val removedHistory = if(aiMovedLast(state) && !aiOnlyGame(state)) state.history.takeLast(2)
else state.history.takeLast(1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ class AnalyticsMiddleware: Middleware<AiGameState, AiGameAction> {
UserAskedForOwnership -> analytics.logEvent("ai_game_user_asked_territory", null)
is UserTriedSuicidalMove -> analytics.logEvent("ai_game_user_tried_suicide", null)
is UserTriedKoMove -> analytics.logEvent("ai_game_user_tried_ko", null)
NextPlayerChanged -> analytics.logEvent("ai_game_next_player_changed", null)
ToggleAIBlack -> analytics.logEvent("ai_game_toggled_ai_black", null)
ToggleAIWhite -> analytics.logEvent("ai_game_toggled_ai_white", null)
}
}
.switchMap { Observable.empty<AiGameAction>() }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import androidx.compose.material.MaterialTheme
import androidx.compose.material.OutlinedTextField
import androidx.compose.material.Surface
import androidx.compose.material.Switch
import androidx.compose.material.Slider
import androidx.compose.material.Text
import androidx.compose.material.TextButton
import androidx.compose.material.icons.Icons
Expand All @@ -44,11 +45,13 @@ import androidx.compose.material.icons.filled.Notifications
import androidx.compose.material.icons.filled.Visibility
import androidx.compose.material.icons.filled.VisibilityOff
import androidx.compose.material.icons.filled.VolumeUp
import androidx.compose.material.icons.rounded.AccountTree
import androidx.compose.material.icons.rounded.DarkMode
import androidx.compose.material.icons.rounded.HeartBroken
import androidx.compose.material.icons.rounded.Logout
import androidx.compose.material.icons.rounded.MilitaryTech
import androidx.compose.material.icons.rounded.Palette
import androidx.compose.material.icons.rounded.Psychology
import androidx.compose.material.icons.rounded._123
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
Expand Down Expand Up @@ -97,7 +100,9 @@ import io.zenandroid.onlinego.ui.screens.settings.SettingsAction.CoordinatesClic
import io.zenandroid.onlinego.ui.screens.settings.SettingsAction.DeleteAccountCanceled
import io.zenandroid.onlinego.ui.screens.settings.SettingsAction.DeleteAccountClicked
import io.zenandroid.onlinego.ui.screens.settings.SettingsAction.DeleteAccountConfirmed
import io.zenandroid.onlinego.ui.screens.settings.SettingsAction.DetailedAnalysisClicked
import io.zenandroid.onlinego.ui.screens.settings.SettingsAction.LogoutClicked
import io.zenandroid.onlinego.ui.screens.settings.SettingsAction.MaxVisitsChanged
import io.zenandroid.onlinego.ui.screens.settings.SettingsAction.NotificationsClicked
import io.zenandroid.onlinego.ui.screens.settings.SettingsAction.PrivacyClicked
import io.zenandroid.onlinego.ui.screens.settings.SettingsAction.RanksClicked
Expand Down Expand Up @@ -407,6 +412,24 @@ fun SettingsScreen(state: SettingsState, onAction: (SettingsAction) -> Unit) {
)
}
}
Section(title = "Engine Settings") {
Column(modifier = Modifier) {
SettingsRow(
title = "Max AI Playouts",
icon = Rounded.AccountTree,
slider = Pair(10.0,9999.0),
position = state.maxVisits,
onValueChanged = { onAction(MaxVisitsChanged(it)) }
)
SettingsRow(
title = "Detailed AI Analysis",
icon = Rounded.Psychology,
checkbox = true,
checked = state.detailedAnalysis,
onClick = { onAction(DetailedAnalysisClicked) }
)
}
}
Section(title = "Account") {
Column(modifier = Modifier) {
SettingsRow(
Expand Down Expand Up @@ -453,10 +476,13 @@ private fun SettingsRow(
icon: ImageVector,
checkbox: Boolean = false,
checked: Boolean = false,
slider: Pair<Double, Double>? = null,
position: Double = 0.0,
value: String? = null,
possibleValues: List<Any> = emptyList(),
onClick: () -> Unit = {},
onValueClick: (String) -> Unit = {},
onValueChanged: (Double) -> Unit = {},
) {
var menuOpen by remember { mutableStateOf(false) }
Row(
Expand Down Expand Up @@ -488,9 +514,27 @@ private fun SettingsRow(
if(checkbox) {
Switch(
checked = checked,
onCheckedChange = { onClick()},
onCheckedChange = { onClick() },
modifier = Modifier.padding(end = 12.dp)
)
} else if(slider != null) {
Slider(
value = Math.log(position).toFloat(),
onValueChange = { onValueChanged(Math.exp(it.toDouble())) },
steps = 10,
valueRange = Math.log(slider.first).toFloat()..Math.log(slider.second).toFloat(),
modifier = Modifier.weight(1f).padding(end = 12.dp)
)
Text(
text = position.toInt().toString().padStart(8),
fontSize = 14.sp,
style = TextStyle(
fontWeight = FontWeight.Normal,
fontSize = 12.sp,
letterSpacing = 0.4.sp
),
modifier = Modifier.padding(end = 16.dp, bottom = 16.dp, top = 16.dp)
)
} else if(value != null) {
Box {
Text(
Expand Down Expand Up @@ -583,4 +627,4 @@ private fun SettingsScreenPreview() {
), {})
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ import io.zenandroid.onlinego.ui.screens.settings.SettingsAction.CoordinatesClic
import io.zenandroid.onlinego.ui.screens.settings.SettingsAction.DeleteAccountCanceled
import io.zenandroid.onlinego.ui.screens.settings.SettingsAction.DeleteAccountClicked
import io.zenandroid.onlinego.ui.screens.settings.SettingsAction.DeleteAccountConfirmed
import io.zenandroid.onlinego.ui.screens.settings.SettingsAction.DetailedAnalysisClicked
import io.zenandroid.onlinego.ui.screens.settings.SettingsAction.LogoutClicked
import io.zenandroid.onlinego.ui.screens.settings.SettingsAction.MaxVisitsChanged
import io.zenandroid.onlinego.ui.screens.settings.SettingsAction.NotificationsClicked
import io.zenandroid.onlinego.ui.screens.settings.SettingsAction.PrivacyClicked
import io.zenandroid.onlinego.ui.screens.settings.SettingsAction.RanksClicked
Expand All @@ -37,6 +39,8 @@ class SettingsViewModel(
sounds = settingsRepository.sound,
ranks = settingsRepository.showRanks,
coordinates = settingsRepository.showCoordinates,
maxVisits = settingsRepository.maxVisits.toDouble(),
detailedAnalysis = settingsRepository.detailedAnalysis,
username = userSessionRepository.uiConfig?.user?.username ?: "",
avatarURL = userSessionRepository.uiConfig?.user?.icon,
)
Expand All @@ -54,6 +58,16 @@ class SettingsViewModel(
state.update { it.copy(ranks = !it.ranks) }
}

is MaxVisitsChanged -> {
settingsRepository.maxVisits = action.value.toInt()
state.update { it.copy(maxVisits = action.value) }
}

DetailedAnalysisClicked -> {
settingsRepository.detailedAnalysis = !settingsRepository.detailedAnalysis
state.update { it.copy(detailedAnalysis = !it.detailedAnalysis) }
}

SoundsClicked -> {
settingsRepository.sound = !state.value.sounds
state.update { it.copy(sounds = !it.sounds) }
Expand Down Expand Up @@ -158,6 +172,8 @@ data class SettingsState(
val sounds: Boolean = true,
val ranks: Boolean = true,
val coordinates: Boolean = true,
val maxVisits: Double = 30.0,
val detailedAnalysis: Boolean = false,
val username: String = "",
val avatarURL: String? = null,
val passwordDialogVisible: Boolean = false,
Expand All @@ -171,11 +187,13 @@ sealed interface SettingsAction {
data class ThemeClicked(val theme: String) : SettingsAction
data class BoardThemeClicked(val boardDisplayName: String) : SettingsAction
data object CoordinatesClicked : SettingsAction
data class MaxVisitsChanged(val value: Double) : SettingsAction
data object DetailedAnalysisClicked : SettingsAction
data object RanksClicked : SettingsAction
data object LogoutClicked : SettingsAction
data object DeleteAccountClicked : SettingsAction
data object DeleteAccountCanceled : SettingsAction
data class DeleteAccountConfirmed(val password: String) : SettingsAction
data object PrivacyClicked : SettingsAction
data object SupportClicked : SettingsAction
}
}
20 changes: 11 additions & 9 deletions app/src/main/java/io/zenandroid/onlinego/ui/views/BoardView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ import io.zenandroid.onlinego.data.model.StoneType
import io.zenandroid.onlinego.data.model.katago.MoveInfo
import io.zenandroid.onlinego.data.model.ogs.PlayCategory
import io.zenandroid.onlinego.gamelogic.Util
import io.zenandroid.onlinego.data.model.katago.MoveInfo
import io.zenandroid.onlinego.data.model.katago.RootInfo
import io.zenandroid.onlinego.data.repositories.SettingsRepository
import org.koin.core.context.GlobalContext
import java.util.*
import kotlin.math.abs
import kotlin.math.ceil
Expand All @@ -42,7 +42,7 @@ import kotlin.math.roundToInt
* that is passed to it via setPosition()
*/
class BoardView : View {
private val settingsRepository: SettingsRepository = get().get()
private val settingsRepository: SettingsRepository = GlobalContext.get().get()

var boardWidth = 19
set(boardWidth) {
Expand Down Expand Up @@ -154,6 +154,7 @@ class BoardView : View {
}
field = value
}
var hintBasis: RootInfo? = null
var hints: List<MoveInfo>? = null
var ownership: List<Float>? = null

Expand Down Expand Up @@ -451,16 +452,17 @@ class BoardView : View {

private fun drawHints(canvas: Canvas, position: Position) {
hints?.let {
//val root = position.aiAnalysisResult?.rootInfo
val moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build()
//val adapter = moshi.adapter(RootInfo::class.java)
val adapter = moshi.adapter(MoveInfo::class.java)
val adapter = moshi.adapter(RootInfo::class.java)
Log.d("BoardView", "Root: ${hintBasis?.let { adapter.toJson(it) }}")
for((index, hint) in it.withIndex()) {
val winrateHighest = hints?.map { it.winrate }.filterNotNull().maxOrNull() ?: 100f
val winrateLowest = hints?.map { it.winrate }.filterNotNull().minOrNull() ?: 0f
val adapter = moshi.adapter(MoveInfo::class.java)
Log.d("BoardView", "Hint: ${hint?.let { adapter.toJson(it) }}")
val winrateHighest = hints?.map { it.winrate }.orEmpty().maxOrNull() ?: 100f
val winrateLowest = hints?.map { it.winrate }.orEmpty().minOrNull() ?: 0f
val winrate = hint.winrate * 100
val playouts = hint.visits
val blackScoreDiff = hint.scoreLead.minus(root?.scoreLead ?: 0f)
val blackScoreDiff = hint.scoreLead.minus(hintBasis?.scoreLead ?: 0f)
val scoreDiff = blackScoreDiff *
if(position.nextToMove == StoneType.WHITE) -1 else 1

Expand Down Expand Up @@ -490,7 +492,7 @@ class BoardView : View {
Log.d("BoardView", "Prediction: ${adapter.toJson(hint)}")
val height = aiTextPaint.getFontMetrics().let { it.ascent - it.descent }
drawTextCentred(canvas, aiTextPaint, "${String.format("%.2g", scoreDiff)}", center.x, center.y - height)
drawTextCentred(canvas, aiTextPaint, "#${index + 1} | ${playouts} ", center.x, center.y)
drawTextCentred(canvas, aiTextPaint, "#${index + 1} | ${playouts}x ", center.x, center.y)
aiTextPaint.let {
it.setTypeface(Typeface.create(it.getTypeface(), Typeface.BOLD))
}
Expand Down
9 changes: 9 additions & 0 deletions app/src/main/res/drawable/ic_menu.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="@color/buttonEnabled"
android:pathData="M3,18h18v-2L3,16v2zM3,13h18v-2L3,11v2zM3,6v2h18L21,6L3,6z"/>
</vector>
Loading

0 comments on commit 0f635a1

Please sign in to comment.