Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > .NET для новичков > Игра "Жизнь"


Автор: SmirnovKemerovo 13.8.2009, 09:09
Здравствуйте!
Пробую начать программировать на C#, придумал для себя несложную задачу - написать код известной игры "Жизнь".
Правила игры можно посмотреть здесь: http://ru.wikipedia.org/wiki/Жизнь_(игра)
Как начинающий программист очень хотел бы выслушать замечания профессионалов относительно своего кода.
Игровое поле представлено массивом контролов Button, живая особь - кнопка белого цвета, мертвая - черного.
На форме так же присутствуют две кнопки, "GO" - запускает игру, "Clear" очищает игровое поле.
Код

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace Life
{
    
    public partial class Form1 : Form
    {
        private bool stopflag = false; //переключатель конца игрового процесса
        private bool[,] mass = new bool[50, 50]; //массив значений мертвый-живой для ячеек игрового поля
        private bool[,] tempmass = new bool[50, 50]; // Массив временных значений
        private Button[,] massbut = new Button[50, 50]; // Массив кнопок-ячеек игрового поля
        private int generation = 0; //Счетчик поколений
        public Form1()
        {   
            InitializeComponent();
           //создаем игровое поле

            for (int i = 0; i < 50; i++)
            {
                for (int j = 0; j < 50; j++)
                {                  
                    massbut[i, j] = new Button();
                    massbut[i, j].Size = new Size(10, 10);
                    massbut[i, j].Location = new Point(i * 10 + i * 3 + 30, j * 10 + j * 3 + 30);
                    massbut[i, j].Click += new System.EventHandler(this.massbutClick);
                    massbut[i, j].Tag = new Coords(i, j); // .Tag для привязки кнопок-ячеек к массиву значений мертвый-живой  
                    massbut[i, j].FlatStyle = FlatStyle.Flat;
                    this.Controls.Add(massbut[i, j]);

                }
            }
            
            NewLife();
        }
       
        //Нажатием на кнопки-ячейки задаем первоначальное расположение особей
        private void massbutClick(object sender, EventArgs e)
        {
            Button btn = (Button)sender;
            Coords co=(Coords)btn.Tag ;
            btn.BackColor=Color.White;
            mass[co.i, co.j] = true;
        }
       
         //Нажатие кнопки GO запускаем игровой процесс в отдельном потоке
        private void butnGoClick(object sender, EventArgs e)
        {
            Thread LifeThread = new Thread(GoLife);
            LifeThread.Start();
        }
        //нажатием кнопки Clear устанавливаем переключатель конца игрового процесса
        private void butnClearClick(object sender, EventArgs e)
        {
            stopflag = true;
        }

        //Начало новой игры
        private void NewLife()
        {
            for (int i = 0; i < 50; i++)
            {
                for (int j = 0; j < 50; j++)
                {
                    mass[i, j] = false;
                    tempmass[i, j] = false;
                    massbut[i, j].BackColor = Color.Black;
                }
            }
            generation = 0;
            label1.Text = string.Empty;
            this.Refresh();
        }

        //метод выполняется в отдельном потоке, вызываем метод генерации нового поколения 
        //и проверяем состояние переключателя конца процесса
        private void GoLife()
        {
        for (int i = 0; i < 100; i++)
            {
                NextGeneration();
                generation++;
                label1.Text = generation.ToString();
                this.Refresh();
                if (stopflag) { i = 100; }
             }
        if (stopflag) { stopflag = false;  NewLife(); }
        }

        //Генерирует новое поколение
        public void NextGeneration()
        {
            this.SuspendLayout();
            
            for (int i = 0; i < 50; i++)
            {
                for (int j = 0; j < 50; j++)
                {
                    if ((sosediCount(i, j) == 3) && (!mass[i, j])) { tempmass[i, j] = true; }
                    if (((sosediCount(i, j) == 3) || (sosediCount(i, j) == 2)) && (mass[i, j])) { tempmass[i, j] = true; }
                    if ((sosediCount(i, j) < 2) && (mass[i, j])) { tempmass[i, j] = false ;  }
                    if ((sosediCount(i, j) > 3) && (mass[i, j])) { tempmass[i, j] = false; }
                }
            }
            for (int i = 0; i < 50; i++)
            {
                for (int j = 0; j < 50; j++)
                {
                    mass[i, j] = tempmass[i, j];
                    if (mass[i, j]) { massbut[i, j].BackColor = Color.White; } else {massbut[i, j].BackColor = Color.Black ; }
                }
            }
            this.ResumeLayout();
        
        }

        //функция расчета количества соседей у особи
        private int sosediCount(int a, int b)
        {
           int sosedi = 0;
            if (a > 0 && mass[a - 1, b]) {sosedi++;}
            if (a > 0 && b < 49 && mass[a - 1, b + 1]) { sosedi++; }
            if (b < 49 && mass[a, b + 1]) { sosedi++; };
            if (a < 49 && b < 49 && mass[a + 1, b + 1]) { sosedi++; }
            if (a < 49 && mass[a + 1, b]) { sosedi++; }
            if (a < 49 && b > 0 && mass[a + 1, b - 1]) { sosedi++; }
            if (b > 0 && mass[a, b - 1]) { sosedi++; }
            if (a > 0 && b > 0 && mass[a - 1, b - 1]) { sosedi++; }
            return sosedi;
        }
    }

    //класс объектов, хранящих индексы массива для Button.Tag
    public class Coords
    {
        private int _i;
        private int _j;
        public int i
        {
            get {return _i;}
            set { _i = i; }
        }
        public int j
        {
            get {return _j;}
            set { _j = j; }
        }
        public Coords(int a, int b)
        {
            _i = a; _j = b;
        }
 
    }

}


Жду комментариев.

Автор: ДобренькийПапаша 13.8.2009, 10:29
Сразу навскидку можно сказать, что именование не очень удачное. Именование функций и переменных не везде идёт в соответствии со спецификацией языка. 
http://msdn.microsoft.com/ru-ru/library/ms229002.aspx

Добавлено через 3 минуты и 35 секунд
А, ну вот что ещё. У вас везде используются магические числа. Заменяйте их на переменные с нормальными именами, как то, если у вас размер массива не меняется. Объявите его границы как константную переменную. Ну и так далее. По поводу хорошего стиля можно почитать MacConell-"Code Complete" (в русском издании "Совершенный код").

Автор: SmirnovKemerovo 13.8.2009, 13:42
ОК, работа над ошибками

Код

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace Life
{
    
    public partial class Form1 : Form
    {
        private bool stopFlag = false; //переключатель конца игрового процесса
        private bool[,] massBool = new bool[50, 50]; //массив значений мертвый-живой для ячеек игрового поля
        private bool[,] massBoolTemp = new bool[50, 50]; // Массив временных значений
        private Button[,] massButton = new Button[50, 50]; // Массив кнопок-ячеек игрового поля
        private int generation = 0; //Счетчик поколений
        
        const int buttonLength = 10;
        Size buttonSize = new Size(buttonLength , buttonLength );
        const int margin = 30;
        const int maxValue = 50;
        const int breakPointGeneration = 100;

        public Form1()
        {   
            InitializeComponent();
           //создаем игровое поле

            for (int i = 0; i < maxValue ; i++)
            {
                for (int j = 0; j < maxValue ; j++)
                {                  
                    massButton[i, j] = new Button();
                    massButton[i, j].Size = buttonSize;
                    massButton[i, j].Location = new Point(i * buttonLength  + i * 2 + margin , j * buttonLength  + j * 2 + margin );
                    massButton[i, j].Click += new System.EventHandler(this.MassButtonClick);
                    massButton[i, j].Tag = new Coords(i, j); // .Tag для привязки кнопок-ячеек к массиву значений мертвый-живой  
                    massButton[i, j].FlatStyle = FlatStyle.Flat;
                    this.Controls.Add(massButton[i, j]);

                }
            }
            
            NewLife();
        }
       
        //Нажатием на кнопки-ячейки задаем первоначальное расположение особей
        private void MassButtonClick(object sender, EventArgs e)
        {
            Button btn = (Button)sender;
            Coords co=(Coords)btn.Tag ;
            btn.BackColor=Color.White;
            massBool[co.I, co.J] = true;
        }
       
         //Нажатие кнопки GO запускаем игровой процесс в отдельном потоке
        private void GoButtonClick(object sender, EventArgs e)
        {
            Thread LifeThread = new Thread(GoLife);
            LifeThread.Start();
        }
        //нажатием кнопки Clear устанавливаем переключатель конца игрового процесса
        private void ClearButtonClick(object sender, EventArgs e)
        {
            stopFlag = true;
        }

        //Начало новой игры
        private void NewLife()
        {
            for (int i = 0; i < maxValue ; i++)
            {
                for (int j = 0; j < maxValue; j++)
                {
                    massBool[i, j] = false;
                    massBoolTemp[i, j] = false;
                    massButton[i, j].BackColor = Color.Black;
                }
            }
            generation = 0;
            label1.Text = string.Empty;
            this.Refresh();
        }

        //метод выполняется в отдельном потоке, вызываем метод генерации нового поколения 
        //и проверяем состояние переключателя конца процесса
        private void GoLife()
        {
        for (int i = 0; i < breakPointGeneration ; i++)
            {
                NextGeneration();
                generation++;
                label1.Text = generation.ToString();
                this.Refresh();
                if (stopFlag) { break; }
             }
        if (stopFlag) { stopFlag = false;  NewLife(); }
        }

        //Генерирует новое поколение
        public void NextGeneration()
        {
            this.SuspendLayout();
            
            for (int i = 0; i < maxValue ; i++)
            {
                for (int j = 0; j < maxValue; j++)
                {
                    if ((SosediCount(i, j) == 3) && (!massBool[i, j])) { massBoolTemp[i, j] = true; }
                    if (((SosediCount(i, j) == 3) || (SosediCount(i, j) == 2)) && (massBool[i, j])) { massBoolTemp[i, j] = true; }
                    if ((SosediCount(i, j) < 2) && (massBool[i, j])) { massBoolTemp[i, j] = false ;  }
                    if ((SosediCount(i, j) > 3) && (massBool[i, j])) { massBoolTemp[i, j] = false; }
                }
            }
            for (int i = 0; i < maxValue ; i++)
            {
                for (int j = 0; j < maxValue; j++)
                {
                    massBool[i, j] = massBoolTemp[i, j];
                    if (massBool[i, j]) { massButton[i, j].BackColor = Color.White; } else {massButton[i, j].BackColor = Color.Black ; }
                }
            }
            this.ResumeLayout();
        
        }

        //функция расчета количества соседей у особи
        private int SosediCount(int a, int b)
        {
           int sosedi = 0;
           int limit = maxValue - 1;
 
            if (a > 0 && massBool[a - 1, b]) {sosedi++;}
            if (a > 0 && b < limit && massBool[a - 1, b + 1]) { sosedi++; }
            if (b < maxValue-1 && massBool[a, b + 1]) { sosedi++; };
            if (a < limit && b < limit && massBool[a + 1, b + 1]) { sosedi++; }
            if (a < limit && massBool[a + 1, b]) { sosedi++; }
            if (a < limit && b > 0 && massBool[a + 1, b - 1]) { sosedi++; }
            if (b > 0 && massBool[a, b - 1]) { sosedi++; }
            if (a > 0 && b > 0 && massBool[a - 1, b - 1]) { sosedi++; }
            return sosedi;
        }
    }

    //класс объектов, хранящих индексы массива для Button.Tag
    public class Coords
    {
        private int i;
        private int j;
        public int I
        {
            get {return i;}
            set { i = I; }
        }
        public int J
        {
            get {return j;}
            set { j = J; }
        }
        public Coords(int a, int b)
        {
            i = a; j = b;
        }
 
    }

}


Так лучше?

Автор: ДобренькийПапаша 13.8.2009, 14:29
Лучше, вы в самом начале задаёте три массива 50 на 50, объявите константу равную 50, и создавайте используя константу. А то вдруг спустя сто лет вы захотите сделать игровое поле больше, тогда вам придёца править возможно в большом количестве мест одно и тоже...
(Я правда в логику приложения не вдавался)

Вобщем в любом случае, вышеуказанную книгу почитайте...

Автор: ZmeyNet 14.8.2009, 13:51
SmirnovKemerovo,

http://www.c-gator.ru/articles/csharp-xml-comment-faq/

http://msdn.microsoft.com/magazine/cc302121.aspx
Анализатор C# раскрывает эти теги XML для предоставления дополнительной информации и экспортирует их во внешний документ для последующей обработки. В данной статье показаны методы использования комментариев XML проводится обсуждение необходимых тегов. Автор демонстрирует метод настройки проекта для экспорта комментариев XML в подходящую документацию для их использования другими разработчиками. Он также объясняет, как использовать комментарии для генерации файлов справки.

Автор: dance 26.5.2010, 16:47
В якому компіляторі Ви її компілювали??? Як переробити на с++???

Автор: jonie 27.5.2010, 21:28
dance, это язык C#, не С++. Тут есть на С++ http://panda.nowere.net/?page_id=75

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)