Hunt the Wumpus forever или Охота на Вампуса по-русски
Какая компьютерная игра была первой игрой на карте-графе, первой текстовой и вообще первой приключенческой игрой на свете? Наверное, всё-таки Вампус.
Программисты до сих пор любят её, боюсь, что нужно быть программистом, чтобы понять, почему :)
А вот найти классические консольно-текстовые реализации с исходниками уже непросто, кажется, проще сделать заново, ну и пусть будет с русскоязычным интерфейсом заодно.
Проверил в консоли Studio 2019, для запуска игры код нужно скомпилировать и выполнить, а для этого хватит вставки листинга в единственный файл нового пустого проекта C++. Никаких цветных пятен, правильная чёрно-белая классика :) В исходнике есть специфичный для Studio код (см. строчку подключения файла windows.h
).
#include <iostream> #include <cstdlib> /* srand, rand */ #include <ctime> /* time */ #include <clocale> /* setlocale */ #include <windows.h> /* SetConsoleCP, SetConsoleOutputCP */ using namespace std; const static int adjacentRooms[20][3] = { // Додекаэдр комнат {1, 4, 7}, {0, 2, 9}, {1, 3, 11}, {2, 4, 13}, {0, 3, 5}, {4, 6, 14}, {5, 7, 16}, {0, 6, 8}, {7, 9, 17}, {1, 8, 10}, {9, 11, 18}, {2, 10, 12}, {11, 13, 19}, {3, 12, 14}, {5, 13, 15}, {14, 16, 19}, {6, 15, 17}, {8, 16, 18}, {10, 17, 19}, {12, 15, 18} }; class WumpusGame { private: int numberOfRooms, currentRoom, startingPosition, wumpusRoom, batRoom1, batRoom2, pitRoom1, pitRoom2, //где вампус, мыши, ямы wumpusStart, bat1Start, bat2Start; //кто в какой комнате bool playerAlive, wumpusAlive; //кто жив int numArrows; //стрелы void PlacePits(); void PlaceBats(); void PlaceWumpus(); void PlacePlayer(); bool IsValidMove (int); bool IsRoomAdjacent (int, int); int Move(int); void InspectCurrentRoom(); void PerformAction(int); void MoveStartledWumpus(int); void PlayGame(); void PlayAgain(); void PrintInstructions(); public: WumpusGame(); void StartGame(); static void clearInput() { cin.clear(); cin.ignore(10000, '\n'); } }; WumpusGame::WumpusGame() { numberOfRooms = 20; } void WumpusGame::PrintInstructions() { char wait; cout << endl << "Игра 'Охота на Вампуса', оригинальный (С) Gregory Yob, 1972" << endl << endl << "Вампус живет в пещере из 20 комнат. В каждой комнате есть 3 туннеля, ведущих в" << endl << "соседние комнаты. Посмотрите на додекаэдр, чтобы увидеть, как это устроено." << endl << "В двух комнатах есть бездонные ямы. Если вы войдёте туда, вы упадёте в яму и" << endl << "проиграете." << endl << "В двух других комнатах есть летучие мыши. Если вы войдёте туда, мышь хватает" << endl << "вас и уносит в другую случайно выбранную комнату. Сама мышь после этого тоже" << endl << "перемещается в случайное место на карте." << endl << "У Вампуса ноги на присосках и он слишком велик для того, чтобы мыши могли его" << endl << "побеспокоить. Обычно он спит. Его могут разбудить две вещи: если вы стреляте" << endl << "или же входите в его комнату. Если Вампус проснется, то есть 3 шанса из 4, что" << endl << "он перейдёт в соседнюю комнату и 1 шанс из 4, что он останется на месте." << endl << "Если вы окажетесь в одной комнате с Вампусом, он съест вас :(" << endl << "За один ход вы можете перейти в смежную комнату или выстрелить в неё. У вас" << endl << "всего 3 стрелы. Вы проиграете, когда они закончатся. Если указать комнату, в" << endl << "которую невозмоно выстрелить, то стрела пропадёт зря." << endl << "Когда вы находитесь в смежной комнате с опасностью, выводятся предупреждения:" << endl << "\"Я чувствую отвратительный запах\" (если рядом Вампус)" << endl << "\"Летучие мыши рядом\"" << endl << "\"Я чувствую сквозняк\" (если рядом - бездонная яма)" << endl << "Введите что-нибудь, чтобы вернуться в главное меню."; cin >> wait; } void WumpusGame::PlaceBats() { bool validRoom = false; while (!validRoom) { batRoom1 = rand() % numberOfRooms + 1; if (batRoom1 != wumpusRoom) validRoom = true; } validRoom = false; while (!validRoom) { batRoom2 = rand() % numberOfRooms + 1; if (batRoom2 != wumpusRoom && batRoom2 != batRoom1) validRoom = true; } bat1Start = batRoom1; bat2Start = batRoom2; } void WumpusGame::PlacePits() { pitRoom1 = rand() % 20 + 1; pitRoom2 = rand() % 20 + 1; } void WumpusGame::PlaceWumpus() { int randomRoom = rand() % 20 + 1; wumpusRoom = randomRoom; wumpusStart = wumpusRoom; } void WumpusGame::PlacePlayer() { startingPosition = 0; currentRoom = Move(0); } bool WumpusGame::IsValidMove(int roomID) { if (roomID < 0) return false; if (roomID > numberOfRooms) return false; if (!IsRoomAdjacent(currentRoom, roomID)) return false; return true; } bool WumpusGame::IsRoomAdjacent(int roomA, int roomB) { for (int j = 0; j < 3; j++) { if (adjacentRooms[roomA][j] == roomB) return true; } return false; } int WumpusGame::Move (int newRoom) { return newRoom; } void WumpusGame::InspectCurrentRoom() { if (currentRoom == wumpusRoom) { cout << endl << "Вампус съел вас, игра окончена :(" << endl; PlayAgain(); } else if (currentRoom == batRoom1 || currentRoom == batRoom2) { int roomBatsLeft = currentRoom; bool validNewBatRoom = false; bool isBatRoom = false; cout << endl << "Вы схвачены летучей мышью!" << endl; if (currentRoom == pitRoom1 || currentRoom == pitRoom2) cout << endl << "К счастью, летучая мышь спасла вас от бездонной ямы" << endl; while (!isBatRoom) { currentRoom = Move(rand() % numberOfRooms + 1); if (currentRoom != batRoom1 && currentRoom != batRoom2) isBatRoom = true; } cout << endl << "Летучая мышь перенесла вас в комнату " << currentRoom << endl; InspectCurrentRoom(); if (roomBatsLeft == batRoom1) { while (!validNewBatRoom) { batRoom1 = rand() % (numberOfRooms-1) + 1; if (batRoom1 != wumpusRoom && batRoom1 != currentRoom) validNewBatRoom = true; } } else { while (!validNewBatRoom) { batRoom2 = rand() % (numberOfRooms-1) + 1; if (batRoom2 != wumpusRoom && batRoom2 != currentRoom) validNewBatRoom = true; } } } else if (currentRoom == pitRoom1 || currentRoom == pitRoom2) { cout << endl << "Вы свалились в бездонную яму, игра окончена :(" << endl; PlayAgain(); } else { cout << endl << "Вы находитесь в комнате " << currentRoom << endl; if (IsRoomAdjacent(currentRoom, wumpusRoom)) { cout << endl << "Я чувствую отвратительный запах..." << endl; } if (IsRoomAdjacent(currentRoom, batRoom1) || IsRoomAdjacent(currentRoom, batRoom2)) { cout << endl << "Летучие мыши рядом..." << endl; } if (IsRoomAdjacent(currentRoom, pitRoom1) || IsRoomAdjacent(currentRoom, pitRoom2)) { cout << endl << "Я чувствую сквозняк..." << endl; } cout << endl << "Туннели ведут в комнаты "; for (int j = 0; j < 3; j++) cout << adjacentRooms[currentRoom][j] << (j < 2 ? ", " : ""); cout << endl; } } void WumpusGame::PerformAction(int cmd) { int newRoom; switch (cmd) { case 1: cout << endl << "В какую комнату пойдете? "; try { cin >> newRoom; if (cin.fail()) throw invalid_argument ("Вы должны ввести число!"); if (IsValidMove(newRoom)) { currentRoom = Move(newRoom); InspectCurrentRoom(); } else { cout << endl << "Вы не можете сейчас перейти в эту комнату :(" << endl; } } catch (invalid_argument& error) { WumpusGame::clearInput(); cerr << endl << error.what() << endl; } break; case 2: if (numArrows > 0) { cout << endl << "В какую комнату будете стрелять? " << endl; try { cin >> newRoom; if (cin.fail()) throw invalid_argument("Вы должны ввести число!"); if (IsValidMove(newRoom)) { numArrows--; if (newRoom == wumpusRoom) { wumpusAlive = false; cout << endl << "Примите поздравления! Вы убили Вампуса и победили!" << endl; cout << endl << "Введите что-нибудь, чтобы вернуться в главное меню" << endl; cin >> newRoom; WumpusGame::clearInput(); } else { cout << endl << "Мимо! Но вы побеспокоили Вампуса..." << endl; MoveStartledWumpus(wumpusRoom); cout << endl << "Осталось стрел: " << numArrows << endl; if (wumpusRoom == currentRoom) { cout << endl << "Вампус ворвался в вашу комнату и сожрал вас, игра окончена :(" << endl; PlayAgain(); } } } else { cout << endl << "Вы не можете стрелять в эту комнату :(" << endl; } } catch (invalid_argument& error) { WumpusGame::clearInput(); cerr << endl << error.what() << endl; } } else { cout << endl << "У вас больше нет ни одной стрелы :(" << endl; } break; case 3: cout << endl << "Выходим из текущей игры..." << endl; playerAlive = false; break; default: cout << endl << "Пожалуйста, выберите правильное действие в меню" << endl; break; } } void WumpusGame::MoveStartledWumpus(int roomNum) { int rando = rand() % 3; if (rando != 3) wumpusRoom = adjacentRooms[roomNum][rando]; } void WumpusGame::PlayAgain() { char reply; cout << endl << "Хотите сыграть заново на этой же карте? Введите Y для новой игры" << endl; cin >> reply; if (reply == 'y' || reply == 'Y') { currentRoom = startingPosition; wumpusRoom = wumpusStart; batRoom1 = bat1Start; batRoom2 = bat2Start; cout << endl << "Начата новая игра" << endl; InspectCurrentRoom(); } else { playerAlive = false; } } void WumpusGame::PlayGame() { int choice; bool validChoice = false; cout << endl << "Запускаем игру..." << endl; PlaceWumpus(); PlaceBats(); PlacePits(); PlacePlayer(); playerAlive = true; wumpusAlive = true; numArrows = 3; InspectCurrentRoom(); while (playerAlive && wumpusAlive) { //Игровой цикл cout << endl << "Выберите действие" << endl << endl << "1) Идти" << endl << "2) Стрельба" << endl << "3) Выход"; do { validChoice = true; cout << endl << "Пожалуйста, выберите пункт меню: "; try { cin >> choice; switch (choice) { case 1: PerformAction(1); break; case 2: PerformAction(2); break; case 3: PerformAction(3); break; default: validChoice = false; cout << endl << "Неверный выбор, попробуем ещё раз" << endl; WumpusGame::clearInput(); break; } } catch (...) { validChoice = false; cout << endl << "Неверный выбор, попробуем ещё раз" << endl; WumpusGame::clearInput(); } } while (validChoice == false); } } void WumpusGame::StartGame() { srand(time(NULL)); int choice; bool validChoice; bool keepPlaying; wumpusStart = bat1Start = bat2Start = -1; do { keepPlaying = true; cout << endl << "Добро пожаловать в \"Охоту на Вампуса\"" << endl << endl << "1) Новая игра" << endl << "2) Помощь" << endl << "3) Выход" << endl; do { validChoice = true; cout << endl << "Пожалуйста, выберите пункт меню: "; try { cin >> choice; switch (choice) { case 1: PlayGame(); break; case 2: PrintInstructions(); break; case 3: cout << endl << "Выполняем выход..." << endl; keepPlaying = false; break; default: validChoice = false; cout << endl << "Неверный выбор, попробуем ещё раз" << endl; WumpusGame::clearInput(); break; } } catch (...) { validChoice = false; cout << endl << "Неверный выбор, попробуем ещё раз" << endl; WumpusGame::clearInput(); } } while (validChoice == false); } while (keepPlaying); } int main() { setlocale(LC_ALL, "Rus"); SetConsoleCP(1251); SetConsoleOutputCP(1251); WumpusGame game; game.StartGame(); return 0; }
Скриншот запущенной игры Вампус
13.06.2020, 08:16 [1560 просмотров]