{"id":15066432,"url":"https://github.com/adventuresmith/dart-dice-parser","last_synced_at":"2025-06-20T13:33:38.191Z","repository":{"id":56827686,"uuid":"112283513","full_name":"Adventuresmith/dart-dice-parser","owner":"Adventuresmith","description":"A dart library for parsing dice notation (`2d6+4`). Supports advantage, disadvantage, exploding, compounding, and other variations.","archived":false,"fork":false,"pushed_at":"2024-11-13T08:01:37.000Z","size":503,"stargazers_count":3,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-11-21T23:59:17.887Z","etag":null,"topics":["dart","dartlang","dice","dice-notation","rpg-tool"],"latest_commit_sha":null,"homepage":"","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Adventuresmith.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-11-28T03:58:23.000Z","updated_at":"2024-11-13T08:01:28.000Z","dependencies_parsed_at":"2024-11-12T05:34:17.204Z","dependency_job_id":null,"html_url":"https://github.com/Adventuresmith/dart-dice-parser","commit_stats":{"total_commits":185,"total_committers":3,"mean_commits":"61.666666666666664","dds":0.2702702702702703,"last_synced_commit":"604b5a68dff40b3e89e63d33f59a37203ca68098"},"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Adventuresmith%2Fdart-dice-parser","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Adventuresmith%2Fdart-dice-parser/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Adventuresmith%2Fdart-dice-parser/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Adventuresmith%2Fdart-dice-parser/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Adventuresmith","download_url":"https://codeload.github.com/Adventuresmith/dart-dice-parser/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225820210,"owners_count":17529139,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dart","dartlang","dice","dice-notation","rpg-tool"],"created_at":"2024-09-25T01:08:02.019Z","updated_at":"2024-11-21T23:59:24.036Z","avatar_url":"https://github.com/Adventuresmith.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"# dart_dice_parser\n[![Pub Package](https://img.shields.io/pub/v/dart_dice_parser.svg)](https://pub.dartlang.org/packages/dart_dice_parser)\n[![Dart](https://github.com/Adventuresmith/dart-dice-parser/actions/workflows/dart.yml/badge.svg)](https://github.com/Adventuresmith/dart-dice-parser/actions/workflows/dart.yml)\n[![codecov](https://codecov.io/gh/Adventuresmith/dart-dice-parser/branch/main/graph/badge.svg?token=YG5OYN9VY1)](https://codecov.io/gh/Adventuresmith/dart-dice-parser)\n[![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](CODE_OF_CONDUCT.md)\n[![style: lint](https://img.shields.io/badge/style-lint-4BC0F5.svg)](https://pub.dev/packages/lint)\n\n\n\nA dart library for parsing dice notation (`2d6+4`). Supports advantage/disadvantage, counting success/failures, \nexploding, compounding, and other variations.\n\n# Example\n\n```dart\n\nimport 'package:dart_dice_parser/dart_dice_parser.dart';\n\nvoid main() {\n  // Create a roller for D20 advantage (roll 2d20, keep highest).\n  final d20adv = DiceExpression.create('2d20 kh');\n\n  stdout.writeln(d20adv.roll());\n  // outputs:\n  //  ((2d20) kh ) ===\u003e RollSummary(total: 16, results: [16], metadata: {rolled: [4, 16], discarded: [4]})\n\n  stdout.writeln(d20adv.roll());\n  // outputs:\n  //  ((2d20) kh ) ===\u003e RollSummary(total: 19, results: [19], metadata: {rolled: [13, 19], discarded: [13]})\n}\n```\n\n# Dice Notation\n\n## Examples:\n\n* `2d20 #cf #cs`\n  * roll 2d20, result will include counts of critical successes (20) and failures (1)\n\n* advantage\n    * `2d20-L` -- drop lowest \n    * `2d20k`, `2d20kh` -- keep highest\n* disadvantage\n    * `2d20-H` -- drop highest\n    * `2d20-kl` -- keep lowest\n* `(2d10+3d20)-L3` -- roll 2d10 and 3d20, combine the two results lists, and drop lowest 3 results\n* `20d10-\u003c3-\u003e8#` -- roll 20 d10, drop any less than 3 or greater than 8 and count the number of remaining dice\n\n\n## Supported notation\n\n* `2d6` -- roll `2` dice of `6` sides\n* special dice variations:\n  * `4dF` -- roll `4` fudge dice (sides: `[-1, -1, 0, 0, 1, 1]`)\n  * `1d%` -- roll `1` percentile dice (equivalent to `1d100`)\n  * `1D66` -- roll `1` D66, aka `1d6*10 + 1d6` \n    * **_NOTE_**: you _must_ use uppercase `D66`, lowercase `d66` will be interpreted as a 66-sided die\n  \n* exploding dice\n  * `4d6!` -- roll `4` `6`-sided dice, explode if max (`6`) is rolled (re-roll and include in results)\n    * `4d6 !=5` or `4d6!5` -- explode a roll if equal to 5 \n    * `4d6 !\u003e=4` - explode if \u003e= 4\n    * `4d6 !\u003c=2` - explode if \u003c=2\n    * `4d6 !\u003e5` - explode if \u003e 5\n    * `4d6 !\u003c2` - explode if \u003c2\n    * To explode only once, use syntax `!o` \n      * `4d6 !o\u003c5`\n* compounding dice (Shadowrun, L5R, etc). Similar to exploding, but the additional rolls for each\n  dice are added together as a single \"roll\". The original roll is replaced by the sum of it and any additional rolls.\n  * `5d6 !!` -- roll `5` `6`-sided dice, compound\n    * `5d6 !!=5` or `5d6!5` -- compound a roll if equal to 5 \n    * `5d6 !!\u003e=4` - compound if \u003e= 4\n    * `5d6 !!\u003c=4` - compound if \u003c= 4\n    * `5d6 !!\u003e5` - compound if \u003e 5\n    * `5d6 !!\u003c3` - compound if \u003c 3\n    * To compound only once, use syntax `!!o` \n      * `5d6 !!o\u003c2`\n* re-rolling dice:\n  * `4d4 r2` -- roll 4d4, re-roll any result = 2\n  * `4d4 r=2` -- roll 4d4, re-roll any result = 2\n  * `4d4 r\u003c=2` -- roll 4d4, re-roll any \u003c= 2\n  * `4d4 r\u003e=3` -- roll 4d4, re-roll any \u003e= 3\n  * `4d4 r\u003c2` -- roll 4d4, re-roll any \u003c 2\n  * `4d4 r\u003e3` -- roll 4d4, re-roll any \u003e 3\n  * To reroll only once, use syntax `ro` \n    * `4d4 ro\u003c2`\n* keeping dice:\n  * `3d20 k 2` -- roll 3d20, keep 2 highest\n  * `3d20 kh 2` -- roll 3d20, keep 2 highest\n  * `3d20 kl 2` -- roll 3d20, keep 2 lowest\n* dropping dice:\n  * `4d6 -H` -- roll 4d6, drop 1 highest\n  * `4d6 -L` -- roll 4d6, drop 1 lowest\n  * `4d6 -H2` -- roll 4d6, drop 2 highest\n  * `4d6 -L2` -- roll 4d6, drop 2 lowest\n  * `4d6 -\u003e5` -- roll 4d6, drop any results \u003e 5\n  * `4d6 -\u003c2` -- roll 4d6, drop any results \u003c 2\n  * `4d6 -\u003e=5` -- roll 4d6, drop any results \u003e= 5\n  * `4d6 -\u003c=2` -- roll 4d6, drop any results \u003c= 2\n  * `4d6 -=1` -- roll 4d6, drop any results equal to 1\n  * NOTE: the drop operators have higher precedence than\n    the arithmetic operators; `4d10-L2+2` is equivalent to `(4d10-L2)+2`\n  * NOTE: drop is not subtraction. \n    * `4d6 - 3` -- roll 4d6, subtract 3\n    * `4d6 - 2d6` -- roll 4d6, subtract the result of rolling 2d6\n* cap/clamp:\n  * `4d20 C\u003c5` -- roll 4d20, change any value \u003c 5 to 5\n  * `4d20 C\u003e15` -- roll 4d20, change any value \u003e 15 to 15\n\n* scoring dice rolls:\n  * counting:\n    * `4d6 #` -- how many results? \n      * For example, you might use this to count # of dice above a target. `(5d10 -\u003c6)#` -- roll 5 d10, drop any less than 6, count results\n    * `4d6 #\u003e3` -- roll 4d6, count any \u003e 3\n    * `4d6 #\u003c3` -- roll 4d6, count any \u003c 3\n    * `4d6 #\u003e=5` -- roll 4d6, count any \u003e= 5\n    * `4d6 #\u003c=2` -- roll 4d6, count any \u003c= 2\n    * `4d6 #=5` -- roll 4d6, count any equal to 5\n  * successes and failures \n    * A normal count operation `#` discards the rolled dice and changes the result to be the count \n      * For example, `2d6#\u003c=3` rolls `[3,4]` then counts which results are `\u003c=3` , returning `[1]`\n    * But, sometimes you want to be able to count successes/failures without discarding the dice rolls. \n      In this case, use modifiers `#s`, `#f`, `#cs`, `#cf` to add metadata to the results.\n      * `6d6 #f\u003c=2 #s\u003e=5 #cs6 #cf1` -- roll 6d6, count results \u003c= 2 as failures, \u003e= 5 as successes, =6 as critical successes, =1 as critical failures\n        * The above returns a result like: `RollSummary(total: 22, results: [6, 2, 1, 5, 3, 5], metadata: {rolled: [6, 2, 1, 5, 3, 5], score: {successes: [6, 5, 5], failures: [2, 1], critSuccesses: [6], critFailures: [1]}})`\n    * NOTE: order matters\n      * `2d20 kh #cf #cs` -- roll 2d20, keep the highest, count critical successes \u0026 failures. If this \n         rolled `[1,18]`, the `1` is dropped and the result metadata won't record a critical failure.\n         If that's not the behavior you want, move the counts prior to the drop (`2d20 #cf #cs kh`).\n      \n* arithmetic operations\n  * parenthesis to force a certain order of operations\n  * addition is a little special -- could be a sum of ints, or it can be used to aggregate results of multiple dice rolls\n    * Addition of integers is the usual sum\n      * `4+5` \n      * `2d6 + 1`\n    * Addition of roll results combines the results (use parens to ensure the order of operations is what you desire)\n      * `(5d6+5d10)-L2` -- roll 5d6 and 5d10, and from aggregate results drop the lowest 2.\n      * `5d6+5d10-L2` -- roll 5d6 and 5d10, and from only the 5d10 results drop the lowest 2. equivalent to `5d6+(5d10-L2)`\n  * `*` for multiplication\n  * `-` for subtraction\n  * numbers must be integers\n  * division is not supported.\n\n\n# Random Number Generator\n\nBy default, Random.secure() is used. You can select other RNGs when creating the\ndice expression. Random() will be faster than Random.secure(); if you're doing lots of rolls\nfor use cases where security doesn't matter, you will want to use Random().\n\nFor example, you might create a dice-rolling app that both provides rolls _and_ displays statistics\n(mean, stddev, etc) about the dice expression. To do that, you might create two separate\n`DiceExpression` objects for the same user-input -- one with the secure RNG (run whenever a user\nclicks a button), and the second to display min/max/mean/stddev/etc\n\n```dart \n  final diceExpr_SecureRNG = DiceExpression.create('2d6');\n  final diceExpr_FastRNG = DiceExpression.create('2d6', Random());\n  \n  //....\n  // on button-click, roll the dice\n  final roll = diceExpr_SecureRNG.roll();\n  \n  //....\n  // when dice expr changes, update the stats graph. \n  final stats = await diceExpr_FastRNG.stats();\n  // output of stats: {mean: 6.98, stddev: 2.41, min: 2, max: 12, count: 10000, histogram: {2: 310, 3: 557, 4: 787, 5: 1090, 6: 1450, 7: 1646, 8: 1395, 9: 1147, 10: 825, 11: 526, 12: 267}}\n\n```\n\n# CLI Usage\n\nThere's no executable in bin, but there's an example CLI at `example/main.dart`. \n\nUsage:\n```\n❯ dart run example/main.dart -h\nUsage:\n-n, --num                       Number of times to roll the expression\n                                (defaults to \"1\")\n-o, --output                    output type\n\n          [json]                output JSON\n          [plain] (default)     output using toString\n          [pretty]              output result summary and detailed results of evaluating the expression tree\n\n-r, --random                    Random number generator to use.\n\n          [\u003cinteger\u003e]           pseudorandom generator initialized with given seed\n          [pseudo] (default)    pseudorandom generator\n          [secure]              secure random\n\n-v, --[no-]verbose              Enable verbose logging\n-s, --[no-]stats                Output statistics for the given dice expression. Uses n=10000 unless overridden\n-h, --[no-]help                 \n\n```\n\nExamples:\n\n```console\n❯ dart example/main.dart '3d6'\n(3d6) ===\u003e RollSummary(total: 13, results: [3, 6, 4], metadata: {rolled: [3, 6, 4]})\n\n\n# run N number of rolls\n❯ dart run example/main.dart -n5 '3d6'\n(3d6) ===\u003e RollSummary(total: 10, results: [2, 2, 6], metadata: {rolled: [2, 2, 6]})\n(3d6) ===\u003e RollSummary(total: 12, results: [6, 4, 2], metadata: {rolled: [6, 4, 2]})\n(3d6) ===\u003e RollSummary(total: 5, results: [2, 1, 2], metadata: {rolled: [2, 1, 2]})\n(3d6) ===\u003e RollSummary(total: 10, results: [5, 3, 2], metadata: {rolled: [5, 3, 2]})\n(3d6) ===\u003e RollSummary(total: 13, results: [4, 5, 4], metadata: {rolled: [4, 5, 4]})\n\n\n\n# show statistics for a dice expression\n❯ dart example/main.dart  -s '3d6'\n{mean: 10.5, stddev: 2.97, min: 3, max: 18, count: 10000, histogram: {3: 49, 4: 121, 5: 273, 6: 461, 7: 727, 8: 961, 9: 1153, 10: 1182, 11: 1272, 12: 1151, 13: 952, 14: 733, 15: 486, 16: 289, 17: 154, 18: 36}}\n\n```\n\nSometimes it's nice to change the output type so you can see the graph of results:\n```console\n# show the result graph:\n❯ dart run example/main.dart -o pretty '3d6 #cs #cf'\n(((3d6) #cs ) #cf ) ===\u003e RollSummary(total: 13, results: [1, 6, 6], metadata: {rolled: [1, 6, 6], score: {critSuccesses: [6, 6], critFailures: [1]}})\n  (((3d6) #cs ) #cf ) =count=\u003e RollResult(total: 13, results: [1, 6, 6], metadata: {score: {critFailures: [1]}})\n      ((3d6) #cs ) =count=\u003e RollResult(total: 13, results: [1, 6, 6], metadata: {score: {critSuccesses: [6, 6]}})\n          (3d6) =rollDice=\u003e RollResult(total: 13, results: [1, 6, 6], metadata: {rolled: [1, 6, 6]})\n\n\n❯ dart run example/main.dart -o json '3d6 #cs #cf'\n{\"expression\":\"(((3d6) #cs ) #cf )\",\"total\":9,\"results\":[2,3,4],\"detailedResults\":{\"expression\":\"(((3d6) #cs ) #cf )\",\"opType\":\"count\",\"nsides\":6,\"ndice\":3,\"results\":[2,3,4],\"left\":{\"expression\":\"((3d6) #cs )\",\"opType\":\"count\",\"nsides\":6,\"ndice\":3,\"results\":[2,3,4],\"left\":{\"expression\":\"(3d6)\",\"opType\":\"rollDice\",\"nsides\":6,\"ndice\":3,\"results\":[2,3,4],\"metadata\":{\"rolled\":[2,3,4]}}}},\"metadata\":{\"rolled\":[2,3,4]}}\n\n\n```\n\n## Statistics output\n\n\nI often wonder, \"what range of values should I expect?\" or \"how likely will this roll explode or compound?\" \n\nTo explore that, you can use stats output: \n\n```console\n\n# roll 4d6\n❯ dart run example/main.dart -s '4d6'\n{mean: 14.0, stddev: 3.44, min: 4, max: 24, count: 10000, histogram: {4: 5, 5: 28, 6: 72, 7: 163, 8: 280, 9: 468, 10: 573, 11: 816, 12: 948, 13: 1069, 14: 1047, 15: 1118, 16: 1010, 17: 786, 18: 637, 19: 412, 20: 278, 21: 161, 22: 84, 23: 32, 24: 13}}\n\n\n# roll 4d6 explode \n❯ dart run example/main.dart -s '4d6!'\n{mean: 16.7, stddev: 6.46, min: 4, max: 54, count: 10000, histogram: {4: 6, 5: 32, 6: 87, 7: 166, 8: 264, 9: 403, 10: 558, 11: 655, 12: 690, 13: 734, 14: 695, 15: 651, 16: 621, 17: 607, 18: 498, 19: 507, 20: 425, 21: 350, 22: 353, 23: 260, 24: 229, 25: 194, 26: 167, 27: 150, 28: 143, 29: 118, 30: 99, 31: 69, 32: 53\n\n# roll 4d5 compounding \n❯ dart run example/main.dart -s '4d6!!'\n{mean: 16.8, stddev: 6.43, min: 4, max: 58, count: 10000, histogram: {4: 6, 5: 29, 6: 78, 7: 162, 8: 230, 9: 389, 10: 506, 11: 635, 12: 726, 13: 705, 14: 751, 15: 682, 16: 597, 17: 602, 18: 571, 19: 498, 20: 456, 21: 365, 22: 310, 23: 286, 24: 262, 25: 192, 26: 167, 27: 156, 28: 114, 29: 92, 30: 76, 31: 72, 32: 57, 33: 41, 34: 32, 35: 31, 36: 20, 37: 15, 38: 16, 39: 10, 40: 12, 41: 8, 42: 10, 43: 4, 44: 8, 45: 5, 46: 4, 47: 2, 48: 1, 49: 2, 50: 3, 51: 2, 53: 1, 58: 1}}\n\n```\n\nOr, if I wonder, \"in those rolls, how many times might I see a roll \u003e=6?\". For that case, I can include a count operation\n\n\n```console\n❯ dart run example/main.dart -s '4d6 #\u003e=6'\n{mean: 0.664, stddev: 0.75, min: 0, max: 4, count: 10000, histogram: {0: 4871, 1: 3781, 2: 1192, 3: 144, 4: 12}}\n\n❯ dart run example/main.dart -s '4d6! #\u003e=6'\n{mean: 0.793, stddev: 0.973, min: 0, max: 7, count: 10000, histogram: {0: 4846, 1: 3213, 2: 1328, 3: 449, 4: 116, 5: 40, 6: 4, 7: 4}}\n\n❯ dart run example/main.dart -s '4d6!! #\u003e=6'\n{mean: 0.665, stddev: 0.747, min: 0, max: 4, count: 10000, histogram: {0: 4840, 1: 3845, 2: 1144, 3: 164, 4: 7}}\n```\n\n\n# Reacting to dice rolls in your application\n\nIf you're using this package within an app, you probably want to display dice-rolling events to the user.\n\nThere's a couple ways for you to act on roll results. Depending on your use-case, one or more will hopefully fit your needs.\n\n## Traversing the result graph\nUse the 'left' and 'right' fields of each RollResult node to walk the graph. For an example, see [simple.dart](example/simple.dart)\n\nWhen a dice expression is parsed, it creates a binary tree to evaluate the roll. \n\nFor example, the expression `(3d6 + 3d6!) kh3` means \"roll 3d6 and 3d6!, combine results. Keep the 3 highest\"\nand it creates a graph like:\n\n```mermaid\nflowchart TD;\n    DROP --\u003e ADD;\n    ADD --\u003e ROLLB;\n    ADD --\u003e EXPLODE;\n    EXPLODE --\u003e ROLLA;\n    \n    DROP([\"(3d6 + 3d6!) kh 3\"]);\n    ADD([\"(3d6 + 3d6!)\"]);\n    ROLLB([\"3d6\"]);\n    EXPLODE([\"(3d6)!\"]);\n    ROLLA([\"3d6\"]);\n```\n\nWhen you roll the dice expression, it traverses the tree from the bottom up and rolls dice or performs the \nrequested operations.\n\n```mermaid\nflowchart TD\n    subgraph dice expr\n        DROP --\u003e ADD;\n        ADD --\u003e ROLLB;\n        ADD --\u003e EXPLODE;\n        EXPLODE --\u003e ROLLA;\n    end\n\n    subgraph results\n        SUMMARY ---|details| DROP_RESULT;\n        DROP_RESULT --\u003e|left| ADD_RESULT;\n        ADD_RESULT --\u003e|left| ROLLB_RESULT;\n        ADD_RESULT --\u003e|right| EXPLODE_RESULT;\n        EXPLODE_RESULT --\u003e|left| ROLLA_RESULT;\n    end \n    \n    ROLLA -.-\u003e|#1| ROLLA_RESULT@{ shape: doc, label: \"RollResult \u003cbr/\u003e\u003cbr/\u003eresults: 2,3,6\u003cbr/\u003erolled:2,3,6\" };\n    EXPLODE -.-\u003e|#2| EXPLODE_RESULT@{ shape: doc, label: \"RollResult \u003cbr/\u003e\u003cbr/\u003eresults: 2,3,6,4\u003cbr/\u003erolled:4\"};\n    ROLLB -.-\u003e|#3| ROLLB_RESULT@{ shape: doc, label: \"RollResult \u003cbr/\u003e\u003cbr/\u003eresults: 1,5,2\u003cbr/\u003erolled:1,5,2\"};\n    ADD -.-\u003e|#4| ADD_RESULT@{ shape: doc, label: \"RollResult \u003cbr/\u003e\u003cbr/\u003eresults: 2,3,6,4,1,5,2\"};\n    DROP -.-\u003e|#5| DROP_RESULT@{ shape: doc, label: \"RollResult\u003cbr/\u003e\u003cbr/\u003eresults: 6,5,4\u003cbr/\u003ediscarded: 2,3,1,2\"};\n    \n    DROP([\"(3d6 + 3d6!) kh 3\"]);\n    ADD([\"(3d6 + 3d6!)\"]);\n    ROLLB([\"3d6\"]);\n    EXPLODE([\"(3d6)!\"]);\n    ROLLA([\"3d6\"]);\n    SUMMARY@{ shape: doc, label: \"RollSummary\u003cbr/\u003e\u003cbr/\u003eTotal: 15 \u003cbr/\u003eresults:6,5,4\u003cbr/\u003e\u003cbr/\u003erolled: 2,3,6,4,1,5,2 \u003cbr/\u003ediscarded: 2,3,1,2\" };\n```\n\n## Convert RollResult to JSON \n\n```dart\n  Map\u003cString,dynamic\u003e rollResultAsJson = DiceExpression.create('2d20kh').roll().toJson();\n```\n\nThe returned objects will look roughly like: \n```json \n{\n  \"expression\": \"((2d20) kh )\",\n  \"total\": 16,\n  \"results\": [\n    16\n  ],\n  \"detailedResults\": {\n    \"expression\": \"((2d20) kh )\",\n    \"opType\": \"drop\",\n    \"nsides\": 20,\n    \"ndice\": 2,\n    \"results\": [\n      16\n    ],\n    \"metadata\": {\n      \"discarded\": [\n        4\n      ]\n    },\n    \"left\": {\n      \"expression\": \"(2d20)\",\n      \"opType\": \"rollDice\",\n      \"nsides\": 20,\n      \"ndice\": 2,\n      \"results\": [\n        4,\n        16\n      ],\n      \"metadata\": {\n        \"rolled\": [\n          4,\n          16\n        ]\n      }\n    }\n  },\n  \"metadata\": {\n    \"rolled\": [\n      4,\n      16\n    ],\n    \"discarded\": [\n      4\n    ]\n  }\n}\n\n\n```\n\n\n## Listen to RollResult events\n\nYou can register one or more listeners that will be informed of roll events.\nThere is a default logging listener that logs at FINE level.\n```dart \n\n    // if you want to listen to every individual operation within the expression\n    DiceExpression.registerListener((rollResult) {\n      stdout.writeln('${rollResult.opType.name} -\u003e $rollResult');\n    });\n\n    // if you want to listen for the RollSummary\n    DiceExpression.registerSummaryListener((rollSummary) {\n      stdout.writeln('$rollSummary');\n    });\n\n```\n\nAlternatively, you may not want to know _all_ roll events, and are only interested in\nthe events for your specific roll. In that case, pass an 'onRoll' method to the `roll()` method\n```dart \n  DiceExpression.create('2d20kh').roll(\n    onRoll: (rr) =\u003e stdout.writeln('roll - $rr'),\n    onSummary: (summary) =\u003e stdout.writeln('summary - $summary')\n  );\n```\n\n\n# Features and bugs\n\nPlease file feature requests and bugs at the [issue tracker][tracker].\n\n[tracker]: https://github.com/Adventuresmith/dart-dice-parser/issues\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadventuresmith%2Fdart-dice-parser","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fadventuresmith%2Fdart-dice-parser","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadventuresmith%2Fdart-dice-parser/lists"}