Croupier

Functionality

Allows users to organize and play peer-to-peer card games together. The Syncbase schema supports general card games, and it is up to each application to support games (e.g., Hearts, Solitaire, etc.).

Key Behaviors

Schema

Data Types

// The GameMetadata tracks information about the game creator and status.
// Note: This is new, since the owner doesn't want other players to write to this.
type GameMetadata struct {
  type          string     // The type of the game. Can also be an enum instead of a string.
  owner         Blessing   // Game creator's Blessing string
  status        GameStatus // See below.
}

// The GameStatus informs players how to transition between game setup, play, and cleanup.
type GameStatus int
const (
  Preparing GameStatus iota
  Running
  Complete
)

// The Proposal struct is used to forge a consensus between players.
// This is important when players can make simultaneous and conflicting moves.
// Essentially, this acts as a "lock" on the game log, which is not visible to players.
type Proposal struct {
  timestamp         int     // When the proposal was created.
  command_string    string  // What ought to be run if the proposal goes through.
  player_number     int     // Original player that proposed this command.
}

// The player Settings struct contains information relevant to a user.
// This information is a mix of fixed and customizable data that is public to all players.
// The user is allowed to change their avatar, name, and color in-game.
type Settings struct {
  avatar     string     // Must point to an avatar asset bundled into the app.
  name       string     // The user's display name in-game. Usually a pseudonym.
  color      int        // An 8 digit hex-encoded integer. 0x{alpha}{red}{green}{blue}
  gameID     UUID       // Most recent game ID for this user, may be null if none or if completed.
}

Organization

<AppGUID>/Games<GameUUID>/players/<player number>
// Tracks position of players in game
// Observing players don't write/claim a player number

Games<GameUUID>/player_settings/<Blessing> ->
// Stores collection for player <Blessing>'s settings

Games<GameUUID>/log/commands/<timestamp>-<player number>
// The command for <player number> at <timestamp>

Games<GameUUID>/log/proposals/<player number>
// the command proposal for <player number>

Games<GameUUID>Meta -> GameMetadata*

Settings<Blessing>
//Settings for the player who owns <Blessing>

Note

Games<GameUUID>/log can instead be replaced with a CRDT list. This would also allow players to write their game actions without conflicting with each other.

Syncing and permissions

There are 3 types of collections to be shared. There are 2 types of game collections, and 1 type of settings collection.

The relevant syncgroups are

Games

Every player needs to participate in setting up the game and then playing it. Game creator has Admin and R/W access. All players initially have R/W access. Observing or overflow players will become R-only on Game Start (unless they are the game creator). Those who haven't joined will have no access after Game Start Theoretical: If the game is shared with them, then they get R-only access.

GamesMet

Only the game creator needs to write to the metadata section, since it determines the game type and game status. All players must be able to read this data. Game creator has Admin and R/W access. All other players have R access.

Settings

Everybody should be able to read this section, but only the person who owns this should be able to write to it. The Player who owns has Admin and R/W access All other players only have R access.

Each game advertisement will advertise the collection "Games" and associate it with the other collections, "GamesMeta" and the creator's "Settings".

When joining a game, players will also write down the "Settings" collection ID into the game state. This will allow other players to see their presence in the game.

Conflicts

As aforementioned, conflicts are disallowed by the game's logic, so this isn't handled in the traditional Syncbase sense. In the case where the game structure allows players to make simultaneous but contradictory moves, the game's logic will shift them into using the "proposal system". Once all players agree on a proposal, that move and that move alone is executed.

The game setup phase has players that are part of the game but haven't "sat" down as well as players that have selected their player number. Since players cannot select the same "seat", we can have Syncbase handle the seating conflicts. The app will be able to determine where players are sitting from that. It will also know which players have not sat down by checking either the list of syncgroup members or the set of player setting collections written to the game.