saving new turn
This commit is contained in:
+3
-3
@@ -10,7 +10,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Repo interface {
|
type Repo interface {
|
||||||
Persist(game.Game) error
|
SaveTurn(uint, game.Game) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGame(r Repo, races []string) (uuid.UUID, error) {
|
func NewGame(r Repo, races []string) (uuid.UUID, error) {
|
||||||
@@ -46,7 +46,7 @@ func NewGame(r Repo, races []string) (uuid.UUID, error) {
|
|||||||
g.Race[i] = game.Race{
|
g.Race[i] = game.Race{
|
||||||
ID: raceID,
|
ID: raceID,
|
||||||
Name: races[i],
|
Name: races[i],
|
||||||
Ally: raceID,
|
Vote: raceID,
|
||||||
Drive: 1,
|
Drive: 1,
|
||||||
Weapons: 1,
|
Weapons: 1,
|
||||||
Shields: 1,
|
Shields: 1,
|
||||||
@@ -104,7 +104,7 @@ func NewGame(r Repo, races []string) (uuid.UUID, error) {
|
|||||||
|
|
||||||
g.Map = *gameMap
|
g.Map = *gameMap
|
||||||
|
|
||||||
if err := r.Persist(*g); err != nil {
|
if err := r.SaveTurn(0, *g); err != nil {
|
||||||
return uuid.Nil, fmt.Errorf("persist: %s", err)
|
return uuid.Nil, fmt.Errorf("persist: %s", err)
|
||||||
}
|
}
|
||||||
return g.ID, nil
|
return g.ID, nil
|
||||||
|
|||||||
+13
-5
@@ -1,12 +1,16 @@
|
|||||||
package game
|
package game
|
||||||
|
|
||||||
import "github.com/google/uuid"
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
type Game struct {
|
type Game struct {
|
||||||
ID uuid.UUID
|
ID uuid.UUID `json:"id"`
|
||||||
Age uint // Game's turn number
|
Age uint `json:"turn"` // Game's turn number
|
||||||
Map Map
|
Map Map `json:"map"`
|
||||||
Race []Race
|
Race []Race `json:"races"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g Game) Votes(raceID uuid.UUID) float64 {
|
func (g Game) Votes(raceID uuid.UUID) float64 {
|
||||||
@@ -19,3 +23,7 @@ func (g Game) Votes(raceID uuid.UUID) float64 {
|
|||||||
}
|
}
|
||||||
return pop / 1000.
|
return pop / 1000.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g Game) MarshalBinary() (data []byte, err error) {
|
||||||
|
return json.Marshal(&g)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package game
|
package game
|
||||||
|
|
||||||
type Map struct {
|
type Map struct {
|
||||||
Width uint32
|
Width uint32 `json:"width"`
|
||||||
Height uint32
|
Height uint32 `json:"height"`
|
||||||
Planet []Planet
|
Planet []Planet `json:"planets"`
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-12
@@ -7,21 +7,22 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Planet struct {
|
type Planet struct {
|
||||||
X, Y float64
|
X float64 `json:"x"`
|
||||||
Size float64
|
Y float64 `json:"y"`
|
||||||
|
Size float64 `json:"size"`
|
||||||
|
|
||||||
Name string
|
Name string `json:"name"`
|
||||||
Number uint
|
Number uint `json:"number"`
|
||||||
Owner uuid.UUID
|
Owner uuid.UUID `json:"owner"`
|
||||||
|
|
||||||
Production ProductionType
|
Production ProductionType `json:"production"`
|
||||||
Population float64 // P - Население
|
Population float64 `json:"population"` // P - Население
|
||||||
Industry float64 // I - Промышленность
|
Industry float64 `json:"industry"` // I - Промышленность
|
||||||
Resources float64 // R - Ресурсы / сырьё
|
Resources float64 `json:"resources"` // R - Ресурсы / сырьё
|
||||||
|
|
||||||
Capital float64 // CAP $ - Запасы промышленности
|
Capital float64 `json:"capital"` // CAP $ - Запасы промышленности
|
||||||
Material float64 // MAT M - Запасы ресурсов / сырья
|
Material float64 `json:"material"` // MAT M - Запасы ресурсов / сырья
|
||||||
Colonists float64 // COL C - Количество колонистов
|
Colonists float64 `json:"colonists"` // COL C - Количество колонистов
|
||||||
// Параметр "L" - Свободный производственный потенциал
|
// Параметр "L" - Свободный производственный потенциал
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type ProductionType struct {
|
type ProductionType struct {
|
||||||
Production PlanetProduction
|
Production PlanetProduction `json:"type"`
|
||||||
SubjectName string // TODO: change to UUID
|
SubjectName string `json:"subject"` // TODO: change to UUID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p PlanetProduction) AsType(subject string) ProductionType {
|
func (p PlanetProduction) AsType(subject string) ProductionType {
|
||||||
|
|||||||
+20
-9
@@ -3,17 +3,28 @@ package game
|
|||||||
import "github.com/google/uuid"
|
import "github.com/google/uuid"
|
||||||
|
|
||||||
type Race struct {
|
type Race struct {
|
||||||
ID uuid.UUID
|
ID uuid.UUID `json:"id"`
|
||||||
Name string
|
Name string `json:"name"`
|
||||||
Killed bool
|
Extinct bool `json:"extinct"`
|
||||||
|
|
||||||
// Votes float64
|
Vote uuid.UUID `json:"vote"`
|
||||||
Ally uuid.UUID // Race's Votes receiver
|
Relations []RaceRelation `json:"relations"`
|
||||||
|
|
||||||
Drive float64
|
Drive float64 `json:"drive"`
|
||||||
Weapons float64
|
Weapons float64 `json:"weapons"`
|
||||||
Shields float64
|
Shields float64 `json:"shields"`
|
||||||
Cargo float64
|
Cargo float64 `json:"cargo"`
|
||||||
|
|
||||||
|
Sciences []Science `json:"science,omitempty"`
|
||||||
|
|
||||||
|
ShipTypes []ShipType `json:"shipType,omitempty"`
|
||||||
|
ShipGroups []ShipGroup `json:"shipGroup,omitempty"`
|
||||||
|
Fleets []Fleet `json:"fleet,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RaceRelation struct {
|
||||||
|
RaceID uuid.UUID `json:"raceId"`
|
||||||
|
Peace bool `json:"peace"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r Race) FlightDistance() float64 {
|
func (r Race) FlightDistance() float64 {
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
package game
|
package game
|
||||||
|
|
||||||
|
import "github.com/google/uuid"
|
||||||
|
|
||||||
type Science struct {
|
type Science struct {
|
||||||
Name string
|
ID uuid.UUID `json:"id"`
|
||||||
Drive float64
|
Name string `json:"name"`
|
||||||
Weapons float64
|
Drive float64 `json:"drive"`
|
||||||
Shields float64
|
Weapons float64 `json:"weapons"`
|
||||||
Cargo float64
|
Shields float64 `json:"shields"`
|
||||||
|
Cargo float64 `json:"cargo"`
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-15
@@ -3,31 +3,34 @@ package game
|
|||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
"github.com/iliadenisov/galaxy/pkg/number"
|
"github.com/iliadenisov/galaxy/pkg/number"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ShipType struct {
|
type ShipType struct {
|
||||||
Name string
|
ID uuid.UUID `json:"id"`
|
||||||
Drive float64 // [0], [1...]
|
Name string `json:"name"`
|
||||||
Armament uint
|
Drive float64 `json:"drive"` // [0], [1...]
|
||||||
Weapons float64 // [0], [1...]
|
Armament uint `json:"armament"`
|
||||||
Shields float64 // [0], [1...]
|
Weapons float64 `json:"weapons"` // [0], [1...]
|
||||||
Cargo float64 // [0], [1...]
|
Shields float64 `json:"shields"` // [0], [1...]
|
||||||
|
Cargo float64 `json:"cargo"` // [0], [1...]
|
||||||
}
|
}
|
||||||
|
|
||||||
type ShipGroup struct {
|
type ShipGroup struct {
|
||||||
Type ShipType
|
TypeID uuid.UUID `json:"id"`
|
||||||
Number uint
|
Type ShipType `json:"-"` // TODO: fill upon load from store
|
||||||
State string // TODO: kinda enum: In_Orbit, In_Space, Transfer_State, Upgrade
|
Number uint `json:"number"`
|
||||||
Load float64 // Cargo loaded - "Масса груза"
|
State string `json:"state"` // TODO: kinda enum: In_Orbit, In_Space, Transfer_State, Upgrade
|
||||||
Drive float64
|
Load float64 `json:"load"` // Cargo loaded - "Масса груза"
|
||||||
Weapons float64
|
Drive float64 `json:"drive"`
|
||||||
Shields float64
|
Weapons float64 `json:"weapons"`
|
||||||
Cargo float64
|
Shields float64 `json:"shields"`
|
||||||
|
Cargo float64 `json:"cargo"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Fleet struct {
|
type Fleet struct {
|
||||||
ShipGroups []ShipGroup
|
ShipGroups []ShipGroup `json:"group"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: test on real values
|
// TODO: test on real values
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_ShipType(t *testing.T) {
|
func TestShipType(t *testing.T) {
|
||||||
Gunship := game.ShipType{
|
Gunship := game.ShipType{
|
||||||
Drive: 4,
|
Drive: 4,
|
||||||
Armament: 2,
|
Armament: 2,
|
||||||
@@ -42,7 +42,7 @@ func Test_ShipType(t *testing.T) {
|
|||||||
assert.Equal(t, upgradeCost, 225.)
|
assert.Equal(t, upgradeCost, 225.)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_CargoCapacity(t *testing.T) {
|
func TestCargoCapacity(t *testing.T) {
|
||||||
test := func(cargoSize float64, expectCapacity float64) {
|
test := func(cargoSize float64, expectCapacity float64) {
|
||||||
ship := game.ShipType{
|
ship := game.ShipType{
|
||||||
Drive: 1,
|
Drive: 1,
|
||||||
@@ -69,7 +69,7 @@ func Test_CargoCapacity(t *testing.T) {
|
|||||||
test(100, 600)
|
test(100, 600)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_BombingPower(t *testing.T) {
|
func TestBombingPower(t *testing.T) {
|
||||||
Gunship := game.ShipType{
|
Gunship := game.ShipType{
|
||||||
Drive: 60.0,
|
Drive: 60.0,
|
||||||
Armament: 3,
|
Armament: 3,
|
||||||
@@ -75,6 +75,10 @@ func (f *fs) Lock() (func() error, error) {
|
|||||||
return unlock, nil
|
return unlock, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *fs) Exist(path string) (bool, error) {
|
||||||
|
return fileExists(filepath.Join(f.root, path))
|
||||||
|
}
|
||||||
|
|
||||||
func (f *fs) Write(path string, v encoding.BinaryMarshaler) error {
|
func (f *fs) Write(path string, v encoding.BinaryMarshaler) error {
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return errors.New("cant't marshal from nil object")
|
return errors.New("cant't marshal from nil object")
|
||||||
|
|||||||
@@ -33,6 +33,27 @@ func TestLock(t *testing.T) {
|
|||||||
assert.False(t, exists, "lock file must be removed")
|
assert.False(t, exists, "lock file must be removed")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestExist(t *testing.T) {
|
||||||
|
root, cleanup := createWorkDir(t)
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
fileName := "some-file.ext"
|
||||||
|
if err := os.WriteFile(filepath.Join(root, fileName), []byte{1, 2, 3, 4}, os.ModePerm); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fs, err := NewFileStorage(root)
|
||||||
|
assert.NoError(t, err, "create file storage")
|
||||||
|
|
||||||
|
exist, err := fs.Exist(fileName)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, exist)
|
||||||
|
|
||||||
|
exist, err = fs.Exist("random/path")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.False(t, exist)
|
||||||
|
}
|
||||||
|
|
||||||
func TestWrite(t *testing.T) {
|
func TestWrite(t *testing.T) {
|
||||||
root, cleanup := createWorkDir(t)
|
root, cleanup := createWorkDir(t)
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package repo
|
||||||
|
|
||||||
|
/*
|
||||||
|
/state.json
|
||||||
|
/000/state.json
|
||||||
|
/000/race/{UUID}/order/001.json
|
||||||
|
/000/race/{UUID}/report.json
|
||||||
|
/000/battle/{planet_UUID}
|
||||||
|
*/
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/iliadenisov/galaxy/pkg/model/game"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (r *repo) SaveTurn(t uint, g game.Game) error {
|
||||||
|
return saveTurn(r.s, t, g)
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveTurn(s Storage, t uint, g game.Game) error {
|
||||||
|
path := fmt.Sprintf("%03d/state.json", t)
|
||||||
|
exist, err := s.Exist(path)
|
||||||
|
if err != nil {
|
||||||
|
return NewStorageError(err)
|
||||||
|
}
|
||||||
|
if exist {
|
||||||
|
return NewStateError(fmt.Sprintf("state for turn %d already saved", t))
|
||||||
|
}
|
||||||
|
if err := s.Write(path, g); err != nil {
|
||||||
|
return NewStorageError(err)
|
||||||
|
}
|
||||||
|
// TODO: save reports
|
||||||
|
// TODO: save battles
|
||||||
|
return saveState(s, g)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *repo) SaveState(g game.Game) error {
|
||||||
|
return saveState(r.s, g)
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveState(s Storage, g game.Game) error {
|
||||||
|
path := "state.json"
|
||||||
|
if err := s.Write(path, g); err != nil {
|
||||||
|
return NewStorageError(err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -2,12 +2,26 @@ package repo
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding"
|
"encoding"
|
||||||
|
"errors"
|
||||||
|
|
||||||
"github.com/iliadenisov/galaxy/pkg/repo/fs"
|
"github.com/iliadenisov/galaxy/pkg/repo/fs"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type StorageError error
|
||||||
|
|
||||||
|
func NewStorageError(err error) error {
|
||||||
|
return StorageError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
type StateError error
|
||||||
|
|
||||||
|
func NewStateError(msg string) error {
|
||||||
|
return StateError(errors.New(msg))
|
||||||
|
}
|
||||||
|
|
||||||
type Storage interface {
|
type Storage interface {
|
||||||
Lock() (func() error, error)
|
Lock() (func() error, error)
|
||||||
|
Exist(string) (bool, error)
|
||||||
Write(string, encoding.BinaryMarshaler) error
|
Write(string, encoding.BinaryMarshaler) error
|
||||||
Read(string, encoding.BinaryUnmarshaler) error
|
Read(string, encoding.BinaryUnmarshaler) error
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user