Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using System.Drawing;
- using System.Drawing.Imaging;
- using ImageMagick;
- using System.IO;
- namespace Infection
- {
- class Program
- {
- #region Infection Options
- private const double ProbabilityOfTransmission = .2;
- private const double ChanceOfMutation = 0.01;
- private const Int16 StageSize = 1000;
- private const Int16 MaxNumberOfMutations = 800;
- private const byte MaxInfectionTime = 3;
- private const byte NumberOfPeopleToRandomlyInfect = 4;
- private static int NumberOfPeriods = 1000;
- #endregion Infection Options
- #region Run Options
- private const bool VerbosMode = false;
- private const int ImageFrequency = 10;
- #endregion Run Options
- #region Stage
- private static Int16 MutationNumber = 1;
- private class Person
- {
- public Person()
- {
- PreviousInfections = new Dictionary<Int16, byte>();
- InfectionTime = 0;
- CurrentInfection = 0;
- PossibleNewInfections = new List<short>(4);
- }
- public Dictionary<Int16, byte> PreviousInfections { get; set; }
- public byte InfectionTime { get; set; }
- public Int16 CurrentInfection { get; set; }
- public List<Int16> PossibleNewInfections { get; set; }
- }
- private static Person[][] Stage = new Person[StageSize][];
- #endregion Stage
- static void Main(string[] args)
- {
- DateTime start = DateTime.UtcNow;
- //Initialize stage
- for (Int16 i = 0; i < Stage.Length; i++)
- {
- var tmpList = new List<Person>();
- for (Int16 j = 0; j < Stage.Length; j++)
- tmpList.Add(new Person());
- Stage[i] = tmpList.ToArray();
- }
- //Randomly infect people
- RandomlyInfectPeople(NumberOfPeopleToRandomlyInfect);
- //Run through the periods(NumberOfPeriods times)
- List<MagickImage> output = new List<MagickImage>();
- while (NumberOfPeriods > 0)
- {
- //Print details(verbose)
- if (VerbosMode && NumberOfPeriods % ImageFrequency == 0)
- {
- Console.WriteLine("Current Number: " + NumberOfPeriods);
- Console.WriteLine("Current Mutation: " + MutationNumber);
- output.Add(BoardToImage());
- }
- Period();
- }
- //Outputs a Animated Gif(verbose)
- if (VerbosMode)
- {
- ImagesToAnimatedGIF(output.ToArray(), Directory.GetCurrentDirectory() + "\\Output.gif");
- System.Diagnostics.Process.Start(Directory.GetCurrentDirectory() + "\\Output.gif");
- }
- //Only outputs the basic result image matching the specs
- SaveBoardToSimpleImage(Directory.GetCurrentDirectory() + "\\FinalState.gif");
- Console.WriteLine("Total run time in seconds: " + (DateTime.UtcNow - start).TotalSeconds);
- Console.WriteLine("Press enter to exit");
- Console.ReadLine();
- }
- #region Image
- private static void SaveBoardToSimpleImage(string filepath)
- {
- using (Bitmap img = new Bitmap(StageSize, StageSize))
- {
- for (int i = 0; i < img.Width; i++)
- for (int j = 0; j < img.Height; j++)
- img.SetPixel(i, j, Stage[i][j].CurrentInfection == 0 ? Color.FromArgb(255, 255, 255) :
- Color.FromArgb(64, 255, 0));
- img.Save(filepath, ImageFormat.Gif);
- }
- }
- private static MagickImage BoardToImage()
- {
- using (Bitmap img = new Bitmap(StageSize, StageSize))
- {
- for (int i = 0; i < img.Width; i++)
- for (int j = 0; j < img.Height; j++)
- img.SetPixel(i, j, Stage[i][j].CurrentInfection == 0 ? Color.White :
- Color.FromArgb(Stage[i][j].CurrentInfection % 255,
- Math.Abs(Stage[i][j].CurrentInfection - 255) % 255,
- Math.Abs(Stage[i][j].CurrentInfection - 510) % 255));
- return new MagickImage(img);
- }
- }
- private static void ImagesToAnimatedGIF(MagickImage[] images, string filepath)
- {
- using (MagickImageCollection collection = new MagickImageCollection())
- {
- foreach (var image in images)
- {
- collection.Add(image);
- collection.Last().AnimationDelay = 20;
- }
- collection.Write(filepath);
- }
- }
- #endregion Image
- #region Infection
- private static void Period()
- {
- Infect();
- ChooseRandomInfections();
- IncrementDiseaseProgress();
- Cure();
- NumberOfPeriods--;
- }
- private static void Cure()
- {
- Parallel.For(0, Stage.Length, i =>
- {
- for (Int16 j = 0; j < Stage.Length; j++)
- if (Stage[i][j].CurrentInfection != 0 && Stage[i][j].InfectionTime == MaxInfectionTime + 1)
- {
- //Add disease to already infected list
- if (Stage[i][j].PreviousInfections.ContainsKey(Stage[i][j].CurrentInfection))
- Stage[i][j].PreviousInfections[Stage[i][j].CurrentInfection]++;
- else
- Stage[i][j].PreviousInfections.Add(Stage[i][j].CurrentInfection, 1);
- //Cure
- Stage[i][j].InfectionTime = 0;
- Stage[i][j].CurrentInfection = 0;
- }
- });
- }
- private static void IncrementDiseaseProgress()
- {
- Parallel.For(0, Stage.Length, i =>
- {
- for (Int16 j = 0; j < Stage.Length; j++)
- if (Stage[i][j].CurrentInfection != 0)
- Stage[i][j].InfectionTime++;
- });
- }
- private static void RandomlyInfectPeople(Int16 numberOfPeopleToInfect)
- {
- var randomList = new List<int>();
- while (randomList.Count() < numberOfPeopleToInfect * 2)
- {
- randomList.Add(RandomGen2.Next(StageSize));
- randomList = randomList.Distinct().ToList();
- }
- while (randomList.Count() > 0)
- {
- Stage[randomList.Last()][randomList[randomList.Count() - 2]].CurrentInfection = MutationNumber;
- Stage[randomList.Last()][randomList[randomList.Count() - 2]].InfectionTime = 1;
- randomList.RemoveAt(randomList.Count() - 2);
- randomList.RemoveAt(randomList.Count() - 1);
- }
- }
- private static void Infect()
- {
- Parallel.For(0, Stage.Length, i =>
- {
- for (Int16 j = 0; j < Stage.Length; j++)
- InfectAllSpacesAround((short)i, j);
- });
- }
- private static void InfectAllSpacesAround(Int16 x, Int16 y)
- {
- //If not infected or just infected this turn return
- if (Stage[x][y].CurrentInfection == 0 || (Stage[x][y].CurrentInfection != 0 && Stage[x][y].InfectionTime == 0)) return;
- //Infect all four directions(if possible)
- if (x > 0)
- InfectOneSpace(Stage[x][y].CurrentInfection, (short)(x - 1), y);
- if (x < Stage.Length - 1)
- InfectOneSpace(Stage[x][y].CurrentInfection, (short)(x + 1), y);
- if (y > 0)
- InfectOneSpace(Stage[x][y].CurrentInfection, x, (short)(y - 1));
- if (y < Stage.Length - 1)
- InfectOneSpace(Stage[x][y].CurrentInfection, x, (short)(y + 1));
- }
- private static void InfectOneSpace(Int16 currentInfection, Int16 x, Int16 y)
- {
- //If the person is infected, or If they've already been infected "MaxInfectionTime" then don't infect
- if (Stage[x][y].CurrentInfection != 0 || (Stage[x][y].PreviousInfections.ContainsKey(currentInfection) &&
- Stage[x][y].PreviousInfections[currentInfection] >= MaxInfectionTime)) return;
- //If random is larger than change of transmission don't transmite disease
- if (RandomGen2.Next(100) + 1 > ProbabilityOfTransmission * 100) return;
- //Possible mutate
- if (MutationNumber <= MaxNumberOfMutations && RandomGen2.Next(100) + 1 <= ChanceOfMutation * 100)
- lock (Stage[x][y])
- {
- MutationNumber++;
- Stage[x][y].PossibleNewInfections.Add(MutationNumber);
- }
- //Regular infection
- else
- lock (Stage[x][y])
- Stage[x][y].PossibleNewInfections.Add(currentInfection);
- }
- private static void ChooseRandomInfections()
- {
- Parallel.For(0, Stage.Length, i =>
- {
- for (Int16 j = 0; j < Stage.Length; j++)
- {
- if (Stage[i][j].CurrentInfection != 0 || !Stage[i][j].PossibleNewInfections.Any()) continue;
- Stage[i][j].CurrentInfection = Stage[i][j].PossibleNewInfections[RandomGen2.Next(Stage[i][j].PossibleNewInfections.Count)];
- Stage[i][j].PossibleNewInfections.Clear();
- Stage[i][j].InfectionTime = 0;
- }
- }
- );
- }
- #endregion Infection
- }
- //Fancy Schmancy new random number generator for threaded stuff, fun times
- //http://blogs.msdn.com/b/pfxteam/archive/2009/02/19/9434171.aspx
- public static class RandomGen2
- {
- private static Random _global = new Random();
- [ThreadStatic]
- private static Random _local;
- public static int Next()
- {
- Random inst = _local;
- if (inst == null)
- {
- int seed;
- lock (_global) seed = _global.Next();
- _local = inst = new Random(seed);
- }
- return inst.Next();
- }
- public static int Next(int input)
- {
- Random inst = _local;
- if (inst == null)
- {
- int seed;
- lock (_global) seed = _global.Next();
- _local = inst = new Random(seed);
- }
- return inst.Next(input);
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement