• zpsoli - Solitaire/Patience card game

    From Russell Marks@21:1/5 to All on Tue Jun 15 13:22:50 2021
    Maybe it's a bit of a stretch to be posting this, but presumably not
    many games are written in awk so I thought I might as well. :-)

    zpsoli is a one-player Solitaire/Patience card game in awk. By default
    it uses VT100 control codes, but it also has optional generic output.
    The standard version requires a new awk - there's also an old-awk
    version which should run on almost everything, including V7 awk.

    It's available here:

    https://zgedneil.nfshost.com/zpsoli.html

    -Rus.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ben Bacarisse@21:1/5 to Russell Marks on Tue Jun 15 15:20:41 2021
    Russell Marks <zgedneil@spam^H^H^H^Hgmail.com> writes:

    Maybe it's a bit of a stretch to be posting this, but presumably not
    many games are written in awk so I thought I might as well. :-)

    Don't worry, the group is not overwhelmed by posts!

    zpsoli is a one-player Solitaire/Patience card game in awk. By default
    it uses VT100 control codes, but it also has optional generic output.
    The standard version requires a new awk - there's also an old-awk
    version which should run on almost everything, including V7 awk.

    It's available here:

    https://zgedneil.nfshost.com/zpsoli.html

    Nice. I'm tempted to ask why here, but then why not?

    I won't offer a code review, but you could make the play a little
    simpler if a single digit was permitted as an abbreviation. The
    simplest being that X means dX, but it could also mean Xa or one of
    [1-7]X or X[1-7] provided the move is unique.

    --
    Ben.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Russell Marks on Tue Jun 15 17:25:46 2021
    On 15.06.2021 15:22, Russell Marks wrote:
    Maybe it's a bit of a stretch to be posting this, but presumably not
    many games are written in awk so I thought I might as well. :-)

    zpsoli is a one-player Solitaire/Patience card game in awk. By default
    it uses VT100 control codes, but it also has optional generic output.
    The standard version requires a new awk - there's also an old-awk
    version which should run on almost everything, including V7 awk.

    It's available here:

    https://zgedneil.nfshost.com/zpsoli.html

    Nice.

    One thing that I find inconvenient is when typing e.g. '1d' (i.e. an
    illegal input); then you're getting a couple lines of warning messages
    and - tempted to get rid of them and a fresh screen layout - hitting
    <Enter> will draw a new card. - I think it would be more convenient to
    just ignore that (illegal) move as done with other ineffective inputs.

    Locating the deck to the left (with some more space to separate it and distinguish it from the other seven heaps) might alleviate the display
    issue you mention (and also the issue I mentioned above).

    And one could homogenize the input syntax to numbers (with d realized
    by number 0); but that's just a matter of taste. (Probably depends on
    whether the existence of a(ce) as target is crucial.)

    I'm also unsure why the %% besides the deck vanish occasionally; but I
    haven't read the docs, maybe it's described? Also unclear to me is the intention of the two .. lines below the stacks.

    A quick look into the source code made me wonder why you documented availabilities of system() while it's not used in the code (I checked
    use of that function to get some insights about possible side effects); probably part of an old portability consideration/documentation?

    Code that appears a bit strange (to me) is e.g. where you use float
    numbers in int contexts like the modulo calculation. And specifically
    the intention of using -1 to shift the number to the range -1..+65335.

    It's probably unnecessary to disallow blank characters in front of the
    new and restart commands (while at the same time allowing "newbie" as
    valid input for "new"). (Same with quit and exit.)

    Terminating an array explicitly with an empty "" value and testing it
    with newdeck[srcnum]!="" (instead of srcnum in newdeck ) might not
    be necessary.

    Since card strings are equal length and operations mainly done at the
    end (or up to the end) of a pile one might consider implementing the
    stacks as strings, it might simplify the card stack manipulations.

    Just a few thoughts.

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Russell Marks@21:1/5 to Janis Papanagnou on Tue Jun 15 18:00:19 2021
    Janis Papanagnou <janis_papanagnou@hotmail.com> wrote:

    On 15.06.2021 15:22, Russell Marks wrote:
    Maybe it's a bit of a stretch to be posting this, but presumably not
    many games are written in awk so I thought I might as well. :-)

    zpsoli is a one-player Solitaire/Patience card game in awk. By default
    it uses VT100 control codes, but it also has optional generic output.
    The standard version requires a new awk - there's also an old-awk
    version which should run on almost everything, including V7 awk.

    It's available here:

    https://zgedneil.nfshost.com/zpsoli.html

    Nice.

    One thing that I find inconvenient is when typing e.g. '1d' (i.e. an
    illegal input); then you're getting a couple lines of warning messages
    and - tempted to get rid of them and a fresh screen layout - hitting
    <Enter> will draw a new card. - I think it would be more convenient to
    just ignore that (illegal) move as done with other ineffective inputs.

    That's a tricky one, I suppose you could argue it both ways. You can
    use "r" (redraw) to avoid drawing a card of course, but I know it's
    not the most intuitive thing ever.

    Locating the deck to the left (with some more space to separate it and distinguish it from the other seven heaps) might alleviate the display
    issue you mention (and also the issue I mentioned above).

    I might be misusing terminology, I'm not sure. On the left are the
    main grouping of face-down cards (potentially not-yet-seen), and just
    to the right of that is a pile of face-up cards that were turned over
    from the top of that.

    (I know the game messes about with the representation of the latter
    pile so that all but the last card dealt are generally kept in a
    face-down state, but from the player's perspective they're all meant
    to be face-up.)

    And one could homogenize the input syntax to numbers (with d realized
    by number 0); but that's just a matter of taste. (Probably depends on
    whether the existence of a(ce) as target is crucial.)

    Having the moves be purely numeric has an appeal, but I think I prefer
    the existing approach.

    I'm also unsure why the %% besides the deck vanish occasionally; but I haven't read the docs, maybe it's described? Also unclear to me is the intention of the two .. lines below the stacks.

    Leftmost is what I would call the deck, to the right of that is a pile
    of turned-over cards from that deck. As cards are moved back and forth
    one or both of the piles can be emptied.

    ".." is to represent the rest of the visible card area, because ASCII
    is just wonderful for drawing cards in a 2x3 space. :-)

    A quick look into the source code made me wonder why you documented availabilities of system() while it's not used in the code (I checked
    use of that function to get some insights about possible side effects); probably part of an old portability consideration/documentation?

    That table is almost entirely documenting what I couldn't use due to
    allowing the use of old awk, since the old-awk version is extremely
    similar and built from the same file.

    The reason system() might have helped - with that and some assumptions (requiring "tput" perhaps), I could have more supported more than just
    VT100 and generic terminals. Well, I could have anyway, but then you
    just end up writing termcap/terminfo again.

    Code that appears a bit strange (to me) is e.g. where you use float
    numbers in int contexts like the modulo calculation. And specifically
    the intention of using -1 to shift the number to the range -1..+65335.

    In rndseed the range is 0..65535, converted to 1..65536 when
    calculating the new seed value for the RNG. Obviously you don't want
    to multiply by zero. :-) It's true that the seed could have been left
    as non-zero, but that would have made it slightly harder to construct
    the rand()-like random number - you'd end up doing much the same
    either way.

    Funnily enough, in a way you could argue this isn't really an int
    context. Quite apart from awk itself being so keen on floating-point
    AIUI, the Spectrum's ROM did all the RNG maths using FP. In software.
    On a Z80. It wasn't fast.

    Actually writing e.g. "65537." is useless I suppose, that's just old
    habits from C and making clear it's not an int. Silly in awk, but
    presumably not an actual problem.

    It's probably unnecessary to disallow blank characters in front of the
    new and restart commands (while at the same time allowing "newbie" as
    valid input for "new"). (Same with quit and exit.)

    They're not documented as allowing an arbitrary number of blanks at
    the start, so I don't see this as an issue really. Similarly, the
    documentation is of the minimum form allowed (though it occurs to me
    that "h" works for help, so that's an exception admittedly).

    Terminating an array explicitly with an empty "" value and testing it
    with newdeck[srcnum]!="" (instead of srcnum in newdeck ) might not
    be necessary.

    There is some level of (ahem) awkwardness as an artifact of the part-translation I did from Z80. I probably kept the code more similar
    than I ideally should have done.

    Since card strings are equal length and operations mainly done at the
    end (or up to the end) of a pile one might consider implementing the
    stacks as strings, it might simplify the card stack manipulations.

    That's an interesting idea, I should have thought of that. It would
    probably be a bit too much of a rewrite to do that at this point
    though, and I wonder if in practice it could actually be slower due to
    partly avoiding the hashing that the awk implementation is likely
    doing for the associative array. (Also the card strings do vary
    between three and four characters in length currently, but that could
    be changed.)

    Just a few thoughts.

    Thanks for the feedback.

    -Rus.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Russell Marks@21:1/5 to Ben Bacarisse on Tue Jun 15 17:41:35 2021
    Ben Bacarisse <ben.usenet@bsb.me.uk> wrote:

    Russell Marks <zgedneil@spam^H^H^H^Hgmail.com> writes:

    Maybe it's a bit of a stretch to be posting this, but presumably not
    many games are written in awk so I thought I might as well. :-)

    Don't worry, the group is not overwhelmed by posts!
    [...]
    Nice. I'm tempted to ask why here, but then why not?

    Is that ask (why here), or (ask why) here?

    For ask (why here) - well I did say it was a bit of a stretch, I
    figured it could be of some interest to those interested in awk. More
    just that it exists, rather than being wonderful code or anything.

    For (ask why) here - I commented on that in the code:

    # Why do an awk version? I wanted to do something fun in awk that was
    # more than the usual random tiny program stuffed in a shell script.

    I do use awk a lot, but it's usually for that sort of thing, or even
    tinier command-line uses - like most awk users probably. This may be
    the longest awk program I've ever written, despite being well under a
    thousand lines with many being comments.

    I won't offer a code review, but you could make the play a little
    simpler if a single digit was permitted as an abbreviation. The
    simplest being that X means dX, but it could also mean Xa or one of
    [1-7]X or X[1-7] provided the move is unique.

    The game is partially based on an existing implementation (well two,
    soliyawn and zcsoli) which worked with direct key-by-key input rather
    than line-based input. So for that it needed the from-then-to. In this
    version as you say it isn't strictly necessary, I just like the idea
    of keeping it fairly consistent with the others.

    -Rus.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Russell Marks on Wed Jun 16 17:12:19 2021
    On 15.06.2021 20:00, Russell Marks wrote:
    Janis Papanagnou <janis_papanagnou@hotmail.com> wrote:

    One thing that I find inconvenient is when typing e.g. '1d' (i.e. an
    illegal input); then you're getting a couple lines of warning messages
    and - tempted to get rid of them and a fresh screen layout - hitting
    <Enter> will draw a new card. - I think it would be more convenient to
    just ignore that (illegal) move as done with other ineffective inputs.

    That's a tricky one, I suppose you could argue it both ways. You can
    use "r" (redraw) to avoid drawing a card of course, but I know it's
    not the most intuitive thing ever.

    The main inconvenience here is the screen corruption; additional lines
    scroll the previous statically (vt100) placed contents upwards. This
    corruption fosters a hit on the <Enter>, and thinking at that moment
    to issue a "non-standard" (in the sense of rarely or not at all used)
    <r> command is not straightforward. And that way you'll spoil the game
    input sequence by accident. It's a question of Input Ergonomics (User Experience, as they often call such things today).


    Locating the deck to the left (with some more space to separate it and
    distinguish it from the other seven heaps) might alleviate the display
    issue you mention (and also the issue I mentioned above).

    I might be misusing terminology, I'm not sure. On the left are the
    main grouping of face-down cards (potentially not-yet-seen), and just
    to the right of that is a pile of face-up cards that were turned over
    from the top of that.

    Sorry for having been unclear. What I meant was a layout that requires
    less rows (to prevent the undesired screen effects) and one more column,
    like this

    Deck Col1 Col2 ... Col7
    : : :
    : :
    :
    instead of

    Col1 Col2 ... Col7
    : : :
    : :
    :

    Deck


    Code that appears a bit strange (to me) is e.g. where you use float
    numbers in int contexts like the modulo calculation. And specifically
    the intention of using -1 to shift the number to the range -1..+65335.

    In rndseed the range is 0..65535, converted to 1..65536 when
    calculating the new seed value for the RNG. Obviously you don't want
    to multiply by zero. :-) It's true that the seed could have been left
    as non-zero, but that would have made it slightly harder to construct
    the rand()-like random number - you'd end up doing much the same
    either way.

    Funnily enough, in a way you could argue this isn't really an int
    context. Quite apart from awk itself being so keen on floating-point
    AIUI, the Spectrum's ROM did all the RNG maths using FP. In software.
    On a Z80. It wasn't fast.

    Actually writing e.g. "65537." is useless I suppose, that's just old
    habits from C and making clear it's not an int. Silly in awk, but
    presumably not an actual problem.

    I think what you implemented looks a lot like a (standard or not)
    Linear Congruential Pseudo Random Number Generator. These are purely
    working in an integer domain. So it makes not much sense "to make
    clear it's not an int".

    But, as said, there seems also to be an inherent issue with it that
    you even documented in the code ("It's tweaked to avoid zero"). But
    you don't prevent that. The expression x % 65537 creates results
    in the range 0..65536, and the -1 puts that in the range -1..65535,
    obviously containing the 0.


    It's probably unnecessary to disallow blank characters in front of the
    new and restart commands (while at the same time allowing "newbie" as
    valid input for "new"). (Same with quit and exit.)

    They're not documented as allowing an arbitrary number of blanks at
    the start, so I don't see this as an issue really. Similarly, the documentation is of the minimum form allowed (though it occurs to me
    that "h" works for help, so that's an exception admittedly).

    This again is a question of interface ergonomics and user experience;
    why abort a command with a blank that has been typed by accident?
    The nice thing with awk is that you control the regexps and string
    comparisons. Currently " new" is an error but "newbie" is okay. Why
    not stay closer to the expectation where (leading/trailing) blanks
    are insignificant. Instead of a match of $0 to /^new/ string-compare
    $1 to "new"; this solves both issues without overhead.


    Since card strings are equal length and operations mainly done at the
    end (or up to the end) of a pile one might consider implementing the
    stacks as strings, it might simplify the card stack manipulations.

    That's an interesting idea, I should have thought of that. It would
    probably be a bit too much of a rewrite to do that at this point
    though, and I wonder if in practice it could actually be slower due to
    partly avoiding the hashing that the awk implementation is likely
    doing for the associative array.

    It was more the thought that iterations and copies/deletions across
    array elements and ranges might be rather less efficient and let the
    code also bloat.

    (But that was anyway just a thought from an observation; I didn't mean
    to suggest a redesign of the code.)

    (Also the card strings do vary
    between three and four characters in length currently, but that could
    be changed.)

    Oh, the version I got from your link uses just (a bit cryptic but at
    least constant-length) 2-letter card descriptions.[*]

    Janis

    [*] BTW, I think the 2-letter cards are difficult to visually parse
    (letters and digits left, lowercase/uppercase letters to the right)
    and since the card symbols are US-centric (Q, J, and H, D, s, c)
    it's yet more confusing for non-US cultures. For my personal use I
    adjusted the code to an easier recognizable more formal syntax; I use

    valuetbl="MLKJIHGFEDCBA"
    suittbl="++--"

    (assuming H and D, and, s and c, respectively, are interchangeable;
    I'm not too familiar with that game, to be honest).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Janis Papanagnou on Wed Jun 16 17:19:33 2021
    On 16.06.2021 17:12, Janis Papanagnou wrote:

    [*] BTW, I think the 2-letter cards are difficult to visually parse
    (letters and digits left, lowercase/uppercase letters to the right)
    and since the card symbols are US-centric (Q, J, and H, D, s, c)
    it's yet more confusing for non-US cultures. For my personal use I
    adjusted the code to an easier recognizable more formal syntax; I use

    valuetbl="MLKJIHGFEDCBA"
    suittbl="++--"

    The result looks like this

    1 2 3 4 5 6 7

    A+ A+ A- A- %% %%
    B- B- B+ B+ H+ %%
    C+ C+ .. C- I- %%
    D- D- .. D+ J+ H-
    E+ E+ E- K- I+
    F- F- F+ .. J-
    G+ .. G- .. K+
    H- .. H+ L-
    I+ I- M+
    J- J+ ..
    K+ K- ..
    L- L+
    M+ M-
    .. ..
    .. ..


    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Russell Marks@21:1/5 to Janis Papanagnou on Thu Jun 17 01:00:25 2021
    Janis Papanagnou <janis_papanagnou@hotmail.com> wrote:

    On 15.06.2021 20:00, Russell Marks wrote:
    Janis Papanagnou <janis_papanagnou@hotmail.com> wrote:
    [...]
    Locating the deck to the left (with some more space to separate it and
    distinguish it from the other seven heaps) might alleviate the display
    issue you mention (and also the issue I mentioned above).

    I might be misusing terminology, I'm not sure. On the left are the
    main grouping of face-down cards (potentially not-yet-seen), and just
    to the right of that is a pile of face-up cards that were turned over
    from the top of that.

    Sorry for having been unclear. What I meant was a layout that requires
    less rows (to prevent the undesired screen effects) and one more column,
    like this

    Deck Col1 Col2 ... Col7
    : : :
    : :
    :
    instead of

    Col1 Col2 ... Col7
    : : :
    : :
    :

    Deck

    You have to put the four ace piles somewhere though (they're not
    visible until aces are moved to them). They could go vertically under
    the deck and turned-over pile, but I'm not sure I like that idea
    really.

    Code that appears a bit strange (to me) is e.g. where you use float
    numbers in int contexts like the modulo calculation. And specifically
    the intention of using -1 to shift the number to the range -1..+65335.

    In rndseed the range is 0..65535, converted to 1..65536 when
    calculating the new seed value for the RNG. Obviously you don't want
    to multiply by zero. :-) It's true that the seed could have been left
    as non-zero, but that would have made it slightly harder to construct
    the rand()-like random number - you'd end up doing much the same
    either way.

    Funnily enough, in a way you could argue this isn't really an int
    context. Quite apart from awk itself being so keen on floating-point
    AIUI, the Spectrum's ROM did all the RNG maths using FP. In software.
    On a Z80. It wasn't fast.

    Actually writing e.g. "65537." is useless I suppose, that's just old
    habits from C and making clear it's not an int. Silly in awk, but
    presumably not an actual problem.

    I think what you implemented looks a lot like a (standard or not)
    Linear Congruential Pseudo Random Number Generator. These are purely
    working in an integer domain. So it makes not much sense "to make
    clear it's not an int".

    Unless I missed something (other than e.g. gawk's option to use GMP)
    awk maths is all doubles. I presume "%" would use fmod() for example.
    Of course there is no need to use floating-point for the algorithm
    but... it's in awk, so I don't generally get the choice. I did use
    int() to limit cumulative error in this case, but that's all.

    But, as said, there seems also to be an inherent issue with it that
    you even documented in the code ("It's tweaked to avoid zero"). But
    you don't prevent that. The expression x % 65537 creates results
    in the range 0..65536, and the -1 puts that in the range -1..65535,
    obviously containing the 0.

    Let's go step by step. rndseed is meant to be kept as 0<=x<65536.
    Initially you have this to set that, from the seed as entered:

    rndseed=0+$0
    if(rndseed<0.) rndseed=0.
    rndseed%=65536.

    When the RNG is used (in the old-awk version only), there's this:

    rndseed=int(((rndseed+1)*75.)%65537.-1)

    For now, let's assume we're doing this with integers:

    - rndseed beforehand is 0<=x<65536.

    - rndseed+1 is 1<=x<65537.

    - Then we do the multiply by 75, and the mod 65537.

    - Result range so far is still 1<=x<65537 (because 65537 is a prime).

    - Then subtract one. rndseed range is now 0<=x<65536, as intended.

    I think you're assuming that there is some input which will result in
    a zero at the "Result range so far" step above. But 65537 is a prime
    number which by definition does not evenly divide by 75, so there is
    no way for the mod-65537 step to give a zero result. (If it were
    possible to get a zero at that stage the RNG wouldn't work.)

    Now, you might be thinking, that'd be fine if this were all integer
    maths, but with it all being floating-point does that break anything?
    Well, I don't think so. Not with the int() happening each time.

    It's easy enough to give a rough demonstration of the non-zero result
    (and thus no negative rndseed happening) with:

    awk 'BEGIN {
    for(f=0;f<65536;f++)
    {
    rndseed=int(((f+1)*75.)%65537.-1)
    if(rndseed<0) print f
    }
    exit
    }'

    If that prints anything the RNG is broken.

    It's probably unnecessary to disallow blank characters in front of the
    new and restart commands (while at the same time allowing "newbie" as
    valid input for "new"). (Same with quit and exit.)

    They're not documented as allowing an arbitrary number of blanks at
    the start, so I don't see this as an issue really. Similarly, the
    documentation is of the minimum form allowed (though it occurs to me
    that "h" works for help, so that's an exception admittedly).

    This again is a question of interface ergonomics and user experience;
    why abort a command with a blank that has been typed by accident?
    The nice thing with awk is that you control the regexps and string comparisons. Currently " new" is an error but "newbie" is okay. Why
    not stay closer to the expectation where (leading/trailing) blanks
    are insignificant. Instead of a match of $0 to /^new/ string-compare
    $1 to "new"; this solves both issues without overhead.

    Trailing everything is insignificant already. Ignoring leading blanks
    is obviously not hard, but I don't see much point.

    (Also the card strings do vary
    between three and four characters in length currently, but that could
    be changed.)

    Oh, the version I got from your link uses just (a bit cryptic but at
    least constant-length) 2-letter card descriptions.[*]

    Internally the cards are represented a bit differently to how they're displayed, I thought you were referring to that form.

    [*] BTW, I think the 2-letter cards are difficult to visually parse
    (letters and digits left, lowercase/uppercase letters to the right)
    and since the card symbols are US-centric (Q, J, and H, D, s, c)
    it's yet more confusing for non-US cultures.

    I haven't found it confusing in the non-US culture here. :-)

    -Rus.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Russell Marks on Sun Jun 20 13:24:01 2021
    On 17.06.2021 03:00, Russell Marks wrote:
    Janis Papanagnou <janis_papanagnou@hotmail.com> wrote:
    On 15.06.2021 20:00, Russell Marks wrote:
    Janis Papanagnou <janis_papanagnou@hotmail.com> wrote:
    [...]
    Sorry for having been unclear. What I meant was a layout that requires
    less rows (to prevent the undesired screen effects) and one more column,
    like this

    Deck Col1 Col2 ... Col7
    : : :
    : :
    :
    instead of

    Col1 Col2 ... Col7
    : : :
    : :
    :

    Deck

    You have to put the four ace piles somewhere though (they're not
    visible until aces are moved to them). They could go vertically under
    the deck and turned-over pile,

    Not sure what you're trying to say here.

    Your program should not corrupt the screen! - That's the main point.

    That is something you should consider to fix if you want to make your
    interface better.

    There are many ways how you can achieve that. I have proposed two ways;
    a functional one (create not an error unnecessarily) and a display one (reorganize the screen layout). (There are yet more option; e.g. place
    the [unnecessary] error message somewhere where there's still room, i.e.
    where the screen will not corrupt.)

    (Not that it would have any practical relevance in context of a funny
    but otherwise meaningless piece of code.)

    but I'm not sure I like that idea really.

    (It's your program, so be sure I care even less about it than you do.)


    Code that appears a bit strange (to me) is e.g. where you use float
    numbers in int contexts like the modulo calculation. And specifically
    the intention of using -1 to shift the number to the range -1..+65335.

    In rndseed the range is 0..65535, converted to 1..65536 when
    calculating the new seed value for the RNG. Obviously you don't want
    to multiply by zero. :-) It's true that the seed could have been left
    as non-zero, but that would have made it slightly harder to construct
    the rand()-like random number - you'd end up doing much the same
    either way.

    Funnily enough, in a way you could argue this isn't really an int
    context. Quite apart from awk itself being so keen on floating-point
    AIUI, the Spectrum's ROM did all the RNG maths using FP. In software.
    On a Z80. It wasn't fast.

    Actually writing e.g. "65537." is useless I suppose, that's just old
    habits from C and making clear it's not an int. Silly in awk, but
    presumably not an actual problem.

    I think what you implemented looks a lot like a (standard or not)
    Linear Congruential Pseudo Random Number Generator. These are purely
    working in an integer domain. So it makes not much sense "to make
    clear it's not an int".

    Unless I missed something (other than e.g. gawk's option to use GMP)
    awk maths is all doubles. I presume "%" would use fmod() for example.
    Of course there is no need to use floating-point for the algorithm
    but... it's in awk, so I don't generally get the choice. I did use
    int() to limit cumulative error in this case, but that's all.

    Even if awk supports only FP numeric data type you can effectively
    do integer arithmetic while you're staying within the integer range
    with your numbers. So that is not an issue in the numeric range we
    are considering here, and we can focus on the actual points I made.

    But, as said, there seems also to be an inherent issue with it that
    you even documented in the code ("It's tweaked to avoid zero"). But
    you don't prevent that. The expression x % 65537 creates results
    in the range 0..65536, and the -1 puts that in the range -1..65535,
    obviously containing the 0.

    Let's go step by step. rndseed is meant to be kept as 0<=x<65536.
    Initially you have this to set that, from the seed as entered:

    rndseed=0+$0
    if(rndseed<0.) rndseed=0.
    rndseed%=65536.

    When the RNG is used (in the old-awk version only), there's this:

    rndseed=int(((rndseed+1)*75.)%65537.-1)

    For now, let's assume we're doing this with integers:

    - rndseed beforehand is 0<=x<65536.

    - rndseed+1 is 1<=x<65537.

    - Then we do the multiply by 75, and the mod 65537.

    - Result range so far is still 1<=x<65537 (because 65537 is a prime).

    Whether 65537 is a prime or not, the modulo operation creates zeros!
    (and results in the range 0..65536).

    - Then subtract one. rndseed range is now 0<=x<65536, as intended.

    No.

    I think you're assuming that there is some input which will result in
    a zero at the "Result range so far" step above.

    No, I am not assuming that.

    But 65537 is a prime
    number which by definition does not evenly divide by 75, so there is
    no way for the mod-65537 step to give a zero result. (If it were
    possible to get a zero at that stage the RNG wouldn't work.)

    Now, you might be thinking, that'd be fine if this were all integer
    maths, but with it all being floating-point does that break anything?
    Well, I don't think so. Not with the int() happening each time.

    It's easy enough to give a rough demonstration of the non-zero result
    (and thus no negative rndseed happening) with:

    awk 'BEGIN {
    for(f=0;f<65536;f++)
    {
    rndseed=int(((f+1)*75.)%65537.-1)
    if(rndseed<0) print f
    }
    exit
    }'

    If that prints anything the RNG is broken.

    My point was that the modulus (rndseed) can become 0. (That's a plain
    fact with any valid X % M expressions; the result range is 0..M-1 .)

    So change your program to compare rndseed<=0 (or ==0) and you get the
    obvious hit.


    This again is a question of interface ergonomics and user experience;
    why abort a command with a blank that has been typed by accident?
    The nice thing with awk is that you control the regexps and string
    comparisons. Currently " new" is an error but "newbie" is okay. Why
    not stay closer to the expectation where (leading/trailing) blanks
    are insignificant. Instead of a match of $0 to /^new/ string-compare
    $1 to "new"; this solves both issues without overhead.

    Trailing everything is insignificant already. Ignoring leading blanks
    is obviously not hard, but I don't see much point.

    The point is just making the interface better. (Presuming you care.)

    Since it's so simple to fix that, I cannot even understand why you are
    so reluctant, and why you prefer typing long posts and not just change
    a handful of characters in your code instead.


    I haven't found it confusing in the non-US culture here. :-)

    I'm sure since you developed it that YOU are quite used to the behavior
    and appearance as it is, that's not surprising.

    As your statement made obvious, you don't seem to care about extending
    your biased view by others' feedback, though. So I obviously wasted
    enough time with providing constructive feedback, abstain from further
    comments here, and "bail out" (as old awks would formulate it).

    Have fun with your programs.

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Russell Marks on Mon Jun 21 17:12:40 2021
    On 2021-06-21, Russell Marks <zgedneil@spam^H^H^H^Hgmail.com> wrote:
    Assuming integer maths as above, a multiply of a non-zero number by 75 followed by modulo of 65537 simply cannot produce a zero result -
    there is no circumstance in which it can happen, as the following
    program demonstrates.

    Yes, the additional constraint that the number is in the range
    [1, 65536] makes it true

    Thre is a is a fact in number theory: any two nonzero elements of a
    residue system can be multiplied together modulo the modulus, resulting
    in a nonzero element of the system.

    Without that we could kiss other results goodbye, like Fermat's Little
    Theorem and Euler's Theorem.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Russell Marks@21:1/5 to Janis Papanagnou on Mon Jun 21 16:33:26 2021
    Janis Papanagnou <janis_papanagnou@hotmail.com> wrote:

    On 17.06.2021 03:00, Russell Marks wrote:
    Janis Papanagnou <janis_papanagnou@hotmail.com> wrote:
    On 15.06.2021 20:00, Russell Marks wrote:
    [...]
    You have to put the four ace piles somewhere though (they're not
    visible until aces are moved to them). They could go vertically under
    the deck and turned-over pile,

    Not sure what you're trying to say here.

    Your program should not corrupt the screen! - That's the main point.

    It doesn't corrupt the screen in my experience, at most it scrolls it.

    (It's your program, so be sure I care even less about it than you do.)

    You're welcome.

    Code that appears a bit strange (to me) is e.g. where you use float
    numbers in int contexts like the modulo calculation. And specifically >>>>> the intention of using -1 to shift the number to the range -1..+65335. >>>>
    In rndseed the range is 0..65535, converted to 1..65536 when
    calculating the new seed value for the RNG. Obviously you don't want
    to multiply by zero. :-) It's true that the seed could have been left
    as non-zero, but that would have made it slightly harder to construct
    the rand()-like random number - you'd end up doing much the same
    either way.
    [...]
    I think what you implemented looks a lot like a (standard or not)
    Linear Congruential Pseudo Random Number Generator. These are purely
    working in an integer domain. So it makes not much sense "to make
    clear it's not an int".

    Unless I missed something (other than e.g. gawk's option to use GMP)
    awk maths is all doubles. I presume "%" would use fmod() for example.
    Of course there is no need to use floating-point for the algorithm
    but... it's in awk, so I don't generally get the choice. I did use
    int() to limit cumulative error in this case, but that's all.
    [...]
    When the RNG is used (in the old-awk version only), there's this:

    rndseed=int(((rndseed+1)*75.)%65537.-1)

    For now, let's assume we're doing this with integers:

    - rndseed beforehand is 0<=x<65536.

    - rndseed+1 is 1<=x<65537.

    - Then we do the multiply by 75, and the mod 65537.

    - Result range so far is still 1<=x<65537 (because 65537 is a prime).

    Whether 65537 is a prime or not, the modulo operation creates zeros!
    (and results in the range 0..65536).

    Assuming integer maths as above, a multiply of a non-zero number by 75
    followed by modulo of 65537 simply cannot produce a zero result -
    there is no circumstance in which it can happen, as the following
    program demonstrates.

    awk 'BEGIN {
    for(f=0;f<65536;f++)
    {
    rndseed=int(((f+1)*75.)%65537.-1)
    if(rndseed<0) print f
    }
    exit
    }'

    If that prints anything the RNG is broken.

    My point was that the modulus (rndseed) can become 0. (That's a plain

    rndseed is *not* the modulus result, see above. Note the "-1".

    fact with any valid X % M expressions; the result range is 0..M-1 .)

    So change your program to compare rndseed<=0 (or ==0) and you get the obvious hit.

    "modulus...can become 0" and "rndseed...==0" are two different things.
    Modulus becoming 0 would mean rndseed being -1, while "rndseed...==0"
    clearly does not.

    For some reason you appear reluctant to accept that the program above
    tests your claim *as-is*, with no modifications, but it does.

    Since it's so simple to fix that, I cannot even understand why you are
    so reluctant, and why you prefer typing long posts and not just change
    a handful of characters in your code instead.

    If enough people find a lack of ignoring (e.g.) leading spaces to be a
    problem I would probably make the change, even if I see little point
    to it myself.

    I haven't found it confusing in the non-US culture here. :-)

    I'm sure since you developed it that YOU are quite used to the behavior
    and appearance as it is, that's not surprising.

    I was joking about the way you seemed to be demonstrating cultural
    biases of your own while criticising mine - I'm not from the US,
    English isn't US-only, and the style of playing cards used is of
    French origin I believe. But you did have a point. There's no
    localisation and the game will clearly be harder to play if you're not
    familiar with the style of cards used and/or English terms for them.

    As your statement made obvious, you don't seem to care about extending
    your biased view by others' feedback, though. So I obviously wasted

    FWIW I don't think that's a fair characterisation.

    enough time with providing constructive feedback, abstain from further comments here, and "bail out" (as old awks would formulate it).

    Ok. Nothing here should directly call for a response.

    -Rus.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Russell Marks@21:1/5 to Kaz Kylheku on Mon Jun 21 21:07:07 2021
    Kaz Kylheku <563-365-8930@kylheku.com> wrote:

    On 2021-06-21, Russell Marks <zgedneil@spam^H^H^H^Hgmail.com> wrote:
    Assuming integer maths as above, a multiply of a non-zero number by 75
    followed by modulo of 65537 simply cannot produce a zero result -
    there is no circumstance in which it can happen, as the following
    program demonstrates.

    Yes, the additional constraint that the number is in the range
    [1, 65536] makes it true

    I really should have included that in the sentence. Obviously
    (65537*75)%65537 would give zero, were 65537 a possible input. :-)

    -Rus.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Russell Marks on Mon Jun 21 22:03:05 2021
    On 2021-06-21, Russell Marks <zgedneil@spam^H^H^H^Hgmail.com> wrote:
    Kaz Kylheku <563-365-8930@kylheku.com> wrote:

    On 2021-06-21, Russell Marks <zgedneil@spam^H^H^H^Hgmail.com> wrote:
    Assuming integer maths as above, a multiply of a non-zero number by 75
    followed by modulo of 65537 simply cannot produce a zero result -
    there is no circumstance in which it can happen, as the following
    program demonstrates.

    Yes, the additional constraint that the number is in the range
    [1, 65536] makes it true

    I really should have included that in the sentence. Obviously (65537*75)%65537 would give zero, were 65537 a possible input. :-)

    BTW the IDEA cipher makes use of modular multiplication aroudn 65537.

    https://en.wikipedia.org/wiki/International_Data_Encryption_Algorithm

    There is a trick to doing it fast; i.e without actually dividing
    by 65537.

    From some IDEA code:

    /*
    * Multiplication, modulo (2**16)+1
    * Note that this code is structured on the assumption that
    * untaken branches are cheaper than taken branches, and the
    * compiler doesn't schedule branches.
    */
    #ifdef SMALL_CACHE
    CONST static uint16
    mul(register uint16 a, register uint16 b)
    {
    register word32 p;

    p = (word32)a * b;
    if (p) {
    b = low16(p);
    a = p>>16;
    return (b - a) + (b < a);
    } else if (a) {
    return 1-b;
    } else {
    return 1-a;
    }
    } /* mul */
    #endif /* SMALL_CACHE */


    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Russell Marks@21:1/5 to Kaz Kylheku on Tue Jun 22 18:51:58 2021
    Kaz Kylheku <563-365-8930@kylheku.com> wrote:

    On 2021-06-21, Russell Marks <zgedneil@spam^H^H^H^Hgmail.com> wrote:
    Kaz Kylheku <563-365-8930@kylheku.com> wrote:

    On 2021-06-21, Russell Marks <zgedneil@spam^H^H^H^Hgmail.com> wrote:
    Assuming integer maths as above, a multiply of a non-zero number by 75 >>>> followed by modulo of 65537 simply cannot produce a zero result -
    there is no circumstance in which it can happen, as the following
    program demonstrates.

    Yes, the additional constraint that the number is in the range
    [1, 65536] makes it true

    I really should have included that in the sentence. Obviously
    (65537*75)%65537 would give zero, were 65537 a possible input. :-)

    BTW the IDEA cipher makes use of modular multiplication aroudn 65537.

    https://en.wikipedia.org/wiki/International_Data_Encryption_Algorithm

    There is a trick to doing it fast; i.e without actually dividing
    by 65537.
    [...]
    a = p>>16;

    Interesting... maybe not ideal in awk as I think you'd still need
    division to do the bitshift. I suppose gawk has rshift(), but the RNG
    code I'd been commenting on is only really intended for old awk on
    e.g. V7.

    -Rus.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Andreas Eder@21:1/5 to Kaz Kylheku on Tue Jun 22 20:32:26 2021
    On Mo 21 Jun 2021 at 17:12, Kaz Kylheku <563-365-8930@kylheku.com> wrote:

    Thre is a is a fact in number theory: any two nonzero elements of a
    residue system can be multiplied together modulo the modulus, resulting
    in a nonzero element of the system.

    Only if the modulus is prime!
    Otherwise it is possible: 2 * 3 = 0 mod 6.

    'Andreas

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Andreas Eder on Tue Jun 22 18:59:26 2021
    On 2021-06-22, Andreas Eder <a_eder_muc@web.de> wrote:
    On Mo 21 Jun 2021 at 17:12, Kaz Kylheku <563-365-8930@kylheku.com> wrote:

    Thre is a is a fact in number theory: any two nonzero elements of a
    residue system can be multiplied together modulo the modulus, resulting
    in a nonzero element of the system.

    Only if the modulus is prime!
    Otherwise it is possible: 2 * 3 = 0 mod 6.

    ISTR, the condition may be weaker; namely that those two elements of the residue system be coprime with the modulus.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Andreas Eder@21:1/5 to Kaz Kylheku on Wed Jun 23 20:34:52 2021
    On Di 22 Jun 2021 at 18:59, Kaz Kylheku <563-365-8930@kylheku.com> wrote:

    On 2021-06-22, Andreas Eder <a_eder_muc@web.de> wrote:
    On Mo 21 Jun 2021 at 17:12, Kaz Kylheku <563-365-8930@kylheku.com> wrote:

    Thre is a is a fact in number theory: any two nonzero elements of a
    residue system can be multiplied together modulo the modulus, resulting
    in a nonzero element of the system.

    Only if the modulus is prime!
    Otherwise it is possible: 2 * 3 = 0 mod 6.

    ISTR, the condition may be weaker; namely that those two elements of the residue system be coprime with the modulus.

    Yes, that is true. Then you are computing in the prime residue group.

    'Andreas

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)