wip: battle
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"maps"
|
||||
"math"
|
||||
@@ -11,29 +12,67 @@ import (
|
||||
)
|
||||
|
||||
type Battle struct {
|
||||
Planet uint
|
||||
BattleReport BattleReport
|
||||
ID uuid.UUID
|
||||
Planet uint
|
||||
// True = In_Battle, False = Out_Battle
|
||||
observerGroups map[int]bool
|
||||
Protocol []BattleAction
|
||||
|
||||
shipAmmo map[int]uint
|
||||
shipName map[int]string
|
||||
attacker map[int]map[int]float64 // a group able to attack and destroy an opponent with some probability > 0
|
||||
}
|
||||
|
||||
type BattleReport struct {
|
||||
BattleAction []BattleAction
|
||||
}
|
||||
|
||||
type BattleAction struct {
|
||||
Attacker int
|
||||
Defenter int
|
||||
Destroyed bool
|
||||
}
|
||||
|
||||
func CollectPlanetGroups(g *Game, cacheShipGroupRaceID map[int]int, cacheShipClass map[int]*ShipType) map[uint][]int {
|
||||
planetGroup := make(map[uint][]int)
|
||||
func (b Battle) ShipClassName(groupIndex int) string {
|
||||
if v, ok := b.shipName[groupIndex]; ok {
|
||||
return v
|
||||
} else {
|
||||
panic(fmt.Sprintf("Battle.ShipClassName: no name stored for groupIndex=%d", groupIndex))
|
||||
}
|
||||
}
|
||||
|
||||
type BattleReport struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
Planet uint `json:"planet"`
|
||||
PlanetName string `json:"planet_name"`
|
||||
Races map[int]string `json:"races"`
|
||||
Ships map[int]string `json:"ships"`
|
||||
Protocol []BattleActionReport `json:"protocol"`
|
||||
}
|
||||
|
||||
type BattleActionReport struct {
|
||||
Attacker int `json:"r1"`
|
||||
AttackerShipClass int `json:"s1"`
|
||||
Defender int `json:"r2"`
|
||||
DefenderShipClass int `json:"s2"`
|
||||
Destroyed bool `json:"d"`
|
||||
}
|
||||
|
||||
type ShipClassBattle struct {
|
||||
ClassName string `json:"class"`
|
||||
Tech TechSet `json:"tech"`
|
||||
Number uint `json:"number"`
|
||||
CargoType *CargoType `json:"loadType,omitempty"`
|
||||
Quantity float64 `json:"quantity"`
|
||||
Left uint `json:"left"`
|
||||
}
|
||||
|
||||
func CollectPlanetGroups(g *Game, cacheShipGroupRaceID map[int]int, cacheShipClass map[int]*ShipType) map[uint]map[int]bool {
|
||||
planetGroup := make(map[uint]map[int]bool)
|
||||
for groupIndex := range g.ShipGroups {
|
||||
if g.ShipGroups[groupIndex].State() == StateInOrbit {
|
||||
state := g.ShipGroups[groupIndex].State()
|
||||
if state == StateInOrbit || state == StateUpgrade {
|
||||
planetNumber := g.ShipGroups[groupIndex].Destination
|
||||
planetGroup[planetNumber] = append(planetGroup[planetNumber], groupIndex)
|
||||
if _, ok := planetGroup[planetNumber]; !ok {
|
||||
planetGroup[planetNumber] = make(map[int]bool)
|
||||
}
|
||||
planetGroup[planetNumber][groupIndex] = false
|
||||
|
||||
if _, ok := cacheShipGroupRaceID[groupIndex]; !ok {
|
||||
cacheShipGroupRaceID[groupIndex] = RaceIndex(g, g.ShipGroups[groupIndex].OwnerID)
|
||||
@@ -57,6 +96,10 @@ func CollectPlanetGroups(g *Game, cacheShipGroupRaceID map[int]int, cacheShipCla
|
||||
return planetGroup
|
||||
}
|
||||
|
||||
func FilterBattleGroups(g *Game, groups map[int]bool) []int {
|
||||
return slices.DeleteFunc(slices.Collect(maps.Keys(groups)), func(groupIndex int) bool { return g.ShipGroups[groupIndex].State() != StateInOrbit })
|
||||
}
|
||||
|
||||
func CacheRelations(g *Game, cacheShipGroupRaceID map[int]int) map[int]map[int]Relation {
|
||||
cache := make(map[int]map[int]Relation)
|
||||
ri := make(map[int]bool)
|
||||
@@ -132,8 +175,8 @@ func ProduceBattles(g *Game) []*Battle {
|
||||
clear(cacheProbability)
|
||||
}()
|
||||
|
||||
planetGroup := CollectPlanetGroups(g, cacheShipGroupRaceID, cacheShipClass)
|
||||
if len(planetGroup) == 0 {
|
||||
planetGroups := CollectPlanetGroups(g, cacheShipGroupRaceID, cacheShipClass)
|
||||
if len(planetGroups) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -144,35 +187,42 @@ func ProduceBattles(g *Game) []*Battle {
|
||||
|
||||
result := make([]*Battle, 0)
|
||||
|
||||
for pl, groups := range planetGroup {
|
||||
for pl, observerGroups := range planetGroups {
|
||||
battleGroups := FilterBattleGroups(g, observerGroups)
|
||||
b := &Battle{
|
||||
Planet: pl,
|
||||
attacker: make(map[int]map[int]float64),
|
||||
shipAmmo: make(map[int]uint),
|
||||
Planet: pl,
|
||||
observerGroups: observerGroups,
|
||||
attacker: make(map[int]map[int]float64),
|
||||
shipAmmo: make(map[int]uint),
|
||||
shipName: make(map[int]string),
|
||||
}
|
||||
|
||||
for i := range groups {
|
||||
attIdx := groups[i]
|
||||
for i := range battleGroups {
|
||||
attIdx := battleGroups[i]
|
||||
|
||||
// Ships with no Ammo will never attack somebody
|
||||
if cacheShipClass[attIdx].Armament == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// TODO: remove slices.Clone?
|
||||
opponents := slices.DeleteFunc(slices.Clone(groups), func(defIdx int) bool {
|
||||
opponents := slices.DeleteFunc(slices.Clone(battleGroups), func(defIdx int) bool {
|
||||
return FilterBattleOpponents(g, attIdx, defIdx, cacheShipGroupRaceID, cacheRelation, cacheShipClass, cacheProbability)
|
||||
})
|
||||
if len(opponents) > 0 {
|
||||
b.shipAmmo[attIdx] = cacheShipClass[attIdx].Armament
|
||||
b.shipName[attIdx] = cacheShipClass[attIdx].Name
|
||||
b.observerGroups[attIdx] = true
|
||||
for _, defIdx := range opponents {
|
||||
b.attacker[attIdx][defIdx] = cacheProbability[attIdx][defIdx]
|
||||
b.shipName[defIdx] = cacheShipClass[defIdx].Name
|
||||
b.observerGroups[defIdx] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(b.attacker) > 0 {
|
||||
SingleBattle(g, b)
|
||||
b.ID = uuid.New()
|
||||
result = append(result, b)
|
||||
}
|
||||
|
||||
@@ -203,7 +253,7 @@ func SingleBattle(g *Game, b *Battle) {
|
||||
panic("SingleBattle: probability unexpected: value <= 0")
|
||||
}
|
||||
|
||||
b.BattleReport.BattleAction = append(b.BattleReport.BattleAction, BattleAction{
|
||||
b.Protocol = append(b.Protocol, BattleAction{
|
||||
Attacker: attIdx,
|
||||
Defenter: defIdx,
|
||||
Destroyed: destroyed,
|
||||
@@ -220,6 +270,8 @@ func SingleBattle(g *Game, b *Battle) {
|
||||
delete(b.attacker, attIdx) // Remove attacker if he lost all opponents
|
||||
}
|
||||
}
|
||||
// FIXME: удалять ShipGroups после генерирования пользовательского отчёта
|
||||
// g.ShipGroups = append(g.ShipGroups[:defIdx], g.ShipGroups[defIdx+1:]...)
|
||||
}
|
||||
if len(b.attacker) == 0 {
|
||||
break
|
||||
@@ -245,3 +297,11 @@ func DestructionProbability(attWeapons, attWeaponsTech, defShields, defShiledsTe
|
||||
func EffectiveDefence(defShields, defShiledsTech, defFullMass float64) float64 {
|
||||
return defShields * defShiledsTech / math.Pow(defFullMass, 1./3.) * math.Pow(30., 1./3.)
|
||||
}
|
||||
|
||||
func (b BattleReport) MarshalBinary() (data []byte, err error) {
|
||||
return json.Marshal(&b)
|
||||
}
|
||||
|
||||
func (b *BattleReport) UnmarshalBinary(data []byte) error {
|
||||
return json.Unmarshal(data, b)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user