Как создать игру шашки в excel
Прочитав пост об игре в XLS, чуть скупая слеза не навернулась. Вспомнил я, как с десяток лет назад, на своей первой работе помимо макросов для коллег пописывал мини-игры для себя, даже скорее для того, чтобы мой мозг не куксился от рутины и не ржавел.
Конечно же, я их сохранил и хочу ими поделиться с вами. В архиве всего 9 файлов, и одна папка, описание каждого из них даю ниже. Все программы написаны на VB, работают на 2003 и 2007 Excel. Сразу скажу, что я по профессии экономист, а не программист, игры писал для развлечения, и код там никакой :) Вирусов быть не должно :)
Casino – планировался как сборник «четыре в одном». У вас имелось определенное количество бабла и можно было его потратить, играя в рулетку, очко, покер и джекпот. Однако мне на каком-то этапе уже не хватало времени и желания все прикрутить, так что в файле есть только рулетка и очко. Да и трата бабла реализована кривовато. В общем там все понятно, нажимаете кнопку на листе и играете :)
JackPot – вообще уже не помню че там за фигня, но смысл вроде в том, что после нажатия кнопки под каждым из чисел из верхней строки в каждый цикл формируется меньшее число, которое в очередной цикл опять уменьшается. Циклы идут до тех пор, пока одно из нижних чисел не станет равно 0 или отрицательным. После окончания каждого цикла ищется сумма всех чисел из второго ряда и проверяется на делимость на 10, 100 и 1000. Типа, если выпала такая редкая удача, то сумма умножается соответственно на 2, 4 и 10. Ну и после окончания всех циклов выдается общая сумма к выигрышу. Вот такой бредовый алгоритм у меня был в мозгах 10 лет назад :)
Poker – конечно, изначально мой юношеский задор хотел сделать полноценную игру с AI. Но получилось вот это. После нажатия кнопки вы видите 3 карты в своей руке и вам предлагается ставить (bet) или скинуть карты (fold). После вашего фолда или когда на столе появятся 5 карт, игра заканчивается и вы видите карты на руках противника и все комбинации ваши и противника.
Guess1000 – угадайка, простейшая игра, которую учили алгоритмизировать во времена моей юности. Вы с компом загадываете число от 1 до 1000 и угадываете их друг у друга, стремясь сделать это первым.
БыкиКоровы – аналогично, популярная игра в свое время. Комп загадывает 4-значное число, состоящее из разных цифр, а вы его угадываете, делая свои попытки. Когда я еще мог хорошо соображать, я мог угадывать числа максимум за 6 ходов. Сейчас сноровка уже далеко не та..
Слова – разновидность игры «Быки и коровы». Здесь комп загадывает не число, а 4-буквенное слово. Правила те же, что и в обычных Быках..
Девяточка – наверняка многие (бывшие) студенты потратили время не на одной паре, играя в эту игру. Правила простые. Изначально подряд записаны все числа от 1 до 19, кроме 10, по одной цифре в клетке. Можно зачеркивать либо рядом стоящие (только по вертикали или горизонтали) одинаковые цифры, либо две цифры, дающие в сумме 10. Когда все, что хотели, зачеркнули, переписываете оставшиеся цифры дальше, заполняя лист. Цель игры – сделать так, чтобы ВСЕ цифры оказались зачеркнуты. В файле роль ручки играет заливка ячейки черным цветом.
Наживка: игру можно закончить за один цикл :) (граница цикла помечена пурпурными клетками)
Реверси – здесь была попытка реализовать игру с AI. Т.к соответствующих знаний у меня не было и нет, то алгоритм, конечно хреновенький, скорее всего комп не сможет выиграть у вас ни одного раза.. Правила игры писать не буду, если их не знаете, то с легкостью найдете в сети. Играть просто - на своем ходе вбиваете координаты ячейки, куда хотите сходить, потом смотрите на ход компа, затем снова ходите..
Наконец, 2 игры, где от вас практически ничего не зависит, а все зависит почти целиком и полностью от великого и ужасного рандома :)
Гонки – имитация автогонок, когда машинки ездят по кругу. До нажатия на кнопку «Погнали» вы можете поменять 3 параметра игры (они помечены комментарием «можно менять») – длина круга, сколько кругов длится гонка и предельное количество поломок, после которого машина выбывает из гонки.
После нажатия кнопки вас спросят о количестве участников от 1 до 10. Чем большее число вы введете, тем больше данных придется заносить. По каждому участнику нужно будет ввести имя, выбор шин на гонку, тип двигателя, тип коробки передач, тип бензина и тип дизеля (даже если двигатель бензиновый)) ). Все остальные места до десяти заполняются компами с рандомным выбором.
Все эти настройки магическим образом (не буду писать как именно :) ) влияют на прохождение машиной всей гонки с учетом, внимание, типа трассы и погоды, которые будут присутствовать во время гонки. Тип трассы и погода генерируются прямо перед началом гонок и являются еще одним элементом рандома для игроков :)
Итак, после того, как вы ввели все данные, гонка начнется, и вам предстоит лишь сидеть и наблюдать за перемещением вашей машины в топе гонки :) Чем больше ваши введенные параметры подходят под тип трассы и погоду, тем меньше количество поломок будет получать ваша машина и выше будет ее скорость. При получении машиной в течение одного круга предельного количества поломок она выбывает из гонок, если же она смогла добраться до пит-стопа, то потратит там время в секундах, равное количеству поломок. Вот и все правила :)
ЧМ – имитатор футбольных матчей :). Сами понимаете, создать в Excel фифу-2015 довольно сложно, поэтому не судите строго. Программа написана и проверялась в работе только в Excel 2007.
На листе «команды» список команд, участвующих в турнире, с перечнем характеристик команд. Числовые параметры можно менять как угодно, главное чтоб они были положительными. Добавление новых команд невозможно. Названия команд можно менять. После изменений идете на лист «game», выбираете из выпадающих списков 2 команды и нажимаете «play». При выборе команд характеристики не меняются, уж извиняйте :) Только после нажатия кнопки запуска игры. На листе полно служебной информации, но нас будет интересовать только количество пройденного времени и счет игры. У меня в те времена было полно свободного времени, так что я даже устраивал виртуальные чемпионаты, используя сетки на листах «сетка» и «сетка 2й тур».
В игре, по сути, вы только определяете характеристики команд. Все остальное на себя берет его величество случай. В зависимости от характеристик команд, каждая из них имеет свой шанс забить или пропустить гол, коэффициент усталости и боевого духа, которые меняются на протяжении всей игры. Игра реализуется 10-минутными циклами, после которого происходит расчет всех показателей, меняется счет и запускается следующий цикл. И так, пока не пройдут все 90 минут матча. Время, конечно же, виртуальное :) Реально одна игра займет 5-10 секунд.
Игры, конечно же, наивного уровня, но, может быть, вы на некоторое время заинтересуете ими своих детей, в т.ч. и образовательных целях, чтоб они не приставали к вам, пока вы гоняете на ваших любимых танках :)
Бонус: в качестве бесплатного бонуса в папке FTW находится 2 файла. Работают они под 2007 Excel. Файл FTW нужен для того, чтобы вы могли передохнуть от работы, пока системщики и ваш босс делают недоуменные глаза от того, что все навигационные клавиши в Excel перестали работать и вы с чистой совестью можете испить чашку кофе или выйти на перекур. Ну а когда решитесь вновь вернуться на свое рабочее место, нажмите на кнопку в другом файле и все восстановится :)
Так уж получилось, что моим первым более-менее серьёзным проектом, связанным с программированием, была реализация шашек для «Шага в будущее». К несчастью, доделать его до конца у меня так и не получилось, так как через некоторое время концепция проекта резко поменялась. Несмотря на это, программа была практически готова и с ней даже можно было играть, к тому же сам процесс её написания оказался весьма интересным, поэтому я решил поделиться теми идеями и алгоритмами, которые сумел придумать.
Правила игры
- Игра ведётся на доске 8х8 клеток, только на черных ячейках
- Шашки в начале игры занимают первые три ряда с каждый стороны
- Бить можно произвольное количество шашек в любых направлениях
- Простые шашки ходят только вперёд
- Простая шашка может срубить назад
- Дамка ходит на любое число полей в любую сторону
- Проигрывает тот, у кого не остается фигур, либо ходов
- Шашка снимается с поля после боя (можно перефразировать так: одну шашки нельзя срубить дважды за один ход)
- Бить обязательно
- Шашка превращается в дамку, достигнув восьмой (для белых) или первой (для черных) линии доски
- Если шашка во время боя проходит через дамочное поле, то она превращается в дамку и следующие бои (если они возможны) совершает уже как дамка
Реализация
Сначала необходимо определить, как наша доска будет храниться в памяти. Оптимальным решением, на мой взгляд, является массив из 32 объектов, каждый из которых имеет набор методов и свойств. Свойства хранят всю возможную информацию о клетке, например:
- name: a1 //Имя клетки на реальной доске
- color: 1 //Цвет шашки, 1 — белая, 2 — черная, 0 — клетка пустая
- queen: false //Является ли шашка дамкой
- border: false //подсвечено ли поле
- doubleWay: false
- goldWay: true //эти два поля будут объяснены чуть позже
Разумеется, это не все необходимые свойства, однако приводить все я не вижу смысла. Что касается методов, то их немного и они выполняют несложные действия типа изменения полей queen, color и прочих, а затем обновляют изображение. Так, при бое будут вызваны функции для «очищения» той клетки, с которой идёт бой и той клетки, на которой стоит срубленная шашка, а так же для отрисовки шашки на том поле, куда происходит бой.
Однако как же определять, нужно рубить, или нет? Для этого перед каждым ходом доска сканируется, проверяя выполнение нескольких условий, выполнение которых означает, что нужно бить. Но для того, чтобы это сделать, придется разбить доски на диагонали, так как бой происходит именно по ним (это, кстати, нужно и для обычных ходов).
- GoldWay: a1, b2, c3, d4, e5, f6, g7, h8 //Так называемая «Большая дорога»
- DoubleWayG1A7: g1, f2, e3, d4, c5, b6, a7 //Двойники
- DoubleWayH2B8: h2, g3, f4, e5, d6, c7, b8
- TripleWayC1A3: c1, b2, a3 //Тройники
- TripleWayC1H6: c1, d2, e3, f4, g5, h6
- TripleWayH6F8: h6, g7, f8
- TripleWayA3F8: a3, b4, c5, d6, e7, f8
- UltraWayA5D8: a5, b6, c7, d8 //Косяки
- UltraWayH4D8: h4, g5, f6, e7, d8
- UltraWayE1A5: e1, d2, c3, b4, a5
- UltraWayE1H4: e1, f2, g3, h4
Разбивка на диагонали происходит именно так. Обратите внимание, что все диагонали перечислены снизу-вверх. Это сделано для удобства программиста, хотя и не является обязательным. В свойствах объектов перечислены все эти диагонали, а у тех диагоналей, на которых клетка лежит, стоит true, на остальных — false.
Таким образом, я создал несколько массивов, каждый из которых содержал ссылки на объекты, соответствующие клеткам, которые находятся на диагонали, которой соответствует массив. Это позволяет нам заставить шашки двигаться.
Я не буду расписывать алгоритм до мелочей, опишу лишь в общих чертах: если на какой-либо из диагоналей встречается следующая ситуация:
«шашка(1) — шашка (2) — пустое поле» (где 1 и 2 — игроки и ход сейчас делает игрок №1), либо «пустое поле — шашка(2) — шашка (1)» [для боя в обе стороны], то присвоить свойству первой клетки, отвечающему за информацию о том, должна ли она рубить, единичку. Кроме этого присвоить некой общей переменной(назовем её jumpInd), отвечающей за бои, единичку. Это нужно, потому что может возникнуть ситуация, в которой у игрока будет выбор какой из шашек рубить.
После того, как игрок кликнул по подсвеченному полю, выполняются все методы, «подчищающие хвосты» и меняющие цвета клеток. Если jumpInd был равен нулю, то передаем ход второму игроку. Если jumpInd=1, то нужно проверить, может ли игрок срубить ещё что-либо. Если да, то подсветим поля, на которые он может попасть в результате боя. Не стоит забывать производить проверку того, не стала ли шашка дамкой. Если да, то бой будет производиться уже по дамочным правилам. Если боя вообще нет, то опять проверим на превращение в дамку, обнулим jumpInd и передадим ход.
Нам удалось реализовать простые передвижения шашки, но это только начало. Теперь мы должны реализовать движение дамок. Здесь всё несколько сложнее в реализации, по крайней мере я с ними изрядно попотел, хотя сама суть похожа.
Для каждой диагонали производится проверка условий в обе стороны, но я буду писать лишь в одну, потому что суть лишь в порядке проверок.
Проверка для хода: если встречается ситуация: «дамка — пустое поле», то подсветить эту клетку и проверить следующую. Выполнять до тех пор, пока диагональ не закончится, либо пока не встретится шашка(дамка) противоположного цвета.
Проверка для боя: если встречается ситуация: «дамка — z пустых полей — шашка(дамка) противоположного цвета — n пустых полей» (z>=0, n>0), то подсветить все n пустых полей после шашки соперника (если встретится ещё одна шашка противника, то прекратить) и проделать все те манипуляции с переменными, хранящими информацию о боях, что и в случае с обычной шашкой. После того, как игрок кликнет на подсвеченную клетку, следует проверить возможность ещё одного боя в любую сторону, кроме той, из которой мы пришли. Реализация всех этих проверок и условий заняла у меня много времени и места, но, возможно, я просто что-то упустил и можно было реализовать всё короче и красивее.
И ещё одна очень важная вещь: не стоит забывать о следующем условии: шашку нельзя срубить дважды. Это означает, что если шашка на диагонали, на которой вы сейчас находитесь, уже была срублена, то ход заканчивается (для обычной шашки на том поле, где она сейчас стоит, а для дамки на любым из пустых полей вплоть до этой уже срубленной шашки противника). Как вариант: можно хранить в каком-нибудь массиве адреса уже срубленных шашек, обнуляя его лишь при передаче хода. (собственно, я примерно так и делал)
(Дамка черных обязана рубить следующим путём: h4:e1:c3:e5 и останавливаться, так как шашка g3 всё ещё на доске. После этого белые рубят в дамки и выигрывают)
Весь этот алгоритм можно очень кратко описать следующей блок-схемой:
Первый клик:
Второй клик:
Чтобы программа поняла, где первый клик, а где второй, — создадим логическую переменную, false = первый клик, true = второй клик.
В общем-то, на этом реализация правил игры заканчиваются. Всё выглядит относительно несложно, но при переносе алгоритма в код возникает множество мелких проблем и трудностей, из-за которых код всё разбухает и разбухает. Виноват в этом сам принцип реализации доски, выбранный мной, но это лучшее из того, что пришло в голову за те две-три недели (да и те с ощутимыми перерывами), так как все действия максимально наглядны, запутаться практически невозможно, а код читается достаточно легко. Полагаю, что пожертвовать ради этого лаконичностью кода — допустимо.
Искусственный Интеллект
Однако на этом наши приключения не заканчиваются. Замечательно, что мы научили шашки двигаться, но с кем же мы будем играть? Нам необходимо создать искусственный интеллект для игры. К сожалению, полноценно его реализовать у меня так и не получилось, так как из-за плохой оптимизации программа начинала виснуть при просчете далее, чем на 5-6 ходов (порядка 20-25 тысяч позиций). При реализации я пользовался книгой Программирование шахмат и других логических игр и рекомендую её всем, кто заинтересуется проблемой ИИ в логических играх. Я остановился на улучшенном алгоритме «альфа-бета отсечений», но описывать здесь я его не буду, потому что он уже много раз на Хабре был описан до меня, например:
К несчастью, концепция моего проекта на конкурс, как я уже говорил в начале, поменялась — поэтому ИИ так и остался недоделанным и был отброшен в дальний ящик. Некоторые принципы оценки позиции, которые я успел сформулировать — тоже. Я мог бы привести их здесь, но особого интереса из-за своей специфичности они не представляют. Если кому-то будет интересно, то могу написать отдельную статью про функцию оценки и алгоритм отсечений. Так как всё это дело происходило полгода назад и статью я писал в основном по памяти, то где-то могли возникнуть неточности или несоответствия, буду рад, если вы укажите мне на них в комментариях. Если что-то нужно расписать более подробно, то обращайтесь там же. Спасибо за внимание.
Все мы знакомы с Excel. Вот и я, душный банковский служащий, что-то да слышал об этом инструменте.
Одни люди умеют лишь форматировать ячейки, другие создают клоны Doom, используя встроенный в Microsoft Office язык программирования.
Я не претендую на второй тип, но и к первым себя не отношу. Для меня Visual Basic for Applications, или VBA, стал тем первым ЯП, который заинтересовал и позволил уверовать в свои силы. Путешествие в этот интересный мир началось с автоматической записи макросов и разбора созданного программой кода.
Как начинающему программисту-самоучке, мне приходилось активно шерстить интернет в поисках решения возникающих проблем. Огромное коммьюнити, большое количество тематических сайтов и, на крайний случай, справка Microsoft помогали в решении практически любой проблемы.
Однако наступил такой момент, когда все рабочие задачи оказались решены и автоматизированы, а внутреннему программисту (ха-ха) все ещё хотелось чего-то большего.
Тогда меня осенило! В Excel ведь можно делать игры. Первая же найденная статья от программиста, который в армии клепал на основе VBA разные вещи, подтвердила мою теорию.
Эта серия статей не была задумана как обучающая (ведь я сам ещё учусь), но если что-нибудь изложенное будет полезно начинающим программистам, которые только погружаются в мир Visual Basic, то считайте, что я пополнил интернет одной полезной ссылкой.
Вторая цель создания цикла заключается в самообразовании и развитии навыков. Я буду ставить себе определенную цель, а потом исполнять ее наиболее приближенной к задумке.
К тому же где, как не в комментариях, мне доходчиво и культурным языком укажут на допущенные ошибки?
Я постараюсь объяснять все подробно, но без углубления в простейшие истины. Не буду рассказывать, что такое переменные, циклы или массивы. Всю эту информацию, изложенную доступным языком, можно найти в интернете.
В этих статьях я буду описывать процесс создания игр в Excel, начиная с простейших пятнашек и заканчивая глобальной RPG. Это позволит мне больше углубиться в тему, а вам поглумиться над неумехой-программистом. Или, в лучшем случае, забрать готовое решение на работу и скрывать безделье за мнимой подготовкой отчета. Ссылки на все исходные материалы будут в свободном доступе.
Темы первых статей цикла уже определены. В этой статье я расскажу, как сделать пятнашки в Excel. В следующий раз разберу создание игры в стиле Toon Blast.
Если вам, к моему удивлению, будет интересен такой формат, то пишите в комментариях, какого типа игры вы бы хотели, чтобы я реализовал на базе Excel.
Необходимо определиться с игровым полем. В данном случае все просто. Что есть пятнашки? Диапазон размером 4 на 4 ячейки, что в сумме даёт 16 ячеек. Переименовываем первый лист (по желанию), приводим нужные ячейки к квадратной форме и декорируем, как душе угодно. Получается примерно следующее:
На этом этапе необходимо в случайном порядке расположить числа от 1 до 15, а также пустое поле на выбранном диапазоне. Для этого открываем окно редактирования кода (Alt + F11), добавляем простой модуль (при желании и его можно переименовать для красоты).
Создаем публичную переменную rngPlayField, которая будет хранить координаты нашего игрового поля, и в методе initializeField() пишем следующий код:
Public rngPlayField As Range Sub initializeField() Dim collNumbers As New Collection, countNumbers As Byte, rndNumber As Byte, fndCells As Range Set rngPlayField = Sheets("MAIN").Range("B2:E5") 'игровой диапазон For countNumbers = 1 To 16 'формируем коллекцию чисел collNumbers.Add countNumbers Next For Each fndCells In rngPlayField.Cells 'цикл для каждого элемента на игровом поле rndNumber = Application.WorksheetFunction.RandBetween(1, collNumbers.Count) 'случайное число от 1 до количества элементов в коллекции fndCells.Value = collNumbers.Item(rndNumber) 'значение ячейки = случайное число из коллекции collNumbers.Remove rndNumber 'удаляем использованное число из коллекции Next Call decorateField 'вызываем декорирование поля End SubСперва метод создаёт коллекцию чисел от 1 до 16.
Я заметил особенность, что в VBA в большинстве случаев удобнее пользоваться коллекциями элементов, чем одномерными массивами. В моей практике были и такие случаи, когда приходилось использовать коллекции массивов (возможно, из-за моей некомпетентности).
InitializeField() запускает цикл For Each, который распространяется на каждую ячейку нашего диапазона. На первом этапе цикла программа рассчитывает случайное число от 1 до значения размера нашей коллекции (в настоящий момент 16) и помещает в первую ячейку диапазона число, хранящееся в коллекции под полученным случайным индексом.
Далее цикл удаляет из коллекции использованное число и переходит к следующей ячейке.
На последующих этапах происходит то же самое, за тем исключением, что размер коллекции постепенно уменьшается, пока в ней не останется ни одного числа, а все ячейки окажутся заполненными.
UPD. Уже в процессе написания статьи я выяснил, что не все комбинации, полученные таким образом, изначально решаемы. Тогда мной в ускоренном темпе был написан код, который сперва формирует правильное поле от 1 до 16, а затем в стиле песков времени разбирает пятнашки в течении 300 ходов (что мы собственно и делаем в реальной жизни, когда хотим "рестартнуть" игру). Направление движения "костяшки" рассчитывается случайным образом.
Sub createRightField() Dim countNumbers As Byte, fndCells As Range, countMoves As Integer, byteRndDir As Byte, fndRndRange As Range countNumbers = 1 For Each fndCells In rngPlayField.Cells 'заполняем поле значениями от 1 до 16 fndCells.Value = countNumbers countNumbers = countNumbers + 1 Next While countMoves < 300 byteRndDir = 3 * Rnd() + 1 ' 1 - up, 2 - down, 3 - left, 4 - right For Each fndRndRange In rngPlayField.Cells If fndRndRange.Value = 16 Then Select Case byteRndDir 'выбор направления Case 1 If fndRndRange.Offset(-1, 0) <> "" Then fndRndRange.Value = fndRndRange.Offset(-1, 0) fndRndRange.Offset(-1, 0) = 16 countMoves = countMoves + 1 End If Case 2 If fndRndRange.Offset(1, 0) <> "" Then fndRndRange.Value = fndRndRange.Offset(1, 0) fndRndRange.Offset(1, 0) = 16 countMoves = countMoves + 1 End If Case 3 If fndRndRange.Offset(0, -1) <> "" Then fndRndRange.Value = fndRndRange.Offset(0, -1) fndRndRange.Offset(0, -1) = 16 countMoves = countMoves + 1 End If Case 4 If fndRndRange.Offset(0, 1) <> "" Then fndRndRange.Value = fndRndRange.Offset(0, 1) fndRndRange.Offset(0, 1) = 16 countMoves = countMoves + 1 End If End Select End If Next Wend Call decorateField End SubСперва создаём обработчик события нажатия на определенную ячейку. Для этого в модуле листа, на котором расположено игровое поле, формируем метод Worksheet_SelectionChange и пишем в нем следующий код. Переменная Target при этом содержит адрес выбранной ячейки.
Private Sub Worksheet_SelectionChange(ByVal Target As Range) Set rngPlayField = Sheets("MAIN").Range("B2:E5") If Target.Cells.Count > 1 Then Exit Sub ElseIf Not Application.Intersect(rngPlayField, Target) Is Nothing Then 'считывает вхождение нажатой ячейки в игровое поле Call moveCells(Target) End If End SubПри выборе диапазона ячеек (больше одной), а также если выбранная ячейка не относится к игровому полю, программа завершает работу.
В ином случае запускается метод имитации движения цифр, принимающий адрес выбранной ячейки в качестве аргумента.
В основном модуле в методе moveCells(byVal rngCell as range) пишем следующее:
Sub moveCells(ByVal rngCell As Range) 'процедура нажатия на ячейку с числом Dim checkCells As Integer For checkCells = -1 To 1 Step 2 'цикл для проверки ячеек слева/справа и сверху/снизу от выбранной ячейки If rngCell.Offset(checkCells, 0).Value = 16 And Not Application.Intersect(rngPlayField, rngCell.Offset(checkCells, 0)) Is Nothing Then 'проверка сверху/снизу rngCell.Offset(checkCells, 0).Value = rngCell.Value rngCell.Value = 16 ElseIf rngCell.Offset(0, checkCells).Value = 16 And Not Application.Intersect(rngPlayField, rngCell.Offset(0, checkCells)) Is Nothing Then 'проверка слева/справа rngCell.Offset(0, checkCells).Value = rngCell.Value rngCell.Value = 16 End If Next Call decorateField ' вызываем декорирование поляЦикл проверяет, есть ли слева, справа, снизу или сверху от нажатой ячейки пустое поле (его имитирует число 16) и считывает вхождение смещенной ячейки в диапазон игрового поля. Если условия выполнены, то программа просто меняет числа местами.
Декорирование игрового поля и проверка победы в методе decorateField()Создаём в рабочей книге второй лист и размещаем на нем победный вариант. Пример:
Далее пишем следующий код:
Sub decorateField() 'декорирует и проверяет на победу Dim fndZero As Range, rngRightData As Range, countRows As Byte, countColumns As Byte, countRight As Integer Set rngRightData = Sheets("DATA").Range("A1:D4") 'диапазон с правильными значениями For countRows = 1 To 4 For countColumns = 1 To 4 If rngPlayField.Cells(countRows, countColumns) = rngRightData.Cells(countRows, countColumns) rngPlayField.Cells(countRows, countColumns) <> 16 Then 'декорирование правильной позиции With rngPlayField.Cells(countRows, countColumns) .Interior.Color = RGB(0, 150, 0) 'vbGreen показался мне слишком ярким .Font.Color = vbWhite End With countRight = countRight + 1 Else With rngPlayField.Cells(countRows, countColumns) .Interior.Color = xlNone .Font.Color = vbBlack End With End If Next Next For Each fndZero In rngPlayField 'цвет шрифта для нуля If fndZero = 16 Then fndZero.Font.Color = vbWhite End If Next If countRight = 15 Then 'проверка победы MsgBox "Победа!", vbExclamation, "Победа" End If End SubДанная программа с помощью цикла проверяет значение каждой ячейки игрового поля на соответствие аналогичной ячейке поля с победной расстановкой значений и закрашивает правильные варианты в зелёный цвет. И наоборот. Далее метод проверяет поле на наличие числа 16 (которое имитирует пустую "костяшку", не забываем) и устанавливает для шрифта белый цвет. Последний момент: проверка победы. При каждом совпадении каких-либо чисел с правильной позицией увеличивается переменная countRight, и когда ее значение станет равно 15, игра сообщит о победе.
В итоге должно получиться примерно следующее:
Вот таким нехитрым образом можно создать себе развлечение на случай скучных рабочих дней. А тем временем на ум приходит следующая картинка:
При желании в игру можно добавить подсчет ходов, рейтинговую таблицу или график динамики побед.
Сейчас же я считаю, что на этом можно остановиться.
Следующая статья выйдет When it's done. Скорее всего в течение недели.
Перейдем к следующему примеру — необходимо разработать несложную игру. На рабочем листе (рис. 1.42) следует разместить пять окон для изображений (элементы управления типа «Изображение»). При этом два окна будут основными — расположены слева и большие по размеру. Другие три окна имеют меньшие размеры и расположены в правой части рабочего листа (они будут содержать эталонные изображения). Также на рис. 1.42 расположены две кнопки и две надписи, при этом надпись Результат является просто поясняющей, и далее мы ее упоминать не будем.
Теперь смысл игры. Предварительно в три маленьких окна в правой части листа выводятся три различные картинки (условно их можно называть эталонными). При щелчке на кнопке Бросок в каждое из двух основных окон для изображений должна попадать (случайным образом) одна из трех возможных картинок (из набора эталонных, которые видны на экране). Если в результате такого случайного выбора картинки в обоих основных окнах совпадают, то в элемент управления «Надпись» для результата добавляется 3 балла, а если нет, то вычитается 1 балл.
Рис. 1.42. Интерфейс разрабатываемой игры
Нам также потребуется датчик случайных чисел — здесь мы воспользуемся уже знакомой функцией Rnd. На первом этапе необходимо дать имена объектам в соответствии с табл. 1.2. Назначение элементов достаточно очевидно. Нескольких слов заслуживает элемент «Надпись» Res для отображения результата. В ней вычисляется суммарный результат по итогам серии произведенных бросков. А по щелчку на кнопке Начать игру снова значение результата обнуляется. Таким образом, вступительная часть перед программированием завершена, и поэтому перейдем к описанию программного кода.
Для того чтобы между сеансами работы на компьютере текущий результат сохранялся, отведем для него ячейку в первой строке на листе — М1. В начале в нее необходимо записать ноль. После каждого броска в эту ячейку программно будет записываться результат. В этом случае при сохранении книги предыдущий результат сохраняется в ячейке М1. Процедура, выполняемая при открытии книги, должна извлечь из ячейки М1 предыдущий результат, и тогда пользователь будет иметь возможность продолжить игру.
В качестве первого программного фрагмента оформим процедуру, выполняемую при открытии книги, так, как представлено в листинге 1.26. Здесь в надпись для результата подставляется содержимое ячейки М1 с первого листа книги.
' Листинг 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.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).
Читайте также:
- Включите cookie и javascript в браузере для продолжения работы с реестром спутник
- Как сделать туман в after effects
- В чем заключается преимущество единого окна для клиента при использовании 1с коннект
- Вылетает дискорд на телефоне во время игры
- Где располагается и как настраивается панель быстрого доступа в окне ms powerpoint 2007