Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,17 @@ interface GameDescriptor<S : Any, A : Any, V : Any, C : Any> {
val botNames: List<String> get() = DEFAULT_BOT_NAMES

/**
* A fresh bot strategy for this room. Called once per room and shared by every bot-played seat,
* each with its own seeded [kotlin.random.Random], so the strategy must be stateless.
* A fresh bot strategy for this room's [config]. Called once per room and shared by every
* bot-played seat, each with its own seeded [kotlin.random.Random], so the strategy must be
* stateless.
*
* Takes the config because a bot is a function of the rules it plays under: a house rule that
* adds a card or a bid changes what a correct move is, and a bot built for the wrong ruleset
* misplays rather than failing loudly.
*
* Prefer a cheap heuristic bot: it runs on the server's single vCPU for every abandoned seat.
*/
fun bot(): Strategy<V, A>
fun bot(config: C): Strategy<V, A>

/** The rules for a lobby's negotiated [config] — the game's house-rule toggles applied. */
fun rulesFor(config: C): GameRules<S, A, V>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,13 @@ class Room<S : Any, A : Any, V : Any, C : Any>(
) {
private val logger = LoggerFactory.getLogger("room")
private val commands = Channel<RoomCommand<S, A>>(Channel.UNLIMITED)
private val bot: Strategy<V, A> = descriptor.bot()

private var lobbyConfig = initialConfig

// Built from the config the room was created with. Only the timeouts can change later
// (RoomCommand.Configure), never the house rules, so the bot never goes stale.
private val bot: Strategy<V, A> = descriptor.bot(initialConfig)

// Read cross-thread (isPlaying/resumedState from the Ktor handler & /health), written on the actor.
@Volatile
private var phase = RoomPhase.LOBBY
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ object ToyDescriptor : GameDescriptor<ToyState, ToyAction, ToyView, ToyConfig> {
override val stateSerializer = ToyState.serializer()
override val configSerializer = ToyConfig.serializer()

override fun bot(): Strategy<ToyView, ToyAction> =
override fun bot(config: ToyConfig): Strategy<ToyView, ToyAction> =
Strategy { view, random -> view.legalActions.ifEmpty { listOf(ToyAction.Move(1)) }.random(random) }

override fun rulesFor(config: ToyConfig): GameRules<ToyState, ToyAction, ToyView> = ToyRules(config.target)
Expand Down
Loading