Что же именно мы будем делать. Смысл игры в том, чтобы добраться к выходу из лабиринта. Игровой процесс выглядит так. Перед вами есть план лабиринта, на котором указана ваша позиция. Вводя направление движения вам необходимо дойти к выходу. При этом движение назад или на стену означает попадание в ловушку и как следствие – проигрыш.
Как это будет реализовано. Реализовано это, как и в прошлый раз, будет в виде диалога. Программа сначала выводит небольшое сюжетное введение, а затем последовательно запрашивает у вас данные. Лабиринт разбит на сектора, каждая из которых имеет свой номер. Поскольку нумерация по горизонтали и вертикали одинакова, программа сначала спрашивает направление движения(по горизонтали или по вертикали), а затем номер сектора. От выбора будет зависеть продолжение игры или проигрыш. В случае продолжения лабиринт обновляется, указывая на новую позицию игрока. При выводе текста должны быть подсказки по управлению программой.
Что для этого понадобится. Вот тут я вас обрадую. Все что нужно вы уже знаете. Поэтому вам понадобится только терпение, сообразительность и внимание поскольку программа содержит свыше 400 строк кода. Правда 50 строк, в небольшой вариации, повторяются шесть раз.
Приступаем. Вспоминаем первый урок, открываем студию и создаем новый проект, который я назвал labyrinth. Затем добавляем в него файл исходного кода и начинаем писать программу. Для этого может скопировать исходный код из нашей игры «Осада», и удалить оттуда, из главной функции main все, кроме строчки
Code
setlocale( LC_ALL, "Russian" );
Она нам еще понадобится. Далее объявляем четыре переменные:
Code
int i; // переменная для направления int num; // номер сектора bool GameOver = false; // эта переменная сигнализирует о проигрыше. int goRes; // вариант проигрыша
Первые две используются для получения данных при вводе. Вторая, логическая переменная GameOver, меняет свое значение в случае возникновения проигрышной ситуации. Переменной сразу же присваивается значение. В принципе в данном случае этого можно и не делать, поскольку при его отсутствии, переменная все равно считается ложной. Как только она становится истинной весь дальнейший код начинает игнорироваться. В переменной goRes будет содержатся информация о способе проигрыша. Может он произошел в результате введения некорректных данных, может вы попали в ловушку и т.д. После переменных выводится небольшое сюжетное введение, дается пояснение по управлению программой и выводится план лабиринта. Я не буду это здесь иллюстрировать, можете посмотреть дальше в коде всей программы. Перемещение по лабиринту происходит в виде последовательных шагов. Далее в коде идет основная конструкция нашей программы, в которой производится обработка каждого шага:
Code
// Шаг № 1 if(!GameOver) { // Ввод информации о перемещении cout << "Как вы будете двигаться, по горизонтали[Введите 1] или по вертикали[2]?\n"; cin >> i; cout << "Укажите номер сектора, куда вы желаете переместится?\n"; cin >> num;
if(i == 1) //Если движение по горизонтали { switch(num) //обработка номера сектора { case 1: goRes = 6; GameOver = true; break; case 2: case 3: goRes = 4; GameOver = true; break; default: // значение по умолчанию, если введено некорректное значение goRes = 2; GameOver = true; } } else { if(i == 2) //Если движение по вертикали { switch(num) //обработка номера сектора { case 1: case 3: goRes = 5; GameOver = true; break; case 2: cout << "\nВы благополучно продвинулись вперед по подземелью\n"; cout << " ____ \n"; cout << "3| | |\n"; cout << "2|0|___|\n"; cout << "1|_____|\n"; cout << " 1 2 3\n"; break; default: // значение по умолчанию, если введено некорректное значение goRes = 2; GameOver = true; } } else // если введено некорректное значение { goRes = 1; GameOver = true; } } }
В самом начале находится оператор ветвления, который проверяет состояние переменной GameOver.
Code
if(!GameOver)
Дальнейший код мог бы исполняться, только если условие истинно. Тогда как переменная GameOver ложная. Поставленный логический оператор !(НЕ) и превращает ложь в правду. Вообще-то в первом шаге эта проверка не нужна, но чтобы в дальнейшем иметь возможность просто скопировать эти строки дальше, я и поставил его с самого начала. Ведь правильной работе он не мешает. После проверки, происходит ввод информации и присвоение ее соответствующим переменным. Далее с помощью все того же оператора ветвления происходит проверка первой переменной – i для направления движения, и выполняется соответствующий блок кода для конкретной сектора. Эта проверка построена по уже знакомому принципу, последующая проверка производится только если первое условие ложное. Также обрабатывается и вариант, когда оба условия не правильные, то есть если введено некорректное значение. Проверка сектора производится с помощью оператора switch.
Code
switch(num) //обработка номера сектора { case 1: goRes = 6; GameOver = true; break; case 2: case 3: goRes = 4; GameOver = true; break; default: // значение по умолчанию, если введено некорректное значение goRes = 2; GameOver = true; }
В зависимости от введенного номера и текущей ситуации, то есть положения в лабиринте, в операторе case происходят действия определения проигрыша. Если эта проигрышная ситуация возникает то переменной GameOver присваивается значение true, а переменной goRes значение варианта проигрыша. А если введенные данные некорректные, то в этом случае срабатывает вариант по умолчанию. И только один вариант должен быть правильным. В этом случае программа выводит подтверждение о правильности хода, и обновленный план лабиринта с изменившейся позицией игрока:
С кодом одного шага разобрались, теперь необходимо его размножить и внести изменения, соответствующие правильному движению по лабиринту. У меня это шесть шагов. После совершения всех шагов находится код вывода результата:
Code
if(GameOver) { switch (goRes) { case 1: cout << "\nВы выбрали иное направление, и попытались проломить головой пол,\n" << "если бы у вас были мозги, то они бы растеклись по полу\n"; break; case 2: cout << "\nБлин, вы цифры знаете, или со зрением проблемы.\n" << "Вобщем, вы достали из ножен свой топор и им застрелились.\n"; break; case 3: cout << "\nВы сделали неосторожный шаг назад \n" << "и свалились в бездонную пропасть.\n"; break; case 4: cout << "\nВы попали в ловушку\n" << "Расколов каменный пол, стальные колья пронзили ваши тела\n"; break; case 5: cout << "\nВы попали в ловушку\n" << "Зловонная жижа заполнила коридор. Вы захлебнулись\n"; break; case 6: cout << "\nВы попали в ловушку\n" << "Стены подземелья сомкнулись, растерев вас в пыль\n"; break; }
cout << "\nВ темных закоулках страшного подземелья вас подстерегла смерть.\n" << "ВЫ ПРОИГРАЛИ!\n"; } else { cout << "\nНу вот и свет в конце тонеля. Вы вышли из лабиринта. Поздравляю.\n" << "ПОБЕДА!\n"; }
Здесь вновь проверяется переменная GameOver. Но на этот раз в ее настоящем значении, без логического оператора.
Code
if(GameOver)
Если ее значение – истина, то это означает, что в игре возникла ситуация, когда игрок проиграл. Поэтому дальше производится проверка переменной и вывод соответствующего ей значения.
Code
switch (goRes) { case 1: cout << "\nВы выбрали иное направление, и попытались проломить головой пол,\n" << "если бы у вас были мозги, то они бы растеклись по полу\n"; break; case 2: cout << "\nБлин, вы цифры знаете, или со зрением проблемы.\n" << "Вобщем, вы достали из ножен свой топор и им застрелились.\n"; break; case 3: cout << "\nВы сделали неосторожный шаг назад \n" << "и свалились в бездонную пропасть.\n"; break; case 4: cout << "\nВы попали в ловушку\n" << "Расколов каменный пол, стальные колья пронзили ваши тела\n"; break; case 5: cout << "\nВы попали в ловушку\n" << "Зловонная жижа заполнила коридор. Вы захлебнулись\n"; break; case 6: cout << "\nВы попали в ловушку\n" << "Стены подземелья сомкнулись, растерев вас в пыль\n"; break; }
Конечно, можно было сделать вывод этих сообщений в том месте кода, где мы присваивали переменной goRes значение. Но в таком случае размер программы стал бы значительно больше, контролировать ее стало бы труднее. Да и появись в тексте сообщения ошибка, ее бы пришлось править везде, а так только в одном месте. После вывода это сообщения программа выводит еще одно, финальное: