refactor: floats, tests
This commit is contained in:
@@ -1,80 +0,0 @@
|
||||
package game
|
||||
|
||||
// import (
|
||||
// "fmt"
|
||||
// "slices"
|
||||
|
||||
// e "github.com/iliadenisov/galaxy/internal/error"
|
||||
// "github.com/iliadenisov/galaxy/internal/util"
|
||||
// )
|
||||
|
||||
// func (g *Game) SendFleet(raceName, fleetName string, planetNumber uint) error {
|
||||
// ri, err := g.raceIndex(raceName)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// fi := g.fleetIndex(ri, fleetName)
|
||||
// if fi < 0 {
|
||||
// return e.NewEntityNotExistsError("fleet %q", fleetName)
|
||||
// }
|
||||
// return g.sendFleetInternal(ri, fi, planetNumber)
|
||||
// }
|
||||
|
||||
// func (g *Game) sendFleetInternal(ri, fi int, planetNumber uint) error {
|
||||
// state, sourcePlanet, _ := FleetState(g, g.Fleets[fi].ID)
|
||||
// if StateInOrbit != state && StateLaunched != state {
|
||||
// return e.NewShipsBusyError()
|
||||
// }
|
||||
|
||||
// p1, ok := PlanetByNum(g, *sourcePlanet)
|
||||
// if !ok {
|
||||
// return e.NewGameStateError("source planet #%d does not exists", sourcePlanet)
|
||||
// }
|
||||
// p2, ok := PlanetByNum(g, planetNumber)
|
||||
// if !ok {
|
||||
// return e.NewEntityNotExistsError("destination planet #%d", planetNumber)
|
||||
// }
|
||||
// rangeToDestination := util.ShortDistance(g.Map.Width, g.Map.Height, p1.X, p1.Y, p2.X, p2.Y)
|
||||
// if rangeToDestination > g.Race[ri].FlightDistance() {
|
||||
// return e.NewSendUnreachableDestinationError("range=%.03f", rangeToDestination)
|
||||
// }
|
||||
|
||||
// for sg := range FleetGroups(g, ri, fi) {
|
||||
// st, ok := ShipClass(g, ri, sg.TypeID)
|
||||
// if !ok {
|
||||
// return e.NewGameStateError("not found: ShipType ID=%v", sg.TypeID)
|
||||
// }
|
||||
// if st.DriveBlockMass() == 0 {
|
||||
// return e.NewSendShipHasNoDrivesError("Class=%s", st.Name)
|
||||
// }
|
||||
// }
|
||||
|
||||
// if *sourcePlanet == planetNumber {
|
||||
// UnsendFleet(g, ri, fi)
|
||||
// return nil
|
||||
// }
|
||||
|
||||
// LaunchFleet(g, ri, fi, planetNumber)
|
||||
|
||||
// return nil
|
||||
// }
|
||||
|
||||
// func LaunchFleet(g *Game, ri, fi int, destination uint) {
|
||||
// for sg := range FleetGroups(g, ri, fi) {
|
||||
// sgi := slices.IndexFunc(g.ShipGroups, func(s ShipGroup) bool { return sg.Index == s.Index })
|
||||
// if sgi < 0 {
|
||||
// panic(fmt.Sprintf("LauncgFleet: cannot find ship group index=%d", sg.Index))
|
||||
// }
|
||||
// g.ShipGroups[sgi] = LaunchShips(sg, destination)
|
||||
// }
|
||||
// }
|
||||
|
||||
// func UnsendFleet(g *Game, ri, fi int) {
|
||||
// for sg := range FleetGroups(g, ri, fi) {
|
||||
// sgi := slices.IndexFunc(g.ShipGroups, func(s ShipGroup) bool { return sg.Index == s.Index })
|
||||
// if sgi < 0 {
|
||||
// panic(fmt.Sprintf("UnsendFleet: cannot find ship group index=%d", sg.Index))
|
||||
// }
|
||||
// g.ShipGroups[sgi] = UnsendShips(sg)
|
||||
// }
|
||||
// }
|
||||
@@ -1,73 +0,0 @@
|
||||
package game_test
|
||||
|
||||
// import (
|
||||
// "slices"
|
||||
// "testing"
|
||||
|
||||
// e "github.com/iliadenisov/galaxy/internal/error"
|
||||
// "github.com/iliadenisov/galaxy/internal/model/game"
|
||||
// "github.com/stretchr/testify/assert"
|
||||
// )
|
||||
|
||||
// func TestSendFleet(t *testing.T) {
|
||||
// g := newGame()
|
||||
// // group #1 - in_orbit Planet_0
|
||||
// assert.NoError(t, g.CreateShips(Race_0_idx, Race_0_Freighter, R0_Planet_0_num, 1))
|
||||
// // group #2 - in_space (later)
|
||||
// assert.NoError(t, g.CreateShips(Race_0_idx, Race_0_Gunship, R0_Planet_0_num, 3))
|
||||
// // group #3 - in_orbit Planet_0, unmovable
|
||||
// g.CreateShipType(Race_0.Name, "Fortress", 0, 50, 30, 100, 0)
|
||||
// assert.NoError(t, g.CreateShips(Race_0_idx, "Fortress", R0_Planet_0_num, 1))
|
||||
// // group #4 - in_orbit Planet_0
|
||||
// assert.NoError(t, g.CreateShips(Race_0_idx, Race_0_Gunship, R0_Planet_0_num, 2))
|
||||
|
||||
// // ensure race has no Fleets
|
||||
// assert.Len(t, slices.Collect(g.ListFleets(Race_0_idx)), 0)
|
||||
|
||||
// fleetSending := "R0_Fleet_one"
|
||||
// fleetInSpace := "R0_Fleet_inSpace"
|
||||
// fleetUnmovable := "R0_Fleet_unmovable"
|
||||
|
||||
// assert.NoError(t, g.JoinShipGroupToFleet(Race_0.Name, fleetSending, 1, 0))
|
||||
// assert.NoError(t, g.JoinShipGroupToFleet(Race_0.Name, fleetSending, 3, 0))
|
||||
|
||||
// assert.NoError(t, g.JoinShipGroupToFleet(Race_0.Name, fleetInSpace, 2, 0))
|
||||
// assert.NoError(t, g.JoinShipGroupToFleet(Race_0.Name, fleetUnmovable, 3, 0))
|
||||
// // group #2 - in_space
|
||||
// g.ShipGroups[1].StateInSpace = &game.InSpace{Origin: 2, Range: 1.23}
|
||||
|
||||
// assert.ErrorContains(t,
|
||||
// g.SendFleet("UnknownRace", fleetSending, 2),
|
||||
// e.GenericErrorText(e.ErrInputUnknownRace))
|
||||
// assert.ErrorContains(t,
|
||||
// g.SendFleet(Race_0.Name, "UnknownFleet", 2),
|
||||
// e.GenericErrorText(e.ErrInputEntityNotExists))
|
||||
// assert.ErrorContains(t,
|
||||
// g.SendFleet(Race_0.Name, fleetInSpace, 2),
|
||||
// e.GenericErrorText(e.ErrShipsBusy))
|
||||
// assert.ErrorContains(t,
|
||||
// g.SendFleet(Race_0.Name, fleetSending, 200),
|
||||
// e.GenericErrorText(e.ErrInputEntityNotExists))
|
||||
// assert.ErrorContains(t,
|
||||
// g.SendFleet(Race_0.Name, fleetSending, 3),
|
||||
// e.GenericErrorText(e.ErrSendUnreachableDestination))
|
||||
// assert.ErrorContains(t,
|
||||
// g.SendFleet(Race_0.Name, fleetUnmovable, 2),
|
||||
// e.GenericErrorText(e.ErrSendShipHasNoDrives))
|
||||
|
||||
// assert.NoError(t, g.SendFleet(Race_0.Name, fleetSending, 2))
|
||||
// fi := slices.IndexFunc(slices.Collect(g.ListFleets(Race_0_idx)), func(f game.Fleet) bool { return f.Name == fleetSending })
|
||||
// state, _, _ := game.FleetState(g, g.Fleets[fi].ID)
|
||||
// assert.Equal(t, game.StateLaunched, state)
|
||||
// for sg := range game.FleetGroups(g, Race_0_idx, fi) {
|
||||
// assert.Equal(t, game.StateLaunched, sg.State())
|
||||
// }
|
||||
|
||||
// assert.NoError(t, g.SendFleet(Race_0.Name, fleetSending, 0))
|
||||
// fi = slices.IndexFunc(slices.Collect(g.ListFleets(Race_0_idx)), func(f game.Fleet) bool { return f.Name == fleetSending })
|
||||
// state, _, _ = game.FleetState(g, g.Fleets[fi].ID)
|
||||
// assert.Equal(t, game.StateInOrbit, state)
|
||||
// for sg := range game.FleetGroups(g, Race_0_idx, fi) {
|
||||
// assert.Equal(t, game.StateInOrbit, sg.State())
|
||||
// }
|
||||
// }
|
||||
@@ -1,136 +0,0 @@
|
||||
package game_test
|
||||
|
||||
// import (
|
||||
// "slices"
|
||||
// "testing"
|
||||
|
||||
// e "github.com/iliadenisov/galaxy/internal/error"
|
||||
// "github.com/iliadenisov/galaxy/internal/model/game"
|
||||
// "github.com/stretchr/testify/assert"
|
||||
// )
|
||||
|
||||
// func TestJoinShipGroupToFleet(t *testing.T) {
|
||||
// g := newGame()
|
||||
// var groupIndex uint = 1
|
||||
|
||||
// assert.ErrorContains(t,
|
||||
// g.JoinShipGroupToFleet(Race_0.Name, " ", groupIndex, 0),
|
||||
// e.GenericErrorText(e.ErrInputEntityTypeNameInvalid))
|
||||
|
||||
// assert.ErrorContains(t,
|
||||
// g.JoinShipGroupToFleet(Race_0.Name, "Unnamed", groupIndex, 0),
|
||||
// e.GenericErrorText(e.ErrInputEntityNotExists))
|
||||
|
||||
// // creating ShipGroup
|
||||
// assert.NoError(t, g.CreateShips(Race_0_idx, Race_0_Freighter, R0_Planet_0_num, 5))
|
||||
|
||||
// assert.ErrorContains(t,
|
||||
// g.JoinShipGroupToFleet(Race_0.Name, "Unnamed", groupIndex, 6),
|
||||
// e.GenericErrorText(e.ErrJoinFleetGroupNumberNotEnough))
|
||||
|
||||
// // ensure race has no Fleets
|
||||
// assert.Len(t, slices.Collect(g.ListFleets(Race_0_idx)), 0)
|
||||
|
||||
// fleetOne := "R0_Fleet_one"
|
||||
// fleetTwo := "R0_Fleet_two"
|
||||
|
||||
// assert.NoError(t, g.JoinShipGroupToFleet(Race_0.Name, fleetOne, groupIndex, 0))
|
||||
// fleets := slices.Collect(g.ListFleets(Race_0_idx))
|
||||
// groups := slices.Collect(g.ListShipGroups(Race_0_idx))
|
||||
// assert.Len(t, groups, 1)
|
||||
// gi := 0
|
||||
// assert.Len(t, fleets, 1)
|
||||
// assert.Equal(t, fleets[0].Name, fleetOne)
|
||||
// state, _, _ := game.FleetState(g, fleets[0].ID)
|
||||
// assert.Equal(t, game.StateInOrbit, state)
|
||||
|
||||
// assert.NotNil(t, groups[gi].FleetID)
|
||||
// assert.Equal(t, fleets[0].ID, *groups[gi].FleetID)
|
||||
|
||||
// // create another ShipGroup
|
||||
// assert.NoError(t, g.CreateShips(Race_0_idx, Race_0_Gunship, R0_Planet_0_num, 3))
|
||||
// groupIndex = 2
|
||||
// assert.NoError(t, g.JoinShipGroupToFleet(Race_0.Name, fleetTwo, groupIndex, 2))
|
||||
// fleets = slices.Collect(g.ListFleets(Race_0_idx))
|
||||
// groups = slices.Collect(g.ListShipGroups(Race_0_idx))
|
||||
// assert.Len(t, groups, 3)
|
||||
// gi = 1
|
||||
// assert.Len(t, fleets, 2)
|
||||
// assert.Equal(t, fleets[1].Name, fleetTwo)
|
||||
// state, _, _ = game.FleetState(g, fleets[1].ID)
|
||||
// assert.Equal(t, game.StateInOrbit, state)
|
||||
|
||||
// assert.NotNil(t, groups[gi].FleetID)
|
||||
// assert.Equal(t, fleets[1].ID, *groups[gi].FleetID)
|
||||
// assert.Equal(t, uint(2), groups[gi].Number)
|
||||
// assert.Equal(t, uint(2), groups[gi].Index)
|
||||
|
||||
// gi = 2
|
||||
// assert.Nil(t, groups[gi].FleetID)
|
||||
// assert.Equal(t, uint(1), groups[gi].Number)
|
||||
// assert.Equal(t, uint(3), groups[gi].Index)
|
||||
|
||||
// groupIndex = groups[gi].Index
|
||||
// assert.NoError(t, g.JoinShipGroupToFleet(Race_0.Name, fleetOne, groupIndex, 0))
|
||||
// fleets = slices.Collect(g.ListFleets(Race_0_idx))
|
||||
// assert.Len(t, fleets, 2)
|
||||
// groups = slices.Collect(g.ListShipGroups(Race_0_idx))
|
||||
// assert.NotNil(t, groups[gi].FleetID)
|
||||
// assert.Equal(t, fleets[0].ID, *groups[gi].FleetID)
|
||||
// state, _, _ = game.FleetState(g, fleets[0].ID)
|
||||
// assert.Equal(t, game.StateInOrbit, state)
|
||||
|
||||
// // group not In_Orbit
|
||||
// assert.NoError(t, g.CreateShips(Race_0_idx, Race_0_Gunship, R0_Planet_0_num, 7))
|
||||
// gi = 3
|
||||
// g.ShipGroups[gi].StateInSpace = &game.InSpace{
|
||||
// Origin: 2,
|
||||
// Range: 1,
|
||||
// }
|
||||
// assert.ErrorContains(t,
|
||||
// g.JoinShipGroupToFleet(Race_0.Name, fleetOne, g.ShipGroups[gi].Index, 0),
|
||||
// e.GenericErrorText(e.ErrShipsBusy))
|
||||
// g.ShipGroups[gi].StateInSpace = nil
|
||||
|
||||
// // existing fleet not on the same planet or in_orbit
|
||||
// g.ShipGroups[0].StateInSpace = &game.InSpace{
|
||||
// Origin: 2,
|
||||
// Range: 1,
|
||||
// }
|
||||
// g.ShipGroups[2].StateInSpace = g.ShipGroups[0].StateInSpace
|
||||
// assert.ErrorContains(t,
|
||||
// g.JoinShipGroupToFleet(Race_0.Name, fleetOne, g.ShipGroups[gi].Index, 0),
|
||||
// e.GenericErrorText(e.ErrShipsNotOnSamePlanet))
|
||||
// }
|
||||
|
||||
// func TestJoinFleets(t *testing.T) {
|
||||
// g := newGame()
|
||||
// // creating ShipGroup #1 at Planet_0
|
||||
// assert.NoError(t, g.CreateShips(Race_0_idx, Race_0_Freighter, R0_Planet_0_num, 1)) // group #1
|
||||
// // creating ShipGroup #2 at Planet_2
|
||||
// assert.NoError(t, g.CreateShips(Race_0_idx, Race_0_Gunship, R0_Planet_2_num, 2)) // group #2
|
||||
// // creating ShipGroup #3 at Planet_0
|
||||
// assert.NoError(t, g.CreateShips(Race_0_idx, Race_0_Gunship, R0_Planet_0_num, 3)) // group #3
|
||||
|
||||
// // ensure race has no Fleets
|
||||
// assert.Len(t, slices.Collect(g.ListFleets(Race_0_idx)), 0)
|
||||
|
||||
// fleetPlanet2 := "R0_Fleet_On_Planet_2"
|
||||
// fleetSource := "R0_Fleet_one"
|
||||
// fleetTarget := "R0_Fleet_two"
|
||||
|
||||
// assert.ErrorContains(t,
|
||||
// g.JoinFleets(Race_0.Name, fleetSource, fleetTarget),
|
||||
// e.GenericErrorText(e.ErrInputEntityNotExists))
|
||||
// assert.NoError(t, g.JoinShipGroupToFleet(Race_0.Name, fleetSource, 1, 0))
|
||||
// assert.ErrorContains(t,
|
||||
// g.JoinFleets(Race_0.Name, fleetSource, fleetTarget),
|
||||
// e.GenericErrorText(e.ErrInputEntityNotExists))
|
||||
// assert.NoError(t, g.JoinShipGroupToFleet(Race_0.Name, fleetTarget, 3, 0))
|
||||
// assert.NoError(t, g.JoinFleets(Race_0.Name, fleetSource, fleetTarget))
|
||||
|
||||
// assert.NoError(t, g.JoinShipGroupToFleet(Race_0.Name, fleetPlanet2, 2, 0))
|
||||
// assert.ErrorContains(t,
|
||||
// g.JoinFleets(Race_0.Name, fleetPlanet2, fleetTarget),
|
||||
// e.GenericErrorText(e.ErrShipsNotOnSamePlanet))
|
||||
// }
|
||||
@@ -22,11 +22,11 @@ func (f Float) F() float64 {
|
||||
return float64(f)
|
||||
}
|
||||
|
||||
type TechSet map[Tech]float64
|
||||
type TechSet map[Tech]Float
|
||||
|
||||
func (ts TechSet) Value(t Tech) float64 {
|
||||
if v, ok := ts[t]; ok {
|
||||
return v
|
||||
return v.F()
|
||||
} else {
|
||||
panic(fmt.Sprintf("TechSet: Value: %s's value not set", t.String()))
|
||||
}
|
||||
@@ -34,7 +34,7 @@ func (ts TechSet) Value(t Tech) float64 {
|
||||
|
||||
func (ts TechSet) Set(t Tech, v float64) TechSet {
|
||||
m := maps.Clone(ts)
|
||||
m[t] = v
|
||||
m[t] = F(v)
|
||||
return m
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ type Game struct {
|
||||
Turn uint `json:"turn"`
|
||||
Map Map `json:"map"`
|
||||
Race []Race `json:"races"`
|
||||
Votes float64 `json:"votes"`
|
||||
Votes Float `json:"votes"`
|
||||
ShipGroups []ShipGroup `json:"shipGroup,omitempty"`
|
||||
Fleets []Fleet `json:"fleet,omitempty"`
|
||||
Winner []uuid.UUID `json:"winner,omitempty"`
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
package game
|
||||
|
||||
// import "iter"
|
||||
|
||||
// func (g *Game) CreateShips(ri int, shipTypeName string, planetNumber uint, quantity int) error {
|
||||
// return nil // g.createShips(ri, shipTypeName, int(planetNumber), quantity)
|
||||
// }
|
||||
|
||||
// func (g Game) ListShipGroups(ri int) iter.Seq[ShipGroup] {
|
||||
// return func(yield func(ShipGroup) bool) {}
|
||||
// // return g.listShipGroups(ri)
|
||||
// }
|
||||
|
||||
// func (g Game) ListFleets(ri int) iter.Seq[Fleet] {
|
||||
// return func(yield func(Fleet) bool) {}
|
||||
// // return g.listFleets(ri)
|
||||
// }
|
||||
|
||||
// func (g Game) MustPlanetByNumber(num uint) Planet {
|
||||
// p, err := g.PlanetByNumber(num)
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
// return p
|
||||
// }
|
||||
@@ -69,7 +69,7 @@ type InUpgrade struct {
|
||||
func (iu InUpgrade) Cost() float64 {
|
||||
var sum float64
|
||||
for i := range iu.UpgradeTech {
|
||||
sum += iu.UpgradeTech[i].Cost
|
||||
sum += iu.UpgradeTech[i].Cost.F()
|
||||
}
|
||||
return sum
|
||||
}
|
||||
@@ -77,16 +77,16 @@ func (iu InUpgrade) Cost() float64 {
|
||||
func (iu InUpgrade) TechCost(t Tech) float64 {
|
||||
for i := range iu.UpgradeTech {
|
||||
if iu.UpgradeTech[i].Tech == t {
|
||||
return iu.UpgradeTech[i].Cost
|
||||
return iu.UpgradeTech[i].Cost.F()
|
||||
}
|
||||
}
|
||||
return 0.
|
||||
}
|
||||
|
||||
type UpgradePreference struct {
|
||||
Tech Tech `json:"tech"`
|
||||
Level float64 `json:"level"`
|
||||
Cost float64 `json:"cost"`
|
||||
Tech Tech `json:"tech"`
|
||||
Level Float `json:"level"`
|
||||
Cost Float `json:"cost"`
|
||||
}
|
||||
|
||||
type Tech string
|
||||
@@ -177,7 +177,7 @@ func (sg ShipGroup) Equal(other ShipGroup) bool {
|
||||
|
||||
// Грузоподъёмность
|
||||
func (sg ShipGroup) CargoCapacity(st *ShipType) float64 {
|
||||
return sg.TechLevel(TechCargo).F() * (st.Cargo + (st.Cargo*st.Cargo)/20) * float64(sg.Number)
|
||||
return sg.TechLevel(TechCargo).F() * (st.Cargo.F() + (st.Cargo.F()*st.Cargo.F())/20) * float64(sg.Number)
|
||||
}
|
||||
|
||||
// Масса перевозимого груза -
|
||||
@@ -200,7 +200,7 @@ func (sg ShipGroup) FullMass(st *ShipType) float64 {
|
||||
// Эффективность двигателя -
|
||||
// равна мощности Двигателей, умноженной на технологический уровень блока Двигателей
|
||||
func (sg ShipGroup) DriveEffective(st *ShipType) float64 {
|
||||
return st.Drive * sg.TechLevel(TechDrive).F()
|
||||
return st.Drive.F() * sg.TechLevel(TechDrive).F()
|
||||
}
|
||||
|
||||
// Корабли перемещаются за один ход на количество световых лет, равное
|
||||
@@ -210,7 +210,7 @@ func (sg ShipGroup) Speed(st *ShipType) float64 {
|
||||
}
|
||||
|
||||
func (sg ShipGroup) UpgradeDriveCost(st *ShipType, drive float64) float64 {
|
||||
return (1 - sg.TechLevel(TechDrive).F()/drive) * 10 * st.Drive
|
||||
return (1 - sg.TechLevel(TechDrive).F()/drive) * 10 * st.Drive.F()
|
||||
}
|
||||
|
||||
// TODO: test on other values
|
||||
@@ -219,17 +219,17 @@ func (sg ShipGroup) UpgradeWeaponsCost(st *ShipType, weapons float64) float64 {
|
||||
}
|
||||
|
||||
func (sg ShipGroup) UpgradeShieldsCost(st *ShipType, shields float64) float64 {
|
||||
return (1 - sg.TechLevel(TechShields).F()/shields) * 10 * st.Shields
|
||||
return (1 - sg.TechLevel(TechShields).F()/shields) * 10 * st.Shields.F()
|
||||
}
|
||||
|
||||
func (sg ShipGroup) UpgradeCargoCost(st *ShipType, cargo float64) float64 {
|
||||
return (1 - sg.TechLevel(TechCargo).F()/cargo) * 10 * st.Cargo
|
||||
return (1 - sg.TechLevel(TechCargo).F()/cargo) * 10 * st.Cargo.F()
|
||||
}
|
||||
|
||||
// Мощность бомбардировки
|
||||
func (sg ShipGroup) BombingPower(st *ShipType) float64 {
|
||||
return (math.Sqrt(st.Weapons*sg.TechLevel(TechWeapons).F())/10. + 1.) *
|
||||
st.Weapons *
|
||||
return (math.Sqrt(st.Weapons.F()*sg.TechLevel(TechWeapons).F())/10. + 1.) *
|
||||
st.Weapons.F() *
|
||||
sg.TechLevel(TechWeapons).F() *
|
||||
float64(st.Armament) *
|
||||
float64(sg.Number)
|
||||
|
||||
@@ -17,15 +17,15 @@ func TestCargoCapacity(t *testing.T) {
|
||||
Armament: 1,
|
||||
Weapons: 1,
|
||||
Shields: 1,
|
||||
Cargo: cargoSize,
|
||||
Cargo: game.F(cargoSize),
|
||||
}
|
||||
sg := game.ShipGroup{
|
||||
Number: 1,
|
||||
Tech: map[game.Tech]float64{
|
||||
game.TechDrive: 1.5,
|
||||
game.TechWeapons: 1.1,
|
||||
game.TechShields: 2.0,
|
||||
game.TechCargo: 1.0,
|
||||
Tech: map[game.Tech]game.Float{
|
||||
game.TechDrive: game.F(1.5),
|
||||
game.TechWeapons: game.F(1.1),
|
||||
game.TechShields: game.F(2.0),
|
||||
game.TechCargo: game.F(1.0),
|
||||
},
|
||||
}
|
||||
assert.Equal(t, expectCapacity, sg.CargoCapacity(&ship))
|
||||
@@ -48,11 +48,11 @@ func TestCarryingAndFullMass(t *testing.T) {
|
||||
}
|
||||
sg := &game.ShipGroup{
|
||||
Number: 1,
|
||||
Tech: map[game.Tech]float64{
|
||||
game.TechDrive: 1.0,
|
||||
game.TechWeapons: 1.0,
|
||||
game.TechShields: 1.0,
|
||||
game.TechCargo: 1.0,
|
||||
Tech: map[game.Tech]game.Float{
|
||||
game.TechDrive: game.F(1.0),
|
||||
game.TechWeapons: game.F(1.0),
|
||||
game.TechShields: game.F(1.0),
|
||||
game.TechCargo: game.F(1.0),
|
||||
},
|
||||
Load: 0.0,
|
||||
}
|
||||
@@ -80,11 +80,11 @@ func TestSpeed(t *testing.T) {
|
||||
}
|
||||
sg := &game.ShipGroup{
|
||||
Number: 1,
|
||||
Tech: map[game.Tech]float64{
|
||||
game.TechDrive: 1.0,
|
||||
game.TechWeapons: 1.0,
|
||||
game.TechShields: 1.0,
|
||||
game.TechCargo: 1.0,
|
||||
Tech: map[game.Tech]game.Float{
|
||||
game.TechDrive: game.F(1.0),
|
||||
game.TechWeapons: game.F(1.0),
|
||||
game.TechShields: game.F(1.0),
|
||||
game.TechCargo: game.F(1.0),
|
||||
},
|
||||
Load: 0.0,
|
||||
}
|
||||
@@ -109,11 +109,11 @@ func TestBombingPower(t *testing.T) {
|
||||
}
|
||||
sg := game.ShipGroup{
|
||||
Number: 1,
|
||||
Tech: map[game.Tech]float64{
|
||||
game.TechDrive: 1.0,
|
||||
game.TechWeapons: 1.0,
|
||||
game.TechShields: 1.0,
|
||||
game.TechCargo: 1.0,
|
||||
Tech: map[game.Tech]game.Float{
|
||||
game.TechDrive: game.F(1.0),
|
||||
game.TechWeapons: game.F(1.0),
|
||||
game.TechShields: game.F(1.0),
|
||||
game.TechCargo: game.F(1.0),
|
||||
},
|
||||
}
|
||||
assert.Equal(t, 139.295, number.Fixed3(sg.BombingPower(&BattleStation)))
|
||||
@@ -123,9 +123,9 @@ func TestBombingPower(t *testing.T) {
|
||||
|
||||
func TestDriveEffective(t *testing.T) {
|
||||
tc := []struct {
|
||||
driveShipType float64
|
||||
driveTech float64
|
||||
expectDriveEffective float64
|
||||
driveShipType game.Float
|
||||
driveTech game.Float
|
||||
expectDriveEffective game.Float
|
||||
}{
|
||||
{1, 1, 1},
|
||||
{1, 2, 2},
|
||||
@@ -139,20 +139,20 @@ func TestDriveEffective(t *testing.T) {
|
||||
someShip := game.ShipType{
|
||||
Drive: tc[i].driveShipType,
|
||||
Armament: rand.UintN(30) + 1,
|
||||
Weapons: rand.Float64()*30 + 1,
|
||||
Shields: rand.Float64()*100 + 1,
|
||||
Cargo: rand.Float64()*20 + 1,
|
||||
Weapons: game.F(rand.Float64()*30 + 1),
|
||||
Shields: game.F(rand.Float64()*100 + 1),
|
||||
Cargo: game.F(rand.Float64()*20 + 1),
|
||||
}
|
||||
sg := game.ShipGroup{
|
||||
Number: rand.UintN(4) + 1,
|
||||
Tech: map[game.Tech]float64{
|
||||
Tech: map[game.Tech]game.Float{
|
||||
game.TechDrive: tc[i].driveTech,
|
||||
game.TechWeapons: rand.Float64()*5 + 1,
|
||||
game.TechShields: rand.Float64()*5 + 1,
|
||||
game.TechCargo: rand.Float64()*5 + 1,
|
||||
game.TechWeapons: game.F(rand.Float64()*5 + 1),
|
||||
game.TechShields: game.F(rand.Float64()*5 + 1),
|
||||
game.TechCargo: game.F(rand.Float64()*5 + 1),
|
||||
},
|
||||
}
|
||||
assert.Equal(t, tc[i].expectDriveEffective, sg.DriveEffective(&someShip))
|
||||
assert.Equal(t, tc[i].expectDriveEffective.F(), sg.DriveEffective(&someShip))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,7 +170,7 @@ func TestShipGroupEqual(t *testing.T) {
|
||||
FleetID: &fleetId,
|
||||
CargoType: &mat,
|
||||
Load: 123.45,
|
||||
Tech: map[game.Tech]float64{
|
||||
Tech: map[game.Tech]game.Float{
|
||||
game.TechDrive: 1.0,
|
||||
game.TechWeapons: 1.0,
|
||||
game.TechShields: 1.0,
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"math"
|
||||
"slices"
|
||||
)
|
||||
|
||||
type UpgradeCalc struct {
|
||||
Cost map[Tech]float64
|
||||
}
|
||||
|
||||
func (uc UpgradeCalc) UpgradeCost(ships uint) float64 {
|
||||
var sum float64
|
||||
for _, v := range uc.Cost {
|
||||
sum += v
|
||||
}
|
||||
return sum * float64(ships)
|
||||
}
|
||||
|
||||
func (uc UpgradeCalc) UpgradeMaxShips(resources float64) uint {
|
||||
return uint(math.Floor(resources / uc.UpgradeCost(1)))
|
||||
}
|
||||
|
||||
func BlockUpgradeCost(blockMass, currentBlockTech, targetBlockTech float64) float64 {
|
||||
if blockMass == 0 || targetBlockTech <= currentBlockTech {
|
||||
return 0
|
||||
}
|
||||
return (1 - currentBlockTech/targetBlockTech) * 10 * blockMass
|
||||
}
|
||||
|
||||
func GroupUpgradeCost(sg *ShipGroup, st ShipType, drive, weapons, shields, cargo float64) UpgradeCalc {
|
||||
uc := &UpgradeCalc{Cost: make(map[Tech]float64)}
|
||||
if drive > 0 {
|
||||
uc.Cost[TechDrive] = BlockUpgradeCost(st.DriveBlockMass(), sg.TechLevel(TechDrive).F(), drive)
|
||||
}
|
||||
if weapons > 0 {
|
||||
uc.Cost[TechWeapons] = BlockUpgradeCost(st.WeaponsBlockMass(), sg.TechLevel(TechWeapons).F(), weapons)
|
||||
}
|
||||
if shields > 0 {
|
||||
uc.Cost[TechShields] = BlockUpgradeCost(st.ShieldsBlockMass(), sg.TechLevel(TechShields).F(), shields)
|
||||
}
|
||||
if cargo > 0 {
|
||||
uc.Cost[TechCargo] = BlockUpgradeCost(st.CargoBlockMass(), sg.TechLevel(TechCargo).F(), cargo)
|
||||
}
|
||||
return *uc
|
||||
}
|
||||
|
||||
func CurrentUpgradingLevel(sg *ShipGroup, tech Tech) float64 {
|
||||
if sg.StateUpgrade == nil {
|
||||
return 0
|
||||
}
|
||||
ti := slices.IndexFunc(sg.StateUpgrade.UpgradeTech, func(pref UpgradePreference) bool { return pref.Tech == tech })
|
||||
if ti >= 0 {
|
||||
return sg.StateUpgrade.UpgradeTech[ti].Level
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func FutureUpgradeLevel(raceLevel, groupLevel, limit float64) float64 {
|
||||
target := limit
|
||||
if target == 0 || target > raceLevel {
|
||||
target = raceLevel
|
||||
}
|
||||
if groupLevel == target {
|
||||
return 0
|
||||
}
|
||||
return target
|
||||
}
|
||||
|
||||
func UpgradeGroupPreference(sg ShipGroup, st ShipType, tech Tech, v float64) ShipGroup {
|
||||
if v <= 0 || st.BlockMass(tech) == 0 || sg.TechLevel(tech).F() >= v {
|
||||
return sg
|
||||
}
|
||||
var su InUpgrade
|
||||
if sg.StateUpgrade != nil {
|
||||
su = *sg.StateUpgrade
|
||||
} else {
|
||||
su = InUpgrade{UpgradeTech: []UpgradePreference{}}
|
||||
}
|
||||
ti := slices.IndexFunc(su.UpgradeTech, func(pref UpgradePreference) bool { return pref.Tech == tech })
|
||||
if ti < 0 {
|
||||
su.UpgradeTech = append(su.UpgradeTech, UpgradePreference{Tech: tech})
|
||||
ti = len(su.UpgradeTech) - 1
|
||||
}
|
||||
su.UpgradeTech[ti].Level = v
|
||||
su.UpgradeTech[ti].Cost = BlockUpgradeCost(st.BlockMass(tech), sg.TechLevel(tech).F(), v) * float64(sg.Number)
|
||||
|
||||
sg.StateUpgrade = &su
|
||||
return sg
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
package game_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/iliadenisov/galaxy/internal/model/game"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var (
|
||||
Cruiser = game.ShipType{
|
||||
Name: "Cruiser",
|
||||
Drive: 15,
|
||||
Armament: 1,
|
||||
Weapons: 15,
|
||||
Shields: 15,
|
||||
Cargo: 0,
|
||||
}
|
||||
)
|
||||
|
||||
func TestBlockUpgradeCost(t *testing.T) {
|
||||
assert.Equal(t, 00.0, game.BlockUpgradeCost(1, 1.0, 1.0))
|
||||
assert.Equal(t, 25.0, game.BlockUpgradeCost(5, 1.0, 2.0))
|
||||
assert.Equal(t, 50.0, game.BlockUpgradeCost(10, 1.0, 2.0))
|
||||
}
|
||||
|
||||
func TestGroupUpgradeCost(t *testing.T) {
|
||||
sg := &game.ShipGroup{
|
||||
Tech: map[game.Tech]float64{
|
||||
game.TechDrive: 1.0,
|
||||
game.TechWeapons: 1.0,
|
||||
game.TechShields: 1.0,
|
||||
game.TechCargo: 1.0,
|
||||
},
|
||||
Number: 1,
|
||||
}
|
||||
assert.Equal(t, 225.0, game.GroupUpgradeCost(sg, Cruiser, 2.0, 2.0, 2.0, 2.0).UpgradeCost(1))
|
||||
}
|
||||
|
||||
func TestUpgradeMaxShips(t *testing.T) {
|
||||
sg := &game.ShipGroup{
|
||||
Tech: map[game.Tech]float64{
|
||||
game.TechDrive: 1.0,
|
||||
game.TechWeapons: 1.0,
|
||||
game.TechShields: 1.0,
|
||||
game.TechCargo: 1.0,
|
||||
},
|
||||
Number: 10,
|
||||
}
|
||||
uc := game.GroupUpgradeCost(sg, Cruiser, 2.0, 2.0, 2.0, 2.0)
|
||||
assert.Equal(t, uint(4), uc.UpgradeMaxShips(1000))
|
||||
}
|
||||
|
||||
func TestCurrentUpgradingLevel(t *testing.T) {
|
||||
sg := &game.ShipGroup{
|
||||
StateUpgrade: nil,
|
||||
}
|
||||
assert.Equal(t, 0.0, game.CurrentUpgradingLevel(sg, game.TechDrive))
|
||||
assert.Equal(t, 0.0, game.CurrentUpgradingLevel(sg, game.TechWeapons))
|
||||
assert.Equal(t, 0.0, game.CurrentUpgradingLevel(sg, game.TechShields))
|
||||
assert.Equal(t, 0.0, game.CurrentUpgradingLevel(sg, game.TechCargo))
|
||||
|
||||
sg.StateUpgrade = &game.InUpgrade{
|
||||
UpgradeTech: []game.UpgradePreference{
|
||||
{Tech: game.TechDrive, Level: 1.5, Cost: 100.1},
|
||||
},
|
||||
}
|
||||
assert.Equal(t, 1.5, game.CurrentUpgradingLevel(sg, game.TechDrive))
|
||||
assert.Equal(t, 0.0, game.CurrentUpgradingLevel(sg, game.TechWeapons))
|
||||
assert.Equal(t, 0.0, game.CurrentUpgradingLevel(sg, game.TechShields))
|
||||
assert.Equal(t, 0.0, game.CurrentUpgradingLevel(sg, game.TechCargo))
|
||||
|
||||
sg.StateUpgrade.UpgradeTech = append(sg.StateUpgrade.UpgradeTech, game.UpgradePreference{Tech: game.TechCargo, Level: 2.2, Cost: 200.2})
|
||||
assert.Equal(t, 1.5, game.CurrentUpgradingLevel(sg, game.TechDrive))
|
||||
assert.Equal(t, 0.0, game.CurrentUpgradingLevel(sg, game.TechWeapons))
|
||||
assert.Equal(t, 0.0, game.CurrentUpgradingLevel(sg, game.TechShields))
|
||||
assert.Equal(t, 2.2, game.CurrentUpgradingLevel(sg, game.TechCargo))
|
||||
}
|
||||
|
||||
func TestFutureUpgradeLevel(t *testing.T) {
|
||||
assert.Equal(t, 0.0, game.FutureUpgradeLevel(2.0, 2.0, 2.0))
|
||||
assert.Equal(t, 0.0, game.FutureUpgradeLevel(2.0, 2.0, 3.0))
|
||||
assert.Equal(t, 1.5, game.FutureUpgradeLevel(1.5, 2.0, 3.0))
|
||||
assert.Equal(t, 2.0, game.FutureUpgradeLevel(2.5, 1.0, 2.0))
|
||||
assert.Equal(t, 2.5, game.FutureUpgradeLevel(2.5, 1.0, 0.0))
|
||||
}
|
||||
|
||||
func TestUpgradeGroupPreference(t *testing.T) {
|
||||
sg := game.ShipGroup{
|
||||
Number: 4,
|
||||
Tech: game.TechSet{
|
||||
game.TechDrive: 1.0,
|
||||
game.TechWeapons: 1.0,
|
||||
game.TechShields: 1.0,
|
||||
game.TechCargo: 1.0,
|
||||
},
|
||||
}
|
||||
assert.Nil(t, sg.StateUpgrade)
|
||||
sg = game.UpgradeGroupPreference(sg, Cruiser, game.TechDrive, 0)
|
||||
assert.Nil(t, sg.StateUpgrade)
|
||||
|
||||
sg = game.UpgradeGroupPreference(sg, Cruiser, game.TechDrive, 2.0)
|
||||
assert.NotNil(t, sg.StateUpgrade)
|
||||
assert.Equal(t, 300., sg.StateUpgrade.TechCost(game.TechDrive))
|
||||
assert.Equal(t, 300., sg.StateUpgrade.Cost())
|
||||
|
||||
sg = game.UpgradeGroupPreference(sg, Cruiser, game.TechWeapons, 2.0)
|
||||
assert.NotNil(t, sg.StateUpgrade)
|
||||
assert.Equal(t, 300., sg.StateUpgrade.TechCost(game.TechWeapons))
|
||||
assert.Equal(t, 600., sg.StateUpgrade.Cost())
|
||||
|
||||
sg = game.UpgradeGroupPreference(sg, Cruiser, game.TechShields, 2.0)
|
||||
assert.NotNil(t, sg.StateUpgrade)
|
||||
assert.Equal(t, 300., sg.StateUpgrade.TechCost(game.TechShields))
|
||||
assert.Equal(t, 900., sg.StateUpgrade.Cost())
|
||||
|
||||
sg = game.UpgradeGroupPreference(sg, Cruiser, game.TechCargo, 2.0)
|
||||
assert.NotNil(t, sg.StateUpgrade)
|
||||
assert.Equal(t, 0., sg.StateUpgrade.TechCost(game.TechCargo))
|
||||
assert.Equal(t, 900., sg.StateUpgrade.Cost())
|
||||
}
|
||||
@@ -23,7 +23,7 @@ const (
|
||||
type Production struct {
|
||||
Type ProductionType `json:"type"`
|
||||
SubjectID *uuid.UUID `json:"subjectId"` // TODO: get rid of Nils?
|
||||
Progress *float64 `json:"progress"`
|
||||
Progress *Float `json:"progress"`
|
||||
}
|
||||
|
||||
func (p ProductionType) AsType(subject uuid.UUID) Production {
|
||||
|
||||
@@ -3,19 +3,15 @@ package game
|
||||
import "github.com/google/uuid"
|
||||
|
||||
type Race struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Extinct bool `json:"extinct"`
|
||||
|
||||
Votes float64 `json:"votes"`
|
||||
ID uuid.UUID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Extinct bool `json:"extinct"`
|
||||
Votes Float `json:"votes"`
|
||||
VoteFor uuid.UUID `json:"voteFor"`
|
||||
Relations []RaceRelation `json:"relations"`
|
||||
|
||||
Tech TechSet `json:"tech"`
|
||||
|
||||
Sciences []Science `json:"science,omitempty"`
|
||||
|
||||
ShipTypes []ShipType `json:"shipType,omitempty"`
|
||||
Tech TechSet `json:"tech"`
|
||||
Sciences []Science `json:"science,omitempty"`
|
||||
ShipTypes []ShipType `json:"shipType,omitempty"`
|
||||
}
|
||||
|
||||
type Relation string
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
type Science struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Drive float64 `json:"drive"`
|
||||
Weapons float64 `json:"weapons"`
|
||||
Shields float64 `json:"shields"`
|
||||
Cargo float64 `json:"cargo"`
|
||||
Drive Float `json:"drive"`
|
||||
Weapons Float `json:"weapons"`
|
||||
Shields Float `json:"shields"`
|
||||
Cargo Float `json:"cargo"`
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
package game
|
||||
|
||||
type GameParameter struct {
|
||||
Series string
|
||||
Players uint
|
||||
Public bool
|
||||
}
|
||||
@@ -7,11 +7,11 @@ import (
|
||||
type ShipType struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Drive float64 `json:"drive"`
|
||||
Drive Float `json:"drive"`
|
||||
Armament uint `json:"armament"`
|
||||
Weapons float64 `json:"weapons"`
|
||||
Shields float64 `json:"shields"`
|
||||
Cargo float64 `json:"cargo"`
|
||||
Weapons Float `json:"weapons"`
|
||||
Shields Float `json:"shields"`
|
||||
Cargo Float `json:"cargo"`
|
||||
}
|
||||
|
||||
func (st ShipType) Equal(o ShipType) bool {
|
||||
@@ -38,22 +38,22 @@ func (st ShipType) BlockMass(t Tech) float64 {
|
||||
}
|
||||
|
||||
func (st ShipType) DriveBlockMass() float64 {
|
||||
return st.Drive
|
||||
return st.Drive.F()
|
||||
}
|
||||
|
||||
func (st ShipType) WeaponsBlockMass() float64 {
|
||||
if st.Armament == 0 || st.Weapons == 0 {
|
||||
return 0
|
||||
}
|
||||
return float64(st.Armament+1) * (st.Weapons / 2)
|
||||
return float64(st.Armament+1) * (st.Weapons.F() / 2)
|
||||
}
|
||||
|
||||
func (st ShipType) ShieldsBlockMass() float64 {
|
||||
return st.Shields
|
||||
return st.Shields.F()
|
||||
}
|
||||
|
||||
func (st ShipType) CargoBlockMass() float64 {
|
||||
return st.Cargo
|
||||
return st.Cargo.F()
|
||||
}
|
||||
|
||||
func (st ShipType) EmptyMass() float64 {
|
||||
|
||||
Reference in New Issue
Block a user