Documentation ¶
Overview ¶
Package trivialpoursuit implements a backend for a multi player trivial poursuit game, where questions are (short) maths questions.
Package trivial implements a game controller for one group of players, handling concurrency. It is meant to be used by a server with websocket connections for the players, but is actually network agnostic.
Index ¶
- Constants
- Variables
- type Answer
- type Categorie
- type ClientEvent
- type ClientEventITF
- type ClientEventITFWrapper
- type ClientMove
- type Connection
- type DiceClicked
- type DiceThrow
- type Events
- type GameEnd
- type GameStart
- type GameState
- type GameTerminated
- type LaunchStrategy
- type LobbyUpdate
- type Move
- type Options
- type Ping
- type Player
- type PlayerAnswerResults
- type PlayerID
- type PlayerJoin
- type PlayerLeft
- type PlayerReconnected
- type PlayerStatus
- type PlayerTurn
- type PlayersStillInQuestionResult
- type PossibleMoves
- type QR
- type QuestionContent
- type QuestionPool
- type QuestionReview
- type Replay
- type Room
- func (r *Room) HasStarted() bool
- func (r *Room) Join(player Player, connection Connection) error
- func (r *Room) Listen(ctx context.Context) (replay Replay, naturalEnding bool)
- func (r *Room) NbActivePlayers() int
- func (r *Room) Options() Options
- func (r *Room) StartGame() error
- func (r *Room) Summary() Summary
- type RoomID
- type RoomSize
- type ServerEvent
- type ServerEventWrapper
- type ShowQuestion
- type StateUpdate
- type Success
- type SuccessHandler
- type Summary
- type WantNextTurn
- type WeigthedQuestions
Constants ¶
const ( AnswerClKind = "Answer" ClientMoveClKind = "ClientMove" DiceClickedClKind = "DiceClicked" PingClKind = "Ping" WantNextTurnClKind = "WantNextTurn" )
const ( DiceThrowSeKind = "DiceThrow" GameEndSeKind = "GameEnd" GameStartSeKind = "GameStart" GameTerminatedSeKind = "GameTerminated" LobbyUpdateSeKind = "LobbyUpdate" MoveSeKind = "Move" PlayerAnswerResultsSeKind = "PlayerAnswerResults" PlayerJoinSeKind = "PlayerJoin" PlayerLeftSeKind = "PlayerLeft" PlayerReconnectedSeKind = "PlayerReconnected" PlayerTurnSeKind = "PlayerTurn" PlayersStillInQuestionResultSeKind = "PlayersStillInQuestionResult" PossibleMovesSeKind = "PossibleMoves" ShowQuestionSeKind = "ShowQuestion" )
const NbCategories = int(nbCategories)
NbCategories is the number of categories of question
Variables ¶
var ( WarningLogger = log.New(os.Stdout, "tv-game:ERROR: ", 0) ProgressLogger = log.New(os.Stdout, "tv-game:INFO : ", 0) )
var ( // Board is the Trivial-Poursuit board game shape. Board = board{ 0: {1: true, nbSquares - 1: true}, 1: {0: true, 2: true}, 2: {1: true, 3: true}, 3: {2: true, 4: true, nbSquares - 3: true}, 4: {3: true, 5: true}, 5: {4: true, 6: true}, 6: {5: true, 7: true}, 7: {6: true, 8: true}, 8: {7: true, 9: true}, 9: {8: true, 10: true, nbSquares - 2: true}, 10: {9: true, 11: true}, 11: {10: true, 12: true}, 12: {11: true, 13: true}, 13: {12: true, 14: true}, 14: {13: true, 3: true}, 15: {16: true, 9: true}, 16: {15: true, 0: true}, } )
var ErrGameStarted = errors.New("game already started")
ErrGameStarted is returned from `Join` when the game has already started
var GameStartDelay = time.Second // reduced in tests to avoid latency
Functions ¶
This section is empty.
Types ¶
type Answer ¶
type Answer struct {
Answer client.QuestionAnswersIn
}
the proposition of a client to a question
type ClientEvent ¶
type ClientEvent struct { Event ClientEventITF // as send by the client Player PlayerID // filled by the server }
ClientEvent is a game event send by a known player
type ClientEventITF ¶
type ClientEventITF interface {
// contains filtered or unexported methods
}
ClientEventITF is the common interface for events send by a student client to the game server
type ClientEventITFWrapper ¶
type ClientEventITFWrapper struct {
Data ClientEventITF
}
ClientEventITFWrapper may be used as replacements for ClientEventITF when working with JSON
func (ClientEventITFWrapper) MarshalJSON ¶
func (item ClientEventITFWrapper) MarshalJSON() ([]byte, error)
func (*ClientEventITFWrapper) UnmarshalJSON ¶
func (out *ClientEventITFWrapper) UnmarshalJSON(src []byte) error
type ClientMove ¶
type ClientMove Move
type Connection ¶
type Connection interface {
WriteJSON(v interface{}) error
}
Connection abstracts away the network technology used to communicate back to the client `WriteJSON` will be called from the event goroutine started by `Room.Listen`, so that implementations should support one concurrent write, as it is the case for gorilla/websocket.Connection
type DiceClicked ¶
type DiceClicked struct{}
DiceClicked is emitted when the current player throws the dice
type DiceThrow ¶
type DiceThrow struct {
Face uint8
}
DiceThrow represents the result obtained when throwing a dice
type GameEnd ¶
type GameEnd struct { QuestionDecrassageIds map[serial][]editor.IdQuestion // player->questions Winners []serial WinnerNames []string Advances map[serial]events.EventNotification }
GameEnd is emitted when at least one player has won
type GameState ¶
type GameState struct { Players map[serial]PlayerStatus // per-player advance PlayerTurn serial // the player currently playing (choosing where to move) PawnTile int // position of the pawn }
GameState represents an on-going game.
type GameTerminated ¶
type GameTerminated struct{}
GameTerminated is emitted when the game is manually terminated by the teacher
type LaunchStrategy ¶
type LaunchStrategy struct { // If manual is [true], the game must be started // with [Room.StartGame] Manual bool // Max is the required number of players to start // a game in auto mode. // It is 0 in manual mode, > 0 in auto mode Max int }
func (LaunchStrategy) String ¶
func (ls LaunchStrategy) String() string
type LobbyUpdate ¶
type Move ¶
type Move struct { // the tiles to go through to animate the move // (only valid when send by the server) Path []int Tile int }
Move is emitted when a player choose to Move the pawn
type Options ¶
type Options struct { // QuestionPool is the list of the question // being asked, for each category Questions QuestionPool Launch LaunchStrategy // QuestionTimeout is the time limit for one question QuestionTimeout time.Duration ShowDecrassage bool // Every player start with [StartNbSuccess] success, which // should be zero in regular use, but may be higher for // testing purposes. StartNbSuccess int }
Options is the configuration of one game. All fields are required.
type Player ¶
type Player struct { ID PlayerID // Pseudo is the display name of each player, // which may change during a game (upon deconnection/reconnection) Pseudo string // PseudoSuffix is added to [Pseudo] when two players // have the same pseudo PseudoSuffix string // Isyro global rank for registrer players, or 0 Rank int }
Player represents one player.
type PlayerAnswerResults ¶
type PlayerAnswerResults struct { Categorie Categorie Results map[serial]playerAnswerResult Advances map[serial]events.EventNotification }
PlayerAnswerResults indicates if the players have answered correctly to the current question
type PlayerID ¶
type PlayerID string
PlayerID is a unique identifier of each player, usually generated at the first connection. It is used to handle reconnection and external monitoring of the players
type PlayerJoin ¶
type PlayerJoin struct {
Player serial
}
PlayerJoin is only emitted to the actual player who join the game
type PlayerLeft ¶
type PlayerLeft struct {
Player serial
}
type PlayerReconnected ¶
type PlayerReconnected struct { ID serial Pseudo string }
type PlayerStatus ¶
type PlayerStatus struct { Name string Review QuestionReview Success Success // Has the player disconnect ? IsInactive bool Rank int // added in v1.9 }
PlayerStatus exposes the information about one player
type PlayerTurn ¶
type PlayerTurn struct { PlayerName string Player serial }
PlayerTurn is emitted at the start of a player
type PlayersStillInQuestionResult ¶
type PlayersStillInQuestionResult struct { Players []serial PlayerNames []string }
PlayersStillInQuestionResult is emitted when some players are still in the [pQuestionResult] step
type PossibleMoves ¶
type PossibleMoves struct { PlayerName string Tiles []int // the tile indices where the current player may move Player serial // the player allowed to play }
PossibleMoves is emitted after a diceThrow
type QR ¶
type QR struct { IdQuestion editor.IdQuestion Success bool }
type QuestionContent ¶
type QuestionContent struct { ID editor.IdQuestion // the origin Question questions.QuestionInstance // the instantiated version Vars expression.Vars // the corresponding parameters Categorie Categorie // the origin }
QuestionContent stores the ID of the question and its instance
type QuestionPool ¶
type QuestionPool [NbCategories]WeigthedQuestions
type QuestionReview ¶
type QuestionReview struct { QuestionHistory []QR // Ids of question the player wants to mark for further work MarkedQuestions []editor.IdQuestion }
QuestionReview stores the results of one player against the questions asked during the game
type Replay ¶
type Replay struct { QuestionHistory map[Player]QuestionReview ID RoomID }
Replay exposes some information to be persisted after the game end, such as the successes of the players
type Room ¶
type Room struct { // ID is the readonly ID for this game. ID RoomID // Terminate is used to cleanly exit the game, // noticing clients and exiting the main goroutine. // It is however not considered as a normal exit, // so that the `Replay` is not emitted. Terminate chan bool // Leave is used when the player leave the game // (either on purpose or when its connection breaks) // For started games, the player is only set inactive, // whereas for waiting (in lobby) games, the player is totaly removed. Leave chan PlayerID // Event is used when a client send an event Event chan ClientEvent // contains filtered or unexported fields }
Room is the game host, and the main entry point of a game. All exported methods are safe for concurrent use; events are send on the exposed channel fields.
func (*Room) HasStarted ¶
HasStarted locks and returns `true` if the game has already started
func (*Room) Join ¶
func (r *Room) Join(player Player, connection Connection) error
Join should be used on a new connection, on one the of the following cases:
- totally fresh connection
- reconnection in an already started game
It is safe for concurrent uses. It returns an error for instance if the game has already started.
func (*Room) Listen ¶
Listen starts the main game loop, listening on the game channels and blocking. Note that it does not start the game itself : the game state is initially in the lobby. It returns `true` when the game is over, or `false` when it was manually terminated. Care should be taken to make sure no more events are send on the channels when this method has returned.
func (*Room) NbActivePlayers ¶
NbActivePlayers locks and returns the number of players currently connected.
type RoomID ¶
type RoomID string
RoomID is the public, full identifier of a game room, whose extact form varies according to the launch mode of the game. It is not used internally by this package but associated to every room object, and will be used by consuming packages.
type ServerEvent ¶
type ServerEvent interface {
// contains filtered or unexported methods
}
ServerEvent is an action (created by the server) advancing the game or requiring to update the UI
type ServerEventWrapper ¶
type ServerEventWrapper struct {
Data ServerEvent
}
ServerEventWrapper may be used as replacements for ServerEvent when working with JSON
func (ServerEventWrapper) MarshalJSON ¶
func (item ServerEventWrapper) MarshalJSON() ([]byte, error)
func (*ServerEventWrapper) UnmarshalJSON ¶
func (out *ServerEventWrapper) UnmarshalJSON(src []byte) error
type ShowQuestion ¶
type ShowQuestion struct { TimeoutSeconds int Categorie Categorie ID editor.IdQuestion // to facilitate the tracking of the question results Question client.Question // the actual question }
ShowQuestion is emitted when a player should answer a question
type StateUpdate ¶
StateUpdate describes a list of events yielding a new game state. Clients should animate the events and update the state.
func (StateUpdate) String ¶
func (su StateUpdate) String() string
type SuccessHandler ¶
type SuccessHandler interface { OnQuestion(player PlayerID, correct, hasStreak3 bool) events.EventNotification OnWin(player PlayerID) events.EventNotification }
SuccessHandler reacts to students acheiving global success.
It will typically be implemented with a [*sql.DB]
type Summary ¶
type Summary struct { PlayerTurn *Player // nil before game start // Successes does not contains disconnected players Successes map[string]Success ID RoomID RoomSize RoomSize // Number of players LatestQuestion QuestionContent // zero ID before the first question // During question phase, it is the list // of players still answering a question. // After a question, is is the list of players still not ready for the next turn. // Empty otherwise InQuestionStudents []string }
Summary provides an high level overview of the game, and may be emitted back to the teacher monitor.
type WantNextTurn ¶
type WantNextTurn struct { // MarkQuestion is true if the player wants to // keep the question for following trainings MarkQuestion bool }
WantNextTurn is emitted when a player is done looking at the question answer panel