using System;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
using Pfz.Drawing;
namespace SimpleLifeSimulation
{
public partial class FormShow : Form
{
public new const int Width = 800;
public new const int Height = 600;
public static FormShow Value;
private Bitmap fSystemBitmap;
internal static ManagedBitmap<Life> PixelMatrix;
internal static Life[] List;
internal static int ActiveCount;
internal static Random fRandom = new Random();
public FormShow()
{
GC.KeepAlive(FormParameters.Value);
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.Idle;
InitializeComponent();
fSystemBitmap = new Bitmap(Width, Height, PixelFormat.Format24bppRgb);
PixelMatrix = new ManagedBitmap<Life>(Width, Height);
List = new Life[Width * Height];
i_Initialize();
p_Render();
}
internal void i_Initialize()
{
var pixelArray = PixelMatrix.PixelArray;
int length = pixelArray.Length;
for(int i=0; i<length; i++)
pixelArray[i] = null;
var formParameters = FormParameters.Value;
int minDots = (int)formParameters.numMinimumInitialDots.Value;
int additionalDots = (int)formParameters.numAdditionalInitialDots.Value;
ActiveCount = minDots + fRandom.Next(additionalDots);
int minTraits = (int)formParameters.numMinimumInitialTraits.Value;
int maxTraits = (int)formParameters.numMaximumInitialTraits.Value;
if (maxTraits < minTraits)
maxTraits = minTraits;
int diff = maxTraits - minTraits;
for(int i=0; i<ActiveCount; i++)
{
Life life = new Life();
life.Strength = minTraits;
life.Speed = minTraits;
life.Resistence = minTraits;
if (diff > 0)
{
life.Strength += fRandom.Next(diff);
life.Speed += fRandom.Next(diff);
life.Resistence += fRandom.Next(diff);
}
life.Health = life.Resistence;
int x;
int y;
do
{
x = fRandom.Next(Width);
y = fRandom.Next(Height);
} while(PixelMatrix[x, y] != null);
life.X = x;
life.Y = y;
List[i] = life;
PixelMatrix[x, y] = life;
}
}
private void p_Render()
{
PixelMatrix.CopyToRgb24
(
fSystemBitmap,
(life) =>
{
if (life == null)
return new Rgb24();
return new Rgb24((byte)life.Strength, (byte)life.Speed, (byte)life.Resistence);
}
);
}
protected override void OnPaintBackground(PaintEventArgs e)
{
// do nothing, ignore call to base.
}
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.DrawImage(fSystemBitmap, ClientRectangle);
}
private void p_Move(Life life)
{
int neededAge = 0;
if (fMustAgeToReproduce)
neededAge = ((life.Strength + life.Speed + life.Resistence) / 50) + 5;
if (life.Age < neededAge)
life.Age++;
int distance = 1;
int x;
int y;
if (!fImageCorrosion)
distance = (life.Speed / 30) + 1;
x = Math.Max(0, Math.Min(Width-1, life.X + fRandom.Next(distance * 2 + 1) - distance));
if (fImageCorrosion)
y = Math.Max(0, Math.Min(Height-1, life.Y + fRandom.Next(5)));
else
y = Math.Max(0, Math.Min(Height-1, life.Y + fRandom.Next(distance * 2 + 1) - distance));
if (x == life.X && y == life.Y)
return;
Life otherLife = PixelMatrix[x, y];
if (otherLife == null)
{
if (life.Age<neededAge)
return;
if (ActiveCount >= fMaxCount)
{
if (!fMove)
return;
PixelMatrix[life.X, life.Y] = null;
PixelMatrix[x, y] = life;
life.X = x;
life.Y = y;
}
else
{
otherLife = new Life();
List[ActiveCount] = otherLife;
ActiveCount++;
p_Reproduce(life, otherLife);
otherLife.X = x;
otherLife.Y = y;
PixelMatrix[x, y] = otherLife;
}
return;
}
if (fImageCorrosion)
return;
// we can't attack our similars.
int difference = life.CompareTo(otherLife);
if (difference < fAttackDifference)
return;
int attackStrength = life.Strength + fRandom.Next(life.Strength)/2 - otherLife.Resistence;
if (attackStrength <= 0)
return;
otherLife.Health -= attackStrength;
if (otherLife.Health >= 0)
return;
if (fEatEnemy)
{
life.Health += attackStrength;
if (otherLife.Strength > life.Strength)
life.Strength = otherLife.Strength;
if (otherLife.Speed > life.Speed)
life.Speed = otherLife.Speed;
if (otherLife.Resistence > life.Resistence)
life.Resistence = otherLife.Resistence;
}
if (life.Age >= neededAge)
{
// So, we killed our victim. We must reproduce now.
p_Reproduce(life, otherLife);
}
}
private void p_Reproduce(Life life, Life otherLife)
{
if (life.Age > 5)
life.Age -= 5;
else
life.Age = 0;
otherLife.Age = 0;
otherLife.Strength = Math.Max(0, Math.Min(255, life.Strength + fRandom.Next(fTendancyRandom) - fDecayTendancy));
otherLife.Speed = Math.Max(0, Math.Min(255, life.Speed + fRandom.Next(fTendancyRandom) - fDecayTendancy));
otherLife.Resistence = Math.Max(0, Math.Min(255, life.Resistence + fRandom.Next(fTendancyRandom) - fDecayTendancy));
if (fImageCorrosion)
otherLife.Health = otherLife.Strength + otherLife.Speed + otherLife.Resistence;
else
otherLife.Health = otherLife.Resistence;
}
private int fMaxCount;
private int fAttackDifference;
private int fEvolveTendancy;
private int fDecayTendancy;
private int fTendancyRandom;
private int fAging;
private bool fEatEnemy;
private bool fMove;
private bool fImageCorrosion;
private bool fMustAgeToReproduce;
private void timer1_Tick(object sender, EventArgs e)
{
var formParameters = FormParameters.Value;
fMaxCount = (int)formParameters.numMaximumLives.Value;
fAttackDifference = (int)formParameters.numAttackDifference.Value;
fEvolveTendancy = (int)formParameters.numTendancyToEvolve.Value;
fDecayTendancy = (int)formParameters.numTendancyToDecay.Value;
fTendancyRandom = fEvolveTendancy + fDecayTendancy + 1;
fAging = (int)formParameters.numAging.Value;
fEatEnemy = formParameters.checkEatEnemy.Checked;
fMove = formParameters.checkMove.Checked;
fImageCorrosion = formParameters.checkImageCorrosion.Checked;
fMustAgeToReproduce = formParameters.checkMustAgeToReproduce.Checked;
for(int i=ActiveCount-1; i>=0; i--)
{
Life life = List[i];
p_Move(life);
}
for(int i=ActiveCount-1; i>=0; i--)
{
Life life = List[i];
if (!fImageCorrosion || life.Y > 0)
life.Health -= fRandom.Next(fAging+1) * (255-fRandom.Next(life.Resistence)) / 255;
}
p_RemoveSome();
p_Render();
Invalidate();
}
private bool fIsDown;
private int fX;
private int fY;
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
fIsDown = true;
fX = e.X;
fY = e.Y;
if (!timer1.Enabled)
{
p_RemoveSome();
p_Render();
Invalidate();
}
}
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (fIsDown)
{
fX = e.X;
fY = e.Y;
if (!timer1.Enabled)
{
p_RemoveSome();
p_Render();
Invalidate();
}
}
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
fIsDown = false;
}
private void p_RemoveSome()
{
for (int i=0; i<ActiveCount; i++)
{
Life life = List[i];
bool mustDie = life.Health < 0;
if (!mustDie && fIsDown)
{
int x = life.X - fX;
int y = life.Y - fY;
double distance = Math.Sqrt(x*x+y*y);
mustDie = distance < 50;
}
if (mustDie)
{
List[i] = null;
PixelMatrix[life.X, life.Y] = null;
}
}
int diff = 0;
for (int i=0; i<ActiveCount; i++)
{
Life nextItem = List[i];
if (nextItem == null)
diff++;
else
List[i-diff] = List[i];
}
ActiveCount -= diff;
}
private void Form1_Load(object sender, EventArgs e)
{
FormParameters.Value.Visible = true;
ClientSize = new Size(Width, Height);
}
private void loadImageToolStripMenuItem_Click(object sender, EventArgs e)
{
bool oldEnabled = timer1.Enabled;
timer1.Enabled = false;
try
{
if (openFileDialog.ShowDialog() != DialogResult.OK)
return;
Bitmap loadedBitmap = null;
try
{
loadedBitmap = (Bitmap)Image.FromFile(openFileDialog.FileName);
if (loadedBitmap.PixelFormat == PixelFormat.Format24bppRgb && loadedBitmap.Width == fSystemBitmap.Width && loadedBitmap.Height == fSystemBitmap.Height)
{
Bitmap aux = loadedBitmap;
loadedBitmap = fSystemBitmap;
fSystemBitmap = aux;
}
else
{
using(var graphics = Graphics.FromImage(fSystemBitmap))
{
graphics.Clear(Color.Black);
graphics.DrawImage(loadedBitmap, 0, 0, loadedBitmap.Width, loadedBitmap.Height);
}
}
}
catch(Exception exception)
{
MessageBox.Show(exception.Message, exception.GetType().FullName);
return;
}
finally
{
if (loadedBitmap != null)
loadedBitmap.Dispose();
}
fImageCorrosion = FormParameters.Value.checkImageCorrosion.Checked;
ActiveCount = 0;
PixelMatrix.CopyFromRgb24
(
fSystemBitmap,
(point, rgb) =>
{
if (rgb.Red == 0 && rgb.Green == 0 && rgb.Blue == 0)
return null;
Life life = new Life();
List[ActiveCount] = life;
ActiveCount++;
life.Strength = rgb.Red;
life.Speed = rgb.Green;
life.Resistence = rgb.Blue;
if (fImageCorrosion)
life.Health = rgb.Red+rgb.Green+rgb.Blue;
else
life.Health = rgb.Blue;
life.X = point.X;
life.Y = point.Y;
return life;
}
);
}
finally
{
if (oldEnabled)
timer1.Enabled = true;
else
Invalidate();
}
}
private void saveImageToolStripMenuItem_Click(object sender, EventArgs e)
{
bool oldEnabled = timer1.Enabled;
timer1.Enabled = false;
try
{
if (saveFileDialog.ShowDialog() != DialogResult.OK)
return;
fSystemBitmap.Save(saveFileDialog.FileName, ImageFormat.Jpeg);
}
catch(Exception exception)
{
MessageBox.Show(exception.Message, exception.GetType().FullName);
}
finally
{
timer1.Enabled = oldEnabled;
}
}
}
}