Merge pull request #1440 from xexyl/bmeyer2k

This commit is contained in:
Landon Curt Noll authored and GitHub committed 2023-11-16 07:27:53 -07:00
commit 19c50d77c7
17 files changed
+311 -250

No files matched your search

+5 -1
View File
@@ -41,7 +41,7 @@ include ../../var.mk
CSILENCE= -Wno-char-subscripts -Wno-error -Wno-implicit-function-declaration \
-Wno-int-conversion -Wno-logical-op-parentheses -Wno-pedantic \
-Wno-return-type -Wno-unknown-escape-sequence -Wno-unused-value \
-Wno-deprecated-non-prototype
-Wno-deprecated-non-prototype -Wno-implicit-int
# Common C compiler warning flags
#
@@ -140,6 +140,10 @@ ${PROG}: ${PROG}.c
alt: data ${ALT_TARGET}
@${TRUE}
${PROG}.alt: ${PROG}.alt.c
${CC} ${CFLAGS} $< -o $@ ${LDFLAGS}
# data files
#
data: ${DATA}
+5 -3
View File
@@ -28,9 +28,11 @@ bugs.md](/bugs.md#1991-buzzard).
## Alternate code:
This version changes the keys `f` for forward, `l` for left and `r` for right to
`k` for forward, `l` for right and `h` for left, which is more natural for those
who use vi(m). Also one can just hit `q` followed by enter to quit the maze.
This version changes the keys `f` for forward, `l` for left and `r` for right by
default to `k` for forward, `l` for right and `h` for left, which is more
natural for those who use vi(m). Also one can just hit `q` followed by enter to
quit the maze. It is problematic to reconfigure the keys except by modifying the
code directly so the keys are not made a `-D` at the compiler.
### Alternate build:
+1 -1
View File
@@ -1,7 +1,7 @@
#include <stdio.h>
#define X(s) (!(s&3)-((s&3)==2))
#define W while
char Z[82][82],A,B,f,g=26;z(q)char**q;{return atoi(q);}m(d,l){return
char Z[82][82],A,B,f,g=26;z(q)char*q;{return atoi(q);}m(d,l){return
Z[ B + X ( f +
3) * d+l *X(f+ 2 )][ A+X ( f ) * d +
l* X ( f + 3 ) ] ;}int
+1 -1
View File
@@ -1,7 +1,7 @@
#include <stdio.h>
#define X(s) (!(s&3)-((s&3)==2))
#define W while
char Z[82][82],A,B,f,g=26;z(q)char**q;{return atoi(q);}m(d,l){return
char Z[82][82],A,B,f,g=26;z(q)char*q;{return atoi(q);}m(d,l){return
Z[ B + X ( f +
3) * d+l *X(f+ 2 )][ A+X ( f ) * d +
l* X ( f + 3 ) ] ;}int
-2
View File
@@ -1,6 +1,4 @@
westley
whereami
whereami.alt
westley.alt
westley.orig
prog.orig
+2 -8
View File
@@ -121,7 +121,7 @@ ALT_TARGET= ${PROG}.alt
# build the entry
#################
#
all: data ${TARGET} whereami whereami.alt
all: data ${TARGET}
@${TRUE}
.PHONY: all alt data everything diff_orig_prog diff_prog_orig \
@@ -133,12 +133,9 @@ ${PROG}: ${PROG}.c
${CC} ${CFLAGS} $< -o $@ ${LDFLAGS}
@echo "NOTE: your terminal must be at least 80 columns wide for this to work right"
whereami: whereami.c
${CC} ${CFLAGS} $< -o $@ ${LDFLAGS} -lcurses
# alternative executable
#
alt: data ${ALT_TARGET} whereami.alt
alt: data ${ALT_TARGET}
@${TRUE}
${PROG}.alt: ${PROG}.alt.c
@@ -146,9 +143,6 @@ ${PROG}.alt: ${PROG}.alt.c
@echo "NOTE: your terminal must be at least 80 columns wide for this to work right"
whereami.alt: whereami.alt.c
${CC} ${CFLAGS} $< -o $@ ${LDFLAGS} -lcurses
# data files
#
data: ${DATA}
+42 -49
View File
@@ -7,42 +7,27 @@
#
# This script will first try compiling the code and alt code (alt = US only with
# higher resolution, based on the author's remarks) and then if all is OK it
# tries to make the whereami and whereami.alt programs. If that fails the
# programs used will be westley and westley.alt; otherwise the programs will be
# whereami and whereami.alt. One can pass CC=foo to set the compiler, defaulting
# to cc.
# will continue.
#
# The difference between whereami and westley is that the former first checks
# that the number of columns is at least 80. The programs whereami and
# whereami.alt can be deceived by way of doing:
# The whereami.sh and whereami.alt.sh scripts correspond to westley.c and
# westley.alt.c but they check that the number of columns is at least 80. If
# it's not at least 80 then it's an error. The scripts can be deceived by doing
# something like:
#
# COLUMNS=100 ./whereami lat long
# COLUMNS=100 ./whereami.sh lat long
#
# even if the number of columns is < 80 but there's nothing that can be done
# about that. This script does not have that problem, however, so it's nice to
# use for that purpose if nothing else.
# about that.
#
# If westley or westley.alt cannot compile then it is an error and the script
# will exit 4, corresponding to the same code that whereami.c and whereami.alt.c
# exit with if westley.c or westley.alt.c cannot be compiled.
# will exit.
#
# If whereami or whereami.alt cannot compile or link, say because libcurses is
# not installed, then it is not an error as such but westley and westley.alt
# will be used instead unless of course there exists an executable of one or
# both called whereami or whereami.alt or westley.c or westley.alt.c cannot be
# compiled. It is an error in the script if either of westley.c or westley.alt.c
# cannot be compiled.
#
# This is the best way to protect against showing poor output. We can't get the
# environmental variable COLUMNS from a program or a script so it has to be done
# this way. Note that in curses the COLUMNS is called COLS.
# If by chance westley.sh or westley.alt.sh are not executable files then it
# will try chmod +x on them and then try again. Otherwise it'll just use westley
# and westley.alt.
#
# This script knows which version, the entry or alt code, to use based on what
# city is being shown.
#
# If whereami and whereami.alt can be built it is run once, ahead of time, and
# if it exits non-zero then we exit to prevent repeatedly showing the error
# message. Otherwise we will call westley or westley.alt directly.
# city is being shown (based on the author's remarks).
#
# Usage: ./try.sh
#
@@ -56,72 +41,80 @@ if [[ -z "$CC" ]]; then
fi
make CC="$CC" westley westley.alt >/dev/null || exit 4
make CC="$CC" whereami whereami.alt >/dev/null || exit 4
# get the path to the right programs
if [[ -x "whereami" ]]; then
WESTLEY="whereami"
CC="$CC" ./"$WESTLEY" 0 0 >/dev/null || exit 1
if [[ -x "whereami.sh" ]]; then
WESTLEY="whereami.sh"
else
WESTLEY="westley"
fi
if [[ -x "whereami.alt" ]]; then
WESTLEY_ALT="whereami.alt"
CC="$CC" ./"$WESTLEY_ALT" 0 0 >/dev/null || exit 1
else
WESTLEY_ALT="westley.alt"
chmod +x whereami.sh
if [[ -x "whereami.sh" ]]; then
WESTLEY="whereami.sh"
else
WESTLEY="westley"
fi
fi
echo "New York:" 1>&2
if [[ -x "whereami.alt.sh" ]]; then
WESTLEY_ALT="whereami.alt.sh"
else
chmod +x whereami.alt.sh
if [[ -x "whereami.alt.sh" ]]; then
WESTLEY_ALT="whereami.alt.sh"
else
WESTLEY_ALT="westley.alt"
fi
fi
read -r -n 1 -p "Press any key to show New York: "
echo 1>&2
./"$WESTLEY_ALT" 41 -74
echo 1>&2
echo "London:" 1>&2
read -r -n 1 -p "Press any key to show London: "
echo 1>&2
./"$WESTLEY" 52 0
echo 1>&2
echo "Moscow:" 1>&2
read -r -n 1 -p "Press any key to show Moscow: "
echo 1>&2
./"$WESTLEY" 56 38
echo 1>&2
echo "New Delhi:" 1>&2
read -r -n 1 -p "Press any key to show New Delhi: "
echo 1>&2
./"$WESTLEY" 29 77
echo 1>&2
echo "Sydney:" 1>&2
read -r -n 1 -p "Press any key to show Sydney: "
echo 1>&2
./"$WESTLEY" -34 151
echo 1>&2
echo "Los Angeles:" 1>&2
read -r -n 1 -p "Press any key to show Los Angeles: "
echo 1>&2
./"$WESTLEY_ALT" 34 -118
echo 1>&2
echo "Paris:" 1>&2
read -r -n 1 -p "Press any key to show Paris: "
echo 1>&2
./"$WESTLEY" 45 2
echo 1>&2
echo "Rio de Janeiro:" 1>&2
read -r -n 1 -p "Press any key to show Rio de Janeiro: "
echo 1>&2
./"$WESTLEY" -23 -43
echo 1>&2
echo "Beijing:" 1>&2
read -r -n 1 -p "Press any key to show Beijing: "
echo 1>&2
./"$WESTLEY" 40 116
echo 1>&2
echo "Tokyo:" 1>&2
read -r -n 1 -p "Press any key to show Tokyo: "
echo 1>&2
./"$WESTLEY" 36 140
echo 1>&2
echo "Approximate judging location:" 1>&2
read -r -n 1 -p "Press any key to show approximate judging location: "
echo 1>&2
./"$WESTLEY_ALT" 37 -122
-79
View File
@@ -1,79 +0,0 @@
/*
* whereami.alt.c: wrapper program to westley.alt.c that checks first the
* columns of the terminal, exiting if < 80 and otherwise try compiling
* westley.alt.c (with make) and then if is already compiled or ends up being
* compiled it will be run with the specified args to this program.
*
* It is an error to not specify two args but it is not an error to specify args
* that are not numbers. The atoi(3) function typically returns 0 in that case
* which westley.alt.c uses.
*
* The reason to use this wrapper is because westley.alt.c needs at least 80
* columns to show the output right. Previously it required 80 column wrapping
* but in 2023 this limitation was removed, allowing it to work as long as there
* are at least 80 columns.
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <curses.h>
int main(int argc, char **argv)
{
int cols;
char *cc = NULL; /* for if the user passes in CC=foo */
char *buf = NULL;
if (argc < 3)
exit(fprintf(stderr, "usage: %s <lat> <long>\n", argv[0]));
/* try and get compiler to use */
cc = getenv("CC");
if (!cc)
cc = "cc";
buf = calloc(1, strlen(cc) + strlen("CC=") + 1);
if (buf != NULL)
sprintf(buf, "CC=%s", cc);
else
buf = "CC=cc";
/* init curses so we can get the number of columns */
if (!initscr())
exit(2);
/* save columns */
cols = COLS;
/*
* end curses so that we can either report an error or compile and run
* westley.alt
*/
endwin();
if (cols < 80)
{
fprintf(stderr, "your terminal must be at\nleast 80 columns wide\nbut is only %d, sorry.\n", COLS);
exit(3);
}
/*
* compile westley.alt.c and run if successful
*/
buf = calloc(1, strlen("make CC=") + strlen(cc) + strlen("westley.alt") + strlen(">/dev/null") + 1);
if (buf)
sprintf(buf, "make CC=%s westley.alt >/dev/null", cc);
else
buf = "make westley.alt >/dev/null";
/* compile source file */
if (system(buf))
{
fprintf(stderr, "couldn't compile westley.alt.c, sorry.\n");
exit(4);
}
/* if we get here we compiled the code or it was already compiled so run it */
execl("./westley.alt", "./westley.alt", argv[1], argv[2], NULL);
return 0;
}
+47
View File
@@ -0,0 +1,47 @@
#!/usr/bin/env bash
#
# whereami.alt - a wrapper script to westley.alt.c that checks first the columns
# of the terminal, exiting if < 80 and otherwise try compiling westley.alt.c
# (with make) and then if is already compiled or ends up being compiled it will
# be run with the specified args to this program.
#
# It is an error to not specify two args but it is not an error to specify args
# that are not numbers. The atoi(3) function typically returns 0 in that case
# which westley.alt.c uses.
#
# The reason to use this wrapper is because westley.alt.c needs at least 80
# columns to show the output right. Previously it required 80 column wrapping
# but in 2023 this limitation was removed, allowing it to work as long as there
# are at least 80 columns.
# make sure there are at least two args
if [[ "$#" -lt 2 ]]; then
echo "usage: $0 lat long" 1>&2
exit 1
fi
# 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
# try getting the columns the simple way first: tput cols
COLUMNS="$(tput cols)"
if [[ "$?" -ne 0 ]]; then
# if tput failed for any reason try stty(1) with awk(1):
COLUMNS="$(stty size|awkf '{print $NF}')"
fi
if [[ "$COLUMNS" -lt 80 ]]; then
echo "Your terminal must be at least 80" 1>&2
echo "columns wide echo but yours is only" 1>&2
echo "$COLUMNS, sorry." 1>&2
exit 2
fi
make CC="$CC" everything >/dev/null || exit 1
./westley.alt "$1" "$2"
+46
View File
@@ -0,0 +1,46 @@
#!/usr/bin/env bash
#
# whereami - a wrapper script to westley.c that checks first the
# columns of the terminal, exiting if < 80 and otherwise try compiling
# westley.c (with make) and then if is already compiled or ends up being
# compiled it will be run with the specified args to this program.
#
# It is an error to not specify two args but it is not an error to specify args
# that are not numbers. The atoi(3) function typically returns 0 in that case
# which westley.c uses.
#
# The reason to use this wrapper is because westley.c needs at least 80 columns
# to show the output right. Previously it required 80 column wrapping but in
# 2023 this limitation was removed, allowing it to work as long as there are at
# least 80 columns.
# make sure there are at least two args
if [[ "$#" -lt 2 ]]; then
echo "usage: $0 lat long" 1>&2
exit 1
fi
# 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
# try getting the columns the simple way first: tput cols
COLUMNS="$(tput cols)"
if [[ "$?" -ne 0 ]]; then
# if tput failed for any reason try stty(1) with awk(1):
COLUMNS="$(stty size|awkf '{print $NF}')"
fi
if [[ "$COLUMNS" -lt 80 ]]; then
echo "Your terminal must be at least 80" 1>&2
echo "columns wide echo but yours is only" 1>&2
echo "$COLUMNS, sorry." 1>&2
exit 1
fi
make CC="$CC" all >/dev/null || exit 1
./westley "$1" "$2"
+4
View File
@@ -2,3 +2,7 @@ bmeyer
lavabus.glic
bmeyer.orig
prog.orig
lenna.pgm
new.pgm
glicbawls
lavabus.glic2
+2
View File
@@ -133,6 +133,8 @@ all: data ${TARGET}
${PROG}: ${PROG}.c
${CC} ${CFLAGS} $< -o $@ ${LDFLAGS}
${RM} -f glicbawls
${CP} -f $@ glicbawls
# alternative executable
#
+52 -85
View File
@@ -17,47 +17,11 @@ make
In a video window (white text on black background):
```sh
./bmeyer < michael.pgm > michael.glic
./try.sh
```
Compare the `michael.pgm` to the screen output.
To test that you are compressing and decompressing the same way the
author was, try:
```sh
./bmeyer < lenna.glic
```
Also try in a reverse video window:
```sh
./bmeyer < michael.pgm 2>/dev/null | ./bmeyer > new.pgm
```
Compare the [michael.pgm](michael.pgm) to the screen output. Compare the
`new.pgm` file to the [michael.pgm](michael.pgm) file.
Create a large reverse video xterm, say 200 columns wide and try:
```sh
./bmeyer 200 < lavabus.pgm > lavabus.glic
```
Produce an even smaller output:
```sh
./bmeyer -2 200 < lavabus.pgm > lavabus.glic2
```
Decompress that smaller glic-file:
```sh
./bmeyer -2 200 < lavabus.glic2 > new.pgm
```
Compare the `new.pgm` file to the [lavabus.pgm](lavabus.pgm) file by viewing
them.
The script will suggest you compare the output of the program with images,
prompting you to press any key to continue so that you may do so.
## Judges' remarks:
@@ -72,7 +36,7 @@ bmeyer: bmeyer.c
CC -DY="__setfpucw(0x127f)" -O6 $? -o $@ -lm
```
However many compilers use -O3 as the maximum level for -O optimization.
However many compilers use `-O3` as the maximum level for `-O` optimization.
And on linux/x86, glibc 2.1:
@@ -85,14 +49,14 @@ Compile with the maximum possible optimization on your system.
If your system has 80-bit internal representation of floating
point values (x86, some Motorola processors) and you want the
compressed format to be portable across platforms, you need
to set your FPU to use 64 bit mode. See the extra build lines
in the Makefile, and read the author's remarks below.
to set your FPU to use 64 bit mode. Read the author's remarks
below for more details.
If you cannot work out how to get into 64 bit mode, you can
try using `-ffloat-store` if you compile with GCC (this may have
a performance penalty). The resulting binary will have a good
chance to produce portable files, but due to the resulting
double-rounding (first internally to 80 bit, then to 64 bit
double-rounding (first internally set to 80 bit, then to 64 bit
on writing the value to memory), there is a small but very real
chance any given file produced might not be portable.
@@ -110,20 +74,20 @@ This program is called `GLICBAWLS`
Squares".
And that's exactly what this program does --- feed it a .PGM file
(either raw [i.e. P5] or ascii [i.e. P2]) on stdin, and it will
(either raw [i.e. P5] or ASCII [i.e. P2]) on stdin, and it will
output a compressed version to stdout. Feed it a compressed file
on stdin, and it will decompress it to stdout --- as either raw or
ascii .PGM, depending on what format it was compressed from. For
ASCII .PGM, depending on what format it was compressed from. For
example:
```sh
./bmeyer < michael.pgm > michael.glic
./glicbawls < michael.pgm > michael.glic
```
and then
```sh
./bmeyer < michael.glic > michael.decoded.pgm
./glicbawls < michael.glic > michael.decoded.pgm
```
As it turns out, `glicbawls` compresses greyscale images (or, more
@@ -133,7 +97,7 @@ program developed for my PhD thesis). Of course, this might take
some time, so a progress indicator is provided. To make things
more interesting, instead of a boring bar or percentage display,
an ASCII rendition of the image being compressed/decompressed is
output to stderr (assuming white text on black background). If you
output to `stderr` (assuming white text on black background). If you
have trouble recognizing the image, try squinting at it ;-).
If you still have trouble, simply use a terminal or xterm with
@@ -141,7 +105,7 @@ more than 80 columns, and tell `glicbawls` about it by giving the
number of columns as an argument. For example
```sh
./bmeyer 260 <lavabus.pgm >lavabus.glic
./glicbawls 260 <lavabus.pgm >lavabus.glic
```
will allow `glicbawls` to use up to 260 columns, which makes things
@@ -154,32 +118,32 @@ compression mode. In that mode, the decoded pixel values are
allowed to differ from the originals, but there is an upper limit
on the magnitude of the difference. For example, if a maximum
error of 2 is allowed, an original pixel value of 37 could be
decoded as 35,36,37, 38 or 39. In order to use this mode, simply
decoded as 35, 36, 37, 38 or 39. In order to use this mode, simply
give the maximum allowed error as an argument, with a dash (`-`)
before it. For example
before it. For example:
```sh
./bmeyer -2 < graph.pgm > graph.2.glic
./glicbawls -2 < graph.pgm > graph.2.glic
```
will compress in a way that allows decompression with a maximum
error of two. You can combine both types of arguments, i.e.
error of two. You can combine both types of arguments, i.e.:
```sh
./bmeyer -3 180 < graph.pgm >graph.3.glic
./glicbawls -3 180 < graph.pgm >graph.3.glic
```
will compress with a maximum error of 3, using a 180 column
terminal for the progress display, and
terminal for the progress display, and:
```sh
./bmeyer -3 180 < graph.3.glic > graph.3maxerr.pgm
./glicbawls -3 180 < graph.3.glic > graph.3maxerr.pgm
```
will decompress the result on such a terminal.
But wait, there is more --- you can also feed `glicbawls` .PPM files
(i.e. colour images), raw or ascii, your choice. `Glicbawls` will
(i.e. colour images), raw or ASCII, your choice. `glicbawls` will
compress and decompress them just fine. However, it only does
"reasonably well" on them; It beats PNG easily, but there are
certainly programs out there that can compress colour images
@@ -190,7 +154,7 @@ from a photo or camera)....
### WARNING
`Glicball` is rather CPU and FPU intensive. Don't run it on anything slow.
`glicball` is rather CPU and FPU intensive. Don't run it on anything slow.
Things start to be usable around 300+MHz, with 600+ being highly desirable.
@@ -208,7 +172,7 @@ Fortunately, just about all current FPUs can be put into IEEE 64
bit mode (or at least something close enough for
`glicbawls`). Unfortunately, there is no standard way of doing
so. For this reason, the build file contains *three* compile
lines; One for machines that already use 64 bit mode by default
lines; one for machines that already use 64 bit mode by default
(most RISC processors), one for linux/x86 machines using libc4,
libc5 or glibc2.0, and one for linux/x86 machines using glibc2.1
(glibc2.1 no longer exports the `__setfpucw()` function, necessitating
@@ -226,10 +190,10 @@ own compressed files, but you may be unable to exchange files with
Most of the obfuscation of this program was driven by the
desperate struggle to fit all of `glicbawls`' features into code
that fits the IOCCC's size limits. All identifiers names are
that fits the IOCCC's size limits. All identifiers' names are
single-character, which was only possible by ruthless exploitation
of scope. There is a function `M()` that handles nearly all input
from stdin, handles all output to stdout, and also recursively
from `stdin`, handles all output to `stdout`, and also recursively
calculates one of the mathematical expressions needed for error
modelling. There is a function that calculates `(A^(-1)*b)*x` with `A`
being a matrix and `b` and `x` being vectors, and does so in a very
@@ -241,7 +205,7 @@ value when control flow reaches the loops. Lots of functions use
the same two global scratch variables. Variables change their
meaning all the time, and the differences between compressing and
decompressing are handled in rather subtle ways all over the
program. The string that holds the ascii values for displaying the
program. The string that holds the ASCII values for displaying the
progress image doubles as a description on how to find a pixel's
causal neighbours. And then there are a few `#define`s that really
are just in there to save a few characters, but as an added
@@ -254,9 +218,9 @@ are a true wizard, it is unlikely to gain you any insights into
what is actually going on....\[0\]
### Bugs, Assumptions and TODOs
### Bugs, Assumptions and TODO
`Glicbawls` assumes that characters are 8 bit wide, and that the
`glicbawls` assumes that characters are 8 bit wide, and that the
character set used is ASCII. If one of these isn't true, all hell
will break loose.
@@ -271,12 +235,12 @@ When decompressing a near-lossless encoded image, the maximum
allowed error is required as a command line parameter. This should
really be saved in the compressed file!
`Glicbawls` relies on the decimal representation of all integers
`glicbawls` relies on the decimal representation of all integers
having less than 255 digits. While ANSI C does not guarantee this,
it seems rather unlikely that anyone in the foreseeable future
would use images with `10^255` rows, columns or different levels of
grey. Also, it is assumed that any integer used can be cast to a
double and back without loss of precision. This limits the number
`double` and back without loss of precision. This limits the number
of rows, columns and grey levels to 9 quintillion, which should
also be sufficient for the next few years.
@@ -287,8 +251,8 @@ million in a lottery. But if it happens to you, don't say I
didn't warn you! Instead, go out and buy a lightning rod and a
lottery ticket ;-)
At one point, a pointer to int is used as the target of a `"%1[#]"`
conversion in a scanf, which makes gcc rather unhappy, but
At one point, a pointer to `int` is used as the target of a `"%1[#]"`
conversion in a `scanf(3)`, which makes gcc rather unhappy, but
shouldn't really cause anyone any trouble. The same goes for a
couple of assignments which are used as truth values.
@@ -300,23 +264,25 @@ the scope of an info file, and would also be quite difficult in
pure ASCII, so the following is just a rough outline, and contains
some compression-speak...
The image is handled in scanline ordering. For each pixel, an
expected value is calculated by creating a least squares predictor
of order 12 based on all of the previously encoded/decoded
pixels. However, the contribution of each pixel is weighted
according to its Manhattan-distance from the current pixel,
D. That weight used is `pow(0.8,D)`. \[1\] \[2\] \[3\]
The image is handled in [scanline](https://en.wikipedia.org/wiki/Scan_line)
ordering. For each pixel, an expected value is calculated by creating a least
squares predictor of order 12 based on all of the previously encoded/decoded
pixels. However, the contribution of each pixel is weighted according to its
[Manhattan-distance](https://en.wikipedia.org/wiki/Taxicab_geometry) from the
current pixel, `D`. That weight used is `pow(0.8,D)`. \[1\] \[2\] \[3\]
In a similar way, the prediction *errors* for all previous pixels
are combined --- a weighted average (with weight `pow(0.7,D)`) of
the squares of all previous prediction errors is taken, and the
square root of the (appropriately scaled) result is called sigma.
The predicted value and sigma are then used as the parameters of a
Student or t-distribution (which is similar to a normal
distribution, but has more weight in the tails), providing a
probability distribution for the current pixel.
The predicted value and sigma are then used as the parameters of a [Student or
t-distribution](https://en.wikipedia.org/wiki/Student%27s_t-distribution) (which
is similar to a [normal
distribution](https://en.wikipedia.org/wiki/Normal_distribution), but has more
weight in the tails), providing a [probability
distribution](https://en.wikipedia.org/wiki/Probability_distribution) for the
current pixel.
Next, the possible interval of values for the current pixel is
halved, and through integration of the probability distribution, a
@@ -332,13 +298,13 @@ en/decoded\[4\].
[0] Yes, this could be seen as a challenge....
[1] Actually, the weight is `pow(0.8,D)/s`, where `s` is the sigma
used for en/decoding the particular previous pixel. Dividing
used for encoding/decoding the particular previous pixel. Dividing
by `s` is a rather arbitrary action justified only by the
improvement in results. Mathematically, I can only justify
dividing by `s^2`, or not dividing at all....
[2] Obviously, these least squares predictors are not calculated
from scratch for each pixel. Some clever reuse of earlier
results allows O(1) calculation, rather than the
results allows `O(1)` calculation, rather than the
`O(previous_rows*columns)` this description would suggest.
[3] As anyone who has ever tried local least squares knows from
bitter experience, there is a lot of numerical instability
@@ -346,7 +312,7 @@ en/decoded\[4\].
averaging predictor to the equation system the least squares
predictor is calculated from. The weight that is given to
this bias is constantly adjusted throughout coding/decoding,
thus justifying the 'a' in "glicbawls".
thus justifying the 'a' in `glicbawls`.
[4] In the case of near-lossless coding, the interval is not
necessarily *halved*, but rather split at a convenient point
(the split points are chosen in such a way as to minimise the
@@ -359,7 +325,7 @@ en/decoded\[4\].
[Lavabus](lavabus.pgm) was taken by the judge, Landon Curt Noll.
[Michael](michael.pgm) was provided by the author. [Lenna](lenna.glic) is a
1972 Playboy centerfold.
1972 Playboy centerfold (doesn't show very much).
- [michael.pgm](michael.pgm)
@@ -367,8 +333,9 @@ en/decoded\[4\].
- [lavabus.pgm](lavabus.pgm)
A bus that was trapped by lava from Kilauea volcano in Hawaii, US. Nobody
was in the bus at the time, BTW. Photo date: 1981.
A bus that was trapped by lava from [Kilauea
volcano](https://en.wikipedia.org/wiki/Kīlauea) in Hawaii, US. Nobody was
in the bus at the time, BTW. Photo date: 1981.
- [lenna.glic](lenna.glic)
+78
View File
@@ -0,0 +1,78 @@
#!/usr/bin/env bash
#
# try.sh - demonstrate IOCCC winner 2000/bmeyer
#
# 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
# We need to have the column count for later on. It is not an error if it cannot
# be determined: we just use a default value.
#
# try getting the columns the simple way first: tput cols
COLUMNS="$(tput cols)"
# ^--^ SC2181 (style): Check exit code directly with e.g. 'if ! mycmd;', not indirectly with $?.
# shellcheck disable=SC2181
if [[ "$?" -ne 0 ]]; then
# if tput failed for any reason try stty(1) with awk(1):
# Disable this warning of shellcheck as it's wrong: awk needs single quotes.
# ^-----------^ SC2016 (info): Expressions don't expand in single quotes, use double quotes for that.
# shellcheck disable=SC2016
COLUMNS="$(stty size|awk '{print $NF}')"
if [[ "$?" -ne 0 ]]; then
COLUMNS=150
fi
fi
echo "Warning: if you don't have white text on a black background the output" 1>&2
echo "might not be as correct or visually appealing." 1>&2
echo 1>&2
if [[ "$COLUMNS" -lt 81 ]]; then
echo "Warning: your terminal is < 81 columns and this might cause output" 1>&2
echo "issues." 1>&2
echo 1>&2
fi
read -r -n 1 -p "Press any key to start: "
echo "$ ./glicbawls < michael.pgm > michael.glic" 1>&2
./glicbawls < michael.pgm > michael.glic
echo "Now compare the michael.pgm to the screen output." 1>&2
read -r -n 1 -p "Press any key to continue: "
echo "$ ./glicbawls < michael.pgm 2>/dev/null | ./glicbawls > new.pgm" 1>&2
./glicbawls < michael.pgm 2>/dev/null | ./glicbawls > new.pgm
echo "Now compare the michael.pgm to the screen output." 1>&2
read -r -n 1 -p "Press any key to continue: "
echo "Now compare the new.pgm file to the michael.pgm file."
read -r -n 1 -p "Press any key to continue: "
read -r -n -p 1 "Press any key to trying and use your screen width on lava bus pic: "
echo "$ ./glicbawls $COLUMNS < lavabus.pgm > lavabus.glic" 1>&2
./glicbawls "$COLUMNS" < lavabus.pgm > lavabus.glic
read -r -n 1 -p "Press any key to continue: "
echo "$ ./glicbawls -2 "$COLUMNS" < lavabus.pgm > lavabus.glic2"
./glicbawls -2 "$COLUMNS" < lavabus.pgm > lavabus.glic2
read -r -n 1 -p "Press any key to decompress the smaller glic-file: "
echo "$ ./glicbawls -2 150 < lavabus.glic2 > new.pgm" 1>&2
./glicbawls -2 150 < lavabus.glic2 > new.pgm
echo "Now compare the new.pgm file to the lavabus.pgm file." 1>&2
-7
View File
@@ -28,13 +28,6 @@ evening of Dec 22, 2000).
Can you find out how it stores the insult strings? Can you then take
an insult and figure out when it will be uttered?
[sc] The code also contained a buffer overflow bug which I have fixed!
The array size of `s` should be 1079 characters long. (From 0 to 1078
inclusive!). Without this it results in an error in the encoding of
"decrepit" -- For a 32bit little endian machine using GCC (because of
the way it assigns variables to memory) it will terminate "decrepit"
with the character `'\200'` (the last value of `F`) instead of `'\0'`.
## Author's remarks:
+17 -13
View File
@@ -1627,22 +1627,19 @@ the final loop it prints another newline. This fix has another bonus in that
resizing the terminal after running it should not mess up the display either,
unless of course it becomes too small.
Cody added the programs [whereami.c](1992/westley/whereami.c) and
[whereami.alt](1992/westley/whereami.alt.c) which correspond to the entry and
the alt code but which, by way of curses, checks for the number of columns; if
all is good it will try compiling the program or alt program, respectively, and
then if successful run the program. Otherwise, if there are not enough columns
it is an error. It is always an error if the compilation of the program itself
(westley.c, westley.alt.c) fails.
Cody added the scripts [whereami.sh](1992/westley/whereami.sh) and
[whereami.alt.sh](1992/westley/whereami.alt.sh) which correspond to the entry and
the alt code but first check that the number of columns is at least 80 and if
not it is an error.
Cody added the [try.sh](1992/westley/try.sh) script that shows the different
cities that the author recommended one try as well as the one recommended by the
judges (approximate judging location), labelling each city and printing a
newline before the next city. The try.sh script uses the `whereami` code, if it
can be compiled and linked, but otherwise it uses `westley` code instead, either
the entry or alt code. The try.sh cannot be deceived by way of `COLUMNS=81
./try.sh` but the `whereami`/`whereami.alt` code can be deceived if directly
called. This is a feature, not a bug: or maybe a limitation of curses.
newline before the next city. The try.sh script uses the `whereami.sh` and
`whereami.alt.sh` scripts, as long as they're executable (if they're not it
first tries to make it executable and if it fails to do so it just uses
`westley` or `westley.alt`. The scripts can be deceived by `COLUMNS=80 ./try.sh`
(or `COLUMNS=80 ./whereami.sh` etc.) but this is a feature, not a bug.
Cody also added an arg check because the program and the
[alternate version](1992/westley/westley.alt.c) might have crashed or
@@ -1650,7 +1647,7 @@ Cody also added an arg check because the program and the
world](https://en.wikipedia.org/wiki/Earth) or just the
[USA](https://en.wikipedia.org/wiki/United_States), respectively, without enough
args (2). And not that we need the help or anything for this :-) but we
encourage you to try the original :-)
encourage you to try the original without two args :-)
## [1993/cmills](1993/cmills/cmills.c) ([README.md](1993/cmills/README.md]))
@@ -2271,6 +2268,13 @@ code looks like before.
Cody also added the [try.sh](2000/anderson/try.sh) script.
## [2000/bmeyer](2000/bmeyer/bmeyer.c) ([README.md](2000/bmeyer/README.md]))
Cody added the [try.sh](2000/bmeyer/try.sh) script with some improvements to the
commands we recommended like not assuming the number of columns one has in their
terminal.
## [2000/briddlebane](2000/briddlebane/briddlebane.c) ([README.md](2000/briddlebane/README.md]))
Cody fixed this to compile in systems that require one to explicitly link in
+9 -1
View File
@@ -1,5 +1,5 @@
# A todo list of known things to check and/or do
*Last updated: Thu 02 Nov 2023 12:32:15 UTC*
*Last updated: Thu 16 Nov 2023 11:20:54 UTC**
This document is primarily for [Cody Boone
Ferguson](/winners.html#Cody_Boone_Ferguson) as he (that is I :-) ) wanted a way
@@ -144,3 +144,11 @@ instead change it to make pull requests. See the
- Check the YYYY/README.md files for other things besides the GitHub pull
requests rather than emailing judges. This can be done on the final pass of the
files.
- In the entries with the alt code that use `usleep(3)` make the macro name
consistent across all entries. At one point `Z` was used but in one entry `Z`
was taken so this would not work. It appears at this time (16 November 2023)
that it might be that `S` will work in all cases (currently?) though one has two
values so the second would could be changed to `SS` (which is convenient as it's
for SDL). This is low priority but it would be nice to have done as it would
make it consistent and easy to remember.