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