fix: battles are not round-based
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"iter"
|
||||
"maps"
|
||||
"math"
|
||||
"math/rand/v2"
|
||||
@@ -84,15 +85,6 @@ func FilterBattleOpponents(c *Cache, attIdx, defIdx int, cacheProbability map[in
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
FIXME: Сражение происходит раундами
|
||||
|
||||
Случайным образом из всех участвующих в сражении вооруженных кораблей выбирается один...
|
||||
...Затем вновь случайным образом выбирается корабль, который будет стрелять...
|
||||
Так продолжается до тех пор, пока не отстреляются все корабли. Если после
|
||||
этого еще остались корабли и с той и с другой стороны, все повторяется с
|
||||
самого начала (происходит еще один цикл сражения).
|
||||
*/
|
||||
func ProduceBattles(c *Cache) []*Battle {
|
||||
cacheProbability := make(map[int]map[int]float64)
|
||||
defer func() { clear(cacheProbability) }()
|
||||
@@ -159,45 +151,65 @@ func ProduceBattles(c *Cache) []*Battle {
|
||||
}
|
||||
|
||||
func SingleBattle(c *Cache, b *Battle) {
|
||||
roundShooters := make(map[int]bool)
|
||||
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] {
|
||||
defenders := slices.Collect(maps.Keys(b.attacker[attIdx]))
|
||||
defIdx := defenders[rand.IntN(len(defenders))]
|
||||
destroyed := false
|
||||
for len(roundShooters) > 0 {
|
||||
// attacke group id among round participants
|
||||
attIdx := randomValue(maps.Keys(roundShooters))
|
||||
delete(roundShooters, attIdx)
|
||||
|
||||
probability := b.attacker[attIdx][defIdx]
|
||||
switch {
|
||||
case probability >= 1:
|
||||
destroyed = true
|
||||
case probability > 0:
|
||||
destroyed = rand.Float64() >= probability
|
||||
default:
|
||||
panic("SingleBattle: probability unexpected: value <= 0")
|
||||
}
|
||||
for range b.shipAmmo[attIdx] {
|
||||
// defender group id among all attacker's opponents
|
||||
defIdx := randomValue(maps.Keys(b.attacker[attIdx]))
|
||||
|
||||
b.Protocol = append(b.Protocol, BattleAction{
|
||||
Attacker: attIdx,
|
||||
Defender: defIdx,
|
||||
Destroyed: destroyed,
|
||||
})
|
||||
destroyed := false
|
||||
|
||||
if destroyed {
|
||||
c.ShipGroupDestroyItem(defIdx)
|
||||
}
|
||||
if c.ShipGroup(defIdx).Number == 0 {
|
||||
delete(b.attacker, defIdx) // Eliminated group cant attack anyone
|
||||
for attIdx := range b.attacker {
|
||||
delete(b.attacker[attIdx], defIdx) // Other attackers can't attack eliminated group anymore
|
||||
if len(b.attacker[attIdx]) == 0 {
|
||||
delete(b.attacker, attIdx) // Remove attacker if he lost all opponents
|
||||
probability := b.attacker[attIdx][defIdx]
|
||||
switch {
|
||||
case probability >= 1:
|
||||
destroyed = true
|
||||
case probability > 0:
|
||||
destroyed = rand.Float64() >= probability
|
||||
default:
|
||||
panic("SingleBattle: probability unexpected: value <= 0")
|
||||
}
|
||||
|
||||
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 {
|
||||
break
|
||||
|
||||
// When attacker has no more targets to shoot - break its ammo cycle
|
||||
if len(b.attacker[attIdx]) == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -212,3 +224,8 @@ 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 randomValue(v iter.Seq[int]) int {
|
||||
ids := slices.Collect(v)
|
||||
return ids[rand.IntN(len(ids))]
|
||||
}
|
||||
|
||||
@@ -14,11 +14,11 @@ func (c *Controller) MakeTurn() error {
|
||||
c.Cache.g.Turn += 1
|
||||
c.Cache.g.Stage = 0
|
||||
|
||||
// TODO: Выполнение приказов
|
||||
|
||||
// 01. Вышедшие расы удаляются из списка участвующих рас перед началом просчета очередного хода
|
||||
c.Cache.TurnWipeExtinctRaces()
|
||||
|
||||
// TODO: передача кораблей между расами
|
||||
|
||||
// 02. Товары загружаются на корабли, находящиеся в начале грузовых маршрутов, и корабли входят в гиперпространство (но ещё не полетели)
|
||||
c.Cache.SendRoutedGroups()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user