DEV-1761: New rules API (#118)

* DEV-1761: Clean up Ruleset interface (#115)

* remove legacy ruleset types and simplify ruleset interface

* remove unnecessary settings argument from Ruleset interface

* decouple rules.Settings from client API and store settings as strings

* DEV 1761: Add new BoardState and Point fields (#117)

* add Point.TTL, Point.Value, GameState and PointState to BoardState

* allow maps to access BoardState.GameState,PointState

* add PreUpdateBoard and refactor snail_mode with it

* fix bug where an extra turn was printed to the console

* fix formatting

* fix lint errors

Co-authored-by: JonathanArns <jonathan.arns@googlemail.com>
This commit is contained in:
Rob O'Dwyer 2022-10-28 16:49:49 -07:00 committed by GitHub
parent 639362ef46
commit 82e1999126
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
50 changed files with 1349 additions and 1610 deletions

View file

@ -38,6 +38,33 @@ var globalRegistry = StageRegistry{
StageMovementWrapBoundaries: MoveSnakesWrapped,
}
// Pipeline is an ordered sequences of game stages which are executed to produce the
// next game state.
//
// If a stage produces an error or an ended game state, the pipeline is halted at that stage.
type Pipeline interface {
// Execute runs the pipeline stages and produces a next game state.
//
// If any stage produces an error or an ended game state, the pipeline
// immediately stops at that stage.
//
// Errors should be checked and the other results ignored if error is non-nil.
//
// If the pipeline is already in an error state (this can be checked by calling Err()),
// this error will be immediately returned and the pipeline will not run.
//
// After the pipeline runs, the results will be the result of the last stage that was executed.
Execute(*BoardState, Settings, []SnakeMove) (bool, *BoardState, error)
// Err provides a way to check for errors before/without calling Execute.
// Err returns an error if the Pipeline is in an error state.
// If this error is not nil, this error will also be returned from Execute, so it is
// optional to call Err.
// The idea is to reduce error-checking verbosity for the majority of cases where a
// Pipeline is immediately executed after construction (i.e. NewPipeline(...).Execute(...)).
Err() error
}
// StageFunc represents a single stage of an ordered pipeline and applies custom logic to the board state each turn.
// It is expected to modify the boardState directly.
// The return values are a boolean (to indicate whether the game has ended as a result of the stage)
@ -46,6 +73,14 @@ var globalRegistry = StageRegistry{
// Errors should be treated as meaning the stage failed and the board state is now invalid.
type StageFunc func(*BoardState, Settings, []SnakeMove) (bool, error)
// IsInitialization checks whether the current state means the game is initialising (turn zero).
// Useful for StageFuncs that need to apply different behaviour on initialisation.
func IsInitialization(b *BoardState, settings Settings, moves []SnakeMove) bool {
// We can safely assume that the game state is in the initialisation phase when
// the turn hasn't advanced and the moves are empty
return b.Turn <= 0 && len(moves) == 0
}
// StageRegistry is a mapping of stage names to stage functions
type StageRegistry map[string]StageFunc
@ -76,32 +111,6 @@ func RegisterPipelineStage(s string, fn StageFunc) {
}
}
// Pipeline is an ordered sequences of game stages which are executed to produce the
// next game state.
//
// If a stage produces an error or an ended game state, the pipeline is halted at that stage.
type Pipeline interface {
// Execute runs the pipeline stages and produces a next game state.
//
// If any stage produces an error or an ended game state, the pipeline
// immediately stops at that stage.
//
// Errors should be checked and the other results ignored if error is non-nil.
//
// If the pipeline is already in an error state (this can be checked by calling Err()),
// this error will be immediately returned and the pipeline will not run.
//
// After the pipeline runs, the results will be the result of the last stage that was executed.
Execute(*BoardState, Settings, []SnakeMove) (bool, *BoardState, error)
// Err provides a way to check for errors before/without calling Execute.
// Err returns an error if the Pipeline is in an error state.
// If this error is not nil, this error will also be returned from Execute, so it is
// optional to call Err.
// The idea is to reduce error-checking verbosity for the majority of cases where a
// Pipeline is immediately executed after construction (i.e. NewPipeline(...).Execute(...)).
Err() error
}
// pipeline is an implementation of Pipeline
type pipeline struct {
// stages is a list of stages that should be executed from slice start to end