Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* Wumpus Cave Game, by skeeto
- * See also: http://redd.it/21kqjq
- * c++ -std=c++11 -Wall wumpus.cc -lncurses -o wumpus
- *
- * This is free and unencumbered software released into the public domain.
- */
- #include <iostream>
- #include <cstdlib>
- #include <ctime>
- #include <deque>
- #include <vector>
- #include <ncurses.h>
- class Vec2 {
- public:
- int x, y;
- Vec2 &operator+=(const Vec2 &rhs) {
- x += rhs.x;
- y += rhs.y;
- return *this;
- }
- Vec2 &operator-=(const Vec2 &rhs) {
- x -= rhs.x;
- y -= rhs.y;
- return *this;
- }
- static Vec2 rand(int min, int max) {
- return Vec2{min + (std::rand() % (max - min)),
- min + (std::rand() % (max - min))};
- }
- };
- Vec2 operator+(Vec2 lhs, Vec2 &rhs) {
- lhs += rhs;
- return lhs;
- }
- Vec2 operator-(Vec2 lhs, Vec2 &rhs) {
- lhs -= rhs;
- return lhs;
- }
- enum Content {
- NONE = '.',
- EXIT = '^',
- GOLD = '$',
- WEAPON = 'W',
- WUMPUS = 'X',
- TRAP = ' ',
- WALL = '#'
- };
- struct Tile {
- public:
- Tile(Content content = Content::NONE, bool explored = false)
- : content{content}, explored{explored} {};
- Content content = Content::NONE;
- bool explored = false;
- };
- const Vec2 kNorth{0, -1}, kSouth{0, 1}, kEast{1, 0}, kWest{-1, 0};
- class Game {
- public:
- Game(int size) : size_{size} {
- for (int y = 0; y <= size_ + 1; y++) {
- for (int x = 0; x <= size_ + 1; x++) {
- if (x == 0 || y == 0 || x == size + 1 || y == size + 1) {
- tiles_[x][y] = {Content::WALL};
- } else {
- double type = rand() / (double)RAND_MAX;
- if (type >= 0.00 && type < 0.15) {
- tiles_[x][y] = {Content::WEAPON};
- } else if (type >= 0.15 && type < 0.30) {
- tiles_[x][y] = {Content::WUMPUS};
- } else if (type >= 0.30 && type < 0.45) {
- tiles_[x][y] = {Content::GOLD};
- } else if (type >= 0.45 && type < 0.50) {
- tiles_[x][y] = {Content::TRAP};
- } else {
- tiles_[x][y] = {Content::NONE};
- }
- }
- }
- }
- player_ = Vec2::rand(1, size + 1);
- tiles_[player_.x][player_.y] = {Content::EXIT, true};
- initscr();
- raw();
- noecho();
- curs_set(0);
- keypad(stdscr, TRUE);
- erase();
- sound();
- }
- ~Game() { endwin(); }
- void draw() {
- for (int y = 0; y <= size_ + 1; y++) {
- for (int x = 0; x <= size_ + 1; x++) {
- draw(x, y);
- }
- }
- draw(player_, '@');
- drawScore();
- refresh();
- }
- void move(Vec2 direction) {
- draw(player_.x, player_.y);
- player_ += direction;
- Tile &t = tiles_[player_.x][player_.y];
- if (t.content == Content::WALL) {
- player_ -= direction;
- } else if (!t.explored) {
- t.explored = true;
- score_ += 1;
- }
- handle(t);
- drawScore();
- sound();
- draw(player_, '@');
- }
- void exit() {
- Tile &t = tiles_[player_.x][player_.y];
- if (t.content == Content::EXIT) {
- message("You run out of the cave entrance and");
- message(" head to the local inn to share your tale.");
- game_over();
- } else {
- message("There is nowhere to escape from here, Brave Sir Robin.");
- }
- }
- void loot() {
- Tile &t = tiles_[player_.x][player_.y];
- if (t.content == Content::WEAPON) {
- t.content = Content::NONE;
- weapon_ = true;
- for (int y = 0; y <= size_ + 1; y++) {
- for (int x = 0; x <= size_ + 1; x++) {
- Tile &w = tiles_[x][y];
- if (w.content == Content::WEAPON) {
- w.content = Content::GOLD;
- }
- }
- }
- score_ += 5;
- message("You are now armed and dangerous.");
- draw();
- } else if (t.content == Content::GOLD) {
- score_ += 5;
- t.content = Content::NONE;
- message("You gather all the gold and put it in your pack.");
- } else {
- message("There's nothing here to loot,");
- message(" even for a hoarder adventurer like you.");
- }
- drawScore();
- }
- const unsigned kMessageMax = 6;
- void message(const char *s) {
- messages_.push_back(s);
- while (messages_.size() > kMessageMax) {
- messages_.pop_front();
- }
- int p = 3;
- for (auto i = messages_.begin(); i != messages_.end(); i++) {
- mvprintw(p++, size_ + 3, *i);
- clrtoeol();
- }
- }
- bool done = false;
- void sound() {
- std::vector<Vec2> adjacent = {kNorth, kSouth, kEast, kWest};
- for (auto &a : adjacent) {
- auto p = player_ + a;
- Tile &t = tiles_[p.x][p.y];
- switch (t.content) {
- case Content::WUMPUS:
- message("You detect a foul stench in the air.");
- break;
- case Content::TRAP:
- message("You hear a howling wind.");
- break;
- default:
- break;
- }
- }
- }
- void game_over() {
- message("***GAME OVER***");
- sprintf(score_message_, "You scored %d %s!", score_,
- score_ == 1 ? "point" : "points");
- message(score_message_);
- done = true;
- }
- private:
- const int size_;
- Tile tiles_[22][22];
- Vec2 player_;
- int score_ = 0;
- std::deque<const char *> messages_;
- bool weapon_ = false;
- char score_message_[80];
- void draw(int x, int y) {
- Tile t = tiles_[x][y];
- int c = t.content;
- mvaddch(y, x, t.content != Content::WALL && !t.explored ? '?' : c);
- }
- void draw(Vec2 v, int c) { mvaddch(v.y, v.x, c); }
- void handle(Tile &t) {
- switch (t.content) {
- case Content::TRAP:
- message("You fall down a pit to your death!");
- message("Your screams are heard by no one.");
- game_over();
- break;
- case Content::WUMPUS:
- message("A hungry wumpus stands before you!");
- if (!weapon_) {
- message("A wumpus attacks you and makes you his lunch.");
- game_over();
- } else {
- message("You slay the wumpus with your sword.");
- t.content = Content::NONE;
- score_ += 10;
- }
- break;
- case Content::WEAPON:
- message("Cast before you in a rock a sword awaits to be looted.");
- break;
- case Content::GOLD:
- message("Before you lies the the gold of a dead adventurer.");
- break;
- case Content::EXIT:
- message("You see see the entrance here. You wish to run away?");
- break;
- default:
- break;
- }
- }
- void drawScore() {
- char score[32];
- sprintf(score, "Score: %d", score_);
- mvprintw(0, size_ + 3, score);
- }
- };
- int main() {
- srand(time(0));
- while (true) {
- int size = 0;
- std::cout << "What game size (10 - 20, 0 quit)? ";
- std::cin >> size;
- if (size == 0) return 0;
- Game game{size};
- game.draw();
- while (!game.done) {
- switch (getch()) {
- case 'n':
- case KEY_UP:
- game.move(kNorth);
- break;
- case 's':
- case KEY_DOWN:
- game.move(kSouth);
- break;
- case 'e':
- case KEY_RIGHT:
- game.move(kEast);
- break;
- case 'w':
- case KEY_LEFT:
- game.move(kWest);
- break;
- case 'l':
- game.loot();
- break;
- case 'r':
- game.exit();
- break;
- case 'D': // debug die
- game.game_over();
- break;
- case '?':
- game.message("NSEW -> player movement (or arrow keys)");
- game.message("L -> loot");
- game.message("R -> exit the dungeon (when on exit)");
- game.message("X or Q -> quit");
- break;
- case 'x':
- case 'q':
- return 0;
- break;
- }
- }
- game.message("Press ENTER to restart.");
- while (getch() != 10)
- ; // pause before new game
- }
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement