Example #1
0
        public void ComputeWarpPointConnectivity()
        {
            warpGraph = new ConnectivityGraph <ObjectLocation <StarSystem> >(Galaxy.Current.StarSystemLocations);

            foreach (var ssl in warpGraph)
            {
                foreach (var wp in ssl.Item.FindSpaceObjects <WarpPoint>())
                {
                    if (wp.TargetStarSystemLocation == null)
                    {
                        continue;                         // can't make connection if we don't know where warp point ends!
                    }
                    warpGraph.Connect(ssl, wp.TargetStarSystemLocation);
                }
            }
        }
Example #2
0
 private static bool IntersectsExceptAtEnds(Point p1, Point p2, ConnectivityGraph <ObjectLocation <StarSystem> > graph)
 {
     foreach (var kvp in graph.Connections)
     {
         var q1 = kvp.Key.Location;
         foreach (var q2 in kvp.Value.Select(l => l.Location))
         {
             if (IntersectsExceptAtEnds(p1, p2, q1, q2))
             {
                 return(true);
             }
             // else no intersection
         }
     }
     return(false);
 }
        public void GenerateConnectivityMatrixTest()
        {
            ConnectivityGraph cGraph = new ConnectivityGraph();

            for (int i = 0; i < 5; i++)
            {
                cGraph.AddVertex();
            }

            cGraph.AddEdge(0, 2);
            cGraph.AddEdge(0, 1);
            cGraph.AddEdge(2, 1);
            cGraph.AddEdge(1, 3);
            cGraph.AddEdge(3, 4);

            var  connectivity = cGraph.GenerateConnectivityMatrix();
            bool row1         = connectivity[0][0] == false && connectivity[0][1] == true &&
                                connectivity[0][2] == true && connectivity[0][3] == true &&
                                connectivity[0][4] == true;

            bool row2 = connectivity[1][0] == false && connectivity[1][1] == false &&
                        connectivity[1][2] == false && connectivity[1][3] == true &&
                        connectivity[1][4] == true;

            bool row3 = connectivity[2][0] == false && connectivity[2][1] == true &&
                        connectivity[2][2] == false && connectivity[2][3] == true &&
                        connectivity[2][4] == true;

            bool row4 = connectivity[3][0] == false && connectivity[3][1] == false &&
                        connectivity[3][2] == false && connectivity[3][3] == false &&
                        connectivity[3][4] == true;

            bool row5 = connectivity[4][0] == false && connectivity[4][1] == false &&
                        connectivity[4][2] == false && connectivity[4][3] == false &&
                        connectivity[4][4] == false;

            Assert.IsTrue(row1 && row2 && row3 && row4 && row5);
        }
        public void GenerateConnectivityMatrixTest()
        {
            ConnectivityGraph cGraph = new ConnectivityGraph();
            for (int i = 0; i < 5; i++)
            {
                cGraph.AddVertex();
            }

            cGraph.AddEdge(0, 2);
            cGraph.AddEdge(0, 1);
            cGraph.AddEdge(2, 1);
            cGraph.AddEdge(1, 3);
            cGraph.AddEdge(3, 4);

            var connectivity = cGraph.GenerateConnectivityMatrix();
            bool row1 = connectivity[0][0] == false && connectivity[0][1] == true
                     && connectivity[0][2] == true && connectivity[0][3] == true
                     && connectivity[0][4] == true;

            bool row2 = connectivity[1][0] == false && connectivity[1][1] == false
                     && connectivity[1][2] == false && connectivity[1][3] == true
                     && connectivity[1][4] == true;

            bool row3 = connectivity[2][0] == false && connectivity[2][1] == true
                     && connectivity[2][2] == false && connectivity[2][3] == true
                     && connectivity[2][4] == true;

            bool row4 = connectivity[3][0] == false && connectivity[3][1] == false
                     && connectivity[3][2] == false && connectivity[3][3] == false
                     && connectivity[3][4] == true;

            bool row5 = connectivity[4][0] == false && connectivity[4][1] == false
                     && connectivity[4][2] == false && connectivity[4][3] == false
                     && connectivity[4][4] == false;

            Assert.IsTrue(row1 && row2 && row3 && row4 && row5);
        }
Example #5
0
        // TODO - status messages for the GUI
        private void PlaceEmpire(Galaxy gal, Empire emp, PRNG dice)
        {
            if (AllSystemsExplored)
            {
                // set all systems explored
                foreach (var sys in gal.StarSystemLocations.Select(ssl => ssl.Item))
                {
                    sys.ExploredByEmpires.Add(emp);
                }
            }

            // give empire starting techs
            Galaxy.Current.CleanGameState();             // need to know what the techs in the game are!
            foreach (var tech in Mod.Current.Technologies.Where(t => !t.IsRacial || emp.Abilities().Any(a => a.Rule.Matches("Tech Area") && a.Value1 == t.RacialTechID)))
            {
                switch (StartingTechnologyLevel)
                {
                case StartingTechnologyLevel.Low:
                    emp.ResearchedTechnologies[tech] = tech.StartLevel;
                    break;

                case StartingTechnologyLevel.Medium:
                    emp.ResearchedTechnologies[tech] = Math.Max(tech.StartLevel, tech.RaiseLevel);
                    break;

                case StartingTechnologyLevel.High:
                    emp.ResearchedTechnologies[tech] = tech.MaximumLevel;
                    break;
                }
            }

            // give empire starting resources and storage capacity
            foreach (var r in Resource.All.Where(r => r.IsGlobal))
            {
                emp.StoredResources.Add(r, StartingResources);
                emp.IntrinsicResourceStorage.Add(r, ResourceStorage);
            }

            // give empire starting research
            emp.BonusResearch = StartingResearch + (int)(ResearchPointsPerUnspentEmpirePoint * (EmpirePoints - emp.PrimaryRace.Traits.Sum(q => q.Cost)));

            // TODO - moddable colony techs?
            string colonyTechName = null;

            if ((emp.PrimaryRace.NativeSurface) == "Rock")
            {
                colonyTechName = "Rock Planet Colonization";
            }
            else if ((emp.PrimaryRace.NativeSurface) == "Ice")
            {
                colonyTechName = "Ice Planet Colonization";
            }
            else if ((emp.PrimaryRace.NativeSurface) == "Gas Giant")
            {
                colonyTechName = "Gas Giant Colonization";
            }
            var colonyTech = Mod.Current.Technologies.SingleOrDefault(t => t.Name == colonyTechName);

            if (colonyTech != null && emp.ResearchedTechnologies[colonyTech] < 1)
            {
                emp.ResearchedTechnologies[colonyTech] = 1;
            }

            // find facilities to place on homeworlds
            var facils = emp.UnlockedItems.OfType <FacilityTemplate>();
            var sy     = facils.WithMax(facil => facil.GetAbilityValue("Space Yard", 2).ToInt()).LastOrDefault();
            var sp     = facils.LastOrDefault(facil => facil.HasAbility("Spaceport"));
            var rd     = facils.LastOrDefault(facil => facil.HasAbility("Supply Generation"));
            var min    = facils.WithMax(facil => facil.GetAbilityValue("Resource Generation - Minerals").ToInt()).LastOrDefault();
            var org    = facils.WithMax(facil => facil.GetAbilityValue("Resource Generation - Organics").ToInt()).LastOrDefault();
            var rad    = facils.WithMax(facil => facil.GetAbilityValue("Resource Generation - Radioactives").ToInt()).LastOrDefault();
            var res    = facils.WithMax(facil => facil.GetAbilityValue("Point Generation - Research").ToInt()).LastOrDefault();
            // TODO - game setup option for intel facilities on homeworlds? HomeworldStartingFacilities.txt ala se5?

            // SY rate, for colonies
            var rate = new ResourceQuantity();

            if (sy != null)
            {
                // TODO - define mappings between SY ability numbers and resource names in a mod file
                rate.Add(Resource.Minerals, sy.GetAbilityValue("Space Yard", 2, true, true, a => a.Value1 == "1").ToInt());
                rate.Add(Resource.Organics, sy.GetAbilityValue("Space Yard", 2, true, true, a => a.Value1 == "2").ToInt());
                rate.Add(Resource.Radioactives, sy.GetAbilityValue("Space Yard", 2, true, true, a => a.Value1 == "3").ToInt());
            }

            // build connectivity graph for computing warp distance
            var graph = new ConnectivityGraph <StarSystem>();

            foreach (var s in Galaxy.Current.StarSystemLocations.Select(ssl => ssl.Item))
            {
                graph.Add(s);
            }
            foreach (var s in Galaxy.Current.StarSystemLocations.Select(ssl => ssl.Item))
            {
                foreach (var wp in s.FindSpaceObjects <WarpPoint>())
                {
                    graph.Connect(s, wp.TargetStarSystemLocation.Item, true);
                }
            }

            for (int i = 0; i < HomeworldsPerEmpire; i++)
            {
                // TODO - respect Empire Placement and Max Homeworld Dispersion settings
                var planets   = gal.StarSystemLocations.SelectMany(ssl => ssl.Item.FindSpaceObjects <Planet>(p => p.Owner == null && p.MoonOf == null));
                var okSystems = gal.StarSystemLocations.Select(ssl => ssl.Item).Where(sys => sys.EmpiresCanStartIn);
                if (i > 0)
                {
                    // make sure subsequent homeworlds are placed within a limited number of warps from the first homeworld
                    okSystems = okSystems.Where(sys => graph.ComputeDistance(sys, emp.OwnedSpaceObjects.OfType <Planet>().First().FindStarSystem()) <= MaxHomeworldDispersion);
                }
                switch (EmpirePlacement)
                {
                case EmpirePlacement.CanStartInSameSystem:
                    // no further filtering
                    break;

                case EmpirePlacement.DifferentSystems:
                    // filter to systems containing no other empires' homeworlds
                    okSystems = okSystems.Where(sys => !sys.FindSpaceObjects <Planet>(p => p.Owner != null && p.Owner != emp).Any());
                    break;

                case EmpirePlacement.Equidistant:
                    // filter to systems containing no other empires' homeworlds
                    okSystems = okSystems.Where(sys => !sys.FindSpaceObjects <Planet>(p => p.Owner != null && p.Owner != emp).Any());
                    // filter to systems that are the maximum distance away from any other empire's homeworlds
                    var otherEmpireHomeSystems = gal.StarSystemLocations.SelectMany(ssl => ssl.Item.FindSpaceObjects <Planet>(p => p.Owner != null && p.Owner != emp).Select(p => p.FindStarSystem()).Distinct()).ToArray();
                    okSystems = okSystems.WithMax(sys => otherEmpireHomeSystems.Min(o => graph.ComputeDistance(sys, o)));
                    break;
                }
                okSystems = okSystems.ToArray();
                if (!okSystems.Any())
                {
                    // replace an inhospitable system with a hospitable one
                    var convertSys = gal.StarSystemLocations.Select(ssl => ssl.Item).Where(sys => !sys.EmpiresCanStartIn).PickRandom(dice);
                    if (convertSys == null)
                    {
                        throw new Exception("No suitable system found to place " + emp + "'s homeworld #" + (i + 1) + ". (Try increasing the number of star systems.)");
                    }
                    var newSys = Mod.Current.StarSystemTemplates.Where(q => q.EmpiresCanStartIn).PickRandom(dice).Instantiate();
                    var sid    = convertSys.ID;
                    newSys.CopyTo(convertSys);
                    convertSys.ID   = sid;
                    convertSys.Name = Mod.Current.StarSystemNames.Except(gal.StarSystemLocations.Select(q => q.Item.Name)).PickRandom(dice);
                    foreach (var l in Galaxy.Current.StarSystemLocations)
                    {
                        foreach (var wp in l.Item.FindSpaceObjects <WarpPoint>().Where(q => q.Target.StarSystem == convertSys).ToArray())
                        {
                            wp.Dispose();
                            WarpPointPlacementStrategy.PlaceWarpPoints(Galaxy.Current.StarSystemLocations.Single(q => q.Item == convertSys), l);
                        }
                    }
                    GalaxyTemplate.NameStellarObjects(convertSys);
                    okSystems = new[] { convertSys };
                }
                Planet hw;
                planets = planets.Where(p => okSystems.Contains(p.FindStarSystem()));
                if (!planets.Any())
                {
                    // make sure we're placing the homeworld in a system with at least one empty sector
                    okSystems = okSystems.Where(sys2 => sys2.Sectors.Any(sec => !sec.SpaceObjects.Any()));

                    if (!okSystems.Any())
                    {
                        throw new Exception("No suitable system found to place " + emp + "'s homeworld #" + (i + 1) + ". (Try regenerating the map or increasing the number of star systems.)");
                    }

                    // make brand new planet in an OK system
                    var sys     = okSystems.PickRandom(dice);
                    var nextNum = sys.FindSpaceObjects <Planet>(p => p.MoonOf == null).Count() + 1;
                    hw = MakeHomeworld(emp, sys.Name + " " + nextNum.ToRomanNumeral(), dice);
                    var okSectors = sys.Sectors.Where(sector => !sector.SpaceObjects.Any());
                    okSectors.PickRandom(dice).Place(hw);
                }
                else
                {
                    hw = planets.PickRandom(dice);
                }
                if (hw.Surface != emp.PrimaryRace.NativeSurface || hw.Atmosphere != emp.PrimaryRace.NativeAtmosphere || hw.Size != HomeworldSize)
                {
                    var replacementHomeworld = MakeHomeworld(emp, hw.Name, dice);
                    replacementHomeworld.CopyTo(hw);
                }
                hw.ResourceValue[Resource.Minerals] = hw.ResourceValue[Resource.Organics] = hw.ResourceValue[Resource.Radioactives] = HomeworldValue;
                hw.Colony = new Colony
                {
                    Owner             = emp,
                    ConstructionQueue = new ConstructionQueue(hw),
                    IsHomeworld       = true,
                };
                hw.AddPopulation(emp.PrimaryRace, hw.Size.MaxPopulation);
                if (sy != null && hw.Colony.Facilities.Count < hw.MaxFacilities)
                {
                    hw.Colony.Facilities.Add(sy.Instantiate());
                }
                if (sp != null && hw.Colony.Facilities.Count < hw.MaxFacilities && (!emp.HasAbility("No Spaceports") || sp.Abilities.Count > 1))
                {
                    // natural merchants get spaceports only if spaceports have more than one ability
                    // of course, if the other abilities are *penalties*... oh well, they can scrap them!
                    hw.Colony.Facilities.Add(sp.Instantiate());
                }
                if (rd != null && hw.Colony.Facilities.Count < hw.MaxFacilities)
                {
                    hw.Colony.Facilities.Add(rd.Instantiate());
                }
                var lastCount = 0;
                while (hw.Colony.Facilities.Count < hw.MaxFacilities && hw.Colony.Facilities.Count > lastCount)
                {
                    lastCount = hw.Colony.Facilities.Count;

                    if (min != null && hw.Colony.Facilities.Count < hw.MaxFacilities)
                    {
                        hw.Colony.Facilities.Add(min.Instantiate());
                    }
                    if (org != null && hw.Colony.Facilities.Count < hw.MaxFacilities)
                    {
                        hw.Colony.Facilities.Add(org.Instantiate());
                    }
                    if (rad != null && hw.Colony.Facilities.Count < hw.MaxFacilities)
                    {
                        hw.Colony.Facilities.Add(rad.Instantiate());
                    }

                    // no research facilities needed at max tech!
                    if (StartingTechnologyLevel != StartingTechnologyLevel.High)
                    {
                        if (res != null && hw.Colony.Facilities.Count < hw.MaxFacilities)
                        {
                            hw.Colony.Facilities.Add(res.Instantiate());
                        }
                    }
                }
                foreach (var f in hw.Colony.Facilities)
                {
                    f.ConstructionProgress = f.Cost;
                }
            }

            // mark home systems explored
            foreach (var sys in gal.StarSystemLocations.Select(ssl => ssl.Item))
            {
                if (!sys.ExploredByEmpires.Contains(emp) && sys.FindSpaceObjects <Planet>().Any(planet => planet.Owner == emp))
                {
                    sys.ExploredByEmpires.Add(emp);
                }
            }

            // in case two empires started in the same system
            foreach (var x in gal.FindSpaceObjects <ISpaceObject>().Owned().ToArray())
            {
                x.UpdateEmpireMemories();
            }
        }
Example #6
0
        private (ObjectLocation <StarSystem>, ObjectLocation <StarSystem>) MinDistanceDisconnectedSystemPair(ConnectivityGraph <ObjectLocation <StarSystem> > graph)
        {
            if (graph.Subgraphs.Count() == 0)
            {
                return(null, null);
            }

            (ObjectLocation <StarSystem>, ObjectLocation <StarSystem>)best = (null, null);
            int bestDistance = int.MaxValue;

            if (graph.Subgraphs.Count() == 1)
            {
                foreach (var l1 in graph)
                {
                    foreach (var l2 in graph)
                    {
                        if (graph.AreDirectlyConnected(l1, l2))
                        {
                            continue;
                        }
                        if (IntersectsExceptAtEnds(l1.Location, l2.Location, graph))
                        {
                            continue;
                        }
                        var dist = l1.Location.ManhattanDistance(l2.Location);
                        if (dist < bestDistance && AreWarpPointAnglesOk(l1, l2, Galaxy.Current, MinWarpPointAngle))
                        {
                            bestDistance = dist;
                            best         = (l1, l2);
                        }
                    }
                }
                return(best);
            }

            foreach (var g1 in graph.Subgraphs)
            {
                foreach (var g2 in graph.Subgraphs.ExceptSingle(g1))
                {
                    foreach (var l1 in g1)
                    {
                        foreach (var l2 in g2)
                        {
                            if (graph.AreDirectlyConnected(l1, l2))
                            {
                                continue;
                            }
                            var dist = l1.Location.ManhattanDistance(l2.Location);
                            if (dist < bestDistance && AreWarpPointAnglesOk(l1, l2, Galaxy.Current, MinWarpPointAngle))
                            {
                                bestDistance = dist;
                                best         = (l1, l2);
                            }
                        }
                    }
                }
            }
            return(best);
        }
Example #7
0
        /// <param name="status">A status object to report status back to the GUI.</param>
        /// <param name="desiredProgress">How much progress should we report back to the GUI when we're done initializing the galaxy? 1.0 means all done with everything that needs to be done.</param>
        public Galaxy Instantiate(Status status, double desiredProgress, PRNG dice)
        {
            var gal = new Galaxy();

            gal.Width                   = GameSetup.GalaxySize.Width;
            gal.Height                  = GameSetup.GalaxySize.Height;
            gal.MinPlanetValue          = GameSetup.MinPlanetValue;
            gal.MinSpawnedPlanetValue   = GameSetup.MinSpawnedPlanetValue;
            gal.MaxSpawnedPlanetValue   = GameSetup.MaxSpawnedPlanetValue;
            gal.MaxPlanetValue          = GameSetup.MaxPlanetValue;
            gal.MinAsteroidValue        = GameSetup.MinAsteroidValue;
            gal.MinSpawnedAsteroidValue = GameSetup.MinSpawnedAsteroidValue;
            gal.MaxSpawnedAsteroidValue = GameSetup.MaxSpawnedAsteroidValue;
            gal.EventFrequency          = GameSetup.EventFrequency;
            gal.MaximumEventSeverity    = GameSetup.MaximumEventSeverity;
            var bounds = new Rectangle(-GameSetup.GalaxySize.Width / 2, -GameSetup.GalaxySize.Height / 2, GameSetup.GalaxySize.Width, GameSetup.GalaxySize.Height);

            var unusedNames = new List <string>(Mod.Current.StarSystemNames);

            // create star systems
            if (status != null)
            {
                status.Message = "Creating star systems";
            }
            var progressPerStarSystem = (desiredProgress - (status == null ? 0 : status.Progress)) / GameSetup.StarSystemCount / 2d;

            for (int i = 0; i < GameSetup.StarSystemCount; i++)
            {
                if (status != null)
                {
                    status.Message = "Creating star system " + (i + 1) + " of " + GameSetup.StarSystemCount;
                }
                var p = StarSystemPlacementStrategy.PlaceStarSystem(gal, MinimumStarSystemDistance, bounds, GameSetup.StarSystemCount - i, dice);
                if (p == null)
                {
                    break;                     // no more locations available
                }
                var sst = StarSystemTemplateChances.PickWeighted(dice);
                sst.Dice = dice;
                var sys = sst.Instantiate();
                sys.Name = unusedNames.PickRandom(dice);
                unusedNames.Remove(sys.Name);
                NameStellarObjects(sys);
                gal.StarSystemLocations.Add(new ObjectLocation <StarSystem> {
                    Location = p.Value, Item = sys
                });
                if (status != null)
                {
                    status.Progress += progressPerStarSystem;
                }
            }

            var progressPerWarp = (desiredProgress - (status == null ? 0 : status.Progress)) / (gal.StarSystemLocations.Count * 2);

            // create warp points
            if (status != null)
            {
                status.Message = "Creating warp points";
            }
            var graph = new ConnectivityGraph <ObjectLocation <StarSystem> >();

            foreach (var ssl in gal.StarSystemLocations)
            {
                graph.Add(ssl);
            }
            int wpsGenerated = 0;

            while (wpsGenerated < gal.StarSystemLocations.Count * 2)
            {
                // pick 2 systems
                ObjectLocation <StarSystem> startLocation = null, endLocation = null;
                (startLocation, endLocation) = MinDistanceDisconnectedSystemPair(graph);

                // create the warp points
                if (startLocation != null && endLocation != null)
                {
                    GameSetup.WarpPointPlacementStrategy.PlaceWarpPoints(startLocation, endLocation);

                    // mark systems connected
                    graph.Connect(startLocation, endLocation, true);

                    wpsGenerated++;
                }
                else
                {
                    break;
                }
                if (status != null)
                {
                    status.Progress += progressPerWarp;
                }
            }

            // TODO - delete excess warp points if system groups count is >1

            if (status != null)
            {
                status.Progress = desiredProgress;
            }

            return(gal);
        }
        // Compares the edges topological order
        private void TopologyCompare(IEnumerable<IStaticGraph> staticGraphs, IEnumerable<IDynamicGraph> dynamicGraphs)
        {
            Console.WriteLine("Starting topology comparer");
            // Find connected pairs to compare
            var connectivity = new ConnectivityGraph();

            for (var i = 0; i < _n; i++)
            {
                connectivity.AddVertex();
            }

            foreach (var edge in _edges)
            {
                connectivity.AddEdge(edge.Item1, edge.Item2);
            }

            // matrix of node connectivity
            Console.WriteLine("Generating connectivity matrix");
            var matrix = connectivity.GenerateConnectivityMatrix();
            var topologies = new List<Tuple<string, SGTree<int>, List<SGTNode<int>>>>();
            Console.WriteLine("Connectivity matrix completed");

            foreach (var algorithm in staticGraphs)
            {
                var sgt = new SGTree<int>(0.75);
                var top = algorithm.TopoSort();
                var items = new List<SGTNode<int>>();

                var prev = sgt.insertFirst(top[0]);
                items.Add(prev);
                for (var i = 1; i < top.Length; i++)
                {
                    prev = sgt.insertAfter(prev, top[i]);
                    items.Add(prev);
                }

                items.Sort(Comparer<SGTNode<int>>.Create((i, j) => i.Value.CompareTo(j.Value)));
                topologies.Add(new Tuple<string, SGTree<int>, List<SGTNode<int>>>
                    (algorithm.GetType().ToString(), sgt, items));
            }

            foreach (var algorithm in dynamicGraphs)
            {
                var sgt = new SGTree<int>(0.75);
                var top = algorithm.Topology();
                var items = new List<SGTNode<int>>();

                var prev = sgt.insertFirst(top[0]);
                items.Add(prev);
                for (var i = 1; i < top.Count; i++)
                {
                    prev = sgt.insertAfter(prev, top[i]);
                    items.Add(prev);
                }

                items.Sort(Comparer<SGTNode<int>>.Create((i, j) => i.Value.CompareTo(j.Value)));
                topologies.Add(new Tuple<string, SGTree<int>, List<SGTNode<int>>>(algorithm.GetType().ToString(), sgt,
                    items));
            }

            Console.Write("Performing topology compare");
            for (var i = 0; i < matrix.Count; i++)
            {
                for (var j = 0; j < matrix.Count; j++)
                {
                    if (matrix[i][j])
                    {
                        foreach (var algorithm in topologies)
                        {
                            //if(!algorithm.Item2.query(algorithm.Item3[i], algorithm.Item3[j]))
                            if (!algorithm.Item2.Query(algorithm.Item3[j], algorithm.Item3[i]))
                            {
                                WriteFile("TopoCompFail");
                                throw new Exception("Topological comparison failed for: " + algorithm.Item1);
                            }
                        }
                    }
                }
            }
        }