Динамические эффекты

Предварительная подготовка

Эффекты форматирования

Графические объекты

Движение объектов

Ожившие графики

Другие варианты

Вентильные схемы

Автоматизация тестирования

Автоматизация оценки

Проект "Машина времени"

Игра "Жизнь"

Заполнение аттестатов

На главную

Игра «Жизнь»

Первое приближение

Второе приближение

Третье приближение

 

Начинаем программироватьА чего мы хотим?Займемся интерфейсомСовершенствуем макросы
Вводим переменныеВходим в режимНабираем скоростьЭкспериментируйте

Третье приближение

Начинаем программировать

Мы уже приобрели некоторый опыт создания, редактирования макросов и подключения их к кнопкам для исполнения. Если у вас не вызвали особых затруднений ранее рассмотренные действия, а желание довести начатую работу до совершенства не иссякло, смело бросаемся в пучины программирования в среде VBA.

Перейдем в редактор Visual Basic и в поле проводника проекта двойным щелчком по строке «Лист1(Лист1)» откроем страницу для записи и редактирования программного кода, относящегося к данному рабочему листу. Открыв левый список в верхней части этой страницы, выберем «Worksheet» (рабочий лист), а в правом списке – «SelectionChange» (выбор или изменение). Дополним появившуюся заготовку событийной процедуры, запускающейся при выделении или изменении значения какой-либо ячейки листа, так чтобы она приобрела следующий вид:

Private Sub Worksheet_SelectionChange(ByVal Target As Range)

  r = Selection.Cells.Row

  c = Selection.Cells.Column

  z = r > 4 And r < 45 And c > 2 And c < 43

  If z Then

    If Cells(r, c) = "" Then

       Cells(r, c) = " "

      Else

       Cells(r, c) = ""

    End If

  End If

End Sub

Здесь переменной r присваивается номер строки выделенной ячейки, а переменной с – номер ее столбца. Затем формируем условие попадания в основное поле и его логическое значение присваиваем переменной z. Если ячейка выделена в пределах «арены», то, если до этого там было пусто, в нее заносится пробел, иначе клетка очищается присвоением пустого текста.

Переключившись в окно MS Excel и пощелкав мышкой в пределах основного диапазона, убеждаемся, что процедура заселения первого поколения теперь заметно упростилась. Однако, как это нередко бывает, новые идеи несут с собой не только новые решения, но и новые проблемы. Не обошлось без неприятных сюрпризов и в данном случае. Щелкая по кнопке «Шаг», замечаем, что клетка в верхнем левом углу «арены», вопреки всем правилам игры, «ожила» на втором шаге и, вопреки правилам Конвея, продолжает свое существование в этом статусе в последующих поколениях.

А чего мы хотим?

Не пора ли нам перестать «ходить вокруг да около», а взяться за дело всерьез и создать действительно полноценный продукт? Для начала определимся, а чего бы такого, кроме устранения уже отмеченных недостатков, нам недостает?

Хорошо бы, наряду с пошаговым, иметь и автоматический режим смены поколений, чтобы щелкнул разок – и наблюдай беззаботно, как разворачиваются события на «арене», а в случае чего остановил исторический процесс, вмешался в ситуацию и пускай снова плодится клеточная «жизнь». Если же в каком-то поколении она вырождается, то игра должна заканчиваться.

Неплохо бы иметь возможность регулировать скорость смены поколений, а также знать, в каком поколении возникла та или иная конфигурация с расселением или произведена остановка, каково количество «живых» клеток на том или ином этапе?

Займемся интерфейсом

Сначала спланируем интерфейс. Последовательно выделим и объединим диапазоны: K47:M48, O47:Q48 и S47:T48, отформатировав в виде сплошной тонкой линии их внешние границы.

Рис. 8. Организация интерфейса

В первый диапазон внесем формулу: =СЧЁТЕСЛИ(C5:AP44;" "), которая будет подсчитывать количество «живых» клеток на арене в том или ином поколении. Сразу же в ячейку W47 впишем связанную с этим диапазоном формулу для вывода предупреждающего сообщения: =ЕСЛИ(K47=0;"Жизнь отсутствует";"").

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

Третий диапазон предназначен для отображения скорости смены поколений в секунду. Для регулировки скорости воспользуемся счетчиком, который, по аналогии с кнопками, создадим с помощью панели «Формы» щелчком по соответствующему элементу и протяжкой на рабочем листе при нажатой левой кнопке мыши. Подогнав размеры и, разместив изображение счетчика справа от диапазона S47:T48, вызовем через контекстное меню диалоговое окно «Формат объекта», где на вкладке «Элемент управления» установим:

Текущее значение: 1.

Минимальное значение: 0.

Максимальное значение: 10.

Шаг изменения: 1.

Связь с ячейкой: $S$47.

Отметим флажок «Объемное затемнение».

Рис. 9. Настройка счетчика

В ячейке AB49 поместим формулу для вывода сообщения о текущем рабочем режиме – пошаговом – в случае нулевой скорости или автоматическом:

=СЦЕПИТЬ(ЕСЛИ(S47=0;"Пошаговый";"Автоматический");" режим")

Совершенствуем макросы

Завершив работу над интерфейсом, переключимся в редактор Visual Basic. Открыв программный код модуля, скопируем ранее записанные макросы переноса и очистки и, перейдя в окно кода рабочего листа с событийной процедурой, которая помогала нам щедро рассыпать пробелы по «арене», вставим. Теперь через контекстное меню модуль можно удалить, так как для осуществления наших замыслов будет достаточно страницы кода первого листа рабочей книги.

Первым делом отредактируем ранее созданные макросы. «Макрос1» переименуем и, удалив строку выделения ячейки, заменим ее команду срабатывания счетчика поколений в ячейке O47.

Sub Новое_поколение()

  Range("HC5:IP44").Copy

  Range("C5:AP44").PasteSpecial Paste:=xlPasteValues

  Range("O47") = Range("O47") + 1

End Sub

«Макрос2» также переименуем и дополним еще двумя строками.

Sub Очистка()

  Range("C5:AP44").ClearContents 'Очистка диапазона

  Range("O47") = 0               'Сброс счетчика поколений

  Call Стоп                      'Вызов процедуры "Стоп"

End Sub

Упомянутую здесь процедуру «Стоп» создадим позже. Естественно, что после переименования подпрограммы придется выполнить переподключение ее к кнопке «Очистка». Для этого вызовем на ней контекстное меню, выберем строку «Назначить макрос…», найдем и выделим в списке «Лист1.Очистка» и нажмем кнопку «OK».

Рис. 10. Подключение макроса к кнопке

В событийную процедуру заселения жизни в выбранные ячейки добавим дополнительные условия выполнения, учитывающие рабочий режим и фактор времени (чтобы не выделялась клетка в верхнем левом углу основного поля при остановке). Определим не только номера строки и столбца активной ячейки, но и адрес всего диапазона выделения, чтобы командой присваивания пробелов или пустого текста иметь возможность одним движением его заселять или очищать. Кроме того, значение счетчика поколений в ячейке O47 устанавливаем на единицу. В окончательном варианте подпрограмма имеет вид:

Sub Worksheet_SelectionChange(ByVal Target As Range)

  If Timer > t + 1 And m <> 2 Then

    ad = Selection.Cells.Address()

    r = Selection.Cells.Row

    c = Selection.Cells.Column

    z = r > 4 And r < 45 And c > 2 And c < 43

      If z Then

        If Cells(r, c) = "" Then

           Range(ad) = " "

         Else

           Range(ad) = ""

        End If

        Range("O47") = 1

      End If

      Range("S47").Select

  End If

End Sub

Вводим переменные

Закончив редактирование, займемся необходимыми дополнениями. Откроем левый список в верхней части страницы и выберем строку «(General)». Оказавшись над ранее созданными подпрограммами в зоне объявления общих для всех процедур данного листа переменных, сделаем следующие записи:

Dim f As Boolean 'Флаг пуска

Dim t As Single 'Время прерывания

Dim m As Integer 'Маркер режима

Эти переменные мы объявили, чтобы упростить процедуру передачи параметров, так как они будут использоваться в нескольких подпрограммах. Остальные локальные переменные можно не объявлять. В последних версиях Visual Basic.Net такие вольности, конечно, не допустимы, но VBA, встроенный в приложения Microsoft Office, относится к этому довольно лояльно. Логическая переменная f будет сигнализировать, нажата ли кнопка «Пуск» или нет, а значение маркера m будет указывать, какой из режимов действует в данный момент: пошаговый, пуск-авто или стоп-авто.

Входим в режим

Для определения режима и смены надписей на первой кнопке запишем следующую процедуру:

Sub Режим()

  ActiveSheet.Shapes(1).Select

  If Range("S47") = 0 Then

     f = False

     m = 1

     Selection.Characters.Text = "Шаг"

    Else

     If f Then

        m = 2

        Selection.Characters.Text = "Стоп"

       Else

        m = 3

        Selection.Characters.Text = "Пуск"

     End If

  End If

  Range("S47").Select

End Sub

В этой подпрограмме, выделив первую кнопку , определяем значение скорости в ячейке S47. Если оно равно нулю, то сбрасываем флаг пуска, задаем значение маркера равное единице и на кнопке делаем надпись «Шаг». Если же скорость отлична от нуля, то есть выбран авторежим, то при запущенной игре (режим «два») на кнопке делаем надпись «Стоп» для последующего останова. В противном случае устанавливаем третий режим и готовим кнопку к пуску.

Для самой кнопки создадим следующую подпрограмму, которую подключим к ней по вышеописанной технологии.

Sub Пуск_Стоп()

  Call Режим          'Вызов процедуры "Режим"

  Select Case m       'Выбор по значению маркера m

    Case 1: Call Шаг  'При m=1 вызов процедуры "Шаг"

    Case 2: Call Стоп 'При m=2 вызов процедуры "Стоп"

    Case 3: Call Пуск 'При m=3 вызов процедуры "Пуск"

  End Select          'Конец выбора

End Sub

Процедуры «Шаг», «Пуск» и «Стоп» запишем отдельно:

Sub Шаг()

  t = Timer            'Фиксируем время

  Call Новое_поколение 'Вызов процедуры "Новое_поколение"

End Sub

Sub Пуск()

  f = True    'Флаг пуска установить

  Call Режим  'Вызов процедуры "Режим"

  Call Таймер 'Вызов процедуры "Таймер"

End Sub

Sub Стоп()

  t = Timer   'Фиксируем время

  f = False   'Флаг пуска сбросить

  Call Режим  'Вызов процедуры "Режим"

End Sub

Набираем скорость

Осталась последняя процедура задержки времени смены поколений, которая работает, пока включен режим «2». Определив текущее время и добавив к нему промежуток, вычисленный на основе установленного в ячейке S47 значения скорости, вызывается подпрограмма «Новое_поколение». Затем по значению счетчика «живых» клеток в ячейке K47 проверяется, не прекратилась ли «жизнь» на площадке? Если «да», то вызывается процедура остановки. Для осуществления задержки времени используется цикл «пока», действующий до истечения временного промежутка, в теле которого проверяется наличие системных событий.

Sub Таймер()

  Do While m = 2

    t = Timer + (11 - Range("S47")) / 10

    Call Новое_поколение

    If Range("K47") = 0 Then Call Стоп

    Do While Timer < t

      DoEvents

    Loop

  Loop

End Sub

Экспериментируйте

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

Вместе с тем, несмотря на то, что самой игре вот уже сорок лет, она продолжает привлекать пытливые умы своей непредсказуемостью, завораживающими узорами, удивительными сюжетами. В ней до сих пор остается еще много белых пятен, которые ждут своих первопроходцев. Словом, как сказал Козьма Прутков: «Бросая в воду камни, смотри на круги, ими образуемые, иначе такое бросание будет пустым занятием».

Готовый проект, макросы которого доступны для изучения и снабжены подробными комментариями, можно найти в интернете по адресу: http://www.rosinka.vrn.ru/dinex/life.htm или загрузить с портала газеты «Информатика», воспользовавшись ссылкой: http://inf.1september.ru/download/life_4.rar


Источники

1. Википедия. Жизнь (игра). http://ru.wikipedia.org/wiki/Игра_Жизни_Конвея

2. Соколинский Ю.А. Игра Жизнь. http://inf.1september.ru/1999/art/life.htm

На верх

 

Динамические эффекты Предварительная подготовка Эффекты форматирования Графические объекты
&Движение объектов Ожившие графики Другие варианты Вентильные схемы Автоматизация тестирования
Автоматизация оценки Проект "Машина времени" Игра "Жизнь" Заполнение аттестатов

© 2009 Государственное областное образовательное учреждение

"Россошанская школа-интернат для детей-сирот и детей, оставшихся без попечения родителей"