Click here to Skip to main content
15,896,915 members
Articles / Desktop Programming / WPF

Conway's Game of Life - A Rule Framework and Implementation

Rate me:
Please Sign up or sign in to vote.
5.00/5 (11 votes)
15 Apr 2013CPOL5 min read 27.3K   1.4K   36  
A rule engine based approach to add and remove rules to play Conway's Game of Life
using System.Collections.Generic;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using gameOfLife.Framework;
using System.IO;
using System;
using System.Reflection;
using System.Linq;
using System.Windows.Shapes;

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        const int rows = 50;
        const int cols = 50;

        bool running = false;
        int sleeptime = 500;

        IDictionary<Point, Rectangle> rects;
        ITransition[] transition;
        IList<string> knownTransitions;

        delegate void ChangeRectangleColorDelegate(Rectangle b, Brush br);

        public MainWindow()
        {
            InitializeComponent();
            InitializeBoard();
            InitializeTransitionIndexes();
            InitializeTransitions();
        }

        private void OnMouseDown(object o, MouseButtonEventArgs e)
        {
            Rectangle b = o as Rectangle;
            string[] buttonId = b.Name.TrimStart('b').Split('_');

            int x = int.Parse(buttonId[0]);
            int y = int.Parse(buttonId[1]);

            if(b.Fill == Brushes.Black)
            {
                PatternOfCells.Instance.Cells.Remove(new Cell(x, y));
                b.Fill = Brushes.White;
            }
            else
            {
                PatternOfCells.Instance.Cells.Add(new Cell(x, y));
                b.Fill = Brushes.Black;
            }
        }

        private void OnMouseEnter(object o, MouseEventArgs e)
        {
            (o as Rectangle).ToolTip = (o as Rectangle).Name.TrimStart('b').Replace('_', ',');
        }

        private void button_Click(object sender, RoutedEventArgs e)
        {
            running = !running;
            button.Content = running ? "Stop" : "Start";
            if (running)
            {
                new Thread(StartTicking).Start();                
            }
        }

        private void slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            int t = 100;
            try
            {
                t = int.Parse((sender as Slider).Value.ToString("0"));
            }
            catch { }

            sleeptime = t;
        }

        private void StartTicking()
        {
            while (running)
            {
                Thread.Sleep(sleeptime);

                PatternOfCells.Instance.Cells.ToList().ForEach(c =>
                {
                    if (c.X >= 0 && c.Y >= 0)
                        Dispatcher.Invoke((Action)(() => rects[new Point(c.X, c.Y)].Fill = Brushes.White));
                });

                PatternOfCells.Instance.ApplyTransitions(transition);

                PatternOfCells.Instance.Cells.ToList().ForEach(c =>
                {
                    if (c.X >= 0 && c.Y >= 0)
                        Dispatcher.Invoke((Action)(() => rects[new Point(c.X, c.Y)].Fill = Brushes.Black));
                });
            }
        }

        private Rectangle CreateShape(int row, int col)
        {
            var rect = new Rectangle() { Stroke = Brushes.Gray, StrokeThickness = 0.5, Fill = Brushes.White, Name = string.Format("b{0}_{1}", row, col) };
            rect.MouseDown += new MouseButtonEventHandler(OnMouseDown);
            rect.MouseEnter += new MouseEventHandler(OnMouseEnter);
            ug.Children.Add(rect);

            return rect;
        }

        private void InitializeBoard()
        {
            rects = new Dictionary<Point, Rectangle>();

            for (int row = rows - 1; row > -1; row--)
                for (int col = 0; col < cols; col++)
                    rects.Add(new Point(row, col), CreateShape(row, col));
        }

        private void InitializeTransitions()
        {
            IList<ITransition> transitions = new List<ITransition>();

            foreach(string file in Directory.GetFiles(Environment.CurrentDirectory, "*.dll"))
            {
                Assembly a = Assembly.LoadFrom(file);

                foreach (Type t in a.GetTypes().Where(m => m.IsClass && m.GetInterface("ITransition") != null))
                {
                    transitions.Add(Activator.CreateInstance(t) as ITransition);
                }
            }

            transition = new ITransition[knownTransitions.Count];

            for (int i = 0; i < transitions.Count; i++)
            {
                string transitionName = transitions[i].ToString().Split('.')[transitions[i].ToString().Split('.').Length - 1];
                int index = knownTransitions.IndexOf(transitionName);
                if (index >= 0)
                {
                    //index = transition.Length - 1;
                    transition[index] = transitions[i];
                }                
            }
        }

        private void InitializeTransitionIndexes()
        {
            string TransitionIndexInfoPath = System.IO.Path.Combine(Environment.CurrentDirectory, "Transitions.txt");
            if (File.Exists(TransitionIndexInfoPath))
            {
                knownTransitions = File.ReadAllText(TransitionIndexInfoPath).Split(',').ToList<string>();
            }
            else
            {
                knownTransitions = new List<string>() { "Loneliness", "OverCrowding", "NextGeneration", "Spawn" };
            }
        }
    }
}

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
Software Developer
India India
is a poor software developer and thinker. Presently working on a theory of "complementary perception". It's a work in progress.

Comments and Discussions