package controller import ( "fmt" "math/rand/v2" "slices" "github.com/google/uuid" "github.com/iliadenisov/galaxy/server/internal/generator" "github.com/iliadenisov/galaxy/server/internal/model/game" ) func NewGame(r Repo, races []string) (uuid.UUID, error) { m, err := generator.Generate(func(ms *generator.MapSetting) { ms.Players = uint32(len(races)) }) if err != nil { return uuid.Nil, fmt.Errorf("generate map: %s", err) } return newGameOnMap(r, races, m) } func newGameOnMap(r Repo, races []string, m generator.Map) (uuid.UUID, error) { g, err := buildGameOnMap(races, m) if err != nil { return uuid.Nil, err } if err := r.SaveNewTurn(0, g); err != nil { return uuid.Nil, err } return g.ID, nil } func buildGameOnMap(races []string, m generator.Map) (*game.Game, error) { if len(races) != len(m.HomePlanets) { return nil, fmt.Errorf("generate map: wrong number of home planets: %d, expected: %d ", len(m.HomePlanets), len(races)) } gameID, err := uuid.NewRandom() if err != nil { return nil, fmt.Errorf("generate game uuid: %s", err) } g := &game.Game{ ID: gameID, Turn: 0, Race: make([]game.Race, len(races)), } gameMap := &game.Map{ Width: m.Width, Height: m.Height, Planet: make([]game.Planet, 0), } var planetCount uint = 0 relations := make([]game.RaceRelation, len(races)) for i := range races { raceID, err := uuid.NewRandom() if err != nil { return nil, fmt.Errorf("generate race uuid: %s", err) } relations[i] = game.RaceRelation{RaceID: raceID, Relation: game.RelationWar} g.Race[i] = game.Race{ ID: raceID, Name: races[i], VoteFor: raceID, TTL: 10, Tech: game.NewTechSet(), } gameMap.Planet = append(gameMap.Planet, NewPlanet( planetCount, m.HomePlanets[i].HW.RandomName(), &raceID, m.HomePlanets[i].HW.Position.X, m.HomePlanets[i].HW.Position.Y, m.HomePlanets[i].HW.Size, m.HomePlanets[i].HW.Size, // HW's pop & ind = size m.HomePlanets[i].HW.Size, m.HomePlanets[i].HW.Resources, game.ResearchDrive.AsType(uuid.Nil), )) planetCount++ for dw := range m.HomePlanets[i].DW { gameMap.Planet = append(gameMap.Planet, NewPlanet( planetCount, m.HomePlanets[i].DW[dw].RandomName(), &raceID, m.HomePlanets[i].DW[dw].Position.X, m.HomePlanets[i].DW[dw].Position.Y, m.HomePlanets[i].DW[dw].Size, m.HomePlanets[i].DW[dw].Size, // DW's pop & ind = size m.HomePlanets[i].DW[dw].Size, m.HomePlanets[i].DW[dw].Resources, game.ResearchDrive.AsType(uuid.Nil), )) planetCount++ } } for i := range g.Race { rel := slices.Clone(relations) selfIdx := slices.IndexFunc(rel, func(a game.RaceRelation) bool { return a.RaceID == g.Race[i].ID }) g.Race[i].Relations = append(rel[:selfIdx], rel[selfIdx+1:]...) } for i := range m.FreePlanets { gameMap.Planet = append(gameMap.Planet, NewPlanet( planetCount, m.FreePlanets[i].RandomName(), &uuid.Nil, m.FreePlanets[i].Position.X, m.FreePlanets[i].Position.Y, m.FreePlanets[i].Size, 0, 0, m.FreePlanets[i].Resources, game.ProductionNone.AsType(uuid.Nil), )) planetCount++ } rand.Shuffle(len(gameMap.Planet), func(i, j int) { gameMap.Planet[i].Number, gameMap.Planet[j].Number = gameMap.Planet[j].Number, gameMap.Planet[i].Number }) for i := range gameMap.Planet { g.Votes = g.Votes.Add(gameMap.Planet[i].Votes()) } g.Map = *gameMap return g, nil } func NewPlanet(num uint, name string, owner *uuid.UUID, x, y, size, pop, ind, res float64, prod game.Production) game.Planet { if owner != nil && *owner == uuid.Nil { owner = nil } return game.Planet{ Owner: owner, X: game.F(x), Y: game.F(y), Number: num, Size: game.F(size), Name: name, Resources: game.F(res), Population: game.F(pop), Industry: game.F(ind), Production: prod, } }