RCRPG/C++11: Difference between revisions
Pistacchio (talk | contribs) (Created page with "{{collection|RCRPG}} C++11 version of RCRPG. The code can also be checked out and contributed to on [https://github.com/pistacchio/rosettacode.clojure....") |
Pistacchio (talk | contribs) No edit summary |
||
Line 1: | Line 1: | ||
{{collection|RCRPG}} |
{{collection|RCRPG}} |
||
[[ |
[[Javascript]] (node) version of [[:Category:RCRPG|RCRPG]]. The code can also be checked out and contributed to on [https://github.com/pistacchio/rcrpgjs github] . |
||
==Code== |
==Code== |
||
<lang |
<lang javascript> |
||
const _ = require('lodash'), |
|||
// |
|||
readline = require('readline'); |
|||
// main.cpp |
|||
// RCRPGCpp |
|||
// |
|||
// Created by pistacchio on 19/03/14. |
|||
// |
|||
// |
|||
#include <algorithm> |
|||
#include <iostream> |
|||
#include <map> |
|||
#include <set> |
|||
#include <string> |
|||
#include <random> |
|||
#include <regex> |
|||
#include <vector> |
|||
/////////////////// |
|||
// Initialize the randomization engine |
|||
// LODASH IMPORT // |
|||
std::default_random_engine rnd_eng(std::random_device{}()); |
|||
/////////////////// |
|||
// import all lodash functions to the main namespace, but isNaN not to cause conflicts |
|||
////////////////// |
|||
_.each(_.keys(_), k => global[k === 'isNaN' ? '_isNaN' : k] = _[k]); |
|||
// String utils // |
|||
////////////////// |
|||
/////////////// |
|||
// Concats string in a nice readable format adding "," and "and" |
|||
// CONSTANTS // |
|||
std::string descriptive_join(const std::vector<std::string>& items) { |
|||
/////////////// |
|||
std::string desc; |
|||
std::vector<std::string> itms {items.begin(), items.end()}; |
|||
int items_size {(int)items.size()}; |
|||
if (items_size > 1) { |
|||
for (int i {0}; i < items_size - 1; i++) { |
|||
itms.insert(itms.begin() + i * 2 + 1, i == items_size -2 ? " and " : ", "); |
|||
} |
|||
} |
|||
std::for_each(itms.begin(), itms.end(), [&](std::string s) { |
|||
desc += s; |
|||
}); |
|||
return desc; |
|||
} |
|||
const DIRECTIONS = { |
|||
////////// |
|||
n: [ 0, -1, 0], |
|||
// Item // |
|||
s: [ 0, 1, 0], |
|||
////////// |
|||
e: [-1, 0, 0], |
|||
w: [ 1, 0, 0], |
|||
enum Item {LADDER, SLEDGE, GOLD}; |
|||
u: [ 0, 0, -1], |
|||
static const std::map<Item, std::string> Item_strings { |
|||
d: [ 0, 0, 1] |
|||
{SLEDGE, "a sledge"}, |
|||
{GOLD, "some gold"} |
|||
}; |
|||
static const std::map<std::string, Item> String_items { |
|||
{"ladder", LADDER}, |
|||
{"sledge", SLEDGE}, |
|||
{"gold", GOLD} |
|||
}; |
}; |
||
///////////// |
///////////// |
||
// |
// HELPERS // |
||
///////////// |
///////////// |
||
function findDirection (world, dir, longName=false) { |
|||
std::map<std::string, std::string> Aliases { |
|||
const maybeDirection = find(world.commands, c => contains(first(c), dir)), |
|||
{"i", "inventory"}, |
|||
dirLetter = first(first(maybeDirection)); |
|||
{"n", "north"}, |
|||
{"e", "east"}, |
|||
if (maybeDirection && has(DIRECTIONS, dirLetter)) { |
|||
{"w", "west"}, |
|||
return longName ? first(maybeDirection)[1] : dirLetter; |
|||
{"s", "south"}, |
|||
} |
|||
{"get", "take"}, |
|||
{"u", "up"}, |
|||
{"l", "look"}, |
|||
{"d", "down"} |
|||
}; |
|||
std::string unalias(std::string term) { |
|||
if (Aliases.find(term) == Aliases.end()) { |
|||
return term; |
|||
} else { |
|||
return Aliases.find(term)->second; |
|||
} |
|||
} |
} |
||
void list_aliases() { |
|||
function makeRoom(location) { |
|||
std::cout << "Current aliases are:" << std::endl; |
|||
return [location, null, compact([ |
|||
for_each(Aliases.begin(), Aliases.end(), [](std::pair<std::string, std::string> alias){ |
|||
random(0, 2) === 0 ? 'sledge': null, |
|||
std::cout << alias.first << " -> " << alias.second << std::endl; |
|||
random(0, 2) === 0 ? 'ladder': null, |
|||
}); |
|||
random(0, 2) === 0 ? 'gold': null |
|||
])]; |
|||
} |
} |
||
void add_alias(std::string alias, std::string command) { |
|||
if (Aliases.find(alias) == Aliases.end()) { |
|||
Aliases[alias] = command; |
|||
} |
|||
function listToDescriptiveString (lst) { |
|||
if (!lst) return; |
|||
if (lst.length === 1) return first(lst); |
|||
return dropRight(lst).join(', ') + ' and ' + last(lst); |
|||
} |
|||
function itemsToDescriptiveItems (items) { |
|||
return map(items, i => { |
|||
switch (i) { |
|||
case 'sledge': return 'a sledge'; |
|||
case 'ladder': return 'a ladder'; |
|||
case 'gold': return 'some gold'; |
|||
} |
|||
}); |
|||
} |
} |
||
////////////// |
////////////// |
||
// |
// MESSAGES // |
||
////////////// |
////////////// |
||
function help () { |
|||
struct Location { |
|||
return `You need a sledge to dig rooms and ladders to go upwards. |
|||
int x; |
|||
Valid commands are: directions (north, south...), dig, take, drop, equip, inventory and look. |
|||
int y; |
|||
Additionally you can tag rooms with the 'name' command and alias commands with 'alias'. |
|||
int z; |
|||
Have fun! |
|||
`; |
|||
Location (int xval, int yval, int zval): x(xval), y(yval), z(zval) {} |
|||
} |
|||
function welcome () { |
|||
Location& operator+= (Location const& other) { |
|||
console.log(`Welcome to the dungeon! |
|||
*this = *this + other; |
|||
Grab the sledge and make your way to room 1,1,5 for a non-existant prize! |
|||
return *this; |
|||
`); |
|||
console.log(help()); |
|||
} |
|||
///////////// |
|||
// ACTIONS // |
|||
///////////// |
|||
function gotoRoom (direction, world) { |
|||
const wantedRoom = zipWith(world.player.location, DIRECTIONS[direction], add), |
|||
room = find(world.rooms, r => isEqual(first(r), world.player.location)); |
|||
if (direction === 'u' && !contains(room[2], 'ladder')) { |
|||
console.log("You can't go upwards without a ladder!"); |
|||
} else { |
|||
if (find(world.rooms, r => isEqual(first(r), wantedRoom))) { |
|||
world.player.location = wantedRoom; |
|||
look(world); |
|||
} else { |
|||
console.log("There's no exit in that direction!"); |
|||
} |
} |
||
} |
|||
Location operator+ (const Location& other) { |
|||
return Location(this->x + other.x, this->y + other.y, this->z + other.z); |
|||
return world |
|||
}; |
|||
bool operator< (const Location& left, const Location& right) { |
|||
return std::to_string(left.x) + '-' + std::to_string(left.y) + '-' + std::to_string(left.z) < |
|||
std::to_string(right.x) + '-' + std::to_string(right.y) + '-' + std::to_string(right.z); |
|||
} |
} |
||
function dig (world, [direction]) { |
|||
/////////////// |
|||
let dir, |
|||
// Direction // |
|||
dirLongName, |
|||
/////////////// |
|||
wantedRoom; |
|||
if (!direction) { |
|||
static const std::map<std::string, Location> Direction { |
|||
console.log('Where do you want to dig?'); |
|||
{"north", Location( 0, -1, 0)}, |
|||
return world |
|||
{"south", Location( 0, 1, 0)}, |
|||
} |
|||
{"east", Location(-1, 0, 0)}, |
|||
if (!(dir = findDirection(world, direction))) { |
|||
{"west", Location( 1, 0, 0)}, |
|||
console.log('That is not a direction I recognize'); |
|||
{"up", Location( 0, 0, -1)}, |
|||
return world; |
|||
{"down", Location( 0, 0, 1)} |
|||
} |
} |
||
if (!contains(world.player.inventory, 'sledge')) { |
|||
console.log('With your bare hands?'); |
|||
return world; |
|||
} |
|||
dirLongName = findDirection(world, direction, true); |
|||
////////////////////////////// |
|||
wantedRoom = zipWith(world.player.location, DIRECTIONS[dir], add); |
|||
// Interface Item Container // |
|||
////////////////////////////// |
|||
if (find(world.rooms, r => isEqual(first(r), wantedRoom))) { |
|||
// Inherited by Player and Room, both need a way to contain items |
|||
console.log('There is already an exit, there!'); |
|||
class IItemContainer { |
|||
return world; |
|||
public: |
|||
} |
|||
bool has_item(const Item item) const { |
|||
return items.find(item) != items.end(); |
|||
} |
|||
bool add_item(Item item) { |
|||
if (items.find(item) == items.end()) { |
|||
items.insert(item); |
|||
return true; |
|||
} else { |
|||
return false; |
|||
} |
|||
} |
|||
std::set<Item> add_all_items(std::set<Item> new_items) { |
|||
items.insert(new_items.begin(), new_items.end()); |
|||
return items; |
|||
} |
|||
bool remove_item(Item item) { |
|||
if (items.find(item) == items.end()) { |
|||
return false; |
|||
} else { |
|||
items.erase(item); |
|||
return true; |
|||
} |
|||
} |
|||
std::set<Item> remove_all_items() { |
|||
std::set<Item> removed_items {items.begin(), items.end()}; |
|||
items = std::set<Item> {}; |
|||
return removed_items; |
|||
} |
|||
protected: |
|||
std::set<Item> items; |
|||
}; |
|||
world.rooms.push(makeRoom(wantedRoom)); |
|||
console.log(`There is now an exit ${dirLongName}ward`); |
|||
return world; |
|||
} |
|||
function look (world) { |
|||
////////// |
|||
const room = find(world.rooms, r => isEqual(first(r), world.player.location)), |
|||
// Room // |
|||
////////// |
|||
itemsOnFloor = itemsToDescriptiveItems(room[2]), |
|||
class Room : public IItemContainer { |
|||
itemsOnFloorStr = isEmpty(itemsOnFloor) |
|||
public: |
|||
? '' |
|||
Room () = default; |
|||
: (itemsOnFloor.length === 1 |
|||
Room (std::string description): description(description) { |
|||
? itemsOnFloor[0] |
|||
std::uniform_int_distribution<int> gen(0, 2); |
|||
: listToDescriptiveString(itemsOnFloor)), |
|||
exits = chain(DIRECTIONS) |
|||
.map((d, kd) => [kd, zipWith(d, first(room), add)]) |
|||
.filter(r => find(world.rooms, rr => isEqual(first(rr), r[1]))) |
|||
} |
|||
.map(d => find(world.commands, c => { |
|||
return contains(first(c), first(d)) |
|||
} |
})[0][1]) |
||
.value(), |
|||
exitsStr = isEmpty(exits) |
|||
? '' |
|||
: (exits.length === 1 |
|||
} |
|||
? `There is one exit: ${exits[0]}.` |
|||
const std::string describe (std::vector<std::string> adjacent_directions) const { |
|||
: `You can see the following exits: ${listToDescriptiveString(exits)}.`); |
|||
std::string items_on_floor; |
|||
std::string exits; |
|||
if (items.size() > 0) { |
|||
items_on_floor = "\nOn the floor you can see " + describe_items(); |
|||
} |
|||
if (adjacent_directions.size() == 1) { |
|||
exits = "There is one exit: " + adjacent_directions.front(); |
|||
} else if (adjacent_directions.size() > 1) { |
|||
exits = "\nYou can see the following directions: "; |
|||
console.log( |
|||
exits += descriptive_join(adjacent_directions) + "."; |
|||
(room[1] ? room[1] : `Room at ${world.player.location[0]}, ${world.player.location[1]}, ${world.player.location[2]}`) + '\n' + |
|||
} |
|||
(!itemsOnFloorStr ? '' : `On the floor you can see ${itemsOnFloorStr}.\n`) + |
|||
exitsStr |
|||
return description + items_on_floor + exits + "\n"; |
|||
); |
|||
private: |
|||
std::string description; |
|||
std::string describe_items () const { |
|||
std::vector<std::string> itms; |
|||
std::for_each(items.begin(), items.end(), [&](Item i) { |
|||
itms.push_back(Item_strings.find(i)->second); |
|||
}); |
|||
return descriptive_join(itms) + "."; |
|||
} |
|||
}; |
|||
return world; |
|||
} |
|||
function inventory (world) { |
|||
/////////// |
|||
if (world.player.inventory.length === 0) { |
|||
// World // |
|||
console.log('You are not carrying anything'); |
|||
/////////// |
|||
} else { |
|||
console.log(`You are carrying: ${listToDescriptiveString(itemsToDescriptiveItems(world.player.inventory))}`); |
|||
} |
|||
return world; |
|||
class World { |
|||
} |
|||
public: |
|||
World () { |
|||
rooms[Location(0, 0, 0)] = Room{"The room where it all started..."}; |
|||
rooms[Location(1, 1, 5)] = Room{"You found it! Lots of gold!"}; |
|||
} |
|||
bool room_exists (const Location room) const { |
|||
return rooms.find(room) != rooms.end(); |
|||
} |
|||
Room& room_at (const Location location) { |
|||
return rooms[location]; |
|||
} |
|||
const void dig (Location location) { |
|||
rooms[location] = Room{}; |
|||
} |
|||
const std::vector<std::string> adjacent_directions (Location location) { |
|||
std::vector<std::string> result {}; |
|||
function take (world, [item]) { |
|||
std::for_each(Direction.begin(), Direction.end(), [&](std::pair<std::string, Location> direction) { |
|||
const room = find(world.rooms, r => isEqual(first(r), world.player.location)) |
|||
if (room_exists(location + direction.second)) { |
|||
result.push_back(direction.first); |
|||
} |
|||
}); |
|||
return result; |
|||
} |
|||
private: |
|||
std::map<Location, Room> rooms; |
|||
}; |
|||
if (!item) { |
|||
//////////// |
|||
console.log('Take what?'); |
|||
// Player // |
|||
return world; |
|||
//////////// |
|||
} |
|||
if (item === 'all') { |
|||
class Player : public IItemContainer { |
|||
if (isEmpty(room[2])) { |
|||
public: |
|||
console.log('There is nothing to take here'); |
|||
Player () : current_location(0, 0, 0) { |
|||
} else{ |
|||
items.insert(SLEDGE); |
|||
world.player.inventory = uniq(world.player.inventory.concat(room[2] || [])); |
|||
}; |
|||
room[2] = []; |
|||
const Location goto_direction (const Location direction) { |
|||
console.log('All items taken'); |
|||
current_location += direction; |
|||
return current_location; |
|||
} |
} |
||
return world; |
|||
Location get_current_location () const { |
|||
} |
|||
return current_location; |
|||
} |
|||
std::string inventory () { |
|||
if (items.size() == 0) { |
|||
return "You are not carrying anything"; |
|||
} else { |
|||
std::vector<std::string> itemsv; |
|||
std::for_each(items.begin(), items.end(), [&](Item i) { |
|||
itemsv.push_back(Item_strings.find(i)->second); |
|||
}); |
|||
return "You are carrying: " + descriptive_join(itemsv); |
|||
} |
|||
} |
|||
bool equip(Item item) { |
|||
if (has_item(item)) { |
|||
equipping = true; |
|||
equipped = item; |
|||
return true; |
|||
} else { |
|||
return false; |
|||
} |
|||
} |
|||
bool unequip(Item item) { |
|||
if (equipped == item) { |
|||
equipping = false; |
|||
return true; |
|||
} else { |
|||
return false; |
|||
} |
|||
} |
|||
bool is_equipping(Item item) { |
|||
return equipping == true && equipped == item; |
|||
} |
|||
private: |
|||
Location current_location; |
|||
bool equipping {false}; |
|||
Item equipped; |
|||
}; |
|||
if (!contains(room[2], item)) { |
|||
console.log("You can't see anything like that here"); |
|||
return world; |
|||
} |
|||
world.player.inventory = uniq(world.player.inventory.concat([item])); |
|||
////////// |
|||
pull(room[2], item); |
|||
// Game // |
|||
console.log('Taken'); |
|||
////////// |
|||
return world |
|||
class Game { |
|||
} |
|||
public: |
|||
void execute(const std::string command) { |
|||
function drop (world, [item]) { |
|||
std::vector<std::string> cmd; |
|||
const room = find(world.rooms, r => isEqual(first(r), world.player.location)) |
|||
if (!item) { |
|||
console.log('Drop what?'); |
|||
return world; |
|||
} |
|||
if (item === 'all') { |
|||
std::for_each(std::sregex_token_iterator {command.begin(), command.end(), std::regex {"\\s+"}, -1}, |
|||
if (isEmpty(world.player.inventory)) { |
|||
std::sregex_token_iterator {}, |
|||
console.log('You have nothing to drop'); |
|||
[&](std::ssub_match sm) { |
|||
} else{ |
|||
cmd.push_back(sm.str()); |
|||
room[2] = uniq(room[2].concat(world.player.inventory || [])); |
|||
}); |
|||
world.player.inventory = []; |
|||
console.log('All items dropped'); |
|||
std::string action {unalias(cmd.front())}; |
|||
// HELP |
|||
if (action == "help") { |
|||
print_help(); |
|||
// MOVE (Up, Down, North etc) |
|||
} else if (Direction.find(action) != Direction.end()) { |
|||
Location direction {Direction.find(action)->second}; |
|||
Location location {direction + player.get_current_location()}; |
|||
if (world.room_exists(location)) { |
|||
Room& room {world.room_at(location)}; |
|||
if (action == "up" && !room.has_item(LADDER)) { |
|||
std::cout << "You can't go upwards without a ladder!" << std::endl; |
|||
} else { |
|||
Location current_location = player.goto_direction(direction); |
|||
std::cout << world.room_at(current_location).describe(world.adjacent_directions(current_location)); |
|||
} |
|||
} else { |
|||
std::cout << "There's no exit in that direction!" << std::endl; |
|||
} |
|||
// LOOK and describe the room |
|||
} else if (action == "look") { |
|||
std::cout << world.room_at(player.get_current_location()).describe(world.adjacent_directions(player.get_current_location())); |
|||
// DIG towards a direction |
|||
} else if (action == "dig") { |
|||
if (cmd.size() != 2) { |
|||
std::cout << "Where do you want to dig?" << std::endl; |
|||
} else if (!player.is_equipping(SLEDGE)) { |
|||
std::cout << "With your bare hands?!" << std::endl; |
|||
} else { |
|||
if (Direction.find(cmd[1]) == Direction.end()) { |
|||
std::cout << "That is not a direction I recognize" << std::endl; |
|||
} else { |
|||
Location new_loc = player.get_current_location() + Direction.find(cmd[1])->second; |
|||
if (world.room_exists(new_loc)) { |
|||
std::cout << "There is already an exit, there!" << std::endl; |
|||
} else { |
|||
world.dig(player.get_current_location() + Direction.find(cmd[1])->second); |
|||
std::cout << "There is now a new exit " << cmd[1] << "ward" << std::endl; |
|||
} |
|||
} |
|||
} |
|||
// DROP an item or all in the inventory |
|||
} else if (action == "drop") { |
|||
if (cmd.size() == 1) { |
|||
std::cout << "Drop what?" << std::endl; |
|||
} else { |
|||
if (cmd[1] == "all" ) { |
|||
Room& room {world.room_at(player.get_current_location())}; |
|||
room.add_all_items(player.remove_all_items()); |
|||
std::cout << "All items dropped;" << std::endl; |
|||
} else if (String_items.find(cmd[1]) == String_items.end()) { |
|||
std::cout << "\"" << cmd[1] <<"\" is not something I recognize" << std::endl; |
|||
} else { |
|||
Item item {String_items.find(cmd[1])->second}; |
|||
if (player.remove_item(item)) { |
|||
Room& room {world.room_at(player.get_current_location())}; |
|||
room.add_item(item); |
|||
std::cout << "Item dropped" << std::endl; |
|||
} else { |
|||
std::cout << "You don't have any" << cmd[1] << std::endl; |
|||
} |
|||
} |
|||
} |
|||
// TAKE an item from the room or all of them |
|||
} else if (action == "take" ) { |
|||
if (cmd.size() == 1) { |
|||
std::cout << "Take what?" << std::endl; |
|||
} else { |
|||
if (cmd[1] == "all") { |
|||
Room& room {world.room_at(player.get_current_location())}; |
|||
player.add_all_items(room.remove_all_items()); |
|||
std::cout << "All items taken;" << std::endl; |
|||
} else if (String_items.find(cmd[1]) == String_items.end()) { |
|||
std::cout << "\"" << cmd[1] <<"\" is not something I recognize" << std::endl; |
|||
} else { |
|||
Item item {String_items.find(cmd[1])->second}; |
|||
Room& room {world.room_at(player.get_current_location())}; |
|||
if (room.remove_item(item)) { |
|||
player.add_item(item); |
|||
std::cout << "Item taken" << std::endl; |
|||
} else { |
|||
std::cout << "There is no such item in the room" << std::endl; |
|||
} |
|||
} |
|||
} |
|||
// INVENTORY listing |
|||
} else if (action == "inventory") { |
|||
std::cout << player.inventory() << std::endl; |
|||
// EQUIP an item currently in the inventory |
|||
} else if (action == "equip") { |
|||
if (cmd.size() == 1) { |
|||
std::cout << "What do you want to equip?" << std::endl; |
|||
} else { |
|||
if (String_items.find(cmd[1]) == String_items.end()) { |
|||
std::cout << "That is not an item I recognize" << std::endl; |
|||
} else { |
|||
if (player.equip(String_items.find(cmd[1])->second)) { |
|||
std::cout << "Item equipped!" << std::endl; |
|||
} else { |
|||
std::cout << "You don't have it" << std::endl; |
|||
} |
|||
} |
|||
} |
|||
// UNEQUIP an item currently equipped |
|||
} else if (action == "unequip") { |
|||
if (cmd.size() == 1) { |
|||
std::cout << "What do you want to unequip?" << std::endl; |
|||
} else { |
|||
if (String_items.find(cmd[1]) == String_items.end()) { |
|||
std::cout << "That is not an item I recognize" << std::endl; |
|||
} else { |
|||
if (player.equip(String_items.find(cmd[1])->second)) { |
|||
std::cout << "Item unequipped!" << std::endl; |
|||
} else { |
|||
std::cout << "You don't have it" << std::endl; |
|||
} |
|||
} |
|||
} |
|||
// ALIAS a command, or list the aliases |
|||
} else if (action == "alias") { |
|||
if (cmd.size() == 1) { |
|||
list_aliases(); |
|||
} else if (cmd.size() == 3) { |
|||
add_alias(cmd[1], cmd[2]); |
|||
std::cout << "Alias added" << std::endl; |
|||
} else { |
|||
std::cout << "The correct use is: alias <ALIAS> <COMMAND>" << std::endl; |
|||
} |
|||
// WHAT?! A command that is not undertood by this simplistic parser |
|||
} else { |
|||
std::cout << "Hm?! What do you mean?" << std::endl; |
|||
} |
|||
} |
} |
||
return world; |
|||
void print_help() { |
|||
} |
|||
std::cout << "You need a sledge to dig rooms and ladders to go upwards." << std::endl |
|||
<< "Valid commands are: directions (north, south...), dig, take, drop, equip, inventory and look." << std::endl |
|||
<< "Additionally you can tag rooms with the 'name' command and alias commands with 'alias'." << std::endl |
|||
<< "Have fun!" << std::endl; |
|||
} |
|||
private: |
|||
World world; |
|||
Player player; |
|||
}; |
|||
if (!contains(world.player.inventory, item)) { |
|||
console.log("You don't have that item"); |
|||
return world; |
|||
} |
|||
room[2] = uniq(room[2].concat([item])); |
|||
//////////////// |
|||
pull(world.player.inventory, item); |
|||
// Main cycle // |
|||
console.log('Dropped'); |
|||
//////////////// |
|||
return world |
|||
int main() |
|||
} |
|||
{ |
|||
Game game; |
|||
function equip (world, [item]) { |
|||
std::string input_line; |
|||
if (!item) { |
|||
console.log('What do you want to equip?'); |
|||
std::cout << "Welcome to the dungeon!" << std::endl |
|||
return world; |
|||
<< "Grab the sledge and make your way to room 1,1,5 for a non-existant prize!" << std::endl << std::endl; |
|||
} |
|||
game.print_help(); |
|||
if (!contains(world.player.inventory, item)) { |
|||
console.log("You don't have such object"); |
|||
while (input_line != "exit") { |
|||
return world; |
|||
std::getline(std::cin, input_line); |
|||
} |
|||
game.execute(input_line); |
|||
world.player.equipped = item; |
|||
console.log('Item equipped!'); |
|||
return world; |
|||
} |
|||
function unequip (world, [item]) { |
|||
if (!item) { |
|||
console.log('What do you want to unequip?'); |
|||
return world; |
|||
} |
|||
if (item !== world.player.equipped) { |
|||
console.log("You don't have it equipped"); |
|||
return world; |
|||
} |
|||
world.player.equipped = null; |
|||
console.log('Item unequipped!'); |
|||
return world; |
|||
} |
|||
function alias (world, [cmd, al]) { |
|||
let foundCommand; |
|||
if (!cmd && !al) { |
|||
console.log('Aliases:' + chain(world.commands) |
|||
.filter(c => first(c).length > 1) |
|||
.map(first) |
|||
.reduce((acc, c) => `${acc}\n${first(c)} => ${rest(c).join(', ')}`, '') |
|||
.value()); |
|||
return world; |
|||
} |
|||
if (!(foundCommand = find(world.commands, c => contains(first(c), cmd)))) { |
|||
console.log('There is no such command'); |
|||
return world |
|||
} |
|||
if (!al) { |
|||
let aliases = reject(first(foundCommand), c => c === cmd); |
|||
if (isEmpty(aliases)) { |
|||
console.log(`There are no aliases for ${cmd}`); |
|||
} else { |
|||
console.log(`Aliases for "${cmd}": ${aliases.join(', ')}`); |
|||
} |
} |
||
return world; |
|||
std::cout << "See you next time!" << std::endl; |
|||
} |
|||
return 0; |
|||
foundCommand[0] = uniq(first(foundCommand).concat([al])); |
|||
console.log('Alias assigned'); |
|||
return world; |
|||
} |
} |
||
////////////////////// |
|||
// INPUT PROCESSING // |
|||
////////////////////// |
|||
function processInput(input, world) { |
|||
const splitInput = trim(input).split(/\s+/g), |
|||
[command, options] = [first(splitInput), rest(splitInput)], |
|||
commandFn = find(world.commands, c => contains(first(c), command.toLowerCase())); |
|||
if (commandFn) { |
|||
return commandFn[1](world, options); |
|||
} else { |
|||
console.log("I don't know what you mean."); |
|||
return world; |
|||
} |
|||
} |
|||
/////////////// |
|||
// MAIN LOOP // |
|||
/////////////// |
|||
(function runGame () { |
|||
let world = { |
|||
rooms: [ |
|||
[[0, 0, 0], "The room where it all started...", ['ladder', 'sledge']], |
|||
[[1, 1 , 5], "You found it! Lots of gold!"] |
|||
], |
|||
commands: [ |
|||
[['n', 'north'], partial(gotoRoom, 'n')], |
|||
[['s', 'south'], partial(gotoRoom, 's')], |
|||
[['w', 'west'], partial(gotoRoom, 'w')], |
|||
[['e', 'east'], partial(gotoRoom, 'e')], |
|||
[['d', 'down'], partial(gotoRoom, 'd')], |
|||
[['u', 'up'], partial(gotoRoom, 'u')], |
|||
[['help'], help], |
|||
[['dig'], dig], |
|||
[['l', 'look'], look], |
|||
[['i', 'inventory'], inventory], |
|||
[['take'], take], |
|||
[['drop'], drop], |
|||
[['equip'], equip], |
|||
[['unequip'], unequip], |
|||
[['alias'], alias] |
|||
], |
|||
player: { |
|||
location: [0, 0, 0], |
|||
inventory: ['sledge'], |
|||
equipped: null |
|||
} |
|||
}; |
|||
welcome(); |
|||
process.stdin.resume(); |
|||
process.stdin.setEncoding('utf8'); |
|||
process.stdin.on('data', input => world = processInput(input, world)) |
|||
})(); |
|||
</lang> |
</lang> |
Revision as of 10:05, 6 May 2015
Javascript (node) version of RCRPG. The code can also be checked out and contributed to on github .
Code
<lang javascript> const _ = require('lodash'),
readline = require('readline');
///////////////////
// LODASH IMPORT //
///////////////////
// import all lodash functions to the main namespace, but isNaN not to cause conflicts _.each(_.keys(_), k => global[k === 'isNaN' ? '_isNaN' : k] = _[k]);
/////////////// // CONSTANTS // ///////////////
const DIRECTIONS = {
n: [ 0, -1, 0], s: [ 0, 1, 0], e: [-1, 0, 0], w: [ 1, 0, 0], u: [ 0, 0, -1], d: [ 0, 0, 1]
};
///////////// // HELPERS // /////////////
function findDirection (world, dir, longName=false) {
const maybeDirection = find(world.commands, c => contains(first(c), dir)), dirLetter = first(first(maybeDirection));
if (maybeDirection && has(DIRECTIONS, dirLetter)) { return longName ? first(maybeDirection)[1] : dirLetter; }
}
function makeRoom(location) {
return [location, null, compact([ random(0, 2) === 0 ? 'sledge': null, random(0, 2) === 0 ? 'ladder': null, random(0, 2) === 0 ? 'gold': null ])];
}
function listToDescriptiveString (lst) {
if (!lst) return; if (lst.length === 1) return first(lst); return dropRight(lst).join(', ') + ' and ' + last(lst);
}
function itemsToDescriptiveItems (items) {
return map(items, i => { switch (i) { case 'sledge': return 'a sledge'; case 'ladder': return 'a ladder'; case 'gold': return 'some gold'; } });
}
////////////// // MESSAGES // //////////////
function help () {
return `You need a sledge to dig rooms and ladders to go upwards.
Valid commands are: directions (north, south...), dig, take, drop, equip, inventory and look. Additionally you can tag rooms with the 'name' command and alias commands with 'alias'. Have fun! `; }
function welcome () {
console.log(`Welcome to the dungeon!
Grab the sledge and make your way to room 1,1,5 for a non-existant prize! `);
console.log(help());
}
///////////// // ACTIONS // /////////////
function gotoRoom (direction, world) {
const wantedRoom = zipWith(world.player.location, DIRECTIONS[direction], add), room = find(world.rooms, r => isEqual(first(r), world.player.location));
if (direction === 'u' && !contains(room[2], 'ladder')) { console.log("You can't go upwards without a ladder!"); } else { if (find(world.rooms, r => isEqual(first(r), wantedRoom))) { world.player.location = wantedRoom; look(world); } else { console.log("There's no exit in that direction!"); } }
return world
}
function dig (world, [direction]) {
let dir, dirLongName, wantedRoom;
if (!direction) { console.log('Where do you want to dig?'); return world } if (!(dir = findDirection(world, direction))) { console.log('That is not a direction I recognize'); return world; } if (!contains(world.player.inventory, 'sledge')) { console.log('With your bare hands?'); return world; }
dirLongName = findDirection(world, direction, true); wantedRoom = zipWith(world.player.location, DIRECTIONS[dir], add);
if (find(world.rooms, r => isEqual(first(r), wantedRoom))) { console.log('There is already an exit, there!'); return world; }
world.rooms.push(makeRoom(wantedRoom)); console.log(`There is now an exit ${dirLongName}ward`); return world;
}
function look (world) {
const room = find(world.rooms, r => isEqual(first(r), world.player.location)),
itemsOnFloor = itemsToDescriptiveItems(room[2]), itemsOnFloorStr = isEmpty(itemsOnFloor) ? : (itemsOnFloor.length === 1 ? itemsOnFloor[0] : listToDescriptiveString(itemsOnFloor)),
exits = chain(DIRECTIONS) .map((d, kd) => [kd, zipWith(d, first(room), add)]) .filter(r => find(world.rooms, rr => isEqual(first(rr), r[1]))) .map(d => find(world.commands, c => { return contains(first(c), first(d)) })[0][1]) .value(), exitsStr = isEmpty(exits) ? : (exits.length === 1 ? `There is one exit: ${exits[0]}.` : `You can see the following exits: ${listToDescriptiveString(exits)}.`);
console.log( (room[1] ? room[1] : `Room at ${world.player.location[0]}, ${world.player.location[1]}, ${world.player.location[2]}`) + '\n' + (!itemsOnFloorStr ? : `On the floor you can see ${itemsOnFloorStr}.\n`) + exitsStr );
return world;
}
function inventory (world) {
if (world.player.inventory.length === 0) { console.log('You are not carrying anything'); } else { console.log(`You are carrying: ${listToDescriptiveString(itemsToDescriptiveItems(world.player.inventory))}`); }
return world;
}
function take (world, [item]) {
const room = find(world.rooms, r => isEqual(first(r), world.player.location))
if (!item) { console.log('Take what?'); return world; }
if (item === 'all') { if (isEmpty(room[2])) { console.log('There is nothing to take here'); } else{ world.player.inventory = uniq(world.player.inventory.concat(room[2] || [])); room[2] = []; console.log('All items taken'); } return world; }
if (!contains(room[2], item)) { console.log("You can't see anything like that here"); return world; }
world.player.inventory = uniq(world.player.inventory.concat([item])); pull(room[2], item); console.log('Taken');
return world
}
function drop (world, [item]) {
const room = find(world.rooms, r => isEqual(first(r), world.player.location))
if (!item) { console.log('Drop what?'); return world; }
if (item === 'all') { if (isEmpty(world.player.inventory)) { console.log('You have nothing to drop'); } else{ room[2] = uniq(room[2].concat(world.player.inventory || [])); world.player.inventory = []; console.log('All items dropped'); } return world; }
if (!contains(world.player.inventory, item)) { console.log("You don't have that item"); return world; }
room[2] = uniq(room[2].concat([item])); pull(world.player.inventory, item); console.log('Dropped');
return world
}
function equip (world, [item]) {
if (!item) { console.log('What do you want to equip?'); return world; } if (!contains(world.player.inventory, item)) { console.log("You don't have such object"); return world; }
world.player.equipped = item; console.log('Item equipped!'); return world;
}
function unequip (world, [item]) {
if (!item) { console.log('What do you want to unequip?'); return world; } if (item !== world.player.equipped) { console.log("You don't have it equipped"); return world; }
world.player.equipped = null; console.log('Item unequipped!'); return world;
}
function alias (world, [cmd, al]) {
let foundCommand;
if (!cmd && !al) { console.log('Aliases:' + chain(world.commands) .filter(c => first(c).length > 1) .map(first) .reduce((acc, c) => `${acc}\n${first(c)} => ${rest(c).join(', ')}`, ) .value()); return world; }
if (!(foundCommand = find(world.commands, c => contains(first(c), cmd)))) { console.log('There is no such command'); return world }
if (!al) { let aliases = reject(first(foundCommand), c => c === cmd);
if (isEmpty(aliases)) { console.log(`There are no aliases for ${cmd}`); } else { console.log(`Aliases for "${cmd}": ${aliases.join(', ')}`); }
return world; }
foundCommand[0] = uniq(first(foundCommand).concat([al])); console.log('Alias assigned'); return world;
}
////////////////////// // INPUT PROCESSING // //////////////////////
function processInput(input, world) {
const splitInput = trim(input).split(/\s+/g), [command, options] = [first(splitInput), rest(splitInput)], commandFn = find(world.commands, c => contains(first(c), command.toLowerCase()));
if (commandFn) { return commandFn[1](world, options); } else { console.log("I don't know what you mean."); return world; }
}
/////////////// // MAIN LOOP // ///////////////
(function runGame () {
let world = { rooms: [ [[0, 0, 0], "The room where it all started...", ['ladder', 'sledge']], [[1, 1 , 5], "You found it! Lots of gold!"] ], commands: [ [['n', 'north'], partial(gotoRoom, 'n')], [['s', 'south'], partial(gotoRoom, 's')], [['w', 'west'], partial(gotoRoom, 'w')], [['e', 'east'], partial(gotoRoom, 'e')], [['d', 'down'], partial(gotoRoom, 'd')], [['u', 'up'], partial(gotoRoom, 'u')],
[['help'], help], [['dig'], dig], [['l', 'look'], look], [['i', 'inventory'], inventory], [['take'], take], [['drop'], drop], [['equip'], equip], [['unequip'], unequip], [['alias'], alias] ], player: { location: [0, 0, 0], inventory: ['sledge'], equipped: null } };
welcome();
process.stdin.resume(); process.stdin.setEncoding('utf8');
process.stdin.on('data', input => world = processInput(input, world))
})(); </lang>