Search code examples
c#wpfconways-game-of-life

Conways game of life trying to get the code behind working


i have four classes

    public class BoolToCol : IValueConverter
    {

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            bool v = (bool)value;
            if (v == true)
            {
                return new SolidColorBrush(Colors.Red);
            }
            else
            {
                return new SolidColorBrush(Colors.Blue);
            }

        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }



    public class Cell : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public bool _ItsAlive;
        public int _CellIndex;
        public bool ItsAlive { 
            get {return _ItsAlive;} 
            set{
                _ItsAlive = value;
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("ItsAlive"));
                }
            } 
        }
        public int CellIndex
        {
            get { return _CellIndex; }
            set
            {
                _CellIndex = value;
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("CellIndex"));
                }
            }
        }
    }



<Window x:Class="Pucketts_ConWaysGameOfLife.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Game of Life" Height="350" Width="525">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="40*"/>
            <ColumnDefinition Width="58*"/>
        </Grid.ColumnDefinitions>
        <Grid Background="Black"
              Grid.Column="0">

            <Grid.Resources>
                <Style TargetType="Button">
                    <Setter Property="Width"
                            Value="80"/>
                    <Setter Property="Height"
                            Value="20"/>
                    <Setter Property="HorizontalAlignment"
                            Value="Left"/>
                    <Setter Property="VerticalAlignment"
                            Value="Top"/>
                    <Setter Property="BorderThickness"
                            Value="0"/>
                    <Setter Property="Foreground"
                            Value="Red"/>
                    <Setter Property="Background"
                            Value="Black"/>
                    <Setter Property="Grid.Row"
                            Value="3"/>
                </Style>
                <Style TargetType="Slider">
                    <Setter Property="TickFrequency"
                            Value="1"/>
                    <Setter Property="SmallChange"
                            Value="1"/>
                    <Setter Property="IsSnapToTickEnabled"
                            Value="True"/>
                    <Setter Property="LargeChange"
                            Value="10"/>
                    <Setter Property="Minimum"
                            Value="0"/>
                    <Setter Property="Width"
                            Value="80"/>
                </Style>
                <SolidColorBrush x:Key="foregroundBrush"
                                 Color="Red"/>
            </Grid.Resources>

            <Grid.RowDefinitions>
                <RowDefinition Height="30"/>
                <RowDefinition Height="30"/>
                <RowDefinition Height="30"/>
                <RowDefinition Height="30"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="68"/>
                <ColumnDefinition Width="76"/>
                <ColumnDefinition Width="68"/>
            </Grid.ColumnDefinitions>
            <Label Grid.Column="0"
                   Grid.Row="2"
                   Content="GenSlide"
                   Foreground="{StaticResource foregroundBrush}"/>
            <Label Grid.Column="0"
                   Grid.Row="1"
                   Content="Width"
                   Foreground="{StaticResource foregroundBrush}"/>
            <Label Grid.Column="0"
                   Grid.Row="0"
                   Content="Height"
                   Foreground="{StaticResource foregroundBrush}"/>
            <Slider Grid.Column="1"
                    Grid.Row="2"
                    LargeChange="2"
                    x:Name="GenSlide"
                    Maximum="15"/>
            <Slider Grid.Column="1"
                    Grid.Row="1"
                    x:Name="WidthSlide"
                    Maximum="100"/>
            <Slider Grid.Column="1"
                    Grid.Row="0"
                    x:Name="HeightSlide"
                    Maximum="100"/>
            <Button Grid.Column="2"
                    Click="SetGrid"
                    Content="Set Grid"/>
            <Button Grid.Column="0"
                    Click="Random"
                    Content="Random"/>
            <Label HorizontalAlignment="Left"
                   Grid.Column="2"
                   Grid.Row="2"
                   x:Name="GenNum"
                   Content="{Binding ElementName=GenSlide, Path= Value}"
                   Foreground="{StaticResource foregroundBrush}"/>
            <Label HorizontalAlignment="Left"
                   Grid.Column="2"
                   Grid.Row="1"
                   x:Name="WidthNum"
                   Content="{Binding ElementName=WidthSlide, Path= Value}"
                   Foreground="{StaticResource foregroundBrush}"/>
            <Label HorizontalAlignment="Left"
                   Grid.Column="2"
                   Grid.Row="0"
                   x:Name="HeightNum"
                   Content="{Binding ElementName=HeightSlide, Path= Value}"
                   Foreground="{StaticResource foregroundBrush}"/>
            <Button Grid.Column="1"
                    Click="Play"
                    Content="Play"/>

            <Button Grid.Column="1"
                    VerticalAlignment="Bottom"
                    Click="Next"
                    Margin="0,0,0,-10"
                    Content="Next"/>
        </Grid>
        <UniformGrid  x:Name="Board" 
          Grid.Column="1">

        </UniformGrid>
    </Grid>
</Window>



    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        Cell[] CellA;
        int _NumOfColumns;
        int CellIndex;
        public event PropertyChangedEventHandler PropertyChanged;
        public MainWindow()
        {
            this.InitializeComponent();

        }
        public int NumOfColumns
        {
            get { return _NumOfColumns; }
            set
            {
                _NumOfColumns = value;
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("NumOfColumns"));
                }
            }
        }
        private void Initializeboard()
        {
            NumOfColumns = (int) (this.HeightSlide.Value);
            CellA = new Cell[NumOfColumns * (int) (this.WidthSlide.Value)];
            for (int i = 0; i < this.HeightSlide.Value * this.WidthSlide.Value; i++)
            {
                Rectangle rec = new Rectangle();
                rec.Stroke = Brushes.Green;
                rec.MouseLeftButtonDown += new MouseButtonEventHandler(rec_MouseLeftButtonDown);
                this.Board.Children.Add(rec);
                Cell c = new Cell();
                c.CellIndex = i;
                Binding newB = new Binding("ItsAlive");
                newB.Source = c;
                newB.Converter = new BoolToCol();
                rec.SetBinding(Rectangle.FillProperty, newB);
                CellA[i] = c;
            }

        }

        public void rec_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {

            foreach (UIElement item in this.Board.Children)
            {
                if (item.IsMouseOver)
                {
                    Cell c = (item as Rectangle).GetBindingExpression(Rectangle.FillProperty).ResolvedSource as Cell;
                    c.ItsAlive = !c.ItsAlive;
                    //c.CellIndex = this.Board.Children.IndexOf((Rectangle) sender);
                    CellIndex = c.CellIndex;
                    Console.WriteLine(CellIndex + " " + CellA[CellIndex].ItsAlive);
                }
            }
        }
        public List<Cell> CheckNeighbours(Cell c)
        {
            //NumOfColumns

            //c.CellIndex
            // 3 secations the ones above below and next to
            List<Cell> NebourCell = new List<Cell> { };
            NebourCell.Clear();
            for (int i = -1; i < 2; i++)
            {
                try
                {
                    NebourCell.Add(CellA[c.CellIndex - NumOfColumns - i]);


                }
                catch (IndexOutOfRangeException)
                {

                    Console.WriteLine("Ignore");
                }
            }
            for (int i = -1; i < 2; i += 2)
            {
                try
                {
                    NebourCell.Add(CellA[c.CellIndex -i]);

                }
                catch (IndexOutOfRangeException)
                {

                    Console.WriteLine("Ignore for middle index out of bounds");
                }
            }
            for (int i = -1; i < 2; i++)
            {
                try
                {
                    NebourCell.Add(CellA[c.CellIndex + NumOfColumns - i]);

                }
                catch (IndexOutOfRangeException)
                {

                    Console.WriteLine("Ignore");
                }

            }
            return NebourCell;



        }
        private void SetGrid(object sender, RoutedEventArgs e)
        {
            this.Board.Children.Clear();
            this.Initializeboard();
        }

        private void Random(object sender, RoutedEventArgs e)
        {
            Random rand = new Random();
            foreach (UIElement item in this.Board.Children)
            {
                Cell c = (item as Rectangle).GetBindingExpression(Rectangle.FillProperty).ResolvedSource as Cell;
                if (rand.Next(0, 2) == 1)
                {
                    c.ItsAlive = !c.ItsAlive;
                }
            }
        }

        private void Play(object sender, RoutedEventArgs e)
        {
            foreach (UIElement item in this.Board.Children)
            {


            }
        }

        private void Next(object sender, RoutedEventArgs e)
        {
            int Alive = 0;

            foreach (Cell AllCell in CellA)
            {
                List<Cell> NebourCells = CheckNeighbours(CellA[AllCell.CellIndex]);
                foreach ( Cell AllBebourCells in NebourCells)
                {
                    Console.WriteLine(CellA[AllBebourCells.CellIndex].ItsAlive);
                    if (CellA[AllBebourCells.CellIndex].ItsAlive)
                        Alive++;   
                }


                Console.WriteLine(Alive);

                if (Alive < 2 || Alive > 3)
                {
                    Console.WriteLine("It dies");
                    CellA[CellIndex].ItsAlive = false;
                }
                if (Alive == 2 || Alive == 3)
                {
                    Console.WriteLine("Its lives on");
                }
                if (Alive == 3)
                {
                    Console.WriteLine("Its alive");
                    CellA[CellIndex].ItsAlive = true;
                }
                //foreach (Cell item in NebourCell)
                //{
                //    Rectangle ind = this.Board.Children[item.CellIndex] as Rectangle;
                //    ind.Fill = new SolidColorBrush(Colors.LightCyan);
                //}
            }
        }
    }

My problem i believe is in the Main Window cs and when you put three squares in a row and you go to next gen it is suppose to go vertical but mine just deletes the farthest one to the right i have been working on this for a while now i have been doing a lot of Debugging i have also debugged with break points i think it also is in the Next Button event Method but i could not find the problem and was wondering if anyone could assist me.


Solution

  • You have two problems with your Next method that I can see. First, you are not resetting your 'Alive' value between each cell that you process. So if the first cell you process has two alive neighbors, you Alive variable gets set to 2, and then if the next cell also has two alive neighbors, Alive is now set to 4!

    Secondly, you are currently modifying the cells in place. This will lead to incorrect results, as if a certain cell dies, it will no longer be counted as alive for the processing of the cells next to it when it should be. You will need to create a temporary cell array that is a copy of CellA, and use the alive status of the cell in CellA but modify the status in the copy. Then at the end, set CellA to the copy.

    Your new function should flow like this, in pseudocode

    private void Next(object sender, RoutedEventArgs e)
    {
       Cell[] copy = copy of CellA
       Loop over cells in copy
       {
           Alive = number of living neighbors of cell in CellA array
           // apply Life logic here
           copy[cell index].IsAlive = new status based on logic
       }
       CellA = copy
    }