瀏覽代碼

Fixing up roll system

Sam Jaffe 7 年之前
父節點
當前提交
228f8b3f89
共有 5 個文件被更改,包括 67 次插入53 次删除
  1. 0 1
      include/exception.h
  2. 1 1
      include/roll.h
  3. 2 1
      src/die.cxx
  4. 41 5
      src/main.cxx
  5. 23 45
      src/roll.cxx

+ 0 - 1
include/exception.h

@@ -31,7 +31,6 @@ namespace dice {
      * "<END>" if position and backup_length are both -1
      */
     std::string pointer(long long backup_length = -1) const;
-    
   private:
     long long position;
   };

+ 1 - 1
include/roll.h

@@ -23,7 +23,7 @@ namespace dice {
     // of rolled is within the integer range [1, M].
     std::vector<int> rolled;
   };
-
+  
   // Describe the actual result of rolling an arbitrary set of dice with mods
   struct dice_roll {
     // Collapse this roll into its actual value

+ 2 - 1
src/die.cxx

@@ -94,7 +94,8 @@ namespace dice { namespace {
    */
   void parser::parse_dN(sign s, int value) {
     advance_over_whitespace(in, "dD");
-    d.of.push_back({s, value, 0});
+    // Disallow 0dM, as that is not a real thing...
+    d.of.push_back({s, std::max(value, 1), 0});
     if (!isnumber(in.peek())) {
       throw unexpected_token("Expected a number of sides", in.tellg());
     }

+ 41 - 5
src/main.cxx

@@ -13,19 +13,55 @@
 #include <iostream>
 #include <sstream>
 
+void print(dice::dice_roll const & r) {
+  std::cout << int(r) << " (" << r << ")\n";
+}
+
+void print(std::vector<dice::dice_roll> const & rs) {
+  if (rs.size() != 1) {
+    std::cout << '\n';
+    for (int i = 0; i < rs.size(); ++i) {
+      std::cout << "  Result/" << i << ": ";
+      print(rs[i]);
+    }
+  } else {
+    print(rs[0]);
+  }
+}
+
+/**
+ *
+ * @param str A string representation of a dice roll, represented as one of the
+ * following expression classes:
+ * Die = [1-9]?\d*d[1-9]\d*
+ * SingleRoll: ($Die|\d+)((+|-)($Die|\d+))*
+ * RepeatRoll: [1-9]\d*\{$SingleRoll\}
+ * @return a dice object representing the roll
+ * @throws dice::unexpected_token if a parse failure occurs
+ */
+dice::dice make_dice(std::string const & str) {
+  std::stringstream ss(str);
+  dice::dice d;
+  ss >> d;
+  return d;
+}
+
+/**
+ * @param str {@see make_dice(std::string const &)}
+ */
 void eval(std::string const & str) {
   try {
-    std::stringstream ss(str);
-    dice::dice d;
-    ss >> d;
-    dice::roll(d);
+    auto d = make_dice(str);
+    auto rs = dice::roll(d);
+    std::cout << "Result of '" << d << "': ";
+    print(rs);
   } catch (dice::unexpected_token const & ut) {
     std::cerr << "Error in roll: '" << str << "': " << ut.what() << "\n";
     std::cerr << "                " << ut.pointer(str.size()+1) << std::endl;
   }
 }
 
-int main(int argc, const char * argv[]) {
+int main(int, const char **) {
   std::string line;
   std::cout << "> ";
   while (std::getline(std::cin, line)) {

+ 23 - 45
src/roll.cxx

@@ -12,22 +12,8 @@
 #include <memory>
 #include <numeric>
 
-#include "die.h"
 #include "random.h"
 
-namespace dice {
-  struct die_roll {
-    operator int() const;
-    sign sign;
-    std::vector<int> rolled;
-  };
-  struct dice_roll {
-    operator int() const;
-    std::vector<die_roll> sub_rolls;
-    std::vector<mod> modifiers;
-  };
-}
-
 namespace dice {
   die_roll::operator int() const {
     return sgn(sign) * std::accumulate(rolled.begin(), rolled.end(), 0);
@@ -38,34 +24,32 @@ namespace dice {
         std::accumulate(modifiers.begin(), modifiers.end(), 0);
   }
   
-  void print(std::ostream & out, die_roll const & r) {
+  std::ostream & operator<<(std::ostream & out, die_roll const & r) {
     out << str(r.sign);
-    if (r.rolled.size() > 1) {
-      out << "[ ";
-    }
-    out << r.rolled[0];
-    for (int i = 1; i < r.rolled.size(); ++i) {
-      out << ", " << r.rolled[i];
-    }
-    if (r.rolled.size() > 1) {
-      out << " ]";
+    switch (r.rolled.size()) {
+        // Prevent crashes if we somehow get a 0dM expression
+      case 0: return out << "0";
+        // Don't bother with braces if there's only a single roll,
+        // the braces are for grouping purposes.
+      case 1: return out << r.rolled[0];
+      default:
+        out << "[ ";
+        out << r.rolled[0];
+        for (int i = 1; i < r.rolled.size(); ++i) {
+          out << ", " << r.rolled[i];
+        }
+        return out << " ]";
     }
   }
   
-  void print(std::ostream & out, dice_roll const & r) {
+  std::ostream & operator<<(std::ostream & out, dice_roll const & r) {
     for (die_roll const & dr : r.sub_rolls) {
-      print(out, dr);
+      out << dr;
     }
     for (mod const & m : r.modifiers) {
-      out << str(m.sign);
-      out << m.value;
+      out << str(m.sign) << m.value;
     }
-  }
-
-  std::ostream & operator<<(std::ostream & out, dice_roll const & r) {
-    out << int(r) << " (";
-    print(out, r);
-    return out << ")";
+    return out;
   }
   
   die_roll roll_impl(die const & d, engine::random & gen) {
@@ -84,18 +68,12 @@ namespace dice {
     return {hits, d.modifier};
   }
   
-  void roll(dice const & d) {
+  std::vector<dice_roll> roll(dice const & d) {
+    std::vector<dice_roll> out;
     engine::random gen;
-    std::cout << "Result of '" << d << "': ";
-    if (d.num != 1) {
-      std::cout << "\n";
-      for (int i = 0; i < d.num; ++i) {
-        auto r = roll_impl(d, gen);
-        std::cout << "  Result/" << i << ": " << r << "\n";
-      }
-    } else {
-      auto r = roll_impl(d, gen);
-      std::cout << r << "\n";
+    for (int i = 0; i < d.num; ++i) {
+      out.emplace_back(roll_impl(d, gen));
     }
+    return out;
   }
 }