473,386 Members | 1,830 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,386 software developers and data experts.

Dice gen and analyser script for RPGs: comments sought

Hi fellow Pythonistas,

I've been using Python in anger for some time, and I must say, as I
wrote in <http://macprang.sourceforge.net/>:

"It's refreshing beyond words to use a language that so freely combines
such a small, clean syntax with such a powerful synthesis of
procedural, object-oriented and functional techniques."

My (hardcore C++) workplace is now very much converted to Python for
scripting tasks! We have completely abandoned Unix and DOS
shell-script, and Perl. We drive our entire "build-for-QA" process,
including code-signing, with Python and also use it for all our
automated nightly builds and unit tests.

So, inspired by the Python cookbook article 17.13, and because the
subject interests me, I've bashed out a module in my own time that can
do brute force and monte carlo analysis of dice under various RPG
rulesets:

* vanilla rolls of n x-sided dice, the result being multiplied by y
(usual d20 system ndx*y)
* as above, but the lowest m rolls are discarded
(optional d20 char gen rules)
* dice beating a threshold (Storyteller-style system),
with optional roll again
* opposed sorted rolls (Risk-style system).

The 1.0 version is at http://www.sailmaker.co.uk/newfiles/dice.py and
is public domain.

Before you ask, yes I'm fully aware of Newton's binomial theorem and
its generaliziations. The point of this code is to however to
generalise, exercise and accumulate the brute force and Monte Carlo
methods across various evaluatuon rules.

All comments welcomed, cc to email preferred merely because it shows up
sooner for me and is less likely to be missed.

Comments, insights and overall evaluations are especially welcomed re:
* Cleanliness of design
* Pythonicity of design
* Pythonicity of code
* Efficiency of code
* Quality of docstrings
* Conformance with modern docstring standards
* Conformance with coding standards e.g. PEP 8

I look forward to receiving your comments and criticisms.

Regards,
Richard.
Sep 5 '06 #1
4 1744
Richard Buckle <ri******@sailmaker.co.nospam.ukwrites:
Comments, insights and overall evaluations are especially welcomed re:
* Cleanliness of design
* Pythonicity of design
* Pythonicity of code
* Efficiency of code
* Quality of docstrings
* Conformance with modern docstring standards
* Conformance with coding standards e.g. PEP 8

I look forward to receiving your comments and criticisms.
I looked at this for a minute and found it carefully written but
somewhat hard to understand. I think it's maybe more OOP-y than
Python programs usually are; perhaps it's Java-like. There are some
efficiency issues that would be serious if the code were being used on
large problems, but probably no big deal for "3D6" or the like. In
particular, you call histogram.numSamples() in a bunch of places and
each call results in scanning through the dict. You might want to
cache this value in the histogram instance. Making histogram a
subclass of dict also seems a little bit peculiar.

You might find it more in the functional programming spirit to use
gencomps rather than listcomps in a few places:

return sum([freq * val for val, freq in self.items()])
becomes
return sum((freq * val) for val, freq in self.iteritems())

etc.
Sep 6 '06 #2
Paul Rubin <http://ph****@NOSPAM.invalidwrote

(re <http://www.sailmaker.co.uk/newfiles/dice.py>)
I looked at this for a minute
Thanks for taking the time to look over it; I greatly appreciate it!
and found it carefully written but somewhat hard to understand.
Obviously, as the author, I have a blind spot about others
understanding it, but I always strive for my code to be self-commenting
and understandable at first sight, so I would genuinely welcome
feedback on which parts are difficult to understand and need more
commenting.

Perhaps it is insufficient commenting of the implementations of the
various subclasses of class Dice? I admit /they/ get a but funky in
places.
I think it's maybe more OOP-y than
Python programs usually are; perhaps it's Java-like.
That's interesting: while my background is certainly more OO than
functional, Java is the language I use least. Certainly I relish the
freedom to mix OO, functional and procedural paradigms that you get
with Python, so if there are ways in which that mixture can improve
dice.py, please enlighten me!

On the other hand, is "being more OOP-y than Python programs usually
are" a bad thing in itself, if the object analysis is cleanly designed?
There are some
efficiency issues that would be serious if the code were being used on
large problems, but probably no big deal for "3D6" or the like. In
particular, you call histogram.numSamples() in a bunch of places and
each call results in scanning through the dict.
A good point which I did consider, however after practical tests I
ruled in favour of code simplicity for the case in hand, while being
careful to leave the Histogram class open to optimisations such as you
describe via subclassing.

An earlier draft of the Histogram class did indeed have each method do
a single pass through the dict, accumulating what is now numSamples(),
sigma() and sigmaSquared() in local variables. But in practice I found
that for my problem domain, even a 'large' problem would have
relatively few histogram buckets, and computing the summary statistics
for the histogram took a /miniscule/ amount of time compared to the
time taken by generating the data.

On that basis I refactored the Histogram class to follow the "once and
only once" coding principle, resulting in a much clearer and more
concise Histogram class, with very simple and natural code that any
high-school statisician can immediately see is correct. I found no
measurable perfomance hit.
You might want to cache this value in the histogram instance.
On the same basis as above, I decided against caching any results in
the Histogram class, preferring simplicity of code to the additional
logic that would be required to manage cache invalidation upon arrival
of new samples.

I've learned the hard way that caching, while a dramatic optimisation
in the right place, introduces a lot of complexity and pitfalls (even
more so in multi-threaded scenarios), so these days I only do it when
performance analysis reveals the need.

Of course, for histograms with huge numbers of buckets, there may well
be mileage in subclassing the Histogram class to implement the above
optimisations, and I think the class is sufficiently cleanly designed
to facilitate that.
Making histogram a subclass of dict also seems a little bit peculiar.
Why? Genuine question. Keep in mind that I might want to re-use the
Histogram class for cases where the buckets may be floating point, so I
can't just use a vector.

I wanted a mapping of bucket->frequency with an easy way to add a new
sample by incrementing the frequency, so dict seemed a natural choice.
I am of course open to better ideas!
You might find it more in the functional programming spirit to use
gencomps rather than listcomps in a few places:

return sum([freq * val for val, freq in self.items()])
becomes
return sum((freq * val) for val, freq in self.iteritems())
Nice: thanks for making me aware of gencomps!

I agree that they're better, but when at home I'm on Mac OS X and so
stuck with Python 2.3 unless I engage in the necessary shenanigans to
slap Python 2.4 onto Mac OS X 10.4.7. Yes, I know how to do it, I've
done it before, but it's a PITA and I don't want to deal with it any
more.

Moreover I want my code to run on vanilla installations of Mac OS X
10.4.x, so I just put up with it and code to Python 2.3.

I'm on Apple's developer program, so if anyone has a Radar bug number I
can cite while requesting they pull their socks up and ship Python 2.4
with the OS, just let me know and I'll cite it to Apple.

Richard.
Sep 13 '06 #3
Richard Buckle wrote:
Comments, insights and overall evaluations are especially welcomed re:
* Cleanliness of design
* Pythonicity of design
* Pythonicity of code
* Efficiency of code
* Quality of docstrings
* Conformance with modern docstring standards
* Conformance with coding standards e.g. PEP 8

I look forward to receiving your comments and criticisms.
Here are some random (and less random) comments in no particular order,
with minimal or no justification; if you're not sure why some point is
good advice, simply ask :) I did just a "shallow parsing", meaning I
didn't attempt to understand what it's actually doing, check for
correctness, algorithm optimizations or major refactorings.

* Instead of importing sets, have the following snippet to be able to
use the builtin set (available since 2.4):
try: set
except NameError: from sets import Set as set

* Prefer new-style classes unless you have a good reason not to. The
change is minimal; just replace "class Dice" with "class Dice(object)".

* Replace most occurences of dict.keys, dict.values, dict.items with
dict.iterkeys, dict.itervalues, dict.iteritems respectively (unless you
write code with Py3K in mind ;-)).

* Avoid mutable default function arguments unless necessary. Instead of
a default empty list, use either an empty tuple or None (in which case
you may assign an empty list in the function's body when the argument
is None).

* Raising LookupError when a sanity check of function arguments fails
looks strange. ValueError (or a a specialised subclass of it) would be
more appropriate. 'assert' statements should also not be used for
arguments checking because they may be turned off when running the
program with '-O'.

* reduce() is discouraged; it's almost always more readable to unroll
it in a for loop.

* Are all the methods public, i.e. useful to a client of the classes ?
If not, the convention is to start the non-public methods' name with a
single underscore (or double underscore sometimes, but name mangling
often causes more problems than it solves in my experience, especially
when inheritance is involved).

* Several snippets can be condensed with list comprehensions, though
one-liners are not to everyone's taste. E.g. I'd write
histograms = []
maxDice = 10
for i in xrange(maxDice):
dice = StoryTellerDice(i)
histogram = dice.bruteforce()
histograms.append(histogram)
as histograms = [StoryTellerDice(i).bruteforce() for i in xrange(10)]

* [personal preference]: Don't leave space between *every* operator in
expressions, group them based on precedence. E.g. instead of "(n *
sigmaSq - sigma * sigma) / (n * n)", I read it easier as "(n*sigmaSq -
sigma*sigma) / (n*n).
HTH,
George

Sep 13 '06 #4
George Sakkis wrote:
* [personal preference]: Don't leave space between *every* operator in
expressions, group them based on precedence. E.g. instead of "(n *
sigmaSq - sigma * sigma) / (n * n)", I read it easier as "(n*sigmaSq -
sigma*sigma) / (n*n).
The spaced-out version is more `PEP 8`_ compliant. Under "Whitespace in
Expressions and Statements -Other Recommendations" it says "Use spaces
around arithmetic operators" and gives a few examples of "Yes" usage
that look much like the OP's usage.

That said, I also tend to omit the spaces around multiplicative
operators (though I'm slowly training myself out of that). As you say,
in the end, this is really a matter of personal preference.

... _PEP 8: http://www.python.org/dev/peps/pep-0008/
STeVe
Sep 13 '06 #5

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

7
by: lawrence | last post by:
Suppose I create dynamic web pages with 3 functions (which call other functions to make everything happen, but these 3 you might think of as being the top layer): registerSessions();...
15
by: kpp9c | last post by:
I am kind of in a bit of a jam (okay a big jam) and i was hoping that someone here could give me a quick hand. I had a few pages of time calculations to do. So, i just started in on them typing...
4
by: Angelos Devletoglou | last post by:
Hello everybody, I am trying to find if there is any simple Documentation tool or PHP file analyser. I am going to confess that I started designing my project but at some point my timeframe did...
11
by: Tomi Lindberg | last post by:
Hi, I'm trying to find a way to calculate a distribution of outcomes with any combination of dice. I have the basics done, but I'm a bit unsure how to continue. My main concern is how to make...
1
by: db55 | last post by:
This script doesn't work. Why? UPDATE SET = LTRIM(SUBSTRING(, 1, convert(bigint, CHARINDEX(',', Comments)-1))) WHERE NOT( IS NULL) AND LEN() > 8 Basically, I'm trying to...
101
by: Elijah Cardon | last post by:
Let's say I have m dice having n sides, such that n^m is not going to bust int as a datatype. With m=4 and n=6, an outcome might be {2, 5, 1, 2}. What is a good way to represent this in c so that...
0
by: Bree | last post by:
The game requires it not to accept negative numbers. At the moment it isnt, and it is urgent I find the solution asap. So if anyone can help I would much appreciate it. Thanks Bree This is the...
4
by: vegtard | last post by:
simple question. is it possible to write a script that rolls a six sided dice? if this is possible, is it possible to tell it to roll the six sided dice 4 times and ignore the dice that rolled...
1
by: clairelee0322 | last post by:
I am a c++ beginner and i am working on a dice loop lab. This program should roll two dice (each dice is from 1 to 6) and then total them together. The user should be able to input how many times...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.