summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/random-var.cc
diff options
context:
space:
mode:
authorRobert Vollmert <rvollmert@gmx.net>2010-04-15 12:58:37 +0200
committerRobert Vollmert <rvollmert@gmx.net>2010-04-15 16:35:56 +0200
commitc4b430219a0677f528269d3e2c5dcdcfa3315918 (patch)
treedcdaeb7a2289e486be8c598e56ec86127a9e7331 /crawl-ref/source/random-var.cc
parent4baeeac951c64219140bc4c2ddf1a16c67ba14a7 (diff)
downloadcrawl-ref-c4b430219a0677f528269d3e2c5dcdcfa3315918.tar.gz
crawl-ref-c4b430219a0677f528269d3e2c5dcdcfa3315918.zip
Integer random variables.
Using these to get at random values is quite inefficient, but it allows computing expected values for complicated formulas like those used in fight.cc.
Diffstat (limited to 'crawl-ref/source/random-var.cc')
-rw-r--r--crawl-ref/source/random-var.cc197
1 files changed, 197 insertions, 0 deletions
diff --git a/crawl-ref/source/random-var.cc b/crawl-ref/source/random-var.cc
new file mode 100644
index 0000000000..794e3c152b
--- /dev/null
+++ b/crawl-ref/source/random-var.cc
@@ -0,0 +1,197 @@
+#include "AppHdr.h"
+
+#include "random-var.h"
+
+#include "random.h"
+
+random_var::random_var(int c)
+ : start(c), end(c+1)
+{
+ weights.push_back(1);
+ init();
+}
+
+random_var::random_var(int s, int e, weight_func w)
+ : start(s), end(e)
+{
+ init_weights(w);
+ init();
+}
+
+random_var::random_var(int s, int e, std::vector<int> ws)
+ : start(s), end(e), weights(ws)
+{
+ ASSERT(weights.size() == static_cast<unsigned int>(end - start));
+ init();
+}
+
+const random_var& random_var::operator=(const random_var& other)
+{
+ start = other.start;
+ end = other.end;
+ total = other.total;
+ weights = other.weights;
+ return (*this);
+}
+
+int random_var::weight(int val) const
+{
+ if (val < start || val >= end)
+ return (0);
+ return (weights[val - start]);
+}
+
+void random_var::init_weights(weight_func w)
+{
+ ASSERT(weights.empty());
+ for (int v = start; v < end; ++v)
+ weights.push_back(w ? (*w)(v) : 1);
+}
+
+void random_var::init()
+{
+ total = 0;
+ for (int v = start; v < end; ++v)
+ total += weight(v);
+ ASSERT(total > 0);
+ ASSERT(weight(start) > 0 && weight(end - 1) > 0);
+}
+
+int random_var::roll2val(int r) const
+{
+ ASSERT(0 <= r && r < total);
+ int v = start;
+ int w = weight(v);
+ while (r >= w)
+ {
+ v++;
+ w += weight(v);
+ }
+ return (v);
+}
+
+int random_var::roll() const
+{
+ return (roll2val(random2(total)));
+}
+
+int random_var::max() const
+{
+ return (end - 1);
+}
+
+int random_var::min() const
+{
+ return (start);
+}
+
+double random_var::expected() const
+{
+ double ev = 0;
+ for (int i = start; i < end; ++i)
+ ev += i * weight(i) / (double)total;
+ return (ev);
+}
+
+
+//////////////////////////////////
+
+random_var constant(int n)
+{
+ return (random_var(n));
+}
+
+random_var operator+(const random_var& x, const random_var& y)
+{
+ const int start = x.min() + y.min();
+ const int end = x.max() + y.max() + 1;
+ std::vector<int> weights(end - start, 0);
+
+ for (int vx = x.min(); vx <= x.max(); ++vx)
+ for (int vy = y.min(); vy <= y.max(); ++vy)
+ weights[vx + vy - start] += x.weight(vx) * y.weight(vy);
+
+ return (random_var(start, end, weights));
+}
+
+random_var negate(const random_var& x)
+{
+ const int start = -x.max();
+ const int end = -x.min() + 1;
+ std::vector<int> weights(end - start, 0);
+
+ for (int v = x.min(); v <= x.max(); ++v)
+ weights[-v - start] = x.weight(v);
+
+ return (random_var(start, end, weights));
+}
+
+random_var operator-(const random_var& x, const random_var& y)
+{
+ return (x + negate(y));
+}
+
+const random_var& operator+=(random_var& x, const random_var& y)
+{
+ x = x + y;
+ return (x);
+}
+
+const random_var& operator-=(random_var& x, const random_var& y)
+{
+ x = x - y;
+ return (x);
+}
+
+random_var operator/(const random_var& x, int d)
+{
+ const int start = x.min() / d;
+ const int end = x.max() / d + 1;
+ std::vector<int> weights(end - start, 0);
+
+ for (int v = x.min(); v <= x.max(); ++v)
+ weights[v/2 - start] += x.weight(v);
+
+ return (random_var(start, end, weights));
+}
+
+random_var rv::max(const random_var& x, const random_var& y)
+{
+ const int start = std::max(x.min(), y.min());
+ const int end = std::max(x.max(), y.max()) + 1;
+ std::vector<int> weights(end - start, 0);
+
+ for (int vx = x.min(); vx <= x.max(); ++vx)
+ for (int vy = y.min(); vy <= y.max(); ++vy)
+ weights[std::max(vx, vy) - start] += x.weight(vx) * y.weight(vy);
+
+ return (random_var(start, end, weights));
+}
+
+random_var rv::min(const random_var& x, const random_var& y)
+{
+ const int start = std::min(x.min(), y.min());
+ const int end = std::min(x.max(), y.max()) + 1;
+ std::vector<int> weights(end - start, 0);
+
+ for (int vx = x.min(); vx <= x.max(); ++vx)
+ for (int vy = y.min(); vy <= y.max(); ++vy)
+ weights[std::min(vx, vy) - start] += x.weight(vx) * y.weight(vy);
+
+ return (random_var(start, end, weights));
+}
+
+random_var rv::roll_dice(int d, int n)
+{
+ if (n <= 0)
+ return (constant(0));
+ random_var x = constant(0);
+ for (int i = 0; i < d; ++i)
+ x += random_var(1, n+1);
+ return (x);
+}
+
+random_var rv::random2(int n)
+{
+ return (random_var(0, std::max(n, 1)));
+}