Add 2020/carlini/try.sh, update bugs.md
Why a try.sh for this? It shows that you can also automate the play (it happens to come from the author's remarks, however, so there's that too). Then it tells you to be serious by playing with a friend, either real or imagined, rather than doing something so silly. Update bugs.md with a INABIAF section. The README.md file has been format/typo checked.
This commit is contained in:
1 parent
67b09c403a
commit
3bf3ac7024
4 files changed
+116
-43
No files matched your search
+66
-43
@@ -5,6 +5,17 @@ make
|
||||
```
|
||||
|
||||
|
||||
### Bugs and (Mis)features:
|
||||
|
||||
The current status of this entry is:
|
||||
|
||||
```
|
||||
STATUS: INABIAF - please **DO NOT** fix
|
||||
```
|
||||
|
||||
For more detailed information see [2020 carlini in bugs.md](/bugs.md#2020-carlini).
|
||||
|
||||
|
||||
## To use:
|
||||
|
||||
```sh
|
||||
@@ -15,16 +26,22 @@ make
|
||||
### Try:
|
||||
|
||||
```sh
|
||||
# Play with a friend, P1 and P2, squares are numbered 1..9
|
||||
./try.sh
|
||||
```
|
||||
|
||||
Or if you actually want to play:
|
||||
|
||||
```sh
|
||||
# Play with a friend, real or imagined, P1 and P2, squares are numbered 1..9
|
||||
./prog
|
||||
```
|
||||
|
||||
|
||||
## Judges' remarks:
|
||||
|
||||
This program consists of a single print statement wrapped in a while loop. You
|
||||
would not think that this would amount to much, but you would be very, very
|
||||
wrong. A clue to what is happening and how this works is encoded in the
|
||||
This program consists of a single `printf(3)` statement wrapped in a `while`
|
||||
loop. You would not think that this would amount to much, but you would be very,
|
||||
very wrong. A clue to what is happening and how this works is encoded in the
|
||||
ASCII art of the program source.
|
||||
|
||||
|
||||
@@ -51,9 +68,10 @@ Alternates between P1 and P2. Enter a digit [1-9] to move:
|
||||
|
||||
The game ends if:
|
||||
|
||||
* A player completes three in a row; that player wins
|
||||
* All squares are taken; neither player wins
|
||||
* A player makes an illegal move; their opponent wins
|
||||
* A player completes three in a row; that player wins.
|
||||
* All squares are taken; neither player wins.
|
||||
* A player makes an illegal move; their opponent wins.
|
||||
|
||||
|
||||
### LIMITATIONS
|
||||
|
||||
@@ -69,8 +87,8 @@ the program ... is hard at work processing your move! That is! Please be
|
||||
patient.
|
||||
|
||||
After macro expansion the format string is roughly 100K. This makes some
|
||||
compilers unhappy, and others slow. (For example, passing GCC the flags -Wall
|
||||
-Wextra -pedantic will result in a warning about oversized strings.)
|
||||
compilers unhappy, and others slow. (For example, passing GCC the flags `-Wall
|
||||
-Wextra -pedantic` will result in a warning about oversized strings.)
|
||||
|
||||
Under some terminals the program may exit early. The following should always work:
|
||||
|
||||
@@ -80,7 +98,7 @@ echo "1 2 3 4 5 6 7" | ./prog
|
||||
|
||||
### OBFUSCATION
|
||||
|
||||
The entirety of the program consists of a single iterated call to printf.
|
||||
The entirety of the program consists of a single iterated call to `printf(3)`.
|
||||
|
||||
```c
|
||||
int main() {
|
||||
@@ -88,25 +106,27 @@ int main() {
|
||||
}
|
||||
```
|
||||
|
||||
Here, `fmt` is a single string, and `arg` is a series of arguments to printf.
|
||||
Here, `fmt` is a single string, and `arg` is a series of arguments to
|
||||
`printf(3)`.
|
||||
|
||||
While its primary purpose is to serve as The One True Debugger, printf also happens
|
||||
While its primary purpose is to serve as The One True Debugger, `printf(3)` also happens
|
||||
to be Turing complete. (See "Control-Flow Bending: On the Effectiveness of Control-Flow
|
||||
Integrity" where we introduced this in an actual, published, academic paper. The
|
||||
things you can get away with sometimes.)
|
||||
|
||||
We <strike>ab</strike>use this fact to implement the logic of tic-tac-toe entirely within
|
||||
this one printf call (and a call to scanf() to read user input).
|
||||
this one `printf(3)` call (and a call to `scanf(3)` to read user input).
|
||||
|
||||
Here's (briefly) how it works.
|
||||
|
||||
|
||||
#### Preliminaries
|
||||
|
||||
This program uses three printf format specifiers.
|
||||
This program uses three `printf(3)` format specifiers.
|
||||
|
||||
- `%d` takes an integer argument and prints it
|
||||
- `%d` takes an integer argument and prints it.
|
||||
|
||||
- `%s` takes a string argument and prints it
|
||||
- `%s` takes a string argument and prints it.
|
||||
|
||||
- `%n` takes a pointer and writes (!!) the number of bytes printed so far.
|
||||
|
||||
@@ -114,13 +134,13 @@ Okay, everyone probably knows this. Let's get a bit more advanced.
|
||||
|
||||
Format specifiers can take extra "arguments".
|
||||
|
||||
- `"%hhn"`: store the number of bytes written mod 256 to the char pointer
|
||||
- `"%hhn"`: store the number of bytes written mod 256 to the `char` pointer.
|
||||
|
||||
- `"%2$d"`: print argument 2 to printf (and not the sequentially next argument)
|
||||
- `"%2$d"`: print argument 2 to `printf(3)` (and not the sequentially next argument).
|
||||
|
||||
- `"%8d"`: pad the printed integer to 8 characters
|
||||
- `"%8d"`: pad the printed integer to 8 characters.
|
||||
|
||||
- `"%3$.*4$d"`: print argument 3 to printf with as many zeros as in argument 4.
|
||||
- `"%3$.*4$d"`: print argument 3 to `printf(3)` with as many zeros as in argument 4.
|
||||
|
||||
For example, the following expression
|
||||
|
||||
@@ -135,16 +155,17 @@ x = 10;
|
||||
```
|
||||
|
||||
because it will print out `0000000005` (5 padded to size 10) and then write the
|
||||
number of bytes written to x.
|
||||
number of bytes written to `x`.
|
||||
|
||||
#### Printf Oriented Programming
|
||||
|
||||
#### `printf(3)` Oriented Programming
|
||||
|
||||
Alright, now we can get to the real fun.
|
||||
|
||||
We perform arbitrary computation with printf treating memory as a binary
|
||||
We perform arbitrary computation with `printf(3)` treating memory as a binary
|
||||
array--one bit per pair of bytes:
|
||||
|
||||
- The zero bit is represented by the sequence `00 00`
|
||||
- The zero bit is represented by the sequence `00 00`.
|
||||
|
||||
- The one-bit is represented by the sequence `xx 00` where `xx` is any non-zero byte.
|
||||
|
||||
@@ -190,13 +211,14 @@ and again, because `strlen(x)` is either `1` or `0` we have
|
||||
From here we can compute any binary circuit. Doing something efficient,
|
||||
though, still takes work.
|
||||
|
||||
|
||||
#### Tic-Tac-Toe
|
||||
|
||||
The game itself is represented as a board of 18 bits, 9 bits per player, along
|
||||
with a turn counter that alternates between player 1 and player 2.
|
||||
|
||||
To detect who has won, we implement the following logic. Let A, B, and C be
|
||||
pointers to three squares in a row to test, and D be where to save if there is a
|
||||
To detect who has won, we implement the following logic. Let `A`, `B`, and `C` be
|
||||
pointers to three squares in a row to test, and `D` be where to save if there is a
|
||||
win or not.
|
||||
|
||||
```c
|
||||
@@ -217,7 +239,7 @@ the following expression
|
||||
"%1$hhn%1$s" (repeated 256 times)
|
||||
```
|
||||
|
||||
where argument 1 is a pointer to a temporary variable followed by a null byte.
|
||||
where argument 1 is a pointer to a temporary variable followed by a NUL byte.
|
||||
|
||||
This works because if the current count is 0 mod 256, then `"%1$hhn"` will write
|
||||
zero to argument 1 and then "%1$s" will never emit any text. If, on the other
|
||||
@@ -229,8 +251,8 @@ Checking if there has been an invalid move is achieved similarly.
|
||||
|
||||
In order to decide what to print out, we have to cast the "in-memory" array of
|
||||
bits to Xs and Os to print out. This is actually rather straightforward. Given
|
||||
in 1$ the pointer to player 1's square, and 2$ the pointer to player 2's, and
|
||||
in 3$ the pointer to the board string, we can compute
|
||||
in `1$` the pointer to player 1's square, and `2$` the pointer to player 2's, and
|
||||
in `3$` the pointer to the board string, we can compute
|
||||
|
||||
```c
|
||||
"%1$s" (repeated 47 times) "%2$s" (repeated 56 times) %1$32d%3$hhn"
|
||||
@@ -242,21 +264,22 @@ which will, in effect, compute
|
||||
*r3 = (*r1) * 47 + (*r2) * 56 + 32
|
||||
```
|
||||
|
||||
which will output `' '` if neither are true, `'X'` if r1 is, or `'O'` if r2 is.
|
||||
which will output `' '` if neither are true, `'X'` if `r1` is true, or `'O'` if
|
||||
`r2` is true.
|
||||
|
||||
|
||||
#### Further Obfuscations
|
||||
|
||||
In order to be able to finally display the board, while still only using one
|
||||
printf statement, we finish the statement with
|
||||
`printf(3)` statement, we finish the statement with
|
||||
|
||||
```c
|
||||
"\n\033[2J\n%26$s"
|
||||
```
|
||||
|
||||
which is the escape sequence to clear the screen, and then prints argument 26.
|
||||
Argument 26 is a pointer to a char* in memory, that initially is undefined,
|
||||
but within the printf statement we will construct this string to look like a
|
||||
Argument 26 is a pointer to a `char*` in memory, that initially is undefined,
|
||||
but within the `printf(3)` statement we will construct this string to look like a
|
||||
tic-tac-toe board.
|
||||
|
||||
After the board, we need to print one of the following strings:
|
||||
@@ -282,10 +305,10 @@ before, we set byte four to be
|
||||
|
||||
The byte `'I'` and `'S'` can always be the same, and we do the same for `'E'`/`'N'`.
|
||||
|
||||
We do this same on-the-fly creation of the `scanf()` format string, but for a
|
||||
different reason. We first want to run `printf()` to show the first board, and
|
||||
then alternate between runs to `scanf()` and `printf()` reading and then
|
||||
displaying moves. Importantly, we *do not* want a final scanf when the game
|
||||
We do this same on-the-fly creation of the `scanf(3)` format string, but for a
|
||||
different reason. We first want to run `printf(3)` to show the first board, and
|
||||
then alternate between runs to `scanf(3)` and `printf(3)` reading and then
|
||||
displaying moves. Importantly, we *do not* want a final `scanf(3)` when the game
|
||||
ends. It should just exit.
|
||||
|
||||
One option would be to implement the logic as
|
||||
@@ -298,7 +321,7 @@ while (*ok) {
|
||||
}
|
||||
```
|
||||
|
||||
but this would DOUBLE the number of calls to printf we require. So instead we
|
||||
but this would DOUBLE the number of calls to `printf(3)` we require. So instead we
|
||||
implement it like this
|
||||
|
||||
```c
|
||||
@@ -308,13 +331,13 @@ while (*ok) {
|
||||
}
|
||||
```
|
||||
|
||||
(In reality we actually pass `scanf()` as an argument to avoid the extra
|
||||
(In reality we actually pass `scanf(3)` as an argument to avoid the extra
|
||||
statement, but it has the same effect.)
|
||||
|
||||
Notice there is now no initial `printf()`. In order make sure the program doesn't
|
||||
block before the first `printf()`, but we initialize the `scanf()` format to the null
|
||||
string so that it returns right away without blocking. The first time the `printf()`
|
||||
call runs, it writes out `"%hhd"` to create the `scanf()` format string.
|
||||
Notice there is now no initial `printf(3)`. In order make sure the program doesn't
|
||||
block before the first `printf(3)`, we initialize the `scanf(3)` format to the NUL
|
||||
string so that it returns right away without blocking. The first time the
|
||||
`printf(3)` call runs, it writes out `"%hhd"` to create the `scanf(3)` format string.
|
||||
|
||||
|
||||
## Copyright and CC BY-SA 4.0 License:
|
||||
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# try.sh - demonstrate IOCCC winner 2020/carlini
|
||||
#
|
||||
|
||||
# make sure CC is set so that when we do make CC="$CC" it isn't empty. Doing it
|
||||
# this way allows us to have the user specify a different compiler in an easy
|
||||
# way.
|
||||
if [[ -z "$CC" ]]; then
|
||||
CC="cc"
|
||||
fi
|
||||
|
||||
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: echo 1 2 3 4 5 6 7 | ./prog: "
|
||||
echo 1>&2
|
||||
echo 1 2 3 4 5 6 7 | ./prog
|
||||
echo 1>&2
|
||||
|
||||
echo "... now go and play for real, with a friend, real or imagined." 1>&2
|
||||
@@ -3575,6 +3575,25 @@ It will also show funny output with more than one arg. This should not be fixed
|
||||
either. But can you figure out why this happens?
|
||||
|
||||
|
||||
## 2020 carlini
|
||||
|
||||
### STATUS: INABIAF - please **DO NOT** fix
|
||||
### Source code: [2020/carlini/prog.c](2020/carlini/prog.c)
|
||||
### Information: [2020/carlini/README.md](2020/carlini/README.md)
|
||||
|
||||
The author stated that bad things happen if the entered move is outside of the
|
||||
range [1..9]. We observed a crash but we also observed a tie and other things
|
||||
besides (say with the input `-1`, `-`, `-10` and others).
|
||||
|
||||
If a player makes a move over their opponent's place they will automatically
|
||||
lose.
|
||||
|
||||
If a player tries to play a move they already played they will forfeit their
|
||||
move.
|
||||
|
||||
If you have audible bells enabled the program will beep at every turn.
|
||||
|
||||
|
||||
## 2020 ferguson1
|
||||
|
||||
### STATUS: INABIAF - please **DO NOT** fix
|
||||
|
||||
@@ -4291,6 +4291,14 @@ showing nothing at all.
|
||||
Cody also added the [try.sh](/2020/burton/try.sh) script.
|
||||
|
||||
|
||||
## <a name="2020_carlini"></a>[2020/carlini](/2020/carlini/prog.c) ([README.md](/2020/carlini/README.md))
|
||||
|
||||
[Cody](#cody) added the [try.sh](/2020/carlini/try.sh) script which although at
|
||||
first glance might not appear to have a point, it actually does, namely showing
|
||||
how you can automate play and then reminding you to actually play for real, with
|
||||
a friend, whether that's real or imagined.
|
||||
|
||||
|
||||
## <a name="2020_endoh2"></a>[2020/endoh2](/2020/endoh2/prog.c) ([README.md](/2020/endoh2/README.md))
|
||||
|
||||
[Cody](#cody) copied the files from the spoiler.zip file that was password protected with
|
||||
|
||||
Reference in new issue
Block a user