chore: refactor structure
This commit is contained in:
@@ -7,7 +7,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/iliadenisov/galaxy/pkg/bitmap"
|
||||
"github.com/iliadenisov/galaxy/internal/bitmap"
|
||||
)
|
||||
|
||||
func TestBitVectorSize(t *testing.T) {
|
||||
@@ -0,0 +1,71 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/iliadenisov/galaxy/internal/model/game"
|
||||
"github.com/iliadenisov/galaxy/internal/repo"
|
||||
)
|
||||
|
||||
type Repo interface {
|
||||
// Lock must be called before any repository operations
|
||||
Lock() error
|
||||
|
||||
// Release must be called after first and only repository operation
|
||||
Release() error
|
||||
|
||||
// SaveTurn stores just generated new turn
|
||||
SaveTurn(uint, game.Game) error
|
||||
|
||||
// SaveState stores current game state updated between turns
|
||||
SaveState(game.Game) error
|
||||
|
||||
// LoadState retrieves game current state
|
||||
LoadState() (game.Game, error)
|
||||
}
|
||||
|
||||
type Ctrl struct {
|
||||
param Param
|
||||
Repo Repo
|
||||
}
|
||||
|
||||
type Param struct {
|
||||
StoragePath string
|
||||
}
|
||||
|
||||
func NewController(configure func(*Param)) (*Ctrl, error) {
|
||||
c := &Param{
|
||||
StoragePath: ".",
|
||||
}
|
||||
if configure != nil {
|
||||
configure(c)
|
||||
}
|
||||
r, err := repo.NewFileRepo(c.StoragePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Ctrl{
|
||||
param: *c,
|
||||
Repo: r,
|
||||
}, nil
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package game
|
||||
package controller
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -6,11 +6,11 @@ import (
|
||||
"slices"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/iliadenisov/galaxy/pkg/generator"
|
||||
"github.com/iliadenisov/galaxy/pkg/model/game"
|
||||
"github.com/iliadenisov/galaxy/internal/generator"
|
||||
"github.com/iliadenisov/galaxy/internal/model/game"
|
||||
)
|
||||
|
||||
func newGame(r Repo, races []string) (uuid.UUID, error) {
|
||||
func NewGame(r Repo, races []string) (uuid.UUID, error) {
|
||||
m, err := generator.Generate(func(ms *generator.MapSetting) {
|
||||
ms.Players = uint32(len(races))
|
||||
})
|
||||
@@ -1,4 +1,4 @@
|
||||
package game
|
||||
package controller_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -6,9 +6,10 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/iliadenisov/galaxy/pkg/model/game"
|
||||
"github.com/iliadenisov/galaxy/pkg/repo"
|
||||
"github.com/iliadenisov/galaxy/pkg/util"
|
||||
"github.com/iliadenisov/galaxy/internal/controller"
|
||||
"github.com/iliadenisov/galaxy/internal/model/game"
|
||||
"github.com/iliadenisov/galaxy/internal/repo"
|
||||
"github.com/iliadenisov/galaxy/internal/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@@ -25,7 +26,7 @@ func TestNewGame(t *testing.T) {
|
||||
races[i] = fmt.Sprintf("race_%02d", i)
|
||||
}
|
||||
assert.NoError(t, r.Lock())
|
||||
gameID, err := newGame(r, races)
|
||||
gameID, err := controller.NewGame(r, races)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.FileExists(t, filepath.Join(root, "state.json"))
|
||||
@@ -14,6 +14,7 @@ const (
|
||||
ErrDeleteShipTypePlanetProduction = 5001
|
||||
ErrDeleteSciencePlanetProduction = 5002
|
||||
ErrMergeShipTypeNotEqual = 5003
|
||||
ErrJoinFleetGroupNumberNotEnough = 5004
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -83,6 +84,8 @@ func GenericErrorText(code int) string {
|
||||
return "Invalid Production type"
|
||||
case ErrMergeShipTypeNotEqual:
|
||||
return "Source and target ship types are not the same"
|
||||
case ErrJoinFleetGroupNumberNotEnough:
|
||||
return "Not enough ships in the group to join a fleet"
|
||||
default:
|
||||
return fmt.Sprintf("Undescribed error with code %d", code)
|
||||
}
|
||||
@@ -67,3 +67,7 @@ func NewProductionInvalidError(arg ...any) error {
|
||||
func NewMergeShipTypeNotEqualError(arg ...any) error {
|
||||
return newGenericError(ErrMergeShipTypeNotEqual, arg...)
|
||||
}
|
||||
|
||||
func NewJoinFleetGroupNumberNotEnoughError(arg ...any) error {
|
||||
return newGenericError(ErrJoinFleetGroupNumberNotEnough, arg...)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"github.com/iliadenisov/galaxy/internal/controller"
|
||||
"github.com/iliadenisov/galaxy/internal/model/game"
|
||||
)
|
||||
|
||||
func JoinEqualGroups(configure func(*controller.Param), race string) (err error) {
|
||||
control(configure, func(c *controller.Ctrl) {
|
||||
c.Execute(func(r controller.Repo, g game.Game) {
|
||||
err = joinEqualGroups(r, g, race)
|
||||
})
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func joinEqualGroups(r controller.Repo, g game.Game, race string) error {
|
||||
if err := g.JoinEqualGroups(race); err != nil {
|
||||
return err
|
||||
}
|
||||
return r.SaveState(g)
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package game_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/iliadenisov/galaxy/internal/controller"
|
||||
"github.com/iliadenisov/galaxy/internal/game"
|
||||
mg "github.com/iliadenisov/galaxy/internal/model/game"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestJoinEqualGroups(t *testing.T) {
|
||||
g(t, func(p func(*controller.Param), g func() mg.Game) {
|
||||
err := game.JoinEqualGroups(p, "race_01")
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"github.com/iliadenisov/galaxy/internal/controller"
|
||||
"github.com/iliadenisov/galaxy/internal/model/game"
|
||||
)
|
||||
|
||||
func RenamePlanet(configure func(*controller.Param), race string, number int, name string) (err error) {
|
||||
control(configure, func(c *controller.Ctrl) {
|
||||
c.Execute(func(r controller.Repo, g game.Game) {
|
||||
err = renamePlanet(r, g, race, number, name)
|
||||
})
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func renamePlanet(r controller.Repo, g game.Game, race string, number int, name string) error {
|
||||
if err := g.RenamePlanet(race, number, name); err != nil {
|
||||
return err
|
||||
}
|
||||
return r.SaveState(g)
|
||||
}
|
||||
@@ -4,16 +4,17 @@ import (
|
||||
"slices"
|
||||
"testing"
|
||||
|
||||
e "github.com/iliadenisov/galaxy/pkg/error"
|
||||
"github.com/iliadenisov/galaxy/internal/controller"
|
||||
e "github.com/iliadenisov/galaxy/internal/error"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/iliadenisov/galaxy/pkg/game"
|
||||
mg "github.com/iliadenisov/galaxy/pkg/model/game"
|
||||
"github.com/iliadenisov/galaxy/internal/game"
|
||||
mg "github.com/iliadenisov/galaxy/internal/model/game"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestRenamePlanet(t *testing.T) {
|
||||
g(t, func(p func(*game.Param), g func() mg.Game) {
|
||||
g(t, func(p func(*controller.Param), g func() mg.Game) {
|
||||
cg := g()
|
||||
var number int
|
||||
var owner uuid.UUID
|
||||
@@ -0,0 +1,22 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"github.com/iliadenisov/galaxy/internal/controller"
|
||||
"github.com/iliadenisov/galaxy/internal/model/game"
|
||||
)
|
||||
|
||||
func PlanetProduction(configure func(*controller.Param), race string, planetNumber int, prodType, subject string) (err error) {
|
||||
control(configure, func(c *controller.Ctrl) {
|
||||
c.Execute(func(r controller.Repo, g game.Game) {
|
||||
err = planetProduction(r, g, race, planetNumber, prodType, subject)
|
||||
})
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func planetProduction(r controller.Repo, g game.Game, race string, planetNumber int, prodType, subject string) error {
|
||||
if err := g.PlanetProduction(race, planetNumber, prodType, subject); err != nil {
|
||||
return err
|
||||
}
|
||||
return r.SaveState(g)
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"github.com/iliadenisov/galaxy/internal/controller"
|
||||
"github.com/iliadenisov/galaxy/internal/model/game"
|
||||
)
|
||||
|
||||
func CreateScience(configure func(*controller.Param), race, typeName string, drive, weapons, shields, cargo float64) (err error) {
|
||||
control(configure, func(c *controller.Ctrl) {
|
||||
c.Execute(func(r controller.Repo, g game.Game) {
|
||||
err = createScience(r, g, race, typeName, drive, weapons, shields, cargo)
|
||||
})
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func createScience(r controller.Repo, g game.Game, race, typeName string, d, w, s, c float64) error {
|
||||
if err := g.CreateScience(race, typeName, d, w, s, c); err != nil {
|
||||
return err
|
||||
}
|
||||
return r.SaveState(g)
|
||||
}
|
||||
|
||||
func DeleteScience(configure func(*controller.Param), race, typeName string) (err error) {
|
||||
control(configure, func(c *controller.Ctrl) {
|
||||
c.Execute(func(r controller.Repo, g game.Game) {
|
||||
err = deleteScience(r, g, race, typeName)
|
||||
})
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func deleteScience(r controller.Repo, g game.Game, race, typeName string) error {
|
||||
if err := g.DeleteScience(race, typeName); err != nil {
|
||||
return err
|
||||
}
|
||||
return r.SaveState(g)
|
||||
}
|
||||
@@ -4,16 +4,18 @@ import (
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
e "github.com/iliadenisov/galaxy/pkg/error"
|
||||
"github.com/iliadenisov/galaxy/pkg/game"
|
||||
mg "github.com/iliadenisov/galaxy/pkg/model/game"
|
||||
"github.com/iliadenisov/galaxy/internal/controller"
|
||||
|
||||
e "github.com/iliadenisov/galaxy/internal/error"
|
||||
"github.com/iliadenisov/galaxy/internal/game"
|
||||
mg "github.com/iliadenisov/galaxy/internal/model/game"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCreateScience(t *testing.T) {
|
||||
race := "race_01"
|
||||
typeName := "First Step"
|
||||
g(t, func(p func(*game.Param), g func() mg.Game) {
|
||||
g(t, func(p func(*controller.Param), g func() mg.Game) {
|
||||
err := game.DeleteScience(p, race, typeName)
|
||||
assert.ErrorContains(t, err, e.GenericErrorText(e.ErrInputEntityNotExists))
|
||||
err = game.CreateScience(p, unknownRaceName, " "+typeName+" ", 1, 0, 0, 0) // TODO: test on dead race
|
||||
@@ -72,7 +74,7 @@ func TestCreateScienceValidation(t *testing.T) {
|
||||
{typeName, 0, 0, 0, -1, e.GenericErrorText(e.ErrInputCargoValue)},
|
||||
{typeName, 0, 1, 1, -1, e.GenericErrorText(e.ErrInputCargoValue)},
|
||||
}
|
||||
g(t, func(p func(*game.Param), g func() mg.Game) {
|
||||
g(t, func(p func(*controller.Param), g func() mg.Game) {
|
||||
for i, tc := range table {
|
||||
if tc.err == "" {
|
||||
err := game.CreateScience(p, race, tc.name+strconv.Itoa(i), tc.d, tc.w, tc.s, tc.c)
|
||||
@@ -0,0 +1,54 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"github.com/iliadenisov/galaxy/internal/controller"
|
||||
"github.com/iliadenisov/galaxy/internal/model/game"
|
||||
)
|
||||
|
||||
func CreateShipType(configure func(*controller.Param), race, typeName string, drive, weapons, shields, cargo float64, armament int) (err error) {
|
||||
control(configure, func(c *controller.Ctrl) {
|
||||
c.Execute(func(r controller.Repo, g game.Game) {
|
||||
err = createShipType(r, g, race, typeName, drive, weapons, shields, cargo, armament)
|
||||
})
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func createShipType(r controller.Repo, g game.Game, race, typeName string, d, w, s, c float64, a int) error {
|
||||
if err := g.CreateShipType(race, typeName, d, w, s, c, a); err != nil {
|
||||
return err
|
||||
}
|
||||
return r.SaveState(g)
|
||||
}
|
||||
|
||||
func MergeShipType(configure func(*controller.Param), race, source, target string) (err error) {
|
||||
control(configure, func(c *controller.Ctrl) {
|
||||
c.Execute(func(r controller.Repo, g game.Game) {
|
||||
err = mergeShipType(r, g, race, source, target)
|
||||
})
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func mergeShipType(r controller.Repo, g game.Game, race, source, target string) error {
|
||||
if err := g.MergeShipType(race, source, target); err != nil {
|
||||
return err
|
||||
}
|
||||
return r.SaveState(g)
|
||||
}
|
||||
|
||||
func DeleteShipType(configure func(*controller.Param), race, typeName string) (err error) {
|
||||
control(configure, func(c *controller.Ctrl) {
|
||||
c.Execute(func(r controller.Repo, g game.Game) {
|
||||
err = deleteShipType(r, g, race, typeName)
|
||||
})
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func deleteShipType(r controller.Repo, g game.Game, race, typeName string) error {
|
||||
if err := g.DeleteShipType(race, typeName); err != nil {
|
||||
return err
|
||||
}
|
||||
return r.SaveState(g)
|
||||
}
|
||||
@@ -4,16 +4,18 @@ import (
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
e "github.com/iliadenisov/galaxy/pkg/error"
|
||||
"github.com/iliadenisov/galaxy/pkg/game"
|
||||
mg "github.com/iliadenisov/galaxy/pkg/model/game"
|
||||
"github.com/iliadenisov/galaxy/internal/controller"
|
||||
|
||||
e "github.com/iliadenisov/galaxy/internal/error"
|
||||
"github.com/iliadenisov/galaxy/internal/game"
|
||||
mg "github.com/iliadenisov/galaxy/internal/model/game"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCreateShipType(t *testing.T) {
|
||||
race := "race_01"
|
||||
typeName := "Drone"
|
||||
g(t, func(p func(*game.Param), g func() mg.Game) {
|
||||
g(t, func(p func(*controller.Param), g func() mg.Game) {
|
||||
err := game.DeleteShipType(p, race, typeName)
|
||||
assert.ErrorContains(t, err, e.GenericErrorText(e.ErrInputEntityNotExists))
|
||||
err = game.CreateShipType(p, unknownRaceName, " "+typeName+" ", 1, 0, 0, 0, 0) // TODO: test on dead race
|
||||
@@ -77,7 +79,7 @@ func TestCreateShipTypeValidation(t *testing.T) {
|
||||
{typeName, 0, 1, 0, 0, 0, e.GenericErrorText(e.ErrInputShipTypeWeaponsAndArmamentValue)},
|
||||
{typeName, 0, 0, 0, 0, 1, e.GenericErrorText(e.ErrInputShipTypeWeaponsAndArmamentValue)},
|
||||
}
|
||||
g(t, func(p func(*game.Param), g func() mg.Game) {
|
||||
g(t, func(p func(*controller.Param), g func() mg.Game) {
|
||||
for i, tc := range table {
|
||||
if tc.err == "" {
|
||||
err := game.CreateShipType(p, race, tc.name+strconv.Itoa(i), tc.d, tc.w, tc.s, tc.c, tc.a)
|
||||
@@ -94,7 +96,7 @@ func TestCreateShipTypeValidation(t *testing.T) {
|
||||
|
||||
func TestMergeShipType(t *testing.T) {
|
||||
race := "race_01"
|
||||
g(t, func(p func(*game.Param), g func() mg.Game) {
|
||||
g(t, func(p func(*controller.Param), g func() mg.Game) {
|
||||
err := game.CreateShipType(p, race, "Drone", 1, 0, 0, 0, 0)
|
||||
assert.NoError(t, err)
|
||||
err = game.CreateShipType(p, race, "Spy", 1, 0, 0, 0, 0)
|
||||
@@ -0,0 +1,27 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"github.com/iliadenisov/galaxy/internal/controller"
|
||||
"github.com/iliadenisov/galaxy/internal/model/game"
|
||||
)
|
||||
|
||||
func DeclareWar(configure func(*controller.Param), from, to string) (err error) {
|
||||
control(configure, func(c *controller.Ctrl) {
|
||||
c.Execute(func(r controller.Repo, g game.Game) { err = updateRelation(r, g, from, to, game.RelationWar) })
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func DeclarePeace(configure func(*controller.Param), from, to string) (err error) {
|
||||
control(configure, func(c *controller.Ctrl) {
|
||||
c.Execute(func(r controller.Repo, g game.Game) { err = updateRelation(r, g, from, to, game.RelationPeace) })
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func updateRelation(r controller.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)
|
||||
}
|
||||
@@ -3,15 +3,16 @@ package game_test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
e "github.com/iliadenisov/galaxy/pkg/error"
|
||||
"github.com/iliadenisov/galaxy/internal/controller"
|
||||
e "github.com/iliadenisov/galaxy/internal/error"
|
||||
|
||||
"github.com/iliadenisov/galaxy/pkg/game"
|
||||
mg "github.com/iliadenisov/galaxy/pkg/model/game"
|
||||
"github.com/iliadenisov/galaxy/internal/game"
|
||||
mg "github.com/iliadenisov/galaxy/internal/model/game"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestDeclarePeaceAndWarSingle(t *testing.T) {
|
||||
g(t, func(f func(*game.Param), g func() mg.Game) {
|
||||
g(t, func(f func(*controller.Param), g func() mg.Game) {
|
||||
hostRace := "race_05"
|
||||
opponentRace := "race_01"
|
||||
|
||||
@@ -37,7 +38,7 @@ func TestDeclarePeaceAndWarSingle(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDeclarePeaceAndWarAll(t *testing.T) {
|
||||
g(t, func(f func(*game.Param), g func() mg.Game) {
|
||||
g(t, func(f func(*controller.Param), g func() mg.Game) {
|
||||
hostRace := "race_07"
|
||||
|
||||
for i := range testRaceCount {
|
||||
@@ -0,0 +1,28 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
"github.com/iliadenisov/galaxy/internal/controller"
|
||||
"github.com/iliadenisov/galaxy/internal/model/game"
|
||||
)
|
||||
|
||||
func LoadState(configure func(*controller.Param)) (g game.Game, err error) {
|
||||
control(configure, func(c *controller.Ctrl) { c.ExecuteInit(func(r controller.Repo) { g, err = c.Repo.LoadState() }) })
|
||||
return
|
||||
}
|
||||
|
||||
func GenerateGame(configure func(*controller.Param), races []string) (gameID uuid.UUID, err error) {
|
||||
control(configure, func(c *controller.Ctrl) {
|
||||
c.ExecuteInit(func(r controller.Repo) { gameID, err = controller.NewGame(r, races) })
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func control(configure func(*controller.Param), consumer func(*controller.Ctrl)) error {
|
||||
c, err := controller.NewController(configure)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
consumer(c)
|
||||
return nil
|
||||
}
|
||||
@@ -4,9 +4,11 @@ import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/iliadenisov/galaxy/pkg/game"
|
||||
mg "github.com/iliadenisov/galaxy/pkg/model/game"
|
||||
"github.com/iliadenisov/galaxy/pkg/util"
|
||||
"github.com/iliadenisov/galaxy/internal/controller"
|
||||
|
||||
"github.com/iliadenisov/galaxy/internal/game"
|
||||
mg "github.com/iliadenisov/galaxy/internal/model/game"
|
||||
"github.com/iliadenisov/galaxy/internal/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@@ -20,21 +22,21 @@ func raceNum(i int) string {
|
||||
}
|
||||
|
||||
func TestComposeGame(t *testing.T) {
|
||||
g(t, func(p func(*game.Param), g func() mg.Game) {
|
||||
g(t, func(p func(*controller.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(p func(*game.Param), g func() mg.Game)) {
|
||||
func g(t *testing.T, f func(p func(*controller.Param), g 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 }
|
||||
p := func(p *controller.Param) { p.StoragePath = root }
|
||||
_, err := game.GenerateGame(p, races)
|
||||
if err != nil {
|
||||
assert.FailNow(t, "g: ComposeGame", err)
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/iliadenisov/galaxy/pkg/generator"
|
||||
"github.com/iliadenisov/galaxy/internal/generator"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"math"
|
||||
"math/rand"
|
||||
|
||||
"github.com/iliadenisov/galaxy/pkg/generator/plotter"
|
||||
"github.com/iliadenisov/galaxy/internal/generator/plotter"
|
||||
)
|
||||
|
||||
type Map struct {
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/iliadenisov/galaxy/pkg/number"
|
||||
"github.com/iliadenisov/galaxy/internal/number"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
g "github.com/iliadenisov/galaxy/pkg/generator"
|
||||
g "github.com/iliadenisov/galaxy/internal/generator"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"math"
|
||||
"math/rand"
|
||||
|
||||
"github.com/iliadenisov/galaxy/pkg/bitmap"
|
||||
"github.com/iliadenisov/galaxy/internal/bitmap"
|
||||
)
|
||||
|
||||
type Plotter struct {
|
||||
@@ -3,7 +3,7 @@ package plotter_test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/iliadenisov/galaxy/pkg/generator/plotter"
|
||||
"github.com/iliadenisov/galaxy/internal/generator/plotter"
|
||||
)
|
||||
|
||||
func TestNewPlotter(t *testing.T) {
|
||||
@@ -0,0 +1,102 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"math"
|
||||
"slices"
|
||||
|
||||
"github.com/google/uuid"
|
||||
e "github.com/iliadenisov/galaxy/internal/error"
|
||||
)
|
||||
|
||||
type Fleet struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
OwnerID uuid.UUID `json:"ownerId"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// TODO: Hello! Wanna know fleet's speed? Good. Implement & test this func first.
|
||||
func (g Game) FleetSpeed(fl Fleet) float64 {
|
||||
result := math.MaxFloat64
|
||||
for sg := range g.ShipGroups {
|
||||
if g.ShipGroups[sg].FleetID == nil || *g.ShipGroups[sg].FleetID != fl.ID {
|
||||
continue
|
||||
}
|
||||
st := g.mustShipType(g.ShipGroups[sg].TypeID)
|
||||
typeSpeed := g.ShipGroups[sg].Speed(st)
|
||||
if typeSpeed < result {
|
||||
result = typeSpeed
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (g Game) JoinShipGroupToFleet(raceName, fleetName string, group, count uint) error {
|
||||
ri, err := g.raceIndex(raceName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return g.joinShipGroupToFleetInternal(ri, fleetName, group, count)
|
||||
}
|
||||
|
||||
func (g Game) joinShipGroupToFleetInternal(ri int, fleetName string, group, count uint) (err error) {
|
||||
name, ok := validateTypeName(fleetName)
|
||||
if !ok {
|
||||
return e.NewEntityTypeNameValidationError("%q", name)
|
||||
}
|
||||
sgi := -1
|
||||
var maxIndex uint
|
||||
for i, sg := range g.listShipGroups(ri) {
|
||||
if sgi < 0 && sg.Index == group {
|
||||
sgi = i
|
||||
}
|
||||
if sg.Index > maxIndex {
|
||||
maxIndex = sg.Index
|
||||
}
|
||||
}
|
||||
if sgi < 0 {
|
||||
return e.NewEntityNotExistsError("group #%d", group)
|
||||
}
|
||||
|
||||
if g.ShipGroups[sgi].Number < count {
|
||||
return e.NewJoinFleetGroupNumberNotEnoughError("%d<%d", g.ShipGroups[sgi].Number, count)
|
||||
}
|
||||
|
||||
fi := g.fleetIndex(ri, name)
|
||||
if fi < 0 {
|
||||
fi, err = g.createFleet(ri, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if g.ShipGroups[sgi].Number != count && count > 0 {
|
||||
newGroup := g.ShipGroups[sgi]
|
||||
newGroup.Number -= count
|
||||
g.ShipGroups[sgi].Number = count
|
||||
newGroup.Index = maxIndex + 1
|
||||
g.ShipGroups = append(g.ShipGroups, newGroup)
|
||||
}
|
||||
|
||||
g.ShipGroups[sgi].FleetID = &g.Fleets[fi].ID
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g Game) fleetIndex(ri int, name string) int {
|
||||
return slices.IndexFunc(g.Fleets, func(f Fleet) bool { return f.OwnerID == g.Race[ri].ID && f.Name == name })
|
||||
}
|
||||
|
||||
func (g Game) createFleet(ri int, name string) (int, error) {
|
||||
n, ok := validateTypeName(name)
|
||||
if !ok {
|
||||
return 0, e.NewEntityTypeNameValidationError("%q", n)
|
||||
}
|
||||
if fl := g.fleetIndex(ri, n); fl >= 0 {
|
||||
return 0, e.NewEntityTypeNameDuplicateError("fleet %w", g.Fleets[fl].Name)
|
||||
}
|
||||
g.Fleets = append(g.Fleets, Fleet{
|
||||
ID: uuid.New(),
|
||||
OwnerID: g.Race[ri].ID,
|
||||
Name: n,
|
||||
})
|
||||
return len(g.Fleets) - 1, nil
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/google/uuid"
|
||||
e "github.com/iliadenisov/galaxy/pkg/error"
|
||||
e "github.com/iliadenisov/galaxy/internal/error"
|
||||
)
|
||||
|
||||
type Game struct {
|
||||
@@ -6,6 +6,6 @@ func (g *Game) CreateShips(ri int, shipTypeName string, planetNumber int, quanti
|
||||
return g.createShips(ri, shipTypeName, planetNumber, quantity)
|
||||
}
|
||||
|
||||
func (g Game) ListShipGroups(ri int) iter.Seq[ShipGroup] {
|
||||
func (g Game) ListShipGroups(ri int) iter.Seq2[int, ShipGroup] {
|
||||
return g.listShipGroups(ri)
|
||||
}
|
||||
@@ -2,12 +2,13 @@ package game
|
||||
|
||||
import (
|
||||
"iter"
|
||||
"maps"
|
||||
"math"
|
||||
"slices"
|
||||
|
||||
"github.com/google/uuid"
|
||||
e "github.com/iliadenisov/galaxy/pkg/error"
|
||||
"github.com/iliadenisov/galaxy/pkg/number"
|
||||
e "github.com/iliadenisov/galaxy/internal/error"
|
||||
"github.com/iliadenisov/galaxy/internal/number"
|
||||
)
|
||||
|
||||
type CargoType string
|
||||
@@ -120,7 +121,7 @@ func (g *Game) JoinEqualGroups(raceName string) error {
|
||||
}
|
||||
|
||||
func (g *Game) joinEqualGroupsInternal(ri int) {
|
||||
shipGroups := slices.Collect(g.listShipGroups(ri))
|
||||
shipGroups := slices.Collect(maps.Values(maps.Collect(g.listShipGroups(ri))))
|
||||
origin := len(shipGroups)
|
||||
if origin < 2 {
|
||||
return
|
||||
@@ -155,7 +156,7 @@ func (g *Game) createShips(ri int, shipTypeName string, planetNumber int, quanti
|
||||
}
|
||||
|
||||
var maxIndex uint
|
||||
for sg := range g.listShipGroups(ri) {
|
||||
for _, sg := range g.listShipGroups(ri) {
|
||||
if sg.Index > maxIndex {
|
||||
maxIndex = sg.Index
|
||||
}
|
||||
@@ -175,11 +176,11 @@ func (g *Game) createShips(ri int, shipTypeName string, planetNumber int, quanti
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g Game) listShipGroups(ri int) iter.Seq[ShipGroup] {
|
||||
return func(yield func(ShipGroup) bool) {
|
||||
func (g Game) listShipGroups(ri int) iter.Seq2[int, ShipGroup] {
|
||||
return func(yield func(int, ShipGroup) bool) {
|
||||
for sg := range g.ShipGroups {
|
||||
if g.ShipGroups[sg].OwnerID == g.Race[ri].ID {
|
||||
if !yield(g.ShipGroups[sg]) {
|
||||
if !yield(sg, g.ShipGroups[sg]) {
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,15 @@
|
||||
package game_test
|
||||
|
||||
import (
|
||||
"iter"
|
||||
"math/rand/v2"
|
||||
"slices"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
e "github.com/iliadenisov/galaxy/pkg/error"
|
||||
gg "github.com/iliadenisov/galaxy/pkg/game"
|
||||
"github.com/iliadenisov/galaxy/pkg/model/game"
|
||||
"github.com/iliadenisov/galaxy/internal/controller"
|
||||
e "github.com/iliadenisov/galaxy/internal/error"
|
||||
"github.com/iliadenisov/galaxy/internal/model/game"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@@ -296,9 +297,9 @@ func TestJoinEqualGroups(t *testing.T) {
|
||||
Height: 10,
|
||||
Planet: make([]game.Planet, 3),
|
||||
}
|
||||
g.Map.Planet[0] = gg.NewPlanet(0, "Planet_0", g.Race[0].ID, 0, 0, 100, 0, 0, 0, game.ProductionNone.AsType(uuid.Nil))
|
||||
g.Map.Planet[1] = gg.NewPlanet(1, "Planet_1", g.Race[1].ID, 1, 1, 100, 0, 0, 0, game.ProductionNone.AsType(uuid.Nil))
|
||||
g.Map.Planet[2] = gg.NewPlanet(1, "Planet_2", g.Race[0].ID, 2, 2, 100, 0, 0, 0, game.ProductionNone.AsType(uuid.Nil))
|
||||
g.Map.Planet[0] = controller.NewPlanet(0, "Planet_0", g.Race[0].ID, 0, 0, 100, 0, 0, 0, game.ProductionNone.AsType(uuid.Nil))
|
||||
g.Map.Planet[1] = controller.NewPlanet(1, "Planet_1", g.Race[1].ID, 1, 1, 100, 0, 0, 0, game.ProductionNone.AsType(uuid.Nil))
|
||||
g.Map.Planet[2] = controller.NewPlanet(1, "Planet_2", g.Race[0].ID, 2, 2, 100, 0, 0, 0, game.ProductionNone.AsType(uuid.Nil))
|
||||
|
||||
err := g.CreateShipType("Race_0", "R0_Gunship", 60, 30, 100, 0, 3)
|
||||
assert.NoError(t, err)
|
||||
@@ -317,48 +318,48 @@ func TestJoinEqualGroups(t *testing.T) {
|
||||
|
||||
err = g.CreateShips(raceIdx, "R0_Freighter", 0, 1) // 1 -> 2
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, slices.Collect(g.ListShipGroups(raceIdx)), 1)
|
||||
assert.Len(t, collectGroups(g.ListShipGroups(raceIdx)), 1)
|
||||
|
||||
err = g.CreateShips(1, "R1_Freighter", 1, 1)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, slices.Collect(g.ListShipGroups(1)), 1)
|
||||
assert.Len(t, collectGroups(g.ListShipGroups(1)), 1)
|
||||
|
||||
err = g.CreateShips(raceIdx, "R0_Freighter", 0, 6) // (2)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, slices.Collect(g.ListShipGroups(raceIdx)), 2)
|
||||
assert.Len(t, collectGroups(g.ListShipGroups(raceIdx)), 2)
|
||||
|
||||
err = g.CreateShips(raceIdx, "R0_Gunship", 0, 2) // (3)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, slices.Collect(g.ListShipGroups(raceIdx)), 3)
|
||||
assert.Len(t, collectGroups(g.ListShipGroups(raceIdx)), 3)
|
||||
|
||||
err = g.CreateShips(1, "R1_Gunship", 1, 1)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, slices.Collect(g.ListShipGroups(1)), 2)
|
||||
assert.Len(t, collectGroups(g.ListShipGroups(1)), 2)
|
||||
|
||||
g.Race[raceIdx].Drive = 1.5
|
||||
err = g.CreateShips(raceIdx, "R0_Gunship", 0, 9) // 4 -> 6
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, slices.Collect(g.ListShipGroups(raceIdx)), 4)
|
||||
assert.Len(t, collectGroups(g.ListShipGroups(raceIdx)), 4)
|
||||
err = g.CreateShips(raceIdx, "R0_Freighter", 0, 7) // 5 -> 7
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, slices.Collect(g.ListShipGroups(raceIdx)), 5)
|
||||
assert.Len(t, collectGroups(g.ListShipGroups(raceIdx)), 5)
|
||||
err = g.CreateShips(raceIdx, "R0_Gunship", 0, 4) // (6)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, slices.Collect(g.ListShipGroups(raceIdx)), 6)
|
||||
assert.Len(t, collectGroups(g.ListShipGroups(raceIdx)), 6)
|
||||
err = g.CreateShips(raceIdx, "R0_Freighter", 0, 4) // (7)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, slices.Collect(g.ListShipGroups(raceIdx)), 7)
|
||||
assert.Len(t, collectGroups(g.ListShipGroups(raceIdx)), 7)
|
||||
|
||||
g.Race[1].Shields = 2.0
|
||||
err = g.CreateShips(1, "R1_Freighter", 1, 1)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, slices.Collect(g.ListShipGroups(1)), 3)
|
||||
assert.Len(t, collectGroups(g.ListShipGroups(1)), 3)
|
||||
|
||||
err = g.JoinEqualGroups("Race_0")
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Len(t, slices.Collect(g.ListShipGroups(1)), 3)
|
||||
assert.Len(t, slices.Collect(g.ListShipGroups(raceIdx)), 4)
|
||||
assert.Len(t, collectGroups(g.ListShipGroups(1)), 3)
|
||||
assert.Len(t, collectGroups(g.ListShipGroups(raceIdx)), 4)
|
||||
|
||||
shipTypeID := func(ri int, name string) uuid.UUID {
|
||||
st := slices.IndexFunc(g.Race[ri].ShipTypes, func(v game.ShipType) bool { return v.Name == name })
|
||||
@@ -369,7 +370,7 @@ func TestJoinEqualGroups(t *testing.T) {
|
||||
return g.Race[ri].ShipTypes[st].ID
|
||||
}
|
||||
|
||||
for sg := range g.ListShipGroups(raceIdx) {
|
||||
for _, sg := range g.ListShipGroups(raceIdx) {
|
||||
switch {
|
||||
case sg.TypeID == shipTypeID(raceIdx, "R0_Freighter") && sg.Drive == 1.1:
|
||||
assert.Equal(t, uint(7), sg.Number)
|
||||
@@ -388,3 +389,11 @@ func TestJoinEqualGroups(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func collectGroups(i iter.Seq2[int, game.ShipGroup]) []game.ShipGroup {
|
||||
result := make([]game.ShipGroup, 0)
|
||||
for _, sg := range i {
|
||||
result = append(result, sg)
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"slices"
|
||||
|
||||
"github.com/google/uuid"
|
||||
e "github.com/iliadenisov/galaxy/pkg/error"
|
||||
e "github.com/iliadenisov/galaxy/internal/error"
|
||||
)
|
||||
|
||||
type UnidentifiedPlanet struct {
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"slices"
|
||||
|
||||
"github.com/google/uuid"
|
||||
e "github.com/iliadenisov/galaxy/pkg/error"
|
||||
e "github.com/iliadenisov/galaxy/internal/error"
|
||||
)
|
||||
|
||||
type PlanetProduction string
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"slices"
|
||||
|
||||
"github.com/google/uuid"
|
||||
e "github.com/iliadenisov/galaxy/pkg/error"
|
||||
e "github.com/iliadenisov/galaxy/internal/error"
|
||||
)
|
||||
|
||||
type Science struct {
|
||||
@@ -74,6 +74,9 @@ func (g Game) createScienceInternal(ri int, name string, d, w, s, c float64) err
|
||||
if !ok {
|
||||
return e.NewEntityTypeNameValidationError("%q", n)
|
||||
}
|
||||
if sc := slices.IndexFunc(g.Race[ri].Sciences, func(s Science) bool { return s.Name == n }); sc >= 0 {
|
||||
return e.NewEntityTypeNameDuplicateError("science %w", g.Race[ri].Sciences[sc].Name)
|
||||
}
|
||||
if d < 0 {
|
||||
return e.NewDriveValueError(d)
|
||||
}
|
||||
@@ -90,9 +93,6 @@ func (g Game) createScienceInternal(ri int, name string, d, w, s, c float64) err
|
||||
if sum != 1 {
|
||||
return e.NewScienceSumValuesError("D=%f W=%f S=%f C=%f sum=%f", d, w, s, c, sum)
|
||||
}
|
||||
if sc := slices.IndexFunc(g.Race[ri].Sciences, func(s Science) bool { return s.Name == n }); sc >= 0 {
|
||||
return e.NewEntityTypeNameDuplicateError("science %w", g.Race[ri].Sciences[sc].Name)
|
||||
}
|
||||
g.Race[ri].Sciences = append(g.Race[ri].Sciences, Science{
|
||||
ID: uuid.New(),
|
||||
ScienceReport: ScienceReport{
|
||||
@@ -2,11 +2,10 @@ package game
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"slices"
|
||||
|
||||
"github.com/google/uuid"
|
||||
e "github.com/iliadenisov/galaxy/pkg/error"
|
||||
e "github.com/iliadenisov/galaxy/internal/error"
|
||||
)
|
||||
|
||||
type ShipTypeReport struct {
|
||||
@@ -28,11 +27,6 @@ type ShipTypeReportForeign struct {
|
||||
ShipTypeReport
|
||||
}
|
||||
|
||||
type Fleet struct {
|
||||
OwnerID uuid.UUID `json:"ownerId"`
|
||||
ShipGroups []ShipGroup `json:"group"`
|
||||
}
|
||||
|
||||
func (st ShipType) Equal(o ShipType) bool {
|
||||
return st.Drive == o.Drive &&
|
||||
st.Weapons == o.Weapons &&
|
||||
@@ -60,18 +54,6 @@ func (st ShipType) ProductionCost() (mat float64, pop float64) {
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: test this
|
||||
func (g Game) FleetSpeed(fl *Fleet) float64 {
|
||||
result := math.MaxFloat64
|
||||
for _, sg := range fl.ShipGroups {
|
||||
st := g.mustShipType(sg.TypeID)
|
||||
if sg.Speed(st) < result {
|
||||
result = sg.Speed(st)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (g Game) mustShipType(id uuid.UUID) *ShipType {
|
||||
for ri := range g.Race {
|
||||
if st := slices.IndexFunc(g.Race[ri].ShipTypes, func(st ShipType) bool { return st.ID == id }); st >= 0 {
|
||||
@@ -3,7 +3,7 @@ package game_test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/iliadenisov/galaxy/pkg/model/game"
|
||||
"github.com/iliadenisov/galaxy/internal/model/game"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/iliadenisov/galaxy/pkg/util"
|
||||
"github.com/iliadenisov/galaxy/internal/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/iliadenisov/galaxy/pkg/util"
|
||||
"github.com/iliadenisov/galaxy/internal/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@@ -11,7 +11,7 @@ package repo
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/iliadenisov/galaxy/pkg/model/game"
|
||||
"github.com/iliadenisov/galaxy/internal/model/game"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -4,8 +4,8 @@ import (
|
||||
"encoding"
|
||||
"errors"
|
||||
|
||||
e "github.com/iliadenisov/galaxy/pkg/error"
|
||||
"github.com/iliadenisov/galaxy/pkg/repo/fs"
|
||||
e "github.com/iliadenisov/galaxy/internal/error"
|
||||
"github.com/iliadenisov/galaxy/internal/repo/fs"
|
||||
)
|
||||
|
||||
func NewStorageError(err error) error {
|
||||
@@ -1,19 +0,0 @@
|
||||
package game
|
||||
|
||||
import "github.com/iliadenisov/galaxy/pkg/model/game"
|
||||
|
||||
func JoinEqualGroups(configure func(*Param), race string) (err error) {
|
||||
control(configure, func(c *ctrl) {
|
||||
c.execute(func(r Repo, g game.Game) {
|
||||
err = joinEqualGroups(r, g, race)
|
||||
})
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func joinEqualGroups(r Repo, g game.Game, race string) error {
|
||||
if err := g.JoinEqualGroups(race); err != nil {
|
||||
return err
|
||||
}
|
||||
return r.SaveState(g)
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package game_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/iliadenisov/galaxy/pkg/game"
|
||||
mg "github.com/iliadenisov/galaxy/pkg/model/game"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestJoinEqualGroups(t *testing.T) {
|
||||
g(t, func(p func(*game.Param), g func() mg.Game) {
|
||||
err := game.JoinEqualGroups(p, "race_01")
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package game
|
||||
|
||||
import "github.com/iliadenisov/galaxy/pkg/model/game"
|
||||
|
||||
func RenamePlanet(configure func(*Param), race string, number int, name string) (err error) {
|
||||
control(configure, func(c *ctrl) {
|
||||
c.execute(func(r Repo, g game.Game) {
|
||||
err = renamePlanet(r, g, race, number, name)
|
||||
})
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func renamePlanet(r Repo, g game.Game, race string, number int, name string) error {
|
||||
if err := g.RenamePlanet(race, number, name); err != nil {
|
||||
return err
|
||||
}
|
||||
return r.SaveState(g)
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package game
|
||||
|
||||
import "github.com/iliadenisov/galaxy/pkg/model/game"
|
||||
|
||||
func PlanetProduction(configure func(*Param), race string, planetNumber int, prodType, subject string) (err error) {
|
||||
control(configure, func(c *ctrl) {
|
||||
c.execute(func(r Repo, g game.Game) {
|
||||
err = planetProduction(r, g, race, planetNumber, prodType, subject)
|
||||
})
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func planetProduction(r Repo, g game.Game, race string, planetNumber int, prodType, subject string) error {
|
||||
if err := g.PlanetProduction(race, planetNumber, prodType, subject); err != nil {
|
||||
return err
|
||||
}
|
||||
return r.SaveState(g)
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package game
|
||||
|
||||
import "github.com/iliadenisov/galaxy/pkg/model/game"
|
||||
|
||||
func CreateScience(configure func(*Param), race, typeName string, drive, weapons, shields, cargo float64) (err error) {
|
||||
control(configure, func(c *ctrl) {
|
||||
c.execute(func(r Repo, g game.Game) {
|
||||
err = createScience(r, g, race, typeName, drive, weapons, shields, cargo)
|
||||
})
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func createScience(r Repo, g game.Game, race, typeName string, d, w, s, c float64) error {
|
||||
if err := g.CreateScience(race, typeName, d, w, s, c); err != nil {
|
||||
return err
|
||||
}
|
||||
return r.SaveState(g)
|
||||
}
|
||||
|
||||
func DeleteScience(configure func(*Param), race, typeName string) (err error) {
|
||||
control(configure, func(c *ctrl) {
|
||||
c.execute(func(r Repo, g game.Game) {
|
||||
err = deleteScience(r, g, race, typeName)
|
||||
})
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func deleteScience(r Repo, g game.Game, race, typeName string) error {
|
||||
if err := g.DeleteScience(race, typeName); err != nil {
|
||||
return err
|
||||
}
|
||||
return r.SaveState(g)
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
package game
|
||||
|
||||
import "github.com/iliadenisov/galaxy/pkg/model/game"
|
||||
|
||||
func CreateShipType(configure func(*Param), race, typeName string, drive, weapons, shields, cargo float64, armament int) (err error) {
|
||||
control(configure, func(c *ctrl) {
|
||||
c.execute(func(r Repo, g game.Game) {
|
||||
err = createShipType(r, g, race, typeName, drive, weapons, shields, cargo, armament)
|
||||
})
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func createShipType(r Repo, g game.Game, race, typeName string, d, w, s, c float64, a int) error {
|
||||
if err := g.CreateShipType(race, typeName, d, w, s, c, a); err != nil {
|
||||
return err
|
||||
}
|
||||
return r.SaveState(g)
|
||||
}
|
||||
|
||||
func MergeShipType(configure func(*Param), race, source, target string) (err error) {
|
||||
control(configure, func(c *ctrl) {
|
||||
c.execute(func(r Repo, g game.Game) {
|
||||
err = mergeShipType(r, g, race, source, target)
|
||||
})
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func mergeShipType(r Repo, g game.Game, race, source, target string) error {
|
||||
if err := g.MergeShipType(race, source, target); err != nil {
|
||||
return err
|
||||
}
|
||||
return r.SaveState(g)
|
||||
}
|
||||
|
||||
func DeleteShipType(configure func(*Param), race, typeName string) (err error) {
|
||||
control(configure, func(c *ctrl) {
|
||||
c.execute(func(r Repo, g game.Game) {
|
||||
err = deleteShipType(r, g, race, typeName)
|
||||
})
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func deleteShipType(r Repo, g game.Game, race, typeName string) error {
|
||||
if err := g.DeleteShipType(race, typeName); err != nil {
|
||||
return err
|
||||
}
|
||||
return r.SaveState(g)
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
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, 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, g game.Game) { err = updateRelation(r, g, from, to, game.RelationPeace) })
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/iliadenisov/galaxy/pkg/model/game"
|
||||
"github.com/iliadenisov/galaxy/pkg/repo"
|
||||
)
|
||||
|
||||
type ctrl struct {
|
||||
param Param
|
||||
repo Repo
|
||||
}
|
||||
|
||||
type Param struct {
|
||||
StoragePath string
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func newController(configure func(*Param)) (*ctrl, error) {
|
||||
c := &Param{
|
||||
StoragePath: ".",
|
||||
}
|
||||
if configure != nil {
|
||||
configure(c)
|
||||
}
|
||||
r, err := repo.NewFileRepo(c.StoragePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ctrl{
|
||||
param: *c,
|
||||
repo: r,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func control(configure func(*Param), consumer func(*ctrl)) error {
|
||||
c, err := newController(configure)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
consumer(c)
|
||||
return nil
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package game
|
||||
|
||||
import "github.com/iliadenisov/galaxy/pkg/model/game"
|
||||
|
||||
type Repo interface {
|
||||
// Lock must be called before any repository operations
|
||||
Lock() error
|
||||
|
||||
// Release must be called after first and only repository operation
|
||||
Release() error
|
||||
|
||||
// SaveTurn stores just generated new turn
|
||||
SaveTurn(uint, game.Game) error
|
||||
|
||||
// SaveState stores current game state updated between turns
|
||||
SaveState(game.Game) error
|
||||
|
||||
// LoadState retrieves game current state
|
||||
LoadState() (game.Game, error)
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package command
|
||||
|
||||
type Command struct {
|
||||
FromRace string
|
||||
}
|
||||
|
||||
type CommandAlly struct {
|
||||
Command
|
||||
ToRace string
|
||||
}
|
||||
|
||||
type CommandWar struct {
|
||||
Command
|
||||
ToRace string
|
||||
}
|
||||
Reference in New Issue
Block a user