~ubuntu-branches/ubuntu/intrepid/dicelab/intrepid

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
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
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


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.