Dice2 library API reference

Overwiew

Dice2 is a library designed to allow evaluation of complex expressions involving dice rolls, and to compute probabilities on those expressions. It is targetted for role-playing games (both real pen & paper and CRPG), and can be used in many different ways:

Of course, it may have different uses, feel free to show your creativity and to use it as you wish :)

General concepts

Dice code

A simple dice code is a basic expression describing a set of dice to roll with some rules. A dice code is an arithmetic operator with some arguments (from 0 to 3). In future versions, functions-like syntax may be added to allow dice code with more than 3 parameters.

Many dice codes are based on a specific RPG rules, like World of Darkness, Rolemaster, Ars Magica, Arkeos or similar dice codes. Some are more generic, like the classical ''sum them all'' dice code.

A complex dice code is an arithmetic expression including one or more simple dice code, like 3d6+2d4. Classic priority is used for arithmetic operators, dice codes having a higher priority than any arithmetic operator: 3d6*2 is the same than (3d6)*2.

Dice tree

A dice tree is the result of the parsing of a string representation of an arithmetic expression containing dice codes (and normal arithmetic operators) into a tree. This tree can then be evaluated by the library, much faster than the string itself. Use a dice tree when you'll have to evaluate (roll) the same expression more than once.

Fuzzy logic

A fuzzy logic engine is included to allow exact and fast computing of (some) probability. The idea is simple: instead of evaluating the dice tree in the space of normal integers, with each dice code resulting in dice rolls, the dice tree is evaluated in the space of fuzzy integers, and each dice code becomes a fuzzy integer with the probability of each result as the weight of each possible value.

Please note that some dice codes, like those who can have infinite values, do not support fuzzy logic evaluation.

Error system

Since version 0.7.0, libdice2 provides an error queue. Errors have a type and and a level. Each error occuring inside an operation of dice2 is pushed at the end of the queue, or discarded, depending of its level and the current configuration.

You should, after each call (or set of calls) to libdice2, fetch errors, and process them as you wish.

Thread safety

Since version 0.7.0, libdice2 provides support for thread-safety. You need to explicit enable it, by giving to libdice2 the functions to use for several operations (locking/unlocking a mutex, and getting the current thread id).

Once the thread-safety is on, you can use libdice2 in a multithreaded program, and the error queue will be local to your current thread.

Pay attention that you still need to provide external locking if more than one thread access to a any given libdice2 object (tree, fuzzy set, ...)

API Reference

This API Reference only contains documentation for the functions designed to be called from a program using libdice2. If you want documentation about some internal functions, look at the source code and .h files, there should be enough comments; if not, mail me.

General API

General information

void dice_help (FILE *out);
Diplays an help message about dice codes on the given file.
const char *dice_version ();
Returns the current version of libdice2, as a x.y.z string.

Customization variables

The following variables are available to customize the library behavior:

int dice_limit_group_size;
Limit the size of each dice pool or group. Negative value means unlimited. You can use this variable to protect from a DoS in case of a publically available dice roller. Pay attention that no warranty is made that there is no way to bypass the DoS protection.
int dice_limit_simulation_iterations;
Limit the number of iterations of a simulated dice roll. See comments of dice_limit_group_size.

Customization functions

void dice_cache_configure (int cachesize, int nbbuckets);

Configure the size of the cache used to store fuzzy logic intermediate computations. Pay attention that if the cache is too small compared to what you ask for, the algorithm used will stop to be polynomial. Changing tne number of buckets or reducing the size of the cache will flush it.

The cache is an hashtable, the number buckets is the size of the primary table, and the cachesize the maximal number of items that can be stored in the cache.

void dice_srandom ();
Seed the pseudo-random number generator using /dev/urandom if available or system time else. You should call this function or seed the PRNG by yourself at the startup of your program.

Tree API

dice_tree_t *dice_tree_build (const char *s);
Parse the string and build a new tree from it.
void dice_tree_free (dice_tree_t *tree);
Free the memory allocated by the tree.

Rolling API

int dice_eval_string (const char *s);
The simplest function, that takes a string, evaluates it and roll all needed dice codes.
int dice_tree_eval (const dice_tree_t *tree);
Do the same as the previous one, but on a previously parsed tree.
int dice_roll_* (...);
For each supported dice code, there is a specific raw dice rolling function, see the full list and prototypes in dice_code.h

Detailed rolling

How to get detailed results

Each of the previous rolling function (string, tree or specific) support a _full version, which can return additional informations. The _full versions take two extra parameters: dice_detail_level_t  level and dice_roll_list_t  **list. The level can be LEVEL_NONE (0), LEVEL_GROUP, LEVEL_SINGLE or LEVEL_BOTH (binary or of the two previous), specifying which results to include.

LEVEL_GROUP includes all intermediate results of dice groups, like in 3d6+2d4, two group results will be returned: the result of 3d6 and the result of 2d4.

LEVEL_SINGLE includes all the individual dice rolled during the evaluation.

How to use detailed results

The dice_roll_list_t is a NULL-terminated linked list of dice_roll_t elements. Each dice_roll_t element contains the string representation of what was rolled in the dice field, the level (group or single) of the intermediate result, and the result of the roll.

You can use the following helper functions:

void dice_roll_list_free (dice_roll_list_t *list);
Free a list and all its elements.
int dice_roll_list_size (const dice_roll_list_t *list);
Count the number of elements of the list (this is O(n) on the number of elements of the list).

Fuzzy logic

How to get a fuzzy logic evaluation ?

dice_fuzzy_t *dice_eval_string_fuzzy (const char *s);
Evaluate a string as a fuzzy integer, set an error if not possible.
dice_fuzzy_t *dice_tree_eval_fuzzy (const dice_tree_t *tree);
Evaluate a tree as a fuzzy integer, set an error if not possible.

How to use simulate ?

When a fuzzy-logic evaluation is not possible, or too complex, you can simulate it using many rolls. The following functions can do it:

dice_fuzzy_t *dice_simulate_string_fuzzy (const char *s, int nbrolls);
Roll nbrolls times a given string, and retruns a simulated fuzzy int.
dice_fuzzy_t *dice_tree_simulate_fuzzy (const dice_tree_t *tree, int nbrolls);
Roll nbrolls times a given tree, and retruns a simulated fuzzy int.
void dice_tree_simulate_into (dice_fuzzy_t *fuzzy, const dice_tree_t *tree, int nbrolls);
Appends results to an already created fuzzy int. This function is useful to simulate the result small bunch by small bunch, like when you want to create progress bars, or to still react to use input without using multithreading.

What to do with a fuzzy int ?

The fuzzy int are handled with the functions in dice_fuzzyint.h. Here are the most important ones to use a result:

dice_fuzzy_t *dice_fuzzy_ref (dice_fuzzy_t *src);
Increase the reference counter on a fuzzy int.
void dice_fuzzy_unref (dice_fuzzy_t *fuzzy);
Decrease the reference counter on a fuzzy int. If the reference counter reaches 0, the fuzzy int is destroyed.
int dice_fuzzy_get_start (const dice_fuzzy_t *fuzzy);
This function gets the smallest possible value (lower bound of the fuzzy set).
int dice_fuzzy_get_ending (const dice_fuzzy_t *fuzzy);
This function gets the highest possible value (upper bound of the fuzzy set).
number_t dice_fuzzy_get (const dice_fuzzy_t *fuzzy, int what);
This function gets the specific weight (probability) of a given result to occur. Pay attention that if the fuzzy int was not scaled, the weight is not directly a probability.
number_t dice_fuzzy_get_total (const dice_fuzzy_t *fuzzy);
Return the sum of all weights; to get a real probability, you need to divide the weight of a specific item by the total weight of the set.
void dice_fuzzy_normalize (dice_fuzzy_t *fuzzy, number_t total);
Rescale all weights so that the sum will be total. Use 1.0 to have weights being mathematical probabilities, and 100.0 if you want percentile probabilities.

Error API

As explained in the introduction, since version 0.7.0, libdice2 now use an error queue (for each thread). Every time an error occured, it is pushed on the queue.

A full list of function can be found in dice_error.h, only the most important ones will be explained in this document.

void dice_error_set_drop_level (dice_error_level_t level);

Configure the minimal level of errors to keep. Levels are:

  • DICE_ERROR_INFORMATION: simple information item, useful for debugging
  • DICE_ERROR_WARNING: non-fatal warning
  • DICE_ERROR_ERROR: real error, making the current operation to fail
  • DICE_ERROR_CRITICAL: should-not-happen situation, usually a bug in the library or in the program using it
  • DICE_ERROR_INVALID: invalid error level, if you set the drop level to it, all errors will be dropped.
dice_error_t *dice_error_pop ();
Get the first error of the queue (less recent one), and remove it from the queue. The dice_error_t structure contains three fields: the level of the error, the type of the error and a message.
void dice_error_free (dice_error_t *error);
Free an error returned by dice_error_pop
void dice_error_clear ();
Clear the error queue (of the current thread).
const char *dice_error_domain_name (dice_error_type_t type);
Get the domain name from the record in the dice_error_t structure.
const char *dice_error_level_name (dice_error_level_t level);
Get the level name from the record in the dice_error_t structure.

Thread-safety API

To enable thread-safety, you need to call the dice_thread_setup function, with for parameters:

  1. lock_callback a function pointer, taking a single argument, that will lock its argument; for example pthread_mutex_lock.
  2. unlock_callback a function pointer, taking a single argument, that will unlock its argument; for example pthread_mutex_unlock.
  3. lock_data an item to be passed to the two previous functions; for example an allocated and initialized pthread_mutex_t
  4. get_id_callback a function pointer, taking no argument, and returning, as an integer, the current thread id; for example pthread_self