Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/games/worms Correct some unfortunate behaviour in extreme ca...



details:   https://anonhg.NetBSD.org/src/rev/eeec5192c7f8
branches:  trunk
changeset: 374318:eeec5192c7f8
user:      kre <kre%NetBSD.org@localhost>
date:      Tue Apr 18 15:02:22 2023 +0000

description:
Correct some unfortunate behaviour in extreme cases pointed out by RVP.
(Very long worms in a smallish window could result in the max number of
worms being 0...)

While here (also suggested by RVP) seed the random number generator,
also add a -S option to set the seed (note: while this is documented
in the updated man page, it does not appear in the usage message in
case of an error ... not likely to be used often enough to include there).

Also some minor improvements suggested by RVP:
        delete the prototype for main()
        exit curses mode before abort() (which should not happen, but...)
        no need to return (->exit) after abort() as modern abort() can
                never return.

In addition, check for extraneous (ignored) (non-option) args.
Check for absurdly small or big screens (the worm placement algorithm
doesn't work well for lines of columns < 3, and the abort() mentioned
above actually happens if one of those is == 1).

More flavours of worms added.

Some minor man page wording improvements.

diffstat:

 games/worms/worms.6 |  39 ++++++++++++++++++------
 games/worms/worms.c |  82 +++++++++++++++++++++++++++++++++++++++-------------
 2 files changed, 90 insertions(+), 31 deletions(-)

diffs (264 lines):

diff -r f7240f5901ce -r eeec5192c7f8 games/worms/worms.6
--- a/games/worms/worms.6       Tue Apr 18 14:24:25 2023 +0000
+++ b/games/worms/worms.6       Tue Apr 18 15:02:22 2023 +0000
@@ -1,4 +1,4 @@
-.\"    $NetBSD: worms.6,v 1.16 2020/10/14 07:32:53 nia Exp $
+.\"    $NetBSD: worms.6,v 1.17 2023/04/18 15:02:22 kre Exp $
 .\"
 .\" Copyright (c) 1989, 1993
 .\"    The Regents of the University of California.  All rights reserved.
@@ -29,7 +29,7 @@
 .\"
 .\"    @(#)worms.6     8.1 (Berkeley) 5/31/93
 .\"
-.Dd October 14, 2020
+.Dd April 17, 2023
 .Dt WORMS 6
 .Os
 .Sh NAME
@@ -41,6 +41,7 @@
 .Op Fl d Ar delay
 .Op Fl l Ar length
 .Op Fl n Ar number
+.Op Fl S Ar seed
 .Sh DESCRIPTION
 .Nm
 is a
@@ -49,11 +50,11 @@ version of the DEC-2136 program
 .Dq worms .
 .Pp
 The options are as follows:
-.Bl -tag -width XlXlengthXX
+.Bl -tag -width Fl
 .It Fl d Ar delay
-Specifies
-.Ar delay
-as a delay, in milliseconds, between each update.
+Specifies a
+.Ar delay ,
+in milliseconds, between each update.
 This is useful for fast terminals.
 Reasonable values are around 20-200;
 the default is 20.
@@ -62,13 +63,31 @@ Makes a
 .Dq field
 for the worm(s) to eat.
 .It Fl l Ar length
-Specifies
+Specifies the
 .Ar length
-as a length for each worm; the default is 16.
+of each worm; the default is 16, the minimum is 2.
 .It Fl n Ar number
-Specifies
+Specifies the
 .Ar number
-as the number of worms; the default is 3.
+of worms; the default is 3.
+There must be at least one.
+.It Fl S Ar seed
+Provide an integer
+.Ar seed
+for the random number generator.
+Specifying zero (0, the default) causes a random seed to be used.
 .It Fl t
 Makes each worm leave a trail behind it.
 .El
+.Pp
+The maximum
+.Ar length ,
+and
+.Ar number ,
+of worms depends upon the screen size, though the
+.Ar length
+can never exceed 1024.
+If the screen is particularly small, even the defaults
+for those may be too large.
+Screens with less than 3 rows or columns cannot be handled,
+nor can ones with insufficient total space.
diff -r f7240f5901ce -r eeec5192c7f8 games/worms/worms.c
--- a/games/worms/worms.c       Tue Apr 18 14:24:25 2023 +0000
+++ b/games/worms/worms.c       Tue Apr 18 15:02:22 2023 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: worms.c,v 1.26 2023/04/15 15:21:56 kre Exp $   */
+/*     $NetBSD: worms.c,v 1.27 2023/04/18 15:02:22 kre Exp $   */
 
 /*
  * Copyright (c) 1980, 1993
@@ -39,7 +39,7 @@
 #if 0
 static char sccsid[] = "@(#)worms.c    8.1 (Berkeley) 5/31/93";
 #else
-__RCSID("$NetBSD: worms.c,v 1.26 2023/04/15 15:21:56 kre Exp $");
+__RCSID("$NetBSD: worms.c,v 1.27 2023/04/18 15:02:22 kre Exp $");
 #endif
 #endif /* not lint */
 
@@ -67,6 +67,7 @@ static char sccsid[] = "@(#)worms.c   8.1 
 #include <err.h>
 #include <limits.h>
 #include <signal.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <strings.h>
@@ -168,7 +169,8 @@ static const struct options {
 
 
 static const char      flavor[] = {
-       'O', '*', '#', '$', '%', '0', '@', '~'
+       'O', '*', '#', '$', '%', '0', '@', '~',
+       '+', 'w', ':', '^', '_', '&', 'x', 'o'
 };
 static const short     xinc[] = {
        1,  1,  1,  0, -1, -1, -1,  0
@@ -182,7 +184,6 @@ static struct       worm {
 
 static volatile sig_atomic_t sig_caught = 0;
 
-int     main(int, char **);
 static void nomem(void) __dead;
 static void onsig(int);
 
@@ -194,17 +195,20 @@ main(int argc, char *argv[])
        const struct options *op;
        short *ip;
        int CO, LI, last, bottom, ch, length, number, trail;
+       unsigned int seed;
        short **ref;
        const char *field;
        char *ep;
        unsigned int delay = 20000;
        unsigned long ul;
+       bool argerror = false;
 
        length = 16;
        number = 3;
        trail = ' ';
        field = NULL;
-       while ((ch = getopt(argc, argv, "d:fl:n:t")) != -1)
+       seed = 0;
+       while ((ch = getopt(argc, argv, "d:fl:n:S:t")) != -1) {
                switch(ch) {
                case 'd':
                        ul = strtoul(optarg, &ep, 10);
@@ -233,10 +237,10 @@ main(int argc, char *argv[])
                                   optarg);
                        }
                        delay = (unsigned int)ul;
-                       break;
+                       continue;
                case 'f':
                        field = "WORM";
-                       break;
+                       continue;
                case 'l':
                        ul = strtoul(optarg, &ep, 10);
                        if (ep == optarg || *ep != '\0' ||
@@ -245,7 +249,7 @@ main(int argc, char *argv[])
                                     optarg, 2, 1024);
                        }
                        length = (int)ul;
-                       break;
+                       continue;
                case 'n':
                        ul = strtoul(optarg, &ep, 10);
                        if (ep == optarg || *ep != '\0' ||
@@ -255,17 +259,30 @@ main(int argc, char *argv[])
                        }
                        /* upper bound is further limited later */
                        number = (int)ul;
-                       break;
+                       continue;
+               case 'S':
+                       ul = strtoul(optarg, &ep, 0);
+                       if (ep == optarg || *ep != '\0' ||
+                           ul > UINT_MAX ) {
+                               errx(1, "-S: invalid seed (%s).", optarg);
+                       }
+                       seed = (unsigned int)ul;
+                       continue;
                case 't':
                        trail = '.';
-                       break;
+                       continue;
                case '?':
                default:
-                       (void)fprintf(stderr,
-                           "usage: worms [-ft] [-d delay] [-l length]"
-                           " [-n number]\n");
-                       exit(1);
+                       argerror = true;
+                       break;
                }
+               break;
+       }
+
+       if (argerror || argc > optind)
+               errx(1,
+                   "Usage: worms [-ft] [-d delay] [-l length] [-n number]");
+               /* -S omitted deliberately, not useful often enough */
 
        if (!initscr())
                errx(1, "couldn't initialize screen");
@@ -273,14 +290,35 @@ main(int argc, char *argv[])
        CO = COLS;
        LI = LINES;
 
-       if (CO > 4*length || LI < 4*length) {
-               ul  = (unsigned long)LI / 2;
-               ul *= (unsigned long)CO / length;
-       } else {
-               ul  = (unsigned long)CO / 2;
-               ul *= (unsigned long)LI / length;
+       if (CO == 0 || LI == 0) {
+               endwin();
+               errx(1, "screen must be a rectangle, not (%dx%d)", CO, LI);
+       }
+       if (CO >= INT_MAX / LI) {
+               endwin();
+               errx(1, "screen (%dx%d) too large for worms", CO, LI);
        }
 
+       /* now known that LI*CO cannot overflow an int => also not a long */
+
+       if (LI < 3 || CO < 3 || LI * CO < 40) {
+               /*
+                * The placement algorithm is too weak for dimensions < 3.
+                * Need at least 40 spaces so we can have (n > 1) worms
+                * of a reasonable length, and still leave empty space.
+                */
+               endwin();
+               errx(1, "screen (%dx%d) too small for worms", CO, LI);
+       }
+
+       ul = (unsigned long)CO * LI;
+       if ((unsigned long)length > ul / 20) {
+               endwin();
+               errx(1, "-l: worms loo long (%d) for screen; max: %lu",
+                   length, ul / 20);
+       }
+
+       ul /= (length * 3);     /* no more than 33% arena occupancy */
        if ((unsigned long)(unsigned)number > ul) {
                endwin();
                errx(1, "-n: too many worms (%d) max: %lu", number, ul);
@@ -332,6 +370,7 @@ main(int argc, char *argv[])
                        refresh();
                }
        }
+       srandom(seed ? seed : arc4random());
        for (;;) {
                refresh();
                if (sig_caught) {
@@ -379,8 +418,9 @@ main(int argc, char *argv[])
                        switch (op->nopts) {
                        case 0:
                                refresh();
+                               endwin();
                                abort();
-                               return(1);
+                               /* NOTREACHED */
                        case 1:
                                w->orientation = op->opts[0];
                                break;



Home | Main Index | Thread Index | Old Index