⚠️ Warning: This is a draft ⚠️

This means it might contain formatting issues, incorrect code, conceptual problems, or other severe issues.

If you want to help to improve and eventually enable this page, please fork RosettaGit's repository and open a merge request on GitHub.

{{collection|RCRPG}} == Commands == *''north, south, east, west, up, down'' moves. *''n, s, e, w, u, d'' are aliases for the above. *''attack

'' to break down walls. You need to have a sledge equipped. *''take '' to take an item. *''take all'' to take everything in the room. *''drop '' to drop an item. *''drop all'' to drop everything. *''equip '' to equip something from your inventory. *''wield '' is an alias for equip. *''unequip'' to return what you're wielding to your inventory. *''name '' to name a room. *''alias '' to create an alias. *''inventory, inv, i'' to see what you have. *''look'' to see the full room description again.

== Code == {{works with | C++11}} {{works with | Visual Studio 2010}}

#include <map>
#include <set>
#include <ctime>
#include <cctype>
#include <string>
#include <random>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;

mt19937 rnd_engine((unsigned long)time(NULL));
uniform_real_distribution<double> rnd_distribution;
auto rnd = bind(rnd_distribution, rnd_engine);

typedef function<void (stringstream&)> action;

map<string, action> actions;
map<string, string> unalias;

void canonical(string &s)
{
  transform(s.begin(), s.end(), s.begin(), tolower);

  while(unalias.find(s) != unalias.end())
    s = unalias[s];
}

class position
{
public:
  int x, y, z;    // north-south, east-west, up-down

  position(): x(0), y(0), z(0) {}

  bool operator<(const position &p) const
  {
    if(x < p.x)
      return true;
    if(x > p.x)
      return false;
    if(y < p.y)
      return true;
    if(y > p.y)
      return false;
    if(z < p.z)
      return true;
    if(z > p.z)
      return false;
    return false;
  }
};

position playerPos;

class directionSet
{
public:
  set<string> directions;

  bool isOpen(string dir) const
  {
    return directions.find(dir) != directions.end();
  }

  bool open(string dir)
  {
    if(directions.find(dir) != directions.end())
      return false;

    directions.insert(dir);
    return true;
  }

  vector<string> list() const
  {
    vector<string> out;
    set<string>::const_iterator iter;
    for(iter = directions.begin(); iter != directions.end(); ++iter)
      out.push_back(*iter);
    return out;
  }
};

class itemSet
{
public:
  map<string, int> counts;

  int count(string item)
  {
    if(counts.find(item) == counts.end())
      return 0;
    return counts[item];
  }

  void add(string item, int number = 1)
  {
    counts[item] += number;
  }

  bool remove(string item)
  {
    if(counts.find(item) == counts.end() || counts[item] == 0)
      return false;

    --counts[item];
    return true;
  }

  void clear()
  {
    counts.clear();
  }

  int transferAll(itemSet &other)
  {
    int total = 0;

    map<string, int>::iterator iter;
    for(iter = counts.begin(); iter != counts.end(); ++iter)
    {
      other.add(iter->first, iter->second);
      total += iter->second;
    }

    counts.clear();
    return total;
  }

  void describe(bool vertical = true) const
  {
    bool any = false;
    map<string, int>::const_iterator iter;
    for(iter = counts.begin(); iter != counts.end(); ++iter)
    {
      if(iter->second == 0)
        continue;

      any = true;

      if(vertical)
        cout << "  ";
      else if(iter != counts.begin())
        cout << ", ";

      if(iter->second == 1)
        cout << "a " << iter->first;
      else
        cout << iter->second << " " << iter->first << "s";

      if(vertical)
        cout << endl;
    }

    if(!any)
      if(vertical)
        cout << "  nothing" << endl;
      else
        cout << "nothing";
  }
};

int sledgeCount = 0;

class room
{
public:
  bool visited;
  itemSet items;
  directionSet exits;
  string name;

  room()
  {
    visited = false;
    name = "";

    if(rnd() < 0.25)
    {
      items.add("sledge");
      sledgeCount++;
    }
    if(rnd() < 0.1)
      items.add("ladder");
    while(rnd() < 0.1)
      items.add("gold");
  }

  void describe(bool full = true)
  {
    visited = true;
    cout << endl;

    if(full)
    {
      cout << "You are in a small room";

      if(name == "")
        cout << " at (" << playerPos.x << ", " << playerPos.y << ", " << playerPos.z << "). ";
      else
        cout << ". You remember this room as " << name << ". ";

      vector<string> e = exits.list();
      if(e.size() == 0)
        cout << "There are no exits here. ";
      else if(e.size() == 1)
        cout << "There is an exit to the " << e[0] << ". ";
      else
      {
        cout << "There are exits to the ";
        for(size_t i = 0; i < e.size(); ++i)
        {
          if(i == e.size() - 1)
            cout << " and ";
          else if(i != 0)
            cout << ", ";
          cout << e[i];
        }
        cout << ". ";
      }

      cout << "You see ";
      items.describe(false);
      cout << " on the floor." << endl;
    }
    else
    {
      if(name == "")
        cout << "(" << playerPos.x << ", " << playerPos.y << ", " << playerPos.z << ")" << endl;
      else
        cout << name << ":" << endl;

      vector<string> e = exits.list();
      if(e.size() == 0)
        cout << "No exits. ";
      else
      {
        cout << "Exits: ";
        for(size_t i = 0; i < e.size(); ++i)
        {
          if(i != 0)
            cout << ", ";
          cout << e[i];
        }
        cout << "." << endl;;
      }

      cout << "Items: ";
      items.describe(false);
      cout << "." << endl;
    }
  }
};

map<position, room> rooms;
itemSet playerInv;
string equipped = "";

void north(stringstream &ss)
{
  if(rooms[playerPos].exits.isOpen("north"))
  {
    playerPos.x++;
    rooms[playerPos].describe(!rooms[playerPos].visited);
  }
  else
    cout << "There's a wall in your way." << endl;
}

void south(stringstream &ss)
{
  if(rooms[playerPos].exits.isOpen("south"))
  {
    playerPos.x--;
    rooms[playerPos].describe(!rooms[playerPos].visited);
  }
  else
    cout << "There's a wall in your way." << endl;
}

void east(stringstream &ss)
{
  if(rooms[playerPos].exits.isOpen("east"))
  {
    playerPos.y++;
    rooms[playerPos].describe(!rooms[playerPos].visited);
  }
  else
    cout << "There's a wall in your way." << endl;
}

void west(stringstream &ss)
{
  if(rooms[playerPos].exits.isOpen("west"))
  {
    playerPos.y--;
    rooms[playerPos].describe(!rooms[playerPos].visited);
  }
  else
    cout << "There's a wall in your way." << endl;
}

void up(stringstream &ss)
{
  if(rooms[playerPos].items.count("ladder") == 0)
    cout << "There's no ladder here." << endl;
  else if(rooms[playerPos].exits.isOpen("up"))
  {
    playerPos.z++;
    rooms[playerPos].describe(!rooms[playerPos].visited);
  }
  else
    cout << "There's a ceiling in your way." << endl;
}

void down(stringstream &ss)
{
  if(rooms[playerPos].exits.isOpen("down"))
  {
    playerPos.z--;
    rooms[playerPos].describe(!rooms[playerPos].visited);
  }
  else
    cout << "There's a floor in your way." << endl;
}

void attack(stringstream &ss)
{
  if(equipped != "sledge")
  {
    cout << "You're not weilding a sledge." << endl;
    return;
  }

  string dir, opp = "";
  ss >> dir;
  canonical(dir);

  position otherPos = playerPos;

  if(dir == "north")
  {
    opp = "south";
    otherPos.x++;
  }
  else if(dir == "south")
  {
    opp = "north";
    otherPos.x--;
  }
  else if(dir == "east")
  {
    opp = "west";
    otherPos.y++;
  }
  else if(dir == "west")
  {
    opp = "east";
    otherPos.y--;
  }
  else if(dir == "up")
  {
    opp = "down";
    otherPos.z++;
  }
  else if(dir == "down")
  {
    opp = "up";
    otherPos.z--;
  }

  if(opp == "")
    cout << "You swing in a fifth direction, and hit nothing." << endl;
  else if(!rooms[playerPos].exits.open(dir))
    cout << "There's already a hole there." << endl;
  else
  {
    rooms[otherPos].exits.open(opp);

    if(dir == "up")
      dir = "ceiling";
    else if(dir == "down")
      dir = "floor";
    else
      dir += " wall";

    cout << "You hammer away at the " << dir << " and make a big hole." << endl;

    if(rnd() < 0.166 && sledgeCount > 1)
    {
      equipped = "";
      cout << "Your sledge breaks!" << endl;
      sledgeCount--;
    }
  }
}

void drop(stringstream &ss)
{
  string item;
  ss >> item;
  canonical(item);

  if(item == "all")
  {
    int n = playerInv.transferAll(rooms[playerPos].items);
    if(n == 0)
      cout << "You don't have anything to drop." << endl;
    else
      cout << "You drop all your stuff on the floor." << endl;
  }
  else if(!playerInv.remove(item))
    cout << "You don't have a " << item << "." << endl;
  else
  {
    rooms[playerPos].items.add(item);
    cout << "You drop a " << item << "." << endl;
  }
}

void take(stringstream &ss)
{
  string item;
  ss >> item;
  canonical(item);

  if(item == "all")
  {
    int n = rooms[playerPos].items.transferAll(playerInv);
    if(n == 0)
      cout << "You don't see anything to take." << endl;
    else
      cout << "You take everything not nailed down." << endl;
  }
  else if(!rooms[playerPos].items.remove(item))
    cout << "You don't see a " << item << " here." << endl;
  else
  {
    playerInv.add(item);
    cout << "You take a " << item << "." << endl;
  }
}

void inventory(stringstream &ss)
{
  cout << "You are weilding " << (equipped == "" ? "nothing" : "a " + equipped) << "." << endl;
  cout << "You are carrying:" << endl;
  playerInv.describe();
}

void name(stringstream &ss)
{
  string newName;
  getline(ss, newName);
  rooms[playerPos].name = newName.substr(1);
  cout << "You'll always remember this room as" << newName << "." << endl;
}

void equip(stringstream &ss)
{
  string item;
  ss >> item;
  canonical(item);

  if(!playerInv.remove(item))
    cout << "You don't have a " << item << " to equip." << endl;
  else if(equipped != "")
  {
    cout << "You unequip your " << equipped << " and wield a " << item << "." << endl;
    playerInv.add(equipped);
    equipped = item;
  }
  else
  {
    cout << "You equip a " << item << "." << endl;
    equipped = item;
  }
}

void unequip(stringstream &ss)
{
  if(equipped == "")
    cout << "You don't have anything equipped." << endl;
  else
  {
    cout << "You stop weilding the " << equipped << "." << endl;
    playerInv.add(equipped);
    equipped = "";
  }
}

void alias(stringstream &ss)
{
  string from, to;
  ss >> from >> to;

  if(actions.find(from) == actions.end() && unalias.find(from) == unalias.end() &&
    from != "gold" && from != "sledge" && from != "ladder")
    cout << "I don't understand " << from << "." << endl;
  else if(actions.find(to) != actions.end() || unalias.find(to) != unalias.end() ||
    to == "gold" || to == "sledge" || to == "ladder")
    cout << "Can't redefine words." << endl;
  else
  {
    unalias[to] = from;
    cout << "Ok." << endl;
  }
}

void look(stringstream &ss)
{
  rooms[playerPos].describe();
}

int main()
{
  actions["north"] = north;
  actions["south"] = south;
  actions["east"] = east;
  actions["west"] = west;
  actions["up"] = up;
  actions["down"] = down;
  actions["attack"] = attack;
  actions["drop"] = drop;
  actions["take"] = take;
  actions["equip"] = equip;
  actions["unequip"] = unequip;
  actions["inventory"] = inventory;
  actions["name"] = name;
  actions["alias"] = alias;
  actions["look"] = look;

  unalias["inv"] = "inventory";
  unalias["i"] = "inventory";
  unalias["n"] = "north";
  unalias["s"] = "south";
  unalias["e"] = "east";
  unalias["w"] = "west";
  unalias["u"] = "up";
  unalias["d"] = "down";
  unalias["wield"] = "equip";

  rooms[playerPos].items.clear();
  rooms[playerPos].items.add("sledge");
  sledgeCount = 1;

  cout << "Welcome to RCRPG, C++ edition. Find your way to (1, 1, 5) to get the treasure and win the game." << endl;

  stringstream dummy;
  look(dummy);

  while(true)
  {
    string input, command;

    cout << "> ";
    getline(cin, input);

    stringstream ss(input);
    ss >> command;

    canonical(command);

    if(actions.find(command) != actions.end())
      actions[command](ss);
    else if(command == "quit")
    {
      cout << "Bye." << endl;
      break;
    }
    else
      cout << "I don't understand." << endl;

    if(playerPos.x == 1 && playerPos.y == 1 && playerPos.z == 5)
    {
      cout << "You made it! And there's the treasure! It's beautiful!" << endl;
      break;
    }
  }
}