Browse Source

Transform into a functionint program

Sam Jaffe 7 years ago
parent
commit
c80d708197
7 changed files with 315 additions and 13 deletions
  1. 18 4
      dice-roll.xcodeproj/project.pbxproj
  2. 29 0
      include/die.h
  3. 17 0
      include/exception.h
  4. 3 4
      include/die.hpp
  5. 104 1
      src/die.cxx
  6. 22 4
      src/main.cxx
  7. 122 0
      src/roll.cxx

+ 18 - 4
dice-roll.xcodeproj/project.pbxproj

@@ -7,6 +7,7 @@
 	objects = {
 	objects = {
 
 
 /* Begin PBXBuildFile section */
 /* Begin PBXBuildFile section */
+		CD8F1ABE21B31E9E00CBB3CA /* roll.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CD8F1ABD21B31E9E00CBB3CA /* roll.cxx */; };
 		CDED6A2721B2F28A00AB91D0 /* main.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CDED6A2621B2F28A00AB91D0 /* main.cxx */; };
 		CDED6A2721B2F28A00AB91D0 /* main.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CDED6A2621B2F28A00AB91D0 /* main.cxx */; };
 		CDED6A3121B2F2DC00AB91D0 /* die.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CDED6A3021B2F2DC00AB91D0 /* die.cxx */; };
 		CDED6A3121B2F2DC00AB91D0 /* die.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CDED6A3021B2F2DC00AB91D0 /* die.cxx */; };
 		CDED6A6121B2F89900AB91D0 /* libshared_random_generator.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = CDED6A6021B2F89900AB91D0 /* libshared_random_generator.dylib */; };
 		CDED6A6121B2F89900AB91D0 /* libshared_random_generator.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = CDED6A6021B2F89900AB91D0 /* libshared_random_generator.dylib */; };
@@ -25,12 +26,15 @@
 /* End PBXCopyFilesBuildPhase section */
 /* End PBXCopyFilesBuildPhase section */
 
 
 /* Begin PBXFileReference section */
 /* Begin PBXFileReference section */
+		CD8F1ABC21B31E9E00CBB3CA /* roll.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = roll.h; sourceTree = "<group>"; };
+		CD8F1ABD21B31E9E00CBB3CA /* roll.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = roll.cxx; sourceTree = "<group>"; };
 		CDED6A2321B2F28A00AB91D0 /* dice-roll */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "dice-roll"; sourceTree = BUILT_PRODUCTS_DIR; };
 		CDED6A2321B2F28A00AB91D0 /* dice-roll */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "dice-roll"; sourceTree = BUILT_PRODUCTS_DIR; };
 		CDED6A2621B2F28A00AB91D0 /* main.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = main.cxx; sourceTree = "<group>"; };
 		CDED6A2621B2F28A00AB91D0 /* main.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = main.cxx; sourceTree = "<group>"; };
-		CDED6A2F21B2F2DC00AB91D0 /* die.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = die.hpp; sourceTree = "<group>"; };
+		CDED6A2F21B2F2DC00AB91D0 /* die.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = die.h; sourceTree = "<group>"; };
 		CDED6A3021B2F2DC00AB91D0 /* die.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = die.cxx; sourceTree = "<group>"; };
 		CDED6A3021B2F2DC00AB91D0 /* die.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = die.cxx; sourceTree = "<group>"; };
 		CDED6A5821B2F6E800AB91D0 /* random.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = random.h; sourceTree = "<group>"; };
 		CDED6A5821B2F6E800AB91D0 /* random.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = random.h; sourceTree = "<group>"; };
 		CDED6A6021B2F89900AB91D0 /* libshared_random_generator.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; path = libshared_random_generator.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
 		CDED6A6021B2F89900AB91D0 /* libshared_random_generator.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; path = libshared_random_generator.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
+		CDF88B9C21B304EF004BAB50 /* exception.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = exception.h; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 /* End PBXFileReference section */
 
 
 /* Begin PBXFrameworksBuildPhase section */
 /* Begin PBXFrameworksBuildPhase section */
@@ -69,6 +73,7 @@
 			children = (
 			children = (
 				CDED6A2621B2F28A00AB91D0 /* main.cxx */,
 				CDED6A2621B2F28A00AB91D0 /* main.cxx */,
 				CDED6A3021B2F2DC00AB91D0 /* die.cxx */,
 				CDED6A3021B2F2DC00AB91D0 /* die.cxx */,
+				CD8F1ABD21B31E9E00CBB3CA /* roll.cxx */,
 			);
 			);
 			path = src;
 			path = src;
 			sourceTree = "<group>";
 			sourceTree = "<group>";
@@ -83,8 +88,10 @@
 		CDED6A2E21B2F2C300AB91D0 /* include */ = {
 		CDED6A2E21B2F2C300AB91D0 /* include */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
-				CDED6A2F21B2F2DC00AB91D0 /* die.hpp */,
+				CDED6A2F21B2F2DC00AB91D0 /* die.h */,
+				CDF88B9C21B304EF004BAB50 /* exception.h */,
 				CDED6A5821B2F6E800AB91D0 /* random.h */,
 				CDED6A5821B2F6E800AB91D0 /* random.h */,
+				CD8F1ABC21B31E9E00CBB3CA /* roll.h */,
 			);
 			);
 			path = include;
 			path = include;
 			sourceTree = "<group>";
 			sourceTree = "<group>";
@@ -155,6 +162,7 @@
 			files = (
 			files = (
 				CDED6A3121B2F2DC00AB91D0 /* die.cxx in Sources */,
 				CDED6A3121B2F2DC00AB91D0 /* die.cxx in Sources */,
 				CDED6A2721B2F28A00AB91D0 /* main.cxx in Sources */,
 				CDED6A2721B2F28A00AB91D0 /* main.cxx in Sources */,
+				CD8F1ABE21B31E9E00CBB3CA /* roll.cxx in Sources */,
 			);
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 		};
@@ -212,7 +220,10 @@
 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
 				GCC_WARN_UNUSED_FUNCTION = YES;
 				GCC_WARN_UNUSED_FUNCTION = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
-				HEADER_SEARCH_PATHS = "$(BUILT_PRODUCTS_DIR)/usr/local/include";
+				HEADER_SEARCH_PATHS = (
+					"$(BUILT_PRODUCTS_DIR)/usr/local/include",
+					/opt/local/include,
+				);
 				MACOSX_DEPLOYMENT_TARGET = 10.13;
 				MACOSX_DEPLOYMENT_TARGET = 10.13;
 				MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
 				MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
 				MTL_FAST_MATH = YES;
 				MTL_FAST_MATH = YES;
@@ -267,7 +278,10 @@
 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
 				GCC_WARN_UNUSED_FUNCTION = YES;
 				GCC_WARN_UNUSED_FUNCTION = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
-				HEADER_SEARCH_PATHS = "$(BUILT_PRODUCTS_DIR)/usr/local/include";
+				HEADER_SEARCH_PATHS = (
+					"$(BUILT_PRODUCTS_DIR)/usr/local/include",
+					/opt/local/include,
+				);
 				MACOSX_DEPLOYMENT_TARGET = 10.13;
 				MACOSX_DEPLOYMENT_TARGET = 10.13;
 				MTL_ENABLE_DEBUG_INFO = NO;
 				MTL_ENABLE_DEBUG_INFO = NO;
 				MTL_FAST_MATH = YES;
 				MTL_FAST_MATH = YES;

+ 29 - 0
include/die.h

@@ -0,0 +1,29 @@
+//
+//  die.hpp
+//  dice-roll
+//
+//  Created by Sam Jaffe on 12/1/18.
+//  Copyright © 2018 Sam Jaffe. All rights reserved.
+//
+
+#pragma once
+
+#include <boost/variant/variant.hpp>
+
+#include <iosfwd>
+#include <memory>
+
+namespace dice {
+  struct dice;
+  using sub_dice = boost::variant<int, std::shared_ptr<dice>>;
+  
+  // Default value: 1d1+0
+  struct dice {
+    int num{1};
+    sub_dice of{1};
+    sub_dice modifier{+0};
+  };
+    
+  std::ostream & operator<<(std::ostream & out, dice const & d);
+  std::istream & operator>>(std::istream & out, dice & d);
+}

+ 17 - 0
include/exception.h

@@ -0,0 +1,17 @@
+//
+//  exception.h
+//  dice-roll
+//
+//  Created by Sam Jaffe on 12/1/18.
+//  Copyright © 2018 Sam Jaffe. All rights reserved.
+//
+
+#pragma once
+
+#include <stdexcept>
+
+namespace dice {
+  struct unexpected_token : public std::runtime_error {
+    unexpected_token(long long position);
+  };
+}

+ 3 - 4
include/die.hpp

@@ -1,5 +1,5 @@
 //
 //
-//  die.hpp
+//  roll.hpp
 //  dice-roll
 //  dice-roll
 //
 //
 //  Created by Sam Jaffe on 12/1/18.
 //  Created by Sam Jaffe on 12/1/18.
@@ -9,7 +9,6 @@
 #pragma once
 #pragma once
 
 
 namespace dice {
 namespace dice {
-  struct random {
-    
-  };
+  struct dice;
+  void roll(dice const & d);
 }
 }

+ 104 - 1
src/die.cxx

@@ -6,4 +6,107 @@
 //  Copyright © 2018 Sam Jaffe. All rights reserved.
 //  Copyright © 2018 Sam Jaffe. All rights reserved.
 //
 //
 
 
-#include "die.hpp"
+#include "die.h"
+#include "exception.h"
+
+#include <boost/variant/get.hpp>
+
+#include <iostream>
+
+static void advance_over_whitespace(std::istream & in) {
+  while (isspace(in.peek())) { in.get(); }
+}
+
+static std::string carrot(long long pos) {
+  if (pos == -1) return "<END>";
+  std::string out;
+  out.resize(pos, '~');
+  out.back() = '^';
+  return out;
+}
+
+void print(std::ostream & out, int i) { out << 'd' << i; }
+void print(std::ostream & out, std::shared_ptr<dice::dice> d) {
+  out << '{' << *d << '}';
+}
+
+void modifier(std::ostream & out, int i) {
+  if (i > 0) out << '+';
+  if (i) out << i;
+}
+void modifier(std::ostream & out, std::shared_ptr<dice::dice> d) {
+  if (d->num > 0) out << '+';
+  out << *d;
+}
+
+namespace dice {
+  unexpected_token::unexpected_token(long long pos) :
+    std::runtime_error(carrot(pos)) {
+    
+  }
+    
+  std::ostream & operator<<(std::ostream & out, dice const & d) {
+    out << d.num;
+    boost::apply_visitor([&out](auto v) { print(out, v); }, d.of);
+    boost::apply_visitor([&out](auto v) { modifier(out, v); }, d.modifier);
+    return out;
+  }
+  
+  static void parse(std::istream & in, dice & d, bool allow_nest = false);
+  
+  static void parse_inner_expr(std::istream & in, dice & d, bool allow_nest) {
+    using sp_dice = std::shared_ptr<dice>;
+    advance_over_whitespace(in);
+    switch (in.get()) {
+      case 'd': case 'D':
+        in >> boost::get<int>(d.of);
+        break;
+      case '{':
+        if (!allow_nest) { throw unexpected_token(in.tellg()); }
+        d.of = std::make_shared<dice>();
+        parse(in, *boost::get<std::shared_ptr<dice>>(d.of));
+        if (in.get() != '}') { throw unexpected_token(in.tellg()); }
+        break;
+      case EOF:
+        break;
+      default:
+        throw unexpected_token(in.tellg());
+    }
+  }
+  
+  static void parse_modifier_expr(std::istream & in, dice & d) {
+    advance_over_whitespace(in);
+    int modifier = 0;
+    switch (in.peek()) {
+      case '+':
+        in.get();
+      case '-':
+        in >> modifier;
+        advance_over_whitespace(in);
+        if (in.peek() != 'd' && in.peek() != 'D') {
+          d.modifier = modifier;
+        } else {
+          d.modifier = std::make_shared<dice>();
+          parse(in, *boost::get<std::shared_ptr<dice>>(d.modifier));
+          boost::get<std::shared_ptr<dice>>(d.modifier)->num = modifier;
+        }
+      default:
+        break;
+    }
+  }
+  
+  static void parse(std::istream & in, dice & d, bool allow_nest) {
+    // Allow implicit 1
+    advance_over_whitespace(in);
+    if (isnumber(in.peek())) { in >> d.num; }
+    parse_inner_expr(in, d, allow_nest);
+    if (!d.of.which()) {
+      parse_modifier_expr(in, d);
+    }
+  }
+
+  std::istream & operator>>(std::istream & in, dice & d) {
+    parse(in, d, true);
+    return in;
+  }
+}

+ 22 - 4
src/main.cxx

@@ -6,13 +6,31 @@
 //  Copyright © 2018 Sam Jaffe. All rights reserved.
 //  Copyright © 2018 Sam Jaffe. All rights reserved.
 //
 //
 
 
+#include "die.h"
+#include "exception.h"
+#include "roll.h"
+
 #include <iostream>
 #include <iostream>
+#include <sstream>
 
 
-#include "die.hpp"
-#include "random.h"
+void eval(std::string const & str) {
+  std::stringstream ss(str + "$");
+  try {
+    dice::dice d;
+    ss >> d;
+    dice::roll(d);
+  } catch (dice::unexpected_token const & ut) {
+    std::cerr << "Error in roll: '" << str << "'\n";
+    std::cerr << "                " << ut.what() << std::endl;
+  }
+}
 
 
 int main(int argc, const char * argv[]) {
 int main(int argc, const char * argv[]) {
-  // insert code here...
-  std::cout << "Hello, World!\n";
+  std::string line;
+  std::cout << "> ";
+  while (std::getline(std::cin, line)) {
+    eval(line);
+    std::cout << "> ";
+  }
   return 0;
   return 0;
 }
 }

+ 122 - 0
src/roll.cxx

@@ -0,0 +1,122 @@
+//
+//  roll.cxx
+//  dice-roll
+//
+//  Created by Sam Jaffe on 12/1/18.
+//  Copyright © 2018 Sam Jaffe. All rights reserved.
+//
+
+#include "roll.h"
+
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/get.hpp>
+
+#include <iostream>
+#include <memory>
+#include <numeric>
+
+#include "die.h"
+#include "random.h"
+
+namespace dice {
+  struct roll_t;
+  using chain_roll = boost::variant<int, std::shared_ptr<roll_t>>;
+  struct roll_t {
+    operator int() const;
+    
+    enum Sign { PLUS=1, MINUS=-1, ZERO=0 } sign{ZERO};
+    std::vector<int> rolled;
+    chain_roll chain;
+  };
+
+  roll_t roll_impl(dice const & d, engine::random & gen);
+}
+
+template <typename T> static int sgn(T val) {
+  return (T(0) < val) - (val < T(0));
+}
+
+namespace dice {
+  int to_int(int i) { return i; }
+  int to_int(std::shared_ptr<roll_t> r) { return *r; }
+  roll_t::operator int() const {
+    return (sign ? sign : 1) *
+    std::accumulate(rolled.begin(), rolled.end(), 0) +
+    boost::apply_visitor([](auto c) { return to_int(c); }, chain);
+  }
+  
+  void print(std::ostream & out, roll_t const & r);
+  void print(std::ostream & out, int i) {
+    if (i > 0) out << '+';
+    if (i) out << i;
+  }
+  void print(std::ostream & out, std::shared_ptr<roll_t> r) {
+    print(out, *r);
+  }
+  void print(std::ostream & out, roll_t const & r) {
+    switch (r.sign) {
+      case roll_t::PLUS:
+        out << '+';
+        break;
+      case roll_t::MINUS:
+        out << '-';
+      default:
+        break;
+    }
+    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 << " ]";
+    }
+    boost::apply_visitor([&out](auto c) { return print(out, c); }, r.chain);
+  }
+
+  std::ostream & operator<<(std::ostream & out, roll_t const & r) {
+    out << int(r) << " (";
+    print(out, r);
+    return out << ")";
+  }
+  
+  chain_roll roll_impl(int i, engine::random &) {
+    return i;
+  }
+  chain_roll roll_impl(std::shared_ptr<dice> d, engine::random & gen) {
+    return std::make_shared<roll_t>(roll_impl(*d, gen));
+  }
+  
+  roll_t roll_impl(dice const & d, engine::random & gen) {
+    std::vector<int> hits;
+    int const count = std::abs(d.num);
+    int const sign = sgn(d.num);
+    hits.reserve(count);
+    for (int i = 0; i < count; ++i) {
+      hits.push_back(gen.roll(boost::get<int>(d.of)));
+    }
+    auto chain = boost::apply_visitor([&gen](auto d) {
+      return roll_impl(d, gen);
+    }, d.modifier);
+    return { (roll_t::Sign)sign, hits, chain };
+  }
+  
+  void roll(dice const & d) {
+    engine::random gen;
+    std::cout << "Result of '" << d << "': ";
+    if (d.of.which()) {
+      std::cout << "\n";
+      for (int i = 0; i < d.num; ++i) {
+        auto r = roll_impl(*boost::get<std::shared_ptr<dice>>(d.of), gen);
+        r.sign = roll_t::ZERO;
+        std::cout << "  Result/" << i << ": " << r << "\n";
+      }
+    } else {
+      auto r = roll_impl(d, gen);
+      r.sign = roll_t::ZERO;
+      std::cout << r << "\n";
+    }
+  }
+}