[squeak-dev] Dice rolling improvement

Stéphane Rollandin lecteur at zogotounga.net
Wed Apr 15 16:44:25 UTC 2020


Hello,

I implemented an improved version of Random>>#roll: (attached)

It has two more operators, > and <, that can be used to discard 
respectively a number of lowest or highest throw results. This is used 
to skew the random distribution to the left or to the right.

The idea is illustrated here:
https://www.gmdice.com/blogs/dnd/dice-probability-explained


So for example,

	Random roll: '3d6>2'

will roll three d6 and discard two of them, keeping only the best result.

Similarly:

	Random roll: '3d6<1'

rolls three d6 and discards the lowest result.

For consistency, the algorithm takes offsets into account:

	Random roll: '3d6>2+10'

adds 10 to the two best throws, while

	Random roll: '3d6+10>2'

will keep 10 and the best throw among the three d6.


What do you think? Should I submit the code to the inbox?


Stef
-------------- next part --------------
'From Squeak5.3 of 3 March 2020 [latest update: #19431] on 15 April 2020 at 6:21:53 pm'!

!Random methodsFor: 'die rolling' stamp: 'spfa 4/15/2020 18:20'!
roll: diceString
	"Roll some dice, DnD-style, according to this mini-grammar:
		dice := epxr {pm dice}
		pm := '+' | '-' | '<' | '>'
		expr := num | num dD | dD numP | num dD numP
		dD := 'd' | 'D'
		num := digit+
		numP := num | '%'"

	| stream op results |
	stream := diceString readStream.
	results := Bag new.
	op := #+.
	[ 	| res range dice token s |

		token := self diceToken: stream.

		token isNumber
			ifTrue: [dice := token.
					res := token.
					token := self diceToken: stream]
			ifFalse: [token == $d
				ifTrue: [dice := 1]
				ifFalse: [self error: 'unknown token' , token]].

		token == $d
			ifTrue: [token := self diceToken: stream.
					token isNumber
						ifTrue: [range := token.
								token := self diceToken: stream]
						ifFalse: [token == $%
							ifTrue: [range := 100.
									token := self diceToken: stream]
							ifFalse: [range := 6]].
					res := nil.
					s := op == #- ifTrue: [-1] ifFalse: [1].
					dice timesRepeat: [
						results add: (self nextInt: range) * s]].
		res ifNotNil: [
			op caseOf: {
				[#+] -> [results add: res].
				[#-] -> [results add: res negated].
				[#>] -> [res timesRepeat: [results remove: results min]].
				[#<] -> [res timesRepeat: [results remove: results max]]}].
	
		token ifNil: [^ (results ifEmpty: [^0]) sum].
		('+-><' includes: token)
			ifFalse: [self error: 'unknown token ' , token].
		op := token asSymbol

	] repeat! !


More information about the Squeak-dev mailing list