Click here to Skip to main content
15,896,111 members
Articles / Programming Languages / C#

Revisit the Game of Life while Learning about Extension Methods in C#

Rate me:
Please Sign up or sign in to vote.
4.65/5 (8 votes)
24 Aug 2008CPOL11 min read 55.7K   594   40  
A fun variation of the Game of Life re-factored using extension methods
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using LifeSimulation.Extensions;

namespace LifeSimulation
{
    public partial class MainForm : Form
    {
        #region Declared variables
        private int zoomFactor = 5;
        private AppState appState = null;
        private bool drawing = false;
        private Point startPoint;
        private SortedDictionary<string, string> favourites = null;
        private int cycleModeCountDown = 0;
        #endregion

        public MainForm()
        {
            InitializeComponent();
            favourites = new SortedDictionary<string, string>();
            if (File.Exists("Favourites.txt"))
            {
                string[] lines = File.ReadAllLines("Favourites.txt");
                foreach (string line in lines)
                {
                    if (!favourites.ContainsKey(line))
                        favourites.Add(line, null);
                }
            }

            InitModel(null);

            PaintFavourites();
            PaintZoomChoices();
        }

        private void pictureBox1_Paint(object sender, PaintEventArgs e)
        {
            for (int i = 0; i < appState.World.Space.GetLength(0); i++)
            {
                for (int j = 0; j < appState.World.Space.GetLength(1); j++)
                {
                    int v = appState.World.Space[i, j];
                    if (v > 0)
                    {
                        v = v * 255 / appState.LifeModel.MaximumAge;
                        if (v > 255 || v < 0) v = 255;
                        int numNeighbours = appState.World.Neighbours[i, j];
                        int r = numNeighbours & 1;
                        int g = numNeighbours & 2;
                        int b = numNeighbours & 4;
                        if (r > 0) r = 255;
                        if (g > 0) g = 255;
                        if (b > 0) b = 255;
                        e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(v, r, g, b)), i * appState.ZoomFactor, j * appState.ZoomFactor, appState.ZoomFactor, appState.ZoomFactor);
                    }
                }
            }
        }


        private void mainForm_Resize(object sender, EventArgs e)
        {
            if (appState == null)
                InitModel(null);
            else
                InitModel(appState.LifeModel.Serialize());
        }

        private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
        {
            drawing = true;
            startPoint = new Point(e.X / appState.ZoomFactor, e.Y / appState.ZoomFactor);
        }

        private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            if (drawing)
            {
                int mi = e.X / appState.ZoomFactor + 1;
                int mj = e.Y / appState.ZoomFactor + 1;
                if (mi > appState.World.Space.GetLength(0)) mi = appState.World.Space.GetLength(0);
                if (mj > appState.World.Space.GetLength(1)) mj = appState.World.Space.GetLength(1);

                for (int i = startPoint.X; i < mi; i++)
                {
                    for (int j = startPoint.Y; j < mj; j++)
                    {
                        appState.World.Space[i, j] = appState.LifeModel.MaximumAge;
                    }
                }
            }
        }

        private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
        {
            drawing = false;

            //If mouse was not dragged, draw a blob
            Point endPoint = new Point(e.X / appState.ZoomFactor, e.Y / appState.ZoomFactor);
            if (endPoint.X == startPoint.X && endPoint.Y == startPoint.Y)
                appState.SpawnBlob(e.X / appState.ZoomFactor, e.Y / appState.ZoomFactor, 5);
        }


        #region Timer events

        private void paintTimer_Tick(object sender, EventArgs e)
        {
            if (!drawing) appState.LifeModel.Process(appState.World);
            pictureBox1.Invalidate();
        }

        private void statusStripTimer_Tick(object sender, EventArgs e)
        {
            toolStripStatusLabel4.Text = appState.LifeModel.Serialize();
        }

        private void demoModeTimer_Tick(object sender, EventArgs e)
        {
            if (!drawing)
            {
                if (!appState.World.IsAlive())
                    cycleModeCountDown = 0; //Abort

                if (cycleModeCountDown == 0)
                {
                    appState.World.Clear();
                    appState.LifeModel.Randomize();
                    PaintFavourites();
                    appState.Spawn(spawnIsRandomToolStripMenuItem.Checked);
                    cycleModeCountDown = 30; //seconds
                }
                else
                    cycleModeCountDown--;

                newModelToolStripStatusLabel.Text = string.Format("New ({0})", cycleModeCountDown);
            }
        }

        #endregion



        #region User interaction events

        private void demoModeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            demoModeToolStripMenuItem.Checked = !demoModeToolStripMenuItem.Checked;
            demoModeTimer.Enabled = demoModeToolStripMenuItem.Checked;
        }

        private void spawnIsRandomToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //Spawn type toggle
            spawnIsRandomToolStripMenuItem.Checked = !spawnIsRandomToolStripMenuItem.Checked;
        }

        void favouriteItem_Click(object sender, EventArgs e)
        {
            //When user selects favourite from drop down
            ToolStripMenuItem item = sender as ToolStripMenuItem;
            if (item != null)
            {
                appState.LifeModel.Deserialize(item.Text);
                PaintFavourites();
            }
        }

        void zoomItem_Click(object sender, EventArgs e)
        {
            //When user selects a zoom factor
            ToolStripMenuItem item = sender as ToolStripMenuItem;
            if (item != null)
            {
                zoomFactor = int.Parse(item.Text);
                InitModel(appState.LifeModel.Serialize());
                PaintZoomChoices();
            }
        }

        private void newModelToolStripStatusLabel_Click(object sender, EventArgs e)
        {
            InitModel(null);
        }

        private void spawnToolStripStatusLabel_Click(object sender, EventArgs e)
        {
            //Spawn request
            if (!drawing)
            {
                appState.Spawn(spawnIsRandomToolStripMenuItem.Checked);
                //In case auto mode is on
                cycleModeCountDown = 30; //seconds
            }
        }

        private void clearToolStripStatusLabel_Click(object sender, EventArgs e)
        {
            appState.World.Clear();
        }

        private void deleteToolStripStatusLabel_Click(object sender, EventArgs e)
        {
            //Delete favourite
            string key = appState.LifeModel.Serialize();
            if (favourites.ContainsKey(key))
            {
                addToolStripStatusLabel.Enabled = true;
                favourites.Remove(key);
                SaveFavourites();
                PaintFavourites();
            }
        }

        private void addToolStripStatusLabel_Click(object sender, EventArgs e)
        {
            //Add to favourite
            string key = appState.LifeModel.Serialize();
            if (!favourites.ContainsKey(key))
            {
                addToolStripStatusLabel.Enabled = false;
                favourites.Add(key, null);
                SaveFavourites();
                PaintFavourites();
            }
        }

        private void editToolStripStatusLabel_Click(object sender, EventArgs e)
        {
            drawing = true;
            EditForm frm = new EditForm();
            appState.LifeModel.Deserialize(frm.EditModel(appState.LifeModel.Serialize()));
            PaintFavourites();
            drawing = false;
        }

        #endregion

        #region Private methods and properties

        private void PaintFavourites()
        {
            addToolStripStatusLabel.Enabled = true;
            deleteToolStripStatusLabel.Enabled = false;
            string currentLifeModel = appState.LifeModel.Serialize();
            toolStripSplitButton1.DropDownItems.Clear();
            foreach (string line in favourites.Keys)
            {
                ToolStripMenuItem item = new ToolStripMenuItem(line);
                item.Click += new EventHandler(favouriteItem_Click);
                if (line == currentLifeModel)
                {
                    item.Checked = true;
                    addToolStripStatusLabel.Enabled = false;
                    deleteToolStripStatusLabel.Enabled = true;
                }
                toolStripSplitButton1.DropDownItems.Add(item);
            }
        }

        private void SaveFavourites()
        {
            string[] keys = (string[])Array.CreateInstance(typeof(string), favourites.Count);
            favourites.Keys.CopyTo(keys, 0);
            File.WriteAllLines("Favourites.txt", keys);
        }

        private void PaintZoomChoices()
        {
            zoomToolStripMenuItem.DropDownItems.Clear();
            for (int i = 1; i < 10; i++)
            {
                ToolStripMenuItem item = new ToolStripMenuItem(i.ToString());
                item.Click += new EventHandler(zoomItem_Click);
                if (i == zoomFactor) item.Checked = true;
                zoomToolStripMenuItem.DropDownItems.Add(item);
            }
        }

        private void InitModel(string lifeModelDna)
        {
            appState = new AppState(pictureBox1.Bounds, zoomFactor, lifeModelDna);
        }

        #endregion

 








    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
Australia Australia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions