2020-01-05 17:08:05 -08:00
|
|
|
package rules
|
2019-12-31 20:43:05 -08:00
|
|
|
|
2022-05-11 08:26:28 -07:00
|
|
|
type Ruleset interface {
|
2022-10-28 16:49:49 -07:00
|
|
|
// Returns the name of the ruleset, if applicable.
|
2022-05-11 08:26:28 -07:00
|
|
|
Name() string
|
2022-10-28 16:49:49 -07:00
|
|
|
|
|
|
|
|
// Returns the settings used by the ruleset.
|
2022-05-11 08:26:28 -07:00
|
|
|
Settings() Settings
|
2022-10-28 16:49:49 -07:00
|
|
|
|
|
|
|
|
// Processes the next turn of the ruleset, returning whether the game has ended, the next BoardState, or an error.
|
|
|
|
|
// For turn zero (initialization), moves will be left empty.
|
|
|
|
|
Execute(prevState *BoardState, moves []SnakeMove) (gameOver bool, nextState *BoardState, err error)
|
2022-05-11 08:26:28 -07:00
|
|
|
}
|
2020-12-11 10:05:19 -08:00
|
|
|
|
2022-05-11 08:26:28 -07:00
|
|
|
type SnakeMove struct {
|
|
|
|
|
ID string
|
|
|
|
|
Move string
|
|
|
|
|
}
|
2020-12-11 10:05:19 -08:00
|
|
|
|
2022-03-16 16:58:05 -07:00
|
|
|
type rulesetBuilder struct {
|
2022-10-28 16:49:49 -07:00
|
|
|
params map[string]string // game customisation parameters
|
|
|
|
|
seed int64 // used for random events in games
|
|
|
|
|
rand Rand // used for random number generation
|
|
|
|
|
solo bool // if true, only 1 alive snake is required to keep the game from ending
|
|
|
|
|
settings *Settings // used to set settings directly instead of via string params
|
2022-03-16 16:58:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NewRulesetBuilder returns an instance of a builder for the Ruleset types.
|
|
|
|
|
func NewRulesetBuilder() *rulesetBuilder {
|
|
|
|
|
return &rulesetBuilder{
|
|
|
|
|
params: map[string]string{},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-28 16:49:49 -07:00
|
|
|
// WithParams accepts a map of string parameters for customizing games.
|
2022-03-16 16:58:05 -07:00
|
|
|
//
|
|
|
|
|
// Parameters are copied. If called multiple times, parameters are merged such that:
|
|
|
|
|
// - existing keys in both maps get overwritten by the new ones
|
|
|
|
|
// - existing keys not present in the new map will be retained
|
|
|
|
|
// - non-existing keys only in the new map will be added
|
|
|
|
|
//
|
|
|
|
|
// Unrecognised parameters will be ignored and default values will be used.
|
|
|
|
|
// Invalid parameters (i.e. a non-numerical value where one is expected), will be ignored
|
|
|
|
|
// and default values will be used.
|
|
|
|
|
func (rb *rulesetBuilder) WithParams(params map[string]string) *rulesetBuilder {
|
|
|
|
|
for k, v := range params {
|
|
|
|
|
rb.params[k] = v
|
|
|
|
|
}
|
|
|
|
|
return rb
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-17 15:45:56 -07:00
|
|
|
// WithSeed sets the seed used for randomisation by certain game modes.
|
2022-03-16 16:58:05 -07:00
|
|
|
func (rb *rulesetBuilder) WithSeed(seed int64) *rulesetBuilder {
|
|
|
|
|
rb.seed = seed
|
|
|
|
|
return rb
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-17 15:45:56 -07:00
|
|
|
// WithRandom overrides the random number generator with a specific instance
|
|
|
|
|
// instead of a Rand initialized from the seed.
|
2022-05-11 08:26:28 -07:00
|
|
|
func (rb *rulesetBuilder) WithRand(rand Rand) *rulesetBuilder {
|
|
|
|
|
rb.rand = rand
|
|
|
|
|
return rb
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-08 15:45:20 -07:00
|
|
|
// WithSolo sets whether the ruleset is a solo game.
|
|
|
|
|
func (rb *rulesetBuilder) WithSolo(value bool) *rulesetBuilder {
|
|
|
|
|
rb.solo = value
|
|
|
|
|
return rb
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-28 16:49:49 -07:00
|
|
|
// WithSettings sets the settings object for the ruleset directly.
|
|
|
|
|
func (rb *rulesetBuilder) WithSettings(settings Settings) *rulesetBuilder {
|
|
|
|
|
rb.settings = &settings
|
|
|
|
|
return rb
|
|
|
|
|
}
|
2022-03-16 16:58:05 -07:00
|
|
|
|
2022-10-28 16:49:49 -07:00
|
|
|
// NamedRuleset constructs a known ruleset by using name to look up a standard pipeline.
|
|
|
|
|
func (rb rulesetBuilder) NamedRuleset(name string) Ruleset {
|
2022-06-08 15:45:20 -07:00
|
|
|
var stages []string
|
|
|
|
|
if rb.solo {
|
|
|
|
|
stages = append(stages, StageGameOverSoloSnake)
|
|
|
|
|
} else {
|
|
|
|
|
stages = append(stages, StageGameOverStandard)
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-16 16:58:05 -07:00
|
|
|
switch name {
|
2022-05-25 11:24:27 -07:00
|
|
|
case GameTypeStandard:
|
2022-06-08 15:45:20 -07:00
|
|
|
stages = append(stages, standardRulesetStages[1:]...)
|
2022-03-16 16:58:05 -07:00
|
|
|
case GameTypeConstrictor:
|
2022-06-08 15:45:20 -07:00
|
|
|
stages = append(stages, constrictorRulesetStages[1:]...)
|
2022-08-17 13:03:09 -07:00
|
|
|
case GameTypeWrappedConstrictor:
|
|
|
|
|
stages = append(stages, wrappedConstrictorRulesetStages[1:]...)
|
2022-03-16 16:58:05 -07:00
|
|
|
case GameTypeRoyale:
|
2022-06-08 15:45:20 -07:00
|
|
|
stages = append(stages, royaleRulesetStages[1:]...)
|
2022-03-16 16:58:05 -07:00
|
|
|
case GameTypeSolo:
|
2022-06-08 15:45:20 -07:00
|
|
|
stages = soloRulesetStages
|
2022-03-16 16:58:05 -07:00
|
|
|
case GameTypeWrapped:
|
2022-06-08 15:45:20 -07:00
|
|
|
stages = append(stages, wrappedRulesetStages[1:]...)
|
2022-05-25 11:24:27 -07:00
|
|
|
default:
|
2022-10-28 16:49:49 -07:00
|
|
|
name = GameTypeStandard
|
2022-06-08 15:45:20 -07:00
|
|
|
stages = append(stages, standardRulesetStages[1:]...)
|
2022-03-16 16:58:05 -07:00
|
|
|
}
|
2022-06-08 15:45:20 -07:00
|
|
|
return rb.PipelineRuleset(name, NewPipeline(stages...))
|
2022-04-19 15:52:57 -07:00
|
|
|
}
|
|
|
|
|
|
2022-10-28 16:49:49 -07:00
|
|
|
// PipelineRuleset constructs a ruleset with the given name and pipeline using the parameters passed to the builder.
|
|
|
|
|
// This can be used to create custom rulesets.
|
|
|
|
|
func (rb rulesetBuilder) PipelineRuleset(name string, p Pipeline) Ruleset {
|
|
|
|
|
var settings Settings
|
|
|
|
|
if rb.settings != nil {
|
|
|
|
|
settings = *rb.settings
|
|
|
|
|
} else {
|
|
|
|
|
settings = NewSettings(rb.params).WithRand(rb.rand).WithSeed(rb.seed)
|
|
|
|
|
}
|
2022-04-19 15:52:57 -07:00
|
|
|
return &pipelineRuleset{
|
|
|
|
|
name: name,
|
|
|
|
|
pipeline: p,
|
2022-10-28 16:49:49 -07:00
|
|
|
settings: settings,
|
2022-03-16 16:58:05 -07:00
|
|
|
}
|
2022-04-19 15:52:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type pipelineRuleset struct {
|
|
|
|
|
pipeline Pipeline
|
|
|
|
|
name string
|
|
|
|
|
settings Settings
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// impl Ruleset
|
|
|
|
|
func (r pipelineRuleset) Settings() Settings {
|
|
|
|
|
return r.settings
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// impl Ruleset
|
|
|
|
|
func (r pipelineRuleset) Name() string { return r.name }
|
|
|
|
|
|
|
|
|
|
// impl Ruleset
|
2022-10-28 16:49:49 -07:00
|
|
|
func (r pipelineRuleset) Execute(bs *BoardState, sm []SnakeMove) (bool, *BoardState, error) {
|
|
|
|
|
return r.pipeline.Execute(bs, r.Settings(), sm)
|
2022-04-19 15:52:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r pipelineRuleset) Err() error {
|
|
|
|
|
return r.pipeline.Err()
|
|
|
|
|
}
|