Skip to content

Commit

Permalink
Various updates:
Browse files Browse the repository at this point in the history
- Add roll counting func
- php doc comments
- syntax to drop multiple dice
  • Loading branch information
JiFish committed Sep 25, 2022
1 parent 979dc63 commit 3a0437b
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 12 deletions.
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ You don't have to use composer to include EZDice in your project, but you can:

### roll($diceStr)

Parse **$diceStr** as dice notation then roll those dice. Returns *(int)* total of all rolls and modifiers, or *false* if none were found.
Parse **$diceStr** as dice notation, then roll those dice. Returns *(int)* total of all rolls and modifiers, or *false* if none were found.

The parser is very forgiving, ignoring whitespace and anything else it doesn't recognise. It is also case-insensitive. Dice notation is briefly documented below.

Expand All @@ -66,13 +66,17 @@ Returns a *(string)* representing the total of all modifiers in the last roll. I

e.g. if you rolled `1d8+10+1d4-2` this method would return `+8`.

### strContainsDice($diceStr)

Parse **$diceStr** and returns true if it contains at least one dice roll, otherwise returns false. Useful for verifying user input. Modifiers without dice don't count.

## Dice Notation

- Dice notation is in the form (number of dice)**d**(dice sides). e.g. `2d10`.
- Additional dice can be chained with **+** and **-** operators. e.g. `2d10+1d6`.
- Modifiers can also be specified. e.g. `2d10-5`
- d% can be used as a shorthand for a percentile dice. `1d%` and `1d100` are equivalent.
- Append a roll with -L to drop the lowest dice in that group, or -H to drop the highest. Dropped dice are excluded from the total. e.g. `2d20-L` will roll 2 twenty sided dice and drop the lowest.
- Append a roll with -L to drop the lowest dice in that group, or -H to drop the highest. Dropped dice are excluded from the total. e.g. `2d20-L` will roll 2 twenty sided dice and drop the lowest. You can also specify a number of dice to drop e.g. `6d6-H3` will drop the highest 3 rolls.
- No notation is currently provided for fudge dice. You can use `1d3-2` instead.
- Whitespace, and anything else not recognised as a dice or a modifier, is treated like a **+** operator. e.g. `foo10 1d4bar1d4 5` is equivalent to `5+1d4+1d4+10`, or simply `2d4+15`.

Expand Down
4 changes: 3 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
"rpg",
"dice-notation",
"die",
"dice-roller"
"dice-roller",
"roller",
"random"
],
"require": {
"php": ">=7.0"
Expand Down
11 changes: 10 additions & 1 deletion example.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@
require 'ezdice.php';

$ezd = new ezdice\EZDice();
echo($ezd->roll('1d20+2d4-L+6').PHP_EOL);

$diceStr = '1d20+2d4-L+6';

// Validating a dice string
if ($ezd->strContainsDice("$diceStr") {
echo "$diceStr contains dice!";
};

// Rolling dice
echo($ezd->roll($diceStr).PHP_EOL);
print_r($ezd->getDiceStates());
echo($ezd->getModifier());
68 changes: 60 additions & 8 deletions ezdice.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,28 @@

namespace ezdice;

/**
* EZDice, a dice rolling library
*/
class EZDice {
// Magic dice & modifier matching regex
private $re = '(?<operator>[\+-])?\s*(?<number>\d+)(?:[dD](?<sides>(?:\d+|%))(?:-(?<variant>[LlHh]))?)?';
private $re = '(?<operator>[\+-])?\s*(?<number>\d+)(?:[dD](?<sides>(?:\d+|%))(?:-(?<drop>[LlHh])(?<dquantity>\d+)?)?)';

// Stores information on last roll
private $total = 0;
private $states = [];
private $modifier = 0;

/**
* Parse **$diceStr** as dice notation, then roll those dice.
*
* The parser is very forgiving, ignoring whitespace and anything else it doesn't recognise.
* It is also case-insensitive. Dice notation is documented in README.md
*
* @param string $diceStr the string containing the dice rolls.
*
* @return int|false total of all rolls and modifiers, or false if none were found.
*/
public function roll(string $diceStr)
{
// Reset result values
Expand All @@ -26,7 +39,8 @@ public function roll(string $diceStr)
}

// Search for dice groups and modifiers
preg_match_all("/{$this->re}/", $diceStr, $matches, PREG_SET_ORDER, 0);
// The extra "?" at the end of the regex allows it to find modifiers too
preg_match_all("/{$this->re}?/", $diceStr, $matches, PREG_SET_ORDER, 0);

// Returning false if no matches found
if (sizeof($matches) == 0) return false;
Expand All @@ -39,6 +53,18 @@ public function roll(string $diceStr)
return $this->total;
}

/**
* Parse **$diceStr** and determine if it contains at least one dice roll.
*
* @param string $diceStr the string which may contain dice rolls.
*
* @return bool true if $diceStr contains at least one dice roll, otherwise false.
*/
public function strContainsDice(string $diceStr)
{
return (preg_match_all("/{$this->re}/", $diceStr) > 0);
}

private function addState(int $sides, int $value, bool $dropped = false): void
{
$this->states[] = [
Expand All @@ -65,8 +91,8 @@ private function processGroup(array $group): void
return;
}

// Collect variant information from group
$variant = (isset($group['variant']) ? strtoupper($group['variant']) : null);
// Collect drop information from group
$drop = (isset($group['drop']) ? strtoupper($group['drop']) : null);

// 'd%' can be used as shorthand for 'd100'
$sides = $sides=="%" ? 100 : $sides;
Expand All @@ -80,15 +106,18 @@ private function processGroup(array $group): void
}

// Dropping dice
if ($variant && $number > 1) {
if ($drop) {
$dropQuantity = min($group['dquantity'] ?? 1, $number);
// Sort low to high
sort($results, SORT_NUMERIC);
// Reverse array if dropping lowest
if ($variant == 'L') {
if ($drop == 'L') {
$results = array_reverse($results);
}
$droppedResult = array_pop($results);
$this->addState($sides, $droppedResult, true);
for ($i=0; $i < $dropQuantity; $i++) {
$droppedResult = array_pop($results);
$this->addState($sides, $droppedResult, true);
}
// Cosmetic re-shuffle of rest of dice
shuffle($results);
}
Expand All @@ -101,21 +130,44 @@ private function processGroup(array $group): void
}
}

/**
* Generates the psudo-random number for dice rolls.
*
* @param int $max the highest number on the dice. Roll is 1 - $max (inclusive).
*
* @return int result of the roll.
*/
protected function getRandomNumber(int $max): int
{
return mt_rand(1,$max);
}

/**
* Get the total of the last roll.
*
* @return bool result of test.
*/
public function getTotal(): int
{
return $this->total;
}

/**
* Get the state of the dice after the last roll.
*
* @return array array that describes the state of the dice after the last roll.
*/
public function getDiceStates(): array
{
return $this->states;
}

/**
* Get the combined modifiers of the last roll.
*
* @return string representing the total of all modifiers in the last roll. If there were no modifiers, or they
* cancelled out, an empty string is returned.
*/
public function getModifier(): string
{
if (!$this->modifier) return "";
Expand Down

0 comments on commit 3a0437b

Please sign in to comment.