on writing a while loop for rolling two dice

Hope Rouselle hrouselle at jevedi.com
Thu Sep 2 10:28:21 EDT 2021


dn <PythonList at DancesWithMice.info> writes:

> On 29/08/2021 08.46, Hope Rouselle wrote:
>> Here's my solution:
>> 
>> --8<---------------cut here---------------start------------->8---
>> def how_many_times():
>>   x, y = 0, 1
>>   c = 0
>>   while x != y:
>>     c = c + 1
>>     x, y = roll()
>>   return c, (x, y)
>
>> 
>> Why am I unhappy?  I'm wish I could confine x, y to the while loop.  The
>> introduction of ``x, y = 0, 1'' must feel like a trick to a novice.  How
>> would you write this?
>
>> ram at zedat.fu-berlin.de (Stefan Ram) writes:
>>> """Rolls two dice until both yield the same value.
>>> Returns the number of times the two dice were rolled
>>> and the final value yielded."""
>>> roll_count = 0
>>> while True:
>>>     outcome = roll_two_dice()
>>>     roll_count += 1
>>>     if outcome[ 0 ]== outcome[ 1 ]: break
>>> return roll_count, outcome[ 0 ]
>> 
>> You totally convinced me.  Thanks.
>
> On the other hand...
> whilst you expressed concern about the apparently disconnected 'set up'
> necessary before the loop, this solution adds a "True/Forever" and a
> "Break" construct, which some may deem not that much better (if at all)
>
> The idea of abrogating the while-condition but then adding another
> (disconnected) condition to break, seems to hold equal potential for
> confusion. or the type of dissatisfaction which motivated the original
> question!

Pretty well observed!  Hats to you.

> Looking at that from the inside-out, the loop's contents perform two
> functions: the rolling and counting (per Statement of Requirements), but
> also a loop-controlling element. Thus the reader's question: "what does
> this loop do?" is conflated with "how many times does it do it?".

Well put.

> Let's go completely off-the-rails, why not use a never-ending range() to
> fuel a for-loop 'counter', and within that loop perform the dice-roll(s)
> and decide if it is time to 'break'. The range replaces the "True". The
> for-loops index or 'counter' will deliver the desired result.
>
> Neat? No!
> Readable? No!
> An improvement over the while-True? Definitely not!
> Yet, the mechanism is the same AND offers a built-in counter. Hmmm...

Yeah.  Here's a little context.  I came across this by processing a list
of exercises.  (I'm teaching a course --- you know that by now, I
guess.)  So the first thing I observed was the equal volume of work
dedicated to while loops and for loops --- so I decided to compared
which appeared more often in a certain sample of well-written Python
code.  It turns out the for loop was much more frequent.  Students have
been reporting too much work in too little time, so I decided to reduce
the number of exercises involving while loops.  When I began to look at
the exercises, to see which ones I'd exclude, I decided to exclude them
all --- lol! --- except for one.  The one that remained was this one
about rolling dice until a satisfying result would appear.  (All other
ones were totally more naturally written with a for loop.)

So if I were to also write this with a for-loop, it'd defeat the purpose
of the course's moment.  Besides, I don't think a for-loop would improve
the readability here.

But I thought your protest against the while-True was very well put:
while-True is not too readable for a novice.  Surely what's readable or
more-natural /to someone/ is, well, subjective (yes, by definition).
But perhaps we may agree that while rolling dice until a certain
success, we want to roll them while something happens or doesn't happen.
One of the two.  So while-True is a bit of a jump.  Therefore, in this
case, the easier and more natural option is to say while-x-not-equal-y.

But this approach seems to force me into initializing x, y with
different values.

> Returning to the concern:
>
> x, y = 0, 1
> c = 0
>
> The first line is purely to ensure that the loop executes at least once,
> ie the two assigned-values are not 'real'. Hence the disquiet!
>
> Initiating the counter is unavoidable (@Chris' suggestion notwithstanding).
>
> However, remember that Python (like decent DBs) has a concept (and an
> idiom) of a value to be used when we don't (yet) know what the value
> is/should be! Further that Python allows such a value to be used in
> comparisons:
>
>>>> None != None
> False
>>>> None == None
> True
>
> Leading to:
>
> c, x, y = 0, None, None
> while ...
>
>
> Which solution reverts to the original loop-contents. which seem more
> obvious and thus more readable. (YMMV!)
>
> Simplicity over 'being clever'...

I don't see it.  You seem to have found what we seem to agree that it
would be the more natural way to write the strategy.  But I can't see
it.  It certainly isn't

--8<---------------cut here---------------start------------->8---
def how_many_times_1():
  c, x, y = 0, None, None
  while x != y:
    c = c + 1
    x, y = roll()
  return c, x, y
--8<---------------cut here---------------end--------------->8---

nor 

--8<---------------cut here---------------start------------->8---
def how_many_times_2():
  c, x, y = 0, None, None
  while x == y:
    c = c + 1
    x, y = dados()
  return c, x, y
--8<---------------cut here---------------end--------------->8---

What do you have in mind?  I couldn't see it.


More information about the Python-list mailing list