{"id":15494126,"url":"https://github.com/line-o/dicey","last_synced_at":"2026-01-07T12:10:23.314Z","repository":{"id":48507205,"uuid":"371703957","full_name":"line-o/dicey","owner":"line-o","description":"Just a bunch of random functions","archived":false,"fork":false,"pushed_at":"2023-01-24T21:00:11.000Z","size":4788,"stargazers_count":7,"open_issues_count":0,"forks_count":0,"subscribers_count":4,"default_branch":"main","last_synced_at":"2024-10-19T11:31:15.085Z","etag":null,"topics":["exist-db","library","random","xar"],"latest_commit_sha":null,"homepage":"","language":"XQuery","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/line-o.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-05-28T13:07:52.000Z","updated_at":"2023-01-13T18:59:47.000Z","dependencies_parsed_at":"2023-02-13T22:31:26.914Z","dependency_job_id":null,"html_url":"https://github.com/line-o/dicey","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/line-o%2Fdicey","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/line-o%2Fdicey/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/line-o%2Fdicey/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/line-o%2Fdicey/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/line-o","download_url":"https://codeload.github.com/line-o/dicey/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246068302,"owners_count":20718503,"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":["exist-db","library","random","xar"],"created_at":"2024-10-02T08:11:34.815Z","updated_at":"2026-01-07T12:10:23.255Z","avatar_url":"https://github.com/line-o.png","language":"XQuery","funding_links":[],"categories":[],"sub_categories":[],"readme":"# dicey\n\n\u003e Just a bunch of random functions \n\n\u003cimg title=\"dicey library logo\" alt=\"A blue icosahedron (twenty-sided dice) with one ancient letter on each side\" src=\"src/icon.svg\" width=\"30%\"\u003e\n\n## Introduction\n\nImport the module with\n\n```xquery\nimport module namespace dicey=\"http://line-o.de/xq/dicey\";\n```\n\nNow you can throw a (six-sided) dice.\n\n```xquery\ndicey:d6()?_item\n```\n\nThe library augments the default `fn:random-number-generator` in several ways.\nSo, you can use dicey random number generators as if they were the XQuery built-ins.\n\nThe added functionality lies in additional keys in the returned map\n\n- `_dicey`: if this is true() you have an augmented random at your hands\n- `_item`: a _thing_ derived from the current random number \n- `_next`: a wrapped call to `next` that will produce the next augmented generator of the __current__ type\n\nFor `dicey:d6`, for example, `_item` will always be a xs:integer between 1 and 6.\n\n```xquery\ndicey:d6()?_next()?_next()?_item\n```\n\nThe underscores might be an acquired taste, but the decision was made after reading the [specification of fn:random-number-generator](https://www.w3.org/TR/xpath-functions-31/#func-random-number-generator). Specifically this sentence struck a chord:\n\n\u003e The map returned by the fn:random-number-generator function may contain additional entries beyond those specified here, but it must match the type map(xs:string, item()). The meaning of any additional entries is ·implementation-defined·. To avoid conflict with any future version of this specification, the keys of any such entries should start with an underscore character.\n\n## Alea iacta est\n\nIs latin for \"the dice have fallen\". There are two functions that are\nuseful whenever you need more than one random value.\n\n`dicey:sequence` and `dicey:array`. The main difference between the two\nis that one returns a `sequence` and the other an `array` (the name gives it away).\n\n### dicey:sequence\n\nThrow one dice three times in a row:\n\n```xquery\ndicey:sequence(3, dicey:d6())?sequence\n```\nIt also works with the built-in random number generator.\n\n```xquery\ndicey:sequence(9, random-number-generator())?sequence\n```\n\n`dicey:sequence` returns a map with:\n\n- _sequence:_ the sequence of n random items\n- _generator:_ the random number generator in use\n\nThe `sequence` key value is what you are usually after.\n\n### dicey:array\n\n`dicey:array` is almost the same, but returns a map with:\n\n- _array:_ the array of n random items\n- _generator:_ the random number generator in use\n\n```xquery\ndicey:array(3, dicey:d6())?array\n```\nIt also works with the built-in random number generator.\n\n```xquery\ndicey:array(9, random-number-generator())?array\n```\n\nRead on to learn what the `generator` key is about.\n\n## Seeded random\n\nWhen you provide your seeded random, throwing a dice \nwill have a reproducible outcome.\n\n```xquery\nlet $piked-dice := dicey:d6(random-number-generator(103))\nreturn dicey:sequence(6, $piked-dice)?sequence\n```\n\n## Continuation\n\nIt is also interesting to continue using the same dice across different uses.\n\n```xquery\nlet $piked-dice := dicey:d6(random-number-generator(103))\nlet $first-batch := dicey:sequence(6, $piked-dice)\nreturn (\n    $first-batch?sequence,\n    dicey:sequence(6, $first-batch?_next())\n)\n```\n\nOr get a hold of the plain `random-number-generator` again. That way you can set up a different dice and throw that, for example.\n\n```xquery\nlet $piked-dice := dicey:d6(random-number-generator(103))\nlet $d20 := dicey:d20($piked-dice?next())\nreturn (\n    $piked-dice?_item,\n    $d20?_item\n)\n```\n\n## One in a million\n\nWhat if you need a random number in an arbitrary range?\n\nFor integers:\n\n```xquery\ndicey:ranged-random-integer(1, 1000000)?_item\n```\n\nFor decimals:\n\n```xquery\ndicey:ranged-random(-1.71, 2.46)?_item\n```\n\nThose two can of course be used with `dicey:sequence`.\nThey also both have a signature that accepts a random number generator as the third parameter.\n\n## Drawing Items from a Stash\n\nIf you want to draw __n__ items from a sequence, so that each item will only\nbe returned once, you can use the `permute` function returned by `random-number-generator`.\n\n```xquery\nrandom-number-generator()?permute($sequence)\n=\u003e subsequence(1, $n)\n```\n\nOr, you can use `dicey:draw` to achieve the same result, but lazily by (re)moving items\nat random indeces. The function can _draw from both, arrays and sequences_. The result is \nreturned in the corresponding key.\n\n```xquery\ndicey:draw($n, $from, random-number-generator())?sequence\n```\n\n`dicey:draw` returns a map with following properties:\n\n- _sequence:_ the sequence of n items that were drawn, if a sequence was provided as $from\n- _array:_ the array of n items that were drawn, if an array was provided as $from\n- _from:_ the remainder of items from the original sequence\n- _generator:_ the random number generator in use\n\nYou can access the two implementations `dicey:draw-from-sequence` and `dicey:draw-from-array` \ndirectly. That way you can be certain which key the result is in.\n\nDrawing a few items from a large stash (\u003e 10K items) is much faster than permuting it.  \n\n## Beyond Numbers\n\nThe library can help you pick all kinds of data at random. \nThat is particularly useful for assembling test-data.\n\n### Pulling Strings\n\nTo construct a random string from a set of characters there is a special function\n`dicey:random-from-characers`.\n\nA \"word\" with ten random small latin characters can be generated with:\n\n```xquery\ndicey:random-from-characters(10, \"abcdefghijklmnopqrstuvwxyz\")?_item\n```\n\nThere is also a signature to provide your generator\n\n```xquery\ndicey:random-from-characters(10, \"abcdefghijklmnopqrstuvwxyz\", random-number-generator(103))\n```\n\n### Picking _Something_\n\nPass a list of items to `dicey:random-from` and it will pick one of them at random.\n\n`dicey:random-from` returns a map with following properties:\n\n- _sequence:_ the sequence of n items that were picked, if a sequence was provided as $from\n- _array:_ the array of n items that were picked, if an array was provided as $from\n- _from:_ the remainder of items from the original sequence\n- _generator:_ the random number generator in use\n\n\nAs with `dicey:draw` earlier `dicey:pick` can also handle arrays and sequences.\n\n```xquery\nlet $stuff-to-pick-from :=\n(\n    map { \n        \"name\": \"alice\", \n        \"id\": 1\n    }, \n    map { \n        \"name\": \"bob\",\n        \"id\": 2\n    }\n)\n\ndicey:sequence(1,\n    dicey:pick(\n        $stuff-to-pick-from, random-number-generator())\n    )?sequence\n```\n\nWith arrays you can also have empty sequences in your options, which can be very handy.\n\n```xquery\nlet $might-be-empty :=\n[\n    map { \n        \"name\": \"alice\", \n        \"id\": 1\n    },\n    ()\n]\n\ndicey:array(1,\n    dicey:picks(\n        $might-be-empty, random-number-generator())\n    )?array\n```\n\nOf course you can deliberately use `dicey:pick-from-array` and `dicey:pick-from-sequence`.\n\n## Roll your own random\n\nYou can use the functions `dicey` provides to build functions that generate random values in other\ndomains.\n\nThe example from the previous section can be generalized into a function creating fake users.\n\n```xquery\nxquery version \"3.1\";\nimport module namespace dicey=\"http://line-o.de/xq/dicey\";\n\ndeclare variable $local:names := (\"alice\", \"bob\");\ndeclare function local:random-user ($generator as map(xs:string, item())) as map(xs:string, item()) {\n    let $fake-user := map {\n        \"id\": dicey:ranged-random-integer(1, 10000, $generator)?_item,\n        \"name\": dicey:random-from($local:names, $generator)?_item\n    }\n\n    return\n        map:merge((\n            map {\n                \"_dicey\": true(),\n                \"_item\":  $fake-user,\n                \"_next\": function() {\n                    local:random-user($generator?next())\n                }\n            },\n            $generator\n        )) \n};\n\ndicey:sequence(2, \n    local:random-user(\n        random-number-generator()))?sequence\n```\n\nA generator creating random colors in CSS' functional rgb notation:\n\n```xquery\nxquery version \"3.1\";\nimport module namespace dicey=\"http://line-o.de/xq/dicey\";\n\ndeclare function local:rgb ($generator as map(xs:string, item())) as map(xs:string, item())s {\n    let $result := dicey:sequence(3, dicey:ranged-random-integer(0, 255, $generator))\n    let $color := ``[rgb(`{string-join($result?sequence, \",\")}`)]``\n    return map:merge((\n        $result?generator,\n        map {\n            \"_dicey\": true(),\n            \"_item\": $color,\n            \"_next\": function () { local:rgb($result?generator?next()) }\n        }\n    ))\n};\n\n(: example output: \n  [\n    \"rgb(183,185,220)\",\n    \"rgb(200,187,39)\",\n    \"rgb(14,43,23)\"\n  ]\n:)\ndicey:array(3, \n    local:rgb(random-number-generator(103)))?array\n```\n\n## Compatibility\n\nWhile the primary target is eXistdb (**starting from version 5.3.0**) the [library module](src/content/dicey.xqm) itself should be compatible with any XQuery 3.1 runtime (e.g. saxon 10, baseX 9.5.x).\n\n## Contributing\n\nI am keen to hear your feedback and welcome additional tests, examples and documentation.\nIf you find a bug or want to propose a new feature please open an issue or pull request.\n\n## Development\n\nTo make developing as seamless as possible some `npm` and `gulp` scripts are included in the\nproject. \n\n### Prerequisites\n\n- node 12+\n\nInstall dependencies with\n\n```bash\nnpm i\n```\n\n### Installation (existdb)\n\n```bash\ngulp install\n```\n\nbuilds the XAR-package and uploads it to the server defined in [.existdb.json](.existdb.json).\n\n\n### File Watcher\n\n```bash\ngulp watch\n```\n\nwatches for changes in either the library module, the specs or the testrunner and \nwill package the XAR and upload it to the database instance when changes are saved to disk.\n\n### Tests\n\nThe [XQSuite with tests](src/test/dicey-spec.xqm) can be run from\nwithin existdb using the [testrunner](src/test/run-tests.xq) or\nfrom the commandline using `npm`.\n\n```bash\nnpm test\n```\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fline-o%2Fdicey","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fline-o%2Fdicey","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fline-o%2Fdicey/lists"}