/// <summary>
        /// Return a list of tuples (IAgent, float), where float is the period in seconds at which the agent should be executed.
        /// </summary>
        public World Create()
        {
            Contract.Requires(this.Size.X > 0, "size.X must be positive");
            Contract.Requires(this.Size.Y > 0, "size.Y must be positive");

            WorldRules rules = this.WorldRulesFactory.Create(this.Random);

            var terrainMap  = this.TerrainGenerator.GenerateTerrainMap(rules, this.Size);
            var zoneMap     = new ArrayMap <int>(this.Size, rules.Zones[Zones.Empty]);
            var buildingMap = new ArrayMap <int>(this.Size, MapTypes.NoBuilding);

            Maps maps = new Maps(this.Size);

            terrainMap.RegisterTerrain(maps);
            zoneMap.RegisterZone(maps);
            buildingMap.RegisterBuilding(maps);

            var buildings = new AnonymousEntities(MapTypes.Building);

            foreach (var buildingComponents in rules.BuildingComponents.Values)
            {
                buildings.Extend(buildingComponents);
            }

            return(new World(maps, buildings, rules, new Ticker(), new RoadGraph(zoneMap, rules.Zones[Zones.Road])));
        }
示例#2
0
        public static void RegisterBuilidingModelResourceProductionComponent(WorldRules worldRules)
        {
            Contract.Requires(worldRules != null);

            var buildingResourceProduction = new TypedComponents <BuildingResourceProduction[]>(
                BuildingModelResourceProductionComponent,
                () => System.Array.Empty <BuildingResourceProduction>());

            var buildingModelsInitializer = new BuildingModelsInitializer(worldRules.BuildingModels, buildingResourceProduction);

            var resources = worldRules.Resources;

            int maxDistance = 16;

            buildingModelsInitializer.Set(
                Farm,
                new BuildingResourceProduction(resources[Resources.Food], 1, maxDistance),
                new BuildingResourceProduction(resources[Resources.Population], -1, maxDistance));

            buildingModelsInitializer.Set(
                House,
                new BuildingResourceProduction(resources[Resources.Food], -2, maxDistance),
                new BuildingResourceProduction(resources[Resources.Population], 4, maxDistance));

            buildingModelsInitializer.Set(
                ConvenienceStore,
                new BuildingResourceProduction(resources[Resources.Food], -5, maxDistance),
                new BuildingResourceProduction(resources[Resources.Population], -4, maxDistance));

            worldRules.BuildingModels.Extend(buildingResourceProduction);
        }
        public static void RegisterBuildingComponent(WorldRules worldRules)
        {
            Contract.Requires(worldRules != null);

            TypedComponents <int> typedComponents = new TypedComponents <int>(Component, worldRules.Random.Next);

            worldRules.BuildingComponents.Add(typedComponents.Name, typedComponents);
        }
示例#4
0
 public World(Maps maps, AnonymousEntities buildings, WorldRules rules, Ticker ticker, IGraph <Vector> transportGraph)
 {
     this.maps           = maps;
     this.Buildings      = buildings;
     this.Rules          = rules;
     this.ticker         = ticker;
     this.transportGraph = transportGraph;
 }
示例#5
0
        public static void RegisterDefaults(WorldRules worldRules)
        {
            Contract.Requires(worldRules != null);

            worldRules.ToolBrushes[Pen.Name]       = Pen;
            worldRules.ToolBrushes[Manatthan.Name] = Manatthan;
            worldRules.ToolBrushes[Rectangle.Name] = Rectangle;
        }
        /// <summary>
        /// The transport link of each building.
        /// The transport link is the position on the map where all path finding related to the building starts and ends.
        /// </summary>
        public static void RegisterBuildingTransportLink(WorldRules worldRules)
        {
            Contract.Requires(worldRules != null);

            var connectionsComponent = new TypedComponents <Vector?>(TransportLinkComponent, () => null);

            worldRules.BuildingComponents.Add(connectionsComponent.Name, connectionsComponent);
        }
        /// <summary>
        /// The connections of each building.
        /// The connection refers to a building id.
        /// Connections are bi-directional, in other words, if a building A has a connection to a building B, then building B must have a connection to building A.
        /// Building connections are used to satisfy the building supply chain.
        /// For example, a building with a model "house" consuming "food" will need to be connected to a building with a model producing "food" such as a "farm".
        /// There can be multiple connections for the same resource, until the constraint is satisfied, considering that resource productions have associated quantities.
        /// </summary>
        public static void RegisterBuildingConnections(WorldRules worldRules)
        {
            Contract.Requires(worldRules != null);

            var connectionsComponent = new TypedComponents <ISet <int> >(ConnectionsComponent, () => new HashSet <int>());

            worldRules.BuildingComponents.Add(connectionsComponent.Name, connectionsComponent);
        }
        /// <summary>
        /// The building model of each building, such a house, or a shop.
        /// Much of the building attributes are defined in the model.
        /// This is an implementation of the flywheel design pattern.
        /// </summary>
        public static void RegisterBuildingModelComponent(WorldRules worldRules)
        {
            Contract.Requires(worldRules != null);

            var buildingModelComponent = new TypedComponents <int>(BuildingModelComponent, () => BuildingModels.NoModel);

            worldRules.BuildingComponents.Add(buildingModelComponent.Name, buildingModelComponent);
        }
        /// <summary>
        /// The location of each building.
        /// </summary>
        public static void RegisterBuildingLocation(WorldRules worldRules)
        {
            Contract.Requires(worldRules != null);

            var connectionsComponent = new TypedComponents <Vector>(LocationComponent, () => new Vector(-1, -1));

            worldRules.BuildingComponents.Add(connectionsComponent.Name, connectionsComponent);
        }
        public static void RegisterDefaults(WorldRules worldRules)
        {
            Contract.Requires(worldRules != null);

            NamedEntities resources = worldRules.Resources;

            resources.Register(Population);
            resources.Register(Food);
        }
        public static void RegisterDefaults(WorldRules worldRules)
        {
            Contract.Requires(worldRules != null);

            NamedEntities terrains = worldRules.Terrains;

            terrains.Register(Land);
            terrains.Register(Water);
        }
示例#12
0
        public static void RegisterDefaults(WorldRules worldRules)
        {
            Contract.Requires(worldRules != null);

            NamedEntities buildingModels = worldRules.BuildingModels;

            buildingModels.Register(Farm);
            buildingModels.Register(House);
            buildingModels.Register(ConvenienceStore);
        }
        /// <summary>
        /// A zone component to define legal terrains corresponding to each zone. By default, the only legal terrain is Land.
        /// </summary>
        public static void RegisterZonableTerrainsComponent(WorldRules worldRules)
        {
            Contract.Requires(worldRules != null);

            var           zones             = worldRules.Zones;
            var           terrains          = worldRules.Terrains;
            ZonableOnlyOn zonableOnlyOnLand = new ZonableOnlyOn(terrains[Terrains.Land]);
            TypedComponents <IZonableTerrain> zonableTerrains = new TypedComponents <IZonableTerrain>(ZonableTerrains, () => zonableOnlyOnLand);

            zonableTerrains[zones[Zones.Empty]] = new AlwaysZonable();
            zones.Extend(zonableTerrains);
        }
        public static void RegisterManuallyZonableComponent(WorldRules worldRules)
        {
            Contract.Requires(worldRules != null);
            NamedEntities zones           = worldRules.Zones;
            var           manuallyZonable = new TypedComponents <bool>(ManuallyZonable, () => false);

            manuallyZonable[zones[Zones.Commercial]]  = true;
            manuallyZonable[zones[Zones.Farmland]]    = true;
            manuallyZonable[zones[Zones.Residential]] = true;
            manuallyZonable[zones[Zones.Road]]        = true;
            zones.Extend(manuallyZonable);
        }
        public static void RegisterDefaults(WorldRules worldRules)
        {
            Contract.Requires(worldRules != null);

            NamedEntities zones = worldRules.Zones;

            zones.Register(Empty);
            zones.Register(Commercial);
            zones.Register(Farmland);
            zones.Register(Residential);
            zones.Register(Road);
        }
        public WorldRules Create(Random random)
        {
            Contract.Requires(this.ConfigProvider != null);
            Contract.Requires(this.WorldRulesCustomizer != null);

            WorldRules wr = new WorldRules(random)
            {
                ConfigProvider = this.ConfigProvider,
            };

            this.WorldRulesCustomizer(wr);
            return(wr);
        }
示例#17
0
        public static void RegisterBuildingModelZoneComponent(WorldRules worldRules)
        {
            Contract.Requires(worldRules != null);

            var buildingModelZoneComponent = new TypedComponents <int>(BuildingModelZoneComponent, () => - 1);
            var buildingModels             = worldRules.BuildingModels;
            var zones = worldRules.Zones;

            buildingModelZoneComponent[buildingModels[Farm]]             = zones[Zones.Farmland];
            buildingModelZoneComponent[buildingModels[House]]            = zones[Zones.Residential];
            buildingModelZoneComponent[buildingModels[ConvenienceStore]] = zones[Zones.Commercial];

            worldRules.BuildingModels.Extend(buildingModelZoneComponent);
        }
        /// <summary>
        /// The default building model for each zone. This is used as estimate when computing how empty zones will develop.
        /// </summary>
        public static void RegisterZonesDefaultBuildingModel(WorldRules worldRules)
        {
            Contract.Requires(worldRules != null);

            var zones          = worldRules.Zones;
            var buildingModels = worldRules.BuildingModels;

            TypedComponents <int> defaultBuildingModels = new TypedComponents <int>(DefaultBuildingModel, () => BuildingModels.NoModel);

            defaultBuildingModels[zones[Zones.Farmland]]    = buildingModels[BuildingModels.Farm];
            defaultBuildingModels[zones[Zones.Residential]] = buildingModels[BuildingModels.House];
            defaultBuildingModels[zones[Zones.Commercial]]  = buildingModels[BuildingModels.ConvenienceStore];

            zones.Extend(defaultBuildingModels);
        }
示例#19
0
        public static void RegisterDefaults(WorldRules worldRules)
        {
            Contract.Requires(worldRules != null);

            var zones = worldRules.Zones;

            worldRules.ToolBehaviors[Zoner] = zoneName =>
            {
                var zone = zones.GetNamedEntity(zoneName);

                if (!zones.GetTypedComponents <bool>(Zones.ManuallyZonable).IsMarked(zone.Id))
                {
                    throw new ArgumentException(zone.Name);
                }

                return(new Zoner(zone));
            };
        }
示例#20
0
        public static void ConfigureBuildingConstructorAgent(WorldRules worldRules)
        {
            Contract.Requires(worldRules != null);

            EmptyLocationVoter emptyLocation = EmptyLocationVoter.GetInstance();
            StochasticVoter    stochastic    = new StochasticVoter(worldRules.Random);

            worldRules.ConfigProvider.RegisterConfigUpdateListener <double>("tiledev.rate", rate =>
            {
                Contract.Requires(rate >= 0.0 && rate <= 1.0);
                stochastic.DevelopmentRate = rate;
            });

            var buildingTransportLinkFinder = new BuildingTransportLinkFinder();

            worldRules.OnNewWorldListener += buildingTransportLinkFinder.OnNewWorld;
            worldRules.ConfigProvider.RegisterConfigUpdateListener <int>("transport_location.max_distance", maxDistance =>
            {
                Contract.Requires(maxDistance > 0);
                buildingTransportLinkFinder.MaxDistance = maxDistance;
            });

            var buildingConnectionFinder = new BuildingConnectionFinder(CreatePathFinder(), new RandomResourceProvider(buildingTransportLinkFinder));

            worldRules.OnNewWorldListener += buildingConnectionFinder.OnNewWorld;


            var buildingResource = new BuildingResourceVoter(buildingConnectionFinder, buildingTransportLinkFinder);

            CombinedBuildingDevelopmentVoter combinedTileDevelopmentVoter = new CombinedBuildingDevelopmentVoter(emptyLocation, stochastic, buildingResource);

            BuildingConstructorVoter buildingConstructionVoter = new BuildingConstructorVoter(combinedTileDevelopmentVoter, new ZoneBuildingModels());

            worldRules.OnNewWorldListener += w => buildingConstructionVoter.OnNewWorld(w);

            var zoneDeveloper = new BuildingConstructor(buildingConstructionVoter);

            worldRules.Agents[zoneDeveloper.Name] = new ScheduledAgent(zoneDeveloper, 1.0f);
        }