Browse Source

Creating a system to handle stateful dice rolling.
This system includes the following features on top of the normal dice
rolling method:
- Store any dice-like object as in a variable name.
- Lookup stored variables.
- Substitute variables when invoking a dice roll.
- Forget stored variables.
- Overwrite stored varaibles.
- Save/Load stored variables from a file.

Sam Jaffe 7 years ago
parent
commit
b119b7927c
1 changed files with 83 additions and 3 deletions
  1. 83 3
      stateful_dice/main.cxx

+ 83 - 3
stateful_dice/main.cxx

@@ -9,19 +9,99 @@
 #include "exception.h"
 #include "terminal_helper.h"
 
+#include <fstream>
 #include <iostream>
+#include <map>
+#include <regex>
 
-void eval(std::string const & str) {
+void usage() {
+  std::cout << "'help'      : Print this message\n";
+  std::cout << "'A := Dice' : Create a substitution pattern\n";
+  std::cout << "'1d6+$Dex'  : Roll 1d6 plus whatever value subs for 'Dex'\n";
+}
+
+void print_binding(std::pair<const std::string, std::string> const & pair,
+                   std::ostream & os = std::cout) {
+  os << pair.first;
+  if (pair.second == "") os << " is not defined\n";
+  else os << " := " << pair.second << "\n";
+}
+
+class evaluator {
+public:
+  void operator()(std::string const & str);
+ 
+private:
+  using binding_t = std::map<std::string, std::string>;
+  
+  bool regex_search(char const * regex) {
+    return std::regex_match(curr, match, std::regex(regex));
+  }
+
+  binding_t::value_type find_or(std::string const & key) const {
+    auto it = bindings.find(key);
+    return it == bindings.cend() ? binding_t::value_type(key, "") : *it;
+  }
+  
+  void save(std::string const & file) const {
+    using namespace std::placeholders;
+    std::ofstream out(file);
+    std::for_each(bindings.begin(), bindings.end(),
+                  std::bind(&print_binding, _1, std::ref(out)));
+  }
+  void load(std::string const & file) {
+    std::ifstream in(file);
+    while (std::getline(in, curr)) {
+      if (regex_search(R"(^(\w+)\s*:=\s*(.*)$)")) {
+        bindings[match[1]] = match[2];
+      }
+    }
+  }
+private:
+  std::string curr;
+  std::smatch match;
+  binding_t bindings;
+};
+
+void evaluator::operator()(std::string const & str) {
+  curr = str;
   try {
-    terminal::process_dice_string(str);
+    if (regex_search(R"(help|\?)")) {
+      usage();
+    } else if (regex_search(R"(^(\w+)\s*:=\s*(.*)$)")) {
+      bindings[match[1]] = match[2];
+    } else if (regex_search(R"(^show (\*|all))")) {
+      std::for_each(bindings.begin(), bindings.end(), &print_binding);
+    } else if (regex_search(R"(^show (\w+))")) {
+      print_binding(find_or(match[1]));
+    } else if (regex_search(R"(^unset (\*|all))")) {
+      bindings.clear();
+    } else if (regex_search(R"(^unset (\w+))")) {
+      bindings.erase(match[1]);
+    } else if (regex_search(R"(^save (.+))")) {
+      save(match[1]);
+    } else if (regex_search(R"(^load new (.+))")) {
+      bindings.clear();
+      load(match[1]);
+    } else if (regex_search(R"(^load (.+))")) {
+      load(match[1]);
+    } else {
+      while (regex_search(R"(.*(\$\w+).*)")) {
+        curr.replace(match[1].first, match[1].second,
+                     find_or(match[1].str().substr(1)).second);
+      }
+      terminal::process_dice_string(curr);
+    }
   } catch (dice::unexpected_token const & ut) {
-    terminal::print_error_message(str, ut);
+    terminal::print_error_message(curr, ut);
   }
 }
 
+
 int main(int, const char **) {
   std::string line;
   std::cout << "> ";
+  evaluator eval;
   while (std::getline(std::cin, line)) {
     eval(line);
     std::cout << "> ";