diff --git a/1991/brnstnd/.gitignore b/1991/brnstnd/.gitignore index 98ba8b35e..5fe33081a 100644 --- a/1991/brnstnd/.gitignore +++ b/1991/brnstnd/.gitignore @@ -1,3 +1,4 @@ brnstnd brnstnd.orig prog.orig +sorta diff --git a/1991/brnstnd/Makefile b/1991/brnstnd/Makefile index b87831d73..c014224b8 100644 --- a/1991/brnstnd/Makefile +++ b/1991/brnstnd/Makefile @@ -133,6 +133,7 @@ all: data ${TARGET} ${PROG}: ${PROG}.c ${CC} ${CFLAGS} $< -o $@ ${LDFLAGS} + ${LN} -sf $@ sorta # alternative executable # diff --git a/1991/brnstnd/README.md b/1991/brnstnd/README.md index e05835d1a..fd89523a7 100644 --- a/1991/brnstnd/README.md +++ b/1991/brnstnd/README.md @@ -21,7 +21,7 @@ For info on more examples, read the [sorta.README.md](sorta.README.md) file. The author wished to win the "most useful program" award and documented this in the source code. The judges were unmoved by this blatant attempt to influence -the contest and rejected this idea... so we gave it the `Best of Show` +the contest and rejected this idea... so we gave it the "Best of Show" instead!! NOTE: One should remove the final trailing newline to obtain the @@ -51,12 +51,12 @@ instance, not to mention infinite-depth tail recursion. SORTA ignores its arguments (though it makes them available to the script); it takes all commands, character by character, from its -standard input. Unrecognized commands are repeated with a '?'. +standard input. Unrecognized commands are repeated with a `'?'`. -SORTA maintains an `i stack` for integers and an `s stack` for strings. It also +SORTA maintains an `i` stack for integers and an `s` stack for strings. It also keeps track of `programs`, one for each character. Operations are silently ignored if the relevant stacks are too low, except as noted for `s`, `S`, and -`!`. If the `i stack` or `s stack` (or the stack of buffered macro commands) +`!`. If the `i` stack or `s` stack (or the stack of buffered macro commands) grows too high, SORTA will exit silently with exit code 2. (Compile parameter `-Do=250` controls what 'too high' means; you should not make `o` larger than 250.) I don't think it's possible to crash the interpreter. @@ -68,24 +68,24 @@ delimiters. ### Basic operations - `q`: quit -- `number`: push that number on top of the i stack -- `"string"`: push that string on top of the s stack, no length limit -- `[string]`: push that string on top of the s stack, no length limit -- `#`: make top of i stack non-destructively in ASCII, push result onto s stack -- ` ` `: print top of s stack non-destructively -- `$`: print top of s stack non-destructively without newline -- `d`: drop (pop) top of i stack -- `D`: dup (duplicate) top of i stack +- `number`: push that number on top of the `i` stack +- `"string"`: push that string on top of the `s` stack, no length limit +- `[string]`: push that string on top of the `s` stack, no length limit +- `#`: make top of `i` stack non-destructively in ASCII, push result onto `s` stack +- ` ` `: print top of `s` stack non-destructively +- `$`: print top of `s` stack non-destructively without newline +- `d`: drop (pop) top of `i` stack +- `D`: dup (duplicate) top of `i` stack - `'`: dup top of s stack - `s`: pop top of i stack. If it is `n`, swap `(n+1)`th-top of `i` stack with top. `1s`, for example, swaps the top two elements; `2s` swaps the top with the - third down; etc. This always pops the top of the `i stack`, even upon + third down; etc. This always pops the top of the `i` stack, even upon failure. -- `S`: pop top of `i stack`, then act just like `s` but upon `s stack` -- `l`: pop top of `s stack`, push its length onto `i stack` +- `S`: pop top of `i` stack, then act just like `s` but upon `s` stack +- `l`: pop top of `s` stack, push its length onto `i` stack - `a`: push argc onto i stack -- `A`: pop top of `i stack`, push `argv[i]` on top of `s stack` -- `T`: concatenate top two elements of `s stack` +- `A`: pop top of `i` stack, push `argv[i]` on top of `s` stack +- `T`: concatenate top two elements of `s` stack - ` _ `: negate top of i stack - `+`: pop top two elements of i stack, add, push back sum - ` * `: pop top two elements of i stack, multiply, push back product @@ -97,17 +97,17 @@ delimiters. ### System operations -- `o`: pop top of `s stack` and top two of `i stack`; `open(s1,i2,i1);` leave -result on `i stack` -- `O`: pop top of `i stack`, `close()` it -- `u`: pop top of `i stack`, `dup()` it, push result back on -- `F`: `fork()`, push result on `i stack`. This is not always safe while SORTA is +- `o`: pop top of `s` stack and top two of `i` stack; `open(s1,i2,i1);` leave +result on `i` stack +- `O`: pop top of `i` stack, `close()` it +- `u`: pop top of `i` stack, `dup()` it, push result back on +- `F`: `fork()`, push result on `i` stack. This is not always safe while SORTA is reading keyboard input or a script, as the forked programs share file descriptors. It is always safe inside a program (see below). -- `P`: `pipe()`, push two ends ` ` onto `i stack`. In case of trouble, -`push <-1>` onto `i stack`. -- `w`: `wait()`, push successful result (or -1 if no children) on `i stack` -- `!`: `execvp()` top of the `s stack`. Arguments are the next things down on +- `P`: `pipe()`, push two ends ` ` onto `i` stack. In case of trouble, +`push <-1>` onto `i` stack. +- `w`: `wait()`, push successful result (or -1 if no children) on `i` stack +- `!`: `execvp()` top of the `s` stack. Arguments are the next things down on the s stack, in reverse order from popping; the first character of each string is lopped off. There must be an empty string somewhere in the s stack to terminate the argument list. If the execve() diff --git a/1991/brnstnd/sorta.README.md b/1991/brnstnd/sorta.README.md index 36086f283..46c39d288 100644 --- a/1991/brnstnd/sorta.README.md +++ b/1991/brnstnd/sorta.README.md @@ -56,13 +56,13 @@ This is self-explanatory. 1=D 1s# " | "T 1s#T " is "T D&1sD&& #T$ld " (" 1=2 ")"T `ld 1=D 1s# " ^ "T 1s#T " is "T 1=D&2sD&1sD&&&D& #T$ld " (" 1=2 ")"T `ld -`icalc` shows off SORTA's understanding of integer arithmetic. You can run +`icalc` shows off `SORTA`'s understanding of integer arithmetic. You can run it with up to two arguments; the arguments have default values of 27182 -and 3145. Notice that sorta doesn't have a language primitive for +and 3145. Notice that `SORTA` doesn't have a language primitive for converting a string to a number, yet `icalc` is performing arithmetic on -its arguments. Can you see how? (Hint: Try `./brnstnd "2 2+" 3 < sorta.icalc`. +its arguments. Can you see how? (Hint: Try `./sorta "2 2+" 3 < sorta.icalc`. Look at program A.) `icalc` also provides a useful binary output routine, -and if you can't remember offhand that `D2sD3s&2sD&1sD&&&D&` means xor, +and if you can't remember offhand that `D2sD3s&2sD&1sD&&&D&` means XOR, you can just look it up here. @@ -74,7 +74,7 @@ you can just look it up here. 0""1=y` This script prints out the maximum file descriptor available from -repeated dup()s---usually NOFILE - 1. Can you see how it works? +repeated `dup(2)`s---usually `NOFILE - 1`. Can you see how it works? # [sorta.iecho](sorta.iecho) @@ -83,9 +83,9 @@ repeated dup()s---usually NOFILE - 1. Can you see how it works? [1s1+DA$ld1s1_+D=sD=x]:xld [ given n (argc-n), print args ]ld 0a1_+D=x""` [ simulation of /bin/echo ]ld -This is a clone of /bin/echo, minus any argument processing and escape -interpretation. (Note that, unlike some shells' echo, /bin/echo prints a -newline even with no arguments.) Try sorta foo bar < iecho. +This is a clone of `/bin/echo`, minus any argument processing and escape +interpretation. (Note that, unlike some shells' echo, `/bin/echo` prints a +newline even with no arguments.) Try `./sorta foo bar < iecho`. # [sorta.ifact1](sorta.ifact1) @@ -105,8 +105,8 @@ multiply by 2, print it, multiply by 3, print it, etc. 1=f 1=f 1=f 1=f 1=f 1=f 1=f 1=f 1=f 1=f `ifact1` does a lot of repeated work. `ifact2` takes advantage of this by -keeping the current `n!` n on the stack. Each call to routine f (1=f) -increments n by 1 and prints out the factorial. +keeping the current `n!` `n` on the stack. Each call to routine `f (1=f)` +increments `n` by `1` and prints out the factorial. # [sorta.ifact3](sorta.ifact3) @@ -117,7 +117,7 @@ increments n by 1 and prints out the factorial. 0 1 10 1=x Finally, `ifact3` removes all the redundancy from `ifact2`, and exhibits -proper documentation of stack routines. You can replace the 10 by +proper documentation of stack routines. You can replace the `10` by anything in this version. @@ -127,7 +127,7 @@ anything in this version. ["] "2 2+":xT ["]T " produces "T 1=x#T " which should be 4."T` -Notice that "2 2+" is a literal string inside the program. +Notice that `"2 2+"` is a literal string inside the program. # [sorta.irot13](sorta.irot13) @@ -144,7 +144,7 @@ Notice that "2 2+" is a literal string inside the program. 0Ou1=x [ in a more complex spawner, this would be done under a fork ]ld Despite its name, `irot13` is meant to show how to exec a program with -redirection from within sorta. You run it as `./brnstnd blah < irot13`; it +redirection from within `sorta`. You run it as `./sorta blah < irot13`; it opens `blah` and runs a (BSD-style) `tr` command to rotate all letters by 13 spots. `1A 0 0 o` opens `argv[1]`; the ` ' ` keeps the filename around for subroutine `h` to print a nice error message if necessary. `0Ou` closes @@ -170,8 +170,8 @@ This script illustrates the classic fork-exec-wait. [3*#" "T$ldD=f]:f 1=f -The sole purpose of this script is to prove that sorta can do infinite -tail recursion (in this case, in program `f`). Do `./brnstnd < itailrec | more` +The sole purpose of this script is to prove that `sorta` can do infinite +tail recursion (in this case, in program `f`). Do `./sorta < itailrec | more` and watch the powers of 3 (mod your computer's word size) flow by. diff --git a/1991/cdupont/README.md b/1991/cdupont/README.md index 81fa33093..b06ccc4d1 100644 --- a/1991/cdupont/README.md +++ b/1991/cdupont/README.md @@ -21,7 +21,7 @@ sorryfor_this_unused_but_very_needed_label: ``` Notice that if you C beautify (cb) or pre-process this program, it -will no longer work correctly, or at all. (go ahead, try it... :-)) +will no longer work correctly, if at all. (go ahead, try it... :-)) NOTE: One should remove the final trailing newline to obtain the original source file. This step is not needed to compile @@ -36,7 +36,7 @@ letter and key. Thus, the message is code. That is why I use silly comments, most often badly spaced. The space character sequence between the words is given by a simple -computation on an octal constant (given here as an hex value, of +computation in an octal constant (given here as an hex value, of course). This way, any message can be mixed into a code, since the keys allow diff --git a/1991/davidguy/Makefile b/1991/davidguy/Makefile index 7c18c7b82..6a7bb0120 100644 --- a/1991/davidguy/Makefile +++ b/1991/davidguy/Makefile @@ -40,7 +40,7 @@ include ../../var.mk # CSILENCE= -Wno-bitwise-op-parentheses -Wno-error -Wno-implicit-function-declaration \ -Wno-int-to-pointer-cast -Wno-return-type -Wno-sign-compare \ - -Wno-deprecated-non-prototype + -Wno-deprecated-non-prototype -Wno-implicit-int # Common C compiler warning flags # @@ -63,7 +63,7 @@ CDEFINE= # Include files that are needed to compile # -CINCLUDE= +CINCLUDE= -include sys/types.h -include sys/socket.h -include unistd.h # Optimization # diff --git a/1991/davidguy/README.md b/1991/davidguy/README.md index 81ac88c3f..3a927f703 100644 --- a/1991/davidguy/README.md +++ b/1991/davidguy/README.md @@ -106,15 +106,15 @@ be computed by a boolean circuit. In addition, intermediate values computed by the circuit can be shared between neighboring cells, reducing the number of gates per cell required. These ideas have been used before, to compute the next generation through a -series of bit blits. Instead of doing this, we map values in the -circuit to bits in registers, so that the next generation can be -computed efficiently within registers, minimizing memory accesses. -As a result, the computation of the next generation is performed -with about 1.6 instructions per life cell, consisting of .125 -memory accesses, .17 shifts, and 1.3 logic operations. The net -result is that the time to transfer the bits to the X server, and -for the X server to draw them on the screen, dominates the time to -compute the next generation. +series of [bit blits](https://en.wikipedia.org/wiki/Bit_blit). + +Instead of doing this, we map values in the circuit to bits in registers, so +that the next generation can be computed efficiently within registers, +minimizing memory access. As a result, the computation of the next generation +is performed with about 1.6 instructions per life cell, consisting of .125 +memory accesses, .17 shifts, and 1.3 logic operations. The net result is that +the time to transfer the bits to the X server, and for the X server to draw them +on the screen, dominates the time to compute the next generation. ## Copyright and CC BY-SA 4.0 License: diff --git a/1991/dds/README.md b/1991/dds/README.md index 80f0858f2..11691d1b9 100644 --- a/1991/dds/README.md +++ b/1991/dds/README.md @@ -8,7 +8,7 @@ make all ## To use: ```sh -./dds basic_program 2>/dev/null +./dds basic_program ./a.out 2>/dev/null ``` @@ -18,14 +18,17 @@ make all The author suggests trying: ```sh -./dds LANDER.BAS 2>/dev/null -./a.out 2>/dev/null +./dds LANDER.BAS +./a.out ``` +Notice that a file `a.c` has been generated. Can you tell how `a.c` was +produced? How does `a.c` relate to [LANDER.BAS](LANDER.BAS)? + What happens if you give the program a C program like itself? Try: ```sh -./dds dds.c 2>/dev/null +./dds dds.c ``` You'll get errors yes but what does the generated file look like? What about @@ -34,9 +37,6 @@ other types of files? ## Judges' remarks: -Notice that a file `a.c` has been generated. Can you tell how `a.c` was -produced? How does `a.c` relate to [LANDER.BAS](LANDER.BAS)? - This obfuscated program translates BASIC programs into obfuscated C programs by way of an obfuscated algorithm. @@ -45,15 +45,16 @@ C programs by way of an obfuscated algorithm. This program is a companion to the [DDS-BASIC interpreter program](/1990/dds/README.md) that was submitted to [the contest in -1990](/years.html#1990). This compiles BASIC programs into executable commands. -The input format is almost identical to the input format of the DDS-BASIC -interpreter. The program needs an executable C compiler called `cc` in your -path in order to work. +1990](/years.html#1990). This compiles BASIC programs into compilable C code +and then compiles it. The input format is almost identical to the input format +of the DDS-BASIC interpreter. The program needs an executable C compiler called +`cc` in your path in order to work. + ### Program commands: -- variable names A to Z +- variable names `A` to `Z` - FOR var = exp TO exp - GOSUB exp - GOTO exp @@ -75,7 +76,7 @@ Many system calls and C library calls can be used. - Free format positioning of tokens on the line. - No space is allowed before the line number. -- Exactly one space is needed after the FOR and NEXT tokens +- Exactly one space is needed after the `FOR` and `NEXT` tokens. - ALL INPUT MUST BE UPPERCASE. ### Error checking / error reports: @@ -85,19 +86,19 @@ Other errors may produce errors in later phases of the compilation. ### Can you figure out how the compiler works? -Hint: +#### Hint: The compiler is NOT written in C, so this is really a meta-obfuscated program. The C code is an interpreter for the four register, seven -instruction COGNIMP$ machine that is contained in the `s` string. -(COGNIMP$ is named after the symbolic names of the seven instructions it -defines (Print Output Goto Match If, iNcrement and Copy). The `$` sign -is used for labels.) The actual compiler is written in COGNIMP$. -Browsing through the COGNIMP$ code we encourage you to examine the -loops for scanning the expression in the IF statement and the way a -decision tree is implemented in order to match the statements. (Of -course the `s` string is encoded by adding one to every character of it just -to confuse you). +instruction `COGNIMP$` machine that is contained in the `s` string. +(`COGNIMP$` is named after the symbolic names of the seven instructions it +defines (`Copy`, `Output`, `Goto`, `iNcrement`, `If`, `Match` and `Print`). + +The `$` sign is used for labels. The actual compiler is written in `COGNIMP$`. +Browsing through the `COGNIMP$` code we encourage you to examine the loops for +scanning the expression in the `IF` statement and the way a decision tree is +implemented in order to match the statements. (Of course the `s` string is +encoded by adding one to every character of it just to confuse you). ## Copyright and CC BY-SA 4.0 License: diff --git a/1991/rince/README.md b/1991/rince/README.md index 71174e91d..ad605b0fb 100644 --- a/1991/rince/README.md +++ b/1991/rince/README.md @@ -66,7 +66,8 @@ version end up allowing any number of movements? ## Judges' remarks: -This entry has been updated to allow most ANSI C compilers. +In 2023 this entry was been updated to allow most ANSI C compilers to compile +the code and to fix a bug where the win or lose message was not seen. ## Author's remarks: diff --git a/1991/westley/.gitignore b/1991/westley/.gitignore index 71f95e6dc..ca193c527 100644 --- a/1991/westley/.gitignore +++ b/1991/westley/.gitignore @@ -1,11 +1,17 @@ merlyn merlyn.c +merlyn.alt.c nextmove nextmove.c +nextmove.alt.c ttt +ttt.alt ttt_game ttt_game.c +ttt_game.alt.c westley +westley.alt +ttt.alt_old.c ttt_old.c westley.orig prog.orig diff --git a/1991/westley/Makefile b/1991/westley/Makefile index ecdd9f865..abcf45332 100644 --- a/1991/westley/Makefile +++ b/1991/westley/Makefile @@ -117,8 +117,8 @@ OBJ= ${PROG}.o DATA= TARGET= ${PROG} ttt # -ALT_OBJ= -ALT_TARGET= +ALT_OBJ= ${PROG}.alt.o +ALT_TARGET= ${PROG}.alt ttt.alt ################# @@ -190,6 +190,60 @@ ttt_game.c: westley.c ${CP} -f westley.c ttt_game.c ${CHMOD} +w ttt_game.c + +# alt version +# +# the hint file gives nextmove.alt.c as an example, provide a build rule for it +# +nextmove.alt: nextmove.alt.c ttt_alt + ${CC} ${CFLAGS} -DP=putchar -DN="P(10)" -DQ="P(34)" -DF="S(&X)" \ + -DJ=z[4] -DK=J[14] \ + -DH="w[]={146,7,292,73,448,56,84,273,325,297,108,324,22,40,48,40,17,325}" \ + nextmove.alt.c -o nextmove.alt + +# the ttt_alt script has been added by the judges to make playing westley.alt easy +# +ttt_alt: ttt_alt.sh + ${RM} -f ttt_alt + ${CP} -f ttt_alt.sh ttt_alt + ${CHMOD} +x ttt_alt + +# used by the ttt_alt shell script when playing westley.alt +# +# The ttt_alt script controls what goes into merlyn.alt.c, and how it is used. +# The merlyn.alt program and source represent the best (hopefully) state that +# the program has evolved into thus far. The ttt_alt_game program and source +# represent the current state of the game. +# +merlyn.alt: merlyn.alt.c ttt_alt + @${CC} ${CFLAGS} -DP=putchar -DN="P(10)" -DQ="P(34)" -DF="S(&X)" \ + -DJ=z[4] -DK=J[14] \ + -DH="w[]={146,7,292,73,448,56,84,273,325,297,108,324,22,40,48,40,17,325}" \ + merlyn.alt.c -o merlyn.alt +ttt_alt_game: ttt_alt_game.c ttt_alt + @${CC} ${CFLAGS} -DP=putchar -DN="P(10)" -DQ="P(34)" -DF="S(&X)" \ + -DJ=z[4] -DK=J[14] \ + -DH="w[]={146,7,292,73,448,56,84,273,325,297,108,324,22,40,48,40,17,325}" \ + ttt_alt_game.c -o ttt_alt_game + +# The upper level makefile wants to make these source files if they don't +# already exist. +# +merlyn.alt.c: westley.alt.c + ${RM} -f merlyn.alt.c + ${CP} -f westley.alt.c merlyn.alt.c + ${CHMOD} +w merlyn.alt.c +nextmove.alt.c: westley.alt.c + ${RM} -f nextmove.alt.c + ${CP} -f westley.alt.c nextmove.alt.c + ${CHMOD} +w nextmove.alt.c +ttt_alt_game.c: westley.alt.c + ${RM} -f ttt_alt_game.c + ${CP} -f westley.alt.c ttt_alt_game.c + ${CHMOD} +w ttt_alt_game.c + + + # data files # data: ${DATA} @@ -256,8 +310,10 @@ clean: clobber: clean ${RM} -f ${TARGET} ${ALT_TARGET} - ${RM} -f merlyn merlyn.c nextmove.c nextmove.c + ${RM} -f merlyn merlyn.c nextmove nextmove.c + ${RM} -f merlyn.alt merlyn.alt.c nextmove.alt nextmove.alt.c ${RM} -f ttt_game ttt_game.c ttt_old.c ttt_new.c nextmove + ${RM} -f ttt.alt_game ttt.alt_game.c ttt.alt_old.c ttt_.altnew.c nextmove.alt @-if [ -e sandwich ]; then \ ${RM} -f sandwich; \ echo 'ate sandwich'; \ diff --git a/1991/westley/README.md b/1991/westley/README.md index da639bffa..9b45ab8f5 100644 --- a/1991/westley/README.md +++ b/1991/westley/README.md @@ -4,6 +4,8 @@ make all ``` +There is an [alternate version](#alternate-code) that is supposed to win all the +time. ### Bugs and (Mis)features: @@ -18,7 +20,11 @@ For more detailed information see [1991 westley in bugs.md](/bugs.md#1991-westle ## To use: -Make and run as follows: + +NOTE: we have provided a script to perform the below procedure which we include +for the interested. See the [try](#try) section if you just want to play. + +Make and then run as follows: ```sh @@ -34,7 +40,7 @@ a move on a tic-tac-toe board: 7 8 9 ``` -If you omit `move_location`, then the computer moves first. For your\ +If you omit `move_location`, then the computer moves first. For your next move, recompile `nextmove.c` and play it again: ```sh @@ -45,7 +51,8 @@ make nextmove ### Try: -We have provided the shell script, [ttt](ttt.sh), to make it easier to play the game: +We have provided the shell script, [ttt](ttt.sh), to make it easier to play the +game: ```sh make ttt @@ -54,12 +61,12 @@ make ttt ``` -The shell script determines when the game is over, and automatically\ -replaces `merlyn.c` (copied from [westley.c](westley.c) with an improved version after a loss. The [ttt](ttt.sh) script\ -has two other modes: +The shell script determines when the game is over, and automatically replaces +`merlyn.c` (copied from [westley.c](westley.c) with an improved version after a +loss). The [ttt](ttt.sh) script has two other modes: ```sh -./ttt quitgame # cancel any game in process, revert to merlyn.c +./ttt quitgame # cancel any game in progress, revert to merlyn.c ./ttt clobber # remove all game files, revert to original source ``` @@ -109,6 +116,24 @@ Redirects stderr to `/dev/null` by default. If you need errors or warnings use `-e`. +## Alternate code: + +This version is based on the author's remarks. It is not supposed to lose but it +can lose if you cheat. That's supposed to happen. Can you win any other time? + + +### Alternate build: + + +```sh +make alt +``` + +### Alternate use: + +Rather than use `ttt` try the script `ttt.alt` instead. + + ## Judges' remarks: Can you figure out why the board looks different than the @@ -119,12 +144,12 @@ What happens if you make a move already made? Now go try and draw or better yet win (without cheating which is very easy :-) )! Why is win better than draw? Because everyone knows how to draw: -> Professor Falken: Did you ever play tic-tac-toe? -> Jennifer Mack: Yeah. Of course. -> Falken: But you don't any more. -> Jennifer: No. -> Falken: Why? -> Jennifer: Because it's a boring game. It's always a tie. +> Professor Falken: Did you ever play tic-tac-toe?\ +> Jennifer Mack: Yeah. Of course.\ +> Falken: But you don't any more.\ +> Jennifer: No.\ +> Falken: Why?\ +> Jennifer: Because it's a boring game. It's always a tie.\ > Falken: Exactly. There's no way to win. The game itself is pointless. But back at the [International Obfuscated C Code Contest judges' room](https://www.ioccc.org/https://www.ioccc.org/judges.html) they believe that @@ -153,12 +178,11 @@ The program, when run, reproduces itself with both the player's move and the computer's move added. Recompile THIS program (using the same compile line) and repeat until the game is finished. -If the computer wins, the "straight face" in the upper right-hand -corner ":-|" will change into a happy face ":-)". If it is a draw, -the face does not change. If the computer loses, the board is -blanked and the face changes into a sad face ":-(". If this -happens, the blank board should replace the original program; the -computer changes its play and will continue to do so until it no +If the computer wins, the "straight face" in the upper right-hand corner, ":-|", +will change into a happy face, ":-)". If it is a draw, the face does not +change. If the computer loses, the board is blanked and the face changes into a +sad face, ":-(". If this happens, the blank board should replace the original +program; the computer changes its play and will continue to do so until it no longer loses games. If you want a program that never loses, simply replace the string @@ -166,47 +190,47 @@ If you want a program that never loses, simply replace the string ### How it works -The vertical "bars" of the grid are identical functions, with the -name of the function as a(), b(), or c(). After each function is -called, the global variables X and O contain bitmasks of where all -the Xs and Os are placed. The statement: +The vertical "bars" of the grid are identical functions, with the name of the +function as `a()`, `b()`, or `c()`. After each function is called, the global +variables `X` and `O` contain bitmasks of where all the `X`s and `O`s are placed. +The statement: ```c X=- -1; -`` +``` -evaluates to 1, -1, or -2 when X is 1 and is one of "X", -"0", or " ". The function S(&X) sets the appropriate bits in -(global var) X and O and resets the value of &X to 1. This is how -the current position is computed. +evaluates to `1`, `-1`, or `-2` when `X` is `1` and `` is one of `"X"`, +`"0"`, or `" "`. The function `S(&X)` sets the appropriate bits in (global +vars) `X` and `O` and resets the value of `&X` to `1`. This is how the current +position is computed. -The player's move is OR'd into the X mask, and (if it is the -opening move) the strategy string's first character is set to the -player's first move (or "5" if the computer moves first). +The player's move is bitwise ORed into the `X` mask, and (if it is the opening +move) the strategy string's first character is set to the player's first move +(or `5` if the computer moves first). -The evalution function y(M) checks if the mask has a winning -pattern (any of the first eight bitmasks of the w[N array), and -sets the variable q to 0 if it does. +The evaluation function `y(M)` checks if the mask has a winning pattern (any of +the first eight bitmasks of the `w[N]` array), and sets the variable `q` to `0` +if it does. -The player's move is evaluated to see if the human has won. The -smiley is set to :-) or :-( depending on this. Also, if the human -has won, the digit in the strategy string is decremented to change -the computer's play for next game. +The player's move is evaluated to see if the human has won. The smiley is set +to ":-)" or ":-(" depending on this. Also, if the human has won, the digit in +the strategy string is decremented to change the computer's play for the next +round. -If the human has NOT won, the e(N,M) function evaluates if ANY move -not in mask N can produce a win in mask M. The first evaluation -e(X,O) checks if O can make a legal winning move. If so, the +If the human has NOT won, the `e(N,M)` function evaluates if ANY move +not in mask `N` can produce a win in mask `M`. The first evaluation +`e(X,O)` checks if `O` can make a legal winning move. If so, the computer has a winning move and makes it. If not, the smiley is -set to :-|, and a non-winning move is generated. +set to ":-|", and a non-winning move is generated. -A non-winning move first checks if X can win in one move; if so, +A non-winning move first checks if `X` can win in one move; if so, this move is selected, blocking the win. Otherwise, a move is generated by looking down the list of "move templates". The first move template that generates a move that is NOT already occupied by -an X or O is returned. +an `X` or `O` is returned. The "move templates" are static tic-tac-toe positions that generate -possible moves by making the e() function return "winning" moves, +possible moves by making the `e()` function return "winning" moves, e.g. the template: ``` @@ -215,14 +239,13 @@ O , O (this is the value 40; 2^3+2^5) . . . ("O"s are 1 bits, "." and "," are 0 bits) ``` -...will make the e() function return a center move, as -this is the only move that produces three in a row. Notice that -the computer does not consider which cells contain Xs and Os when -making a template move, only which cells are empty and not-empty. -This makes for unusual play. +...will make the `e()` function return a center move, as this is the only move +that produces three in a row. Notice that the computer does not consider which +cells contain `X`s and `O`s when making a template move, only which cells are +empty and not-empty. This makes for unusual play. -The templates are carefully chosen to eventually block all traps -that X can try, by just blundering in the way. +The templates are carefully chosen to eventually block all traps that `X` can +try, by just blundering in the way. Also note that the winning & strategy templates are part of the compile line, making it possible to change the rules of the game by @@ -272,10 +295,10 @@ O , O O , O ``` -A digit of "9" means start with the first template, "8" starts at +A digit of `9` means start with the first template, `8` starts at the second, etc. The templates are scanned until a legal move is found. A template is scanned from bottom to top, right to left -(i.e. move 9 is tested first, then 8, down to move 1). +(i.e. move `9` is tested first, then `8`, down to move `1`). ## Copyright and CC BY-SA 4.0 License: diff --git a/1991/westley/ttt.alt.sh b/1991/westley/ttt.alt.sh new file mode 100755 index 000000000..92146f8d1 --- /dev/null +++ b/1991/westley/ttt.alt.sh @@ -0,0 +1,200 @@ +#!/usr/bin/env bash +# +# play tic-tac-toe + +# parse args +# + +export USAGE="usage: $0 [-h] [-e] + -h show this help and exit + -e show compiler stdout + + commands: + ./ttt.alt [move_digit] play a place + ./ttt.alt quitgame quit the game + ./ttt.alt clobber clean the state of the game +" + +export E_FLAG= +while getopts :he flag; do + case "$flag" in + h) echo "$USAGE" 1>&2 + exit 2 + ;; + e) E_FLAG="1" + ;; + \?) echo "$0: ERROR: invalid option: -$OPTARG" 1>&2 + exit 3 + ;; + :) echo "$0: ERROR: option -$OPTARG requires an argument" 1>&2 + exit 3 + ;; + *) + ;; + esac +done + +# check args +# +shift $(( OPTIND - 1 )); +if [[ $# -gt 1 ]]; then + echo "$USAGE" 1>&2 + exit 1 +elif [[ $# -eq 1 ]]; then + move="$1" +else + move= +fi + +# catch the clobber case +# +if [[ clobber = "$move" ]]; then + echo "ttt.alt: rm -f ttt.alt_game ttt.alt_game.o ttt.alt_game.c ttt.alt_old.c ttt.alt_new.c" 1>&2 + rm -f ttt.alt_game ttt.alt_game.o ttt.alt_game.c ttt.alt_old.c ttt.alt_new.c + echo "ttt.alt: rm -f merlyn.alt.c merlyn.o merlyn" 1>&2 + rm -f merlyn.alt.c merlyn.o merlyn + echo "ttt.alt: removed all but the original source" 1>&2 + exit 0 +fi + +# catch the quitgame case +# +if [[ quitgame = "$move" ]]; then + echo "ttt.alt: rm -f ttt.alt_game ttt.alt_game.o ttt.alt_game.c ttt.alt_old.c ttt.alt_new.c" 1>&2 + rm -f ttt.alt_game ttt.alt_game.o ttt.alt_game.c ttt.alt_old.c ttt.alt_new.c + echo "ttt.alt: current game removed, perhaps you were going to lose? :-)" 1>&2 + exit 0 +fi + +# watch for bad args +# +if [[ $# -eq 1 ]]; then + case "$move" in + 1|2|3|4|5|6|7|8|9) ;; + *) echo "ttt.alt: bad argument" 1>&2 + echo "usage: ./ttt.alt [move_digit]" 1>&2 + echo " ./ttt.alt quitgame" 1>&2 + echo " ./ttt.alt clobber" 1>&2 + exit 2 ;; + esac +fi + +# be sure that we have the merlyn.alt.c source +# +if [[ ! -f merlyn.alt.c ]]; then + if [[ -f westley.alt.c ]]; then + echo "ttt.alt: No merlyn.alt.c around these parts, using a copy of westley.alt.c" 1>&2 + cp westley.alt.c merlyn.alt.c + chmod +w merlyn.alt.c + else + echo "ttt.alt: Ouch! merlyn.alt.c and no westley.alt.c are gone!" 1>&2 + exit 3 + fi + # check to see if the copy worked + if [[ ! -f merlyn.alt.c ]]; then + echo "ttt.alt: Darn, couldn't copy westley.alt.c to merlyn.alt.c" 1>&2 + exit 4 + fi +fi + +# be sure we have the merlyn program +# +if [[ ! -f merlyn ]]; then + export status=0 + if [[ -n $E_FLAG ]]; then + echo "ttt.alt: make merlyn" 1>&2 + make merlyn + status=$? + else + make merlyn 2>/dev/null + status=$? + fi + if [[ "$status" -ne 0 ]]; then + echo "ttt.alt: something is wrong, fix merlyn.alt.c and build it yourself!" 1>&2 + echo " or maybe type: ./ttt.alt clobber" 1>&2 + exit 5 + fi + rm -f ttt.alt_game.c +fi + +# If we don't have a ttt.alt_game.c, or we cannot write it, make a new ttt.alt_game.c +# +if [[ ! -w ttt.alt_game.c ]]; then + rm -f ttt.alt_game.c + if [[ -z "$move" ]]; then + ./merlyn | tee ttt.alt_game.c + else + ./merlyn "$move" | tee ttt.alt_game.c + fi + chmod +w ttt.alt_game.c + +# If we have a ttt.alt_game.c, then assume that we are in the process of playing +# +else + rm -f ttt.alt_game ttt.alt_new.c + export status=0 + if [[ -n $E_FLAG ]]; then + echo "ttt.alt: make ttt.alt_game" 1>&2 + make ttt.alt_game + status=$? + else + make ttt.alt_game 2>/dev/null + status=$? + fi + if [[ "$status" -ne 0 ]]; then + echo "ttt.alt: something is wrong, fix ttt.alt_game.c and build it yourself!" 1>&2 + echo " or maybe type: ./ttt.alt quitgame" 1>&2 + exit 6 + fi + if [[ -z "$move" ]]; then + ./ttt.alt_game | tee ttt.alt_new.c + else + ./ttt.alt_game "$move" | tee ttt.alt_new.c + fi + chmod +w ttt.alt_new.c + if [[ -s ttt.alt_new.c ]]; then + mv ttt.alt_game.c ttt.alt_old.c + mv ttt.alt_new.c ttt.alt_game.c + +# Check for win, lose, or draw +# For a win or draw, copy merlyn.alt.c to ttt.alt_game.c +# For a loss, copy ttt.alt_game.c to merlyn.alt.c, as it is now better +# Also remove the executable for the file replaced +# For anything else, game in progress, do not do anything + + # SC2006 (style): Use $(...) notation instead of legacy backticks `...`. + # shellcheck disable=SC2006 + if [[ -n "`grep ':-(' ttt.alt_game.c`" ]]; then + echo + echo "ttt.alt: I lose...I won't make THAT mistake again!" + chmod +w merlyn.alt.c + mv ttt.alt_game.c merlyn.alt.c + rm -f merlyn ttt.alt_game + else + # SC2006 (style): Use $(...) notation instead of legacy backticks `...`. + # shellcheck disable=SC2006 + if [[ -n "`grep ':-)' ttt.alt_game.c`" ]]; then + echo + echo "ttt.alt: I win!" + cp merlyn.alt.c ttt.alt_game.c + rm -f ttt.alt_game + else + # SC2006 (style): Use $(...) notation instead of legacy backticks `...`. + # shellcheck disable=SC2006 + if [[ -z "`grep 'X=-. ' ttt.alt_game.c`" && -z "`grep '^. ' ttt.alt_game.c`" ]]; then + echo + echo "ttt.alt: It's a draw - play again?" + cp merlyn.alt.c ttt.alt_game.c + rm -f ttt.alt_game + fi + fi + fi + + else + echo "ttt.alt: something is wrong, maybe ttt.alt_old.c will help" 1>&2 + echo " or maybe type: ./ttt.alt quitgame" 1>&2 + echo " or maybe type: ./ttt.alt clobber" 1>&2 + exit 7 + fi +fi + diff --git a/1991/westley/westley.alt.c b/1991/westley/westley.alt.c new file mode 100644 index 000000000..279041ca3 --- /dev/null +++ b/1991/westley/westley.alt.c @@ -0,0 +1,26 @@ + a(X){/*/X=- a(X){/*/X=- + -1;F;X=- -1;F;X=- + -1;F;}/*/ -1;F;}/*/ +char z[][100]={"char z[][100]={","a(X){/*/X=-","-1;F;X=-","-1;F;}/*/","9883857753 :-|", +"int q,i,j,k,X,O=0,H;S(x)int*x;{X+=X;O+=O;*x+1?*x+2||X++:O++;*x=1;}L(n){for(*", +"z[i=1]=n+97;i<4;i++)M(256),s(i),M(128),s(i),M(64),N;X*=8;O*=8;}s(R){char*r=z", +"[R];for(q&&Q;*r;)P(*r++);q&&(Q,P(44));}M(m){P(9);i-2||P(X&m?88:O&m?48:32);P(", +"9);}y(A){for(j=8;j;)~A&w[--j]||(q=0);}e(W,Z){for(i-=i*q;i<9&&q;)y(W|(1<4&&N", +";s(q=12);P(48);P('}');P(59);N;q=0;L(1);for(i=5;i<13;)s(i++),N;L(2);}",0}; + b(X){/*/X=- b(X){/*/X=- + -1;F;X=- -1;F;X=- + -1;F;}/*/ -1;F;}/*/ +int q,i,j,k,X,O=0,H;S(x)int*x;{X+=X;O+=O;*x+1?*x+2||X++:O++;*x=1;}L(n){for(* +z[i=1]=n+97;i<4;i++)M(256),s(i),M(128),s(i),M(64),N;X*=8;O*=8;}s(R){char*r=z +[R];for(q&&Q;*r;)P(*r++);q&&(Q,P(44));}M(m){P(9);i-2||P(X&m?88:O&m?48:32);P( +9);}y(A){for(j=8;j;)~A&w[--j]||(q=0);}e(W,Z){for(i-=i*q;i<9&&q;)y(W|(1<4&&N +;s(q=12);P(48);P('}');P(59);N;q=0;L(1);for(i=5;i<13;)s(i++),N;L(2);} + c(X){/*/X=- c(X){/*/X=- + -1;F;X=- -1;F;X=- + -1;F;}/*/ -1;F;}/*/ diff --git a/thanks-for-fixes.md b/thanks-for-fixes.md index 17e78bfd0..038657dad 100644 --- a/thanks-for-fixes.md +++ b/thanks-for-fixes.md @@ -1129,6 +1129,14 @@ him): `k` for forward, `h` for left and `l` for right. This version also has a more useful way to exit, just entering `q` followed by enter. +## [1991/davidguy](1991/davidguy/davidguy.c) ([README.md](1991/davidguy/README.md])) + +As some systems like macOS can be particular about not declaring functions Cody +added to the Makefile some `-include` options. These appear to not be strictly +necessary but it was done due to other syscalls being a problem not being +declared first. + + ## [1991/dds](1991/dds/dds.c) ([README.md](1991/dds/README.md])) Cody fixed a segfault that prevented this entry from working in any condition @@ -1282,6 +1290,12 @@ also improved it so that warnings/errors/about to compile messages are not shown unless the `-e` option is used. This is because the errors being shown kind of ruins the experience. Finally he made it pass ShellCheck. +Cody also added the alt version which is based on the author's remarks, a +version that supposedly (:-) ) always wins. + +Cody also fixed the make clobber rule where a file was left lying about when it +should have been removed. + ## [1992/adrian](1992/adrian/adrian.c) ([README.md](1992/adrian/README.md]))