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