commands A, W
This commit is contained in:
+8
-16
@@ -3,29 +3,21 @@ package game
|
||||
import "github.com/iliadenisov/galaxy/pkg/model/game"
|
||||
|
||||
func DeclareWar(configure func(*Param), from, to string) (err error) {
|
||||
control(configure, func(c *ctrl) { c.execute(func(r Repo) { err = updateRelation(r, from, to, game.RelationWar) }) })
|
||||
control(configure, func(c *ctrl) {
|
||||
c.execute(func(r Repo, g game.Game) { err = updateRelation(r, g, from, to, game.RelationWar) })
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func DeclarePeace(configure func(*Param), from, to string) (err error) {
|
||||
control(configure, func(c *ctrl) { c.execute(func(r Repo) { err = updateRelation(r, from, to, game.RelationPeace) }) })
|
||||
control(configure, func(c *ctrl) {
|
||||
c.execute(func(r Repo, g game.Game) { err = updateRelation(r, g, from, to, game.RelationPeace) })
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func updateRelation(r Repo, hostRace, opponentRace string, rel game.Relation) error {
|
||||
g, err := r.LoadState()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hostID, err := g.HostRaceID(hostRace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
opponentID, err := g.OpponentRaceID(opponentRace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := g.UpdateRelation(hostID, opponentID, rel); err != nil {
|
||||
func updateRelation(r Repo, g game.Game, hostRace, opponentRace string, rel game.Relation) error {
|
||||
if err := g.UpdateRelation(hostRace, opponentRace, rel); err != nil {
|
||||
return err
|
||||
}
|
||||
return r.SaveState(g)
|
||||
|
||||
+58
-14
@@ -1,26 +1,70 @@
|
||||
package game_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/iliadenisov/galaxy/pkg/game"
|
||||
"github.com/iliadenisov/galaxy/pkg/util"
|
||||
mg "github.com/iliadenisov/galaxy/pkg/model/game"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestRelation(t *testing.T) {
|
||||
root, cleanup := util.CreateWorkDir(t)
|
||||
defer cleanup()
|
||||
players := 20
|
||||
races := make([]string, players)
|
||||
for i := range players {
|
||||
races[i] = fmt.Sprintf("race_%02d", i)
|
||||
}
|
||||
_, err := game.ComposeGame(func(p *game.Param) { p.StoragePath = root }, races)
|
||||
assert.NoError(t, err)
|
||||
func TestDeclarePeaceAndWarSingle(t *testing.T) {
|
||||
g(t, func(f func(*game.Param), g func() mg.Game) {
|
||||
hostRace := "race_05"
|
||||
opponentRace := "race_01"
|
||||
|
||||
err = game.DeclarePeace(func(p *game.Param) { p.StoragePath = root }, "race_05", "race_01")
|
||||
r, err := g().Relation(hostRace, opponentRace)
|
||||
assert.NoError(t, err)
|
||||
// TODO: check relation state changed
|
||||
assert.Equal(t, mg.RelationWar, r.Relation)
|
||||
|
||||
assert.NoError(t, game.DeclarePeace(f, hostRace, opponentRace))
|
||||
r, err = g().Relation(hostRace, opponentRace)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, mg.RelationPeace, r.Relation)
|
||||
|
||||
assert.NoError(t, game.DeclareWar(f, hostRace, opponentRace))
|
||||
r, err = g().Relation(hostRace, opponentRace)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, mg.RelationWar, r.Relation)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDeclarePeaceAndWarAll(t *testing.T) {
|
||||
g(t, func(f func(*game.Param), g func() mg.Game) {
|
||||
hostRace := "race_07"
|
||||
|
||||
for i := range testRaceCount {
|
||||
opponentRace := raceNum(i)
|
||||
if opponentRace == hostRace {
|
||||
continue
|
||||
}
|
||||
r, err := g().Relation(hostRace, opponentRace)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, mg.RelationWar, r.Relation)
|
||||
}
|
||||
|
||||
assert.NoError(t, game.DeclarePeace(f, hostRace, hostRace))
|
||||
|
||||
for i := range testRaceCount {
|
||||
opponentRace := raceNum(i)
|
||||
if opponentRace == hostRace {
|
||||
continue
|
||||
}
|
||||
r, err := g().Relation(hostRace, opponentRace)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, mg.RelationPeace, r.Relation)
|
||||
}
|
||||
|
||||
assert.NoError(t, game.DeclareWar(f, hostRace, hostRace))
|
||||
|
||||
for i := range testRaceCount {
|
||||
opponentRace := raceNum(i)
|
||||
if opponentRace == hostRace {
|
||||
continue
|
||||
}
|
||||
r, err := g().Relation(hostRace, opponentRace)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, mg.RelationWar, r.Relation)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
+21
-3
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/iliadenisov/galaxy/pkg/model/game"
|
||||
"github.com/iliadenisov/galaxy/pkg/repo"
|
||||
)
|
||||
|
||||
@@ -16,8 +17,13 @@ type Param struct {
|
||||
StoragePath string
|
||||
}
|
||||
|
||||
func ComposeGame(configure func(*Param), races []string) (gameID uuid.UUID, err error) {
|
||||
control(configure, func(c *ctrl) { c.execute(func(r Repo) { gameID, err = newGame(r, races) }) })
|
||||
func LoadState(configure func(*Param)) (g game.Game, err error) {
|
||||
control(configure, func(c *ctrl) { c.executeInit(func(r Repo) { g, err = c.repo.LoadState() }) })
|
||||
return
|
||||
}
|
||||
|
||||
func GenerateGame(configure func(*Param), races []string) (gameID uuid.UUID, err error) {
|
||||
control(configure, func(c *ctrl) { c.executeInit(func(r Repo) { gameID, err = newGame(r, races) }) })
|
||||
return
|
||||
}
|
||||
|
||||
@@ -47,10 +53,22 @@ func control(configure func(*Param), consumer func(*ctrl)) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ctrl) execute(consumer func(Repo)) error {
|
||||
func (c *ctrl) executeInit(consumer func(Repo)) error {
|
||||
if err := c.repo.Lock(); err != nil {
|
||||
return fmt.Errorf("execute: lock failed: %s", err)
|
||||
}
|
||||
consumer(c.repo)
|
||||
return c.repo.Release()
|
||||
}
|
||||
|
||||
func (c *ctrl) execute(consumer func(Repo, game.Game)) error {
|
||||
if err := c.repo.Lock(); err != nil {
|
||||
return fmt.Errorf("execute: lock failed: %s", err)
|
||||
}
|
||||
g, err := c.repo.LoadState()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
consumer(c.repo, g)
|
||||
return c.repo.Release()
|
||||
}
|
||||
|
||||
+36
-10
@@ -5,21 +5,47 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/iliadenisov/galaxy/pkg/game"
|
||||
mg "github.com/iliadenisov/galaxy/pkg/model/game"
|
||||
"github.com/iliadenisov/galaxy/pkg/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestComposeGame(t *testing.T) {
|
||||
root, cleanup := util.CreateWorkDir(t)
|
||||
defer cleanup()
|
||||
players := 20
|
||||
races := make([]string, players)
|
||||
for i := range players {
|
||||
races[i] = fmt.Sprintf("race_%02d", i)
|
||||
const (
|
||||
testRaceCount = 20
|
||||
)
|
||||
|
||||
func raceNum(i int) string {
|
||||
return fmt.Sprintf("race_%02d", i)
|
||||
}
|
||||
_, err := game.ComposeGame(func(p *game.Param) { p.StoragePath = root }, races)
|
||||
assert.NoError(t, err)
|
||||
_, err = game.ComposeGame(func(p *game.Param) { p.StoragePath = root }, races)
|
||||
|
||||
func TestComposeGame(t *testing.T) {
|
||||
g(t, func(p func(*game.Param), g func() mg.Game) {
|
||||
_, err := game.GenerateGame(p, []string{"r1", "r2"})
|
||||
assert.Error(t, err)
|
||||
assert.ErrorContains(t, err, "state for turn 0 already saved")
|
||||
})
|
||||
}
|
||||
|
||||
func g(t *testing.T, f func(func(*game.Param), func() mg.Game)) {
|
||||
root, cleanup := util.CreateWorkDir(t)
|
||||
defer cleanup()
|
||||
races := make([]string, testRaceCount)
|
||||
for i := range testRaceCount {
|
||||
races[i] = raceNum(i)
|
||||
}
|
||||
p := func(p *game.Param) { p.StoragePath = root }
|
||||
_, err := game.GenerateGame(p, races)
|
||||
if err != nil {
|
||||
assert.FailNow(t, "g: ComposeGame", err)
|
||||
return
|
||||
}
|
||||
g := func() mg.Game {
|
||||
g, err := game.LoadState(p)
|
||||
if err != nil {
|
||||
assert.FailNow(t, "g: LoadState", err)
|
||||
return mg.Game{}
|
||||
}
|
||||
return g
|
||||
}
|
||||
f(p, g)
|
||||
}
|
||||
|
||||
+52
-4
@@ -25,14 +25,14 @@ func (g Game) Votes(raceID uuid.UUID) float64 {
|
||||
return pop / 1000.
|
||||
}
|
||||
|
||||
func (g Game) HostRaceID(name string) (uuid.UUID, error) {
|
||||
func (g Game) hostRaceID(name string) (uuid.UUID, error) {
|
||||
if v, ok := g.raceID(name); ok {
|
||||
return v, nil
|
||||
}
|
||||
return uuid.Nil, e.NewHostRaceUnknownError(name)
|
||||
}
|
||||
|
||||
func (g Game) OpponentRaceID(name string) (uuid.UUID, error) {
|
||||
func (g Game) opponentRaceID(name string) (uuid.UUID, error) {
|
||||
if v, ok := g.raceID(name); ok {
|
||||
return v, nil
|
||||
}
|
||||
@@ -48,20 +48,68 @@ func (g Game) raceID(raceName string) (uuid.UUID, bool) {
|
||||
return uuid.Nil, false
|
||||
}
|
||||
|
||||
func (g Game) UpdateRelation(hostID, opponentID uuid.UUID, rel Relation) error {
|
||||
func (g Game) UpdateRelation(hostRace, opponentRace string, rel Relation) error {
|
||||
hostID, err := g.hostRaceID(hostRace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var opponentID uuid.UUID
|
||||
if hostRace == opponentRace {
|
||||
opponentID = hostID
|
||||
} else if opponentID, err = g.opponentRaceID(opponentRace); err != nil {
|
||||
return err
|
||||
}
|
||||
return g.updateRelationInternal(hostID, opponentID, rel)
|
||||
}
|
||||
|
||||
func (g Game) updateRelationInternal(hostID, opponentID uuid.UUID, rel Relation) error {
|
||||
for r := range g.Race {
|
||||
if g.Race[r].ID == hostID {
|
||||
for o := range g.Race[r].Relations {
|
||||
if g.Race[r].Relations[o].RaceID == opponentID {
|
||||
switch {
|
||||
case hostID == opponentID:
|
||||
g.Race[r].Relations[o].Relation = rel
|
||||
case g.Race[r].Relations[o].RaceID == opponentID:
|
||||
g.Race[r].Relations[o].Relation = rel
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if hostID != opponentID {
|
||||
return e.NewGameStateError("UpdateRelation: opponent not found")
|
||||
}
|
||||
}
|
||||
}
|
||||
if hostID != opponentID {
|
||||
return e.NewGameStateError("UpdateRelation: host %v not found", hostID)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g Game) Relation(hostRace, opponentRace string) (RaceRelation, error) {
|
||||
hostID, err := g.hostRaceID(hostRace)
|
||||
if err != nil {
|
||||
return RaceRelation{}, err
|
||||
}
|
||||
opponentID, err := g.opponentRaceID(opponentRace)
|
||||
if err != nil {
|
||||
return RaceRelation{}, err
|
||||
}
|
||||
return g.relationInternal(hostID, opponentID)
|
||||
}
|
||||
|
||||
func (g Game) relationInternal(hostID, opponentID uuid.UUID) (RaceRelation, error) {
|
||||
for r := range g.Race {
|
||||
if g.Race[r].ID == hostID {
|
||||
for o := range g.Race[r].Relations {
|
||||
if g.Race[r].Relations[o].RaceID == opponentID {
|
||||
return g.Race[r].Relations[o], nil
|
||||
}
|
||||
}
|
||||
return RaceRelation{}, e.NewGameStateError("Relation: opponent not found")
|
||||
}
|
||||
}
|
||||
return RaceRelation{}, e.NewGameStateError("Relation: host %v not found", hostID)
|
||||
}
|
||||
|
||||
func (g Game) MarshalBinary() (data []byte, err error) {
|
||||
return json.Marshal(&g)
|
||||
|
||||
@@ -25,8 +25,8 @@ type Race struct {
|
||||
type Relation string
|
||||
|
||||
const (
|
||||
RelationWar = "War"
|
||||
RelationPeace = "Peace"
|
||||
RelationWar Relation = "War"
|
||||
RelationPeace Relation = "Peace"
|
||||
)
|
||||
|
||||
type RaceRelation struct {
|
||||
|
||||
Reference in New Issue
Block a user