fix: battles are not round-based

This commit is contained in:
IliaDenisov
2026-02-19 15:07:51 +02:00
parent 8378df29c2
commit 0c0df976bd
2 changed files with 60 additions and 43 deletions
+58 -41
View File
@@ -1,6 +1,7 @@
package controller package controller
import ( import (
"iter"
"maps" "maps"
"math" "math"
"math/rand/v2" "math/rand/v2"
@@ -84,15 +85,6 @@ func FilterBattleOpponents(c *Cache, attIdx, defIdx int, cacheProbability map[in
} }
/*
FIXME: Сражение происходит раундами
Случайным образом из всех участвующих в сражении вооруженных кораблей выбирается один...
...Затем вновь случайным образом выбирается корабль, который будет стрелять...
Так продолжается до тех пор, пока не отстреляются все корабли. Если после
этого еще остались корабли и с той и с другой стороны, все повторяется с
самого начала (происходит еще один цикл сражения).
*/
func ProduceBattles(c *Cache) []*Battle { func ProduceBattles(c *Cache) []*Battle {
cacheProbability := make(map[int]map[int]float64) cacheProbability := make(map[int]map[int]float64)
defer func() { clear(cacheProbability) }() defer func() { clear(cacheProbability) }()
@@ -159,45 +151,65 @@ func ProduceBattles(c *Cache) []*Battle {
} }
func SingleBattle(c *Cache, b *Battle) { func SingleBattle(c *Cache, b *Battle) {
roundShooters := make(map[int]bool)
for len(b.attacker) > 0 { for len(b.attacker) > 0 {
attackers := slices.Collect(maps.Keys(b.attacker)) // список участников раунда
attIdx := attackers[rand.IntN(len(attackers))] clear(roundShooters)
for sgi := range b.attacker {
roundShooters[sgi] = true
}
for range b.shipAmmo[attIdx] { for len(roundShooters) > 0 {
defenders := slices.Collect(maps.Keys(b.attacker[attIdx])) // attacke group id among round participants
defIdx := defenders[rand.IntN(len(defenders))] attIdx := randomValue(maps.Keys(roundShooters))
destroyed := false delete(roundShooters, attIdx)
probability := b.attacker[attIdx][defIdx] for range b.shipAmmo[attIdx] {
switch { // defender group id among all attacker's opponents
case probability >= 1: defIdx := randomValue(maps.Keys(b.attacker[attIdx]))
destroyed = true
case probability > 0:
destroyed = rand.Float64() >= probability
default:
panic("SingleBattle: probability unexpected: value <= 0")
}
b.Protocol = append(b.Protocol, BattleAction{ destroyed := false
Attacker: attIdx,
Defender: defIdx,
Destroyed: destroyed,
})
if destroyed { probability := b.attacker[attIdx][defIdx]
c.ShipGroupDestroyItem(defIdx) switch {
} case probability >= 1:
if c.ShipGroup(defIdx).Number == 0 { destroyed = true
delete(b.attacker, defIdx) // Eliminated group cant attack anyone case probability > 0:
for attIdx := range b.attacker { destroyed = rand.Float64() >= probability
delete(b.attacker[attIdx], defIdx) // Other attackers can't attack eliminated group anymore default:
if len(b.attacker[attIdx]) == 0 { panic("SingleBattle: probability unexpected: value <= 0")
delete(b.attacker, attIdx) // Remove attacker if he lost all opponents }
b.Protocol = append(b.Protocol, BattleAction{
Attacker: attIdx,
Defender: defIdx,
Destroyed: destroyed,
})
if destroyed {
c.ShipGroupDestroyItem(defIdx)
}
if c.ShipGroup(defIdx).Number == 0 {
// Eliminated group cant attack anyone
delete(b.attacker, defIdx)
delete(roundShooters, defIdx)
for attIdx := range b.attacker {
// Other attackers can't attack eliminated group anymore
delete(b.attacker[attIdx], defIdx)
if len(b.attacker[attIdx]) == 0 {
// Remove attacker if he lost all opponents
delete(b.attacker, attIdx)
delete(roundShooters, attIdx)
}
} }
} }
}
if len(b.attacker[attIdx]) == 0 { // When attacker has no more targets to shoot - break its ammo cycle
break if len(b.attacker[attIdx]) == 0 {
break
}
} }
} }
} }
@@ -212,3 +224,8 @@ func DestructionProbability(attWeapons, attWeaponsTech, defShields, defShiledsTe
func EffectiveDefence(defShields, defShiledsTech, defFullMass float64) float64 { func EffectiveDefence(defShields, defShiledsTech, defFullMass float64) float64 {
return defShields * defShiledsTech / math.Pow(defFullMass, 1./3.) * math.Pow(30., 1./3.) return defShields * defShiledsTech / math.Pow(defFullMass, 1./3.) * math.Pow(30., 1./3.)
} }
func randomValue(v iter.Seq[int]) int {
ids := slices.Collect(v)
return ids[rand.IntN(len(ids))]
}
+2 -2
View File
@@ -14,11 +14,11 @@ func (c *Controller) MakeTurn() error {
c.Cache.g.Turn += 1 c.Cache.g.Turn += 1
c.Cache.g.Stage = 0 c.Cache.g.Stage = 0
// TODO: Выполнение приказов
// 01. Вышедшие расы удаляются из списка участвующих рас перед началом просчета очередного хода // 01. Вышедшие расы удаляются из списка участвующих рас перед началом просчета очередного хода
c.Cache.TurnWipeExtinctRaces() c.Cache.TurnWipeExtinctRaces()
// TODO: передача кораблей между расами
// 02. Товары загружаются на корабли, находящиеся в начале грузовых маршрутов, и корабли входят в гиперпространство (но ещё не полетели) // 02. Товары загружаются на корабли, находящиеся в начале грузовых маршрутов, и корабли входят в гиперпространство (но ещё не полетели)
c.Cache.SendRoutedGroups() c.Cache.SendRoutedGroups()