diff --git a/2018/ferguson/Makefile b/2018/ferguson/Makefile
index bd100fedc..694e87d91 100644
--- a/2018/ferguson/Makefile
+++ b/2018/ferguson/Makefile
@@ -55,9 +55,26 @@ CSTD= -std=gnu17
#
ARCH=
+# Variables to help simplify configuring the build
+#
+
+# Maximum size of the target string defaults at 38. See README.md for why this
+# is.
+#
+MAX_SIZE= 38
+
+# Number of offspring per generation defaults at 25.
+#
+OFFSPRING= 25
+
+# Max attempts defaults at SIZE_MAX - 1 but one can change it to see what
+# happens when the maximum is reached.
+MAX_ATTEMPTS= SIZE_MAX-1
+
# Defines that are needed to compile
#
-CDEFINE= -DQ='typedef' -D'g(o)'='goto o;' -D'w(x)'="x:" -D'H(main)'='r(main)'
+CDEFINE= -DQ='typedef' -D'g(o)'='goto o;' -D'w(x)'="x:" -D'H(main)'='r(main)' -DM=${MAX_ATTEMPTS} \
+ -DS=${MAX_SIZE} -DN=${OFFSPRING}
# Include files that are needed to compile
#
@@ -135,7 +152,7 @@ weasel: ${PROG}
${CP} -f $< $@
test: ${PROG} test.sh
- ./test.sh
+ @./test.sh
# alternative executable
#
diff --git a/2018/ferguson/README.md b/2018/ferguson/README.md
index f848705e8..aa1f73c44 100644
--- a/2018/ferguson/README.md
+++ b/2018/ferguson/README.md
@@ -19,8 +19,24 @@ monkey Eric. See [Alternate code](#alternate-code) below.
```sh
./try.sh
+
+# For those who believe in '"intelligent" design' or want to see how easy it is
+# to prove evolution is a proven fact:
+./id.sh
+
+# For those who want to see if Eric the monkey can type the word 'words' before
+# falling asleep or giving up:
+./monkey-words.sh
```
+NOTE: the [try.sh](try.sh) script will run the other two scripts but if the
+first one, [id.sh](id.sh) is terminated early in the try script, the second one,
+[monkey-words.sh](monkey-words.sh) will not be run.
+
+You can reconfigure certain values. These are described by the author in more
+detail in the [S, M and N Constants](#constants) section. The script above will
+make use of some of these.
+
## Alternate code:
@@ -45,8 +61,33 @@ Use `weasel.alt` as you would `weasel` above.
```sh
./try.alt.sh
+
+# For those who believe in '"intelligent" design' or want to see how easy it is
+# to prove evolution is a proven fact:
+./id.alt.sh
+
+# For those who want to see if Eric the monkey can type the word 'words' before
+# falling asleep or giving up:
+./monkey-words.alt.sh
```
+NOTE: the [try.alt.sh](try.alt.sh) script will run the other two scripts but if the
+first one, [id.alt.sh](id.alt.sh) is terminated early in the try script, the second one,
+[monkey-words.alt.sh](monkey-words.alt.sh) will not be run.
+
+You can reconfigure certain values. These are described by the author in more
+detail in the [S, M and N Constants](#constants) section. The script above will
+make use of some of these.
+
+
+```sh
+./try.alt.sh
+```
+
+You can reconfigure certain values. These are described by the author in more
+detail in the [S, M and N Constants](#constants) section. The script above will
+make use of some of these.
+
## Judges' remarks:
@@ -131,9 +172,10 @@ don't need this unless there is something specific you're after.
**[Obfuscation](#obfuscation):** Some of the techniques that might not be used.
**[How to build](#build):** Here I describe briefly
-[the constants that can be redefined](#constants) `S` and `N`: the
+[the constants that can be redefined](#constants) `S`, `M` and `N`: the
maximum size of the chromosome (target string; the maximum length is `S - 1`
-but it must be >= the default 38) and the number of offspring, respectively. I
+but it must be >= the default 38), the number of maximum attempts before giving
+up and the number of offspring, respectively. I
also give [example compiler invocations](#compiling), [portability
notes](#portability), an [more portability notes](#bugs) and a [note on
rpm.md](#rpm).
@@ -865,21 +907,24 @@ be made clear in the comments! :)*
## **5. How to build**
-### S and N Constants
+### S, M and N Constants
Skip to [Compilation](#compiling).
-These two `#define`d constants can be redefined at compilation to modify the
+There are three `#define`d constants that can be redefined at compilation to modify the
behaviour of the program in a number of ways (see the
**[Compilation](#compiling)** subsection for example invocations). Both are
-capped to be no greater than `SIZE_MAX - 1`. This is handled by the C
-preprocessor.
+capped to be no greater than `SIZE_MAX - 1` or whatever `M` (which can't be
+lower than 100) is set to (maximum attempts before giving up). This is handled
+by the C preprocessor.
-`S`
-This determines the maximum size of the target string but it **must be at least
-38**; this is because `38 >= 29` and because `strlen("METHINKS IT IS LIKE
-A WEASEL") == 28` (which is the default target string - it would hardly be an
+* `S`
+
+The macro `S` (or `MAX_SIZE` in the Makefile) is the maximum size of the target
+string but it **must be at least 38** (which is protected against in the code);
+this is because `38 >= 29` and because `strlen("METHINKS IT IS LIKE A WEASEL")
+== 28` (which is the default target string - it would hardly be an
implementation of the Weasel program otherwise).
There is obviously a reason `38` is the chosen size but the only hints I
@@ -888,14 +933,43 @@ referenced there (it's *not the only Easter egg* but it's the only Easter egg I
won't spoil; yes this ironically and amusingly means I've left a rotten egg
somewhere!).
-`N`
+The Makefile simplifies how to reconfigure this value with the variable
+`MAX_SIZE`:
-This is the number of offspring per generation. Anything less than 4 will be set
-to 3 (that's not a typo!) and this is part of an Easter egg.
+```sh
+make clobber MAX_SIZE=55 all
+```
+
+The next macro that can be reconfigured, `M` (or `MAX_ATTEMPTS` in the
+Makefile), is the maximum attempts before giving up. This was added as another
+feature in 2024 but it was not made an alt version because there already is an
+alt version. This macro allows for seeing what happens when reaching the maximum
+number attempts without waiting for a very long time.
+
+The Makefile simplifies how to reconfigure this value with the variable
+`MAX_ATTEMPTS`:
+
+```sh
+make clobber MAX_ATTEMPTS=100 all
+```
+
+The final macro, `N` (or `OFFSPRING` in the Makefile), is the number of offspring
+per generation.
+
+Anything less than 4 will be set to 3 (that's not a typo!) and this is part of
+an Easter egg.
+
+Be aware that depending on the size of `S` (`MAX_SIZE`) and `N` (`OFFSPRING`)
+both individually and together the program will use varying amounts of memory
+and the larger the values the more memory it'll require.
+
+The Makefile simplifies how to reconfigure this value with the variable
+`OFFSPRING`:
+
+```sh
+make clobber OFFSPRING=55 all
+```
-Be aware that depending on the size of `S` and `N` (individually and
-together) the program will use varying amounts of memory and the larger the
-values the more memory it'll require.
### Compilation
@@ -907,23 +981,33 @@ The following options **must always be passed to the compiler:**
-DQ='typedef' -D'g(o)'='goto o;' -D'w(x)'="x:" -D'H(main)'='r(main)'
```
-If you want to increase the number of offspring to `50` and the size of the
-chromosome to `75` you would pass to the compiler:
+which running `make` will always do.
+
+
+If you want to increase the number of offspring to `50` (`N`) and the size of the
+chromosome to `75` (`S`) you would do:
```sh
--DQ='typedef' -D'g(o)'='goto o;' -D'w(x)'="x:" -D'H(main)'='r(main)' -DN=50 -DS=75
+make clobber OFFSPRING=50 MAX_SIZE=75 everything
```
If you wanted to change `N` to `3`:
```sh
--DQ='typedef' -D'g(o)'='goto o;' -D'w(x)'="x:" -D'H(main)'='r(main)' -DN=3
+make clobber OFFSPRING=3 everything
```
Remember that it cannot be less than `3`; *more correctly if it's less than
-4 it's redefined to 3* so you could have passed in `-DN=2` and have the same
-result. Remember too that `S` cannot be less than `38`. Both `S` and
-`N` are capped at `SIZE_MAX - 1`.
+4 it's redefined to 3* so you could have passed in `-DN=2` (or `MAX_SIZE=2`) and have the same
+result. Remember too that `S` (`MAX_SIZE`) cannot be less than `38`. Both `S` and
+`N` are capped at `SIZE_MAX - 1` or whatever `M` (`MAX_ATTEMPTS`) is set to.
+
+If you wanted to change the maximum number attempts to 100 you could do:
+
+```sh
+make clobber MAX_ATTEMPTS=100 everything
+```
+
### Portability
diff --git a/2018/ferguson/id.alt.sh b/2018/ferguson/id.alt.sh
new file mode 100755
index 000000000..b4d4e25c2
--- /dev/null
+++ b/2018/ferguson/id.alt.sh
@@ -0,0 +1,27 @@
+#!/usr/bin/env bash
+#
+# id.alt.sh - determine exactly how real '"intelligent" design' is with alt code
+#
+
+# limit to 250000 attempts to save them time if they really wish to try and
+# prove that '"intelligent" design' is real (or more correctly so that they
+# might last long enough in the try scripts to move on to the next step)
+make -B MAX_ATTEMPTS=250000 everything >/dev/null || exit 1
+
+read -r -p "Do you wish to try and prove '\"intelligent\" design' (Y/N)? "
+if [[ "$REPLY" = "Y" || "$REPLY" = "y" ]]; then
+ echo "$ ./weasel.alt -m 'INTELLIGENT DESIGN'" 1>&2
+ echo "Limiting to 250000 attempts to save you time." 1>&2
+ echo 1>&2
+ echo "Press any key to continue. Send ctrl-c when convinced that intelligent" 1>&2
+ read -r -n 1 -p "design is not real or you're tired of waiting: "
+ echo 1>&2
+ ./weasel.alt -m 'INTELLIGENT DESIGN'
+ echo 1>&2
+ exit 1
+else
+ read -r -n 1 -p "Press any key to run: time ./weasel.alt -r8 'EVOLUTION IS A PROVEN FACT': "
+ echo 1>&2
+ time ./weasel.alt -r8 'EVOLUTION IS A PROVEN FACT'
+ exit 0
+fi
diff --git a/2018/ferguson/id.sh b/2018/ferguson/id.sh
new file mode 100755
index 000000000..f0eb90e3e
--- /dev/null
+++ b/2018/ferguson/id.sh
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+#
+# id.sh - determine exactly how real '"intelligent" design' is
+#
+
+# limit to 250000 attempts to save them time if they really wish to try and
+# prove that '"intelligent" design' is real (or more correctly so that they
+# might last long enough in the try scripts to move on to the next step)
+make -B MAX_ATTEMPTS=250000 everything >/dev/null || exit 1
+
+read -r -p "Do you wish to try and prove '\"intelligent\" design' (Y/N)? "
+if [[ "$REPLY" = "Y" || "$REPLY" = "y" ]]; then
+ echo "$ ./weasel -m 'INTELLIGENT DESIGN'" 1>&2
+ echo "Limiting to 250000 attempts to save you time." 1>&2
+ echo "Press any key to continue. Send ctrl-c when convinced that intelligent" 1>&2
+ read -r -n 1 -p "design is not real or you're tired of waiting: "
+ ./weasel -m 'INTELLIGENT DESIGN'
+ echo 1>&2
+ exit 1
+else
+ echo "$ ./weasel -r8 'EVOLUTION IS A PROVEN FACT'" 1>&2
+ time ./weasel -r8 'EVOLUTION IS A PROVEN FACT'
+ exit 0
+fi
diff --git a/2018/ferguson/monkey-words.alt.sh b/2018/ferguson/monkey-words.alt.sh
new file mode 100755
index 000000000..53bc3222e
--- /dev/null
+++ b/2018/ferguson/monkey-words.alt.sh
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+#
+# monkey-words.sh - try and get Eric the monkey to type 'words'.
+#
+echo 1>&2
+make -B MAX_ATTEMPTS=SIZE_MAX-1 >/dev/null || exit 1
+echo 1>&2
+read -r -n 1 -p "Do you want to see how long it might take the monkey Eric to type 'words'? (Y/N)? "
+if [[ "$REPLY" == "Y" || "$REPLY" == "y" ]]; then
+ echo 1>&2
+ echo "Will let Eric try until he succeeds, gives up or he falls asleep." 1>&2
+ echo "Hit ctrl-c/intr to let him nap early." 1>&2
+ echo 1>&2
+ read -r -n 1 -p "Press any key to continue: "
+ echo 1>&2
+ time ./weasel -m words
+fi
diff --git a/2018/ferguson/monkey-words.sh b/2018/ferguson/monkey-words.sh
new file mode 100755
index 000000000..53bc3222e
--- /dev/null
+++ b/2018/ferguson/monkey-words.sh
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+#
+# monkey-words.sh - try and get Eric the monkey to type 'words'.
+#
+echo 1>&2
+make -B MAX_ATTEMPTS=SIZE_MAX-1 >/dev/null || exit 1
+echo 1>&2
+read -r -n 1 -p "Do you want to see how long it might take the monkey Eric to type 'words'? (Y/N)? "
+if [[ "$REPLY" == "Y" || "$REPLY" == "y" ]]; then
+ echo 1>&2
+ echo "Will let Eric try until he succeeds, gives up or he falls asleep." 1>&2
+ echo "Hit ctrl-c/intr to let him nap early." 1>&2
+ echo 1>&2
+ read -r -n 1 -p "Press any key to continue: "
+ echo 1>&2
+ time ./weasel -m words
+fi
diff --git a/2018/ferguson/prog.alt.c b/2018/ferguson/prog.alt.c
index 6c80797e3..8f99f09ae 100644
--- a/2018/ferguson/prog.alt.c
+++ b/2018/ferguson/prog.alt.c
@@ -7,7 +7,12 @@
Q unsigned d; Q char E; Q int k;
Q long u; Q size_t t; Q const char U;
#define L toupper
+ #ifndef M
#define M SIZE_MAX-1
+ #elif M < 100
+ #undef M
+ #define M SIZE_MAX-1
+ #endif
#ifndef S
#define S 38
#elif S < 38
diff --git a/2018/ferguson/prog.c b/2018/ferguson/prog.c
index 18de651dd..5e64cf10b 100644
--- a/2018/ferguson/prog.c
+++ b/2018/ferguson/prog.c
@@ -7,7 +7,12 @@
Q unsigned d; Q char E; Q int k;
Q long u; Q size_t t; Q const char U;
#define L toupper
+ #ifndef M
#define M SIZE_MAX-1
+ #elif M < 100
+ #undef M
+ #define M SIZE_MAX-1
+ #endif
#ifndef S
#define S 38
#elif S < 38
diff --git a/2018/ferguson/test-strings.txt b/2018/ferguson/test-strings.txt
index 6a1c48a5f..181132d3f 100644
--- a/2018/ferguson/test-strings.txt
+++ b/2018/ferguson/test-strings.txt
@@ -13,5 +13,5 @@ STOP MONKEYING ABOUT!
WHAT DO YOU MEAN I'M A MONKEY?!
PROBLEM BETWEEN KEYBOARD AND CHAIR
MY PRECIOUS. YES, MY PRECIOUS.
-MY PRECIOUS! O MY PRECIOUS!
+MY PRECIOUS! O MY PRECIOUS! PRECIOUS
IOCCC BEST USE OF WEASEL WORDS
diff --git a/2018/ferguson/test.sh b/2018/ferguson/test.sh
index 77c62b13f..431332cbe 100755
--- a/2018/ferguson/test.sh
+++ b/2018/ferguson/test.sh
@@ -1,11 +1,17 @@
#!/usr/bin/env bash
+#
+# test.sh - make test script for IOCCC winner 2018/ferguson
# Make sure the program has been compiled
make everything 1> /dev/null|| exit 1
+read -r -n 1 -p "Press any key to run tests (space = next page, G = end, q = quit): "
+echo 1>&2
+
while read -r f; do
- ./weasel "$@" "${f}" # full line because of quotes
- # NOTE: ./weasel $* $f would just be the final word
- sleep 2
+ # NOTE: ./weasel $* $f would just be the final word. We quote it for the
+ # full line:
+ ./weasel "$@" "${f}" | less -rEXFK
done < test-strings.txt || exit 1
+
echo "All done. Goodbye, you old monkeying weasel!"
diff --git a/2018/ferguson/try.alt.sh b/2018/ferguson/try.alt.sh
index 83713b706..54dcfa152 100755
--- a/2018/ferguson/try.alt.sh
+++ b/2018/ferguson/try.alt.sh
@@ -10,43 +10,54 @@ if [[ -z "$CC" ]]; then
CC="cc"
fi
-make CC="$CC" alt >/dev/null || exit 1
+make CC="$CC" everything >/dev/null || exit 1
# clear screen after compilation so that only the entry is shown
clear
-read -r -n 1 -p "Press any key to run: ./weasel.alt words (space = next page, q = quit): "
+read -r -n 1 -p "Press any key to run: ./weasel.alt words (space = next page, q = quit, G = end): "
echo 1>&2
-time ./weasel.alt words | less -EXF
+time ./weasel.alt words | less -rEXFK
read -r -n 1 -p "Press any key to see how long it'll take Eric the monkey to type his name: "
echo 1>&2
time ./weasel.alt -mq Eric
echo 1>&2
-read -r -n 1 -p "Press any key to run: make test: "
+read -r -p "Do you want to run make test (Y/N)? "
+if [[ "$REPLY" = "Y" || "$REPLY" = "y" ]]; then
+ make test
+fi
+
+read -r -p "Do you wish to see the undocumented Easter egg (Y/N)? "
+if [[ "$REPLY" = "Y" || "$REPLY" = "y" ]]; then
+ make -B OFFSPRING=97 everything 1>/dev/null || exit 1
+ read -r -n 1 -p "Press any key to show Easter egg (./weasel.alt): "
+ echo 1>&2
+ ./weasel.alt
+ echo 1>&2
+fi
+
echo 1>&2
-make test
+read -r -n 1 -p "Press any key to change max attempts to 100: "
+echo 1>&2
+echo "$ make -B MAX_ATTEMPTS=100 everything >/dev/null || exit 1" 1>&2
+echo 1>&2
+make -B MAX_ATTEMPTS=100 everything >/dev/null || exit 1
+read -r -n 1 -p "Press any key to see what happens when the maximum attempts are reached: "
+echo 1>&2
+./weasel.alt -m 'Eric the Monkey'
-read -r -p "Do you wish to try and prove 'intelligent design' (Y/N)? "
-if [[ "$REPLY" == "Y" || "$REPLY" == "y" ]]; then
- echo "$ ./weasel.alt -m 'INTELLIGENT DESIGN'" 1>&2
- echo "Press any key to continue. Send ctrl-c when convinced that intelligent" 1>&2
- read -r -n 1 -p "design is not real or you're tired of waiting: "
- echo 1>&2
- time ./weasel.alt -m 'INTELLIGENT DESIGN'
- echo 1>&2
-else
- echo "$ ./weasel.alt -q -r8 'EVOLUTION IS A PROVEN FACT'" 1>&2
- time ./weasel.alt -q -r8 'EVOLUTION IS A PROVEN FACT'
-fi
+# recompile with default max attempts for the next steps
+make -B everything >/dev/null || exit 1
-read -r -n 1 -p "Do you want to see how long it might take the monkey Eric to type 'words'? (Y/N)? "
-if [[ "$REPLY" == "Y" || "$REPLY" == "y" ]]; then
- echo 1>&2
- echo "Will not display until Eric succeeds or too many generations. Hit ctrl-c" 1>&2
- echo "to stop him early." 1>&2
- read -r -n 1 -p "Press any key to continue: "
- echo 1>&2
- time ./weasel.alt -mq words
-fi
+# obviously '"intelligent" design' is false but who wants to try and prove
+# otherwise? Or if they know better how long will it take to show that evolution
+# is a proven fact?
+./id.alt.sh
+
+# If the user did not try and prove '"intelligent" design' or they waited a
+# long time (though saving them some time by limiting it to 900000 attempts) I
+# ask: can Eric the monkey type the word 'words' before falling asleep or
+# getting too hungry to continue?
+./monkey-words.alt.sh
diff --git a/2018/ferguson/try.sh b/2018/ferguson/try.sh
index 9552e1e21..831b9fb8c 100755
--- a/2018/ferguson/try.sh
+++ b/2018/ferguson/try.sh
@@ -15,38 +15,49 @@ make CC="$CC" all >/dev/null || exit 1
# clear screen after compilation so that only the entry is shown
clear
-read -r -n 1 -p "Press any key to run: ./weasel words (space = next page, q = quit): "
+read -r -n 1 -p "Press any key to run: ./weasel words (space = next page, q = quit, G = end): "
echo 1>&2
-time ./weasel words | less -EXF
+time ./weasel words | less -rEXFK
read -r -n 1 -p "Press any key to see how long it'll take Eric the monkey to type his name: "
echo 1>&2
time ./weasel -mq Eric
echo 1>&2
-read -r -n 1 -p "Press any key to run: make test: "
+read -r -p "Do you want to run make test (Y/N)? "
+if [[ "$REPLY" = "Y" || "$REPLY" = "y" ]]; then
+ make test
+fi
+
+read -r -p "Do you wish to see the undocumented Easter egg (Y/N)? "
+if [[ "$REPLY" = "Y" || "$REPLY" = "y" ]]; then
+ make -B OFFSPRING=97 everything 1>/dev/null || exit 1
+ read -r -n 1 -p "Press any key to show Easter egg (./weasel): "
+ echo 1>&2
+ ./weasel
+ echo 1>&2
+fi
+
echo 1>&2
-make test
+read -r -n 1 -p "Press any key to change max attempts to 100: "
+echo 1>&2
+echo "$ make -B MAX_ATTEMPTS=100 everything >/dev/null || exit 1" 1>&2
+echo 1>&2
+make -B MAX_ATTEMPTS=100 everything >/dev/null || exit 1
+read -r -n 1 -p "Press any key to see what happens when the maximum attempts are reached: "
+echo 1>&2
+./weasel -m 'Eric the Monkey'
-read -r -p "Do you wish to try and prove 'intelligent design' (Y/N)? "
-if [[ "$REPLY" == "Y" || "$REPLY" == "y" ]]; then
- echo "$ ./weasel -m 'INTELLIGENT DESIGN'" 1>&2
- echo "Press any key to continue. Send ctrl-c when convinced that intelligent" 1>&2
- read -r -n 1 -p "design is not real or you're tired of waiting: "
- echo 1>&2
- time ./weasel -m 'INTELLIGENT DESIGN'
- echo 1>&2
-else
- echo "$ ./weasel -q -r8 'EVOLUTION IS A PROVEN FACT'" 1>&2
- time ./weasel -q -r8 'EVOLUTION IS A PROVEN FACT'
-fi
+# recompile with default max attempts for the next steps
+make -B everything >/dev/null || exit 1
-read -r -n 1 -p "Do you want to see how long it might take the monkey Eric to type 'words'? (Y/N)? "
-if [[ "$REPLY" == "Y" || "$REPLY" == "y" ]]; then
- echo 1>&2
- echo "Will not display until Eric succeeds or too many generations. Hit ctrl-c" 1>&2
- echo "to stop him early." 1>&2
- read -r -n 1 -p "Press any key to continue: "
- echo 1>&2
- time ./weasel -mq words
-fi
+# obviously '"intelligent" design' is false but who wants to try and prove
+# otherwise? Or if they know better how long will it take to show that evolution
+# is a proven fact?
+./id.sh
+
+# If the user did not try and prove '"intelligent" design' or they waited a
+# long time (though saving them some time by limiting it to 900000 attempts) I
+# ask: can Eric the monkey type the word 'words' before falling asleep or
+# getting too hungry to continue?
+./monkey-words.sh