Merge pull request #1307 from xexyl/1991-brnstnd-fmt
This commit is contained in:
15 files changed
+464
-135
No files matched your search
@@ -1,3 +1,4 @@
|
||||
brnstnd
|
||||
brnstnd.orig
|
||||
prog.orig
|
||||
sorta
|
||||
@@ -133,6 +133,7 @@ all: data ${TARGET}
|
||||
|
||||
${PROG}: ${PROG}.c
|
||||
${CC} ${CFLAGS} $< -o $@ ${LDFLAGS}
|
||||
${LN} -sf $@ sorta
|
||||
|
||||
# alternative executable
|
||||
#
|
||||
|
||||
+26
-26
@@ -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 `<p0> <p1>` 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 `<p0> <p1>` 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()
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
#
|
||||
|
||||
@@ -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:
|
||||
|
||||
+24
-23
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
+59
-3
@@ -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'; \
|
||||
|
||||
+77
-54
@@ -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=- <char> -1;
|
||||
``
|
||||
```
|
||||
|
||||
evaluates to 1, -1, or -2 when X is 1 and <char> 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 `<char>` 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:
|
||||
|
||||
Executable
+200
@@ -0,0 +1,200 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# play tic-tac-toe
|
||||
|
||||
# parse args
|
||||
#
|
||||
|
||||
export USAGE="usage: $0 [-h] [-e] <command>
|
||||
-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
|
||||
|
||||
@@ -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<<i++&",
|
||||
"~Z));}R(){for(k=J[*J-48]-40;k;)e(w[k--],X|O);}main(u,v)char**v;{a(q=1);b(1);",
|
||||
"c(1);*J=--u?O?*J:*v[1]:53;X|=u<<57-*v[u];y(X);K=40+q;q?e(O,X),q&&(K='|'),e(X",
|
||||
",O),R(),O|=1<<--i:J[*J-48+(X=O=0)]--;L(q=0);for(s(i=0);q=i<12;)s(i++),i>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<<i++&
|
||||
~Z));}R(){for(k=J[*J-48]-40;k;)e(w[k--],X|O);}main(u,v)char**v;{a(q=1);b(1);
|
||||
c(1);*J=--u?O?*J:*v[1]:53;X|=u<<57-*v[u];y(X);K=40+q;q?e(O,X),q&&(K='|'),e(X
|
||||
,O),R(),O|=1<<--i:J[*J-48+(X=O=0)]--;L(q=0);for(s(i=0);q=i<12;)s(i++),i>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;}/*/
|
||||
@@ -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]))
|
||||
|
||||
|
||||
Reference in new issue
Block a user