Программирование игр. Урок 2. Основные структуры в алгоритме.
Основные структуры в алгоритме.
На прошлом занятии мы познакомились с вами с алгоритмами, сегодня мы рассмотрим основные структуры в алгоритме для управления ходом выполнения нашей программы, а также напишем формальный алгоритм для нашей первой игры "Быки и коровы".
Для первой игры нам понадобятся две структуры - это цикл и условие.
Цикл - это повторение одного и того же действия пока не будет выполнено определённое условие.
В нашем первом алгоритме для приготовления чая цикл был из действия перемешивание, а условием для прекращения цикла было растворение сахара, тогда можно прекратить перемешивать чай (остановить цикл).
Циклы в программировании используются очень часто: перебор списка элементов, расчёт каких либо периодически величин (расчёт сумм в бухгалтерии для отчёта по месяцам), регулярные опросы устройств Ввода-вывода. В нашей игре один из главных циклов будет вопрос к игроку, пока игрок не разгадает загадку.
Цикл состоит из условия и тела цикла. Условие определяет будет ли выполняться тело цикл, а тело цикла содержит в себе различные команды, которые будут выполнены.
Условие - структура, которая позволяет выбрать какие действия мы должны выполнить, если наше условие истинно (true) или ложно (false).
К примеру в нашем первом алгоритме было несколько условий, одно из них "проверить есть ли в чайнике вода". Простое условие, если вода есть, наше условие истинно, если нет - ложно. И в зависимости от результата проверки мы либо выполняем действие "включить чайник", либо действие "налить в него воды".
Есть некоторые тонкости с циклами и условиями, но я не хочу перегружать вас информацией, в конце урока я дам вам ссылки, где можно будет почитать подробнее, а пока для наших целей этой информации будет достаточно.
Давайте же наконец приступим к написанию алгоритма для нашей первой игры.
Игра "Быки и коровы".
Это очень простая игра, в которую можно играть вдвоём и без компьютера. Но именно её простота позволяет понять и научится строить алгоритмы, которые потом можно легко запрограммировать.
Быки и коровы — логическая игра, в ходе которой за несколько попыток один из игроков должен определить, что задумал другой игрок. Варианты игры могут зависеть от типа отгадываемой последовательности — это могут быть числа, цвета, пиктограммы или слова. После каждой попытки задумавший игрок выставляет «оценку», указывая количество угаданного без совпадения с их позициями (количество «коров») и полных совпадений (количество «быков»)
Мы возьмём вариант с 4х значным числом и в качестве второго игрока у нас будет компьютер. Для начала напишем весьма упрощённый алгоритм, и будем постепенно усложнять.
- Компьютер загадывает 4х значительно число и сохраняет его в памяти.
- Компьютер предлагает пользователю отгадать число, появляется форма для ввода числа.
- Пользователь вводит свой вариант.
- Компьютер берет вариант пользователя и сравнивает со своим загаданным числом (тут будет наиболее сложная часть программы, но это потом). Вычисляет сколько пользователь угадал цифр на неверных позициях - число "коров" и сколько угадал абсолютно верно - число "быков". Заносит эти данные в переменные.
- Проверяет сколько получилось быков, если их 4, то пользователь угадал число, поздравляем его и идём к шагу (пока не знаем к какому, после написания алгоритма это шаг 8), иначе переходим к шагу 6. (условие)
- Выводит на экран информацию для пользователя о количестве "быков" и "коров" из соответствующих переменных.
- Так как пользователь ещё не отгадал число, переходит к шагу 2 и даёт пользователю ещё одну попытку (цикл).
- Поздравляем пользователя с успешной попыткой! Предлагаем пользователю сыграть ещё раз. Выводим диалог с вопросом и двумя кнопками "ок" и "отмена".
- Если пользователь выбирает "ок" идём к шагу 1, иначе завершаем программу (условие).
Вот такой получился общий алгоритм для нашей игры, но в нем пока не хватает самой сложной математической части - проверки сколько цифр угадал пользователь и подсчёта "быков" и "коров".
Эти действия должны выполняться на шаге 4 нашего общего алгоритма. Давайте напишем отдельный небольшой алгоритм который будет заниматься именно этим. В программировании так делают очень часто и в большинстве языков программирования это называется "функция".
Стоит немного рассказать о функциях в программировании. Функция - это специальная конструкция в языке программирования, которая может принимать аргументы, делать различные вычисления и может, но не обязана возвращать результат. Аргументы - это переменные, которые передаются в функцию в момент вызова. Помните в математике были тригонометрические функции косинуса и синуса?
Y = sin(X)
Вот в программирование все примерно также, sin - это название функции, X - передаваемый аргумент (их может быть несколько, через запятую), а Y - возвращаемое значение.
Так вот, наш подалгоритм будет функцией, которая будет принимать два аргумента - числа: то что загадал компьютер, и то которое указал пользователь. Она будет проводить сравнение и вычислять сколько "быков" и "коров" угадал пользователь и возвращать эту информацию как результат выполнения функции.
4.1. Компьютер вызывает функцию проверки и передаёт в неё свое число и число введённое пользователем.
4.2. Компьютер производит расчёт "коров".
4.3. Компьютер производит расчёт "быков".
4.4. Компьютер возвращает результат расчётов.
Вроде уже почти все есть, но остаётся вопрос: "как нам рассчитать число "коров" и "быков"? Для этого нам надо ещё уточнить два шага нашего алгоритма: 4.2 и 4.3.
Для подсчёта "коров" и "быков" мы должны работать с отдельными цифрами в наших числах, а для этого разбить наши числа на отдельные элементы и сохранить в форме, удобной для дальнейших манипуляций с ними. В программировании такой формой является массив.
"Массив" - (array) - структура данных в виде набора компонентов (элементов массива), расположенных в памяти непосредственно друг за другом, что позволяет обращаться к элементам по числовому индексу.
Преимущества массива в том, что мы можем обратиться к каждому его элементу по индексу, и таким образом мы можем обойти весь массив элементов используя цикл. Давайте посмотрим на примере.
Пусть у нас будет массив фруктов с названием "фрукты" :
['яблоко', 'груша', 'персик', 'манго'].
Получить конкретный элемент массива можно так:
фрукты[0]
Программа вернёт нам наше яблоко. Заметьте что элементы в массиве начинаются с 0.
А чтобы напечатать (или выполнить какие то другие действия) со всеми элементами нашего массива мы можем использовать цикл:
- Создать переменную счётчик и присвоить ей первоначальное значение 0.
- Если переменная счётчик ещё не больше длины массива фрукты перейти к шагу 3, иначе перейти к шагу 6.
- Напечатать элемент массива
фрукты [переменная счётчик]
. - Увеличить переменную счётчик на один.
- Перейти к шагу два.
- Массив распечатан, можно завершить программу.
Вот так все просто. Я оставлю ссылку, что почитать о массивах. Там ещё много всяких тонкостей, но пока нам хватит этого.
Мы объединим два шага для вычисления "коров" и "быков" в один. Для начала разобьем наши числа на составляющие и сохраним в два массива:
4.2.1. Создадим пустой массив numberPcArray.
4.2.2. Создадим пустой массив numberUserArray.
4.2.3. Сохраним в нулевую ячейку каждого массива значение тысяч соответствующего числа.
4.2.4. Сохраним в первую ячейку каждого массива значение сотен соответствующего числа.
4.2.5. Сохраним во вторую ячейку каждого массива значение десятков соответствующего числа.
4.2.6. Сохраним в третью ячейку каждого массива значение единиц соответствующего числа.
Вы возможно спросите, а как нам получить значения тысяч, сотен, десятков и единиц. Тут нам поможет математика и специальные функции в языках программирования.
В большинстве языков программирования есть такие математические операторы как деление без остатка и получить остаток от деления.
Для целочисленного деления в JavaScript
(а мы в дальнейшем будем писать на нем) используется обычное деление, но результат округляется в меньшую сторону.
Math.floor(x/y)
Math - это специальная математическая библиотека в языке JavaScript, которая представляет множество полезных функций. Например мы используем функцию floor - она позволяет округлить число в меньшую сторону (floor с английского пол).
А для получения остатка от деления есть специальный оператор "%"
x % y
Давайте посмотрим на примере.
Возьмём число 3572. Ну а почему бы и нет)
Нам надо его программно разбить на "3", "5", "7" и "2".
Сохраним наше число в переменную number:
number = 3572
Получим из него количество тысяч:
thousands = Math.floor(number/1000)
В итоге получаем 3.
Для получения сотен, нам надо убрать из нашего числа тысячи.
number = number % 1000
Таким образом мы перезаписываем нашу переменную number новым значением, а именно остатком от деления на тысячу. Сейчас в нашей переменной число 572.
Теперь нам нужно повторить эти операции чтобы получить сотни, десятки.
hundreds = Math.floor(number/100)
Получаем 5.
number = number % 100
Остается 72
tens = Math.floor(number/10)
Получаем 7.
singles = number % 10
И остаются единицы 2.
Таким образом мы смогли разбить наше четырехзначное число на четыре отдельных переменных. Вместо переменных правильнее было взять массив и записать значение для каждого разряда в отдельный элемент. Давайте так и сделаем:
numberPcArray = [];
numberUserArray = [];
numberPcArray[0] = Math.floor(numberPc/1000);
numberPc = numberPc % 1000;
numberUserArray[0] = Math.floor(numberUser/1000);
numberUser = numberUser % 1000;
numberPcArray[1] = Math.floor(numberPc/100);
numberPc = numberPc % 100;
numberUserArray[1] = Math.floor(numberUser/100);
numberUser = numberUser % 100;
numberPcArray[2] = Math.floor(numberPc/10);
numberPcArray[3] = numberPc % 10;
numberUserArray[2] = Math.floor(numberUser/10);
numberUserArray[3] = numberUser % 10;
Обратите внимание на точку с запятой в конце каждой строки - это специальный разделитель команд в языках программирования, не во всех конечно так, но в JavaScript именно так.
В итоге мы получили два массива с нашими разбитыми на составляющие числами.
Теперь мы можем сравнивать их по отдельности и посчитать количество наших "коров" и "быков". Для этого нам понадобятся: две переменных счётчика для хранения количества "коров" и "быков", два цикла и пара условий.
4.2.7. Создадим переменную cows и присвоим ей первоначальное значение 0.
4.2.8. Создадим переменную bulls и присвоим ей первоначальное значение 0.
4.2.9. Создадим переменную счётчик для первого цикла (в программировании часто для простых итерации используют переменные с именами i, j, k) i и присвоим ей первоначальное значение 0.
4.2.10. Создадим переменную счётчик для второго цикла j и присвоим ей первоначальное значение 0.
4.2.11. Если i = j (значит мы будем сравнивать цифры наших чисел, стоящие на одинаковых позициях, а это "Быки"), перейти к шагу 4.2.12, иначе перейти к шагу 4.2.13.
4.2.12. Если numberPcArray[i] = numberUserArray[j], то увеличить переменную bulls на один и перейти к шагу 4.2.14, иначе перейти к шагу 4.2.14.
4.2.13. Если numberPcArray[i] = numberUserArray[j], то увеличить переменную cows на один и перейти к шагу 4.2.14, иначе перейти к шагу 4.2.14.
4.2.14. Увеличить переменную счётчик второго цикла на один.
4.2.15. Если j < длинны массива numberPcArray, увеличиваем j на один и переходим к шагу 4.2.11, иначе присваиваем переменной j значение 0 и переходим к шагу 4.2.16.
4.2.16. Если i < длинны массива numberPcArray, увеличиваем i на один и переходим к шагу 4.2.11, иначе переходим к шагу 4.2.17.
4.2.17. Наши циклы отработали и количество "коров" и "быков" посчитано.
Ну вот, получилась большая статья, но давайте соберём наш алгоритм воедино для полной картины.
Полный алгоритм
Компьютер загадывает 4х значительно число и сохраняет его в памяти.
Компьютер предлагает пользователю отгадать число, появляется форма для ввода числа.
Пользователь вводит свой вариант.
Компьютер берет вариант пользователя и сравнивает со своим числом. Вычисляет сколько пользователь угадал цифр на неверных позициях - число "коров" и сколько угадал абсолютно верно - число "быков". Заносит эти данные в переменные.
4.1. Компьютер вызывает функцию проверки и передаёт в неё свое число и число введённое пользователем.
4.2. Компьютер производит расчёт "коров" и "быков".
4.2.1. Создадим пустой массив numberPcArray.
4.2.2. Создадим пустой массив numberUserArray.
4.2.3. Сохраним в нулевую ячейку каждого массива значение тысяч соответствующего числа.
4.2.4. Сохраним в первую ячейку каждого массива значение сотен соответствующего числа.
4.2.5. Сохраним во вторую ячейку каждого массива значение десятков соответствующего числа.
4.2.6. Сохраним в третью ячейку каждого массива значение единиц соответствующего числа.
4.2.7. Создадим переменную cows и присвоим ей первоначальное значение 0.
4.2.8. Создадим переменную bulls и присвоим ей первоначальное значение 0.
4.2.9. Создадим переменную счётчик для первого цикла (в программировании часто для простых итерации используют переменные с именами i, j, k) i и присвоим ей первоначальное значение 0.
4.2.10. Создадим переменную счётчик для второго цикла j и присвоим ей первоначальное значение 0.
4.2.11. Если i = j (значит мы будем сравнивать цифры наших чисел, стоящие на одинаковых позициях, а это "Быки"), перейти к шагу 4.2.12, иначе перейти к шагу 4.2.13.
4.2.12. Если numberPcArray[i] = numberUserArray[j], то увеличить переменную bulls на один и переходим к шагу 4.2.14, иначе переходим к шагу 4.2.14.
4.2.13. Если numberPcArray[i] = numberUserArray[j], то увеличить переменную cows на один и переходим к шагу 4.2.14, иначе переходим к шагу 4.2.14.
4.2.14. Увеличить переменную счётчик второго цикла на один.
4.2.15. Если j < длинны массива numberPcArray, увеличиваем j на один и переходим к шагу 4.2.11, иначе присваивает переменной j значение 0 и переходим к шагу 4.2.16.
4.2.16. Если i < длинны массива numberPcArray, увеличиваем i на один и переходим к шагу 4.2.11, иначе переходим к шагу 4.2.17.
4.2.17. Наши циклы отработали и количество "коров" и "быков" посчитано.
4.3. Компьютер возвращает результат расчётов.
Проверяет сколько получилось быков, если их 4, то пользователь угадал число, поздравляем его и идём к шагу 8, иначе переходим к шагу 6. (условие)
Выводит на экран информацию для пользователя о количестве "быков" и "коров" из соответствующих переменных.
Так как пользователь ещё не отгадал число, переходит к шагу 2 и даёт пользователю ещё одну попытку (цикл).
Поздравляем пользователя с успешной попыткой! Предлагаем пользователю сыграть ещё раз. Выводим диалог с вопросом и двумя кнопки "ок" и" отмена".
Если пользователь выбирает "ок" идём к шагу 1, иначе завершаем программу (условие).
Ну вот мы с вами и написали алгоритм для нашей первой игры. Наверное какие-то моменты получились несколько сумбурные и не до конца понятные. Как обычно я дам ссылки, чтобы почитать подробнее про новые понятия, и буду давать их сразу для языка программирования JavaScript.
На следующем уроке мы начнём программировать. По плану у нас было изучение системы контроля версий, но мы отложим это дело на одно занятие.
Ссылка на первое занятие: Урок 1 - Программирование. Как работает компьютер. Что такое алгоритм.
Ссылки на материалы, чтобы больше узнать о циклах, условиях, массивах, функциях и переменных:
Теги которые я буду использовать и по которым можно будет найти мои статьи:
программированиеигр,
javascript,
phaserjs.
P. S. Данный пост также написан на телефоне, с использованием редактора Markor. Есть незначительные минусы у этого редактора в плане отображения информации.
P. P. S. Клавиатура на телефоне (я использую SwiftKey) не предназначена для набора программ, постоянно пытается вмешаться и все сделать по своему.
P. P. P. S. Писать статьи не так просто, особенно их проверять и редактировать ошибки. Так как я пишу в основном в маршрутке, я уже трижды проезжал свою остановку на пару остановок дальше).
Программировать можно и на телефоне, не очень удобно правда. Попробуйте приложение JS Run. Наша первая программа вполне может быть написана в нем (что я и сделаю на следующем уроке).