Игра Сапер (Minesweeper) на C#

Опубликовано Sep 30, 2012 в Игры, ООП, Разбор примеров кода, Рефакторинг и оптимизация, Хорошие проекты студентов | 7 коммент.

, ,

Игра Сапер (Minesweeper) на C#

Предлагается разработать программу, похожую на известную игру Windows под названием Minesweeper. Если вдруг кто-то не знает ее правил – то описание

правил игры Minesweeper можно найти здесь.

Для старта предлагается готовое работающее решение, якобы созданное студентами, как pet-project и предоставленное для оценки и разбора. Позднее оказалось, что этот проект взят из книги C#. Сборник рецептов. Агуров П.В.

  Код можно скачать здесь (первый релиз – структурный подход)

Это код проекта VS-2010  игры “Сапер” на C#

Приведенный код написан с использованием полностью структурного подхода. В программе имеется единственный класс, который за все и отвечает. Идея архитектуры основана на том, что поле игры, как известно, состоит из ячеек. Эти ячейки отличаются друг от друга с точки зрения пользователя конечным набором состояний, которые закодированы целыми числами. Дальше в менеджере игры в цикле по всем ячейкам условными операторами выясняется в каком состоянии находится текущая ячейка, и в зависимости от этого вызывается тот или иной кусок кода для рисования ячейки. Описанный процесс инициируется, когда в результате действий пользователя наступает событие OnPaint для панели, на которой собственно и рисуются клетки.

Игровое поле в процессе игры выглядит, как показано на рисунке.

 

Разумные шаги, если подходить к задаче с целью обучения

  • Для начала можно попробовать реализовать описанную структурную архитектуру, не подглядывая в ответ, то есть в тот код, который дан выше для загрузки. Для того, чтобы полностью понять, как работает прототип, можно добраться до exe-файла в заархивированном проекте и запускать его автономно, используя как спецификацию на разработку.
  • Дальше стоит сравнить свое решение с приведенным, и определить, что где лучше, а что хуже.
  • Теперь стоит попробовать реализовать добавление функциональности, чтобы написанная вами программа, действительно работала бы, как Minesweeper в Windows. То есть, как минимум, добавить  несколько уровней сложности в игру и  Form resizing в ее GUI. Если при этом вам не понадобится добавлять множество условных операторов, разбирающихся с новыми состояниями и размерами клеток, или набирать новые куски кода, чтобы нарисовать мину с другими размерами,  – значит все спроектировано более-менее хорошо (пока).
  • Ну и финальное действие – начать применять ООП, отказаться от состояний ячеек в менеджере игры, а вместо этого ввести класс “клетка”, который сам знает, в каком состоянии находится тот или иной его экземпляр, и этот экземпляр  может сам себя нарисовать, так как нужно по ходу игры.

Чтобы было “как надо” – рефакторинг предыдущей версии.

Недостатки:

  • Состояние клеток описано целочисленными искусственно введенными кодами, которые абсолютно не очевидны и не масштабируемы. Если потерян комментарий, приведенный ниже, то понять логику программы по коду весьма сложно. Код написан, исходя из парадигмы структурного подхода, – все в одном классе, в одном файле. Как следствие – множество if-ов, в которых встречаются различные цифры, о смысле которых нужно гадать.
    private int[,] Pole = new int[MR + 2, MC + 2];       
    // значение элемента массива:       
    // 0..8 - количество мин в соседних клетках       
    // 9 - в клетке мина       
    // 100..109 - клетка открыта       
    // 200..209 - в клетку поставлен флаг
Как исправить. Вводим класс клетка Cell. Его поля описывают, в каком состоянии находится клетка по ходу игры. Объект класса Cell сам знает как себя отобразить (нарисовать)  в зависимости от своего состояния. Убираем массив Pole, вместо него создаем массив из объектов Cell в классе GameManagerForm, который, в свою очередь, отвечает за взаимодействие с пользователем и изменения свойств клеток (объектов типа Cell ) при этом взаимодействии.
  • Не удалось правильно организовать рекурсию в методе, открывающем клетки,  без введения фиктивных клеток. В массиве Pole имеются окаймляющие его по периметру служебные клетки (закодированные “магическим” числом -3), нужные лишь из-за реализации алгоритма.
Как исправить.  Убираем ненужные клетки, изменяем алгоритм в методе OpenСells.
  • Можно совместить инициацию клеток на старте игры с подсчетом количества мин в соседних клетках.
Как исправить.  Делаем это. Кроме того причесываем код по мелочам.

  • Вводим именованные статусы игры вместо циферок.
  • Следим за осмысленностью имен переменных (более-менее).
  • Убираем ширину и высоту ячейки, предполагая, что достаточно одного размера СellSize, так как клетки должны быть квадратными. 

Этот код рекомендуется к использованию для различных обучающих программ. Его ни в коем случае нельзя рассматривать как результат коммерческой деятельности компании FulcrumWeb


Автор публикации: