Files
galaxy-game/internal/controller/race.go
T
2026-01-14 22:17:24 +02:00

149 lines
3.5 KiB
Go

package controller
import (
"fmt"
"slices"
e "github.com/iliadenisov/galaxy/internal/error"
"github.com/iliadenisov/galaxy/internal/model/game"
)
func (c Controller) Relation(from, to string) (game.Relation, error) {
r1, err := c.Cache.raceIndex(from)
if err != nil {
return game.Relation(""), err
}
r2, err := c.Cache.raceIndex(to)
if err != nil {
return game.Relation(""), err
}
return c.Cache.Relation(r1, r2), nil
}
func (c Controller) UpdateRelation(race, opponent string, rel game.Relation) error {
ri, err := c.Cache.raceIndex(race)
if err != nil {
return err
}
var other int
if race == opponent {
other = ri
} else if other, err = c.Cache.raceIndex(opponent); err != nil {
return err
}
if err != nil {
return err
}
return c.Cache.UpdateRelation(ri, other, rel)
}
func (c *Cache) Relation(r1, r2 int) game.Relation {
if c.cacheRelation == nil {
c.cacheRelation = make(map[int]map[int]game.Relation)
for r1 := range c.g.Race {
for r2 := range c.g.Race {
if r1 == r2 {
continue
}
rel := slices.IndexFunc(c.g.Race[r1].Relations, func(r game.RaceRelation) bool { return r.RaceID == c.g.Race[r2].ID })
if rel < 0 {
panic(fmt.Sprintf("Relation: opponent not found idx=%d", r2))
}
c.updateRelationCache(r1, r2, c.g.Race[r1].Relations[rel].Relation)
}
}
}
if _, ok := c.cacheRelation[r1]; !ok {
panic(fmt.Sprintf("Relation: no left race idx=%d", r1))
}
if v, ok := c.cacheRelation[r1][r2]; !ok {
panic(fmt.Sprintf("Relation: no right race idx=%d", r2))
} else {
return v
}
}
func (c *Cache) updateRelationCache(r1, r2 int, rel game.Relation) {
if r1 == r2 {
return
}
if c.cacheRelation == nil {
c.cacheRelation = make(map[int]map[int]game.Relation)
}
if _, ok := c.cacheRelation[r1]; !ok {
c.cacheRelation[r1] = make(map[int]game.Relation)
}
c.cacheRelation[r1][r2] = rel
}
func (c *Cache) GiveVotes(race, recipient string) error {
ri, err := c.raceIndex(race)
if err != nil {
return err
}
rec, err := c.raceIndex(recipient)
if err != nil {
return err
}
c.g.Race[ri].Vote = c.g.Race[rec].ID
return nil
}
func (c *Cache) Voted(ri int) int {
c.validateRaceIndex(ri)
return c.RaceIndex(c.g.Race[ri].Vote)
}
func (c *Cache) UpdateRelation(ri, other int, rel game.Relation) (err error) {
defer func() {
if err == nil && c.cacheRelation != nil {
c.updateRelationCache(ri, other, rel)
}
}()
for o := range c.g.Race[ri].Relations {
switch {
case ri == other:
c.g.Race[ri].Relations[o].Relation = rel
case c.g.Race[ri].Relations[o].RaceID == c.g.Race[other].ID:
c.g.Race[ri].Relations[o].Relation = rel
return nil
}
}
if ri != other {
err = e.NewGameStateError("UpdateRelation: opponent not found")
}
return
// for o := range c.g.Race[r1].Relations {
// if c.g.Race[r1].Relations[o].RaceID == c.g.Race[r2].ID {
// c.g.Race[r1].Relations[o].Relation = rel
// if c.cacheRelation != nil {
// c.updateRelationCache(r1, r2, rel)
// }
// return nil
// }
// }
// return e.NewGameStateError("UpdateRelation: opponent not found")
}
func (c *Cache) validateRaceIndex(i int) {
if i >= len(c.g.Race) {
panic(fmt.Sprintf("race index out of range: %d >= %d", i, len(c.g.Race)))
}
}
func (c *Cache) raceIndex(name string) (int, error) {
i := slices.IndexFunc(c.g.Race, func(r game.Race) bool { return r.Name == name })
if i < 0 {
return i, e.NewRaceUnknownError(name)
}
return i, nil
}
func (c *Cache) racetTechLevel(ri int, t game.Tech, v float64) {
c.validateFleetIndex(ri)
c.g.Race[ri].Tech = c.g.Race[ri].Tech.Set(t, v)
}