public World(ushort initialHealthy, ushort initialSick, float timeScale, bool singleCore, List <Pipeline> pipelines)
        {
            // Using 2/3 of the computer cores. The other 1/3 is used for UI
            // rendering, server handling, your OS, etc.
            // Remove the arithmetic below and watch your computer INCENERATE.
            var calculatedOptimalCores = Environment.ProcessorCount * 2 / 3;

            if (singleCore || calculatedOptimalCores < 1)
            {
                this.NumberOfCores = 1;
            }
            else
            {
                this.NumberOfCores = calculatedOptimalCores;
            }
            this.initialHealthy = initialHealthy;
            this.initialSick    = initialSick;
            this.timeScale      = timeScale;
            this.SimState       = SimulationState.PAUSED;
            this.pipelines      = pipelines;

            /* Create different entity managers */
            regionManagers = new Region[NumberOfCores];
            int deltaX = World.MaxCoords.X / NumberOfCores;
            List <EntityOnMap <AbstractEntity> > population = new List <EntityOnMap <AbstractEntity> >();

            // Populate the initially healthy population
            if (outOfBoundsLock.WaitOne())
            {
                for (ushort _ = 0; _ < initialHealthy; _++)
                {
                    var p = new Point(rnd.Next(0, MaxCoords.X), rnd.Next(0, MaxCoords.Y));
                    var entity_constructed = new HealthyEntity();
                    outOfBoundsPopulationHealthy.Add(new EntityOnMap <HealthyEntity>(p, entity_constructed));
                }
                // Populate the initially sick population
                for (ushort _ = 0; _ < initialSick; _++)
                {
                    var p = new Point(rnd.Next(0, MaxCoords.X), rnd.Next(0, MaxCoords.Y));
                    var entity_constructed = new SickEntity();
                    outOfBoundsPopulationSick.Add(new EntityOnMap <SickEntity>(p, entity_constructed));
                }
                outOfBoundsLock.ReleaseMutex();
            }
            else
            {
                throw new InvalidOperationException("The initial mutex was already locked!");
            }
            for (int i = 0; i < NumberOfCores; i++)
            {
                int localMaxX = i * deltaX + deltaX;
                int localMinX = i * deltaX;
                regionManagers[i] = new Region(
                    (Point point) => MustLeave(point, localMaxX, localMinX),
                    (List <EntityOnMap <SickEntity> > entitiesSick, List <EntityOnMap <HealthyEntity> > entitiesHealthy) => SyncResource(entitiesSick, entitiesHealthy, i)
                    );
            }
        }
Example #2
0
        public override PipelineReturnData pushThrough(List <EntityOnMap <SickEntity> > currentSick, List <EntityOnMap <HealthyEntity> > currentHealthy, ulong timeDeltaMs)
        {
            // Make entities sick if they need to

            /*
             * NOTE: Because the timeScale parameter removes "frames"
             * and possible intersections (no interpolation is being
             * done as it's quite intensive to do at real time),
             * the code tries to compensate by increasing the radius.
             * Because we don't want everyone to become sick immediately,
             * then linear scaling is not possible. Using this
             * (https://www.desmos.com/calculator/7agyg8rqqz) for
             * trying out some things.
             */
            var toBeSick = currentHealthy
                           .Where(h =>
            {
                // Only keep entries that are intersecting with sick people
                return(currentSick
                       .Any(s => EntityOnMap <SickEntity> .IsIntersecting(
                                s.location, radius,
                                h.location, radius)
                            ));
            })
                           .Select((x, idx) =>
            {
                // Covert to sick entities
                var sickEntity  = SickEntity.ConvertToSick(x.entity);
                var sickMapItem = EntityConverterUtility <HealthyEntity, SickEntity> .ConvertInnerEntities(x, sickEntity);
                return(sickMapItem);
            })
                           .Aggregate((new List <ulong>(), new List <EntityOnMap <SickEntity> >()), (aggregate, item) =>
            {
                aggregate.Item1.Add(item.ID);
                aggregate.Item2.Add(item);
                return(aggregate);
            })
                           .ToTuple();

            return(new PipelineReturnData
            {
                newHealthy = currentHealthy.Where(x => !toBeSick.Item1.Contains(x.ID)).ToList(),
                newSick = currentSick.Concat(toBeSick.Item2).ToList(),
            });
        }
        public override PipelineReturnData pushThrough(List <EntityOnMap <SickEntity> > currentSick, List <EntityOnMap <HealthyEntity> > currentHealthy, ulong timeDeltaMs)
        {
            var newHealthy = currentSick
                             .Where(x => ((SickEntity)x.entity).recovery >= 1f)
                             .Aggregate(new Tuple <List <EntityOnMap <HealthyEntity> >, List <ulong> >(new List <EntityOnMap <HealthyEntity> >(), new List <ulong>()), (aggregate, x) =>
            {
                var healthyEntity = SickEntity.ConvertToHealthy(x.entity);
                var sickMapItem   = EntityConverterUtility <SickEntity, HealthyEntity> .ConvertInnerEntities(x, healthyEntity);
                aggregate.Item1.Add(sickMapItem);
                aggregate.Item2.Add(sickMapItem.ID);
                return(aggregate);
            }).ToValueTuple();

            return(new PipelineReturnData
            {
                newHealthy = currentHealthy.Concat(newHealthy.Item1).ToList(),
                newSick = currentSick.Where(x => !newHealthy.Item2.Contains(x.ID)).ToList(),
            });
        }