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
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
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.
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?
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.
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.
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.
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).
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.)
[*] 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="++--"
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
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.
(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.[*]
[*] 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.
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,
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.
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.
I haven't found it confusing in the non-US culture here. :-)
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.
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'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 floatIn rndseed the range is 0..65535, converted to 1..65536 when
numbers in int contexts like the modulo calculation. And specifically >>>>> the intention of using -1 to shift the number to the range -1..+65335. >>>>
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).
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.
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).
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
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. :-)
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;
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.
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.
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.
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 296 |
Nodes: | 16 (2 / 14) |
Uptime: | 79:37:22 |
Calls: | 6,658 |
Calls today: | 4 |
Files: | 12,203 |
Messages: | 5,333,092 |
Posted today: | 1 |