All Projects → bakame-php → dice-roller

bakame-php / dice-roller

Licence: MIT license
a dice roller generator in PHP

Programming Languages

PHP
23972 projects - #3 most used programming language

Projects that are alternatives of or similar to dice-roller

quick-dice-roller
The flexible, complete and handy Android dice roller for boardgame & RPG geeks.
Stars: ✭ 16 (+23.08%)
Mutual labels:  dice, dice-roller, rpg-dice-roller
d20
A fast, powerful, and extensible dice engine for D&D, d20 systems, and any other system that needs dice!
Stars: ✭ 78 (+500%)
Mutual labels:  dice, dice-roller
rfyl
An RPG dice roller.
Stars: ✭ 11 (-15.38%)
Mutual labels:  dice-roller, rpg-dice-roller
dice-simulator
A Python simple Dice Simulator just for fun
Stars: ✭ 17 (+30.77%)
Mutual labels:  dice, dice-roller
tavernbot
D&D Discord Bot - based on Discord.js and Node 8.
Stars: ✭ 21 (+61.54%)
Mutual labels:  dice, dice-roller
DiceRoller
Extensible and well-documented dice roller with a robust set of features. Excellent for play-by-post forums, virtual tabletops, or for integrating into character sheets or encounter managers.
Stars: ✭ 22 (+69.23%)
Mutual labels:  dice, dice-roller
rpg-dice-roller
📱 RPG Dice Roller, Number Generator, Coin Flip - Available on Google Play Store - Made with React Native | Styled-Components
Stars: ✭ 15 (+15.38%)
Mutual labels:  dice-roller, rpg-dice-roller
Random-Number-Generator
A clean, simple random number generator for Android. Downloaded 180,000+ times and rated 2,000+ times on Google Play with 4.7+ average rating.
Stars: ✭ 30 (+130.77%)
Mutual labels:  dice
roller
Dice roller written in Go and Javascript to run on Google Appengine
Stars: ✭ 26 (+100%)
Mutual labels:  dice
rollem-telegram-bot
🎲 An RPG dice rolling bot for Telegram.
Stars: ✭ 26 (+100%)
Mutual labels:  dice
RelevancyTuning
Dice.com tutorial on using black box optimization algorithms to do relevancy tuning on your Solr Search Engine Configuration from Simon Hughes Dice.com
Stars: ✭ 28 (+115.38%)
Mutual labels:  dice
dice-coefficient
Sørensen–Dice coefficient
Stars: ✭ 37 (+184.62%)
Mutual labels:  dice
ApocaBot
ApocaBot: A Discord Bot for PbtA Games
Stars: ✭ 30 (+130.77%)
Mutual labels:  rpg-dice-roller
fast-loaded-dice-roller
The Fast Loaded Dice Roller: A Near-Optimal Exact Sampler for Discrete Probability Distributions
Stars: ✭ 41 (+215.38%)
Mutual labels:  dice-roller
roll
RPG dice roller with both Rust CLI and ClojureScript Web interfaces
Stars: ✭ 14 (+7.69%)
Mutual labels:  rpg-dice-roller
mirai-rulateday-dice
利用Mirai框架的Mirai-Console开发TRPG骰子插件模板。目前集成了大部分的常用指令,并在此基础上实现更多的跑团体系优化指令。例如COC7技能详细查询、DND5e技能列表查询、DND5e怪物图鉴等。目前处于测试阶段。
Stars: ✭ 55 (+323.08%)
Mutual labels:  dice
SolrConfigExamples
Examples of Solr configuration entries for Solr plugins and Conceptual Search\Semantic Search from Simon Hughes Dice.com
Stars: ✭ 26 (+100%)
Mutual labels:  dice
PolyDiceGenerator
A customizable Polyhedral Dice Generator for OpenSCAD.
Stars: ✭ 63 (+384.62%)
Mutual labels:  dice
dicefont
Scalable vector graphics for dice in icon font format
Stars: ✭ 20 (+53.85%)
Mutual labels:  dice
DicePP
基于nonebot和go-cqhttp的骰子机器人
Stars: ✭ 17 (+30.77%)
Mutual labels:  dice

Dice Roller

Software License Build Status

A simple Dice Roller implemented in PHP.

<?php

// First: import needed class
use Bakame\DiceRoller\Factory;

// Factory allow us to create dice cup.
$factory = Factory::fromSystem();

// We create the cup that will contain the two die:
$cup = $factory->newInstance('2D6');

// Roll and display the result:
echo $cup->roll()->value(); // returns 6

This is a fork of Ethtezahl/Dice-Roller. The goal of this package is to build a modern PHP package which follow best practices while creating a fun OSS project.

System Requirements

You need PHP >= 8.0 but the latest stable version of PHP is recommended.

Installation

$ composer require bakame-php/dice-roller

All classes are defined under the Bakame\DiceRoller namespace.

Usage through the bundle cli command

$ bin/roll --iteration=3 --logs 2D3+5
 ====== ROLL RESULTS ======= 
 Result #1:  8
 Result #2:  10
 Result #3:  10

 ====== ROLL TRACE ======= 
 [Bakame\DiceRoller\Cup::roll] - 2D3 : 1 + 2 = 3   
 [Bakame\DiceRoller\Arithmetic::roll] - 2D3+5 : 3 + 5 = 8   
 [Bakame\DiceRoller\Cup::roll] - 2D3 : 3 + 2 = 5   
 [Bakame\DiceRoller\Arithmetic::roll] - 2D3+5 : 5 + 5 = 10   
 [Bakame\DiceRoller\Cup::roll] - 2D3 : 3 + 2 = 5   
 [Bakame\DiceRoller\Arithmetic::roll] - 2D3+5 : 5 + 5 = 10  

Basic usage

Use the library factory to simulate the roll of two six-sided die

<?php

use Bakame\DiceRoller\Factory;

$factory = Factory::fromSystem();
$pool = $factory->newInstance('2D6+3');

echo $pool->notation();    // returns 2D6+3
echo $pool->roll()->value(); // returns 6

Advance usage

Use the library bundled rollable objects to build a dice pool to roll.

<?php

use Bakame\DiceRoller\Cup;
use Bakame\DiceRoller\SidedDie;
use Bakame\DiceRoller\Arithmetic;

$die1 = new SidedDie(6);
$die2 = new SidedDie(6);
$cup = new Cup($die1, $die2);
$pool = Arithmetic::add($cup, 3);

echo $pool->notation();      // returns 2D6+3
echo $pool->roll()->value(); // returns 12

Tracing an operation

<?php

use Bakame\DiceRoller\Factory;
use Bakame\DiceRoller\MemoryTracer;

$tracer = new MemoryTracer();
$factory = Factory::fromSystem();
$pool = $factory->newInstance('2D6+3', $tracer);

echo $pool->notation();  // returns 2D6+3
$roll = $pool->roll();
echo $roll->value();      // displays 12
echo $roll->operation(); // displays 9 + 3

foreach ($tracer as $trace) {
    echo sprintf(
        '[%s] - %s : %s = %s',
        $trace->context()->source(),
        $trace->context()->notation(),
        $trace->operation(),
        $trace->value()
    ), PHP_EOL;
}

// [Bakame\DiceRoller\Cup::roll] - 2D6 : 5 + 4 = 9
// [Bakame\DiceRoller\Arithmetic::roll] - 2D6+3 : 9 + 3 = 12

Documentation

Parsing Dice notation

The Factory

In order to roll the dice, the package comes bundles with a factory class, Bakame\DiceRoller\Factory, to create a Rollable object from the result of such parsing. The factory is able to extract roll rules in a case incensitive way from a string notation and convert them into an PHP Rollable object.

Here's the list of supported roll rules by Bakame\DiceRoller\Factory.

Annotation Examples Description
NDX 3D4 create a dice pool where N represents the number of dices and X the number of sides. If X is omitted this means you are requesting a 6 sides basic dice. If N is omitted this means that you are requestion a single dice.
NDF 3DF create a dice pool where N represents the number of fudge dices. If N is omitted this means that you are requestion a single fugde dice.
ND% 3D% create a dice pool where N represents the number of percentile dices. If N is omitted this means that you are requestion a single percentile dice.
ND[x,x,x,x,...] 2D[1,2,2,5] create a dice pool where N represents the number of custom dices and x the value of a specific dice side. The number of x represents the side count. If N is omitted this means that you are requestion a single custome dice. a Custom dice must contain at least 2 sides.
oc ^3 where o represents the supported operators (+, -, *, /, ^) and c a positive integer
!oc !>3 an explode modifier where o represents one of the supported comparision operator (>, <, =) and c a positive integer
[dh,dl,kh,kl]z dh4 keeping or dropping the lowest or highest z dice

When using the factory:

  • Only 2 arithmetic modifiers can be appended to a given dice pool.
  • The = comparison sign when using the explode modifier can be omitted

TIP: You should use parenthesis to add more modifiers to your pool

The Factory can optionally attach a tracer to any object that can be traced.

<?php

namespace Bakame\DiceRoller;

final class Factory
{
    public function __construct(RandomIntGenerator $randomIntGenerator);
    public function newInstance(string $notation, Tracer $tracer = null): Rollable;
}

Using both classes we can then parse the following notation.

<?php

use Bakame\DiceRoller\Factory;

$factory = Factory::fromSystem();
$cup = $factory->newInstance('3D20+4+D4!>3/4^3');

echo $cup->roll()->value();

If the Factory is not able to parse or create a Rollable object from the string notation a Bakame\DiceRoller\CanNotBeRolled exception will be thrown.

Rollable

The Factory::newInstance method always returns objects implementing the Bakame\DiceRoller\Rollable interface.

<?php

namespace Bakame\DiceRoller;

interface Rollable
{
    public function minimum(): int;
    public function maximum(): int;
    public function roll(): Roll;
    public function notation(): string;
}
  • Rollable::minimum returns the minimum value that can be returned during a roll;
  • Rollable::maximum returns the maximum value that can be returned during a roll;
  • Rollable::roll returns a a Roll object.
  • Rollable::notation returns the object string notation.

All exceptions thrown by the package extends the basic Bakame\DiceRoller\CanNotBeRolled exception.

Dices Type

In addition to the Rollable interface, all dices objects implement the Dice interface. The size method returns the die sides count.

<?php

use Bakame\DiceRoller\Rollable;

interface Dice extends Rollable
{
    public function size(): int;
}

The following die type are bundled in the library:

Class Name Definition
SidedDie classic die
FudgeDie 3 sided die with side values being -1, 0 and 1.
PercentileDie 100 sided die with values between 1 and 100.
CustomDie die with custom side values
  • A die object must have at least 2 sides otherwise a Bakame\DiceRoller\SyntaxError exception is thrown on instantiation.
  • If a named constructor does not recognize the string notation a Bakame\DiceRoller\Exception\UnknownNotationexception is thrown.
Examples
<?php

use Bakame\DiceRoller\CustomDie;
use Bakame\DiceRoller\FudgeDie;
use Bakame\DiceRoller\PercentileDie;
use Bakame\DiceRoller\SidedDie;

$basic = new SidedDie(3);
echo $basic->notation(); // 'D3';
$basic->roll()->value(); // may return 1, 2 or 3
$basic->size();          // returns 3

$basicBis = SidedDie::fromNotation('d3');
$basicBis->notation() === $basic->notation();

$custom = CustomDie::fromNotation('D[3,2,1,1]');
echo $custom->notation(); // 'D[3,2,1,1]';
$custom->roll()->value(); // may return 1, 2 or 3
$custom->size();          // returns 4

$customBis = CustomDie::fromNotation('d[3,2,1,1]');
$custom->notation() === $customBis->notation();

$fudge = new FudgeDie();
echo $fudge->notation(); // displays 'DF'
$fudge->roll()->value(); // may return -1, 0, or 1
$fudge->size();          // returns 3

$percentile = new PercentileDie();
echo $percentile->notation(); // displays 'D%'
$percentile->roll()->value(); // returns a value between 1 and 100
$fudge->size();               // returns 100

Pool

If you need to roll multiple dice at the same time, you need to implement the Bakame\DiceRoller\Pool interface.

<?php

namespace Bakame\DiceRoller;

interface Pool implements \Countable, \IteratorAggregate, Rollable
{
    public function isEmpty(): bool;
}

A Pool is a collection of Rollable objects which also implements the Rollable interface. The package comes bundle with the Bakame\DiceRoller\Cup class which implements the interface.

<?php

use Bakame\DiceRoller\EnablesDeepTracing;
use Bakame\DiceRoller\Pool;
use Bakame\DiceRoller\Rollable;

final class Cup implements Pool, EnablesDeepTracing
{
    public function __construct(Rollable ...$rollable);
    public static function of(Rollable $rollable, int $quantity = 1): self;
    public function withAddedRollable(Rollable ...$rollable): self;
}

The Cup::of named constructor enables creating uniformed Cup objects which contains only 1 type of rollable object.

<?php

use Bakame\DiceRoller\Cup;
use Bakame\DiceRoller\CustomDie;
use Bakame\DiceRoller\FudgeDie;
use Bakame\DiceRoller\PercentileDie;
use Bakame\DiceRoller\SidedDie;

echo Cup::of(3, new SidedDie(5))->notation();           // displays 3D5
echo Cup::of(4, new PercentileDie())->notation();       // displays 4D%
echo Cup::of(2, CustomDie::fromNotation('d[1, 2, 2, 4]'))->notation(); // displays 2D[1,2,2,4]
echo Cup::of(42, new FudgeDie())->notation();           // displays 42DF

A Cup created using of must contain at least 1 Rollable object otherwise a Bakame\DiceRoller\SyntaxError is thrown.

When iterating over a Cup object you will get access to all its inner Rollable objects.

<?php

use Bakame\DiceRoller\Cup;
use Bakame\DiceRoller\SidedDie;

foreach (Cup::of(3, new SidedDie(5)) as $rollable) {
    echo $rollable->notation(); // will always return D5
}

Once a Cup is instantiated there are no method to alter its properties. However the Cup::withAddedRollable method enables you to build complex Cup object using the builder pattern. The method will always returns a new Cup object but with the added Rollable objects while maintaining the state of the current Cup object.

<?php

use Bakame\DiceRoller\Cup;
use Bakame\DiceRoller\FudgeDie;
use Bakame\DiceRoller\SidedDie;

$cup = Cup::of(3, new SidedDie(5));
count($cup);             //returns 3 the number of dices
echo $cup->notation(); //returns 3D5

$altCup = $cup->withAddedRollable(new FudgeDie());
count($altCup);             //returns 4 the number of dices
echo $altCup->notation(); //returns 3D5+DF

WARNING: a Cup object can be empty but adding an empty Cup object is not possible. The empty Cup object will be filtered out on instantiation or on modification.

<?php

use Bakame\DiceRoller\Cup;
use Bakame\DiceRoller\FudgeDie;

$cup = new Cup(new Cup(), new FudgeDie());
count($cup); // returns 1

Modifiers

Sometimes you may want to modify the outcome of a roll. The library comes bundle with three (3) objects implementing the Modifier interface.
The Modifier interface extends the Rollable interface by giving access to the rollable object being decorated through the Modifier::getInnerRollable method.

<?php

namespace Bakame\DiceRoller;

interface Modifier implements Rollable
{
    public function getInnerRollable(): Rollable;
}

The Arithmetic modifiers

<?php

use Bakame\DiceRoller\Modifier;
use Bakame\DiceRoller\Rollable;
use Bakame\DiceRoller\Tracer;
use Bakame\DiceRoller\SupportsTracing;

final class Arithmetic implements Modifier, SupportsTracing
{
    public static function add(Rollable $rollable, int $value, Tracer $tracer = null): self;
    public static function sub(Rollable $rollable, int $value, Tracer $tracer = null): self;
    public static function mul(Rollable $rollable, int $value, Tracer $tracer = null): self;
    public static function div(Rollable $rollable, int $value, Tracer $tracer = null): self;
    public static function pow(Rollable $rollable, int $value, Tracer $tracer = null): self;
    public static function fromOperation(Rollable $rollable, string $operator, int $value, Tracer $tracer = null): self;
}

This modifier decorates a Rollable object by applying an arithmetic operation on the submitted Rollable object.

The value given must be a positive integer or 0. If the value or the operator are not valid a Bakame\DiceRoller\CanNotBeRolled exception will be thrown.

<?php

use Bakame\DiceRoller\SidedDie;
use Bakame\DiceRoller\Arithmetic;

$modifier = Arithmetic::mul(new SidedDie(6),  3);
echo $modifier->notation();  // displays D6*3;

The DropKeep modifier

<?php

use Bakame\DiceRoller\SupportsTracing;
use Bakame\DiceRoller\Modifier;
use Bakame\DiceRoller\Rollable;

final class DropKeep implements Modifier, SupportsTracing
{
    public static function dropHighest(Rollable $rollable, int $threshold, Tracer $tracer = null): self;
    public static function dropLowest(Rollable $rollable, int $threshold, Tracer $tracer = null): self;
    public static function keepHighest(Rollable $rollable, int $threshold, Tracer $tracer = null): self;
    public static function keepLowest(Rollable $rollable, int $threshold, Tracer $tracer = null): self;
    public static function fromAlgorithm(Rollable $rollable, string $algorithm, int $threshold, Tracer $tracer = null): self;
}

This modifier decorates a Rollable object by applying one of the dropkeep algorithm. The constructor expects:

  • a Rollable object;
  • a algorithm name;
  • a threshold to trigger the algorithm;

The supported algorithms are:

  • dropHighest to drop the $threshold highest results of a given Cup object;
  • dropLowest to drop the $threshold lowest results of a given Cup object;
  • keepHighest to keep the $threshold highest results of a given Cup object;
  • keepLowest to keep the $threshold lowest results of a given Cup object;

The $threshold MUST be lower or equals to the total numbers of rollable items.

If the algorithm or the threshold are not valid a Bakame\DiceRoller\CanNotBeRolled exception will be thrown.

<?php

use Bakame\DiceRoller\Cup;
use Bakame\DiceRoller\SidedDie;
use Bakame\DiceRoller\DropKeep;

$cup = Cup::of(4, new SidedDie(6));
$modifier = DropKeep::dropHighest($cup, 3);
echo $modifier->notation(); // displays '4D6DH3'

The Explode modifier

<?php

use Bakame\DiceRoller\SupportsTracing;
use Bakame\DiceRoller\Modifier;
use Bakame\DiceRoller\Rollable;

final class Explode implements Modifier, SupportsTracing
{
    public static function equals(Rollable $rollable, ?int $threshold, Tracer $tracer = null): self;
    public static function greaterThan(Rollable $rollable, ?int $threshold, Tracer $tracer = null): self;
    public static function lesserThan(Rollable $rollable, ?int $threshold, Tracer $tracer = null): self;
    public static function fromAlgorithm(Rollable $rollable, string $compare, ?int $threshold, Tracer $tracer = null): self;
}

This modifier decorates a Rollable object by applying one of the explode algorithm. The constructor expects:

  • a Rollable implementing object;
  • a comparison operator string;
  • a threshold to trigger the algorithm;

The supported comparison operator are:

  • Explode::equals explodes if any inner rollable roll result is equal to the $threshold;
  • Explode::greaterThan explodes if any inner rollable roll result is greater than the $threshold;
  • Explode::lesserThan explodes if any inner rollable roll result is lesser than the $threshold;

If the comparison operator is not recognized a Bakame\DiceRoller\CanNotBeRolled exception will be thrown.

<?php

use Bakame\DiceRoller\Cup;
use Bakame\DiceRoller\FudgeDie;
use Bakame\DiceRoller\SidedDie;
use Bakame\DiceRoller\Explode;

$cup = new Cup(new SidedDie(6), new FudgeDie(), new SidedDie(6), new SidedDie(6));
$modifier = Explode::equals($cup, 3);
echo $modifier->notation(); // displays (3D6+DF)!=3

Tracing and Profiling

If you want to know how internally your roll result is calculated your Rollable object must implements the SupportsTracing interface.

<?php

namespace Bakame\DiceRoller;

use Bakame\DiceRoller\Tracer;

interface SupportsTracing
{
    public function setTracer(Tracer $tracer): void;
    public function getTracer(): Tracer;
}

The interface enables getting the trace from the last operation as well as profiling the total execution of the operation using a Bakame\DiceRoller\Tracer implementing object.

<?php

namespace Bakame\DiceRoller;

interface Tracer
{
    public function append(Roll $roll): void;
}

The package comes bundle with:

  • the Bakame\DiceRoller\NullTracer which keeps no info about tracing.
  • the Bakame\DiceRoller\MemoryTracer which keeps the trace in a in-memory collection.
  • the Bakame\DiceRoller\Psr3LogTracer which sends the traces to a PSR-3 compliant logger.

Tracing using the MemoryTracer

No configuration is needed you just need to give your object an instantiated MemoryTracer.

<?php

use Bakame\DiceRoller\Cup;
use Bakame\DiceRoller\SidedDie;
use Bakame\DiceRoller\MemoryTracer;

$tracer = new MemoryTracer();
$tracer->isEmpty(); //returns true
$cup = Cup::of(3, new SidedDie(6));
$cup->setTracer($tracer);
$cup->roll();
$tracer->isEmpty(); //returns false
foreach ($tracer as $roll) {
    //do something meaningful with the $roll object
}
//or
$trace = $tracer->get(0);
$tracer->reset();  //clear all the traces from the object
$tracer->isEmpty(); //returns true

The MemoryTracer can also be encoded using json_encode.

Tracing using the Prs3LogTracer

<?php

namespace Bakame\DiceRoller;

use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;

final class Psr3LogTracer implements Tracer
{
    public const DEFAULT_LOG_FORMAT = '[{method}] - {rollable} : {trace} = {result}';
    public function __construct(
        LoggerInterface $logger,
        string $logLevel = LogLevel::DEBUG,
        string $logFormat = self::DEFAULT_LOG_FORMAT
    );
    public function logger(): LoggerInterface;
    public function logLevel(): string;
    public function logFormat(): string;
}

The LogTracer log messages, by default, will match this format:

[{source}] - {notation} : {operation} = {value}

The context keys are:

  • {source}: The method that has created the profile entry.
  • {notation}: The string representation of the Rollable object to be analyzed.
  • {operation}: The mathematical operation that produced the result.
  • {value}: The result from performing the calculation.

Configuring the logger is done on instantiation.

<?php

use Bakame\DiceRoller\Psr3Logger;
use Bakame\DiceRoller\Psr3LogTracer;
use Psr\Log\LogLevel;

$logger = new Psr3Logger();
$tracer = new Psr3LogTracer($logger, LogLevel::DEBUG, '{notation} = {result}');

Even though, the library comes bundles with a Psr\Log\LoggerInterface implementation you should consider using a better flesh out implementation than the one provided out of the box.

Happy Coding!

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].