1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
|
D I C E L A B R E A D M E
===========================
Purpose
-------
Dicelab is intended to examine dice rolling schemes and roll dice according
to such a scheme. It may be helpfull when designing or playing certain games.
The current version can determine the statistical distribution by rolling over
and over again, or by actually doing the maths. The latter is more precise, but
might be prohibitively slow in some cases.
Getting new Versions
--------------------
New versions should always be available from
http://www.semistable.com/dicelab/
Build Requirements
------------------
In order to build dicelab from source you will need:
* GNU Make
* gcc
If you want to hack on this, you will also need:
* flex
* bison
* treecc
Compilation
-----------
To build this program run './configure' and inspect the output for problems.
This will also honour the '--prefix' option to specify where you want the
program to be installed. To build dicelab then run 'make'.
Installation
------------
The command 'make install' (as root) will install the program and accompanying
documentation files to the location specified during './configure' (the default
is /usr). Optionally, you can of course copy the files to their intended
location by hand.
Win32
-----
Dicelab can be built into a Win32 (commandline) executable using Mingw32 (and
probably other tools as well). In order to do this, you need a static flex
library for the target system, and then set CC and LDFLAGS accordingly. In my
case i do change the Makefile that gets generated by ./configure:
CC=i586-mingw32msvc-cc
LDFLAGS=-L../flex/lib
Should you have problems getting this to work, you can always mail me and i'll
provide you with a binary (though i don't understand why you use win32 at all)
Running
-------
Dicelab is called like this:
dicelab [options] [-f <file>]
The options include
--help -h -? print a help message
--version -v display the version number
--print-tree -p print the parse tree (for debugging purposes)
--eval -e evaluate the statistical distribution by re-rollingp
--count -c specify the number of rolls used with --eval
default is 10000
--roll -r roll the dice as specified. This will also be used
if no other action is requested
--threshold -t cutoff threshold, results with a probability less
than this value will be discarded by some operations
when using --calc
--file -f <name> read the dice rolling specs from the file
specified, use stdin if not supplied
If you don't specify a file with the dice rolling scheme, dicelab will read
from stdin.
Quick Start
-----------
Single die rolls may be made using the 'd' operator, followed by the number of
faces on the die to be rolled. E.g., d6 will roll a single six-sided die, and
d2 will flip a coin. Expressions may be modified by the standard arithmetic
operators. d10-1 will yield a value between 0 and 9, inclusive. In order to
roll multiple dice of the same type, use the repetition operator '#'. 2#d6
will roll two six-sided dice; this is not the same as 2*d6, which rolls only
a single die but multipies the result by two, or 2d6 which will cause a syntax
error. In order to get the sum of two six-sided dice, do sum(2#d6).
Full Syntax
-----------
<integer> ::=
-?[0-9]+
<variable> ::=
[A-Za-z]+
<scalar> ::=
<integer>
| <variable>
| ( <scalar> )
| - <scalar>
| <scalar> + <scalar>
| <scalar> - <scalar>
| <scalar> * <scalar>
| <scalar> / <scalar>
| <scalar> % <scalar>
| <scalar> ^ <scalar>
| <scalar> . <scalar>
| d<scalar>
| sum <expr>
| prod <expr>
| count <expr>
<list> ::=
<scalar> # <expr>
| ( <list> )
| <scalar> .. <scalar>
| <expr> , <expr>
| perm <expr>
| sort <expr>
| rev <expr>
| (drop|keep)? low <scalar> <expr>
| (drop|keep)? high <scalar> <expr>
| (drop|keep)? first <scalar> <expr>
| (drop|keep)? last <scalar> <expr>
| (drop|keep)? == <scalar> <expr>
| (drop|keep)? != <scalar> <expr>
| (drop|keep)? < <scalar> <expr>
| (drop|keep)? > <scalar> <expr>
| (drop|keep)? <= <scalar> <expr>
| (drop|keep)? >= <scalar> <expr>
| if <expr> then <expr> else <expr>
| let <variable> = <expr> in <expr>
| while <variable> = <expr> do <expr>
| foreach <variable> in <expr> do <expr>
<expr> ::=
<scalar>
<list>
<input> ::=
<expr>
| <expr> ; <expr>
Comments may be inserted by using double slashed (//) as in C.
Sematics
--------
+
-
*
/
^
These are the familiar binary arithmetic operators for addition,
subtraction, multiplication, division, and exponentiation. Division
rounds toward zero. Examples: 5+7, d6-1, 2^10
-
This is the unary minus operator. Examples: -1
%
This is the modulus operator. x % y gives the remainder of x divided by y.
Examples: 11%2, d6%3
.
This is the scalar concatenation operator. x . y gives xy, the
concatenation of x and y. Examples: -10.9, d6.d6
d
This is the die roll operator. dn gives the value of a single roll of an
n-sided die. Examples: d6, 2#d6
sum
prod
These are the extended sum and product operators. If e is an expression,
sum e and prod e give the sum of the members of e and the product of the
members of e, respectively. Examples: sum(1..100), prod(3#d6)
count
This is the list size operator. If e is an expression, then count e gives
the number of members of e. Examples: count(1,2,3), count(== 6 10#d6)
#
This is the list repetition operator. If n is a nonnegative scalar and e is
an expression, then n#e is a list containing the results of n evaluations
of e. Examples: 10#8, 3#d10
..
This is the range operator. If x and y are scalars, then x..y is a list
consisting of the interval [x,y]. If x>y, then the resulting list is empty.
Examples: 1..10, 4..d10
,
This is the list concatenation operator. v,u gives the list consisting of
all of the members of v, followed by all of the members of u. Examples:
1,2 4,(3#d6)
sort
This is the list sorting operator. sort e sorts the list e in ascending
order. Examples: sort(10#d6)
perm
This is the list permutation operator. sort e results in a random
permutation of the list e. Use perm to shuffle a list.
Examples: perm(1..52)
rev
This is the list reversal operator. rev e results in a list with the same
members as the list e, but in reverse order. Examples: rev(1..10), rev
sort(10#d8)
low
high
These operators act as filters by finding the least and greatest values in
lists. If n is a nonnegative scalar and e is an expression, then low n e
gives the n least members of e, and high n e gives the n greatest members
of e. Examples: high 3 5#d6
first
last
These operators act as filters by finding initial and final segments of
lists. If n is a nonnegtive scalar and e is an expression, then first n e
gives the first n members of e, and last n e gives the last n members of e.
Examples: first 3 (1..10)
==
!=
<
>
<=
>=
These operators act as filters by finding values in lists which meet given
conditions. If x is a scalar and e is an expression, then == x e gives the
list of members of e equal to x; != x e gives the list of members of e not
equal to x; < x e gives the list of members of e less than x; > x e gives
the list of members of e greater than x; <= x e gives the list of members
of e less than or equal to x; >= x e gives the list of members of e greater
than or equal to x. Examples: >= 3 5#d6
drop
keep
These operators modify filters on lists. If fop is a filter operation on an
expression e, then keep fop e has the same result as fop e and drop fop e
evaluates to e less keep fop e. In other words, drop negates filter
conditions, and keep affirms them. keep is never necessary and exists only
for symmetry. Examples: sum(drop low 1 4#d6)
let
This is the variable assignment and substitution operator. If x is a
variable and e and f are an expressions, then let x = e in f gives the list
which results from evaluating f with the value of e substituted for every
occurance of x in f. Evaluation of e is done prior to substitution.
Examples: let x = d6 in x*x
foreach
This is the bounded iteration operator. If x is a variable and e and f are
expressions, then foreach x in e do f gives the list which results from
assigning to x each of the members of e and evaluating f. Examples: foreach
x in c do x+1
while
This is the unbounded iteration operator. If x is a variable and e and f
are expressions, then while x = e do f is the list v0,v1,...,vn, where v0
is the result of evaluating e and vi+1 is the result of assigning vi to x
and evaluating f, stopping at the first vi which is empty.
Examples: while x=d6 do ((count <6 x)#d6)
if
This is the branching operator. If e, f, and g are expressions, then if e
then f else g gives f if e is nonempty, and g otherwise. Examples: if
count(>4 2#d6) then 1 else 0
Examples
--------
* Count the number of dice greater than 7:
count >7 5#d10
* Count the number of dice greater than 7 minus the number of dice equal to 1:
let c=5#d10 in (count >7 c)-(count ==1 c)
* Count the number of rolls until a 6 is rolled:
count (while x=d6 do ((count <6 x)#d6))
* Count the number of rolls until a 6 is rolled, more efficiently:
count (while x=(d6/6) do ((count <1 x)#(d6/6)))
* Roll attributes for a new D&D character:
6#sum(drop low 1 4#d6)
* Roll on the 11..66 morale check table in The Gamers' Civil War Brigade
Series:
d6.d6
* Find the median of 3 d20s:
high 1 low 2 3#d20
* 3d6 with rerolls on 6s:
sum(while x=3#d6 do ((count ==6 x)#d6))
* Roll 7 d10 and find the largest sum of identical dice:
let x = 7#d10 in high 1 (foreach y in 1..10 do sum (==y x))
* The Fibonacci sequence is defined by Fn = Fn-1 + Fn-2, with F1 = F2 = 1.
Calculate the first twenty Fibonacci numbers:
let n = 20 in
let f = (1,1) in
foreach i in 1..n do
let f = (f,sum(high 2 f)) in
if ==n i then f else ()
* Risk has battles where the attacker rolls 3d6 and the defender rolls 2d6.
The highest attacker die is matched with the highest defender die and the
second highest attacker die to the second highest defender die. For both
matches, the highest wins, with ties going to the defender. The number of
attacker wins:
let a = 3#d6 in
let b = 2#d6 in
count( (<(high 1 a) high 1 b),
(<(high 1 low 2 a) low 1 b))
* Storyteller die roll with target number 8 and botches indicated at -1:
let c=5#d10 in
let succs = count >7 c in
let ones = count ==1 c in
if >0 succs then high 1 (0,succs-ones)
else if >0 ones then -1 else 0
* Combat in Silent Death is rather complex. Three dice are rolled. If their
sum is above a target, the roll is a hit. To calculate damage, the same dice
are sorted. If all three are equal, all are summed to yield the damage. If
the least two are equal, but the third is higher, the high die is the damage.
If the two highest are equal, but the third is lower, the two high dice are
summed to yield the damage. If all three dice are different, the middle die
is the damage. This example assumes that the dice are two d8s and a d10, with
a target number of 15:
let x = 2#d8,d10 in
(count >15 sum x)#
let a = low 1 x in // low die
let b = high 1 low 2 x in // middle die
let c = high 1 x in // high die
if ==a ==b c then a+b+c // all equal
else if ==a <c b then c // two low equal
else if >a ==c b then b+c // two high equal
else b // all different
Documentation
-------------
A more in-depth documentation of dicelab and the language can be found in the
"Dicelab Manual" that should have been included in your copy of dicelab, or
can be gotten from the web site.
Credits
-------
Dicelab is based on the excellent work "roll" by Torben Mogensen
(http://www.diku.dk/~torbenm/Dice.zip). Without his work and comments, this
would hardly ever have happened.
The current language specification and the extensions to the original language
are derived from the work of Joel Uckelman (http://dice.nomic.net/bones.html),
most of the documentation is stolen from him as well.
This code was written by Robert Lemmen <robertle@semistable.com>, who would be
glad to hear your questions and remarks.
|