Advertisement
Guest User

wumpus.cc

a guest
Mar 28th, 2014
416
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.79 KB | None | 0 0
  1. /* Wumpus Cave Game, by skeeto
  2.  * See also: http://redd.it/21kqjq
  3.  * c++ -std=c++11 -Wall wumpus.cc -lncurses -o wumpus
  4.  *
  5.  * This is free and unencumbered software released into the public domain.
  6.  */
  7.  
  8. #include <iostream>
  9. #include <cstdlib>
  10. #include <ctime>
  11. #include <deque>
  12. #include <vector>
  13. #include <ncurses.h>
  14.  
  15. class Vec2 {
  16.  public:
  17.   int x, y;
  18.   Vec2 &operator+=(const Vec2 &rhs) {
  19.     x += rhs.x;
  20.     y += rhs.y;
  21.     return *this;
  22.   }
  23.   Vec2 &operator-=(const Vec2 &rhs) {
  24.     x -= rhs.x;
  25.     y -= rhs.y;
  26.     return *this;
  27.   }
  28.   static Vec2 rand(int min, int max) {
  29.     return Vec2{min + (std::rand() % (max - min)),
  30.                 min + (std::rand() % (max - min))};
  31.   }
  32. };
  33.  
  34. Vec2 operator+(Vec2 lhs, Vec2 &rhs) {
  35.   lhs += rhs;
  36.   return lhs;
  37. }
  38.  
  39. Vec2 operator-(Vec2 lhs, Vec2 &rhs) {
  40.   lhs -= rhs;
  41.   return lhs;
  42. }
  43.  
  44. enum Content {
  45.   NONE = '.',
  46.   EXIT = '^',
  47.   GOLD = '$',
  48.   WEAPON = 'W',
  49.   WUMPUS = 'X',
  50.   TRAP = ' ',
  51.   WALL = '#'
  52. };
  53.  
  54. struct Tile {
  55.  public:
  56.   Tile(Content content = Content::NONE, bool explored = false)
  57.       : content{content}, explored{explored} {};
  58.   Content content = Content::NONE;
  59.   bool explored = false;
  60. };
  61.  
  62. const Vec2 kNorth{0, -1}, kSouth{0, 1}, kEast{1, 0}, kWest{-1, 0};
  63.  
  64. class Game {
  65.  public:
  66.   Game(int size) : size_{size} {
  67.     for (int y = 0; y <= size_ + 1; y++) {
  68.       for (int x = 0; x <= size_ + 1; x++) {
  69.         if (x == 0 || y == 0 || x == size + 1 || y == size + 1) {
  70.           tiles_[x][y] = {Content::WALL};
  71.         } else {
  72.           double type = rand() / (double)RAND_MAX;
  73.           if (type >= 0.00 && type < 0.15) {
  74.             tiles_[x][y] = {Content::WEAPON};
  75.           } else if (type >= 0.15 && type < 0.30) {
  76.             tiles_[x][y] = {Content::WUMPUS};
  77.           } else if (type >= 0.30 && type < 0.45) {
  78.             tiles_[x][y] = {Content::GOLD};
  79.           } else if (type >= 0.45 && type < 0.50) {
  80.             tiles_[x][y] = {Content::TRAP};
  81.           } else {
  82.             tiles_[x][y] = {Content::NONE};
  83.           }
  84.         }
  85.       }
  86.     }
  87.     player_ = Vec2::rand(1, size + 1);
  88.     tiles_[player_.x][player_.y] = {Content::EXIT, true};
  89.     initscr();
  90.     raw();
  91.     noecho();
  92.     curs_set(0);
  93.     keypad(stdscr, TRUE);
  94.     erase();
  95.     sound();
  96.   }
  97.  
  98.   ~Game() { endwin(); }
  99.  
  100.   void draw() {
  101.     for (int y = 0; y <= size_ + 1; y++) {
  102.       for (int x = 0; x <= size_ + 1; x++) {
  103.         draw(x, y);
  104.       }
  105.     }
  106.     draw(player_, '@');
  107.     drawScore();
  108.     refresh();
  109.   }
  110.  
  111.   void move(Vec2 direction) {
  112.     draw(player_.x, player_.y);
  113.     player_ += direction;
  114.     Tile &t = tiles_[player_.x][player_.y];
  115.     if (t.content == Content::WALL) {
  116.       player_ -= direction;
  117.     } else if (!t.explored) {
  118.       t.explored = true;
  119.       score_ += 1;
  120.     }
  121.     handle(t);
  122.     drawScore();
  123.     sound();
  124.     draw(player_, '@');
  125.   }
  126.  
  127.   void exit() {
  128.     Tile &t = tiles_[player_.x][player_.y];
  129.     if (t.content == Content::EXIT) {
  130.       message("You run out of the cave entrance and");
  131.       message("    head to the local inn to share your tale.");
  132.       game_over();
  133.     } else {
  134.       message("There is nowhere to escape from here, Brave Sir Robin.");
  135.     }
  136.   }
  137.  
  138.   void loot() {
  139.     Tile &t = tiles_[player_.x][player_.y];
  140.     if (t.content == Content::WEAPON) {
  141.       t.content = Content::NONE;
  142.       weapon_ = true;
  143.       for (int y = 0; y <= size_ + 1; y++) {
  144.         for (int x = 0; x <= size_ + 1; x++) {
  145.           Tile &w = tiles_[x][y];
  146.           if (w.content == Content::WEAPON) {
  147.             w.content = Content::GOLD;
  148.           }
  149.         }
  150.       }
  151.       score_ += 5;
  152.       message("You are now armed and dangerous.");
  153.       draw();
  154.     } else if (t.content == Content::GOLD) {
  155.       score_ += 5;
  156.       t.content = Content::NONE;
  157.       message("You gather all the gold and put it in your pack.");
  158.     } else {
  159.       message("There's nothing here to loot,");
  160.       message("  even for a hoarder adventurer like you.");
  161.     }
  162.     drawScore();
  163.   }
  164.  
  165.   const unsigned kMessageMax = 6;
  166.  
  167.   void message(const char *s) {
  168.     messages_.push_back(s);
  169.     while (messages_.size() > kMessageMax) {
  170.       messages_.pop_front();
  171.     }
  172.     int p = 3;
  173.     for (auto i = messages_.begin(); i != messages_.end(); i++) {
  174.       mvprintw(p++, size_ + 3, *i);
  175.       clrtoeol();
  176.     }
  177.   }
  178.  
  179.   bool done = false;
  180.  
  181.   void sound() {
  182.     std::vector<Vec2> adjacent = {kNorth, kSouth, kEast, kWest};
  183.     for (auto &a : adjacent) {
  184.       auto p = player_ + a;
  185.       Tile &t = tiles_[p.x][p.y];
  186.       switch (t.content) {
  187.         case Content::WUMPUS:
  188.           message("You detect a foul stench in the air.");
  189.           break;
  190.         case Content::TRAP:
  191.           message("You hear a howling wind.");
  192.           break;
  193.         default:
  194.           break;
  195.       }
  196.     }
  197.   }
  198.  
  199.   void game_over() {
  200.     message("***GAME OVER***");
  201.     sprintf(score_message_, "You scored %d %s!", score_,
  202.             score_ == 1 ? "point" : "points");
  203.     message(score_message_);
  204.     done = true;
  205.   }
  206.  
  207.  private:
  208.   const int size_;
  209.   Tile tiles_[22][22];
  210.   Vec2 player_;
  211.   int score_ = 0;
  212.   std::deque<const char *> messages_;
  213.   bool weapon_ = false;
  214.   char score_message_[80];
  215.  
  216.   void draw(int x, int y) {
  217.     Tile t = tiles_[x][y];
  218.     int c = t.content;
  219.     mvaddch(y, x, t.content != Content::WALL && !t.explored ? '?' : c);
  220.   }
  221.  
  222.   void draw(Vec2 v, int c) { mvaddch(v.y, v.x, c); }
  223.  
  224.   void handle(Tile &t) {
  225.     switch (t.content) {
  226.       case Content::TRAP:
  227.         message("You fall down a pit to your death!");
  228.         message("Your screams are heard by no one.");
  229.         game_over();
  230.         break;
  231.       case Content::WUMPUS:
  232.         message("A hungry wumpus stands before you!");
  233.         if (!weapon_) {
  234.           message("A wumpus attacks you and makes you his lunch.");
  235.           game_over();
  236.         } else {
  237.           message("You slay the wumpus with your sword.");
  238.           t.content = Content::NONE;
  239.           score_ += 10;
  240.         }
  241.         break;
  242.       case Content::WEAPON:
  243.         message("Cast before you in a rock a sword awaits to be looted.");
  244.         break;
  245.       case Content::GOLD:
  246.         message("Before you lies the the gold of a dead adventurer.");
  247.         break;
  248.       case Content::EXIT:
  249.         message("You see see the entrance here. You wish to run away?");
  250.         break;
  251.       default:
  252.         break;
  253.     }
  254.   }
  255.  
  256.   void drawScore() {
  257.     char score[32];
  258.     sprintf(score, "Score: %d", score_);
  259.     mvprintw(0, size_ + 3, score);
  260.   }
  261. };
  262.  
  263. int main() {
  264.   srand(time(0));
  265.   while (true) {
  266.     int size = 0;
  267.     std::cout << "What game size (10 - 20, 0 quit)? ";
  268.     std::cin >> size;
  269.     if (size == 0) return 0;
  270.     Game game{size};
  271.     game.draw();
  272.     while (!game.done) {
  273.       switch (getch()) {
  274.         case 'n':
  275.         case KEY_UP:
  276.           game.move(kNorth);
  277.           break;
  278.         case 's':
  279.         case KEY_DOWN:
  280.           game.move(kSouth);
  281.           break;
  282.         case 'e':
  283.         case KEY_RIGHT:
  284.           game.move(kEast);
  285.           break;
  286.         case 'w':
  287.         case KEY_LEFT:
  288.           game.move(kWest);
  289.           break;
  290.         case 'l':
  291.           game.loot();
  292.           break;
  293.         case 'r':
  294.           game.exit();
  295.           break;
  296.         case 'D':  // debug die
  297.           game.game_over();
  298.           break;
  299.         case '?':
  300.           game.message("NSEW   -> player movement (or arrow keys)");
  301.           game.message("L      -> loot");
  302.           game.message("R      -> exit the dungeon (when on exit)");
  303.           game.message("X or Q -> quit");
  304.           break;
  305.         case 'x':
  306.         case 'q':
  307.           return 0;
  308.           break;
  309.       }
  310.     }
  311.     game.message("Press ENTER to restart.");
  312.     while (getch() != 10)
  313.       ;  // pause before new game
  314.   }
  315.   return 0;
  316. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement