Mailing List Archive

on writing a while loop for rolling two dice
How should I write this? I'd like to roll two six-sided dice until I
get the same number on both. I'd like to get the number of times I
tried. Here's a primitive I'm using:

--8<---------------cut here---------------start------------->8---
>>> x, y = roll()
>>> x
6
>>> y
6 # lucky

>>> x, y = roll()
>>> x
4
>>> y
1 # unlucky
--8<---------------cut here---------------end--------------->8---

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)
--8<---------------cut here---------------end--------------->8---

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? Thank you!
--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
ram@zedat.fu-berlin.de (Stefan Ram) writes:

> Hope Rouselle <hrouselle@jevedi.com> writes:
>>How would you write this?
>
> """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.
--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
Hope Rouselle <hrouselle@jevedi.com> writes:

> ram@zedat.fu-berlin.de (Stefan Ram) writes:
>
>> Hope Rouselle <hrouselle@jevedi.com> writes:
>>>How would you write this?
>>
>> """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.

Wait, I'm surprised ``outcome'' is still a valid name at the
return-statement. Wasn't it defined inside the while? Shouldn't its
scope be restricted to the while block? I had no idea. I should learn
some Python.
--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
ram@zedat.fu-berlin.de (Stefan Ram) writes:

> Hope Rouselle <hrouselle@jevedi.com> writes:
>>Wait, I'm surprised ``outcome'' is still a valid name at the
>>return-statement. Wasn't it defined inside the while? Shouldn't its
>>scope be restricted to the while block? I had no idea. I should learn
>>some Python.
>
> In Python, local names can be introduced by an assignment
> and have function scope. There is no block scope in Python.
>
> Below, "name" /is/ a local name already, but is being
> used before being assigned to.
>
> def function():
> if False:
> name = 0
> return name
>
> function()
>
> # return name
> # UnboundLocalError: local variable 'name' referenced before assignment

I appreciated the example. I had no idea. (I had looked up the rules
and it was pretty simple to understand, but an example is always nice.)
Thank you so much.
--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On Sun, Aug 29, 2021 at 7:37 AM Hope Rouselle <hrouselle@jevedi.com> wrote:
>
> How should I write this? I'd like to roll two six-sided dice until I
> get the same number on both. I'd like to get the number of times I
> tried. Here's a primitive I'm using:
>
> --8<---------------cut here---------------start------------->8---
> >>> x, y = roll()
> >>> x
> 6
> >>> y
> 6 # lucky
>
> >>> x, y = roll()
> >>> x
> 4
> >>> y
> 1 # unlucky
> --8<---------------cut here---------------end--------------->8---
>
> 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)
> --8<---------------cut here---------------end--------------->8---
>
> 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? Thank you!

Your loop, fundamentally, is just counting. So let's just count.

def how_many_times():
for c in itertools.count():
...

Inside that loop, you can do whatever you like, including returning
immediately if you have what you want. I'll let you figure out the
details. :)

ChrisA
--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On 8/28/2021 8:00 AM, Hope Rouselle wrote:
> How should I write this? I'd like to roll two six-sided dice until I
> get the same number on both. I'd like to get the number of times I
> tried. Here's a primitive I'm using:
>
> --8<---------------cut here---------------start------------->8---
>>>> x, y = roll()
>>>> x
> 6
>>>> y
> 6 # lucky
>
>>>> x, y = roll()
>>>> x
> 4
>>>> y
> 1 # unlucky
> --8<---------------cut here---------------end--------------->8---
>
> 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)
> --8<---------------cut here---------------end--------------->8---
>
> 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? Thank you!

Something like (untested)

c = 0
while True:
c += 1
x, y = roll()
if x == y:
return c, (x,y)

or even better to me, as it will not loop forever if you mess up the
condition

for i in range(1, 1000000):
x, y = roll()
if x == y:
return i, (x,y)
# return "The universe ends as the essentially impossible happened"


--
Terry Jan Reedy

--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
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@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!

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?".


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...


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'...
--
Regards,
=dn
--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On 28/08/2021 21:50, Hope Rouselle wrote:

>>> roll_count = 0
>>> while True:
>>> outcome = roll_two_dice()
>>> roll_count += 1
>>> if outcome[ 0 ]== outcome[ 1 ]: break
>>> return roll_count, outcome[ 0 ]
>>
>
> Wait, I'm surprised ``outcome'' is still a valid name at the
> return-statement. Wasn't it defined inside the while?

If that really bugs you just replace the break with the return.


>>> if outcome[ 0 ]== outcome[ 1 ]:
>>> return roll_count, outcome[ 0 ]

Now its all inside the loop.

But remember readable code is better than cute code every time.
And personally I'd just declare the x,y up front. Easier to
understand and debug IMHO.

--
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


--
https://mail.python.org/mailman/listinfo/python-list
RE: on writing a while loop for rolling two dice [ In reply to ]
And there is the ever popular recursive version you call with no while loop
in sight. And, oddly, no variable declared in your main body:

#---- CODE START ---
import random

def roll2():
return random.randint(1,6), random.randint(1,6)

def roll_equal(counter):
first, second = roll2()
encountered = counter + 1
if (first == second):
return(encountered)
else:
return(roll_equal(encountered))

#--- CODE END ---

Since the result is usually a single digit of iterations, no biggie. Here is
some output:

>>> roll_equal(0)
6
>>> roll_equal(0)
7
>>> roll_equal(0)
1
>>> roll_equal(0)
7
>>> roll_equal(0)
6
>>> [ roll_equal(0) for n in range(10)]
[3, 4, 2, 5, 8, 1, 1, 2, 3, 9]
>>> [ roll_equal(0) for n in range(10)]
[3, 3, 7, 19, 7, 2, 1, 3, 8, 4]
>>> [ roll_equal(0) for n in range(10)]
[1, 3, 1, 13, 11, 4, 3, 5, 2, 4]

And the code can be a tad shorter, LOL!

But obviously then you have more overhead than an iterative solution or one
using a generator ...

-----Original Message-----
From: Python-list <python-list-bounces+avigross=verizon.net@python.org> On
Behalf Of Alan Gauld via Python-list
Sent: Saturday, August 28, 2021 6:52 PM
To: python-list@python.org
Subject: Re: on writing a while loop for rolling two dice

On 28/08/2021 21:50, Hope Rouselle wrote:

>>> roll_count = 0
>>> while True:
>>> outcome = roll_two_dice()
>>> roll_count += 1
>>> if outcome[ 0 ]== outcome[ 1 ]: break return roll_count,
>>> outcome[ 0 ]
>>
>
> Wait, I'm surprised ``outcome'' is still a valid name at the
> return-statement. Wasn't it defined inside the while?

If that really bugs you just replace the break with the return.


>>> if outcome[ 0 ]== outcome[ 1 ]:
>>> return roll_count, outcome[ 0 ]

Now its all inside the loop.

But remember readable code is better than cute code every time.
And personally I'd just declare the x,y up front. Easier to understand and
debug IMHO.

--
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


--
https://mail.python.org/mailman/listinfo/python-list

--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On 28/08/2021 14:00, Hope Rouselle wrote:

> def how_many_times():
> x, y = 0, 1
> c = 0
> while x != y:
> c = c + 1
> x, y = roll()
> return c, (x, y)
> --8<---------------cut here---------------end--------------->8---
>
> 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? Thank you!

I'd probably hide the while loop under the rug:

>>> import random
>>> def roll_die():
while True: yield random.randrange(1, 7)


Then:

>>> def hmt():
for c, (x, y) in enumerate(zip(roll_die(), roll_die()), 1):
if x == y:
return c, (x, y)


>>> hmt()
(1, (2, 2))
>>> hmt()
(4, (4, 4))
>>> hmt()
(1, (5, 5))


OK, maybe a bit complicated... but does it pay off if you want to
generalize?

>>> def roll_die(faces):
while True: yield random.randrange(1, 1 + faces)

>>> def hmt(faces, dies):
for c, d in enumerate(zip(*[roll_die(faces)]*dies), 1):
if len(set(d)) == 1: return c, d


>>> hmt(10, 1)
(1, (2,))
>>> hmt(10, 2)
(3, (10, 10))
>>> hmt(10, 3)
(250, (5, 5, 5))
>>> hmt(1, 10)
(1, (1, 1, 1, 1, 1, 1, 1, 1, 1, 1))

You decide :)

--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On 29/08/2021 20.06, Peter Otten wrote:
...
> OK, maybe a bit complicated... but does it pay off if you want to
> generalize?
>
>>>> def roll_die(faces):
>     while True: yield random.randrange(1, 1 + faces)
>
>>>> def hmt(faces, dies):
>     for c, d in enumerate(zip(*[roll_die(faces)]*dies), 1):
>         if len(set(d)) == 1: return c, d


Curiosity:
why not add dies as a parameter of roll_die()?

Efficiency:
- wonder how max( d ) == min( d ) compares for speed with the set() type
constructor?
- alternately len( d ) < 2?
- or len( d ) - 1 coerced to a boolean by the if?
- how much more efficient is any of this (clever thinking!) than the
OP's basic, simpler, and thus more readable, form?

English language 'treachery':
- one die
- multiple dice
(probably not followed in US-English (can't recall), particularly on
computers running the Hollywood Operating System).

Continuous Education:
Thanks for the reminder that enumerate() can be seeded with a "start" value!
--
Regards,
=dn
--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On Sun, Aug 29, 2021 at 8:14 PM dn via Python-list
<python-list@python.org> wrote:
> Efficiency:
> - wonder how max( d ) == min( d ) compares for speed with the set() type
> constructor?

That may or may not be an improvement.

> - alternately len( d ) < 2?
> - or len( d ) - 1 coerced to a boolean by the if?

Neither of these will make any notable improvement. The work is done
in constructing the set, and then you're taking the length. How you do
the comparison afterwards is irrelevant.

ChrisA
--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On 29/08/2021 12:13, dn via Python-list wrote:
> On 29/08/2021 20.06, Peter Otten wrote:
> ...
>> OK, maybe a bit complicated... but does it pay off if you want to
>> generalize?
>>
>>>>> def roll_die(faces):
>>     while True: yield random.randrange(1, 1 + faces)
>>
>>>>> def hmt(faces, dies):
>>     for c, d in enumerate(zip(*[roll_die(faces)]*dies), 1):
>>         if len(set(d)) == 1: return c, d
>
>
> Curiosity:
> why not add dies as a parameter of roll_die()?

Dunno. Maybe because I've "always" [1] wanted a version of
random.randrange() that generates values indefinitely. It would need to
check its arguments only once, thus leading to some extra

> Efficiency:
> - wonder how max( d ) == min( d ) compares for speed with the set() type
> constructor?

I did the simplest thing, speed was not a consideration. If it is, and
dies (sorry for that) is large I'd try

first = d[0]
all(x == first for x in d) # don't mind one duplicate test

For smaller numbers of dice I'd unpack (first, *rest) inside the for
loop. But it's a trade-off, you' have to measure if/when it's better to
go through the whole tuple in C.


> - alternately len( d ) < 2?
> - or len( d ) - 1 coerced to a boolean by the if?
> - how much more efficient is any of this (clever thinking!) than the
> OP's basic, simpler, and thus more readable, form?

It really isn't efficiency, it's a (misled?) sense of aesthetics where
I've come to prefer

- for-loops over while, even when I end up with both to get the desired for

- enumerate() over an explicit counter even though there is the extra
unpack, and you still need to initialize the counter in the general case:

for i, item in enumerate([]): pass
print(f"There are {i+1} items in the list.") # Oops

> English language 'treachery':
> - one die
> - multiple dice

You might have inferred that I knew (or had looked up) the singular of
dice, so this is but a momentary lapse of reason. It hurts me more than
you, trust me. Not as much, as going on record with confusing they're
and their, but still ;)

> (probably not followed in US-English (can't recall), particularly on
> computers running the Hollywood Operating System).

I've come to the conclusion that International English is hopelessly and
inevitably broken. That's the price native speakers have to pay for
having they're (oops, I did it again!) language used as lingua franca.

> Continuous Education:
> Thanks for the reminder that enumerate() can be seeded with a "start" value!

[1] I think I've suggested reimplementing the whole module in terms of
generators -- can't find the post though.

--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On 29/08/2021 22.24, Chris Angelico wrote:
> On Sun, Aug 29, 2021 at 8:14 PM dn via Python-list
> <python-list@python.org> wrote:
>> Efficiency:
>> - wonder how max( d ) == min( d ) compares for speed with the set() type
>> constructor?
>
> That may or may not be an improvement.
>
>> - alternately len( d ) < 2?
>> - or len( d ) - 1 coerced to a boolean by the if?
>
> Neither of these will make any notable improvement. The work is done
> in constructing the set, and then you're taking the length. How you do
> the comparison afterwards is irrelevant.

It was far too late for either of us (certainly this little boy) to be
out-and-coding - plus an excellent illustration of why short-names are a
false-economy which can quickly (and easily) lead to "technical debt"!


The "d" is a tuple (the 'next' returned from the zip-output object)
consisting of a number of die-throw results). Thus, can toss that into
len() without (any overhead of) conversion to a set.
--
Regards,
=dn
--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On Mon, Aug 30, 2021 at 9:53 AM dn via Python-list
<python-list@python.org> wrote:
>
> On 29/08/2021 22.24, Chris Angelico wrote:
> > On Sun, Aug 29, 2021 at 8:14 PM dn via Python-list
> > <python-list@python.org> wrote:
> >> Efficiency:
> >> - wonder how max( d ) == min( d ) compares for speed with the set() type
> >> constructor?
> >
> > That may or may not be an improvement.
> >
> >> - alternately len( d ) < 2?
> >> - or len( d ) - 1 coerced to a boolean by the if?
> >
> > Neither of these will make any notable improvement. The work is done
> > in constructing the set, and then you're taking the length. How you do
> > the comparison afterwards is irrelevant.
>
> It was far too late for either of us (certainly this little boy) to be
> out-and-coding - plus an excellent illustration of why short-names are a
> false-economy which can quickly (and easily) lead to "technical debt"!
>
>
> The "d" is a tuple (the 'next' returned from the zip-output object)
> consisting of a number of die-throw results). Thus, can toss that into
> len() without (any overhead of) conversion to a set.

Oh. Well, taking the length of the tuple is fast... but useless. The
point was to find out if everything in it was unique :)

Conversion to set tests this because the length of the set is the
number of unique elements; checking max and min works because two
scans will tell you if they're all the same; using all with a
generator stops early if you find a difference, but requires
back-and-forth calls into Python code; there are various options, and
the choice probably won't make a material performance difference
anyway :)

ChrisA
--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On 30/08/2021 00.47, Peter Otten wrote:
> On 29/08/2021 12:13, dn via Python-list wrote:
>> On 29/08/2021 20.06, Peter Otten wrote:
>> ...
>>> OK, maybe a bit complicated... but does it pay off if you want to
>>> generalize?
>>>
>>>>>> def roll_die(faces):
>>>      while True: yield random.randrange(1, 1 + faces)
>>>
>>>>>> def hmt(faces, dies):
>>>      for c, d in enumerate(zip(*[roll_die(faces)]*dies), 1):
>>>          if len(set(d)) == 1: return c, d
>>
>>
>> Curiosity:
>> why not add dies as a parameter of roll_die()?
>
> Dunno. Maybe because I've "always" [1] wanted a version of
> random.randrange() that generates values indefinitely. It would need to
> check its arguments only once, thus leading to some extra

Each code-unit should do one job, and do it well!
SRP...


>> Efficiency:
>> - wonder how max( d ) == min( d ) compares for speed with the set() type
>> constructor?
>
> I did the simplest thing, speed was not a consideration. If it is, and
> dies (sorry for that) is large I'd try
>
> first = d[0]
> all(x == first for x in d)  # don't mind one duplicate test
>
> For smaller numbers of dice I'd unpack (first, *rest) inside the for
> loop. But it's a trade-off, you' have to measure if/when it's better to
> go through the whole tuple in C.

For larger numbers of dice, and presuming a preference for an
inner-function which rolls only a single die per call; would it be more
efficient to test each individual die's value against the first,
immediately after its (individual) roll/evaluation (rinse-and-repeat for
each die thereafter)? This, on the grounds that the first mis-match
obviates the need to examine (or even roll), any other die/dice in the
collection.

OTOH the simulation of rolling n-number of dice, as would happen in the
real-world, would be broken by making the computer's algorithm more
efficient (rolling until the first non-equal value is 'found'). Does
that mean the realism of the model dies?
(sorry - no, I'm not sorry - you deserved that!)

Does one "roll" a die, or "shake the dice"???


We don't know the OP's requirements wrt to execution-efficiency.
However, as you (also) probably suffered, such exercises regularly
feature in stats and probability courses. Sometimes 'the numbers' are
quite large in order to better-illustrate ("smooth") distribution
characteristics, etc.


I have a love?hate relationship with questions of Python and
'efficiency'. Today, discovered that using a cut-down Linux version (on
AWS) was actually slower than using a full-fat distribution - upon
analysis, my friendly 'expert' was able to point the finger at the way
the two distros compiled/prepared/distribute the(ir) Python Interpreter.
(I'm glad he thought such investigation 'fun'!) All of which further
complicates the business of design, given we already know of situations
where approach-a will run faster than approach-b, on your machine; yet
the comparison may be reversed on mine.

This discussion forms a sub-set of that: when to use the built-in
functions (implemented in C) because they are (claimed to be) more
efficient than another approach - and, when one approach using a
built-in function might be faster than another 'built-in'/C-coded approach.

("small things amuse small minds" - mind how you describe my mind!)


"Bottom line": I prefer to think of Python's "efficiency" as reflected
in the amount of my time that is needed, in order to complete a project!


>> - alternately len( d ) < 2?
>> - or len( d ) - 1 coerced to a boolean by the if?
>> - how much more efficient is any of this (clever thinking!) than the
>> OP's basic, simpler, and thus more readable, form?
>
> It really isn't efficiency, it's a (misled?) sense of aesthetics where
> I've come to prefer
>
> - for-loops over while, even when I end up with both to get the desired for
>
> - enumerate() over an explicit counter even though there is the extra
> unpack, and you still need to initialize the counter in the general case:
>
> for i, item in enumerate([]): pass
> print(f"There are {i+1} items in the list.")  # Oops

Next thing you'll be using for-else...
[insane giggling]


It's interesting how we arrive at these views (as a trainer I spend a
lot of time trying to detect how learners build their mental maps, or
"models", of each topic).

I've always had a clear 'formula'/rule/hobgoblin: if the number of loops
can be predicted, use 'for', otherwise use 'while'.

Of course, Python alters that view because it offers a for-each, which
means that I don't need to know the number of loops, only that the loop
will cycle through each item in the iterable.

It used to be a far simpler world!


That said, I really miss the option of while controlling the loop with a
pre-condition AND having a repeat...until controlling the loop with a
post-condition - the former enabling >=0 loops; the latter, requiring at
least one!


Using enumerate() may be a matter of aesthetics (English-English
spelling!). However, it is a basic Python idiom. It is as much a tool in
our coding as a fork/spoon/chop-sticks/fingers are to someone eating.
(yes, I'm feeling hungry).

At times I feel a 'siren call' to use some of the powerful, let's call
them "one-liner" tools, because it is 'fun' to bend my mind around the
challenge. However, most such code tends to lose readability in some
sort of inverse proportion to its power - it leaves the clarity and
simplicity of Python-space and heads towards APL, Lisp, et al.

The 'problem' is that as a coder increases his/her knowledge (learns to
harness 'the force'), the code-structures which count as one "chunk" of
thought, expand. For example, it can be difficult to see (remember) that
although comprehensions may have become a single 'unit' of thought to a
skilled practitioner; for others they are (still) opaque, and
'mountains' to climb.

Thus, the 'balance' between 'power' and readability; and between using
techniques which demand Python-expertise and thus carry an expectation
that less-capable/-experienced programmers will 'improve their game' (to
be able to contribute to 'this' project, or future re-use/maintenance).
(see also "Zen of Python")

The 'level' then becomes a convention - just as much as 'do we adhere to
PEP-008 naming' (etc). The important point is not what the convention
is, but that the team has arrived at a pragmatic agreement, eg will we
use comprehensions or explicit loops. Your team might say "of course",
whereas mine says "can't cope with that"...

BTW you already know this, but I'm not writing only to you!
(don't fret, you're still 'special'...)


>> English language 'treachery':
>> - one die
>> - multiple dice
>
> You might have inferred that I knew (or had looked up) the singular of
> dice, so this is but a momentary lapse of reason. It hurts me more than
> you, trust me. Not as much, as going on record with confusing they're
> and their, but still ;)

Reason? Logic? Consistency?
The English language.
Surely, you jest...


Having learned/lived many languages, struggling-mightily with some,
feeling comfortable with others; I am enormously grateful (greatly
grateful?) that English was one of my home-languages, and that I didn't
have to "learn" it!

I do enjoy 'playing' with it though, and as pointed-out annually
(?semesterly), making students groan in response to my
weak/pathetic/Dad-joke/seven-year-old's humor (in live-lectures) at
least gives feedback that they are 'there' and paying some attention.
(alternately, it's Pavlovian-conditioning - BTW: yes, I'm still hungry...)


Please consider the die/dice as 'educational', and a reflection of my
confusion of comprehension when trying to infer meaning whilst reading
the code-example - rather than arrogance or placing undue demand on you.


>> (probably not followed in US-English (can't recall), particularly on
>> computers running the Hollywood Operating System).
>
> I've come to the conclusion that International English is hopelessly and
> inevitably broken. That's the price native speakers have to pay for
> having they're (oops, I did it again!) language used as lingua franca.

If English really set-out to be the world's lingua-franca, why didn't it
come up with its own, a particularly (and peculiarly) English word, for
the concept???


I've spent quite some time looking into the idea of 'International
English' - to attempt to find 'an English' to employ in our course
materials used world-wide. Even 'native speakers' can't agree on what is
'English'! When the question is widened to include the broader, majority
of the world; the concept of a 'core' of English becomes impossible to
define or encapsulate...


Even being a 'native speaker' doesn't necessarily help: George Bernard
Shaw described "Britain and America are two nations divided by [the use
of] a common language"!

He was Irish - and I recall another quotation along the lines of: the
Irish learn English in order to hurl insults.

Sigh!


Let's not be racist though - or would that be lingual-ist(?) Advice when
learning French was "always expect exceptions" (apologies, I went
looking for a source, in English or French - but Python-references
crowded the first couple of web-search 'hits'). I enjoy the word-picture
in Spanish: "Hijo de tigre, no siempre sale pintado. Siempre ahi esa
excepción." (The tiger-cub isn't always born (ready-)painted
(colored?striped). There is always an exception!) So much more apropos
(to use another (?)English expression) than, that "a leopard NEVER
changes its spots"!


>> Continuous Education:
>> Thanks for the reminder that enumerate() can be seeded with a "start"
>> value!
>
> [1] I think I've suggested reimplementing the whole module in terms of
> generators -- can't find the post though.

Can't we assume lazy-evaluation - if only by virtue of the example
equivalent-code illustration in the docs? (it features a "yield")
(https://docs.python.org/3/library/functions.html?highlight=enumerate#enumerate)

Must admit, once the use of generators started to multiply
release-after-release (both in Python code and 'under the hood'), and
tools like range()/xrange() were made more memory-efficient, etc, that
pretty much all such constructs had become "lazy".
(Careless assumption. Don't know!)
--
Regards,
=dn
--
https://mail.python.org/mailman/listinfo/python-list
RE: on writing a while loop for rolling two dice [ In reply to ]
> def how_many_times():
> x, y = 0, 1
> c = 0
> while x != y:
> c = c + 1
> x, y = roll()
> return c, (x, y)

Since I haven't seen it used in answers yet, here's another option using our new walrus operator

def how_many_times():
roll_count = 1
while (rolls := roll())[0] != rolls[1]:
roll_count += 1
return (roll_count, rolls)
--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On Mon, Aug 30, 2021 at 11:13 PM David Raymond <David.Raymond@tomtom.com> wrote:
>
> > def how_many_times():
> > x, y = 0, 1
> > c = 0
> > while x != y:
> > c = c + 1
> > x, y = roll()
> > return c, (x, y)
>
> Since I haven't seen it used in answers yet, here's another option using our new walrus operator
>
> def how_many_times():
> roll_count = 1
> while (rolls := roll())[0] != rolls[1]:
> roll_count += 1
> return (roll_count, rolls)
>

Since we're creating solutions that use features in completely
unnecessary ways, here's a version that uses collections.Counter:

def how_many_times():
return next((count, rolls) for count, rolls in
enumerate(iter(roll, None)) if len(Counter(rolls)) == 1)

Do I get bonus points for it being a one-liner that doesn't fit in
eighty characters?

ChrisA
--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On 30/08/2021 15:50, Chris Angelico wrote:

> def how_many_times():
> return next((count, rolls) for count, rolls in
> enumerate(iter(roll, None)) if len(Counter(rolls)) == 1)


That's certainly the most Counter-intuitive version so far;)


> Do I get bonus points for it being a one-liner that doesn't fit in
> eighty characters?

Nah, but you'll get an honorable mention when you run it through
pycodestyle without line break...

--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On Tue, Aug 31, 2021 at 12:28 AM Peter Otten <__peter__@web.de> wrote:
>
> On 30/08/2021 15:50, Chris Angelico wrote:
>
> > def how_many_times():
> > return next((count, rolls) for count, rolls in
> > enumerate(iter(roll, None)) if len(Counter(rolls)) == 1)
>
>
> That's certainly the most Counter-intuitive version so far;)

Thank you, I appreciate that :)

> > Do I get bonus points for it being a one-liner that doesn't fit in
> > eighty characters?
>
> Nah, but you'll get an honorable mention when you run it through
> pycodestyle without line break...
>

Are there any linters that warn against "unintuitive use of
two-argument iter()"?

ChrisA
--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On 30/08/2021 06:17, dn via Python-list wrote:

> OTOH the simulation of rolling n-number of dice, as would happen in the
> real-world, would be broken by making the computer's algorithm more
> efficient (rolling until the first non-equal value is 'found'). Does
> that mean the realism of the model dies?

You've got to ask your dietician...

(I'm sure everyone agrees that I should stop here. And stop I will)

--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
dn <PythonList@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@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.
--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
David Raymond <David.Raymond@tomtom.com> writes:

>> def how_many_times():
>> x, y = 0, 1
>> c = 0
>> while x != y:
>> c = c + 1
>> x, y = roll()
>> return c, (x, y)
>
> Since I haven't seen it used in answers yet, here's another option using our new walrus operator
>
> def how_many_times():
> roll_count = 1
> while (rolls := roll())[0] != rolls[1]:
> roll_count += 1
> return (roll_count, rolls)

That's nice, although it doesn't seem more readable to a novice seeing a
while for the first time, seeing a loop for the first time, than that
while-True version. In fact, I think the while-True is the clearest so
far. But it's always nice to spot a walrus in the wild! (If you're
somewhere safe, that is.)
--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
Chris Angelico <rosuav@gmail.com> writes:

> On Mon, Aug 30, 2021 at 11:13 PM David Raymond <David.Raymond@tomtom.com> wrote:
>>
>> > def how_many_times():
>> > x, y = 0, 1
>> > c = 0
>> > while x != y:
>> > c = c + 1
>> > x, y = roll()
>> > return c, (x, y)
>>
>> Since I haven't seen it used in answers yet, here's another option using our new walrus operator
>>
>> def how_many_times():
>> roll_count = 1
>> while (rolls := roll())[0] != rolls[1]:
>> roll_count += 1
>> return (roll_count, rolls)
>>
>
> Since we're creating solutions that use features in completely
> unnecessary ways, here's a version that uses collections.Counter:
>
> def how_many_times():
> return next((count, rolls) for count, rolls in
> enumerate(iter(roll, None)) if len(Counter(rolls)) == 1)
>
> Do I get bonus points for it being a one-liner that doesn't fit in
> eighty characters?

Lol. You do not. In fact, this should be syntax error :-D --- as I
guess it would be if it were a lambda expression?
--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On Fri, Sep 3, 2021 at 4:33 AM Hope Rouselle <hrouselle@jevedi.com> wrote:
> 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.

It's on the cusp. When you ask someone to express the concept of "do
this until this happens", obviously that's a while loop; but as soon
as you introduce the iteration counter, it becomes less obvious, since
"iterate over counting numbers until this happens" is a quite viable
way to express this. However, if the students don't know
itertools.count(), they'll most likely put in an arbitrary limit (like
"for c in range(100000000)"), which you can call them out for.

> 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.

That may be the case, but in Python, I almost never write "while
True". Consider the two while loops in this function:

https://github.com/Rosuav/shed/blob/master/autohost_manager.py#L92

Thanks to Python's flexibility and efficient compilation, these loops
are as descriptive as those with actual conditions, while still
behaving exactly like "while True". (The inner loop, "more pages",
looks superficially like it should be a for loop - "for page in
pages:" - but the data is coming from successive API calls, so it
can't know.)

> 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.

You're overlaying two loops here. One is iterating "c" up from zero,
the other is calling a function and testing its results. It's up to
you which of these should be considered the more important, and which
is a bit of extra work added onto it. With the counter as primary, you
get something like this:

for c in itertools.count():
x, y = roll()
if x == y: return c, x, y

With the roll comparison as primary, you get this:

c, x, y = 0, 0, 1
while x != y:
x, y = roll()
c += 1
return c, x, y

Reworking the second into a do-while style (Python doesn't have that,
so we have to write it manually):

c = 0
while "x and y differ":
x, y = roll()
c += 1
if x == y: break
return c, x, y

And at this point, it's looking pretty much identical to the for loop
version. Ultimately, they're all the same and you can pick and choose
elements from each of them.

ChrisA
--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On Fri, Sep 3, 2021 at 4:51 AM Hope Rouselle <hrouselle@jevedi.com> wrote:
>
> Chris Angelico <rosuav@gmail.com> writes:
>
> > On Mon, Aug 30, 2021 at 11:13 PM David Raymond <David.Raymond@tomtom.com> wrote:
> >>
> >> > def how_many_times():
> >> > x, y = 0, 1
> >> > c = 0
> >> > while x != y:
> >> > c = c + 1
> >> > x, y = roll()
> >> > return c, (x, y)
> >>
> >> Since I haven't seen it used in answers yet, here's another option using our new walrus operator
> >>
> >> def how_many_times():
> >> roll_count = 1
> >> while (rolls := roll())[0] != rolls[1]:
> >> roll_count += 1
> >> return (roll_count, rolls)
> >>
> >
> > Since we're creating solutions that use features in completely
> > unnecessary ways, here's a version that uses collections.Counter:
> >
> > def how_many_times():
> > return next((count, rolls) for count, rolls in
> > enumerate(iter(roll, None)) if len(Counter(rolls)) == 1)
> >
> > Do I get bonus points for it being a one-liner that doesn't fit in
> > eighty characters?
>
> Lol. You do not. In fact, this should be syntax error :-D --- as I
> guess it would be if it were a lambda expression?

It got split across lines when I posted it, but if I did this in a
program, I'd make it a single long line. That said, though - Python
doesn't mind if you mess up the indentation inside a parenthesized
expression. Even broken like this, it WILL work. It just looks even
uglier than it does with proper indentation :)

BTW, this sort of thing is great as an anti-plagiarism check. If a
student ever turns in an abomination like this, you can be extremely
confident that it was copied from some programming site/list.
Especially since I've used the two-arg version of iter() in there -
that's quite a rarity.

Hmmmmm.

My mind is straying to evil things.

The two-arg iter can do SO much more than I'm using it for here.

By carefully designing the second argument, we could make something
that is equal to anything whose two elements are equal, which would
then terminate the loop. This... could be a lot worse than it seems.

I'll leave it as an exercise for the reader to figure out how to
capture the matching elements for return.

ChrisA
--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
>> def how_many_times():
>> x, y = 0, 1
>> c = 0
>> while x != y:
>> c = c + 1
>> x, y = roll()
>> return c, (x, y)
>
> Since I haven't seen it used in answers yet, here's another option using our new walrus operator
>
> def how_many_times():
> roll_count = 1
> while (rolls := roll())[0] != rolls[1]:
> roll_count += 1
> return (roll_count, rolls)
>

I would go even further, saying there is no need to «roll dices»:

def how_many_times():
nb_times = random.choice([n for n in range(50) for _ in
range(round(10000*(1/6)*(5/6)**(n-1)))])
return nb_times, (random.randint(1, 6),) * 2

If i had more time on my hands, i would do something with bissect to get
nb_times with more precision, as i have (mis)calculated that the
probability of having nb_times = N is N = (1/6) * (5/6) ** (N-1)
Something like this may work:

nb_times = [.random.random() < (1/6) * (5/6) ** (N-1) for N in
range(1, 50)].index(True)+1
--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On 2021-09-02 11:28:21 -0300, Hope Rouselle wrote:
> dn <PythonList@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?
[...]
> 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.

You can get around this by using NaN:

def how_many_times():
c, x, y = 0, math.nan, math.nan
while x != y:
c = c + 1
x, y = roll()
return c, x, y

Not sure if this is an improvement. Now you have to explain to your
students why math.nan != math.nan.

When I need a guaranteed unique value I often just use object():

def how_many_times():
c, x, y = 0, object(), object()
while x != y:
c = c + 1
x, y = roll()
return c, x, y

Of course now you are back to two different values, but they look the
same. Which may be better or worse for your students. Plus x and y are
now bound to objects of different types during their lifetime, which may
be a bit dicey.

hp


--
_ | Peter J. Holzer | Story must make more sense than reality.
|_|_) | |
| | | hjp@hjp.at | -- Charles Stross, "Creative writing
__/ | http://www.hjp.at/ | challenge!"
Re: on writing a while loop for rolling two dice [ In reply to ]
Chris Angelico <rosuav@gmail.com> writes:

> On Fri, Sep 3, 2021 at 4:33 AM Hope Rouselle <hrouselle@jevedi.com> wrote:
>> 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.
>
> It's on the cusp. When you ask someone to express the concept of "do
> this until this happens", obviously that's a while loop; but as soon
> as you introduce the iteration counter, it becomes less obvious, since
> "iterate over counting numbers until this happens" is a quite viable
> way to express this. However, if the students don't know
> itertools.count(), they'll most likely put in an arbitrary limit (like
> "for c in range(100000000)"), which you can call them out for.
>
>> 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.
>
> That may be the case, but in Python, I almost never write "while
> True". Consider the two while loops in this function:
>
> https://github.com/Rosuav/shed/blob/master/autohost_manager.py#L92
>
> Thanks to Python's flexibility and efficient compilation, these loops
> are as descriptive as those with actual conditions, while still
> behaving exactly like "while True". (The inner loop, "more pages",
> looks superficially like it should be a for loop - "for page in
> pages:" - but the data is coming from successive API calls, so it
> can't know.)

That's pretty nice. I did suggest the same to my students, showing your
code to them, actually. The course explicitly avoided talking about
regular values being considered True, but now I couldn't keep the truth
from them.

>> 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.
>
> You're overlaying two loops here. One is iterating "c" up from zero,
> the other is calling a function and testing its results. It's up to
> you which of these should be considered the more important, and which
> is a bit of extra work added onto it. With the counter as primary, you
> get something like this:
>
> for c in itertools.count():
> x, y = roll()
> if x == y: return c, x, y
>
> With the roll comparison as primary, you get this:
>
> c, x, y = 0, 0, 1
> while x != y:
> x, y = roll()
> c += 1
> return c, x, y
>
> Reworking the second into a do-while style (Python doesn't have that,
> so we have to write it manually):
>
> c = 0
> while "x and y differ":
> x, y = roll()
> c += 1
> if x == y: break
> return c, x, y
>
> And at this point, it's looking pretty much identical to the for loop
> version. Ultimately, they're all the same and you can pick and choose
> elements from each of them.

I see. That's why C must have added the do-while, but yeah --- it's not
really worth it. (An educational investigation. Thank you.)
--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
"Peter J. Holzer" <hjp-python@hjp.at> writes:

> On 2021-09-02 11:28:21 -0300, Hope Rouselle wrote:
>> dn <PythonList@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?
> [...]
>> 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.
>
> You can get around this by using NaN:
>
> def how_many_times():
> c, x, y = 0, math.nan, math.nan
> while x != y:
> c = c + 1
> x, y = roll()
> return c, x, y
>
> Not sure if this is an improvement. Now you have to explain to your
> students why math.nan != math.nan.
>
> When I need a guaranteed unique value I often just use object():
>
> def how_many_times():
> c, x, y = 0, object(), object()
> while x != y:
> c = c + 1
> x, y = roll()
> return c, x, y
>
> Of course now you are back to two different values, but they look the
> same. Which may be better or worse for your students. Plus x and y are
> now bound to objects of different types during their lifetime, which may
> be a bit dicey.

Lol. I would argue that it's quite appropriate to the event (``of
rolling dice'' --- clarity-obsession). :D Pretty nice alternatives.
Thank you so much.
--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On 04/09/2021 08.53, Hope Rouselle wrote:
> Chris Angelico <rosuav@gmail.com> writes:

>> And at this point, it's looking pretty much identical to the for loop
>> version. Ultimately, they're all the same and you can pick and choose
>> elements from each of them.
>
> I see. That's why C must have added the do-while, but yeah --- it's not
> really worth it.

Kernighan and Ritchie agree(d) with you. Per _The C Programming
Language__:
Experience shows that do-while is much less used that while
and for.

(Second edition, Section 3.6, page 63)

--
Michael F. Stemper
Outside of a dog, a book is man's best friend.
Inside of a dog, it's too dark to read.
--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
"Michael F. Stemper" <michael.stemper@gmail.com> writes:

> On 04/09/2021 08.53, Hope Rouselle wrote:
>> Chris Angelico <rosuav@gmail.com> writes:
>
>>> And at this point, it's looking pretty much identical to the for loop
>>> version. Ultimately, they're all the same and you can pick and choose
>>> elements from each of them.
>> I see. That's why C must have added the do-while, but yeah --- it's
>> not
>> really worth it.
>
> Kernighan and Ritchie agree(d) with you. Per _The C Programming
> Language__:
> Experience shows that do-while is much less used that while
> and for.
>
> (Second edition, Section 3.6, page 63)

Special thanks for the reference! Here's what they say on the first
edition.

``As might be expected, do-while is much less used than while and for,
accounting for perhaps five percent of all loops.'' (First edition,
section 3.6, page 59.)

They looked into a sample and decided to remove the statistic. :-)
--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On Sat, 4 Sep 2021 12:27:55 -0500, "Michael F. Stemper"
<michael.stemper@gmail.com> declaimed the following:

>
>Kernighan and Ritchie agree(d) with you. Per _The C Programming
>Language__:
> Experience shows that do-while is much less used that while
> and for.
>

And just for confusion, consider languages with "repeat / until"...

"do / while" repeats so long as the condition evaluates to "true";
"repeat / until" /exits/ when the condition evaluates to "true".

Then... there is Ada...

While one is most likely to encounter constructs:

for ix in start..end loop
...
end loop;

and

while condition loop
...
end loop;

the core construct is just a bare

loop
...
end loop;

which, with the "exit when condition" statement allows low-level emulation
of any loop... (same as Python "if condition: break"

loop -- "while" loop
exit when not condition;
...
end loop;

loop -- "repeat / until"
...
exit when condition;
end loop;

loop -- split
...
exit when condition;
...
end loop;

{I'm not going to do the "for" loop, but one can easily manage
initialization/increment/test statements}.


To really get your mind blown, look at loops in REXX...

do while condition
...
end

do until condition
/* note that the termination parameter is listed at top, */
/* but takes effect at the bottom, so always one pass */
...
end

do forever
...
if condition then
leave
...
end

do idx = start to end /* optional: by increment */
...
end

do idx = 1 by increment for repetitions
...
end

AND worse! You can combine them...

do idx = start for repetitions while condition1 until condition2
...
end

{I need to check if both while and until can be in the same statement}


--
Wulfraed Dennis Lee Bieber AF6VN
wlfraed@ix.netcom.com http://wlfraed.microdiversity.freeddns.org/

--
https://mail.python.org/mailman/listinfo/python-list
RE: on writing a while loop for rolling two dice [ In reply to ]
For some people the "while true" method seems reasonable but it has a
problem if the internal body does not have some guarantee of an exit. And
that exit can be subtle. Many have mentioned ways an end condition can fail
due to rounding errors not being exactly equal to what you are looking for,
or an asymptotic process that approaches zero with a cutoff that is thus
never reached.

But I have seen some cases where you want a process or thread to run
indefinitely until it is killed by another process or you reboot. You could
of course use something like flag="green" and have your while keep testing
that value but that is just wasted motion. Of course, properly used, it does
help explain to the reader what your intention is, if done properly. It also
can confuse if you put in "while 5 < 6" or other weird ways to say do this
indefinitely.

I think part of this conversation is about programming styles and what we
should teach new students versus those who are trying to find more creative
ways to do things or more efficiently or more generality. Sometimes a more
direct method may be reasonable. On another forum, I saw someone write
somewhat lengthy and redundant code on how to deal with partitioning data
into three clusters randomly. My algorithm was general and handled any
number of N clusters and since N often does not cleanly divide the number of
items, has to place the remaining items into one of the N clusters or
distribute them one at a time into some to make them almost even in size.

His solution was to repeat large sections of code, three times, with some
modification, for the cases where the remainder (modulo N) was 0, 1 or 2.
The latter method was longer but in an odd way, much easier to understand.
It boiled down to, if you have one extra put it here. If you have two, put
one here and one there. My method had all kinds of bells and whistles that
this specific case did not need.

Let me end with asking if anyone has ever seen a mild variant of this:

... # code

while false
apologize()

... # more code

-----Original Message-----
From: Python-list <python-list-bounces+avigross=verizon.net@python.org> On
Behalf Of Hope Rouselle
Sent: Thursday, September 2, 2021 10:42 AM
To: python-list@python.org
Subject: Re: on writing a while loop for rolling two dice

David Raymond <David.Raymond@tomtom.com> writes:

>> def how_many_times():
>> x, y = 0, 1
>> c = 0
>> while x != y:
>> c = c + 1
>> x, y = roll()
>> return c, (x, y)
>
> Since I haven't seen it used in answers yet, here's another option
> using our new walrus operator
>
> def how_many_times():
> roll_count = 1
> while (rolls := roll())[0] != rolls[1]:
> roll_count += 1
> return (roll_count, rolls)

That's nice, although it doesn't seem more readable to a novice seeing a
while for the first time, seeing a loop for the first time, than that
while-True version. In fact, I think the while-True is the clearest so far.
But it's always nice to spot a walrus in the wild! (If you're somewhere
safe, that is.)
--
https://mail.python.org/mailman/listinfo/python-list

--
https://mail.python.org/mailman/listinfo/python-list
RE: on writing a while loop for rolling two dice [ In reply to ]
I actually like it if a language lets you spell out your intention, although adding many keywords is not a plus.

So, yes something like:

loop
...
end loop;

Is appealing as it makes clear the decision on when to exit the loop must be within the loop (or till something kills ...)

In languages like C/C++ there are people who make up macros like:

#define INDEFINITELY_LOOP while (true)

Or something like that and then allow the preprocessor to replace INDEFINITELY_LOOP with valid C code.

So, how to do something like that in python, is a challenge left to the user ????

Bottom line I find is it is a great idea to write comments as even if you are the one reviewing the code much later, you may struggle to figure out what you did and why.

-----Original Message-----
From: Python-list <python-list-bounces+avigross=verizon.net@python.org> On Behalf Of Dennis Lee Bieber
Sent: Sunday, September 5, 2021 12:50 PM
To: python-list@python.org
Subject: Re: on writing a while loop for rolling two dice

On Sat, 4 Sep 2021 12:27:55 -0500, "Michael F. Stemper"
<michael.stemper@gmail.com> declaimed the following:

>
>Kernighan and Ritchie agree(d) with you. Per _The C Programming
>Language__:
> Experience shows that do-while is much less used that while
> and for.
>

And just for confusion, consider languages with "repeat / until"...

"do / while" repeats so long as the condition evaluates to "true"; "repeat / until" /exits/ when the condition evaluates to "true".

Then... there is Ada...

While one is most likely to encounter constructs:

for ix in start..end loop
...
end loop;

and

while condition loop
...
end loop;

the core construct is just a bare

loop
...
end loop;

which, with the "exit when condition" statement allows low-level emulation of any loop... (same as Python "if condition: break"

loop -- "while" loop
exit when not condition;
...
end loop;

loop -- "repeat / until"
...
exit when condition;
end loop;

loop -- split
...
exit when condition;
...
end loop;

{I'm not going to do the "for" loop, but one can easily manage initialization/increment/test statements}.


To really get your mind blown, look at loops in REXX...

do while condition
...
end

do until condition
/* note that the termination parameter is listed at top, */
/* but takes effect at the bottom, so always one pass */
...
end

do forever
...
if condition then
leave
...
end

do idx = start to end /* optional: by increment */
...
end

do idx = 1 by increment for repetitions
...
end

AND worse! You can combine them...

do idx = start for repetitions while condition1 until condition2
...
end

{I need to check if both while and until can be in the same statement}


--
Wulfraed Dennis Lee Bieber AF6VN
wlfraed@ix.netcom.com http://wlfraed.microdiversity.freeddns.org/

--
https://mail.python.org/mailman/listinfo/python-list

--
https://mail.python.org/mailman/listinfo/python-list
RE: on writing a while loop for rolling two dice [ In reply to ]
Let me add something, Stefan. Some people just want to get a job done. For
this person, he had a very specific need for a one-time project where the
rest of it was understood but one small step was confusing. Frankly, he
could have done it faster by opening a text editor on something like a CSV
file and flipped some (actual) three-sided coins while manually doing a cut
and past of lines into three new files and near the end, make sure the last
few only went into files with a missing row or two.

I have too often had people ask me for programming help and when I suggested
they learn how to do it or let me make a more careful piece of code that
checks for errors or will easily work under various changed conditions,
guess what I usually encounter? Many just want it DONE. They often
sheepishly come back some time later with some variant of the same need that
mysteriously does not work with code they asked to be designed to just work
in one case! Often they hack away at the code in odd ways first and then
come to me to have it fixed.

But there are costs to generality and creating functions with dozens of
optional arguments and that handle a wide variety of inputs and thus
constantly are checking what types they are working with and perhaps
converting to others or need to create objects with lots of dunders, can
also make it error prone.

Looking at our forever loop discussion, how often are the contents of the
loop written with multiple terminating parts within the loop body that get
complex? I mean lots of break or continue statements all over the place
with multi-part if statements. Some can be rewritten as a more standard loop
with a condition like "while (a < 5 && found_it == FALSE || ( ... )) ..."
and often in the body you need if statements that let you skip the rest if
found_it is true. It can be a mess either way. At times you need to consider
rewriting it from scratch. This especially happens as requirements keep
changing. Ages ago we had code that processed MTA headers and every time we
had a meeting of standards bodies, we kept adding ever more headers and
keywords that often required some existing code to also look at other
headers that now might be present as they might change what you did in
existing code locations. I eventually suggested a rewrite and it turned out
to be more compact now that we evaluated some things first, rather than
within many existing parts.

Has anyone mentioned the really stupid looking forever loop in languages
with the other style of for loop?

for ( ; ;)

All that generally was, was an initialization command before a while and so
on but here all three parts were null, so why use it?

And in the python version, has anyone made a generator that returned NULL or
the like so you can say uselessly:

for ( _ in forever() ) ...


-----Original Message-----
From: Python-list <python-list-bounces+avigross=verizon.net@python.org> On
Behalf Of Stefan Ram
Sent: Monday, September 6, 2021 12:34 PM
To: python-list@python.org
Subject: Re: on writing a while loop for rolling two dice

"Avi Gross" <avigross@verizon.net> writes:
>For some people the "while true" method seems reasonable but it has a
>problem if the internal body does not have some guarantee of an exit.
>And

A programming error where the condition used does not
express the intent of the programmer can happen with
any kind of while loop.

>help explain to the reader what your intention is, if done properly. It
>also can confuse if you put in "while 5 < 6" or other weird ways to say
>do this indefinitely.

If any reader cannot understand "while True:", it's not
a problem with the source code.

When someone writes "while True:", it is clearly his intention
that the following indented code is repeated until it's exited
by some means, which means is not the while condition.

>His solution was to repeat large sections of code, three times, with
>some modification, for the cases where the remainder (modulo N) was 0, 1 or
2.

This is typical of

- beginners who just do not know the means of the language
to reduce redundancy yet,

- less experience programmers, who know the language but
still are not able to apply features to reduce redundancy
always,

- premature publication of unfinished code where the
redundancy has not yet been reduced, or

- programmers who do not have the personal means to climb to
the level of abstraction needed to remove the redundancy
in a specific case.

And, I think you wrote that too, sometimes less smart code is
more readable or maintainable. Maybe three very similar blocks
are repeated literally because future modifications are expected
that will make them less similar.


--
https://mail.python.org/mailman/listinfo/python-list

--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On 2021-09-06 at 20:11:41 -0400,
Avi Gross via Python-list <python-list@python.org> wrote:

> And in the python version, has anyone made a generator that returned
> NULL or the like so you can say uselessly:
>
> for ( _ in forever() ) ...

while "forever":
...
--
https://mail.python.org/mailman/listinfo/python-list
RE: on writing a while loop for rolling two dice [ In reply to ]
I hate to quibble but as almost anything in Python can evaluate to being
truthy, a command like

while "never"

evaluates to true as the string is not empty.

I meant a generator like

>>> def boring():
while True: yield()


>>> for _ in boring():
print("repeating ...")

The above gives me a nice infinite loop, with the second one looking like a
normal loop but actually doing nothing much.

-----Original Message-----
From: Python-list <python-list-bounces+avigross=verizon.net@python.org> On
Behalf Of 2QdxY4RzWzUUiLuE@potatochowder.com
Sent: Monday, September 6, 2021 8:28 PM
To: python-list@python.org
Subject: Re: on writing a while loop for rolling two dice

On 2021-09-06 at 20:11:41 -0400,
Avi Gross via Python-list <python-list@python.org> wrote:

> And in the python version, has anyone made a generator that returned
> NULL or the like so you can say uselessly:
>
> for ( _ in forever() ) ...

while "forever":
...
--
https://mail.python.org/mailman/listinfo/python-list

--
https://mail.python.org/mailman/listinfo/python-list
RE: on writing a while loop for rolling two dice [ In reply to ]
It has been nearly three decades since I have had to write in C, Stefan, but
what I suggested jokingly is quite mild compared to what the winners of the
obfuscated C Contest do:

https://www.ioccc.org/

Time for me to drop out of this thread. Personally I fully agree uses of
"while' as described are perfectly understandable. Features that
sophisticated programmers love tend to confuse novices. I recall my exposure
to PERL where weird things seemed to just happen with no rhyme or reason or
connections. Turned out just about everything puts things into or takes them
out of hidden variables so much of the time, a string of commands just does
what might be expected. Another variant on the elusive concept of a
pipeline. But all the nice gimmicks and tricks make novices a bit puzzled.
On the other hand, you can still write most programs the old fashioned way
and sort of start normal then head off into hyperspace at warp speed.

Python too has a way to write fairly unsophisticated programs as well as
idioms and methods that rapidly become hard to comprehend.

-----Original Message-----
From: Python-list <python-list-bounces+avigross=verizon.net@python.org> On
Behalf Of Stefan Ram
Sent: Monday, September 6, 2021 7:49 PM
To: python-list@python.org
Subject: Re: on writing a while loop for rolling two dice

"Avi Gross" <avigross@verizon.net> writes:
> In languages like C/C++ there are people who make up macros like:
>#define INDEFINITELY_LOOP while (true)
>Or something like that and then allow the preprocessor to replace
>INDEFINITELY_LOOP with valid C code.

Those usually are beginners.

>So, how to do something like that in python, is a challenge left to the
>user

Such a use of macros is frowned upon by most C programmers,
because it renders the code unreadable.

"while(1)" in C or "while True:" in Python is perfectly clear.
Don't fix it if it ain't broke!


--
https://mail.python.org/mailman/listinfo/python-list

--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On 7/09/21 11:38 am, Avi Gross wrote:

> #define INDEFINITELY_LOOP while (true)
>
> So, how to do something like that in python, is a challenge left to the user ????

def hell_frozen_over():
return False

while not hell_frozen_over():
....

--
Greg

--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On 2021-09-06, Stefan Ram <ram@zedat.fu-berlin.de> wrote:
> "Avi Gross" <avigross@verizon.net> writes:
>> In languages like C/C++ there are people who make up macros like:
>>#define INDEFINITELY_LOOP while (true)
>>Or something like that and then allow the preprocessor to replace
>>INDEFINITELY_LOOP with valid C code.
>
> Those usually are beginners.
>
>>So, how to do something like that in python, is a challenge left to the
>>user
>
> Such a use of macros is frowned upon by most C programmers,
> because it renders the code unreadable.

I remember engineering manager I worked with about 35 years ago who
used a set of C macros to try to make his code look as much like BASIC
as possible:

#define IF if (
#define THEN ) {
#define ELSE } else {
#define ENDIF }
...

IIRC he copied them out of a magazine article.

He then proceeded to try to implement a tree search algorithm (he
didn't actually know that's what he was doing) using his new
"language" without using recursion (which he had never heard of and
couldn't grok) by keeping track of state using an array. It did not go
well and made him a bit of a laughingstock. IIRC, he had first tried
to write it in actual BASIC, but gave up on that before switching to C
and his ridiculous macro set.


--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On Tue, 07 Sep 2021 14:53:29 +0000, Grant Edwards wrote:

> On 2021-09-06, Stefan Ram <ram@zedat.fu-berlin.de> wrote:
>> "Avi Gross" <avigross@verizon.net> writes:
>>> In languages like C/C++ there are people who make up macros like:
>>>#define INDEFINITELY_LOOP while (true)
>>>Or something like that and then allow the preprocessor to replace
>>>INDEFINITELY_LOOP with valid C code.
>>
>> Those usually are beginners.
>>
>>>So, how to do something like that in python, is a challenge left to the
>>>user
>>
>> Such a use of macros is frowned upon by most C programmers,
>> because it renders the code unreadable.
>
> I remember engineering manager I worked with about 35 years ago who used
> a set of C macros to try to make his code look as much like BASIC as
> possible:
>
> #define IF if ( #define THEN ) { #define ELSE } else {
> #define ENDIF }
> ...
>
> IIRC he copied them out of a magazine article.
>
> He then proceeded to try to implement a tree search algorithm (he didn't
> actually know that's what he was doing) using his new "language" without
> using recursion (which he had never heard of and couldn't grok) by
> keeping track of state using an array. It did not go well and made him a
> bit of a laughingstock. IIRC, he had first tried to write it in actual
> BASIC, but gave up on that before switching to C and his ridiculous
> macro set.

1 Simple rule, if you are programming in language 'a' then write Language
'a' Code it.

Just because you can do something doesn't mean you should


--
Help! I'm trapped in a Chinese computer factory!
--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
Grant Edwards <grant.b.edwards@gmail.com> writes:

> On 2021-09-06, Stefan Ram <ram@zedat.fu-berlin.de> wrote:
>> "Avi Gross" <avigross@verizon.net> writes:
>>> In languages like C/C++ there are people who make up macros like:
>>>#define INDEFINITELY_LOOP while (true)
>>>Or something like that and then allow the preprocessor to replace
>>>INDEFINITELY_LOOP with valid C code.
>>
>> Those usually are beginners.

[...]

>> Such a use of macros is frowned upon by most C programmers,
>> because it renders the code unreadable.
>
> I remember engineering manager I worked with about 35 years ago who
> used a set of C macros to try to make his code look as much like BASIC
> as possible:
>
> #define IF if (
> #define THEN ) {
> #define ELSE } else {
> #define ENDIF }
> ...
>
> IIRC he copied them out of a magazine article.
>
> He then proceeded to try to implement a tree search algorithm (he
> didn't actually know that's what he was doing) using his new
> "language" without using recursion (which he had never heard of and
> couldn't grok) by keeping track of state using an array. It did not go
> well and made him a bit of a laughingstock. IIRC, he had first tried
> to write it in actual BASIC, but gave up on that before switching to C
> and his ridiculous macro set.

LOL! (Had fun reading this.)
--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On Tue, 7 Sep 2021 16:08:04 +1200, Greg Ewing <greg.ewing@canterbury.ac.nz>
declaimed the following:

>On 7/09/21 11:38 am, Avi Gross wrote:
>
>> #define INDEFINITELY_LOOP while (true)
>>
>> So, how to do something like that in python, is a challenge left to the user ?
>
>def hell_frozen_over():
> return False
>
>while not hell_frozen_over():
> ....

Hell typically freezes every January (scroll down to monthly average):
https://www.worldweatheronline.com/hell-weather-averages/michigan/us.aspx


--
Wulfraed Dennis Lee Bieber AF6VN
wlfraed@ix.netcom.com http://wlfraed.microdiversity.freeddns.org/

--
https://mail.python.org/mailman/listinfo/python-list
RE: on writing a while loop for rolling two dice [ In reply to ]
Although I sort of agree with Alister, I also note that many languages
deliberately provide you with the means to customize in ways that make your
personal life more amenable while making it perhaps harder for others.

Consider the humble import statement frequently used as:

import numpy as np
import pandas as pd

The above is perfectly legal and in some circles is expected. But I suspect
many people do not care about being able to type a slightly abbreviated
np.name(..) rather than numpy.name(...) and yet others import specific
functions from a package like:

from numpy import arrange

The bottom line is that there are many ways the same code can be called,
including quite a few other variations I am not describing. People can
customize their code in many ways including making it look more like the way
they might program in some other computer language/environment. Anyone
reading their code with a different viewpoint may have some adjustment
issues.

I am wondering if anyone has written programs that would take some complete
body of code and not prettify it or reformat it as some tools do, but sort
of make it into a standard format. In the above example, it might undo
things like renaming numpy to np and change all the code that looks like
np.name to numpy.name and similarly changes any function imported directly
to also be fully qualified.

Of course, some code I have seen changes things mid-stream or has some if
statement that sets one of several function calls to be the one to use
beyond that point.

So, I am not sanguine on trying to enforce some standards to make your code
easy to read by others and am more a fan of suggesting enough comments in
the code to guide anyone on your own idiosyncratic uses.


-----Original Message-----
From: Python-list <python-list-bounces+avigross=verizon.net@python.org> On
Behalf Of alister via Python-list
Sent: Tuesday, September 7, 2021 2:58 PM
To: python-list@python.org
Subject: Re: on writing a while loop for rolling two dice

On Tue, 07 Sep 2021 14:53:29 +0000, Grant Edwards wrote:

> On 2021-09-06, Stefan Ram <ram@zedat.fu-berlin.de> wrote:
>> "Avi Gross" <avigross@verizon.net> writes:
>>> In languages like C/C++ there are people who make up macros like:
>>>#define INDEFINITELY_LOOP while (true) Or something like that and
>>>then allow the preprocessor to replace INDEFINITELY_LOOP with valid C
>>>code.
>>
>> Those usually are beginners.
>>
>>>So, how to do something like that in python, is a challenge left to
>>>the user
>>
>> Such a use of macros is frowned upon by most C programmers,
>> because it renders the code unreadable.
>
> I remember engineering manager I worked with about 35 years ago who
> used a set of C macros to try to make his code look as much like BASIC
> as
> possible:
>
> #define IF if ( #define THEN ) { #define ELSE } else {
> #define ENDIF }
> ...
>
> IIRC he copied them out of a magazine article.
>
> He then proceeded to try to implement a tree search algorithm (he
> didn't actually know that's what he was doing) using his new
> "language" without using recursion (which he had never heard of and
> couldn't grok) by keeping track of state using an array. It did not go
> well and made him a bit of a laughingstock. IIRC, he had first tried
> to write it in actual BASIC, but gave up on that before switching to C
> and his ridiculous macro set.

1 Simple rule, if you are programming in language 'a' then write Language
'a' Code it.

Just because you can do something doesn't mean you should


--
Help! I'm trapped in a Chinese computer factory!
--
https://mail.python.org/mailman/listinfo/python-list

--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On 07/09/2021 15:53, Grant Edwards wrote:

> I remember engineering manager I worked with about 35 years ago who
> used a set of C macros to try to make his code look as much like BASIC
> as possible:
>
> #define IF if (
> #define THEN ) {
> #define ELSE } else {
> #define ENDIF }
> ...
>
> IIRC he copied them out of a magazine article.

That was quite common in C before it became popular(early/mid 80s).
I've seen Pascal, Algol and Coral macro sets in use.
You could even download pre-written ones from various
bulletin boards (remember them?!) for a while.

--
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On 8/09/21 2:53 am, Grant Edwards wrote:
> #define IF if (
> #define THEN ) {
> #define ELSE } else {
> #define ENDIF }
> ...

I gather that early versions of some of the Unix utilities were
written by someone who liked using macros to make C resemble Algol.

I guess you can get away with that sort of thing if you're a
Really Smart Person.

--
Greg
--
https://mail.python.org/mailman/listinfo/python-list
RE: on writing a while loop for rolling two dice [ In reply to ]
Greg,

Yes, a smart person may come up with such tricks but a really smart person,
in my view, adjusts. With some exceptions, such as when trying to port
existing code to a new language quickly, someone who is not too obsessive
will try to pick up the goals and spirit of a new language and use them when
it seems reasonable. And, a smart person, if they see nothing new, might
just go back to their old language or ...

Pick a language that easily supports regular expressions and object creation
and functional programming and so on, like python, and ask why you might
want to use it to simulate a really old version of BASIC when you can just
use BASIC.

Admittedly, most people are not flexible. I find that with human languages
too that some learn another language just enough to recognize words but not
to use the changed grammar or the different idioms and never become fluent.

I am amused though at the fact that python, by using indentation rather than
things like curly braces, would make some of the games like shown below
quite a bit more difficult.

-----Original Message-----
From: Python-list <python-list-bounces+avigross=verizon.net@python.org> On
Behalf Of Greg Ewing
Sent: Tuesday, September 7, 2021 9:08 PM
To: python-list@python.org
Subject: Re: on writing a while loop for rolling two dice

On 8/09/21 2:53 am, Grant Edwards wrote:
> #define IF if (
> #define THEN ) {
> #define ELSE } else {
> #define ENDIF }
> ...

I gather that early versions of some of the Unix utilities were written by
someone who liked using macros to make C resemble Algol.

I guess you can get away with that sort of thing if you're a Really Smart
Person.

--
Greg
--
https://mail.python.org/mailman/listinfo/python-list

--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On 9/7/21 3:51 PM, Avi Gross via Python-list wrote:
> and similarly changes any function imported directly
> to also be fully qualified.

One danger with this is that it can actual change the behavior of the
program. Maybe more likely with global objects than functions, but still
an issue.

Remember, "from module import fun" will bind the name fun in this
modules namespace to the current definiton of the object fun in the
other modules name space. If after that point, something rebinds the
name in the other module, the module that did the from import won't see
that change, but if the reference is changed to module.fun, it will.

Since that rebinding might even be some third module doing a 'monkey
patch', detecting if it is safe is basically impossible.

Admittedly, if this is an issue, the sensitivity to timing makes the
difference something very fussy to exactly the order you do things, the
cases where the difference is intended is likely fairly small.

--
Richard Damon

--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On 9/7/2021 9:20 PM, Avi Gross wrote:
> Greg,
>
> Yes, a smart person may come up with such tricks but a really smart person,
> in my view, adjusts. With some exceptions, such as when trying to port
> existing code to a new language quickly, someone who is not too obsessive
> will try to pick up the goals and spirit of a new language and use them when
> it seems reasonable. And, a smart person, if they see nothing new, might
> just go back to their old language or ...
>
> Pick a language that easily supports regular expressions and object creation
> and functional programming and so on, like python, and ask why you might
> want to use it to simulate a really old version of BASIC when you can just
> use BASIC.
>
> Admittedly, most people are not flexible. I find that with human languages
> too that some learn another language just enough to recognize words but not
> to use the changed grammar or the different idioms and never become fluent.
>
> I am amused though at the fact that python, by using indentation rather than
> things like curly braces, would make some of the games like shown below
> quite a bit more difficult.
>
> -----Original Message-----
> From: Python-list <python-list-bounces+avigross=verizon.net@python.org> On
> Behalf Of Greg Ewing
> Sent: Tuesday, September 7, 2021 9:08 PM
> To: python-list@python.org
> Subject: Re: on writing a while loop for rolling two dice
>
> On 8/09/21 2:53 am, Grant Edwards wrote:
>> #define IF if (
>> #define THEN ) {
>> #define ELSE } else {
>> #define ENDIF }
>> ...
>
> I gather that early versions of some of the Unix utilities were written by
> someone who liked using macros to make C resemble Algol.
>
> I guess you can get away with that sort of thing if you're a Really Smart
> Person.
>
> --
> Greg
> --
> https://mail.python.org/mailman/listinfo/python-list
>

So what do yoy think or feel about a language like RATFOR (Rational
FORTRAN) which was implemented as macros? Should they instead have
simply adapted themselves to FORTRAN?
--
https://mail.python.org/mailman/listinfo/python-list
RE: on writing a while loop for rolling two dice [ In reply to ]
I think I already agreed with much of your point. That is indeed the
problem. You are allowed to do some possibly non-standard things. A static
evaluation/replacement may show the wrong function being called and a
dynamic one may still mess up as there are many ways to do indirection.

I mention this partially because of a recent discussion on another computer
where the question was why they got an error message that the object being
given a function was not a data.frame or something compatible. What was
being passed was a data structure meant to hold some simulation of an EXCEL
spreadsheet. Not quite the same. But they insisted it had to be a data.frame
because they called functionA() and it is documented to return a data.frame.


It turned out that they had loaded lots of packages (modules but not) and
had not paid attention when they got a message that one function called
functionA was now being covered by another with the same name. Each such
package loaded often gets a new namespace/environment and when searching for
a function by name, the new package was ahead of the older package, hence
the warning.

So one solution was to change his code in one of several ways, but more
generally to call any functions that may be hidden this way in a fully
qualified manner as in packageA::functionA(...) do you do not accidentally
get package::functionA(...)

Now note this is not so much a bug as a feature in that language and It is
quite common to sort of redefine a function name to do what you want.

But if you have developed your own package and want to guarantee the user
does not undo your work in specific cases, you should also call some things
as explicitly within your own namespace.

Back to Python, it is a tad too flexible in some places and my point was
that it would be interesting, along the lines of a linter, to have some
tools that help explain what the program might be doing a tad more
explicitly. But as an interpreted language, so much can happen at runtime
that this may not be very effective or accurate. The language is full of
places where slipping in another object means you over-rode the meaning of
+= for instance.

-----Original Message-----
From: Python-list <python-list-bounces+avigross=verizon.net@python.org> On
Behalf Of Richard Damon
Sent: Tuesday, September 7, 2021 10:09 PM
To: python-list@python.org
Subject: Re: on writing a while loop for rolling two dice

On 9/7/21 3:51 PM, Avi Gross via Python-list wrote:
> and similarly changes any function imported directly to also be fully
> qualified.

One danger with this is that it can actual change the behavior of the
program. Maybe more likely with global objects than functions, but still an
issue.

Remember, "from module import fun" will bind the name fun in this modules
namespace to the current definiton of the object fun in the other modules
name space. If after that point, something rebinds the name in the other
module, the module that did the from import won't see that change, but if
the reference is changed to module.fun, it will.

Since that rebinding might even be some third module doing a 'monkey patch',
detecting if it is safe is basically impossible.

Admittedly, if this is an issue, the sensitivity to timing makes the
difference something very fussy to exactly the order you do things, the
cases where the difference is intended is likely fairly small.

--
Richard Damon

--
https://mail.python.org/mailman/listinfo/python-list

--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On 2021-09-08, charles hottel <chottel@earthlink.net> wrote:

> So what do yoy think or feel about a language like RATFOR (Rational
> FORTRAN) which was implemented as macros? Should they instead have
> simply adapted themselves to FORTRAN?

That's an interesting question. If the langauge is complete,
well-defined, and well-documented then it's not that much different
than any other source language than gets translated into a lower level
language (e.g. C -> assembly). My recollection of RATFOR was that it
provided enough signifcant "features" that weren't available in the
underlying FORTRAN to make it worthwhile.

That seems to me to be qualitatively different than a set of macros
that simply make one language look (somewhat) like a different
language with a similar level of abstraction -- without providing
anything other than cosmetic changes.

--
Grant

--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On 2021-09-08, charles hottel <chottel@earthlink.net> wrote:

> So what do yoy think or feel about a language like RATFOR (Rational
> FORTRAN) which was implemented as macros?

The RATFOR implementations I've seen weren't done using macros. It was
a preprocessor, yes. But it generates code for the various structured
statement types (while, for, if/then/else) and source structures
(open/close brace) the way a compiler does, even though the generated
code is FORTRAN66 rather than assembly or bytecode or whatever.

> Should they instead have simply adapted themselves to FORTRAN?


--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On Wed, 8 Sep 2021 00:24:44 +0100, Alan Gauld via Python-list
<python-list@python.org> declaimed the following:

>
>That was quite common in C before it became popular(early/mid 80s).
>I've seen Pascal, Algol and Coral macro sets in use.
>You could even download pre-written ones from various
>bulletin boards (remember them?!) for a while.

And if one wants to expose themselves to real horror -- look at the
output of one of those "structured FORTRAN" preprocessors (RATFOR, TEXTFOR,
others) that were cropping up in the late 70s to generate FORTRAN-IV from
code written with block IF, WHILE, etc.

I spent close to 20 years (80s-90s) maintaining the /output/ of such a
preprocessor. The software had apparently originated with a sub-contractor,
and we did not have access to their preprocessor (and/or no one ported it
to the VAX-11 from PDP-11).

At first my practice was to study a file in detail, and then rewrite it
using F77 with separately compiled subroutines (the preprocessor was "one
file per program" and implemented BASIC-style GOSUB, relying on shared
variables and ASSIGNed GOTO for the return address -- I had to move the
shared variables to COMMON blocks to make separate subroutines usable).

By the end of those decades, I'd been exposed to the preprocessor
enough to hand-write smaller patches within its style. The only good thing
is that is left the structured source as comments, and tended to
right-justify the F-IV output, so easy to locate...



--
Wulfraed Dennis Lee Bieber AF6VN
wlfraed@ix.netcom.com http://wlfraed.microdiversity.freeddns.org/

--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On 2021-09-08, Dennis Lee Bieber <wlfraed@ix.netcom.com> wrote:

> I spent close to 20 years (80s-90s) maintaining the /output/ of such
> a preprocessor.

Ouch. I hope it paid well. ;)

Back when I did a lot of TeX/LaTeX stuff on VMS, I used to make
occasional fixes and add (very minor) features to one of the dvi
handling executables (I don't remember if it was the VT2xx previewer,
or the laser-printer "driver") using the VMS "PATCH" utility. I also
can't remember how we ended up without source code for that piece of
the toolchain when we build all of the reset of it from source.

> The software had apparently originated with a sub-contractor, and we
> did not have access to their preprocessor

Allowing that to happen is definitely a major management F*%k-up for
which somebody should have had their career ended.

> (and/or no one ported it to the VAX-11 from PDP-11).

I would have though that would have been pretty trivial compared to
maintaining the output source for 20 years.

--
Grant




--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On Wed, 8 Sep 2021 14:46:28 -0000 (UTC), Grant Edwards
<grant.b.edwards@gmail.com> declaimed the following:

>On 2021-09-08, charles hottel <chottel@earthlink.net> wrote:
>
>> So what do yoy think or feel about a language like RATFOR (Rational
>> FORTRAN) which was implemented as macros? Should they instead have
>> simply adapted themselves to FORTRAN?
>
>That's an interesting question. If the langauge is complete,
>well-defined, and well-documented then it's not that much different
>than any other source language than gets translated into a lower level
>language (e.g. C -> assembly). My recollection of RATFOR was that it
>provided enough signifcant "features" that weren't available in the
>underlying FORTRAN to make it worthwhile.
>

Primarily providing block structured IF/ELSE and loops -- in a language
that only really provided IF/GOTO...

My college tried using one of these (for some reason the name TextFOR
sticks with me)... The experiment only lasted one term. The preprocessor
ate CPU and I/O time -- with the result that the FORTRAN class used two or
three times the times of the COBOL class! (The native compilers were
designed as re-entrant, allowing multiple compiles to share one in-core
image; the preprocessor no doubt ran as one image per compile, triggering
lots of page swapping to disk)


--
Wulfraed Dennis Lee Bieber AF6VN
wlfraed@ix.netcom.com http://wlfraed.microdiversity.freeddns.org/

--
https://mail.python.org/mailman/listinfo/python-list
RE: on writing a while loop for rolling two dice [ In reply to ]
Charles,

This forum is for python discussions so I will clarify that there is nothing
wrong with making up a new language, including by bootstrapping an old
language. But why not call it new and do not try to confuse people using the
old.

Python has grown and added much over the years and even had a fairly
negative experience in a transition from versions 2 to 3 as some people
complain their old software no longer works.

If you look at a language like C which was remade into C++, guess what? It
has a new name and makes no claims to be fully compatible.

If RATFOR was a more pleasant programming environment for some people and
purposes, fine.

I note Python has many modules that for some people become the most used
parts even when the base language might allow some similar functionality.
Someone who learns python but has never experienced those, may feel a bit
lost. And you can customize Python to a point where it does things in fairly
hidden ways too. There are no promises of purity.

What this particular discussion began with was much lower level and about
various ways of writing a while loop within very basic Python and seems to
be heading away into discussions of other languages. I happen to enjoy
learning and contrasting lots of languages but doubt many others do and most
people want to learn just a few good tools and use them to get their job
done. My point was if you have a tool you like and you try another you
don't, then rather than trying to force the new one, just use what works and
leave others that like it alone. Make your own religion and let others keep
theirs.

However, improvements and increased functionality may be more welcome, than
examples where the interface was changed with no benefits.

-----Original Message-----
From: Python-list <python-list-bounces+avigross=verizon.net@python.org> On
Behalf Of charles hottel
Sent: Tuesday, September 7, 2021 11:31 PM
To: python-list@python.org
Subject: Re: on writing a while loop for rolling two dice

<SNIP>

So what do yoy think or feel about a language like RATFOR (Rational
FORTRAN) which was implemented as macros? Should they instead have simply
adapted themselves to FORTRAN?
--
https://mail.python.org/mailman/listinfo/python-list

--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On Wed, 8 Sep 2021 16:32:45 -0000 (UTC), Grant Edwards
<grant.b.edwards@gmail.com> declaimed the following:

>On 2021-09-08, Dennis Lee Bieber <wlfraed@ix.netcom.com> wrote:
>
>> I spent close to 20 years (80s-90s) maintaining the /output/ of such
>> a preprocessor.
>
>Ouch. I hope it paid well. ;)

Only if one ignores the bloody cost of apartments (given the rent paid
over the 30 years I spent in that 1BR 680sq.ft. unit I should have owned
it, if not half the facility <G>)
>
>> The software had apparently originated with a sub-contractor, and we
>> did not have access to their preprocessor
>
>Allowing that to happen is definitely a major management F*%k-up for
>which somebody should have had their career ended.
>
For all I know, someone might have... Back when the application was
running on PDP-11 (I joined the program early 80s, when the "mission
planning" software was being ported to the VAX-11).

Most of the "mission planning" software was local-grown, so was DEC
FORTRAN (may have started as F-IV, and developed F77 during maintenance and
the porting to the VAX). Not the part I maintained -- which drove a Ramtek
9300 graphics engine (only one engine could be installed into a VAX, it was
that archaic). It got to the point where I think Ramtek service was
recycling the parts when ever we had a service call. Eventually I proposed
that a VAXstation (DECWindows) and GKS could replace most of the display
side. We weren't approved to rewrite the application to directly display --
but rewriting the Ramtek library to send the plotting data to a separate
program, which managed the display window, was in the budget.

>
>I would have though that would have been pretty trivial compared to
>maintaining the output source for 20 years.

I'm not so sure -- that "one file per executable" would have led to
long compile times (first for the preprocessor, then for the generated F-IV
output), vs my rewrites into multiple files, where only isolated changes
needed to be recompiled.

Humorously, the graphics application suite was known as "MESS" (I can't
go deeper into the acronym without violating security classification).


--
Wulfraed Dennis Lee Bieber AF6VN
wlfraed@ix.netcom.com http://wlfraed.microdiversity.freeddns.org/

--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On 31/08/2021 01.50, Chris Angelico wrote:
> On Mon, Aug 30, 2021 at 11:13 PM David Raymond <David.Raymond@tomtom.com> wrote:
>>
>>> def how_many_times():
>>> x, y = 0, 1
>>> c = 0
>>> while x != y:
>>> c = c + 1
>>> x, y = roll()
>>> return c, (x, y)
>>
>> Since I haven't seen it used in answers yet, here's another option using our new walrus operator
>>
>> def how_many_times():
>> roll_count = 1
>> while (rolls := roll())[0] != rolls[1]:
>> roll_count += 1
>> return (roll_count, rolls)
>>
>
> Since we're creating solutions that use features in completely
> unnecessary ways, here's a version that uses collections.Counter:
>
> def how_many_times():
> return next((count, rolls) for count, rolls in
> enumerate(iter(roll, None)) if len(Counter(rolls)) == 1)
>
> Do I get bonus points for it being a one-liner that doesn't fit in
> eighty characters?


Herewith my claim to one-liner fame (assuming such leads in any way to
virtue or fame)

It retains @Peter's preference for a more re-usable roll_die() which
returns a single event, cf the OP's roll() which returns two results).


import itertools, random

def roll_die():
while True:
yield random.randrange(1, 7)

def how_many_times():
return list( itertools.takewhile( lambda r:r[ 0 ] != r[ 1 ],
zip( roll_die(), roll_die() )
)
)

Also, a claim for 'bonus points' because the one-liner will fit within
80-characters - if only I didn't have that pernicious and vile habit of
coding a more readable layout.

It doesn't use a two-arg iter, but still rates because it does use a
relatively-obscure member of the itertools library...


https://docs.python.org/3.8/library/itertools.html#itertools.takewhile
--
Regards,
=dn
--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On Sat, Sep 11, 2021 at 3:26 PM dn via Python-list
<python-list@python.org> wrote:
>
> On 31/08/2021 01.50, Chris Angelico wrote:
> > On Mon, Aug 30, 2021 at 11:13 PM David Raymond <David.Raymond@tomtom.com> wrote:
> >>
> >>> def how_many_times():
> >>> x, y = 0, 1
> >>> c = 0
> >>> while x != y:
> >>> c = c + 1
> >>> x, y = roll()
> >>> return c, (x, y)
> >>
> >> Since I haven't seen it used in answers yet, here's another option using our new walrus operator
> >>
> >> def how_many_times():
> >> roll_count = 1
> >> while (rolls := roll())[0] != rolls[1]:
> >> roll_count += 1
> >> return (roll_count, rolls)
> >>
> >
> > Since we're creating solutions that use features in completely
> > unnecessary ways, here's a version that uses collections.Counter:
> >
> > def how_many_times():
> > return next((count, rolls) for count, rolls in
> > enumerate(iter(roll, None)) if len(Counter(rolls)) == 1)
> >
> > Do I get bonus points for it being a one-liner that doesn't fit in
> > eighty characters?
>
>
> Herewith my claim to one-liner fame (assuming such leads in any way to
> virtue or fame)
>
> It retains @Peter's preference for a more re-usable roll_die() which
> returns a single event, cf the OP's roll() which returns two results).
>
>
> import itertools, random
>
> def roll_die():
> while True:
> yield random.randrange(1, 7)
>
> def how_many_times():
> return list( itertools.takewhile( lambda r:r[ 0 ] != r[ 1 ],
> zip( roll_die(), roll_die() )
> )
> )
>
> Also, a claim for 'bonus points' because the one-liner will fit within
> 80-characters - if only I didn't have that pernicious and vile habit of
> coding a more readable layout.
>
> It doesn't use a two-arg iter, but still rates because it does use a
> relatively-obscure member of the itertools library...
>

Nice, but that's only going to give you the ones that don't match. You
can then count those, and that's a start, but how do you capture the
matching rolls?

I smell another opportunity for gratuitous use of a language feature:
nonlocal. In a lambda function. Which may require shenanigans of epic
proportions.

ChrisA
--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On 11/09/2021 18.03, Chris Angelico wrote:
> On Sat, Sep 11, 2021 at 3:26 PM dn via Python-list
> <python-list@python.org> wrote:
>>
>> On 31/08/2021 01.50, Chris Angelico wrote:
>>> On Mon, Aug 30, 2021 at 11:13 PM David Raymond <David.Raymond@tomtom.com> wrote:
>>>>
>>>>> def how_many_times():
>>>>> x, y = 0, 1
>>>>> c = 0
>>>>> while x != y:
>>>>> c = c + 1
>>>>> x, y = roll()
>>>>> return c, (x, y)
>>>>
>>>> Since I haven't seen it used in answers yet, here's another option using our new walrus operator
>>>>
>>>> def how_many_times():
>>>> roll_count = 1
>>>> while (rolls := roll())[0] != rolls[1]:
>>>> roll_count += 1
>>>> return (roll_count, rolls)
>>>>
>>>
>>> Since we're creating solutions that use features in completely
>>> unnecessary ways, here's a version that uses collections.Counter:
>>>
>>> def how_many_times():
>>> return next((count, rolls) for count, rolls in
>>> enumerate(iter(roll, None)) if len(Counter(rolls)) == 1)
>>>
>>> Do I get bonus points for it being a one-liner that doesn't fit in
>>> eighty characters?
>>
>>
>> Herewith my claim to one-liner fame (assuming such leads in any way to
>> virtue or fame)
>>
>> It retains @Peter's preference for a more re-usable roll_die() which
>> returns a single event, cf the OP's roll() which returns two results).
>>
>>
>> import itertools, random
>>
>> def roll_die():
>> while True:
>> yield random.randrange(1, 7)
>>
>> def how_many_times():
>> return list( itertools.takewhile( lambda r:r[ 0 ] != r[ 1 ],
>> zip( roll_die(), roll_die() )
>> )
>> )
>>
>> Also, a claim for 'bonus points' because the one-liner will fit within
>> 80-characters - if only I didn't have that pernicious and vile habit of
>> coding a more readable layout.
>>
>> It doesn't use a two-arg iter, but still rates because it does use a
>> relatively-obscure member of the itertools library...
>>
>
> Nice, but that's only going to give you the ones that don't match. You
> can then count those, and that's a start, but how do you capture the
> matching rolls?
>
> I smell another opportunity for gratuitous use of a language feature:
> nonlocal. In a lambda function. Which may require shenanigans of epic
> proportions.


The stated requirement is: "I'd like to get the number of times I
tried". Given such: why bother with returning any of the pairs of values?

Further, if you look at the OP's original solution, it only publishes
the last pair, ie the match, without mention of the list of non-matches.
Was it perhaps only a means of testing the solution?

Regret that I'll settle for (or continue to seek) 'fame'. I don't play
guitar, so have no use for epic.
--
Regards,
=dn
--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On 11/09/2021 10:09, dn via Python-list wrote:
>
>
>
> The stated requirement is: "I'd like to get the number of times I
> tried". Given such: why bother with returning any of the pairs of values?

Indeed, if that's the requirement, then you can do even better, noting
that the probability of getting a matched pair is 1/6 (6 matches out of
6*6 possibilities). So the answer to the problem is exactly the same as
rolling a single die until you get any particular number (e.g., 1).

This is somewhat easier to simulate than the two-dice problem (and the
number of throws until a match is also a known, analytic distribution
that you could sample from, but this is probably easier).


--
https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice [ In reply to ]
On 2021-09-08 13:07:47 +1200, Greg Ewing wrote:
> On 8/09/21 2:53 am, Grant Edwards wrote:
> > #define IF if (
> > #define THEN ) {
> > #define ELSE } else {
> > #define ENDIF }
>
> I gather that early versions of some of the Unix utilities were
> written by someone who liked using macros to make C resemble Algol.

Steve Bourne, the author of the eponymous shell.

hp

--
_ | Peter J. Holzer | Story must make more sense than reality.
|_|_) | |
| | | hjp@hjp.at | -- Charles Stross, "Creative writing
__/ | http://www.hjp.at/ | challenge!"
Re: on writing a while loop for rolling two dice [ In reply to ]
dn <PythonList@DancesWithMice.info> writes:

[...]

> Further, if you look at the OP's original solution, it only publishes
> the last pair, ie the match, without mention of the list of non-matches.
> Was it perhaps only a means of testing the solution?

It was a means of showing the student that indeed they obtained a match.
If the exercise asked for returning a single die or no die at all, they
would make mistakes and there'd be no sign of them being wrong. For
instance, one trouble a lot of them went through was to start counting
from zero and so their number of rolls was off by one. (I didn't see
that coming!) The reason they fall for this is that they also test
little --- for some it never occurred a match on the first roll, so they
never saw the zero counter coming out.
--
https://mail.python.org/mailman/listinfo/python-list