pif_DiceSimulator

by Popisfizzy
A library simulate dice rolls and perform handling and filtration of collections of dice.
ID:1963217
 
pif_DiceSimulator is a library that can be used to go beyond the native functionality of the DM language in terms of simulation of dice rolls. Its intended use is to allow programmers to implement non-standard dice of various sorts, and to let them simulate rolling them either individually or as collections of dice. Furthermore, as collection of die one can maintain a state of rolled dice for arbitrarily long and perform inspection and filtration of these die.

The primary built-in functions that one would use to simulate dice rolls are roll(), pick(), and rand(). roll() is limited, in that while it is able to simulate the rolling of arbitrarily many die with arbitrarily-many sides, these die are always 'standard'. That is, the die it simulates are always numbered with {1, ..., k} where k >= 1 is some natural number. Thus, it can not simulate biased die or coins, non-transitive die, or any other interesting die that result from uneven probabilities. Furthermore, the result of multiple die is always summed and output, precluding any sort of filtration or inspection of individual die.

pick() can mitigate these issues by allowing for the simulation of non-standard die, but it does not allow for the easy inspection and filtration of die without what would be, effectively, re-implementing this library. rand() is similar in this regard, in that while this library uses rand() for its random numbers, to mimic this library's functionality you would effectively be re-implementing the library.

How to Use

This library comes with two parts: the simulation of individual dice, and the handling of collections of die.

Basic Dice

Basic dice refers to any dice that can be stored as a list of sides. For example, standard die such as a six-sided die could be stored as list(1, 2, 3, 4, 5, 6), while a die with a slight bias for 1 and a slightly stronger bias for 6 could be stored as list(1, 1, 2, 3, 4, 5, 6, 6, 6).

These sorts of die can be implemented without any extension of the native classes. To do this, one must simply pass the list as either a /list object or a list of arguments to the constructor of the /pif_DiceSimulator/Dice class. For example, a standard six-sided die could be implemented on the fly as

var/pif_DiceSimulator/Dice/d6 = new(1, 2, 3, 4, 5, 6)


Then, to simulate a dice roll, one would simply use the /Dice.Roll() method:

world << d6.Roll() // Would output 1, 2, 3, 4, 5, or 6.


Common Dice

To simplify things, seven common types of dice (including all dice derived from Platonic solids) are pre-implemented as children of the /Dice class.

  1. A two-sided die (a.k.a. a coin), under /pif_DiceSimulator/d2 and with an alias under /pif_DiceSimulator/coin (technically a child of /d2 without any changes). In addition to the standard /Dice.Roll() method, it also has a /d2.Flip() method which is an alias for Roll(). Additionally, the Map() method will output "heads" and "tails".
  2. A four-sided die, implemented under /pif_DiceSimulator/d4.
  3. A six-sided die (the prototypical type of die), implemented under /pif_DiceSimulator/d6.
  4. An eight-sided die, under /pif_DiceSimulator/d8.
  5. A ten-sided die, under /pif_DiceSimulator/d10.
  6. A twenty-sided die, under /pif_DiceSimulator/d20.
  7. A fudge die, used in the Fudge role-playing system. This die has numeric sides given by [-1, -1, 0, 0, 1, 1] when using the Roll() method, and text sides given by ["-", "-", " ", " ", "+", "+"] when using the Map() method.

Custom Dice

In addition to simple dice, one may also extend the /pif_DiceSimulator/Dice class in order to create die with more complex behaviors. To do this, one would create a child class of the /Dice class and modify its Roll() method and possibly its Map() method.

The Roll() method should only produce numeric outputs, or else functionality of this library will break. If you wish to associate a text (or other) value with the sides, the Map() method should be used instead. When this method is not supplied an argument, it will simulate a dice roll (by calling the Roll() method) and then outputs the associated value of the simulated roll.

Collections of Dice

While simulating dice rolls is the first part of this library, the second part is the handling of rolling collections of various dice. This is done by the /pif_DiceSimulator/Collection class. This class is instantiated in one of the following two ways.

new /pif_DiceSimulator/Collection(D1, ... ,Dk)
new /pif_DiceSimulator/Collection("NdS")


In the first, D1 through Dk are /Dice objects that will be simulated being rolled. In the latter, "NdS" is a string where N is an optional, positive natural number indicating the number of dice to roll, and S is a positive natural number indicating the number of sides on the die being rolled. If N is left off (i.e., the string is "dS" instead of "NdS") it defaults to 1.

When you wish to roll a collection of dice, you call the Roll() method. This method will, as it simulates the roll, order the data from smallest to largest based on the numerical value of the roll, and also generate a list of data pulled from Map() for each roll, arranged using the order data of the numeric values. This data is stored until it is cleared either by another call to Roll() or by calling the Clear() method.

The /Collection class also has several filtration methods, allowing you to sort out rolls that don't meet certain criteria. These are Above(), Below(), Inside(), and Outside():

  1. Above() returns only rolls that are at or above a certain bound.
  2. Below() returns only rolls that are at or below a certain bound.
  3. Inside() returns only rolls that are within an upper and lower bound, inclusive.
  4. Outside() returns only rolls that are above a certain upper bound or below a certain lower bound, inclusive.

There is also MapAbove(), MapBelow(), MapInside(), and MapOutside( for the Map() values of these rolls.

Both the inspection and filtration methods are useful because they result in much different probability distributions that you would get from just taking the sum of the die, though this is still possible via the Sum() method. Thus, they allow you to skew results in favor of one outcome or another by choosing die in a certain manner—though not with absolute certainty. In terms of game design, this can make for interesting choices for the player.

Release Notes
Version 1.1.20191223.
  • Changed class naming conventions to be consistent with future libraries (capitalized the first letter of class names).
  • Updated documentation.
    • Changed class naming convention to match class implementation.
    • Added some extra class information.
    • Documented the PIF_DICESIMULATOR_INCLUDED preprocessor.
    • Added Release Notes section.
  • Note: Apparently this update has been sitting on my hard drive since late October 2015, and I never actually got around to putting it up on the hub. Whoops!
Version 1.0.20151016.
  • Initial release.
The MIT License
Copyright (c) 2019 Timothy "popisfizzy" Reilly

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.