Как в excel написать игру на

Развлекая — поучай.
(Гораций)

Если вы уже имели какой-то опыт программирования в прошлой жизни (привет, Basic, Pascal и т.д.), то, скорее всего, уже прошли этап «игрописательства». Однако, тряхнуть стариной и размять мозги вполне можно. Если же вы никогда не программировали игр, то никогда не поздно начать этот весьма увлекательный процесс. Всё, что нам потребуется — это Excel (любой версии) и 15-20 минут времени для начала.

Тренироваться будем на известной в узких кругах программистов игре «Жизнь» (Life). Её придумал британский математик Джон Конвей еще в 1970 году на основе работ легендарного Джона фон Неймана — прадедушки всех современных компьютеров. Если вы не сталкивались с ней раньше — не проблема, правила можно объяснить за полминуты:

  • Игра идет на большом (иногда даже бесконечном) поле в клеточку («вселенной»). Как вы понимаете, Excel для такого подходит идеально :)

  • В один момент времени каждая клетка может быть в двух состояниях — живой (обозначим её каким-нибудь значком или просто единичкой) или же мертвой (пустой). Начальное состояние всех клеток в игре называют первым поколением.

  • Если брать блок клеток 3х3 с текущей клеткой в середине, то вокруг неё оказывается 8 клеток-соседей. Дальнейшая судьба клетки зависит от того, сколько именно живых клеток (N) окажется в этой окружающей области. Вариантов несколько:

  • Правила игры

  • Если клетка была пустая (мертвая), но у нее есть ровно 3 живых соседа, то в ней зарождается жизнь.
  • Если клетка живая, но у неё меньше 2 соседей, то она умирает от одиночества.
  • Если клетка живая, но у неё больше 3 соседей, то она умирает от перенаселения.
  • Если клетка живая и у нее 2-3 соседа, то клетка продолжает жить.

Вот, собственно, и все правила. Можно даже сказать, что всё это неправильно называть игрой, т.к. здесь нет соперников в привычном понимании. Вы расставляете первое поколение, запускаете процесс и затем просто наблюдаете за развитием вашей «колонии» на протяжении нескольких поколений.

Однако, не стоит недооценивать обманчивую простоту этой логики — количество комбинаций, сценариев игры и многообразие фигур в такой игровой вселенной поражает своим разнообразием и поистине бесконечно. В математике подобные модели называют клеточными автоматами. А самое интересное, что реализовать подобную модель можно в любой версии Excel буквально на 20 строчках кода.

Поехали.

Шаг 1. Готовим игровое пространство

Создадим в новой книге три листа:

  • game — это будет основной листы игры, где мы будем наблюдать за развитием нашей «колонии»
  • next — этот лист будет формировать следующее поколение, которое затем придет на смену текущему
  • start — на этом листе мы будем задавать начальную конфигурацию, т.е. первое поколение в нашей игре

На каждом листе (можно выделить их заранее, удерживая клавишу Shift или Ctrl, чтобы не повторять трижды одни и те же действия), разметим игровое поле размером, допустим, 30 на 30 ячеек. Впоследствии размер поля можно будет подправить в соответствии с вашими аппетитами и мощью вашего ПК:

Игровое пространство

На листе start разметим с помощью единичек первое поколение любым желаемым образом:

Первое поколение

Шаг 2. Пишем макрос

Теперь пришла пора расчехлить наш VBA и написать макрос, который и будет делать всю работу, а именно:

  1. Копировать первое поколение с листа start на лист game.
  2. Проходить по ячейкам игрового поля на листе game и проверять окружающих соседей (блок 3х3) для каждой из них.
  3. В зависимости от результатов проверки помечать на листе следующего поколения next ту же ячейку как живую (1) или мертвую (пусто).
  4. Копировать получившееся новое поколение с листа next вместо текущего на листы игры game.
  5. Повторять пункты 2-4 несколько раз, сменяя одно поколение другим и отображая на экране изменения в нашей «колонии».

Для начала откроем редактор Visual Basic на вкладке Разработчик (Developer). Если такой вкладки не видно, то её нужно будет сначала отобразить через Файл — Параметры — Настройка ленты (File — Options — Customize Ribbon), включив соответствующий флажок.

В открывшемся окне редактора создадим новый модуль с помощью команды меню Insert — Module, а затем скопируем и вставим туда код нашего макроса:

Sub Life()
    Dim cell As Range, n As Integer, i As Integer
    
    Set rGame = Worksheets("Game").Range("B2:AE31")
    Set rStart = Worksheets("Start").Range("B2:AE31")
    Set rNext = Worksheets("Next").Range("B2:AE31")
    Set wNext = Worksheets("Next")

    rStart.Copy Destination:=rGame
    
    For i = 1 To 50
        rNext.ClearContents
        For Each cell In rGame.Cells
            n = WorksheetFunction.CountA(cell.Offset(-1, -1).Resize(3, 3)) - cell.value
            If cell = "" And n = 3 Then wNext.Cells(cell.Row, cell.Column) = 1
            If cell = 1 And (n = 2 Or n = 3) Then wNext.Cells(cell.Row, cell.Column) = 1
            If cell = 1 And (n < 2 Or n > 3) Then wNext.Cells(cell.Row, cell.Column) = ""
        Next cell
        rNext.Copy Destination:=rGame
    Next i
End Sub

Теперь давайте разберем его построчно для понятности:

Поскольку в коде нам придется несколько раз ссылаться и много раз работать с диапазонами игрового пространства (B2:AE31) на каждом из трёх листов книги, то имеет смысл сразу оформить их как переменные. Это делается в блоке:

Set rGame = Worksheets("Game").Range("B2:AE31")
Set rStart = Worksheets("Start").Range("B2:AE31")
Set rNext = Worksheets("Next").Range("B2:AE31")

Заодно мы создаем ещё и переменную wNext, которая ссылается на весь лист next целиком — это нам тоже пригодится в будущем:

Set wNext = Worksheets("Next")

Затем, перед началом игры, мы должны перенести первое поколение с листа start на лист game. Это выполяется командой прямого копирования с использованием уже созданных переменных:

rStart.Copy Destination:=rGame

Поскольку мы хотим прокрутить в нашей игре не одно, а несколько (например, 50 для начала) поколений, то дальнейшие действия заключены в цикл:

For i = 1 to 50
...
Next i

А внутри этого цикла мы, во-первых, сначала очищаем рабочее пространство на листе next для формирования следующего поколения:

rNext.ClearContents

А, во-вторых, запускаем вложенный цикл прохода по всем ячейкам игровой вселенной на листе game, чтобы проверить каждую из них — это реализовано циклом прохода по коллекции:

For Each cell in rGame.Cells
...
Next cell

Ссылка на очередную проверяемую ячейку будет храниться в переменной cell. Для этой ячейки нам нужно сначала построить окрестность 3х3 с ней в середине. Это выполняется с помощью конструкции:

cell.Offset(-1, -1).Resize(3, 3)

Здесь метод Offset(-1,-1) виртуально сдвигает текущую проверяемую ячейку на одну строку вверх и на один столбец влево, а потом метод Resize(3,3) опять же виртуально растягивает эту одну ячейку до новых размеров 3 на 3:

Offset и Resize

Чтобы посчитать количество заполненных ячеек в полученной окрестности применяется функция рабочего листа СЧЁТЗ (COUNTA), которую в VBA можно вызвать с помощью объекта WorksheetFunction. Таким образом количество живых соседей в окружающей текущую ячейку области 3 на 3 мы получаем выражением (не забыв вычесть из полученного количества текущую ячейку):

n = WorksheetFunction.CountA(cell.Offset(-1, -1).Resize(3, 3)) - WorksheetFunction.CountA(cell)

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

If cell = "" And n = 3 Then wNext.Cells(cell.Row, cell.Column) = 1
If cell = 1 And (n = 2 Or n = 3) Then wNext.Cells(cell.Row, cell.Column) = 1
If cell = 1 And (n < 2 Or n > 3) Then wNext.Cells(cell.Row, cell.Column) = ""

Когда цикл прохода по ячейкам будет завершен, то сформированное следующее поколение с листа next нужно скопировать на место текущего на листе game — делаем это уже знакомой конструкцией:

rNext.Copy Destination:=rGame

Вот, собственно, и вся логика.

Осталось вернуться в Excel на лист game, запустить нашу игру через вкладку Разработчик — Макросы (Developer — Macro) и насладиться процессом развития нашей колонии:

Игра Жизнь Life

Ссылки по теме

  • Что такое макросы и как их программировать в Microsoft Excel
  • Справочник по игре «Жизнь» — сайт LifeWiki

Вам бывает скучно на работе? Часто сидите два-три дня без единого намёка на трудовую деятельность и пытаетесь ее имитировать, а руководство так и ждет ошибки с вашей стороны?

Теперь этого можно будет избежать, ведь в разработке находится пошаговая RPG в стиле Dragon Quest на NES для офисного приложения Excel.

Конечно, идея не нова. В Excel и раньше делали разнообразные игры (даже полноценный шутер). Но если вы читали мои предыдущие статьи, то поймёте, что создавать троллейбусы из батонов белого (или чёрного) хлеба — мое небольшое хобби.

Перейдём же к делу

На данный момент готова альфа-версия графического движка и редактор карт. С вероятностью в 99% они будут дорабатываться в процессе разработки.

Сперва немного расскажу о некоторых технических характеристиках.

1. Скорее всего в игре будет использоваться событийная модель, а не циклическая, ведь для пошаговой стратегии цикл не так уж и важен. Это будет зависеть от того, как быстро Excel справится с рендером одного кадра. Минус такого подхода заключается в том, что написать какой-нибудь платформер на этой основе не получится. В любом случае я попробую оба варианта.

2. Все текстуры имеют размер 16*16 пикселей. Палитра состоит всего из 56 цветов (стандартный размер палитры Excel). В качестве основы я взял палитру NES.

3. Текстуры я рисую в программе Aseprite, а в Excel из. bmp перевожу с помощью небольшого, написанного на VBA софта, который нашел в интернете.

4. Бэкграунд состоит из тайлов, спрайты же привязаны к системе координат.

Графический движок

Карта уровня представляет собой двумерный массив с кодовым обозначением тайла в формате «XXXY», где XXX — номер текстуры по порядку, Y — значение, указывающее на то, можно ли пройти сквозь тайл. Вторая функция пока что не реализована.

Спрайты хранятся в отдельном массиве в формате: координата X, координата Y, порядковый номер спрайта, тип спрайта и тэг. Два последних значения пока не используются.

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

— высота и ширина игрового экрана;

— диапазон игрового экрана;

— массив игрового экрана для рендеринга;

— размер одной текстуры;

— координаты камеры;

— координаты игрока;

— номер уровня;

— карта тайлов и координаты спрайтов;

— массив спрайтов, тайлов и спрайтов игрока.

Все текстуры хранятся на отдельном листе с отображением индексов цветов палитры.

Так как это только первая версия движка, нажатие на «Новую игру» тут же запускает метод fillWithTextures (процесс создания массива цифровых значений цвета).

‘##########ЯДРО ГРАФИЧЕСКОГО ДВИЖКА##########
Sub fillWithTextures()

Dim cntRow As Integer, cntCol As Integer, pixOffsetX As Double, pixOffsetY As Double, _
mapBlockX As Integer, mapBlockY As Integer, texXOffset As Integer, texYOffset As Integer, _
texNumber As Integer, arrBlockTex() As Variant

Dim cntSprites As Integer, spriteOffsetX As Integer, spriteOffsetY As Integer, _
spriteNumber As Integer

ReDim arrRender(main.screenH, main.screenW)

For cntRow = 1 To main.screenH

For cntCol = 1 To main.screenW

‘Считаем смещение пикселя экрана относительно координат камеры
pixOffsetX = main.cameraX + cntCol
pixOffsetY = main.cameraY + cntRow

‘считаем спрайты
For cntSprites = 1 To UBound(arrMapSprites(), 1)

‘считаем смещение спрайта относительно пикселя
spriteOffsetX = pixOffsetX — arrMapSprites(cntSprites, 1)
spriteOffsetY = pixOffsetY — arrMapSprites(cntSprites, 2)

‘если пиксель содержит спрайт
If spriteOffsetX >= 0 And spriteOffsetY >= 0 And spriteOffsetX + pixOffsetX < pixOffsetX + main.blockSize _
And spriteOffsetY + pixOffsetY < pixOffsetY + main.blockSize Then

‘если элемент спрайта не пуст
If arrSprites((spriteOffsetY + blockSize * arrMapSprites(cntSprites, 3)) + 1, spriteOffsetX + 1) <> 0 Then

arrRender(cntRow, cntCol) = arrSprites((spriteOffsetY + blockSize * arrMapSprites(cntSprites, 3)) + 1, spriteOffsetX + 1)

End If

End If

Next

‘рисуем тайлы
If (pixOffsetX > 0 And pixOffsetX < main.mapWidth) And _
(pixOffsetY > 0 And pixOffsetY < main.mapHeight) Then

‘расчет тайла, в который входит пиксель
mapBlockX = WorksheetFunction.RoundUp(pixOffsetX / main.blockSize, 0)
mapBlockY = WorksheetFunction.RoundUp(pixOffsetY / main.blockSize, 0)

‘определяем номер текстуры
texNumber = arrMapTiles(mapBlockY, mapBlockX)

‘Определение цвета текстуры для пикселя
texXOffset = getTexOffset(pixOffsetX) + 1
texYOffset = getTexOffset(pixOffsetY) + 1

If arrMapTiles(mapBlockY, mapBlockX) <> «» And arrTiles(texNumber * _
main.blockSize + texYOffset, texXOffset) <> «» And arrRender(cntRow, cntCol) = «» Then

arrRender(cntRow, cntCol) = arrTiles(texNumber * main.blockSize + texYOffset, texXOffset)

End If

End If

Next

Next

End Sub

Первым делом происходит поиск спрайтов, которые нужно отрисовать. Для этого программа проверяет каждый «пиксель» игрового экрана, считает смещение этого пикселя относительно стартовых координат камеры, а также смещение относительно всех спрайтов на уровне. Если смещение «пикселя» относительно спрайта по каждой оси равно от 0 до 15 (так как размер текстуры 16*16), берётся индекс нужного цвета из массива спрайтов.

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

‘Возвращает координату текстуры
Function getTexOffset(dCoordinate As Double) As Integer

getTexOffset = (dCoordinate — 1) Mod main.blockSize

End Function

Почему сперва происходит проверка спрайтов, а затем тайлов?

Все просто. Программа просто не трогает те «пиксели», которые уже закрашены спрайтами, что влияет на производительность в лучшую строну.

P.S. На следующий день я понял, что проверка условия «закрашенности» спрайтами должна производиться в начале. Тогда это повлияет на производительность. Привет, оптимизация.

Вторая проблема — это проверка спрайтов для каждого пикселя экрана. Предположим, что на уровне находится 40 спрайтов. При размере экрана 96*64 = 6144 пикселей количество итераций цикла достигает 6144 * 40 = 245760. Если пойти другим путём и проверять спрайты не для каждого пикселя, а по условию нахождения в поле зрения камеры, то количество итераций не превысит 40*16*16 = 10240. Эта проблема решается быстро.

Создание игрока и рендеринг изображения

Для того, чтобы поместить спрайт игрока в рендер-массив нужно посчитать смещение спрайта относительно координат камеры.

Sub renderPlayer(imagePose As Integer)

Dim offsetX As Double, offsetY As Double, cntRow As Integer, _
cntCol As Integer

‘Считаем смещение относительно координат камеры
offsetX = main.playerX — main.cameraX
offsetY = main.playerY — main.cameraY

‘Если игрок не находится за пределами камеры
If offsetX >= 0 And offsetY >= 0 And _
offsetX < main.cameraX + main.screenW And _
offsetY < main.cameraY + main.screenH Then

For cntRow = 0 To main.blockSize — 1

For cntCol = 0 To main.blockSize — 1
‘Если пиксель текстуры заполнен
If main.arrPlayerSpr((cntRow + 1) + (imagePose * main.blockSize), cntCol + 1) <> 0 Then

‘Если пиксель не заходит за пределы камеры
If cntRow + main.playerY <= main.screenH + main.cameraY And cntCol + main.playerX <= main.screenW + main.cameraX Then

arrRender(offsetY + cntRow, offsetX + cntCol) = main.arrPlayerSpr((cntRow + 1) + (imagePose * main.blockSize), cntCol + 1)

End If

End If

Next

Next

End If

End Sub

Аргумент imagePose будет использоваться для имитации поворота игрока при движении.

В конце-концов рендер-массив готов, поэтому вызываем последнюю процедуру, которая рисует сформированный кадр на игровом поле. Ее я показывать не буду, потому что она очень сырая и будет дорабатываться.

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

Вот, что получается в итоге:

На этом можно пока закончить. Надеюсь, что из ваших глаз не пошла кровь от «лучшего в мире» языка программирования и попыток написать что-то осмысленное.

В любом случае жду критику и советы. Всегда интересно послушать, что скажут люди.

Немного саморекламы

Я создал паблик ВКонтакте, куда буду выкладывать свои мысли, алгоритмы, код, ссылки на эти статьи и конечно мемасики:) Если вам интересно наблюдать за разработкой игр и разных странных вещей, добро пожаловать.

Время на прочтение
1 мин

Количество просмотров 190K

Бухгалтер из Торонто по имени Кэри Уолкин (Cary Walkin) никогда не занимался разработкой компьютерных игр, но в совершенстве освоил Excel. Этого оказалось достаточно для создания RPG-игры, которая работает на макросах VBA, встроенного языка программирования Excel.

Игру Arena.Xlsm версии 1.0 можно скачать здесь:

v1-0-arena.xlsm (работает в Excel 2007 и Excel 2010 под Windows)

Ключевые особенности:

  • Увлекательный сюжет с четырьмя различными концовками, в зависимости от прохождения игры
  • Более 2000 врагов с различным уровнем ИИ
  • 39 модификаторов вещей означает более 1000 возможных комбинаций и свойств предметов
  • 8 схваток с боссами, для победы над каждым из них нужна особая тактика
  • 4 предварительно подготовленных игровых пространства
  • 31 заклинание, есть много разных стратегий для успеха
  • 15 уникальных артефактов
  • 36 наград (достижений)
  • Вся игра от начала до конца проходит внутри рабочей книги Excel

Официальная wiki-страница для помощи по игре, там же информация о базовых стратегиях.

Так что если увидите бухгалтера в офисе, который целыми сутками сидит в программе Excel, присмотритесь к нему повнимательнее. Кто знает, какие заклинания он сейчас подбирает для босса на шестом уровне.

Теги:

  • Arena.Xlsm
  • Excel
  • RPG
  • рабочая книга Excel
  • макрос
  • VBA

Хабы:

  • Ненормальное программирование
  • Разработка игр
  • Visual Basic for Applications

У нас появилось свободное время.. значит можно поиграть! В этой рубрике мы будем выкладывать простенькие игры в Excel. Да, в Excel тоже можно писать игры, ведь в нем встроен язык программирования VBA. После того как вы скачаете игру (по ссылкам ниже), необходимо будет только включить макросы (как это сделать описано тут). Во многих Ирах в Excel (в макросах) есть много интересных находок. Кто знает, может игра в Excel поможет вам не только скоротать время, но и научиться чему-то новому. Играйте в Excel и пишите игры сами!

Игра в Excel «Морской бой»:

Battleships

Игра в Excel «Змейка»:

snaked

Игра в Excel «Вертолет»:

gmexcopter

Игра в Excel «Квадрат»

Squares

Игра в Excel «Лягушка»

frog_leap

Игра в Excel «Темница»

dungeon

Если у вас есть чем поделиться — присылайте!

Спасибо за внимание.

Перейдем к следующему примеру — необходимо разработать несложную игру. На рабочем листе (рис. 1.42) следует разместить пять окон для изображений (элементы управления типа «Изображение»). При этом два окна будут основными — расположены слева и большие по размеру. Другие три окна имеют меньшие размеры и расположены в правой части рабочего листа (они будут содержать эталонные изображения). Также на рис. 1.42 расположены две кнопки и две надписи, при этом надпись Результат является просто поясняющей, и далее мы ее упоминать не будем.

Теперь смысл игры. Предварительно в три маленьких окна в правой части листа выводятся три различные картинки (условно их можно называть эталонными). При щелчке на кнопке Бросок в каждое из двух основных окон для изображений должна попадать (случайным образом) одна из трех возможных картинок (из набора эталонных, которые видны на экране). Если в результате такого случайного выбора картинки в обоих основных окнах совпадают, то в элемент управления «Надпись» для результата добавляется 3 балла, а если нет, то вычитается 1 балл.

Рис. 1.42. Интерфейс разрабатываемой игры

Рис. 1.42. Интерфейс разрабатываемой игры

Нам также потребуется датчик случайных чисел — здесь мы воспользуемся уже знакомой функцией Rnd. На первом этапе необходимо дать имена объектам в соответствии с табл. 1.2. Назначение элементов достаточно очевидно. Нескольких слов заслуживает элемент «Надпись» Res для отображения результата. В ней вычисляется суммарный результат по итогам серии произведенных бросков. А по щелчку на кнопке Начать игру снова значение результата обнуляется. Таким образом, вступительная часть перед программированием завершена, и поэтому перейдем к описанию программного кода.

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

В качестве первого программного фрагмента оформим процедуру, выполняемую при открытии книги, так, как представлено в листинге 1.26. Здесь в надпись для результата подставляется содержимое ячейки М1 с первого листа книги.

1
2
3
4
' Листинг 1.26. Процедура, выполняемая при открытии книги
Private Sub Workbook_Open()
Worksheets(1).Res.Caption = Worksheets(1).Range("M1").Value
End Sub

Таблица 1.2. Имена объектов на рис. 1.42

Свойство Name Тип объекта Комментарий
Image1 Изображение Левое основное окно для изображения
Image2 Изображение Правое основное окно для изображения
ImageEtalon1 Изображение Левое окно для образца
ImageEtalon2 Изображение Среднее окно для образца
ImageEtalon3 Изображение Правое окно для образца
Label1 Надпись Подпись «Результат»
Res Надпись Для отображения результата
Brosok Надпись Для выполнения броска
NewGame Надпись Начать игру снова

В листинге 1.27 приведена основная процедура, выполняемая по щелчку на кнопке с надписью Бросок.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
' Листинг 1.27. Обработка щелчка на кнопке Бросок
Private Sub Brosok_Click()
Symma = Range("M1")
Randomize
' Формирование случайных чисел
a = CInt(Rnd * 3 + 0.5)
b = CInt(Rnd * 3 + 0.5)
' Отображение картинки в первом окне
If a = 1 Then
	Image1.Picture = ImageEtalon1.Picture
ElseIf a = 2 Then
	Image1.Picture = ImageEtalon2.Picture
Else
	Image1.Picture = ImageEtalon3.Picture
End If
' Отображение картинки во втором окне
If b = 1 Then
	Image2.Picture = ImageEtalon1.Picture
ElseIf b = 2 Then
	Image2.Picture = ImageEtalon2.Picture
Else
	Image2.Picture = ImageEtalon3.Picture
End If
' Формирование результата
If a = b Then
	Symma = Symma + 3
Else
	Symma = Symma - 1
End If
' Фиксирование результата в надписи и в ячейке на листе
Res.Caption = Symma
Range("M1").Value = Symma
End Sub

В тексте процедуры используется функция Rnd, которая нам уже встречалась. Преобразование CInt (Rnd * 3 + 0.5) позволяет сформировать случайное целое число, которое может принимать одно из трех возможных значений: 1, 2 или 3. Таким образом, можно значения переменных а и b сопоставить с номерами картинок. В результате при совпадении картинок мы увеличиваем сумму выигрыша на 3 балла, а при несовпадении, соответственно, уменьшаем на один.

Если не предпринимать каких-либо действий, то функция Rnd при каждом повторном открытии книги выдает одну и ту же последовательность случайных чисел. Чтобы устранить данный недостаток, мы воспользовались функцией Randomize, которая выполняет перемешивание случайных чисел. В результате при различных сеансах работы последовательность, выдаваемая по нажатию кнопки Бросок, каждый раз будет разная.

Другая кнопка на листе (NewGame) позволяет сбросить содержимое ячейки М1 и значение свойства Caption элемента Res в ноль для начала новой игры (листинг 1.28).

1
2
3
4
5
6
' Листинг 1.28. Процедура сброса суммы баллов в ноль
Private Sub NewGame_Click()
Symma = О
Res.Caption = Symma
Range("M1") = Symma
End Sub

Один из вариантов развития игры показан на рис. 1.43.

Рис. 1.43. Один из сценариев развития игры

Рис. 1.43. Один из сценариев развития игры

В мир информатики # 91 (1-15 мая).
Microsoft Excel углубленно

Игра “Крестики-нолики” в среде Microsoft Excel


Кто сам пилит свои дрова,
тот согревается дважды
1.

Кто сам программирует свои
компьютерные игры, тот наслаждается дважды
2.

Мы продолжаем (см. [1]) публикацию
материалов, посвященных моделированию
простейших игр средствами программы Microsoft Excel. В
этой статье мы рассмотрим известную игру
“Крестики-нолики”. Правила этой игры вы,
конечно, знаете.

На рис. 1 представлен вид рабочего
листа в начале новой игры (после щелчка на кнопке
с надписью “Новая игра”).


Рис. 1

Прежде всего надо оформить рабочее
поле игры — диапазон ячеек А6:С8:

— размеры строк и столбцов сделать
такими, чтобы каждая клетка поля имела форму
квадрата;

— установить соответствующие размеры
символов, которые будут записываться в каждую
ячейку диапазона (это будут буквы Х и О);
начертание символов предусмотреть полужирное;

— выравнивание текста в ячейках
сделать по центру.

Разместите на листе три кнопки. О том,
как это сделать и как разместить на кнопке
соответствующую надпись, рассказано в статье [1].
Там же описано, как создаются и “привязываются”
к кнопке макросы — программы, написанные на
языке программирования VBA, которые выполняются
по щелчку на той или иной кнопке.

Текст в ячейках А3 и А4 выводится по
щелчку на кнопке с надписью “Новая игра”, а
название игры в ячейку А1 следует ввести
“вручную”. По щелчку на этой кнопке очищаются
также 9 ячеек рабочего поля игры и ячейка E3.

Макрос, “привязанный” к кнопке с
надписью “Новая игра”, можно назвать
аналогичным именем:


Sub НоваяИгра()

Range(«A3»).Value = «Имя первого
игрока:»

Range(«A4»).Value = «Имя второго
игрока:»

‘Очищаем 9 ячеек рабочего поля

Range(«A6»).Value = «»

Range(«A7»).Value = «»

Range(«C7»).Value = «»

Range(«C8»).Value = «»

‘Готовимся принять имена играющих

‘Устанавливаем указатель

‘активной ячейки на ячейку E3

Range(«E3»).Activate

‘и очищаем ее

Range(«E3»).Value = «»

End Sub

Напомним, что:

1) запись Range(«E3»).Value (и подобные)
означает значение, записанное в ячейке с адресом
Е3. Это значение может использоваться в любом
месте программы — в операторе присваивания (в
его левой или правой части), в условном операторе
и т.д.;

2) запись Range(«E3»).Activate
соответствует установке указателя активной
ячейки (его часто называют “курсором”) на ячейку
Е3.

Вернемся к игре. В ходе нее после ввода
имен играющих в ячейки E3 и E4 нужно щелкнуть на
кнопке с надписью “Начало” — картина изменится
на приведенную на рис. 2. В ней в ячейке будет
отражаться имя игрока, делающего очередной ход.

Рис. 2

Макрос, связанный с кнопкой с надписью
“Начало”, имеет вид:


Sub Начало()

‘Очищаем ячейки А4 и Е4

Range(«A4»).Value = «»

Range(«E4»).Value = «»

‘Запоминаем имена участников игры

Имя1игрока = Range(«E3»).Value

Имя2игрока = Range(«E4»).Value

‘Выводим текст в ячейку А3

Range(«A3»).Value = «Очередной ход
делает»

‘Определяем начинающего игру

‘и выводим его имя в ячейке Е3

If Int(Rnd * 2) + 1 = 1 Then

‘Начинает 1-й участник

Range(«E3»).Value = Имя1игрока

НомерИгрокаДелающегоХод = 1

Else

‘Начинает 2-й участник

Range(«E3»).Value = Имя2игрока

НомерИгрокаДелающегоХод = 2

End If

‘Устанавливаем указатель

‘активной ячейки на ячейку D7

Range(«D7»).Activate

End Sub

— где Имя1игрока и Имя2игрока —
переменные величины, означающие имена
участников (эти имена в ходе игры будут
поочередно отражаться в ячейке Е3);

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

Так как значения этих трех величин
будут использоваться в макросе, связанном с
кнопкой с надписью “Х/О”3, то они должны быть
описаны не в процедуре Начало, а как глобальные —
перед всеми макросами.


Option Explicit4


DIM Имя1игрока, Имя2игрока As String,

НомерИгрокаДелающегоХод As Integer

Теперь настало время рассказать, что
для простановки того или иного знака следует
установить (мышью или используя клавиатуру)
указатель активной ячейки на нужную клетку
рабочего поля, после чего щелкнуть на кнопке с
надписью “Х/О”. Поскольку знаки должны
чередоваться, макрос, связанный с этой кнопкой,
нужно оформить следующим образом:


Sub СтавимЗнак()

If НомерИгрокаДелающегоХод = 1 Then

‘Ставим крестик

ActiveCell.Value = «X»

‘Следующий ход будет делать другой
игрок

НомерИгрокаДелающегоХод = 2

‘Выводим его имя в ячейке Е3

Range(«E3»).Value = Имя2игрока

Else

‘Ставим нолик

ActiveCell.Value = «O»

‘Следующий ход будет делать другой
игрок

НомерИгрокаДелающегоХод = 1

‘Выводим его имя в ячейке Е3

Range(«E3»).Value = Имя1игрока

End If


End Sub

Но всегда ли можно ставить крестик или
нолик? Нет, конечно. Во-первых, знак нельзя
ставить в клетки (ячейки), не принадлежащие
рабочему полю игры. Это условие записывается в
виде:

ActiveCell.Address <> “$A$6” And ActiveCell.Address <>
“$A$7” And ActiveCell.Address <> “$A$8” And ActiveCell.Address <>
“$B$6” And ActiveCell.Address <> “$B$7” And ActiveCell.Address <>
“$B$8” And ActiveCell.Address <> “$C$6” And ActiveCell.Address <>
“$C$7” And ActiveCell.Address <> “$C$8”

Кроме того, нельзя ставить знак в
клетку, в которой уже что-то записано.

С учетом сказанного процедура
СтавимЗнак примет вид:


Sub СтавимЗнак()

If ActiveCell.Address<>»$A$6″ And
ActiveCell.Address<>»$A$7″ AndThen

MsgBox «Клетка вне рабочего поля!»

Else

If ActiveCell.Value <> «» Then

MsgBox «В этой клетке уже стоит знак!»

Else ‘Можно ставить знак

If НомерИгрокаДелающегоХод = 1 Then

ActiveCell.Value = «X»

НомерИгрокаДелающегоХод = 2

Range(«E3»).Value = Имя2игрока

Else

ActiveCell.Value = «O»

НомерИгрокаДелающегоХод = 1

Range(«E3»).Value = Имя1игрока

End If


End If ‘Можно ставить знак

End If


End Sub

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

Else ‘Можно ставить знак

If НомерИгрокаДелающегоХод = 1 Then

ActiveCell.Value = «X»

‘Проверяем, не выиграл ли 1-й игрок

If Range(«A6″).Value=»X» And
Range(«A7″).Value=»X» And
Range(«A8″).Value=»X» Or
Range(«B6″).Value=»X» And
Range(«B7″).Value=»X» And
Range(«B8″).Value=»X» OrThen

MsgBox («Выиграл» + Имя1игрока)

Else ‘игра продолжается

НомерИгрокаДелающегоХод = 2

Range(«E3»).Value = Имя2игрока

End If ‘Конец проверки

Else

ActiveCell.Value = «O»

‘Проверяем, не выиграл ли 2-й игрок

If Range(«A6″).Value=»О» And
Range(«A7″).Value=»О» And
Range(«A8″).Value=»О» Or
Range(«B6″).Value=»О» And
Range(«B7″).Value=»О» And
Range(«B8″).Value=»О» OrThen

MsgBox («Выиграл» + Имя2игрока)

Else ‘игра продолжается

НомерИгрокаДелающегоХод = 1

Range(«E3»).Value = Имя1игрока

End If ‘Конец проверки

End If


End If ‘Можно ставить знак

End If


End Sub

Внимание! При оформлении условия
победы того или иного игрока следует учитывать
одинаковое написание русских и латинских
символов “Х” и “О”.

И, наконец, следует проверить, не
окончилась ли игра вничью:

End If ‘Можно ставить знак

End If

‘Проверка на ничью

IfThen

MsgBox «Ничья!»

End If


End Sub

Условие, при котором игра закончилась
вничью, запишите самостоятельно. Обращаем
внимание на то, что если все 9 клеток рабочего
поля игры заполнены, то это не означает, что игра
закончилась вничью — один из играющих мог
выиграть в результате последнего, девятого, хода.

Литература

1. Игра “Быки и коровы” в среде Microsoft Excel. / “В
мир информатики” № 78 (“Информатика”
№ 19/2006).


1 Французская поговорка

2 Из книги: Арсак Ж. Программирование игр и
головоломок. М.: Наука, 1985

Понравилась статья? Поделить с друзьями:
  • Как в excel написать знак больше или равно
  • Как в excel найти разницу между ячейками
  • Как в excel найти разницу между двумя датами
  • Как в excel найти разницу между датами в месяцах
  • Как в excel найти похожие значения в двух столбцах