Random table rolls
Our random table script is doing a lot for us now. We can roll any arbitrary number of times on any text file. But often, we aren’t rolling a known number of times: our number of rolls on the random table is itself random. So it would be nice to, in addition to ./random 3 gems we could also do ./random d4 gems.
Now that we have the dice library installed, we can do this. The main issue is that the script currently knows whether to roll more than once by looking to see if the first item on the command line is all digits:
[toggle code]
-
if firstArgument.isdigit():
- count = int(firstArgument)
If we are going to accept die rolls, then we need to accept another character as well as digits: the letter ‘d’. There does, however, have to be at least one number. Basically, we need our script to recognize a die roll.
When we need to recognize text patterns, the most common tool is a regular expression. In Python, we use regular expressions by importing the re library. Add this to the top of the script with the rest of the imports:
- import re
Replace the if/count lines above with:
[toggle code]
-
if re.match(r'[0-9]*d?[1-9][0-9]*$', firstArgument):
- count = firstArgument
That looks complicated—and regular expressions can certainly become complicated—but in this case it isn’t.
- re.match matches text patterns from the beginning of the text.
- The last character is a dollar sign, which requires that the pattern match the entire piece of text instead of just the beginning.
- The first set of characters are in square brackets: [0-9]. Items in square brackets mean, match any character in that range. For example, [a-m] would mean any character from lower-case ‘a’ through lower-case ‘m’. In this case, it’s any number.
- The next character immediately following the first set is an asterisk. The asterisk means any number of the preceding character. The preceding character is any digit. So, “[0-9]*” means any number of digits. Any number includes zero, so this means zero or more digits at the start of the text.
- The next portion is the letter ‘d’ followed by a question mark. The letter ‘d’ is needed to show that this is a die roll, and the question mark means that we need zero or one of the previous characters. If this is not a die roll, there will be no ‘d’. If this is a die roll, there will be only one ‘d’. The question mark handles this for us.
- The next portion is “[1-9]”. There must be at least one digit from 1 to 9 in either a die roll or an arbitrary number.
- And the final portion is “[0-9]*”. We have already seen this; it means from zero to any amount of digits.
You can construct most of your regular expression search patterns using those rules.
Now that the count is not an integer but can also be a die roll, we need to add some code to the Table.choose method to recognize die rolls. Add the highlighted code:
[toggle code]
- #print some random items from the table
-
def choose(self, count):
-
if type(count) is not int:
-
if count.isdigit():
- count = int(count)
-
else:
- count = dice.roll(count + 't')
-
if count == 1:
- time = 'time:'
-
else:
- time = 'times:'
- print 'Rolling', count, time
-
if count.isdigit():
- maximumLength = len(unicode(count))
- formatString = '%' + unicode(maximumLength) + 'i. %s'
-
for counter in range(count):
-
if count > 1:
- print formatString % (counter+1, self.choice())
-
else:
- print self.choice()
-
if count > 1:
-
if type(count) is not int:
The new code first checks to see if the count is not an integer; if it isn’t, it checks to see if the variable is all digits; if it is, this is just a number. It turns the text into an integer so that Python can use it for counting, and that’s that.
If the count is not all digits, it must be a die roll. It adds the letter ‘t’ at the end to tell the dice library to total the result, and then rolls that number. The roll result will be an integer. We also print out the result, pluralizing “time” appropriately.
./random d4 Deep\ Forest Rolling 2 times: 1. Pixies (17) 2. Apparitions (32) ./random d6 East/gems Rolling 3 times: 1. jasper 2. chalcedony 3. sapphire
In response to Programming for Gamers: Choosing a random item: If you can understand a roleplaying game’s rules, you can understand programming. Programming is a lot easier.
- Python regular expression operations
- “This module provides regular expression matching operations similar to those found in Perl. Both patterns and strings to be searched can be Unicode strings as well as 8-bit strings.”
More Programming for Gamers
- Are my dice random?
- My d20 appears to have been rolling a lot of ones, a disaster if I were playing D&D but a boon for Gods & Monsters. Is my die really random, or is it skewed towards a particular result? Use the ‘R’ open source statistics tool to find out.
- Programming for Gamers: Choosing a random item
- If you can understand a roleplaying game’s rules, you can understand programming. Programming is a lot easier.
- Easier random tables
- Rather than having to type --table and --count, why not just type the table name and an optional count number?
- Programming a Roman thumb
- Before we move on to more complex stuff with the “random” script, how about something even simpler? Choose or die, Bezonian!
- Multiple tables on the same command
- The way the “random” script currently stands, it does one table at a time. Often, however, you have more than one table you know you’re going to need. Why not use one command to rule them all?
- 12 more pages with the topic Programming for Gamers, and other related pages
More random tables
- Island Book 1 and old-school tables
- Judges Guild Island Book 1 is a fascinating playground on which to place a sea-going adventure or campaign. It’s also a great example of the usefulness and wildness of old-school encounter tables.
- Percentage-based random tables
- Our current random item generator assumes that each item shows up as often as any other item. That’s very OD&D-ish. But AD&D uses percentage dice to weight toward some monsters and items more than others.
- Wandering monster chart assistant
- Use the encounter chart assistant to create wandering monster charts using percentages rather than ranges. Copy your tables into this tool to make sure they add up, adjust them, then copy them back out to your word processor. Never worry about missing or overlapping ranges again!
- Multiple tables on the same command
- The way the “random” script currently stands, it does one table at a time. Often, however, you have more than one table you know you’re going to need. Why not use one command to rule them all?
- Easier random tables
- Rather than having to type --table and --count, why not just type the table name and an optional count number?
- Three more pages with the topic random tables, and other related pages
More regular expressions
- Simple .ics iCalendar file creator
- A simple Perl script to create an ics file from a human-readable text of events.
- Automatically link related URLs in Django
- One of the features of my old blog and my new Django CMS is autolinking the URLs that I mention in the text.