Role-Playing Game Dice-Rolling

5

0

Background

When playing an RPG such as Dungeons & Dragons, Pathfinder, or Paranoia, players each need a set of dice. You are hosting one such game this weekend, and some of the friends you invited have never played an RPG before. They don't want to commit to buying their own set of dice until they know they'll use them (if they want to keep playing). This is fine and dandy with you, but you're not going to let them use your lucky set of dice that you pre-rolled the ones out of...

Goal

...so you are going to write a program or function that simulates the dice-rolling for them.

Dice are often described in the format: <How many dice>d<Number of sides> A common set of dice for RPG use includes: 1d4, 1d6, 1d8, 2d10 (also used as 1d% or 1d100), 1d12, and 1d20.

Your code must accept a string of any number of the above dice specifiers separated by spaces or commas as input. It must then output the result of each individual die-roll separated by spaces, with parentheses around groups; then the sum of each grouping on the next line, separated by spaces; and finally, the total sum on a third line. Single-die groups don't have parentheses. Dice must always be in the same order as provided in the input.

The percent die, whether written as 1d% or 1d100, should be calculated as the concatenation of 2d10 (just 2 rolls, each from 0-9, but a final result of zero is instead counted as 100), but each occurrence will be displayed as if a single roll. 2d10 in the input will still be treated and displayed as 2 individual rolls. It can be easy to get confused by percent dice, here's a good explanation.

Edit: To clarify, the number of rolls may exceed 9.

Examples

Input:

1d4 3d6 2d8

Possible Output:

3 (1 5 2) (8 4)
3 8 12
23

Input:

1d20 1d% 2d10 1d100 5d12

Possible Output:

16 100 (9 4) 42 (5 1 7 7 11)
16 100 13 42 31
204

Rules

  • Standard loopholes are disallowed.
  • Printable ASCII in code, only.
  • - shortest code wins.
  • -10 bytes if the rolls are actually random, rather than pseudo-random.

mbomb007

Posted 2015-09-03T21:40:57.310

Reputation: 21 944

2So, wait. Am I right that the d10s are 0-9 but the others are 1-n? Or do they also go 0 to (n-1)? Clearly the d100s are supposed to have values 1-100. – DLosc – 2015-09-03T22:04:15.267

1Very closely related. – Martin Ender – 2015-09-03T22:30:33.930

@DLosc I was only specifying how to calculate a d%. 1d10 is still in the range 1-10. – mbomb007 – 2015-09-03T22:59:31.910

@mbomb007 I didn't say duplicate. ;) – Martin Ender – 2015-09-03T23:01:05.527

For the percentage die, couldn't a program just generate a single (pseudo-)random number between 1 and 100? If so, what's the reason for calculating it as the concatenation of 2d10 and special-casing 00? – DLosc – 2015-09-03T23:05:50.603

1I imagine because that's how it's handed in DnD. – Celeo – 2015-09-03T23:11:46.013

Yes, but this is code golf. If generating a number in the right range is equivalent and takes fewer bytes, can my program just do that? – DLosc – 2015-09-03T23:44:04.130

@DLosc I guess so. Makes the most sense. – mbomb007 – 2015-09-04T01:13:16.810

Will the number of rolls always be single-digit? – Trebuchette – 2015-09-04T03:41:28.557

@Trebuchette No. I didn't show it in my examples, but the number of rolls can be more than a single digit. – mbomb007 – 2015-09-04T13:35:43.777

Answers

3

Pyth, 48 bytes

-jdm?td(.*dhdJ.bmOSYNmm.xsk100cd\dcz))\,jdsMJssJ

Test Suite

Tricks / golfs in this code:

  • Everything that's not a number will be treated as 100, not just %.

  • To get the parentheses, I make the list into a tuple, then subtract out the commas.

  • This is the first time I've used .b, the binary map, which was added 3 days ago.

  • The code contains 6 different map functions.

isaacg

Posted 2015-09-03T21:40:57.310

Reputation: 39 268

This shows one use for not exorcising tuples, or at least making it .( – Maltysen – 2015-09-06T04:28:30.190

1

R, 200 bytes

for(d in strsplit(scan(,""),"d")){d=gsub("%","100",d);u=d[1]>1;cat(if(u)"(",paste(i<-sample.int(d[2],d[1],T),collapse=" "),if(u)")"," ",sep="");F=c(F,sum(i))};cat("\n");cat(F[-1],"\n");cat(sum(F[-1]))

Try it online!

for(d in strsplit(scan(,""),"d")){
    d=gsub("%","100",d)                                # replace "%"
    u=d[1]>1                                           # whether to print parenthesis
    cat(if(u)"(",
        paste(i<-sample.int(d[2],d[1],T),collapse=" "),# dice rolls
            if(u)")",
            " ",
            sep="")
        F=c(F,sum(i))}
cat("\n")
cat(F[-1],"\n")                                        # sum of rolls of a certain type
cat(sum(F[-1]))                                        # sum of all dice rolls.

This can be shortened for sure... this is a naïve implementation with a for loop.

JayCe

Posted 2015-09-03T21:40:57.310

Reputation: 2 655

1

Pyth - 56 bytes

Nothing fancy, many nested maps. As OP said above in comments, we don't need to do the concatenating thing, just recognizing % is enough.

jdm?tld++\(j\ d\)j\ dKmmhOeGh=GsMcsXd\%]100\dczdjdJsMKsJ

Test Suite.

Maltysen

Posted 2015-09-03T21:40:57.310

Reputation: 25 023

1

Lua, 183 bytes

a=arg[1]:gsub("(%g+)d(%g+)",function(r,d)d=d=="%"and 100 or d n=tonumber(r)s=n>1 and"("or""for i=1,r do s=s..math.random(d)..(i<n and" "or"")end return s..(n>1 and")"or"")end)print(a)

Trebuchette

Posted 2015-09-03T21:40:57.310

Reputation: 1 692

1

Pyth, 59 bytes

JmhMOMd.b*N]?YY100mvdcXz",d%"" ,0";-jdm?td(.*dhdJ\,jdsMJssJ

Test Suite

Unfortunately, neither isaacg's nor Maltysen's answer handles commas properly. When/if isaacg fixes it, I'm sure his will remain smaller.

Brian Tuck

Posted 2015-09-03T21:40:57.310

Reputation: 296