Skip to content

Commit 742ce6a

Browse files
authored
Merge pull request #30 from borntyping/feature/2023
Release a 4.0.0 update
2 parents 98e1475 + 20183f1 commit 742ce6a

24 files changed

+339
-739
lines changed

.envrc

-3
This file was deleted.

.github/workflows/tests.yaml

+14-19
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,21 @@
1-
name: Tests
1+
name: Test
22
on: [push]
33
jobs:
4-
build:
4+
pytest:
55
runs-on: ubuntu-latest
66
strategy:
77
max-parallel: 4
88
matrix:
9-
python-version: [3.9, 3.8, 3.7, 3.6, 'pypy-3.6', 'pypy-3.7']
9+
python-version:
10+
- '3.8'
11+
- '3.9'
12+
- '3.10'
13+
- '3.11'
1014
steps:
11-
- uses: actions/checkout@v2
12-
- name: 'Set up Python ${{ matrix.python-version }}'
13-
uses: actions/setup-python@v2
14-
with:
15-
python-version: '${{ matrix.python-version }}'
16-
- name: 'Install Python packaging tools'
17-
run: |
18-
python -m pip install --upgrade pip pipenv
19-
pipenv install --dev
20-
env:
21-
PIPENV_NOSPIN: yes
22-
- name: 'Run pytest'
23-
run: |
24-
pipenv run pytest
25-
env:
26-
PIPENV_NOSPIN: yes
15+
- uses: actions/checkout@v2
16+
- uses: actions/setup-python@v2
17+
with:
18+
python-version: '${{ matrix.python-version }}'
19+
- run: python -m pip install pytest black .
20+
- run: pytest
21+
- run: black --check .

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22
*.pyc
33
.cache/
44
.coverage
5+
.idea/
56
.pytest_cache/
7+
.tox/
8+
.venv/
69
__pycache__/
710
build/
811
dist/

LICENCE renamed to LICENSE.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
The MIT License (MIT)
22

3-
Copyright (c) 2013 Sam Clements
3+
Copyright (c) 2013-2023 Sam Clements, 2017 Caleb Johnson
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy of
66
this software and associated documentation files (the "Software"), to deal in

Pipfile

-18
This file was deleted.

Pipfile.lock

-305
This file was deleted.

README.md

+172
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
# dice
2+
3+
A Python library and command line tool for parsing and evaluating dice notation.
4+
5+
_I consider this library "finished", and don't expect to add any more features to it. Bug and security fixes may still be released, especially if you find any bugs after all this time. If you're interested in other libraries in this space, [dyce] has [a great comparison table][comparison-to-alternatives] of Python dice rolling libraries._
6+
7+
[dyce]: https://posita.github.io/dyce/latest/
8+
[comparison-to-alternatives]: https://posita.github.io/dyce/0.6/#comparison-to-alternatives
9+
10+
## Quickstart
11+
12+
### Command-line
13+
14+
```shell
15+
$ roll 3d6
16+
```
17+
18+
The command line arguments are as follows:
19+
20+
* `-m` `--min` Make all rolls the lowest possible result
21+
* `-M` `--max` Make all rolls the highest possible result
22+
* `-h` `--help` Show this help text
23+
* `-v` `--verbose` Show additional output
24+
* `-V` `--version` Show the package version
25+
26+
If your expression begins with a dash (`-`), then put a double dash (`--`)
27+
before it to prevent the parser from trying to process it as a command option.
28+
Example: `roll -- -10d6`. Alternatively, use parenthesis: `roll (-10d6)`.
29+
30+
### Python API
31+
32+
Invoking from python:
33+
34+
```python
35+
import dice
36+
dice.roll('3d6')
37+
```
38+
39+
This returns an `Element` which is the result of the roll, which can be a
40+
`list`, `int`, or subclass thereof, depending on the top-level operator.
41+
42+
## Usage
43+
44+
### Installation
45+
46+
This library is available as `dice` on PyPI. Install it with your Python
47+
package or dependency manager of choice — if you're installing it as a
48+
command-line tool, I recommend [pipx].
49+
50+
A recent version of Python 3 (3.8 or above) is required. You can probably run
51+
it or easily adapt it for older versions of Python, but I don't support any
52+
end-of-life Python versions. Beyond that, the only dependency is the `pyparsing` library.
53+
54+
[pipx]: https://pypa.github.io/pipx/
55+
56+
### Notation
57+
58+
The expression works like a simple equation parser with some extra operators.
59+
60+
*The following operators are listed in order of precedence. Parentheses may
61+
be used to force an alternate order of evaluation.*
62+
63+
The dice (`[N]dS`) operator takes an amount (N) and a number of sides (S), and
64+
returns a list of N random numbers between 1 and S. For example: `4d6` may
65+
return `[6, 3, 2, 4]`. Using a `%` as the second operand is shorthand for
66+
rolling a d100, and a using `f` is shorthand for ±1 fudge dice.
67+
68+
The fudge dice (`[N]uS`) operator is interchangeable with the dice operator,
69+
but makes the dice range from -S to S instead of 1 to S. This includes 0.
70+
71+
A wild dice (`[N]wS`) roll is special. The last roll in this set is called the
72+
"wild die". If this die's roll is the maximum value, the second-highest roll
73+
in the set is set to the maximum value. If its roll is the minimum, then
74+
both it and the highest roll in the set aer set to zero. Then another die is
75+
rolled. If this roll is the minimum value again, then ALL die are set to zero.
76+
If a single-sided wild die is rolled, the roll behaves like a normal one.
77+
78+
If N is not specified, it is assumed you want to roll a single die.
79+
`d6` is equivalent to `1d6`.
80+
81+
Rolls can be exploded with the `x` operator, which adds additional dice
82+
to the set for each roll above a given threshold. If a threshold isn't given,
83+
it defaults to the maximum possible roll. If the extra dice exceed this
84+
threshold, they "explode" again! Safeguards are in place to prevent this from
85+
crashing the parser with infinite explosions.
86+
87+
You can make the parser re-roll dice below a certain threshold with the `r`
88+
and `rr` operators. The single `r` variety allows the new roll to be below
89+
the threshold, whereas the double variety's roll *changes* the roll range to
90+
have a minimum of the threshold. The threshold defaults to the minimum roll.
91+
92+
The highest, middle or lowest rolls or list entries can be selected with
93+
(`^` or `h`), (`m` or `o`), or (`v` or `l`) respectively.
94+
`6d6^3` will keep the highest 3 rolls, whereas `6d6v3` will select
95+
the lowest 3 rolls. If a number isn't specified, it defaults to keeping all
96+
but one for highest and lowest, and all but two for the middle. If a negative
97+
value is given as the operand for any of these operators, this operation will
98+
drop that many elements from the result. For example, `6d6^-2` will drop the
99+
two lowest values from the set, leaving the 4 highest. Zero has no effect.
100+
101+
A variant of the "explode" operator is the `a` ("again") operator. Instead of
102+
re-rolling values equal to or greater than the threshold (or max value), this
103+
operator doubles values *equal* to the provided threshold (or max value). When
104+
no right-side operand is specified, the left side must be a dice expression.
105+
106+
There are two operators for taking a set of rolls or numbers and counting the
107+
number of elements at or above a certain threshold, or "successes". Both
108+
require a right-hand operand for the threshold. The first, `e`, only counts
109+
successes. The second, `f`, counts successes minus failures, which are when
110+
a roll is the minimum possible value for the die element, or 1 for lists.
111+
112+
A list or set of rolls can be turned into an integer with the total (`t`)
113+
operator. `6d1t` will return `6` instead of `[1, 1, 1, 1, 1, 1]`.
114+
Applying integer operations to a list of rolls will total them automatically.
115+
116+
A set of dice rolls can be sorted with the sort (`s`) operator. `4d6s`
117+
will not change the return value, but the dice will be sorted from lowest to
118+
highest.
119+
120+
The `+-` operator is a special prefix for sets of rolls and lists. It
121+
negates odd roles within a list. Example: `[1, 2, 3]` -> `[-1, 2, -3]`.
122+
There is also a negate (`-`) operator, which works on either single
123+
elements, sets or rolls, or lists. There is also an identity `+` operator.
124+
125+
Values can be added or subtracted from each element of a list or set of rolls
126+
with the point-wise add (`.+`) and subtract (`.-`) operators. For example:
127+
`4d1 .+ 3` will return `[4, 4, 4, 4]`.
128+
129+
Basic integer operations are also available: `(16 / 8 * 4 - 2 + 1) % 4 -> 3`.
130+
131+
132+
Finally, there are two operators for building and extending lists. To build a
133+
list, use a comma to separate elements. If any comma-seperated item isn't a
134+
scalar (e.g. a roll), it is flattened into one by taking its total. The
135+
"extend" operator (`|`) is used to merge two lists into one, or append single
136+
elements to the beginning or end of a list.
137+
138+
### Python API
139+
140+
The calls to `dice.roll()` above may be replaced with `dice.roll_min()` or
141+
`dice.roll_max()` to force ALL rolls to their highest or lowest values
142+
respectively. This might be useful to see what the minimum and maximum
143+
possible values for a given expression are. Beware that this causes wild dice
144+
rolls to act like normal ones, and rolls performed as explosions are not
145+
forced high or low.
146+
147+
The `roll()` function and variants take a boolean `raw` parameter which
148+
makes the library return the element instead of the result. Note that the
149+
`evaluate_cached` method is called as part of `roll()`, which populates
150+
`element.result`. Calling `element.evaluate()` will not reset this value.
151+
152+
To display a verbose breakdown of the element tree, the
153+
`dice.utilities.verbose_print(element)` function is available.
154+
If `element.result` has not yet been populated, the function calls
155+
`evaluate_cached()` first. Keep this in mind if you want to print the result
156+
of an evaluation with custom arguments. `verbose_print()` returns a `str`.
157+
158+
Most evaluation errors will raise `DiceError` or `DiceFatalError`, both of
159+
which are subclasses of `DiceBaseError`. These exceptions have a method
160+
named `pretty_print`, which will output a string indicating where the error
161+
happened::
162+
163+
```python-repl
164+
>>> try:
165+
... dice.roll('1/0')
166+
... except dice.DiceBaseException as e:
167+
... print(e.pretty_print())
168+
...
169+
1/0
170+
^ Division by zero
171+
>>>
172+
```

0 commit comments

Comments
 (0)