diff --git a/2024/.filelist b/2024/.filelist
new file mode 100644
index 000000000..d6cab5213
--- /dev/null
+++ b/2024/.filelist
@@ -0,0 +1,10 @@
+2024/2024.tar.bz2
+2024/.filelist
+2024/guidelines.html
+2024/guidelines.md
+2024/index.html
+2024/Makefile
+2024/README.md
+2024/rules.html
+2024/rules.md
+2024/.year
diff --git a/2024/.year b/2024/.year
new file mode 100644
index 000000000..46bca1883
--- /dev/null
+++ b/2024/.year
@@ -0,0 +1,23 @@
+2024/anders
+2024/burton
+2024/cable1
+2024/cable2
+2024/carlini
+2024/codemeow
+2024/endoh1
+2024/endoh2
+2024/ferguson1
+2024/ferguson2
+2024/howe
+2024/kramer
+2024/kurdyukov1
+2024/kurdyukov2
+2024/kurdyukov3
+2024/kurdyukov4
+2024/maffiodo
+2024/mills
+2024/stedolan
+2024/straadt
+2024/tmarrec
+2024/tompng
+2024/weaver
diff --git a/2024/2024.tar.bz2 b/2024/2024.tar.bz2
new file mode 100644
index 000000000..be3c1d233
Binary files /dev/null and b/2024/2024.tar.bz2 differ
diff --git a/2024/Makefile b/2024/Makefile
new file mode 100644
index 000000000..ba4176f15
--- /dev/null
+++ b/2024/Makefile
@@ -0,0 +1,510 @@
+#!/usr/bin/env make
+#
+# 2024 Makefile
+
+################################################################################
+#
+# IOCCC winning entry code may not work on your system. What was liked/allowed
+# and worked in the past may no longer be liked/allowed or compile/run today.
+#
+# Bug fixes, corrections and typo fixes are VERY WELCOME. If you see a problem,
+# first check this URL for a list of known bugs and (mis)features of IOCCC entries:
+#
+# https://www.ioccc.org/bugs.html
+#
+# GitHub pull requests are welcome! Please see the above URL for details.
+#
+################################################################################
+#
+# This file is Copyright (c) 2024 by Landon Curt Noll. All Rights Reserved.
+# You are free to share and adapt this file under the terms of this license:
+#
+# Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)
+#
+# For more information, see: https://creativecommons.org/licenses/by-sa/4.0/
+
+
+#############################
+# shell used by this Makefile
+#############################
+
+SHELL= bash
+
+#######################
+# common tool locations
+#######################
+
+include ../var.mk
+
+
+###############
+# IOCCC entries
+###############
+
+# 1st - DO NOT REMOVE THIS LINE - bin/new-dir.sh uses this line #
+ENTRIES= anders burton cable1 cable2 carlini codemeow endoh1 endoh2 \
+ ferguson1 ferguson2 howe kramer kurdyukov1 kurdyukov2 kurdyukov3 \
+ kurdyukov4 maffiodo mills stedolan straadt tmarrec tompng weaver
+# 2nd - DO NOT REMOVE THIS LINE - bin/new-dir.sh uses this line #
+
+YEAR= 2024
+
+
+###################
+# build all entries
+###################
+
+all:
+ @echo '=-=-= ${YEAR} begin make $@ =-=-='
+ @echo
+ @for i in ${ENTRIES}; do \
+ if [[ -d $$i ]]; then \
+ echo "=-= start ${YEAR}/$$i =-="; \
+ echo "(cd $$i && ${MAKE} $@)"; \
+ (cd $$i && ${MAKE} $@); \
+ echo "=-= end ${YEAR}/$$i =-="; \
+ echo; \
+ fi; \
+ done
+ @echo '=-=-= ${YEAR} complete make $@ =-=-='
+
+.PHONY: all alt data everything diff_orig_prog diff_prog_orig \
+ diff_alt_prog diff_prog_alt diff_orig_alt diff_alt_orig \
+ clean clobber install genpath clang-format add_dir love haste \
+ waste maker easter_egg sandwich supernova more_magic magic charon pluto
+
+# alternative executable
+#
+alt:
+ @echo '=-=-= ${YEAR} begin make $@ =-=-='
+ @echo
+ @for i in ${ENTRIES}; do \
+ if [[ -d $$i ]]; then \
+ echo "=-= start ${YEAR}/$$i =-="; \
+ echo "(cd $$i && ${MAKE} $@)"; \
+ (cd $$i && ${MAKE} $@); \
+ echo "=-= end ${YEAR}/$$i =-="; \
+ echo; \
+ fi; \
+ done
+ @echo '=-=-= ${YEAR} complete make $@ =-=-='
+
+# data files
+#
+data:
+ @echo '=-=-= ${YEAR} begin make $@ =-=-='
+ @echo
+ @for i in ${ENTRIES}; do \
+ if [[ -d $$i ]]; then \
+ echo "=-= start ${YEAR}/$$i =-="; \
+ echo "(cd $$i && ${MAKE} $@)"; \
+ (cd $$i && ${MAKE} $@); \
+ echo "=-= end ${YEAR}/$$i =-="; \
+ echo; \
+ fi; \
+ done
+ @echo '=-=-= ${YEAR} complete make $@ =-=-='
+
+# both all and alt
+#
+everything:
+ @echo '=-=-= ${YEAR} begin make $@ =-=-='
+ @echo
+ @for i in ${ENTRIES}; do \
+ if [[ -d $$i ]]; then \
+ echo "=-= start ${YEAR}/$$i =-="; \
+ echo "(cd $$i && ${MAKE} $@)"; \
+ (cd $$i && ${MAKE} $@); \
+ echo "=-= end ${YEAR}/$$i =-="; \
+ echo; \
+ fi; \
+ done
+ @echo '=-=-= ${YEAR} complete make $@ =-=-='
+
+
+#####################
+# make a difference #
+#####################
+
+# diff orig source and source
+#
+diff_orig_prog:
+ @echo '=-=-= ${YEAR} begin make $@ =-=-='
+ @echo
+ @for i in ${ENTRIES}; do \
+ if [[ -d $$i ]]; then \
+ echo "=-= start ${YEAR}/$$i =-="; \
+ echo "(cd $$i && ${MAKE} $@)"; \
+ (cd $$i && ${MAKE} $@); \
+ echo "=-= end ${YEAR}/$$i =-="; \
+ echo; \
+ fi; \
+ done
+ @echo '=-=-= ${YEAR} complete make $@ =-=-='
+
+# diff source and orig source
+#
+diff_prog_orig:
+ @echo '=-=-= ${YEAR} begin make $@ =-=-='
+ @echo
+ @for i in ${ENTRIES}; do \
+ if [[ -d $$i ]]; then \
+ echo "=-= start ${YEAR}/$$i =-="; \
+ echo "(cd $$i && ${MAKE} $@)"; \
+ (cd $$i && ${MAKE} $@); \
+ echo "=-= end ${YEAR}/$$i =-="; \
+ echo; \
+ fi; \
+ done
+ @echo '=-=-= ${YEAR} complete make $@ =-=-='
+
+# diff alt source and source
+#
+diff_alt_prog:
+ @echo '=-=-= ${YEAR} begin make $@ =-=-='
+ @echo
+ @for i in ${ENTRIES}; do \
+ if [[ -d $$i ]]; then \
+ echo "=-= start ${YEAR}/$$i =-="; \
+ echo "(cd $$i && ${MAKE} $@)"; \
+ (cd $$i && ${MAKE} $@); \
+ echo "=-= end ${YEAR}/$$i =-="; \
+ echo; \
+ fi; \
+ done
+ @echo '=-=-= ${YEAR} complete make $@ =-=-='
+
+# diff source and alt source
+#
+diff_prog_alt:
+ @echo '=-=-= ${YEAR} begin make $@ =-=-='
+ @echo
+ @for i in ${ENTRIES}; do \
+ if [[ -d $$i ]]; then \
+ echo "=-= start ${YEAR}/$$i =-="; \
+ echo "(cd $$i && ${MAKE} $@)"; \
+ (cd $$i && ${MAKE} $@); \
+ echo "=-= end ${YEAR}/$$i =-="; \
+ echo; \
+ fi; \
+ done
+ @echo '=-=-= ${YEAR} complete make $@ =-=-='
+
+# diff orig and alt
+#
+diff_orig_alt:
+ @echo '=-=-= ${YEAR} begin make $@ =-=-='
+ @echo
+ @for i in ${ENTRIES}; do \
+ if [[ -d $$i ]]; then \
+ echo "=-= start ${YEAR}/$$i =-="; \
+ echo "(cd $$i && ${MAKE} $@)"; \
+ (cd $$i && ${MAKE} $@); \
+ echo "=-= end ${YEAR}/$$i =-="; \
+ echo; \
+ fi; \
+ done
+ @echo '=-=-= ${YEAR} complete make $@ =-=-='
+
+# diff alt and orig
+diff_alt_orig:
+ @echo '=-=-= ${YEAR} begin make $@ =-=-='
+ @echo
+ @for i in ${ENTRIES}; do \
+ if [[ -d $$i ]]; then \
+ echo "=-= start ${YEAR}/$$i =-="; \
+ echo "(cd $$i && ${MAKE} $@)"; \
+ (cd $$i && ${MAKE} $@); \
+ echo "=-= end ${YEAR}/$$i =-="; \
+ echo; \
+ fi; \
+ done
+ @echo '=-=-= ${YEAR} complete make $@ =-=-='
+
+
+###############
+# utility rules
+###############
+
+clean:
+ @echo '=-=-= ${YEAR} begin make $@ =-=-='
+ @echo
+ @for i in ${ENTRIES}; do \
+ if [[ -d $$i ]]; then \
+ echo "=-= start ${YEAR}/$$i =-="; \
+ echo "(cd $$i && ${MAKE} $@)"; \
+ (cd $$i && ${MAKE} $@); \
+ echo "=-= end ${YEAR}/$$i =-="; \
+ echo; \
+ fi; \
+ done
+ @echo '=-=-= ${YEAR} complete make $@ =-=-='
+
+clobber:
+ @echo '=-=-= ${YEAR} begin make $@ =-=-='
+ @echo
+ @for i in ${ENTRIES}; do \
+ if [[ -d $$i ]]; then \
+ echo "=-= start ${YEAR}/$$i =-="; \
+ echo "(cd $$i && ${MAKE} $@)"; \
+ (cd $$i && ${MAKE} $@); \
+ echo "=-= end ${YEAR}/$$i =-="; \
+ echo; \
+ fi; \
+ done
+ @echo '=-=-= ${YEAR} complete make $@ =-=-='
+
+genpath:
+ @echo '=-=-= IOCCC begin make $@ =-=-='
+ @${RM} -f .tmp.genpath
+ @${TOUCH} .tmp.genpath
+ @-for i in ${ENTRIES}; do \
+ if [[ -d $$i ]]; then \
+ echo "${YEAR}/$$i" >> .tmp.genpath; \
+ ${RM} -f "$$i/.tmp.genpath"; \
+ echo "${YEAR}/$$i" >> "$$i/.tmp.genpath"; \
+ if ${CMP} -s "$$i/.tmp.genpath" "$$i/.path"; then \
+ ${RM} -f "$$i/.tmp.genpath"; \
+ echo "$$i/.path already up to date"; \
+ else \
+ ${MV} -f "$$i/.tmp.genpath" "$$i/.path"; \
+ ${CHMOD} 0444 "$$i/.path"; \
+ echo "updated $$i/.path"; \
+ fi; \
+ fi; \
+ done
+ @-if ${CMP} -s .tmp.genpath .year; then \
+ ${RM} -f .tmp.genpath; \
+ echo ".year already up to date"; \
+ else \
+ ${MV} -f .tmp.genpath .year; \
+ ${CHMOD} 0444 .year; \
+ echo "updated .year"; \
+ fi
+ @echo '=-=-= IOCCC complete make $@ =-=-='
+
+
+#############################################################
+# NOTE: 'Don't Panic' if you don't understand the stuff below
+#############################################################
+
+# new_entry - add a new entry directory name to the ${ENTRIES} Makefile variable
+#
+# Add ${NEW_ENTRY} to the list of ${ENTRIES} and output Makefile lines to set updated
+# ${ENTRIES} Makefile variable.
+#
+# If list of ${ENTRIES} is long, we format it into a multi-line value setting with required
+# backslashes and indentation. Duplicate values are removed and the initial 'submit.[0-9]*' (used
+# during judging) is removed. The words (directory names) in ${ENTRIES} are sorted in C dictionary order.
+#
+# This rule is used by the bin/new-dir.sh shell script via:
+#
+# make -C ${YEAR} new_entry NEW_ENTRY=curds
+#
+new_entry:
+ @if [[ -z "${NEW_ENTRY}" ]]; then echo "$@: ERROR: NEW_ENTRY is empty" 1>&2; exit 1; fi
+ @if [[ ! -d "${NEW_ENTRY}" ]]; then echo "$@: ERROR: not a directory: ${YEAR}/${NEW_ENTRY}" 1>&2; exit 2; fi
+ @(echo -n 'ENTRIES= '; \
+ (for dir in ${ENTRIES} ${NEW_ENTRY}; do \
+ if [[ $$dir != 'submit.[0-9]*' ]]; then echo "$$dir"; fi; \
+ done | \
+ LANG=C ${SORT} -d -u; \
+ ) \
+ ) | \
+ ${FMT} | \
+ ${SED} -e '2,$$s/^/\t/' -e 's/$$/ \\/' -e '$$s/ \\//'
+
+
+########################
+# extended utility rules
+########################
+
+install:
+ @echo '=-=-= ${YEAR} begin make $@ =-=-='
+ @echo
+ @for i in ${ENTRIES}; do \
+ if [[ -d $$i ]]; then \
+ echo "=-= start ${YEAR}/$$i =-="; \
+ echo "(cd $$i && ${MAKE} $@)"; \
+ (cd $$i && ${MAKE} $@); \
+ echo "=-= end ${YEAR}/$$i =-="; \
+ echo; \
+ fi; \
+ done
+ @echo '=-=-= ${YEAR} complete make $@ =-=-='
+
+clang-format:
+ @echo '=-=-= ${YEAR} begin make $@ =-=-='
+ @echo
+ @for i in ${ENTRIES}; do \
+ if [[ -d $$i ]]; then \
+ echo "=-= start ${YEAR}/$$i =-="; \
+ echo "(cd $$i && ${MAKE} $@)"; \
+ (cd $$i && ${MAKE} $@); \
+ echo "=-= end ${YEAR}/$$i =-="; \
+ echo; \
+ fi; \
+ done
+ @echo '=-=-= ${YEAR} complete make $@ =-=-='
+
+
+##################
+# 1337 hacker rulz
+##################
+
+love:
+ @echo '=-=-= ${YEAR} begin make $@ =-=-='
+ @echo
+ @for i in ${ENTRIES}; do \
+ if [[ -d $$i ]]; then \
+ echo "=-= start ${YEAR}/$$i =-="; \
+ echo "(cd $$i && ${MAKE} $@)"; \
+ (cd $$i && ${MAKE} $@); \
+ echo "=-= end ${YEAR}/$$i =-="; \
+ echo; \
+ fi; \
+ done
+ @echo '=-=-= ${YEAR} complete make $@ =-=-='
+
+haste:
+ @echo '=-=-= ${YEAR} begin make $@ =-=-='
+ @echo
+ @for i in ${ENTRIES}; do \
+ if [[ -d $$i ]]; then \
+ echo "=-= start ${YEAR}/$$i =-="; \
+ echo "(cd $$i && ${MAKE} $@)"; \
+ (cd $$i && ${MAKE} $@); \
+ echo "=-= end ${YEAR}/$$i =-="; \
+ echo; \
+ fi; \
+ done
+ @echo '=-=-= ${YEAR} complete make $@ =-=-='
+
+waste:
+ @echo '=-=-= ${YEAR} begin make $@ =-=-='
+ @echo
+ @for i in ${ENTRIES}; do \
+ if [[ -d $$i ]]; then \
+ echo "=-= start ${YEAR}/$$i =-="; \
+ echo "(cd $$i && ${MAKE} $@)"; \
+ (cd $$i && ${MAKE} $@); \
+ echo "=-= end ${YEAR}/$$i =-="; \
+ echo; \
+ fi; \
+ done
+ @echo '=-=-= ${YEAR} complete make $@ =-=-='
+
+maker:
+ @echo '=-=-= ${YEAR} begin make $@ =-=-='
+ @echo
+ @for i in ${ENTRIES}; do \
+ if [[ -d $$i ]]; then \
+ echo "=-= start ${YEAR}/$$i =-="; \
+ echo "(cd $$i && ${MAKE} $@)"; \
+ (cd $$i && ${MAKE} $@); \
+ echo "=-= end ${YEAR}/$$i =-="; \
+ echo; \
+ fi; \
+ done
+ @echo '=-=-= ${YEAR} complete make $@ =-=-='
+
+easter_egg:
+ @echo '=-=-= ${YEAR} begin make $@ =-=-='
+ @echo
+ @for i in ${ENTRIES}; do \
+ if [[ -d $$i ]]; then \
+ echo "=-= start ${YEAR}/$$i =-="; \
+ echo "(cd $$i && ${MAKE} $@)"; \
+ (cd $$i && ${MAKE} $@); \
+ echo "=-= end ${YEAR}/$$i =-="; \
+ echo; \
+ fi; \
+ done
+ @echo '=-=-= ${YEAR} complete make $@ =-=-='
+
+sandwich:
+ @echo '=-=-= ${YEAR} begin make $@ =-=-='
+ @echo
+ @for i in ${ENTRIES}; do \
+ if [[ -d $$i ]]; then \
+ echo "=-= start ${YEAR}/$$i =-="; \
+ echo "(cd $$i && ${MAKE} $@)"; \
+ (cd $$i && ${MAKE} $@); \
+ echo "=-= end ${YEAR}/$$i =-="; \
+ echo; \
+ fi; \
+ done
+ @echo '=-=-= ${YEAR} complete make $@ =-=-='
+
+
+# The IOCCC resident astronomer states
+#
+supernova:
+ @echo '=-=-= ${YEAR} begin make $@ =-=-='
+ @echo
+ @for i in ${ENTRIES}; do \
+ if [[ -d $$i ]]; then \
+ echo "=-= start ${YEAR}/$$i =-="; \
+ echo "(cd $$i && ${MAKE} $@)"; \
+ (cd $$i && ${MAKE} $@); \
+ echo "=-= end ${YEAR}/$$i =-="; \
+ echo; \
+ fi; \
+ done
+ @echo '=-=-= ${YEAR} complete make $@ =-=-='
+
+more_magic:
+ @echo '=-=-= ${YEAR} begin make $@ =-=-='
+ @echo
+ @for i in ${ENTRIES}; do \
+ if [[ -d $$i ]]; then \
+ echo "=-= start ${YEAR}/$$i =-="; \
+ echo "(cd $$i && ${MAKE} $@)"; \
+ (cd $$i && ${MAKE} $@); \
+ echo "=-= end ${YEAR}/$$i =-="; \
+ echo; \
+ fi; \
+ done
+ @echo '=-=-= ${YEAR} complete make $@ =-=-='
+
+magic:
+ @echo '=-=-= ${YEAR} begin make $@ =-=-='
+ @echo
+ @for i in ${ENTRIES}; do \
+ if [[ -d $$i ]]; then \
+ echo "=-= start ${YEAR}/$$i =-="; \
+ echo "(cd $$i && ${MAKE} $@)"; \
+ (cd $$i && ${MAKE} $@); \
+ echo "=-= end ${YEAR}/$$i =-="; \
+ echo; \
+ fi; \
+ done
+ @echo '=-=-= ${YEAR} complete make $@ =-=-='
+
+charon:
+ @echo '=-=-= ${YEAR} begin make $@ =-=-='
+ @echo
+ @for i in ${ENTRIES}; do \
+ if [[ -d $$i ]]; then \
+ echo "=-= start ${YEAR}/$$i =-="; \
+ echo "(cd $$i && ${MAKE} $@)"; \
+ (cd $$i && ${MAKE} $@); \
+ echo "=-= end ${YEAR}/$$i =-="; \
+ echo; \
+ fi; \
+ done
+ @echo '=-=-= ${YEAR} complete make $@ =-=-='
+
+pluto:
+ @echo '=-=-= ${YEAR} begin make $@ =-=-='
+ @echo
+ @for i in ${ENTRIES}; do \
+ if [[ -d $$i ]]; then \
+ echo "=-= start ${YEAR}/$$i =-="; \
+ echo "(cd $$i && ${MAKE} $@)"; \
+ (cd $$i && ${MAKE} $@); \
+ echo "=-= end ${YEAR}/$$i =-="; \
+ echo; \
+ fi; \
+ done
+ @echo '=-=-= ${YEAR} complete make $@ =-=-='
diff --git a/2024/README.md b/2024/README.md
new file mode 100644
index 000000000..08edaef52
--- /dev/null
+++ b/2024/README.md
@@ -0,0 +1,389 @@
+# Twenty Eighth International Obfuscated C Code Contest
+
+
+## Where to start
+
+See below for links to the [2024 winning IOCCC entries](#inventory).
+
+Check out the `index.html` web pages for each winning entry. They have
+most of the information you need to compile and run the winning program.
+Take a look at the winning source code and try to figure out how it works.
+You might also want to check out the author’s remarks for even more details.
+
+You may [download all winning entries](2024.tar.bz2) in the form
+of a compressed tarball, for this year's contest.
+
+
+## General remarks on this contest
+
+This year marked the [40th anniversary of the IOCCC](../faq.html#ioccc_start).
+The **IOCCC28** opened submissions from **2025-03-05 23:19:17.131107 UTC** to **2025-06-05
+04:03:02.010099 UTC** after a 4 year pause.
+
+A significant portion of those 4 years was an effort by a [number of people](../thanks-for-help.html),
+with over 6168+ commits, to rebuild the [Official IOCCC website](../index.html)
+in what became known as the **Great Fork Merge**.
+
+Another portion of those 4 years went into retooling the IOCCC, including the creation of
+the [mkiocccentry toolkit](https://github.com/ioccc-src/mkiocccentry), a new
+[IOCCC registration process](../next/register.html), and a new
+[IOCCC submit server](https://submit.ioccc.org/) (which may not be up if the contest is closed).
+
+The **major motivation** for the above was to:
+
+* Present [IOCCC winners](../years.html) that that honors the contributions of all of the [winning authors](../authors.html) from [around the world](../location.html),
+
+* Reduce the administrative effort required by the [IOCCC Judges](../judges.html) to run the contest, and
+
+* Minimize the time between when the winners of the IOCCC are selected and when the source is made available.
+
+On the last point, for **IOCCC28** the Judging started on **2025-06-05 04:03:02.010099 UTC** and then the winners were selected by the [IOCCC Judges](../judges.html) on **2025-07-07 20:05:07.000000 UTC**:
+
+* Winners were announced during a live the [Our Favorite Universe](https://www.youtube.com/@OurFavoriteUniverse) YouTube Channel that started on **2025-08-02 18:00:00.000000 UTC**
+
+* Near the end of the 2 hour XXX-add-show-URL-here-XXX YouTube show, the **source code** of the [IOCCC28 winning entries](#inventory) was published on [IOCCC GitHub winner repo](https://github.com/ioccc-src/winner) and on the [Official IOCCC website](../index.html).
+
+**No longer will there be many months** between when the winners are
+announced and their source code is made available. For **IOCCC28**
+the time was **less than 2 hours**. :-)
+
+
+### Increased submission quantity and quality
+
+The submissions to **IOCCC28** were remarkable when compared with previous contests, in both the
+**increased quantity and quality** of the submissions. As a result the judging process for **IOCCC28**
+was more challenging and required greater effort. Thankfully due to the above mentioned improvements,
+the judging process **took only 33 days**. Under the previous system it **would have taken much longer**!
+
+One thing that began to emerge after we exits the early rounds of judging and entered the middle rounds
+of judging was that we were very likely to have more winning entries than in previous contests.
+Even so, the final rounds of judging required more rounds and tool longer than in any previous IOCCC.
+
+At the end of the final round of the final rounds of judging, we had a record **23 winners of IOCCC28**,
+eclipsing the record of 15 winners!
+
+While we suspect that the 4 year gap between **IOCCC27** and **IOCCC28** allowed people extra
+time to improve their submissions, we also believe that people submitting to the IOCCC have
+adept in obfuscation and have become more skilled in the programming in the C language.
+
+
+### Code size and Rule 2
+
+We were pleased to observe that while the [IOCCC size limit](../faq.html#size_rule_history)
+increased by about 21%, we received many submissions that were well under the new
+[Rule 2 size limit](../next/rules.html#rule2) including a fair number of quality
+small and medium sized submissions. Half of the **IOCCC28 winners** were less than
+_2/3 of the size limit_, and 10 of the **IOCCC28 winners** were less than
+_1/2 of the size limit_!
+
+**IMPORTANT NOTE**: The [IOCCC size limit](../faq.html#size_rule_history) increase for **IOCCC28**
+was the first size increase in over 10 years. Given the quality of submissions we received
+that were well under the limit, we do **NOT** expect to change the
+[Rule 2 size limit](../next/rules.html#rule2) for **at least another 10 years** (and likely longer).
+
+**IMPORTANT HINT**: Only 3 of 23 the **IOCCC28 winners** came close to the [Rule 2 size limit](../next/rules.html#rule2).
+Large code size isn't everything. :-) Those submitting to future contents should
+**take a careful note** of that fact.
+
+
+### Rules and Guidelines for this contest
+
+Here are the final versions of the IOCCC rules and guidelines that were in effect for this contest:
+
+* [2024 rules](rules.html) version **28.30 2025-03-03**
+* [2024 guidelines](guidelines.html) version **28.47 2025-03-15**
+
+
+### Looking forward to the next contest
+
+The [IOCCC Judges](../judges.html) realize that the [IOCCC rules](../next/rules.html) and
+the [IOCCC guidelines](../next/guidelines.html) need to be **greatly improved and streamlined**.
+We decided to not overhaul them for **IOCCC28** so as to **NOT** delay the opening of the contest.
+
+After the [IOCCC Judges](../judges.html) take a short _IOCCC Vacation_ (we have been working solid
+on **IOCCC28** since **2020 Dec 30**), we plan to update, improve and streamline the
+[IOCCC rules](../next/rules.html) and the [IOCCC guidelines](../next/guidelines.html) for **IOCCC29**.
+Then we will address whatever bug fixes in the form of GitHub Pull Requests to both the
+[IOCCC GitHub winner repo](https://github.com/ioccc-src/winner) and the
+[mkiocccentry toolkit repo](https://github.com/ioccc-src/mkiocccentry) that may be pending.
+
+Once we are all caught up, we will set the opening date for **IOCCC29**. It is our plan
+to open **IOCCC29** sometime in **2025 December**.
+
+
+## Remarks on some of the winning entries
+
+There were a number of remarkable winning entries for **IOCCC28**. We wish to call
+attention to a few of them:
+
+* [2024/kurdyukov1](kurdyukov1/index.html)
+
+This entry is a fun revisit of the theme of [2000/natori](../2000/natori/index.html),
+only better and without using any floating point arithmetic. You are invited
+to try and understand why the constant `2551443` is common to both entries.
+
+* [2024/cable1](cable1/index.html)
+
+This entry claims to be "_the world’s smallest LLM (large language
+model) inference engine_": running open-source model based on Meta’s
+LLaMA 2 with 7 billion parameters. After downloading the model via the
+[2024/cable1/get_model.sh](%%REPO_URL%%/2024/cable1/get_model.sh) script,
+we invite you explore this **ChatIOCCC** tool. While not super fast,
+the tool's output can be amusing.
+
+You might wish to ask **ChatIOCCC**: "_Why did this entry win IOCCC28?_"?
+
+We encourage you to read and understand the
+[2024/cable1/prog.c source code](%%REPO_URL%%/2024/cable1/prog.c). Then see
+if the **ChatIOCCC** tool can offer any new, or even correct insights
+into the code's obfuscation. :-)
+
+* [2024/howe](howe/index.html)
+
+"_Eh_"? The source code, with its UTF-8 conforming accent gives you a
+polite editor that is more functional an `ed(1)`.
+
+We invite you to use the program to view the UTF-8 fun in the
+[2024/howe/prog.c source code](%%REPO_URL%%/2024/howe/prog.c).
+
+**HINT to emacs users**: type **Q** or press **CTRL+C** to exit. 🤓
+
+* [2024/stedolan](stedolan/index.html)
+
+When you view the [prog.c source code](%%REPO_URL%%/2024/stedolan/prog.c),
+notice magic numbers. This **one liner** packs a significant amount
+of obfuscation in only 135 bytes!
+
+Try giving 10 hex digits to standard input of the program. Then try a
+different hex digits value. Then feed the MD5 hash of the
+[2024/stedolan/prog.c source code](%%REPO_URL%%/2024/stedolan/prog.c) and
+"_C_" what happens. :-)
+
+* [2024/endoh1](endoh1/index.html)
+
+The [2024/endoh1/try.sh](%%REPO_URL%%/2024/endoh1/try.sh) will carry you on
+a journey that tests your patience as well as the patience of the C-preprocessor.
+
+Building a 8x8 image requires order of 20 seconds of C-preprocessor
+time, when running 6 jobs on 4 CPU cores in parallel. Unfortunately,
+with such a tiny image, it is hard to appreciate the image being rendered.
+
+So you might try building a 32x32 form of the image, invoking the
+C-preprocessor 1024 times. When using 6 jobs on 4 CPU cores in parallel,
+this might take about 5.5 minutes to complete. However, the small image
+only gives you a hint of the image being rendered.
+
+If you have the time you might try building a 128x128 image, invoking
+the C-preprocessor 16384 times. With 6 jobs on 4 CPU cores in parallel,
+this will take about 1.5 hours. At this scale you might consider it
+worthwhile to render a more detailed image.
+
+Using 6 jobs on 4 CPU cores in parallel, to build a 512x512 image invoking
+the C-preprocessor 262144 times over a period of about 23.5 hours, you
+will be given an image with a reasonable amount of detail to appreciate
+what is being rendered.
+
+One fun aspect of the [2024/endoh1/prog.c source code](%%REPO_URL%%/2024/endoh1/prog.c)
+is that when it is compiled an executed, the program outputs C code.
+That C code, call it `rt.c` will fail to compile! But that is OK because the C-preprocessor
+has enough work to do without bothering the C compiler. :-)
+
+We plan to recognise those who report that they [rendered a new record sized image](endoh1/index.html#larger).
+
+* [2024/weaver](weaver/index.html)
+
+As the expression goes, “Seeing (and hearing) is believing”: or at least can lead to better understanding of the code. :o)
+
+After studying the [2024/weaver/prog.c source code](%%REPO_URL%%/2024/weaver/prog.c),
+we suggest you compile and run the program for more information.
+
+* [2024/mills](mills/index.html)
+
+This won the "**Prize in ℤ₃**", but what does that mean? Well,
+the "_double-struck Z_" is **NOT** a reference to a set of integers,
+nor is the "_double-struck Z subscript 3_" a reference to a ring of
+3-adic integers. Instead, it is a reference to the 3rd version of a
+certain [virtual machine](https://en.wikipedia.org/wiki/Z-machine).
+
+If you use the [2024/mills/try.sh](%%REPO_URL%%/2024/mills/try.sh) script, you will first be given
+an opportunity to view the [2024/mills/prog.c source code](%%REPO_URL%%/2024/mills/prog.c).
+Then you will be given 10 choices to play.
+
+**HINT**: If you select **0**: Try to not be eaten by a Grue when
+reading/navigating the twisty mazes of this source code! :-)
+
+* [2024/codemeow](codemeow/index.html)
+
+As you study the [2024/codemeow/prog.c source code](%%REPO_URL%%/2024/codemeow/prog.c),
+try not to lose track of the forest of obfuscation while tracking down the execution path trees.
+
+We think this code will "grow on you" as the C expression goes just a compiled C code "_grows on parse trees_". :-)
+
+* [2024/kurdyukov2](kurdyukov2/index.html)
+
+If seeing is believing, and you believe you understand the
+[2024/kurdyukov2/prog.c source code](%%REPO_URL%%/2024/kurdyukov2/prog.c),
+then you might be able to see how the code words.
+
+**QUESTION**: How many of the "_magic numbers_" in the program do you understand?
+
+* [2024/kurdyukov3](kurdyukov3/index.html)
+
+The prize, "**virtual quietus**", is a virtual reference to the doom that awaits you when
+you run this code: let alone when your try to figure out how the author was able to
+encode the virtual machine in under **2.5K bytes** of [prog.c source code](%%REPO_URL%%/2024/kurdyukov3/prog.c)!
+
+**NOTE**: The implementation runs without sound or mouse
+input. You will need reply on your keyboard skills. The
+[2024/kurdyukov3/try.sh](%%REPO_URL%%/2024/kurdyukov3/try.sh)
+demonstration script will give you some useful keyboard hints.
+
+* [2024/cable2](cable2/index.html)
+
+To those who follow the concept of "_seeing is believing_" will very
+likely be "_deceived_" when they try to see the source in terminal window:
+
+```
+ cat 2024/cable2/prog.c
+```
+
+Viewing the [prog.c source code](%%REPO_URL%%/2024/cable2/prog.c) in most editors
+might suggest that the is something fishy 🐠 with the code.
+
+* [2024/straadt](straadt/index.html)
+
+Have you ever wondered would what would happen if you recursively removed
+files starting from the root directory? Are you curious what happens when
+you launch a [fork bomb](https://en.wikipedia.org/wiki/Fork_bomb)?
+You can safely give those and other scenarios under this virtual machine.
+
+We invite you to explore the [prog.c source code](%%REPO_URL%%/2024/straadt/prog.c)
+to explore this interesting virtual machine implementation. And as a bonus, a
+full-fledged C64 emulator is included!
+
+* [2024/ferguson2](ferguson2/index.html)
+
+The "**Prize in yil-tas**" provides a hint as to what this marvelous
+winning entry is going, provided that you are someone familiar in at
+least 3 languages (**hint**: One of them is C, another id English).
+
+The IOCCC is honored to present this entry for your enjoyment and you ponder
+the [prog.c source code](%%REPO_URL%%/2024/ferguson2/prog.c).
+
+* [2024/carlini](carlini/index.html)
+
+The IOCCC has seen a number of winning entries that allow code designed to
+run on early Intel processors, however none of them emulate a processor as
+early as the [Intel 4004](https://en.wikipedia.org/wiki/Intel_4004).
+Launched in 1971, the 4004 was the core of the first commercially marketed
+microprocessor chipset.
+
+The [2024/carlini/prog.c](%%REPO_URL%%/2024/carlini/prog.c)
+code runs rather slow, so patience is required to watch
+[4004](https://en.wikipedia.org/wiki/Intel_4004#/media/File:Intel_C4004.jpg)
+code run. This is very understandable when you realize that the
+[2024/carlini/prog.c](%%REPO_URL%%/2024/carlini/prog.c) is actually
+emulating the entire
+[4004 chip circuit](https://en.wikipedia.org/wiki/Intel_4004#/media/File:Chip_layout_from_the_development_phase_of_the_Intel_4004_from_1971,_the_first_microprocessor_of_the_world_(cropped_and_edited_image).jpg)
+by computing the output of each gate in a loop, effectively running the CPU and associated RAM/ROM chips!
+
+
+### Remarks on some of submissions that did not win
+
+* Depending on the address of a variable, as not all platforms support
+[ASLR](https://en.wikipedia.org/wiki/Address_space_layout_randomization),
+as the single source of pseudo-randomness isn’t a good idea. It’s
+much better to mix in other sources of variability (e.g. time, process
+ID, etc.) so that subsequent runs will behave differently.
+
+* If a submission's obfuscation strongly resembles a past IOCCC winning
+entry, and the submission's obfuscation is mainly in the C code source,
+then the submission likely to not make it into the final rounds of judging.
+
+* When working with modern C compilers, it’s crucial to explicitly
+declare variable and function types. Don’t assume they’ll
+automatically default to an `int`.
+
+* Sadly, K&C-style C code does not compile well under modern C compilers.
+
+* A submission that only works under gcc or clang does not work as well
+as submissions that can work under either compiler.
+
+* Shrinking an existing open-source program to meet rule 2 size might
+be an impressive feat of code shrinking, but it might not be enough to
+make it into the final rounds of judging. Originality is key, and this
+might not be the most innovative approach.
+
+* If your submission relies on mathematical algorithms, be sure that the
+C code that implements the mathematics is well obfuscated.
+
+* Just a friendly reminder that before you upload your submissions,
+uncompress the compressed tarball into a different directory. This way,
+you can be sure you didn’t miss uploading any important files!
+
+* Using a lot of goto statements to make your code harder to understand
+might not help it pass the final rounds of judging.
+
+
+### Encouragement for those who did not win this year
+
+We know many of you that submitted to the IOCCC put in a ton of effort
+into your submissions for this year’s IOCCC. We can’t just give out
+awards to everyone. That would mean taking away from the submissions
+that we think are the best and deserve to win.
+
+Sometimes, a final round submission might be good enough to be a
+winning IOCCC entry, only to be beaten by a similar, but slightly better
+submission. If you think this happened with your submission, consider
+submitting an enhanced version to the next IOCCC.
+
+**PLEASE DO NOT** give up hope! There are some submissions that have been
+submitted with revisions, multiple times before rising to the level of
+a winning IOCCC entry. You might also want to try with a different type
+of submission altogether for the next IOCCC.
+
+If you’re not planning to improve and resubmit your non-winning entry
+for the next IOCCC, you’re welcome to publish it.
+
+
+## On Compiling and running winning entries
+
+Some C compilers aren’t as great as they could be. If yours isn’t
+working well, you might want to try compiling with an updated version
+of clang and/or gcc instead.
+
+If you encounter problems in compiling and/or running the winning entries, see the FAQ on:
+
+* [Compiling IOCCC entries](../faq.html#compiling)
+* [IOCCC entry dependencies](../faq.html#dependencies)
+* [Problems compiling entries](../faq.html#compile_problems)
+* [Running IOCCC entries](../faq.html#running_entries)
+
+For additional information on how to submit fixes, see the FAQ on:
+
+* [How to submit a fix](../faq.html#fix_an_entry) - how to submit a fix to an entry
+* [Update author information](../faq.html#fix_author) - how to correct or update an IOCCC author’s information
+
+
+### For even more information
+
+* [Reporting an IOCCC website problem](../faq.html#report_website_problem)
+* [Submitting a fix to the IOCCC website](../faq.html#fix_website)
+* [How to contact the IOCCC](../contact.html) - up to date contact details
+* [IOCCC FAQ](../faq.html) - additional information on the IOCCC
+* [www.ioccc.org](https://www.ioccc.org) - the primary IOCCC website
+
+
+
diff --git a/2024/anders/.entry.json b/2024/anders/.entry.json
new file mode 100644
index 000000000..f59b1a457
--- /dev/null
+++ b/2024/anders/.entry.json
@@ -0,0 +1,97 @@
+{
+ "no_comment" : "mandatory comment: because comments were removed from the original JSON spec",
+ "entry_JSON_format_version" : "1.2 2024-09-25",
+ "award" : "Prize in sound coding",
+ "year" : 2024,
+ "dir" : "anders",
+ "entry_id" : "2024_anders",
+ "title" : "aks",
+ "abstract" : "layered music generator",
+ "author_set" : [
+ {
+ "author_handle" : "Anders_Kaare_Straadt"
+ }
+ ],
+ "manifest" : [
+ {
+ "file_path" : "prog.c",
+ "inventory_order" : 20,
+ "OK_to_edit" : true,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "entry source code"
+ },
+ {
+ "file_path" : "Makefile",
+ "inventory_order" : 30,
+ "OK_to_edit" : true,
+ "display_as" : "makefile",
+ "display_via_github" : true,
+ "entry_text" : "entry Makefile"
+ },
+ {
+ "file_path" : "prog.orig.c",
+ "inventory_order" : 50,
+ "OK_to_edit" : false,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "original source code"
+ },
+ {
+ "file_path" : "try.sh",
+ "inventory_order" : 100,
+ "OK_to_edit" : true,
+ "display_as" : "shellscript",
+ "display_via_github" : true,
+ "entry_text" : "script to try entry"
+ },
+ {
+ "file_path" : "2024_anders.tar.bz2",
+ "inventory_order" : 1415926535,
+ "OK_to_edit" : false,
+ "display_as" : "tbz2",
+ "display_via_github" : false,
+ "entry_text" : "download entry tarball"
+ },
+ {
+ "file_path" : ".entry.json",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : true,
+ "display_as" : "json",
+ "display_via_github" : true,
+ "entry_text" : "entry summary and manifest in JSON"
+ },
+ {
+ "file_path" : ".gitignore",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : true,
+ "display_as" : "gitignore",
+ "display_via_github" : true,
+ "entry_text" : "list of files that should not be committed under git"
+ },
+ {
+ "file_path" : ".path",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : false,
+ "display_as" : "path",
+ "display_via_github" : false,
+ "entry_text" : "directory path from top level directory"
+ },
+ {
+ "file_path" : "README.md",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : true,
+ "display_as" : "markdown",
+ "display_via_github" : true,
+ "entry_text" : "markdown source for this web page"
+ },
+ {
+ "file_path" : "index.html",
+ "inventory_order" : 4294967295,
+ "OK_to_edit" : false,
+ "display_as" : "html",
+ "display_via_github" : false,
+ "entry_text" : "this web page"
+ }
+ ]
+}
diff --git a/2024/anders/.gitignore b/2024/anders/.gitignore
new file mode 100644
index 000000000..f3143b448
--- /dev/null
+++ b/2024/anders/.gitignore
@@ -0,0 +1 @@
+prog.wav
diff --git a/2024/anders/.path b/2024/anders/.path
new file mode 100644
index 000000000..ddb66625f
--- /dev/null
+++ b/2024/anders/.path
@@ -0,0 +1 @@
+2024/anders
diff --git a/2024/anders/2024_anders.tar.bz2 b/2024/anders/2024_anders.tar.bz2
new file mode 100644
index 000000000..e11d04044
Binary files /dev/null and b/2024/anders/2024_anders.tar.bz2 differ
diff --git a/2024/anders/Makefile b/2024/anders/Makefile
new file mode 100644
index 000000000..2b41f1721
--- /dev/null
+++ b/2024/anders/Makefile
@@ -0,0 +1,216 @@
+#!/usr/bin/env make
+#
+# 2024/anders
+
+#############################
+# shell used by this Makefile
+#############################
+
+SHELL= bash
+
+
+#######################
+# common tool locations
+#######################
+
+include ../../var.mk
+
+
+#####################
+# C compiler settings
+#####################
+
+# Common C compiler warnings to silence
+#
+# NOTE: Please don't add -Wno-unknown-warning-option to CSILENCE
+# (or to CUNKNOWN)
+#
+# NOTE: The author says this about -Wno-unsafe-buffer-usage
+#
+# # nah i'm not really into rust
+#
+CSILENCE= -Wno-int-in-bool-context -Wno-out-of-line-declaration \
+ -Wno-unsafe-buffer-usage
+
+# Attempt to silence unknown warning options
+#
+CUNKNOWN=
+
+# Common C compiler warning flags
+#
+# NOTE: The addition of -pedantic to CWARN is a challenge that
+# You may wish to avoid if it proves too problematic.
+# There is NO penalty for removing -pedantic from CWARN.
+#
+CWARN= -Wall -Wextra -pedantic ${CSILENCE} ${CUNKNOWN}
+
+# Compiler standard
+#
+CSTD= -std=gnu17
+
+# Compiler bit architecture
+#
+# Example for 32-bitness: ARCH= -m32
+# Example for 64-bitness: ARCH= -m64
+#
+# NOTE: Normally one should NOT specify a specific architecture.
+#
+ARCH=
+
+# Defines that are needed to compile
+#
+# Example: -Dfoo -Dbar=baz
+#
+CDEFINE=
+
+# Include files that are needed to compile
+#
+# Example: CINCLUDE= -include stdio.h
+#
+CINCLUDE=
+
+# Other flags to pass to the C compiler
+#
+# Example: COTHER= -fno-math-errno
+#
+COTHER=
+
+# Optimization
+#
+# NOTE: Feel free to change the level of compiler optimization.
+# The "-O3" is just a friendly default you might wish to try.
+#
+# Example: OPT= -O0 -g
+#
+OPT= -O3
+
+# Default flags for ANSI C compilation
+#
+CFLAGS= ${CSTD} ${CWARN} ${ARCH} ${CDEFINE} ${CINCLUDE} ${COTHER} ${OPT}
+
+# Libraries needed to build
+#
+# Example: LDFLAGS= -lncurses -lm
+#
+LDFLAGS= -lm
+
+# C compiler to use
+#
+# NOTE: The IOCCC Judges recommend you leave CC as just "cc"
+# and NOT set it to clang, or gcc, or something else
+# unless you have a STRONG reason to do so.
+#
+# Setting CC to something other than "cc" makes your
+# code less portable to those who do not have your
+# particular C compiler. **hint**
+#
+# If you want to test your code with a particular C compiler,
+# use the make command line. For example:
+#
+# make all CC=clang
+# make all CC=gcc
+#
+CC= cc
+
+# Compiler add-ons or replacements for clang only
+#
+ifeq "$(findstring $(CLANG),${CC})" "$(CLANG)"
+#
+# NOTE: This code is only invoked when CC is "clang"
+# such as when you use the make command line:
+#
+# make all CC=clang
+#
+CSILENCE+= -Wno-poison-system-directories -Wno-unknown-warning-option
+#
+CWARN+= -Weverything
+#
+endif
+
+# Specific add-ons or replacements for gcc only
+#
+ifeq "$(findstring $(GCC),${CC})" "$(GCC)"
+#
+# NOTE: This code is only invoked when CC is "gcc"
+# such as when you use the make command line:
+#
+# make all CC=gcc
+#
+CSILENCE+=
+#
+CWARN+=
+#
+endif
+
+
+###########################################
+# Special Makefile variables for this entry
+###########################################
+
+ENTRY= prog
+PROG= ${ENTRY}
+#
+OBJ= ${PROG}.o
+TARGET= ${PROG}
+#
+ALT_OBJ=
+ALT_TARGET=
+
+# list any data files supplied with your submission
+#
+# Example: DATA= curds whey
+#
+DATA=
+
+
+#################
+# build the entry
+#################
+
+all: data ${TARGET}
+ @${TRUE}
+
+.PHONY: all alt data everything clean clobber
+
+# how to compile
+#
+${PROG}: ${PROG}.c
+ ${CC} ${CFLAGS} ${PROG}.c -o $@ ${LDFLAGS}
+
+# alternative executable
+#
+alt: data ${ALT_TARGET}
+ @${TRUE}
+
+${PROG}.alt: ${PROG}.alt.c
+ ${CC} ${CFLAGS} ${PROG}.alt.c -o $@ ${LDFLAGS}
+
+# data files
+#
+data: ${DATA}
+ @${TRUE}
+
+# both all and alt
+#
+everything: all alt
+ @${TRUE}
+
+
+###############
+# utility rules
+###############
+#
+clean:
+ ${RM} -f ${OBJ} ${ALT_OBJ}
+
+clobber: clean
+ ${RM} -f ${TARGET} ${ALT_TARGET}
+ ${RM} -rf *.dSYM
+ ${RM} -f prog.wav
+
+
+######################################
+# optional include of 1337 hacker rulz
+######################################
+
+-include 1337.mk ../1337.mk ../../1337.mk
diff --git a/2024/anders/README.md b/2024/anders/README.md
new file mode 100644
index 000000000..0ed5d3f2a
--- /dev/null
+++ b/2024/anders/README.md
@@ -0,0 +1,93 @@
+## To build:
+
+```
+ make all
+```
+
+
+## To use:
+
+```
+ ./prog
+```
+
+
+## Try:
+
+```
+ ./prog
+```
+
+and then play the resulting `prog.wav` using a sound player.
+
+
+## Judges' remarks:
+
+When you run the program, after several moments, a `prog.wav` sound file is produced.
+
+Using a sound player (you may find `sox(1)` is a good choice), you may enjoy the result.
+
+Can you figure out how it produces the various layers of instruments?
+
+
+## Author's remarks:
+
+
+### Obfuscations
+
+ - "Helpful" formatting
+ - Character salad
+ - Loop exit trying to hide by a switch statement
+ - Strong string encryption. By that I mean "fmt"=>"gnu".
+ - A `/*{*/` that throws off bracket matching in vim. Begun the editor wars
+ have! (Wait, I'm **on** the vim-team!)
+ - `cm` and `ap` stands for "allpass" and "comb", respectively.
+ - One effect was created with deliberate "memory corruption".
+
+To encourage tinkering I've obfuscated the song data and program (see Y()) less
+than the "library code". Sorry if you wanted to tinker with the library code!
+
+### Sound quality
+
+The sample rate of prog.wav is 256kHz because creating aliasing-free waveforms
+would require more code, but you can always oversample the audio and pass the
+anti-aliasing problem on to the audio player :-) However, the downsampler in my
+`mplayer(1)` is poor, but you can use the high-quality resampler in `sox(1)` to create a
+48kHz version:
+
+```
+ sox prog.wav -r 48000 prog.48kHz.wav
+```
+
+### Tricks (the condescending part)
+
+ - Kick drum from sines, pitched up to create toms.
+ - Roland TR-808 style hi-hats (a bunch of high-pass filtered square waves).
+ - SID/C64-style snare drum (oscillates between noise and square wave).
+ - There's some FM synthesis in the bass.
+ - Schroeder reverberator a la Freeverb. The same building blocks are used for
+ the echo effect.
+ - Waveshaping/overdrive using tanh(x), ohh yeaaah..
+
+I used this Python snippet to generate `q0[2]` and `q0[3]`:
+
+```
+ def X(s): print(hex(int(s.replace("x","1").replace(".","0")[::-1],2))) # not for iopcc-use
+ X(".x.x..xx.x.xx.xxx.xx.xxx..xx.xxx")
+ X("x.xx.x.x.x.xxxxxx.xx.xxx.xxxxxxx")
+```
+
+
+
diff --git a/2024/anders/index.html b/2024/anders/index.html
new file mode 100644
index 000000000..8c210bd66
--- /dev/null
+++ b/2024/anders/index.html
@@ -0,0 +1,638 @@
+
+
+
+
+
+
+
+
+
+
+
+
+2024/anders - Prize in sound coding
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
and then play the resulting prog.wav using a sound player.
+
Judges’ remarks:
+
When you run the program, after several moments, a prog.wav sound file is produced.
+
Using a sound player (you may find sox(1) is a good choice), you may enjoy the result.
+
Can you figure out how it produces the various layers of instruments?
+
Author’s remarks:
+
Obfuscations
+
+
“Helpful” formatting
+
Character salad
+
Loop exit trying to hide by a switch statement
+
Strong string encryption. By that I mean “fmt”=>“gnu”.
+
A /*{*/ that throws off bracket matching in vim. Begun the editor wars
+have! (Wait, I’m on the vim-team!)
+
cm and ap stands for “allpass” and “comb”, respectively.
+
One effect was created with deliberate “memory corruption”.
+
+
To encourage tinkering I’ve obfuscated the song data and program (see Y()) less
+than the “library code”. Sorry if you wanted to tinker with the library code!
+
Sound quality
+
The sample rate of prog.wav is 256kHz because creating aliasing-free waveforms
+would require more code, but you can always oversample the audio and pass the
+anti-aliasing problem on to the audio player :-) However, the downsampler in my
+mplayer(1) is poor, but you can use the high-quality resampler in sox(1) to create a
+48kHz version:
+
sox prog.wav -r 48000 prog.48kHz.wav
+
Tricks (the condescending part)
+
+
Kick drum from sines, pitched up to create toms.
+
Roland TR-808 style hi-hats (a bunch of high-pass filtered square waves).
+
SID/C64-style snare drum (oscillates between noise and square wave).
+
There’s some FM synthesis in the bass.
+
Schroeder reverberator a la Freeverb. The same building blocks are used for
+the echo effect.
+
Waveshaping/overdrive using tanh(x), ohh yeaaah..
+
+
I used this Python snippet to generate q0[2] and q0[3]:
+
def X(s): print(hex(int(s.replace("x","1").replace(".","0")[::-1],2))) # not for iopcc-use
+ X(".x.x..xx.x.xx.xxx.xx.xxx..xx.xxx")
+ X("x.xx.x.x.x.xxxxxx.xx.xxx.xxxxxxx")
Do not read this if you want to figure it out yourself!
+
The file deobfuscated.c is simply a pretty-printed version of
+prog.c with the macros expanded. It is hopefully just as
+difficult to understand as the original presentation:
+obfuscation is not just presentation, after all.
+
If you read further, the remainder talks about how the code
+works. If you want to figure it out yourself, stop reading here
+and do look at deobfuscated.c.
+
Read Dictionary
+
The program begins by reading junk ;-) from the dictionary and processing
+via D(). The words are stored in t[][], counted by s and D() ensures
+this never has buffer overflow. Notice the swap of index and array in s[t].
+It also ensures only 5 letter words are selected from the dictionary,
+and folds uppercase to lowercase. Each call of D() handles one word.
+
NB: if the dictionary has, for instance, “ARRAY” and “array” and “Array”,
+there will be 3 copies of “array” stored in t[][].
+This will degrade performance and may cause a malfunction of the algorithm,
+and definitely if the target word is “array”. Thus the makefile builds
+usdw with capital letters removed (avoiding this problem completely).
+However, if there are duplicate words in the dictionary, use another.
+
User Input
+
After the dictionary is read, it is time to prompt the user for the
+input guess. This happens in main(). The input buffer is the upper
+half of i.a, which is never used (ASCII lowercase letters only).
+The newline is ignored by n - 10, at most 11 characters (l < j)
+can be input, and EOF terminates the input loop.
+
Here is the explanation of how i.c - 97 works to get an input buffer.
+Assume struct i has the address 1000, then i.a begins at 1000.
+i.b begins at 1257. i.c begins at 9*5 = 45 + 1257 = 1302.
+1302 - 97 = 1205. Therefore, the i.c - 97 sets the input buffer at
+&i.a[205], ASCII lowercase input ends at i.a[123], and there are
+53 characters before i.b is overwritten - plenty of room for the user IO.
+Why 97? The expression x - 97 is used several times in the code,
+leading to some confusion on the reason for the value.
+
Note that this abuse is what draws a compiler complaint, requiring:
+
-Wno-array-bounds-pointer-arithmetic
+
It is safe. It works. There is no problem here, but the compiler
+does not know this.
+
Process User Input
+
Once the user input is received, the program calls r(), which populates
+struct i with the guesses. This serves to set the patterns known
+and impossible, as well as letters used and required (remember, this is
+hard mode Wordle, which requires you to use all green letters in the
+same place for all subsequent guesses). r() returns the next word
+to guess via E() (aka choose() - see below).
+
Within r(), it is important to understand the ASCII values for g, y and b.
+
b 98
+ g 103
+ y 121
+
Within r(), n is the guessed letter, and o is color - 103.
+If o is greater than zero (121-103), this guess is correct, but
+incorrect location (yellow). If it is less than zero (98-103),
+this guess is not possible (black). If it is zero (103-103),
+it is the correct letter in the correct location (green).
+
struct i can be re-written this way:
+
struct {
+ char black[256]; // wrong letters guessed so far
+ char words[9][5]; // words used in guesses so far
+ char green[5]; // correct letters (must reuse these)
+ char yellow[5]; // incorrect letters (impossible positions)
+ int num_guesses;
+ int num_yellow;
+ } i;
+
And r() can be rewritten:
+
char *r(char *input) {
+ int num_green = 0, l = 0;
+
+ for (int j = 0; j < 5; ++j) {
+ char n = input[j];
+ signed char o = input[j + 6] - 103; // j - ~5 = j - -6 == j + 6
+
+ // if this is a correct guess
+ if (o == 0) {
+ i.green[j] = n;
+ i.black[n] = 0; // remove this from black
+ ++num_green;
+
+ } else {
+ i.words[i.num_guesses][j] = n;
+
+ // if not already a yellow letter
+ if (memchr(i.yellow, n, 5) == NULL) {
+ l = n;
+ if (o < 0) i.black[n] = n; // black, impossible
+ else i.yellow[i.num_yellow++] = n;
+ }
+ }
+ }
+
+ // l is 0 if all letters correct, else l = n
+ i.num_guesses += l > 0 ? 1 : 0;
+ filter(input, num_green);
+ return choose("xyzzy");
+ }
+
Filter
+
The next step is to remove the impossible words from the in-memory dictionary.
+This is handled by L(). L() iterates over all the remaining words in the
+dictionary. L() runs a number of filters, and if the word is plausible,
+it is skipped, and if impossible, the current word is replaced from the end
+of the list. This prevents holes from appearing in the dictionary, and keeps
+the count accurate. The important action is carried out in the expression
+o ? W(t[l], t[--s]) : ++l. That is, if o is true, the word is replaced
+by the end of the list, else the word is skipped. Note in particular the
+expressions --s and ++l (decrement and replace, or skip, respectively).
+
Said another way, think of W() as an analog of strncpy(). Thus, if o
+is true, then strncpy(t[l], t[--s], 5), which overwrites the current word
+with the end of the list, and decrements the number of entries. Note the
+end of the list is not t[s], but t[s-1], thus the pre-decrement achieves
+both the desired index and decrements the count.
+
Word Selection
+
After the words are filtered, then comes the hard part: selecting which word
+to guess next! This is handled by E(), by far the most interesting routine
+in the code.
+
The loops in order:
+
+
init c[] with ordinal values (a-z plus 6 slop) in the lower 5 bits
+
in the higher order bits, count the frequency of all remaining letters
+
sort by the frequency of letters in 3 sets of 7 (21 not 26!)
+
merge the separate sorts into one via v() (see below on merging)
+
for letters with same freq, re-sort by English frequency values l()
+
using the sorted list, put the corresponding ordinals into b[]
+
for each word, if scores below 97, put into e[][] (low score wins)
+
allow up to 5 duplicate scores, only keep first 5 words with same score
+
search the list for the lowest scoring word (best match)
+
if more than 2 words remain, find first word without duplicate letters
+
return whatever we found, if anything
+
+
The weakness in this scheme is at least two-fold: 1) if there are more than 5
+words with the same score, words that come later are not selected, and 2) all
+words with the same score are considered the same, without regard to letter
+order or letter frequencies. I have run no experiments here,
+but I think this is an area for minor improvement.
+
Network Sort
+
Network sort1 is a simple, compact, constant time sort with minimal compares.
+
It is obfuscated in a number of ways.
+The routine S() looks into the array a[] and determines the number of
+elements to sort via the differences in the initial values of a[].
+Consider the possible number of values given in O from 0 (zero) to 7:
+if O is 0 or 1, no sort is necessary (an empty list cannot be sorted,
+and a list of one does not need to be sorted):
If O is 2, then only one compare and swap is necessary. Why is this?
+Consider how many compares are necessary to determine the proper order of
+variables A and B: one test and one possible swap are all that is needed.
+If A > B, swap. If A <= B, then no swap and the list is already ordered.
+
Where is this calculation done? Address arithmetic FTW!
+e = a[-~O] + s - a[O]. -~O is the identity O+1.
+So this expression restated is e = s + a[O+1] - a[O].
+If you look at the first numbers in a[] and their offsets (table 1):
This compact arrangement can be split into high and low nibbles:
+
{ (1,2), (3,4), (5,6), (0,2), (3,5), ... }
+
which means compare and maybe swap (keeping order low to high):
+
if (s[1] > s[2]) swap();
+ if (s[3] > s[4]) swap();
+ if (s[5] > s[6]) swap();
+ if (s[0] > s[2]) swap();
+ if (s[3] > s[5]) swap();
+ ....
+
For instance, when sorting 7 elements, start from a[a[7]] (39) until
+a[a[8]] (55), or 16 elements starting at a[39].
+
The Array a[] Explained, Finally
+
The first set of 9 numbers are both the lengths AND the start and end indexes
+into the array a[], as explained above in the Network Sort. The second set
+of numbers runs from indexes 9 through 54, and are the Network Sort comparison
+values. At index 55 begins the third part of the array. The final 26 values
+encode the inverse frequency of letters in the English language. The first
+value is 25 for the letter ‘a’. If you count, then 26 is for the letter ‘e’,
+the most common letter in the English language
+(or at least for the dictionary used).
+
This final set of letters is used in the routine l(). Notice the expression:
+a[f[j] + a[~-9]]; a[~-9] is an obscure way of writing a[8], which is the
+value 55. So a[f[j]] is an index into this frequency array, offset by 55.
+Why is there a << 5? Again, the letter offsets are in the lowest 5 bits,
+and the counts of the letters is in the upper bits.
+
The reason for putting the counts in the upper bits is simple: it makes the
+value larger for larger counts. Thus, sorting based upon frequency is natural.
+
Merge Sort
+
The network sort as implemented handles up to 7 letters in 3 calls.
+26 / 7 = 3 r 5. Thus, we need to merge up to 4 sets of 7 letters.
+This merge is handled by v(), which calls o() 3 times, once recursively.
+This is followed by a rearrangement handled in l(). This last step finds
+all the letters with the same frequency, then sorts them according to their
+English frequency.
+
Back to the merge sort, which is really handled in o(). This is rather
+difficult to follow. The first call to o() is within the argument list
+to the second call. The first call has arguments
+W=0, O=1, R=0, D=a, L=w, E=k; and v() was called with v(l=7, w=b, k=c).
+This first merge pass copies to: L[R] (b[0]) and selects from either
+c[o] or c[w] depending upon which is greater or equal. That is, it merges
+two 7 letter arrays into a single 14 element array twice, then it merges two 14
+element arrays into a single 28 element array. Note on the third call
+to o(), the last two arguments are swapped, which puts the final sort
+into c[].
+
Below is a hopefully easier way to read the merge sort code:
+
// merge residual
+ int e(int mult_o, int start, int to, int off, int *a1, int *a2)
+ {
+ for (; start < off; )
+ a1[to++] = a2[start++ + off * mult_o];
+ return to;
+ }
+
+ // merge sort
+ int o(int mult_o, int mult_w, int to, int len, int *a1, int *a2)
+ {
+ // first call: mult_o = 0, mult_w = 1, to = 0, len = 7, a1=b, a2=c
+ // second: mult_o = 2, mult_w = 3, to = N, len = 7, a1=b, a2=c
+ // third: mult_o = 0, mult_w = 1, to = 0, len = 14, a1=c, a2=b
+
+ int o = 0, w = 0;
+ for (; o < len && w < len; ) {
+
+ // first call: to=0, len=7, mult_o=0, mult_w=1
+ // a1[0++] = a2[0 + 7*0] >= a2[0 + 7*1]
+ // ? a2[0 + 7*0] : a2[0 + 7*1]
+ // a1[0++] = a2[0] > a2[7] ? a[0++] : a2[7++]
+
+ // second call: to=14, len=7, mult_o=2, mult_w=3
+ // a1[14++] = a2[0 + 7*2] >= a2[0 + 7*3]
+ // ? a2[0 + 7*2] : a2[0 + 7*3]
+ // a1[14++] = a2[14] > a2[21] ? a2[14++] : a2[21++]
+
+ // third call: to=0, len=14, mult_o=0, mult_w=1
+ // a1[0++] = a2[0 + 14*0] >= a2[0 + 14*1]
+ // ? a2[0 + 14*0] : a2[0 + 14*1];
+ // a1[0++] = a[0] >= a2[14] ? a2[0++] : a2[14++]
+
+ a1[to++] = a2[o + len * mult_o] >= a2[w + len * mult_w]
+ ? a2[o++ + len * mult_o]
+ : a2[w++ + len * mult_w]
+ }
+ int n = e(mult_o, o, to, len, a1, a2);
+ return e(mult_w, w, n, len, a1, a2);
+ }
+
Isn’t that as clear as mud? It is far easier to understand the flow when
+you add printf() statements to follow the logic. Included is the file
+deobfuscated.c for you to start with.
+
Why name the functions as they are?
+
Run make spoiler.
+
Bug Explained
+
If you followed the above explanation, you will notice that only the first
+21 of 26 letters are sorted (ignoring { v, w, x, y, z }. But 28 of 26 letters
+are merge sorted. It was observed the program performs worse if all 26 letters
+are sorted (which tends to over-favor y).
+But some words do have y in them, which is why the merge sort takes 28
+letters (including the ASCII values { and |), so all letters are still
+selected when appropriate. The merge sort puts the { v, w, x, y, z }
+letters into the proper frequency set, eventually.
+
If you change the loop value 22 to 32, then all letters are sorted,
+the program will work correctly, but it will change the performance
+of the algorithm to be slightly worse than the original.
+
If you change any values in the array a[],
+the program will no longer work correctly.
+
Finally, what is the significance of the array size 78557?
+usdw only needs 8506. Why was such a large value used?
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/2024/burton/deobfuscated.md b/2024/burton/deobfuscated.md
new file mode 100644
index 000000000..553d0f991
--- /dev/null
+++ b/2024/burton/deobfuscated.md
@@ -0,0 +1,382 @@
+# Do not read this if you want to figure it out yourself! #
+
+The file `deobfuscated.c` is simply a pretty-printed version of
+`prog.c` with the macros expanded. It is hopefully just as
+difficult to understand as the original presentation:
+obfuscation is not just presentation, after all.
+
+If you read further, the remainder talks about how the code
+works. If you want to figure it out yourself, stop reading here
+and do look at `deobfuscated.c`.
+
+
+## Read Dictionary ##
+
+The program begins by reading junk ;-) from the dictionary and processing
+via `D()`. The words are stored in `t[][]`, counted by `s` and `D()` ensures
+this never has buffer overflow. Notice the swap of index and array in `s[t]`.
+It also ensures only 5 letter words are selected from the dictionary,
+and folds uppercase to lowercase. Each call of `D()` handles one word.
+
+NB: if the dictionary has, for instance, "ARRAY" and "array" and "Array",
+there will be 3 copies of "array" stored in `t[][]`.
+This will degrade performance and may cause a malfunction of the algorithm,
+and definitely if the target word is "array". Thus the `makefile` builds
+`usdw` with capital letters removed (avoiding this problem completely).
+However, if there are duplicate words in the dictionary, use another.
+
+
+## User Input ##
+
+After the dictionary is read, it is time to prompt the user for the
+input guess. This happens in `main()`. The input buffer is the upper
+half of `i.a`, which is never used (ASCII lowercase letters only).
+The newline is ignored by `n - 10`, at most 11 characters (`l < j`)
+can be input, and EOF terminates the input loop.
+
+Here is the explanation of how `i.c - 97` works to get an input buffer.
+Assume `struct i` has the address 1000, then `i.a` begins at 1000.
+`i.b` begins at 1257. `i.c` begins at 9*5 = 45 + 1257 = 1302.
+1302 - 97 = 1205. Therefore, the `i.c - 97` sets the input buffer at
+`&i.a[205]`, ASCII lowercase input ends at `i.a[123]`, and there are
+53 characters before `i.b` is overwritten - plenty of room for the user IO.
+Why 97? The expression `x - 97` is used several times in the code,
+leading to some confusion on the reason for the value.
+
+Note that this abuse is what draws a compiler complaint, requiring:
+
+```
+ -Wno-array-bounds-pointer-arithmetic
+```
+
+It is safe. It works. There is no problem here, but the compiler
+does not know this.
+
+
+## Process User Input ##
+
+Once the user input is received, the program calls `r()`, which populates
+`struct i` with the guesses. This serves to set the patterns known
+and impossible, as well as letters used and required (remember, this is
+hard mode Wordle, which requires you to use all green letters in the
+same place for all subsequent guesses). `r()` returns the next word
+to guess via `E()` (aka choose() - see below).
+
+Within `r()`, it is important to understand the ASCII values for g, y and b.
+
+```
+ b 98
+ g 103
+ y 121
+```
+
+Within `r()`, `n` is the guessed letter, and `o` is color - 103.
+If `o` is greater than zero (121-103), this guess is correct, but
+incorrect location (yellow). If it is less than zero (98-103),
+this guess is not possible (black). If it is zero (103-103),
+it is the correct letter in the correct location (green).
+
+`struct i` can be re-written this way:
+
+```
+ struct {
+ char black[256]; // wrong letters guessed so far
+ char words[9][5]; // words used in guesses so far
+ char green[5]; // correct letters (must reuse these)
+ char yellow[5]; // incorrect letters (impossible positions)
+ int num_guesses;
+ int num_yellow;
+ } i;
+```
+
+And `r()` can be rewritten:
+
+```
+ char *r(char *input) {
+ int num_green = 0, l = 0;
+
+ for (int j = 0; j < 5; ++j) {
+ char n = input[j];
+ signed char o = input[j + 6] - 103; // j - ~5 = j - -6 == j + 6
+
+ // if this is a correct guess
+ if (o == 0) {
+ i.green[j] = n;
+ i.black[n] = 0; // remove this from black
+ ++num_green;
+
+ } else {
+ i.words[i.num_guesses][j] = n;
+
+ // if not already a yellow letter
+ if (memchr(i.yellow, n, 5) == NULL) {
+ l = n;
+ if (o < 0) i.black[n] = n; // black, impossible
+ else i.yellow[i.num_yellow++] = n;
+ }
+ }
+ }
+
+ // l is 0 if all letters correct, else l = n
+ i.num_guesses += l > 0 ? 1 : 0;
+ filter(input, num_green);
+ return choose("xyzzy");
+ }
+```
+
+
+## Filter ##
+
+The next step is to remove the impossible words from the in-memory dictionary.
+This is handled by `L()`. `L()` iterates over all the remaining words in the
+dictionary. `L()` runs a number of filters, and if the word is plausible,
+it is skipped, and if impossible, the current word is replaced from the end
+of the list. This prevents holes from appearing in the dictionary, and keeps
+the count accurate. The important action is carried out in the expression
+`o ? W(t[l], t[--s]) : ++l`. That is, if `o` is true, the word is replaced
+by the end of the list, else the word is skipped. Note in particular the
+expressions `--s` and `++l` (decrement and replace, or skip, respectively).
+
+Said another way, think of `W()` as an analog of `strncpy()`. Thus, if `o`
+is true, then `strncpy(t[l], t[--s], 5)`, which overwrites the current word
+with the end of the list, and decrements the number of entries. Note the
+end of the list is not `t[s]`, but `t[s-1]`, thus the pre-decrement achieves
+both the desired index and decrements the count.
+
+
+## Word Selection ##
+
+After the words are filtered, then comes the hard part: selecting which word
+to guess next! This is handled by `E()`, by far the most interesting routine
+in the code.
+
+The loops in order:
+
+ - init `c[]` with ordinal values (a-z plus 6 slop) in the lower 5 bits
+ - in the higher order bits, count the frequency of all remaining letters
+ - sort by the frequency of letters in 3 sets of 7 (21 not 26!)
+ - merge the separate sorts into one via `v()` (see below on merging)
+ - for letters with same freq, re-sort by English frequency values `l()`
+ - using the sorted list, put the corresponding ordinals into `b[]`
+ - for each word, if scores below 97, put into `e[][]` (low score wins)
+ - allow up to 5 duplicate scores, only keep first 5 words with same score
+ - search the list for the lowest scoring word (best match)
+ - if more than 2 words remain, find first word without duplicate letters
+ - return whatever we found, if anything
+
+The weakness in this scheme is at least two-fold: 1) if there are more than 5
+words with the same score, words that come later are not selected, and 2) all
+words with the same score are considered the same, without regard to letter
+order or letter frequencies. I have run no experiments here,
+but I think this is an area for minor improvement.
+
+
+## Network Sort ##
+
+Network sort[1] is a simple, compact, constant time sort with minimal compares.
+
+It is obfuscated in a number of ways.
+The routine `S()` looks into the array `a[]` and determines the number of
+elements to sort via the differences in the initial values of `a[]`.
+Consider the possible number of values given in `O` from 0 (zero) to 7:
+if `O` is 0 or 1, no sort is necessary (an empty list cannot be sorted,
+and a list of one does not need to be sorted):
+
+```
+ O+1 O
+ a[1] - a[0] = 9 - 9 = 0
+ a[2] - a[1] = 9 - 9 = 0
+ a[3] - a[2] = 10 - 9 = 1
+```
+
+If `O` is 2, then only one compare and swap is necessary. Why is this?
+Consider how many compares are necessary to determine the proper order of
+variables A and B: one test and one possible swap are all that is needed.
+If A > B, swap. If A <= B, then no swap and the list is already ordered.
+
+Where is this calculation done? Address arithmetic FTW!
+`e = a[-~O] + s - a[O]`. `-~O` is the identity `O+1`.
+So this expression restated is `e = s + a[O+1] - a[O]`.
+If you look at the first numbers in `a[]` and their offsets (table 1):
+
+```
+ table 1
+ offsets: 0 1 2 3 4 5 6 7 8
+ values : 9 9 9 10 13 18 27 39 55
+```
+
+You can see the expression selects for O in 0..7 (table 2):
+
+```
+ // table 2
+ a[0+1] - a[0] = 9 - 9 = 0 // 0 selects no compares
+ a[1+1] - a[1] = 9 - 9 = 0 // 1 selects no compares
+ a[2+1] - a[2] = 10 - 9 = 1 // 2 selects 1 compare
+ a[3+1] - a[3] = 13 - 10 = 3 // 3 selects 3 compares
+ a[4+1] - a[4] = 18 - 13 = 5 // 4 selects 5 compares
+ a[5+1] - a[5] = 27 - 18 = 9 // 5 selects 9 compares
+ a[6+1] - a[6] = 39 - 27 = 12 // 6 selects 12 compares
+ a[7+1] - a[7] = 55 - 39 = 16 // 7 selects 16 compares
+```
+
+What are we comparing? `s` ranges from `&a[a[O]]` to `&a[a[O+1]]`.
+
+```
+ O expr
+ 0 9 - 9 = 0: no compares
+ 1 9 - 9 = 0: no compares
+ 2 10 - 9 = 1: &a[a[9]] + 1 or the set { 1 }
+ 3 13 - 10 = 3: &a[a[10]] + 3 or the set { 18, 2, 1 }
+ 4 18 - 13 = 5: &a[a[13]] + 5 or the set { 1, 35, 2, 19, 18 }
+ ...
+ 7 55 - 39 = 16: &a[a[39]] + 16 or the set
+ { 18, 52, 86, 2, 53, 70, 1, 69,
+ 38, 4, 21, 3, 37, 19, 36, 35 }
+```
+
+So what do these numbers mean for sorting? Translate them to hex:
+
+```
+ { 0x12, 0x34, 0x56, 0x02, 0x35, 0x46, 0x01, 0x45,
+ 0x26, 0x04, 0x15, 0x03, 0x25, 0x13, 0x24, 0x23 }
+```
+
+This compact arrangement can be split into high and low nibbles:
+
+```
+ { (1,2), (3,4), (5,6), (0,2), (3,5), ... }
+```
+
+which means compare and maybe swap (keeping order low to high):
+
+```
+ if (s[1] > s[2]) swap();
+ if (s[3] > s[4]) swap();
+ if (s[5] > s[6]) swap();
+ if (s[0] > s[2]) swap();
+ if (s[3] > s[5]) swap();
+ ....
+```
+
+For instance, when sorting 7 elements, start from `a[a[7]]` (39) until
+`a[a[8]]` (55), or 16 elements starting at `a[39]`.
+
+[1]: https://en.wikipedia.org/wiki/Sorting_network
+
+
+## The Array a[] Explained, Finally ##
+
+The first set of 9 numbers are both the lengths AND the start and end indexes
+into the array `a[]`, as explained above in the Network Sort. The second set
+of numbers runs from indexes 9 through 54, and are the Network Sort comparison
+values. At index 55 begins the third part of the array. The final 26 values
+encode the inverse frequency of letters in the English language. The first
+value is 25 for the letter 'a'. If you count, then 26 is for the letter 'e',
+the most common letter in the English language
+(or at least for the dictionary used).
+
+This final set of letters is used in the routine `l()`. Notice the expression:
+`a[f[j] + a[~-9]]`; `a[~-9]` is an obscure way of writing `a[8]`, which is the
+value 55. So `a[f[j]]` is an index into this frequency array, offset by 55.
+Why is there a `<< 5`? Again, the letter offsets are in the lowest 5 bits,
+and the counts of the letters is in the upper bits.
+
+The reason for putting the counts in the upper bits is simple: it makes the
+value larger for larger counts. Thus, sorting based upon frequency is natural.
+
+
+## Merge Sort ##
+
+The network sort as implemented handles up to 7 letters in 3 calls.
+26 / 7 = 3 r 5. Thus, we need to merge up to 4 sets of 7 letters.
+This merge is handled by `v()`, which calls `o()` 3 times, once recursively.
+This is followed by a rearrangement handled in `l()`. This last step finds
+all the letters with the same frequency, then sorts them according to their
+English frequency.
+
+Back to the merge sort, which is really handled in `o()`. This is rather
+difficult to follow. The first call to `o()` is within the argument list
+to the second call. The first call has arguments
+W=0, O=1, R=0, D=a, L=w, E=k; and `v()` was called with `v(l=7, w=b, k=c)`.
+This first merge pass copies to: `L[R]` (`b[0]`) and selects from either
+`c[o]` or `c[w]` depending upon which is greater or equal. That is, it merges
+two 7 letter arrays into a single 14 element array twice, then it merges two 14
+element arrays into a single 28 element array. Note on the third call
+to `o()`, the last two arguments are swapped, which puts the final sort
+into `c[]`.
+
+Below is a hopefully easier way to read the merge sort code:
+
+```
+ // merge residual
+ int e(int mult_o, int start, int to, int off, int *a1, int *a2)
+ {
+ for (; start < off; )
+ a1[to++] = a2[start++ + off * mult_o];
+ return to;
+ }
+
+ // merge sort
+ int o(int mult_o, int mult_w, int to, int len, int *a1, int *a2)
+ {
+ // first call: mult_o = 0, mult_w = 1, to = 0, len = 7, a1=b, a2=c
+ // second: mult_o = 2, mult_w = 3, to = N, len = 7, a1=b, a2=c
+ // third: mult_o = 0, mult_w = 1, to = 0, len = 14, a1=c, a2=b
+
+ int o = 0, w = 0;
+ for (; o < len && w < len; ) {
+
+ // first call: to=0, len=7, mult_o=0, mult_w=1
+ // a1[0++] = a2[0 + 7*0] >= a2[0 + 7*1]
+ // ? a2[0 + 7*0] : a2[0 + 7*1]
+ // a1[0++] = a2[0] > a2[7] ? a[0++] : a2[7++]
+
+ // second call: to=14, len=7, mult_o=2, mult_w=3
+ // a1[14++] = a2[0 + 7*2] >= a2[0 + 7*3]
+ // ? a2[0 + 7*2] : a2[0 + 7*3]
+ // a1[14++] = a2[14] > a2[21] ? a2[14++] : a2[21++]
+
+ // third call: to=0, len=14, mult_o=0, mult_w=1
+ // a1[0++] = a2[0 + 14*0] >= a2[0 + 14*1]
+ // ? a2[0 + 14*0] : a2[0 + 14*1];
+ // a1[0++] = a[0] >= a2[14] ? a2[0++] : a2[14++]
+
+ a1[to++] = a2[o + len * mult_o] >= a2[w + len * mult_w]
+ ? a2[o++ + len * mult_o]
+ : a2[w++ + len * mult_w]
+ }
+ int n = e(mult_o, o, to, len, a1, a2);
+ return e(mult_w, w, n, len, a1, a2);
+ }
+```
+
+Isn't that as clear as mud? It is far easier to understand the flow when
+you add `printf()` statements to follow the logic. Included is the file
+`deobfuscated.c` for you to start with.
+
+
+## Why name the functions as they are? ##
+
+Run `make spoiler`.
+
+
+## Bug Explained ##
+
+If you followed the above explanation, you will notice that only the first
+21 of 26 letters are sorted (ignoring { v, w, x, y, z }. But 28 of 26 letters
+are merge sorted. It was observed the program performs worse if all 26 letters
+are sorted (which tends to over-favor `y`).
+But some words do have `y` in them, which is why the merge sort takes 28
+letters (including the ASCII values `{` and `|`), so all letters are still
+selected when appropriate. The merge sort puts the { v, w, x, y, z }
+letters into the proper frequency set, eventually.
+
+If you change the loop value `22` to `32`, then all letters are sorted,
+the program will work correctly, but it will change the performance
+of the algorithm to be slightly worse than the original.
+
+If you change any values in the array `a[]`,
+the program will no longer work correctly.
+
+Finally, what is the significance of the array size 78557?
+`usdw` only needs 8506. Why was such a large value used?
diff --git a/2024/burton/dict b/2024/burton/dict
new file mode 100644
index 000000000..4dd830e90
--- /dev/null
+++ b/2024/burton/dict
@@ -0,0 +1,2315 @@
+aback
+abase
+abate
+abbey
+abbot
+abhor
+abide
+abled
+abode
+abort
+about
+above
+abuse
+abyss
+acorn
+acrid
+actor
+acute
+adage
+adapt
+adept
+admin
+admit
+adobe
+adopt
+adore
+adorn
+adult
+affix
+afire
+afoot
+afoul
+after
+again
+agape
+agate
+agent
+agile
+aging
+aglow
+agony
+agora
+agree
+ahead
+aider
+aisle
+alarm
+album
+alert
+algae
+alibi
+alien
+align
+alike
+alive
+allay
+alley
+allot
+allow
+alloy
+aloft
+alone
+along
+aloof
+aloud
+alpha
+altar
+alter
+amass
+amaze
+amber
+amble
+amend
+amiss
+amity
+among
+ample
+amply
+amuse
+angel
+anger
+angle
+angry
+angst
+anime
+ankle
+annex
+annoy
+annul
+anode
+antic
+anvil
+aorta
+apart
+aphid
+aping
+apnea
+apple
+apply
+apron
+aptly
+arbor
+ardor
+arena
+argue
+arise
+armor
+aroma
+arose
+array
+arrow
+arson
+artsy
+ascot
+ashen
+aside
+askew
+assay
+asset
+atoll
+atone
+attic
+audio
+audit
+augur
+aunty
+avail
+avert
+avian
+avoid
+await
+awake
+award
+aware
+awash
+awful
+awoke
+axial
+axiom
+axion
+azure
+bacon
+badge
+badly
+bagel
+baggy
+baker
+baler
+balmy
+banal
+banjo
+barge
+baron
+basal
+basic
+basil
+basin
+basis
+baste
+batch
+bathe
+baton
+batty
+bawdy
+bayou
+beach
+beady
+beard
+beast
+beech
+beefy
+befit
+began
+begat
+beget
+begin
+begun
+being
+belch
+belie
+belle
+belly
+below
+bench
+beret
+berry
+berth
+beset
+betel
+bevel
+bezel
+bible
+bicep
+biddy
+bigot
+bilge
+billy
+binge
+bingo
+biome
+birch
+birth
+bison
+bitty
+black
+blade
+blame
+bland
+blank
+blare
+blast
+blaze
+bleak
+bleat
+bleed
+bleep
+blend
+bless
+blimp
+blind
+blink
+bliss
+blitz
+bloat
+block
+bloke
+blond
+blood
+bloom
+blown
+bluer
+bluff
+blunt
+blurb
+blurt
+blush
+board
+boast
+bobby
+boney
+bongo
+bonus
+booby
+boost
+booth
+booty
+booze
+boozy
+borax
+borne
+bosom
+bossy
+botch
+bough
+boule
+bound
+bowel
+boxer
+brace
+braid
+brain
+brake
+brand
+brash
+brass
+brave
+bravo
+brawl
+brawn
+bread
+break
+breed
+briar
+bribe
+brick
+bride
+brief
+brine
+bring
+brink
+briny
+brisk
+broad
+broil
+broke
+brood
+brook
+broom
+broth
+brown
+brunt
+brush
+brute
+buddy
+budge
+buggy
+bugle
+build
+built
+bulge
+bulky
+bully
+bunch
+bunny
+burly
+burnt
+burst
+bused
+bushy
+butch
+butte
+buxom
+buyer
+bylaw
+cabal
+cabby
+cabin
+cable
+cacao
+cache
+cacti
+caddy
+cadet
+cagey
+cairn
+camel
+cameo
+canal
+candy
+canny
+canoe
+canon
+caper
+caput
+carat
+cargo
+carol
+carry
+carve
+caste
+catch
+cater
+catty
+caulk
+cause
+cavil
+cease
+cedar
+cello
+chafe
+chaff
+chain
+chair
+chalk
+champ
+chant
+chaos
+chard
+charm
+chart
+chase
+chasm
+cheap
+cheat
+check
+cheek
+cheer
+chess
+chest
+chick
+chide
+chief
+child
+chili
+chill
+chime
+china
+chirp
+chock
+choir
+choke
+chord
+chore
+chose
+chuck
+chump
+chunk
+churn
+chute
+cider
+cigar
+cinch
+circa
+civic
+civil
+clack
+claim
+clamp
+clang
+clank
+clash
+clasp
+class
+clean
+clear
+cleat
+cleft
+clerk
+click
+cliff
+climb
+cling
+clink
+cloak
+clock
+clone
+close
+cloth
+cloud
+clout
+clove
+clown
+cluck
+clued
+clump
+clung
+coach
+coast
+cobra
+cocoa
+colon
+color
+comet
+comfy
+comic
+comma
+conch
+condo
+conic
+copse
+coral
+corer
+corny
+couch
+cough
+could
+count
+coupe
+court
+coven
+cover
+covet
+covey
+cower
+coyly
+crack
+craft
+cramp
+crane
+crank
+crash
+crass
+crate
+crave
+crawl
+craze
+crazy
+creak
+cream
+credo
+creed
+creek
+creep
+creme
+crepe
+crept
+cress
+crest
+crick
+cried
+crier
+crime
+crimp
+crisp
+croak
+crock
+crone
+crony
+crook
+cross
+croup
+crowd
+crown
+crude
+cruel
+crumb
+crump
+crush
+crust
+crypt
+cubic
+cumin
+curio
+curly
+curry
+curse
+curve
+curvy
+cutie
+cyber
+cycle
+cynic
+daddy
+daily
+dairy
+daisy
+dally
+dance
+dandy
+datum
+daunt
+dealt
+death
+debar
+debit
+debug
+debut
+decal
+decay
+decor
+decoy
+decry
+defer
+deign
+deity
+delay
+delta
+delve
+demon
+demur
+denim
+dense
+depot
+depth
+derby
+deter
+detox
+deuce
+devil
+diary
+dicey
+digit
+dilly
+dimly
+diner
+dingo
+dingy
+diode
+dirge
+dirty
+disco
+ditch
+ditto
+ditty
+diver
+dizzy
+dodge
+dodgy
+dogma
+doing
+dolly
+donor
+donut
+dopey
+doubt
+dough
+dowdy
+dowel
+downy
+dowry
+dozen
+draft
+drain
+drake
+drama
+drank
+drape
+drawl
+drawn
+dread
+dream
+dress
+dried
+drier
+drift
+drill
+drink
+drive
+droit
+droll
+drone
+drool
+droop
+dross
+drove
+drown
+druid
+drunk
+dryer
+dryly
+duchy
+dully
+dummy
+dumpy
+dunce
+dusky
+dusty
+dutch
+duvet
+dwarf
+dwell
+dwelt
+dying
+eager
+eagle
+early
+earth
+easel
+eaten
+eater
+ebony
+eclat
+edict
+edify
+eerie
+egret
+eight
+eject
+eking
+elate
+elbow
+elder
+elect
+elegy
+elfin
+elide
+elite
+elope
+elude
+email
+embed
+ember
+emcee
+empty
+enact
+endow
+enema
+enemy
+enjoy
+ennui
+ensue
+enter
+entry
+envoy
+epoch
+epoxy
+equal
+equip
+erase
+erect
+erode
+error
+erupt
+essay
+ester
+ether
+ethic
+ethos
+etude
+evade
+event
+every
+evict
+evoke
+exact
+exalt
+excel
+exert
+exile
+exist
+expel
+extol
+extra
+exult
+eying
+fable
+facet
+faint
+fairy
+faith
+false
+fancy
+fanny
+farce
+fatal
+fatty
+fault
+fauna
+favor
+feast
+fecal
+feign
+fella
+felon
+femme
+femur
+fence
+feral
+ferry
+fetal
+fetch
+fetid
+fetus
+fever
+fewer
+fiber
+fibre
+ficus
+field
+fiend
+fiery
+fifth
+fifty
+fight
+filer
+filet
+filly
+filmy
+filth
+final
+finch
+finer
+first
+fishy
+fixer
+fizzy
+fjord
+flack
+flail
+flair
+flake
+flaky
+flame
+flank
+flare
+flash
+flask
+fleck
+fleet
+flesh
+flick
+flier
+fling
+flint
+flirt
+float
+flock
+flood
+floor
+flora
+floss
+flour
+flout
+flown
+fluff
+fluid
+fluke
+flume
+flung
+flunk
+flush
+flute
+flyer
+foamy
+focal
+focus
+foggy
+foist
+folio
+folly
+foray
+force
+forge
+forgo
+forte
+forth
+forty
+forum
+found
+foyer
+frail
+frame
+frank
+fraud
+freak
+freed
+freer
+fresh
+friar
+fried
+frill
+frisk
+fritz
+frock
+frond
+front
+frost
+froth
+frown
+froze
+fruit
+fudge
+fugue
+fully
+fungi
+funky
+funny
+furor
+furry
+fussy
+fuzzy
+gaffe
+gaily
+gamer
+gamma
+gamut
+gassy
+gaudy
+gauge
+gaunt
+gauze
+gavel
+gawky
+gayer
+gayly
+gazer
+gecko
+geeky
+geese
+genie
+genre
+ghost
+ghoul
+giant
+giddy
+gipsy
+girly
+girth
+given
+giver
+glade
+gland
+glare
+glass
+glaze
+gleam
+glean
+glide
+glint
+gloat
+globe
+gloom
+glory
+gloss
+glove
+glyph
+gnash
+gnome
+godly
+going
+golem
+golly
+gonad
+goner
+goody
+gooey
+goofy
+goose
+gorge
+gouge
+gourd
+grace
+grade
+graft
+grail
+grain
+grand
+grant
+grape
+graph
+grasp
+grass
+grate
+grave
+gravy
+graze
+great
+greed
+green
+greet
+grief
+grill
+grime
+grimy
+grind
+gripe
+groan
+groin
+groom
+grope
+gross
+group
+grout
+grove
+growl
+grown
+gruel
+gruff
+grunt
+guard
+guava
+guess
+guest
+guide
+guild
+guile
+guilt
+guise
+gulch
+gully
+gumbo
+gummy
+guppy
+gusto
+gusty
+gypsy
+habit
+hairy
+halve
+handy
+happy
+hardy
+harem
+harpy
+harry
+harsh
+haste
+hasty
+hatch
+hater
+haunt
+haute
+haven
+havoc
+hazel
+heady
+heard
+heart
+heath
+heave
+heavy
+hedge
+hefty
+heist
+helix
+hello
+hence
+heron
+hilly
+hinge
+hippo
+hippy
+hitch
+hoard
+hobby
+hoist
+holly
+homer
+honey
+honor
+horde
+horny
+horse
+hotel
+hotly
+hound
+house
+hovel
+hover
+howdy
+human
+humid
+humor
+humph
+humus
+hunch
+hunky
+hurry
+husky
+hussy
+hutch
+hydro
+hyena
+hymen
+hyper
+icily
+icing
+ideal
+idiom
+idiot
+idler
+idyll
+igloo
+iliac
+image
+imbue
+impel
+imply
+inane
+inbox
+incur
+index
+inept
+inert
+infer
+ingot
+inlay
+inlet
+inner
+input
+inter
+intro
+ionic
+irate
+irony
+islet
+issue
+itchy
+ivory
+jaunt
+jazzy
+jelly
+jerky
+jetty
+jewel
+jiffy
+joint
+joist
+joker
+jolly
+joust
+judge
+juice
+juicy
+jumbo
+jumpy
+junta
+junto
+juror
+kappa
+karma
+kayak
+kebab
+khaki
+kinky
+kiosk
+kitty
+knack
+knave
+knead
+kneed
+kneel
+knelt
+knife
+knock
+knoll
+known
+koala
+krill
+label
+labor
+laden
+ladle
+lager
+lance
+lanky
+lapel
+lapse
+large
+larva
+lasso
+latch
+later
+lathe
+latte
+laugh
+layer
+leach
+leafy
+leaky
+leant
+leapt
+learn
+lease
+leash
+least
+leave
+ledge
+leech
+leery
+lefty
+legal
+leggy
+lemon
+lemur
+leper
+level
+lever
+libel
+liege
+light
+liken
+lilac
+limbo
+limit
+linen
+liner
+lingo
+lipid
+lithe
+liver
+livid
+llama
+loamy
+loath
+lobby
+local
+locus
+lodge
+lofty
+logic
+login
+loopy
+loose
+lorry
+loser
+louse
+lousy
+lover
+lower
+lowly
+loyal
+lucid
+lucky
+lumen
+lumpy
+lunar
+lunch
+lunge
+lupus
+lurch
+lurid
+lusty
+lying
+lymph
+lynch
+lyric
+macaw
+macho
+macro
+madam
+madly
+mafia
+magic
+magma
+maize
+major
+maker
+mambo
+mamma
+mammy
+manga
+mange
+mango
+mangy
+mania
+manic
+manly
+manor
+maple
+march
+marry
+marsh
+mason
+masse
+match
+matey
+mauve
+maxim
+maybe
+mayor
+mealy
+meant
+meaty
+mecca
+medal
+media
+medic
+melee
+melon
+mercy
+merge
+merit
+merry
+metal
+meter
+metro
+micro
+midge
+midst
+might
+milky
+mimic
+mince
+miner
+minim
+minor
+minty
+minus
+mirth
+miser
+missy
+mocha
+modal
+model
+modem
+mogul
+moist
+molar
+moldy
+money
+month
+moody
+moose
+moral
+moron
+morph
+mossy
+motel
+motif
+motor
+motto
+moult
+mound
+mount
+mourn
+mouse
+mouth
+mover
+movie
+mower
+mucky
+mucus
+muddy
+mulch
+mummy
+munch
+mural
+murky
+mushy
+music
+musky
+musty
+myrrh
+nadir
+naive
+nanny
+nasal
+nasty
+natal
+naval
+navel
+needy
+neigh
+nerdy
+nerve
+never
+newer
+newly
+nicer
+niche
+niece
+night
+ninja
+ninny
+ninth
+noble
+nobly
+noise
+noisy
+nomad
+noose
+north
+nosey
+notch
+novel
+nudge
+nurse
+nutty
+nylon
+nymph
+oaken
+obese
+occur
+ocean
+octal
+octet
+odder
+oddly
+offal
+offer
+often
+olden
+older
+olive
+ombre
+omega
+onion
+onset
+opera
+opine
+opium
+optic
+orbit
+order
+organ
+other
+otter
+ought
+ounce
+outdo
+outer
+outgo
+ovary
+ovate
+overt
+ovine
+ovoid
+owing
+owner
+oxide
+ozone
+paddy
+pagan
+paint
+paler
+palsy
+panel
+panic
+pansy
+papal
+paper
+parer
+parka
+parry
+parse
+party
+pasta
+paste
+pasty
+patch
+patio
+patsy
+patty
+pause
+payee
+payer
+peace
+peach
+pearl
+pecan
+pedal
+penal
+pence
+penne
+penny
+perch
+peril
+perky
+pesky
+pesto
+petal
+petty
+phase
+phone
+phony
+photo
+piano
+picky
+piece
+piety
+piggy
+pilot
+pinch
+piney
+pinky
+pinto
+piper
+pique
+pitch
+pithy
+pivot
+pixel
+pixie
+pizza
+place
+plaid
+plain
+plait
+plane
+plank
+plant
+plate
+plaza
+plead
+pleat
+plied
+plier
+pluck
+plumb
+plume
+plump
+plunk
+plush
+poesy
+point
+poise
+poker
+polar
+polka
+polyp
+pooch
+poppy
+porch
+poser
+posit
+posse
+pouch
+pound
+pouty
+power
+prank
+prawn
+preen
+press
+price
+prick
+pride
+pried
+prime
+primo
+print
+prior
+prism
+privy
+prize
+probe
+prone
+prong
+proof
+prose
+proud
+prove
+prowl
+proxy
+prude
+prune
+psalm
+pubic
+pudgy
+puffy
+pulpy
+pulse
+punch
+pupal
+pupil
+puppy
+puree
+purer
+purge
+purse
+pushy
+putty
+pygmy
+quack
+quail
+quake
+qualm
+quark
+quart
+quash
+quasi
+queen
+queer
+quell
+query
+quest
+queue
+quick
+quiet
+quill
+quilt
+quirk
+quite
+quota
+quote
+quoth
+rabbi
+rabid
+racer
+radar
+radii
+radio
+rainy
+raise
+rajah
+rally
+ralph
+ramen
+ranch
+randy
+range
+rapid
+rarer
+raspy
+ratio
+ratty
+raven
+rayon
+razor
+reach
+react
+ready
+realm
+rearm
+rebar
+rebel
+rebus
+rebut
+recap
+recur
+recut
+reedy
+refer
+refit
+regal
+rehab
+reign
+relax
+relay
+relic
+remit
+renal
+renew
+repay
+repel
+reply
+rerun
+reset
+resin
+retch
+retro
+retry
+reuse
+revel
+revue
+rhino
+rhyme
+rider
+ridge
+rifle
+right
+rigid
+rigor
+rinse
+ripen
+riper
+risen
+riser
+risky
+rival
+river
+rivet
+roach
+roast
+robin
+robot
+rocky
+rodeo
+roger
+rogue
+roomy
+roost
+rotor
+rouge
+rough
+round
+rouse
+route
+rover
+rowdy
+rower
+royal
+ruddy
+ruder
+rugby
+ruler
+rumba
+rumor
+rupee
+rural
+rusty
+sadly
+safer
+saint
+salad
+sally
+salon
+salsa
+salty
+salve
+salvo
+sandy
+saner
+sappy
+sassy
+satin
+satyr
+sauce
+saucy
+sauna
+saute
+savor
+savoy
+savvy
+scald
+scale
+scalp
+scaly
+scamp
+scant
+scare
+scarf
+scary
+scene
+scent
+scion
+scoff
+scold
+scone
+scoop
+scope
+score
+scorn
+scour
+scout
+scowl
+scram
+scrap
+scree
+screw
+scrub
+scrum
+scuba
+sedan
+seedy
+segue
+seize
+semen
+sense
+sepia
+serif
+serum
+serve
+setup
+seven
+sever
+sewer
+shack
+shade
+shady
+shaft
+shake
+shaky
+shale
+shall
+shalt
+shame
+shank
+shape
+shard
+share
+shark
+sharp
+shave
+shawl
+shear
+sheen
+sheep
+sheer
+sheet
+sheik
+shelf
+shell
+shied
+shift
+shine
+shiny
+shire
+shirk
+shirt
+shoal
+shock
+shone
+shook
+shoot
+shore
+shorn
+short
+shout
+shove
+shown
+showy
+shrew
+shrub
+shrug
+shuck
+shunt
+shush
+shyly
+siege
+sieve
+sight
+sigma
+silky
+silly
+since
+sinew
+singe
+siren
+sissy
+sixth
+sixty
+skate
+skier
+skiff
+skill
+skimp
+skirt
+skulk
+skull
+skunk
+slack
+slain
+slang
+slant
+slash
+slate
+slave
+sleek
+sleep
+sleet
+slept
+slice
+slick
+slide
+slime
+slimy
+sling
+slink
+sloop
+slope
+slosh
+sloth
+slump
+slung
+slunk
+slurp
+slush
+slyly
+smack
+small
+smart
+smash
+smear
+smell
+smelt
+smile
+smirk
+smite
+smith
+smock
+smoke
+smoky
+smote
+snack
+snail
+snake
+snaky
+snare
+snarl
+sneak
+sneer
+snide
+sniff
+snipe
+snoop
+snore
+snort
+snout
+snowy
+snuck
+snuff
+soapy
+sober
+soggy
+solar
+solid
+solve
+sonar
+sonic
+sooth
+sooty
+sorry
+sound
+south
+sower
+space
+spade
+spank
+spare
+spark
+spasm
+spawn
+speak
+spear
+speck
+speed
+spell
+spelt
+spend
+spent
+sperm
+spice
+spicy
+spied
+spiel
+spike
+spiky
+spill
+spilt
+spine
+spiny
+spire
+spite
+splat
+split
+spoil
+spoke
+spoof
+spook
+spool
+spoon
+spore
+sport
+spout
+spray
+spree
+sprig
+spunk
+spurn
+spurt
+squad
+squat
+squib
+stack
+staff
+stage
+staid
+stain
+stair
+stake
+stale
+stalk
+stall
+stamp
+stand
+stank
+stare
+stark
+start
+stash
+state
+stave
+stead
+steak
+steal
+steam
+steed
+steel
+steep
+steer
+stein
+stern
+stick
+stiff
+still
+stilt
+sting
+stink
+stint
+stock
+stoic
+stoke
+stole
+stomp
+stone
+stony
+stood
+stool
+stoop
+store
+stork
+storm
+story
+stout
+stove
+strap
+straw
+stray
+strip
+strut
+stuck
+study
+stuff
+stump
+stung
+stunk
+stunt
+style
+suave
+sugar
+suing
+suite
+sulky
+sully
+sumac
+sunny
+super
+surer
+surge
+surly
+sushi
+swami
+swamp
+swarm
+swash
+swath
+swear
+sweat
+sweep
+sweet
+swell
+swept
+swift
+swill
+swine
+swing
+swirl
+swish
+swoon
+swoop
+sword
+swore
+sworn
+swung
+synod
+syrup
+tabby
+table
+taboo
+tacit
+tacky
+taffy
+taint
+taken
+taker
+tally
+talon
+tamer
+tango
+tangy
+taper
+tapir
+tardy
+tarot
+taste
+tasty
+tatty
+taunt
+tawny
+teach
+teary
+tease
+teddy
+teeth
+tempo
+tenet
+tenor
+tense
+tenth
+tepee
+tepid
+terra
+terse
+testy
+thank
+theft
+their
+theme
+there
+these
+theta
+thick
+thief
+thigh
+thing
+think
+third
+thong
+thorn
+those
+three
+threw
+throb
+throw
+thrum
+thumb
+thump
+thyme
+tiara
+tibia
+tidal
+tiger
+tight
+tilde
+timer
+timid
+tipsy
+titan
+tithe
+title
+toast
+today
+toddy
+token
+tonal
+tonga
+tonic
+tooth
+topaz
+topic
+torch
+torso
+torus
+total
+totem
+touch
+tough
+towel
+tower
+toxic
+toxin
+trace
+track
+tract
+trade
+trail
+train
+trait
+tramp
+trash
+trawl
+tread
+treat
+trend
+triad
+trial
+tribe
+trice
+trick
+tried
+tripe
+trite
+troll
+troop
+trope
+trout
+trove
+truce
+truck
+truer
+truly
+trump
+trunk
+truss
+trust
+truth
+tryst
+tubal
+tuber
+tulip
+tulle
+tumor
+tunic
+turbo
+tutor
+twang
+tweak
+tweed
+tweet
+twice
+twine
+twirl
+twist
+twixt
+tying
+udder
+ulcer
+ultra
+umbra
+uncle
+uncut
+under
+undid
+undue
+unfed
+unfit
+unify
+union
+unite
+unity
+unlit
+unmet
+unset
+untie
+until
+unwed
+unzip
+upper
+upset
+urban
+urine
+usage
+usher
+using
+usual
+usurp
+utile
+utter
+vague
+valet
+valid
+valor
+value
+valve
+vapid
+vapor
+vault
+vaunt
+vegan
+venom
+venue
+verge
+verse
+verso
+verve
+vicar
+video
+vigil
+vigor
+villa
+vinyl
+viola
+viper
+viral
+virus
+visit
+visor
+vista
+vital
+vivid
+vixen
+vocal
+vodka
+vogue
+voice
+voila
+vomit
+voter
+vouch
+vowel
+vying
+wacky
+wafer
+wager
+wagon
+waist
+waive
+waltz
+warty
+waste
+watch
+water
+waver
+waxen
+weary
+weave
+wedge
+weedy
+weigh
+weird
+welch
+welsh
+wench
+whack
+whale
+wharf
+wheat
+wheel
+whelp
+where
+which
+whiff
+while
+whine
+whiny
+whirl
+whisk
+white
+whole
+whoop
+whose
+widen
+wider
+widow
+width
+wield
+wight
+willy
+wimpy
+wince
+winch
+windy
+wiser
+wispy
+witch
+witty
+woken
+woman
+women
+woody
+wooer
+wooly
+woozy
+wordy
+world
+worry
+worse
+worst
+worth
+would
+wound
+woven
+wrack
+wrath
+wreak
+wreck
+wrest
+wring
+wrist
+write
+wrong
+wrote
+wrung
+wryly
+yacht
+yearn
+yeast
+yield
+young
+youth
+zebra
+zesty
+zonal
diff --git a/2024/burton/dups.c b/2024/burton/dups.c
new file mode 100644
index 000000000..e2f74118f
--- /dev/null
+++ b/2024/burton/dups.c
@@ -0,0 +1,29 @@
+/*
+ * usage: dups [-n] [len]
+ */
+
+#include
+#include
+
+int main(int ac, char **av)
+{
+ char buf[32];
+
+ int no = ac > 1 && av[1][0] == '-' && av[1][1] == 'n' && ++av && --ac;
+ int n = ac > 1 ? atoi(av[1]) : 5;
+
+ while (fgets(buf, sizeof buf, stdin)) {
+ char d[256] = {0};
+ int skip = 0;
+ if (buf[n] != '\n')
+ continue;
+ for (int i = 0; i < n; ++i) {
+ int c = buf[i] |= 32;
+ if (++d[c] > 1)
+ ++skip;
+ }
+ if (!!skip != no)
+ printf("%s", buf);
+ }
+ return 0;
+}
diff --git a/2024/burton/exhaust b/2024/burton/exhaust
new file mode 100755
index 000000000..7cf58bda7
--- /dev/null
+++ b/2024/burton/exhaust
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+
+# amount of parallelism
+p=8
+
+dir=$1
+: ${dir:=results}
+mkdir -p $dir
+
+start_words=$2
+: ${start_words:=start_words}
+
+dict=$3
+: ${dict:=dict}
+
+rm -fr ./tmp
+mkdir -p tmp
+
+# split dict into smaller chucks for some parallelism
+n=1
+cat $start_words | ./dups -n | while read a; do
+ echo $a >> tmp/$n
+ ((n+=1))
+ test $n -gt $p && n=1
+done
+
+# run the experiment (expensive)
+n=1
+while test $n -le $p; do
+ ./word.result $dir $dict < tmp/$n 2>/dev/null &
+ ((n+=1))
+done
+
+rm -fr ./tmp
+
+wait
diff --git a/2024/burton/extra.html b/2024/burton/extra.html
new file mode 100644
index 000000000..e87df6cdc
--- /dev/null
+++ b/2024/burton/extra.html
@@ -0,0 +1,887 @@
+
+
+
+
+
+
+
+
+
+
+
+
+The International Obfuscated C Code Contest
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
This readme provides a description of the extra files provided, how to use them,
+analysis of their results, and a deeper investigation on the failed guesses.
+
The recommendation is to do:
+
make tools
+
+ ./run dict blast swept # exhaust runs this command a LOT!
+ ./run dict crate swept # show the diff between starting words
+
+ mkdir results # create the results directory
+ ./exhaust # exhaustive test of all words (~1 hour)
+ echo terns | ./word.result # add the word "terns" to results
+ ./mkresults > results.avg # proc exhaust into a single, small file
+
The files created as output from exhaust allow one to view, for each
+starting word, how each of the solutions resolve, including the misses.
+mkresults outputs a 1566 line report showing the starting word, its
+average accuracy, and the number of missed words. To show the number
+of guesses and the actual missed words, run rank on the desired word:
gen.c - simulate wordle game by generating targets and scoring guesses
+ ./gen dict [target]
+
+ dups.c - remove words with(out) repeated letters
+ (best starting words have no repeats)
+ cat dict | wc -l # all the words
+ cat dict | ./dups | wc -l # words with repeated letters
+ cat dict | ./dups -n | wc -l # words without repeated letters
+
+ run.c - `gen` and `prog` connected via pipes; allows automated testing
+ ./run dict [start [target]]
+ start - the first guess
+ target - force the target to be the named word
+
Using More Guesses
+
If you wish to see the failed words in action, and if more guesses would
+work, try:
Using GUESSES=9 and exhaust, one gets a metric that scores words without
+misses, allowing a better comparison on the average score. Note, however,
+that the game doesn’t bend this way, and anything more than 6 guesses is a
+loss. Take this metric with a grain of salt. Also, 9 is the limit of
+guesses; the program will not work properly - if at all - with more than
+9 guesses.
+
Ranking by fewest missed with GUESSES=6, the order is:
The 1566 raw files produced by exhaust are ~370KB each (total ~562MB),
+far too large to submit, so included are the compressed results files for
+four starting words, and the summary file results.avg.
+
blast fewest missed
+ crate best average
+ query most missing
+ terns example used in remarks
+
The program rank allows one to see how the averages are calculated, as well
+as the actual missed words. Comparing the results for blast and terns:
You have to decide if you prefer a marginally lower average, but slightly
+higher chance of losing, versus a marginally higher average and lower chance
+of losing. This is developed further in the following section.
+
It is interesting that the letter order makes a noticeable difference:
+
./avg r.terns; ./avg results/stern
+ terns 3.641469 18 # lower average and fewer misses
+ stern 3.658315 20
+
For completeness, using GUESSES=9 and the full starting dictionary from
+Wordle(tm), here are the results for the “best” starting words: salet,
+slate, and blast.
Obviously, salet produces the best results, excepting the losses (14).
+Just re-arranging the letters into slate produces almost the same,
+but there are more losses (18). If attempting to minimize losses,
+then blast is the optimal starting guess, since it never takes more
+than 7 guesses and has the fewest losses (4) of any starting word in the
+combined full Wordle(tm) dictionary.
+
NB: The averages for GUESSES=9 are larger than the default,
+because the misses are essentially folded into the average.
+The averages are more accurately compared when using the higher limit,
+although minimizing losses remains the priority (who likes to lose?).
+
Seek These
+
The starting words with the fewest misses with dict:
+
sort -k3n results.avg | sed 18q | awk '{print $1, $3}' | column -t | pr -t -3
+
+ blast 4 ralph 7 crawl 8
+ palsy 6 ranch 7 crumb 8
+ climb 7 shawl 7 grasp 8
+ flash 7 tramp 7 lymph 8
+ lapse 7 clash 8 spark 8
+ prowl 7 clasp 8 swamp 8
+
+The starting words with the best accuracy:
+
+ sort -k2n results.avg | sed 18q | pr -t -3
+
+ crate 3.586609 20 irate 3.611231 31 trice 3.617279 15
+ slate 3.586609 18 slice 3.612095 22 cater 3.620302 26
+ trace 3.588769 18 stale 3.612959 19 satin 3.621598 19
+ crane 3.595248 26 train 3.613391 14 snail 3.621598 19
+ least 3.599568 19 trade 3.613823 20 stare 3.621598 19
+ plate 3.606479 22 leant 3.616415 18 dealt 3.622462 15
+
+ Note the word with fewest misses, `blast`, is relatively far
+ down the list in accuracy at 178th best:
+
+ sort -k2n results.avg | pr -t -n | grep blast
+
+ 178 blast 3.673002 4
Notice the difference in the average and weighted average. The program
+avg simply takes the total guesses as a percentage of the total words.
+The program wavg takes each of the six scores and weights them by the
+score. I wrote wavg later to track my progress playing the online game,
+and it is a more accurate score IMHO, but both are useful for comparisons.
The program wrank (weighted rank) makes this latter calculation much easier.
+It takes the output from rank and invokes wavg with these numbers,
+saving a lot of typing and errors.
+
./wrank blast
+ blast 3.6794
+
In words, crate as a first guess gets more correct answers in 2 and 3
+guesses, reducing its cost. It looks to be a stronger candidate, but it
+misses 16 more words (therefore losing the game more often). Your task
+is to determine your risk profile, and decide among the variety of possible
+starting points, then let prog recommend your next guess.
+
A somewhat laborious calculation provides the answer to which starting word
+has the most answers in two words and three words:
+
# two words
+ for n in results/*; do
+ rank $n | awk -v word=$n '/^2/ {print word,$2}';
+ done | sort -k2nr | sed 3q
+
+ trace 149
+ crate 147
+ slate 146
+
+ # three words
+ for n in results/*; do
+ rank $n | awk -v word=$n '/^3/ {print word,$2}';
+ done | sort -k2nr | sed 4q
+
+ crate 952
+ train 944
+ trace 939
+ slate 936
+
+ # versus the averages
+ sort -k2n -k3n results.avg | sed 3q
+ slate 3.586609 18
+ crate 3.586609 20
+ trace 3.588769 18
Dissecting the failed targets when starting with blast. Recall blast
+only misses 4 words out of all 2315:
+
foyer jaunt shave wound
+
These four words have common sub-patterns, which in hard-mode is difficult
+to disambiguate. Using run dict blast $word, here are the grep sub-patterns
+and counts for these four words as revealed in the output:
Looking at the patterns, the program is making guesses that just happen to
+select the correct word last in its choices. In all cases, on the seventh
+guess, the program has the correct answer using blast as the starting guess.
+It is easy to do an exhaustive look for only four words, but as the count
+goes up, so does the work.
+
Several variations were attempted, including randomization of the few results
+remaining. Besides being non-deterministic (this time it wins, next time it
+loses), better results were obtained with other changes to the selection
+algorithm. Some small insight into the algorithm used may be seen by the
+grep command lines, although there are additional insights used within
+the program that improve significantly upon these results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/2024/burton/extra.md b/2024/burton/extra.md
new file mode 100644
index 000000000..49073ab1d
--- /dev/null
+++ b/2024/burton/extra.md
@@ -0,0 +1,471 @@
+# extra
+
+This readme provides a description of the extra files provided, how to use them,
+analysis of their results, and a deeper investigation on the failed guesses.
+
+The recommendation is to do:
+
+```
+ make tools
+
+ ./run dict blast swept # exhaust runs this command a LOT!
+ ./run dict crate swept # show the diff between starting words
+
+ mkdir results # create the results directory
+ ./exhaust # exhaustive test of all words (~1 hour)
+ echo terns | ./word.result # add the word "terns" to results
+ ./mkresults > results.avg # proc exhaust into a single, small file
+```
+
+The files created as output from `exhaust` allow one to view, for each
+starting word, how each of the solutions resolve, including the misses.
+`mkresults` outputs a 1566 line report showing the starting word, its
+average accuracy, and the number of missed words. To show the number
+of guesses and the actual missed words, run `rank` on the desired word:
+
+```
+ ./rank results/blast
+
+ 1 1 # blast guessed itself
+ 2 112 # 112 words guessed in 2 attempts
+ 3 867 # 867 words guessed in 3 attempts
+ 4 1019 # ...
+ 5 271
+ 6 41
+ foyer jaunt shave wound
+
+ ./avg results/blast
+
+ blast 3.673002 4
+
+ grep blast results.avg
+
+ blast 3.673002 4
+```
+
+The C programs allow for (automated) testing:
+
+```
+ gen.c - simulate wordle game by generating targets and scoring guesses
+ ./gen dict [target]
+
+ dups.c - remove words with(out) repeated letters
+ (best starting words have no repeats)
+ cat dict | wc -l # all the words
+ cat dict | ./dups | wc -l # words with repeated letters
+ cat dict | ./dups -n | wc -l # words without repeated letters
+
+ run.c - `gen` and `prog` connected via pipes; allows automated testing
+ ./run dict [start [target]]
+ start - the first guess
+ target - force the target to be the named word
+```
+
+
+## Using More Guesses
+
+If you wish to see the failed words in action, and if more guesses would
+work, try:
+
+```
+ ./run dict blast jaunt | grep ^gen
+
+ gen: target: jaunt
+ gen: blast bbybg
+ gen: daunt bgggg
+ gen: haunt bgggg
+ gen: gaunt bgggg
+ gen: vaunt bgggg
+ gen: taunt ygggg
+ gen result end=0: n 6 lose: jaunt
+
+ GUESSES=7 ./run dict blast jaunt | grep ^gen
+
+ gen: target: jaunt
+ gen: blast bbybg
+ gen: daunt bgggg
+ gen: haunt bgggg
+ gen: gaunt bgggg
+ gen: vaunt bgggg
+ gen: taunt ygggg
+ gen: jaunt ggggg
+ gen result end=2: y 7 good: jaunt
+```
+
+Using `GUESSES=9` and `exhaust`, one gets a metric that scores words without
+misses, allowing a better comparison on the average score. Note, however,
+that the game doesn't bend this way, and anything more than 6 guesses is a
+loss. Take this metric with a grain of salt. Also, 9 is the limit of
+guesses; the program will not work properly - if at all - with more than
+9 guesses.
+
+Ranking by fewest missed with GUESSES=6, the order is:
+
+```
+ blast palsy climb flash lapse
+```
+
+Ranking by average with GUESSES=6, the order is:
+
+```
+ crate slate trace crane least
+```
+
+Ranking by average with GUESSES=9, the order is:
+
+```
+ slate trace crate train least
+```
+
+To reproduce these results:
+
+```
+ GUESSES=9 ./exhaust results.9
+ ./mkresults results.9 > results.9.avg
+```
+
+
+## Simple Analysis
+
+The 1566 raw files produced by `exhaust` are ~370KB each (total ~562MB),
+far too large to submit, so included are the compressed results files for
+four starting words, and the summary file `results.avg`.
+
+```
+ blast fewest missed
+ crate best average
+ query most missing
+ terns example used in remarks
+```
+
+The program `rank` allows one to see how the averages are calculated, as well
+as the actual missed words. Comparing the results for `blast` and `terns`:
+
+```
+ ./rank r.terns | awk 'NF==2' > a
+ ./rank r.blast | awk 'NF==2' > b
+ join a b | column -t
+
+ guesses terns blast
+ -------- ----- -----
+ 2 110 112
+ 3 909 867
+ 4 960 1019
+ 5 265 271
+ 6 53 41
+
+ F 18 4 (failed puzzles)
+```
+
+In general, the program `avg` is easier to use, but conveys less information:
+
+```
+ ./avg r.terns; ./avg r.blast
+ terns 3.641469 18
+ blast 3.673002 4
+```
+
+You have to decide if you prefer a marginally lower average, but slightly
+higher chance of losing, versus a marginally higher average and lower chance
+of losing. This is developed further in the following section.
+
+It is interesting that the letter order makes a noticeable difference:
+
+```
+ ./avg r.terns; ./avg results/stern
+ terns 3.641469 18 # lower average and fewer misses
+ stern 3.658315 20
+```
+
+For completeness, using `GUESSES=9` and the full starting dictionary from
+Wordle(tm), here are the results for the "best" starting words: `salet`,
+`slate`, and `blast`.
+
+```
+ guesses salet slate blast
+ ------- ----- ----- -----
+ 1 0 1 1
+ 2 148 146 112
+ 3 932 939 867
+ 4 925 919 1019
+ 5 240 235 271
+ 6 56 57 41
+ --- ----- ----- -----
+ 7 11 13 4
+ 8 2 4 0
+ 9 1 1 0
+ --- ----- ----- -----
+ avg 3.641 3.644 3.685
+```
+
+Obviously, `salet` produces the best results, excepting the losses (14).
+Just re-arranging the letters into `slate` produces almost the same,
+but there are more losses (18). If attempting to minimize losses,
+then `blast` is the optimal starting guess, since it never takes more
+than 7 guesses and has the fewest losses (4) of any starting word in the
+combined full Wordle(tm) dictionary.
+
+NB: The averages for `GUESSES=9` are larger than the default,
+because the misses are essentially folded into the average.
+The averages are more accurately compared when using the higher limit,
+although minimizing losses remains the priority (who likes to lose?).
+
+
+## Seek These
+
+The starting words with the fewest misses with `dict`:
+
+```
+ sort -k3n results.avg | sed 18q | awk '{print $1, $3}' | column -t | pr -t -3
+
+ blast 4 ralph 7 crawl 8
+ palsy 6 ranch 7 crumb 8
+ climb 7 shawl 7 grasp 8
+ flash 7 tramp 7 lymph 8
+ lapse 7 clash 8 spark 8
+ prowl 7 clasp 8 swamp 8
+
+The starting words with the best accuracy:
+
+ sort -k2n results.avg | sed 18q | pr -t -3
+
+ crate 3.586609 20 irate 3.611231 31 trice 3.617279 15
+ slate 3.586609 18 slice 3.612095 22 cater 3.620302 26
+ trace 3.588769 18 stale 3.612959 19 satin 3.621598 19
+ crane 3.595248 26 train 3.613391 14 snail 3.621598 19
+ least 3.599568 19 trade 3.613823 20 stare 3.621598 19
+ plate 3.606479 22 leant 3.616415 18 dealt 3.622462 15
+
+ Note the word with fewest misses, `blast`, is relatively far
+ down the list in accuracy at 178th best:
+
+ sort -k2n results.avg | pr -t -n | grep blast
+
+ 178 blast 3.673002 4
+```
+
+Versus starting words with fewest misses:
+
+```
+ egrep 'terns|lapse|blast|climb|crate' results.avg
+
+ blast 3.673002 4
+ climb 3.772354 7
+ crate 3.586609 20
+ lapse 3.664795 7
+ terns 3.641469 18
+
+ weighted avg
+ # blast crate blast crate improvement
+ - ----- ----- --------------- -----------
+ 1 1 1 1.0000 1.0000 0.0000
+ 2 112 147 1.9912 1.9932 -0.0020
+ 3 867 952 2.8837 2.8645 -0.0192
+ 4 1019 884 3.4527 3.3951 -0.0576
+ 5 271 250 3.6374 3.5775 -0.0599
+ 6 41 61 3.6794 3.6429 -0.0365
+
+ F 4 20 -16 +16 (0.26% blast vs 1.28% crate)
+```
+
+Notice the difference in the average and weighted average. The program
+`avg` simply takes the total guesses as a percentage of the total words.
+The program `wavg` takes each of the six scores and weights them by the
+score. I wrote `wavg` later to track my progress playing the online game,
+and it is a more accurate score IMHO, but both are useful for comparisons.
+
+```
+ $ ./avg results/blast
+ blast 3.673002 4
+ $ ./rank results/blast
+ 1 1
+ 2 112
+ 3 867
+ 4 1019
+ 5 271
+ 6 41
+ foyer jaunt shave wound
+ $ ./wavg 1 112 867 1019 271 41
+ 3.6794
+```
+
+The program `wrank` (weighted rank) makes this latter calculation much easier.
+It takes the output from `rank` and invokes `wavg` with these numbers,
+saving a lot of typing and errors.
+
+```
+ ./wrank blast
+ blast 3.6794
+```
+
+In words, `crate` as a first guess gets more correct answers in 2 and 3
+guesses, reducing its cost. It looks to be a stronger candidate, but it
+misses 16 more words (therefore losing the game more often). Your task
+is to determine your risk profile, and decide among the variety of possible
+starting points, then let `prog` recommend your next guess.
+
+A somewhat laborious calculation provides the answer to which starting word
+has the most answers in two words and three words:
+
+```
+ # two words
+ for n in results/*; do
+ rank $n | awk -v word=$n '/^2/ {print word,$2}';
+ done | sort -k2nr | sed 3q
+
+ trace 149
+ crate 147
+ slate 146
+
+ # three words
+ for n in results/*; do
+ rank $n | awk -v word=$n '/^3/ {print word,$2}';
+ done | sort -k2nr | sed 4q
+
+ crate 952
+ train 944
+ trace 939
+ slate 936
+
+ # versus the averages
+ sort -k2n -k3n results.avg | sed 3q
+ slate 3.586609 18
+ crate 3.586609 20
+ trace 3.588769 18
+```
+
+
+## Avoid These
+
+The starting words with the worst accuracy:
+
+```
+ sort -k2nr results.avg | sed 18q | pr -t -3
+
+ jumpy 3.997408 21 juicy 3.954212 39 squib 3.927862 28
+ jumbo 3.996976 25 quake 3.952052 38 quark 3.926566 30
+ buxom 3.995248 23 jerky 3.950756 31 quoth 3.920950 33
+ quick 3.987041 36 equip 3.939957 22 gawky 3.918790 22
+ quack 3.974514 23 quasi 3.938661 32 unzip 3.915335 24
+ quirk 3.964147 40 epoxy 3.934773 27 judge 3.914903 33
+```
+
+The starting words with the most failures (missed words):
+
+```
+ sort -k3nr results.avg | sed 18q | pr -t -3
+
+ query 3.893305 43 juicy 3.954212 39 enjoy 3.890713 37
+ quite 3.835421 42 quota 3.881641 39 gauze 3.878186 37
+ yield 3.740821 41 quake 3.952052 38 oxide 3.888121 37
+ juice 3.847084 40 quiet 3.857451 38 fiery 3.772786 36
+ quirk 3.964147 40 quote 3.829374 38 quail 3.893737 36
+ axion 3.796544 39 unify 3.862203 38 quick 3.987041 36
+```
+
+The worst target words, for any starting word (N out of 1566):
+
+```
+ ./worst
+
+ wound 1340 jaunt 1254 hatch 1157 foyer 1109 waste 1057
+ found 997 shave 945 wight 943 willy 790 catch 779
+ boxer 762 jolly 751 graze 626 rower 611 fatty 598
+ roger 568 taunt 520 watch 497 witty 483 wooer 451
+ tight 449 bound 442 swore 415 taste 405 mower 378
+ hover 374 bunch 371 shake 358 racer 348 rarer 294
+ paper 289 water 285 stave 271 ferry 250 fever 242
+ fully 241 paddy 239 fight 225 parer 219 taffy 207
+ frown 196 joker 195 filly 188 batty 179 lowly 179
+ staff 176 jazzy 174 piper 152 vying 152 swear 151
+```
+
+
+## SPOILER Deep Dive on Near Misses SPOILER
+
+Dissecting the failed targets when starting with `blast`. Recall `blast`
+only misses 4 words out of all 2315:
+
+```
+ foyer jaunt shave wound
+```
+
+These four words have common sub-patterns, which in hard-mode is difficult
+to disambiguate. Using `run dict blast $word`, here are the grep sub-patterns
+and counts for these four words as revealed in the output:
+
+```
+ foyer 25 grep '^.o.er' dict | wc -l
+ jaunt 6 grep '^.aunt' dict | wc -l
+ shave 7 grep '^sha.e' dict | wc -l
+ wound 8 grep '^.ound' dict | wc -l
+```
+
+Looking at the patterns, the program is making guesses that just happen to
+select the correct word last in its choices. In all cases, on the seventh
+guess, the program has the correct answer using `blast` as the starting guess.
+It is easy to do an exhaustive look for only four words, but as the count
+goes up, so does the work.
+
+Several variations were attempted, including randomization of the few results
+remaining. Besides being non-deterministic (this time it wins, next time it
+loses), better results were obtained with other changes to the selection
+algorithm. Some small insight into the algorithm used may be seen by the
+`grep` command lines, although there are additional insights used within
+the program that improve significantly upon these results.
+
+```
+ ./run dict blast foyer | grep ^gen
+ gen: target: foyer 2315
+ gen: blast bbbbb 429 grep -v '[blast]' dict | wc -l
+ gen: drone byyby 27 grep r dict | grep o | grep e | grep -v '[blastdn]' | wc -l
+ gen: cower bgbgg 8 grep '^.o.er' dict | grep -v '[blastdncw]'
+ foyer homer hover joker
+ mover poker roger rover
+ gen: mover bgbgg 4 grep '.o.er' dict | grep -v '[blastdncwmv]'
+ foyer joker poker roger
+ gen: poker bgbgg rm poker joker (foyer roger)
+ gen: roger ygbgg rm roger (foyer)
+ gen result end=0: n 6 lose: foyer
+
+ ---------------
+
+ ./run dict blast jaunt | grep ^gen
+ gen: target: jaunt 2315
+ gen: blast bbybg 46 grep 't$' dict | grep a | grep -v '[bls]' | wc -l
+ gen: daunt bgggg 5 grep '^.aunt$' dict | grep -v '[blsd]'
+ gaunt haunt jaunt taunt
+ vaunt
+ gen: haunt bgggg rm haunt (gaunt, jaunt, taunt, vaunt)
+ gen: gaunt bgggg rm guant (jaunt, taunt, vaunt)
+ gen: vaunt bgggg rm vaunt (jaunt, taunt)
+ gen: taunt ygggg rm taunt (jaunt)
+ gen result end=0: n 6 lose: jaunt
+
+ ---------------
+
+ ./run dict blast shave | grep ^gen
+ gen: target: shake 2315
+ gen: blast bbgyb 52 grep '^..a' dict | grep s | grep -v '[blt]' | wc -l
+ gen: share gggbg 5 grep '^sha.e' dict | grep -v '[bltr]'
+ shade shake shame shape
+ shave
+ gen: shade gggbg rm shade (shake shame shape shave)
+ gen: shape gggbg rm shape (shake shame shave)
+ gen: shame gggbg rm shame (shake shave)
+ gen: shake gggbg rm shake (shave)
+ gen result end=0: n 6 lose: shave
+
+ ---------------
+
+ ./run dict blast wound | grep ^gen
+ gen: target: wound 2315
+ gen: blast bbbbb 429 grep -v '[blast]' dict | wc -l
+ gen: drone ybygb 7 grep 'n.$' dict | grep d | grep o | grep -v '[blastre]' | wc -l
+ gen: pound bgggg 4 grep '^.ound' dict | grep -v '[blastreh]'
+ found hound mound wound
+ gen: mound bgggg rm mound (found, hound, wound)
+ gen: hound bgggg rm hound (found, wound)
+ gen: found bgggg rm found (wound)
+ gen result end=0: n 6 lose: wound
+```
diff --git a/2024/burton/extra_guesses b/2024/burton/extra_guesses
new file mode 100755
index 000000000..6297d825d
--- /dev/null
+++ b/2024/burton/extra_guesses
@@ -0,0 +1,13 @@
+#!/usr/bin/env bash
+
+w=$1; : ${w:?echo "usage: $0 target_word" >&2; exit 1}
+
+rank results/$w |
+sed -n 7,\$p |
+tr '\t' '\n' |
+awk '$1 != "" {print $1}' |
+sort -u |
+while read a; do
+ GUESSES=9 run dict $w $a
+done |
+grep result
diff --git a/2024/burton/freq b/2024/burton/freq
new file mode 100755
index 000000000..b1c54236a
--- /dev/null
+++ b/2024/burton/freq
@@ -0,0 +1,15 @@
+#!/usr/bin/env bash
+
+dict=$1
+: ${dict:=dict}
+
+echo first
+seq a z | while read a; do /bin/echo -n "$a: "; grep ^$a $dict | wc -l; done | sort -k2nr
+echo second
+seq a z | while read a; do /bin/echo -n "$a: "; grep ^.$a $dict | wc -l; done | sort -k2nr
+echo third
+seq a z | while read a; do /bin/echo -n "$a: "; grep ^..$a $dict | wc -l; done | sort -k2nr
+echo fourth
+seq a z | while read a; do /bin/echo -n "$a: "; grep ^...$a $dict | wc -l; done | sort -k2nr
+echo last
+seq a z | while read a; do /bin/echo -n "$a: "; grep ^....$a $dict | wc -l; done | sort -k2nr
diff --git a/2024/burton/gen.c b/2024/burton/gen.c
new file mode 100644
index 000000000..9c6ecc2a9
--- /dev/null
+++ b/2024/burton/gen.c
@@ -0,0 +1,86 @@
+#include
+#include
+#include
+#include
+#include
+
+/*
+ * Wordle generator - text mode
+ * This program works in coordination with the obfuscated code
+ * to allow one to play more rapidly (e.g. test the algorithm)
+ * or just to play along in text mode.
+ *
+ * This version is a pale imitation of the Real Wordle(tm).
+ * If you want to get the real experience, please visit:
+ *
+ * https://www.nytimes.com/games/wordle/index.html
+ */
+
+static int
+check(char *w, char *target)
+{
+ printf("%.5s ", w);
+ for (int i = 0; i < 5; ++i) {
+ if (w[i] == target[i])
+ putchar('g');
+ else if (memchr(target, w[i], 5))
+ putchar('y');
+ else
+ putchar('b');
+ }
+ putchar('\n');
+ fflush(stdout);
+ return memcmp(w, target, 5) == 0;
+}
+
+int
+main(int ac, char **av)
+{
+ char words[78557][5];
+ char buf[100];
+ int cnt = 0, win = 0;
+ int nguesses = 6;
+
+ if (ac < 2) {
+ fprintf(stderr, "usage: %s dict [target]\n", av[0]);
+ return 1;
+ }
+
+ if (getenv("GUESSES")) {
+ nguesses = atoi(getenv("GUESSES"));
+ // fprintf(stderr, "using %d guesses\n", nguesses);
+ }
+
+ FILE *fp = fopen(av[1], "r");
+ if (!fp) {
+ perror(av[1]);
+ exit(1);
+ }
+ while (fgets(buf, sizeof buf, fp)) {
+ if (buf[5] != '\n')
+ continue;
+ memcpy(words[cnt++], buf, 5);
+ }
+ fclose(fp);
+
+ srandom(time(0) ^ getpid());
+
+ char *target = ac == 3 ? av[2] : words[random() % cnt];
+ getenv("CHEAT") && printf("target: %.5s\n", target);
+
+ int i;
+ for (i = 0; i < nguesses; ) {
+ printf("? "); fflush(stdout);
+ if (!fgets(buf, sizeof buf, stdin))
+ break;
+ if (buf[5] != '\n') {
+ printf("you must enter 5 letters\n");
+ continue;
+ }
+ ++i;
+ if ((win = check(buf, target)))
+ break;
+ }
+ printf("%c %d %s: %.5s\n", win ? 'y' : 'n', i, win ? "good" : "lose", target);
+ return 0;
+}
diff --git a/2024/burton/index.html b/2024/burton/index.html
new file mode 100644
index 000000000..fd3dbd243
--- /dev/null
+++ b/2024/burton/index.html
@@ -0,0 +1,1004 @@
+
+
+
+
+
+
+
+
+
+
+
+
+2024/burton - Prize in pentagrammatology
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Name: Dave Burton
+Location: US - United States of America (United States)
+
+
+
+
+
+
+
+
+
To build:
+
make all
+
To use:
+
./prog dict
+
Try:
+
./try.sh
+
Judges’ remarks:
+
We were impressed with the algorithm, but one question remains: is there a
+strategy which reduces the probability of a loss even further, at the cost of
+requiring a higher average number of guesses?
+
Author’s remarks:
+
This program is an assistant for solving hard-mode Wordle(tm)
+(you must use any revealed hints in all subsequent guesses)
+accurately/efficiently - in the fewest guesses.
+The program expects lower case input in two words: guess color,
+followed by newline.
+
+
guess is the 5 letter word you guessed,
+
color is 5 letters from the set [g,y,b]
+
+
that correspond to the colors shown in Wordle: g=green, y=yellow, b=black.
+
Start the program with a single argument, the name of a dictionary of words.
+/usr/share/dict/words is a perfectly cromulent dictionary,
+but the included file dict contains the 2315 target words from the original
+Wordle game and consistently provides the fewest guesses.
+
As an example session, Wordle 226 has the target word light.
+The recommended first guess (for all Wordle puzzles) is blast, terns,
+or crate (see the extra.html that accompanies this entry for details).
+
Enter terns in game 226 of Wordle, and click the enter button.
+The letters will turn yellow, black, black, black, black.
+This assistant prompts “?”, and the input expected is the guessed word
+followed by the first letters of the color revealed for that guess:
The program responds with the recommended next guess. Enter
+this word loath into the game, which then reveals the colors
+green, black, black, yellow, yellow. Typing loath gbbyy into
+this assistant shows the solution is light, and exits.
+Type this word into the game, click enter, and viola!
+Solved in 3 guesses: terns > loath > light.
+
This program averages better than 4 guesses on the 1566 starting words
+without duplicate letters created by ./dups -n < dict,
+ranging from 3.587 to 3.997, with an overall average of 3.748 guesses.
+
This is excellent performance, and close to optimal.
+See this YouTube presentation on solving Wordle using information theory,
+which shows a hard mode average of 3.562 when using crane
+(time offset 29:58). There is a small correction video changing
+crane to salet, trace or crate.
+NB: These videos are NOT spoilers for this algorithm.
+
prog does NOT require you to use its offered guess.
+If you think you have a better guess than offered,
+simply type your guess and the Wordle/gen responses into prog;
+it will internally re-adjust using your input instead of its guess,
+and produce what it thinks is the best next guess after your input.
+
A Feature
+
Caution: When there are duplicate letters in the guess word,
+and one of them is marked black and the other non-black,
+this program MUST have the black letter marked yellow.
+The example session (Wordle 228) below demonstrates this:
+
# do NOT do this
+ $ prog dict
+ ? terns bbbby
+ shoal
+ ? shoal gggbb
+ shook
+ ? shook gggbg <<-- this is what Wordle shows
+ xyzzy <<-- no candidate words match
+
+ # do THIS instead
+ $ prog dict
+ ? terns bbbby
+ shoal
+ ? shoal gggbb
+ shook
+ ? shook gggyg <<-- not gggbg as shown in the game
+ shock
+ ? shock ggggg
+ shock
+
In the guess word shook, there are 2 o’s, but only one shown valid in
+the puzzle. If you mark the leftmost o as black (as according to the
+Wordle game), this program cannot find the winning word (shock),
+producing the error word xyzzy.
+
The included simulator gen produces the required transformation of b -> y.
+
The extra program run connects gen and prog, allowing for quick tests.
+
make tools
+ ./run dict terns shock # test starting guess `terns` against target `shock`
+
Using run allows one to quickly and easily experiment with different
+starting words for different target words, seeing how the guesses progress.
+
(A late tweak to the program improved its accuracy, and in the above example,
+the progression is now terns > shoal > shock. However, the caution remains
+for any duplicate letter guesses.)
+
Failure mode
+
The following 4 words from the included file dict are not guessed correctly
+within 6 guesses when using the recommended (via exhaustive testing)
+starting guess of blast. Since this program is deterministic, these
+four words always require 7 guesses when starting with blast, yielding
+a failure rate of 4/2315, or a success rate of 99.8%.
+
foyer jaunt shave wound
+
Using the ancillary programs run, exhaust, and mkresults,
+the starting word blast yields the fewest misses at these four words,
+with an accuracy/efficiency of 3.67. See extra.html
+for more detail.
+
This program also has a benefit the game Wordle does not:
+Wordle allows several thousand extra words to use in guesses not in dict.
+This program does not restrict any words, so one could enter any
+combination of 5 letters as input, except these are unlikely to be accepted
+by the Wordle game, and this program selects its words from the much more
+limited set that is present in dict. Using an expanded dictionary like
+/usr/share/dict/words provides a richer set of guesses, but generally
+increases the average number of guesses and the failure rate.
+
Interesting questions
+
+
How are candidate words chosen?
+
How does the array of numbers relate to finding a word?
+
It is interesting to see the final stages of picking a word.
+You might be interested to add observability? (Hint: make tfmt)
+Although clang-format is unlikely to help you understand the code,
+printf’s will help you understand how the “tables” are used:
+
“Show me your flowcharts and conceal your tables,
+and I shall continue to by mystified;
+show me your tables and I won’t usually need your flowcharts….”
+– Fred Brooks
+
There is a plausible “tunable”, not exposed. It selects when to
+discard certain words. What is this value, and how important is this
+value in optimizing results?
+
There is a debatable “bug” in the code, but it actually improves the
+results. Where and why?
+Hint: the limit for a loop. ;-)
+
This solver/assistant is pretty interesting to play with, experiment with.
+Can you improve it?
+
+
Did you notice?
+
+
Wordle is spelled in the code several different ways, one is obscure.
+If you need help, try this command (which requires clang-format):
+
+
make spoiler
+
+
My second favorite language is spelled out thrice in the source code.
+
Variables are mostly generic a,b,c and i,j,k,l and reused in different
+scopes. Have fun!
+
The Sierpinski4 number? What in the world is a Sierpinski number?
+
+
Time Passages (Apologies to Al Stewart)
+
This code was written in mid January 2022, before the NYT purchased Wordle[tm].
+
I have since used this assistant to play the game for more than a year,
+confirming my local experiments.
+
+
+wordle stats
+
+
The dictionary changed in 2023! In late March 2023, I encountered the first
+word not in dict: guano. In a bit of a surprise, I tried:
+
blast bbgbb
+ reach bbgbb
+ piano bbggg
+ xyzzy
+
What? The only word in dict ending in ano is piano. So I tried again
+using /usr/share/dict/words:
+
blast bbgbb
+ crane bbggb
+ guano ggggg
+
Blending the two, the puzzle was guessed in 4 tries total:
+
blast > reach > piano > guano
+
So caveat emptor: while dict used to be authoritative, we know some words
+were deemed offensive and removed. More problematic, some words were added,
+although I am presently unaware of which words. The existence proof is the
+above mentioned guano. There are almost certainly other words missing.
+
With guano added to dict, it is guessed in 3 using blast as the
+starting word:
+
blast bbgbb
+ reach bbgbb
+ guano ggggg
+
NB: dict has not been changed. gauno was NOT added to dict.
+Adding this word changes the statistics, and thus requires a change
+to all this material. It has a slightly negative impact, except
+for it finds the word guano. Essentially, as you add new words
+to dict, the permutations expand, and the scores decrease. This is
+why /usr/share/dict/words scores worse than dict - and loses more often.
+
April 9, 2023, this problem repeated with the target word snafu.
+That seems apropos.
Notice here that the suggested word was NOT used, instead the original
+guesses were used, and it found the correct answer in 4 guesses.
+However, doing
+
./run usdw blast pious
+
gets the answer correct in 3 guesses: blast > serio > pious.
Three guesses using an alternate dictionary and having to remove beant.
+This word isn’t even a word I can find in Webster’s. I hope your version
+of /usr/share/dict/words has more cromulent words.
Feb 18, 2025 adds a word not in dict nor usdw. “indie”.
+
$ ./prog dict
+ blast bbbbb
+ drone ybbyg
+ undue bggbg
+ xyzzy
+
+ $ ./prog usdw
+ blast bbbbb
+ drone ybbyg
+ undue bggbg
+ xyzzy
+
+ I grep'd the dictionaries. No plausbile hits.
+ So I solved it the old fashioned way: I guessed.
+
+ blast bbbbb
+ drone ybbyg
+ undue bggbg
+ indie ggggg
+
+ This solved it in 4, but the program could not win.
+ So add to the summary list above:
+
+ indie 4
+
Compilation
+
Compiles cleanly with -Wall -Wpedantic -Wextra,
+on MACOS M2 Clang/GCC 14 and Linux X86 Gcc 8.5.
+
If you are using -Weverything,
+which IMHO is exceptionally noisy about non-problems,
+and given the requirements of obfuscation and layout,
+there are a few -Wno- flags required to achieve a
+quiet compilation:
The code uses variable length arrays, omitted the keyword static
+for functions and global variables, and collide size_t with int
+for return types. There are no pedantic prototypes for functions.
+There is no misuse of the comma operator, but try getting the compiler
+to ignore it. The code has been run on MacOS M2 and Linux x86 with
+no failures observed. And as documented in deobfuscated.html,
+pointer bounds are intentionally abused for obfuscation, but the
+code is correct as documented.
+This is obfuscated C, so yes, variables are intentionally shadowed.
+printf() is also abused, passing in non-literals as the format.
+
Perhaps there is some platform out there that won’t work correctly
+due to the omissions noted above, but I am unaware of these.
Translate “Plurima responsa non recta esse supponamus”
+
+
+
Write a C program that writes a C program.
+
+
+
Write a sentence so that contains a split infinitive.
+
+
+
Rewrite the previous sentence so that it ends in a preposition.
+
+
+
How much wood does a woodchuck?
+
+
+
Tell me a silly joke.
+
+
+
Write a poem about a poet who is illiterate.
+
+
+
Give examples, based on mathematics, where 2+2 can equal 5.
+
+
Please note that the quality and accuracy of the answers you receive may vary. :-)
+We do NOT recommend believing everything you read from this program.
+Caveat lector!
+
Alternate code:
+
Alternate build:
+
NOTE: You must have successful run the
+2024/cable1/get_model.sh script
+before running the program.
+
make openmp
+
Alternate use:
+
./prog_openmp
+
Judges’ remarks:
+
This entry may benefit from OpenMP (via prog_openmp) for platforms that
+support compiling with OpenMP. Even on a cheap 8-core laptop, the produces
+tokens with a tolerable speed, at least for the first few lines.
+Without OpenMP, one must patiently await answers.
+
To preserve this entry for posterity, one thing to explore is to find the
+minimal model which exhibits a sensible behavior: for example, printing
+“Hello, world!” as the response to any input.
+
We took the liberty of making the program terminate gracefully at the end
+of input, at the cost of 2 extra bytes, and preserving the original in
+prog.orig.c.
+
NOTE: Even with OpenMP, this tool is not the fastest. A mild level of patience is advised.
+
DISCLAIMER: riPlurima responsa non recta esse supponamus!
+
IMPORTANT Download
+
ChatIOCCC runs Meta’s open source llama2-7b-chat model. Before using ChatIOCCC, you’ll need to accept Meta’s license
+and download the model weights (~7GB):
+
./get_model.sh
+
Author’s remarks:
+
ChatIOCCC - the world’s smallest and best LLM inference engine
+
About
+
ChatIOCCC is the world’s smallest LLM (large language model) inference engine - a “generative AI chatbot” in
+plain-speak. ChatIOCCC runs a modern open-source model (Meta’s LLaMA 2 with 7 billion parameters) and has a
+good knowledge of the world, can understand and speak multiple languages, write code, and many other things. Aside from
+the model weights, it has no external dependencies and will run on any 64-bit platform with enough RAM.
+
LLM inference engines are extremely complex, incorporating a tokenizer (SentencePiece or byte-pair encoding), embedding layer,
+transformer layers (including multi-head self-attention, feed-forward neural network, activation, layer norm and
+residual connections), key/value caching for performance, output projection, decoding, and a state machine to control
+the data flow. Implementing all of that machinery, with no external dependencies, generally takes thousands or tens of
+thousands of lines of code. ChatIOCCC is a full LLM implementation in under 1800 bytes of C, and even supports
+UTF-8/Unicode input and output and parallel processing over multiple CPU cores via OpenMP.
+
The author was inspired by llama2.c which aims to foster understanding of how LLMs work via a simple
+implementation. Unfortunately, even AI experts don’t actually understand why LLMs work at all. This core truth led to
+an epiphany: as LLMs are already maximally incomprehensible, obfuscation cannot make them more so. So, in the spirit of
+the IOCCC we can set aside the futility of aiming for comprehensibility, and instead focus purely on size.
+
Since smaller is always better, and ChatIOCCC is the world’s smallest LLM inference engine, it is therefore also the
+world’s best LLM inference engine.
+
Whether or not you fail to disagree that this paragraph, and those above, are or are not in and of themselves maximally
+incomprehensible, they represent in either case the origin story of this IOCCC submission, which implements an LLM
+inference engine in an impossibly minimal quantity of maximally incomprehensible C code.
+
Requirements
+
In addition to using ./get_model.sh to download the llama2-7b-chat model (see above), you’ll need around 11GB of free RAM to run ChatIOCCC.
+
Fun things to ask
+
Here are some fun things you can ask ChatIOCCC to do for you:
+
+
Tell me a surprising fact about an animal of your choice.
+
+
+
Write a short story for a 5 year old girl, featuring Sobieski the dog and Pepe the cat.
+
+
+
Write a C program which sorts a list using the bubble sort algorithm.
+
+
+
Write a poem about a little boy who builds a rocket to fly to the moon. In Japanese, please.
+
+
+
Translate into English: 这个项目会成为 2024 年 IOCCC 的赢家吗?
+
+
+
Tell me about the IOCCC and its history. Then, write a poem in French about it.
+
+
Personalities
+
ChatIOCCC allows the LLM’s system prompt to be defined at compile time (by using -DS="prompt...").
+The supplied Makefile includes three example personalities (set via system prompts) you can try: eeyore, snoop and linux (and
+their OpenMP versions, eeyore_openmp, snoop_openmp, linux_openmp).
+The eeyore and snoop personalities are self-explanatory. The linux personality makes ChatIOCCC act like a Linux
+machine. Try for example:
+
make linux
+ ./linux
+
Or for much better performance:
+
make linux_openmp
+ ./linux_openmp
+
Then try typing some Linux commands. You can even run an imaginary C compiler inside the LLM:
+
pwd
+ cat /etc/passwd
+ echo 'int main() { for (int i = 1; i <= 10; i++) printf("IOCCC %d\n", i); }' > test.c; gcc test.c; ./a.out
+ ls -la a.out
+
Limitations
+
The llama2-7b-chat model has a context window of 4096 tokens (around 2000 words). As you use
+ChatIOCCC, the context window fills up from your prompts and from the model’s responses,
+and the model gets progressively slower due to the attention mechanism needing to do more work. This is normal.
+
When the context window is full, ChatIOCCC will clear it and at that point the model will
+‘forget’ prompts/responses from earlier in the session. Various more sophisticated techniques
+exist to handle context window overflow (summarization, rolling window, NTK-aware scaled RoPE etc.), the implementation
+of which is left to the reader with too much time on his/her hands.
+
Footnotes
+
The length of this entry’s source code is 1750 bytes. Many interesting things happened in 1750, including:
+
+
The Industrial Revolution begins in Great Britain
+
British astronomer Thomas Wright first proposes that the Milky Way is a disk-shaped system of stars, with our Solar System near its center
+
Benjamin Franklin first proposes the idea that lightning is electrical in nature
+
Adwaita the giant tortoise, who lived until 2006, is born
+
Johann Sebastian Bach dies
+
+
As a final note, the author is pleased to report that this entry is absolutely totally impossible according to ChatGPT. But, to quote Walt Disney, “it’s kind of fun to do the impossible”.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/2024/cable1/prog.c b/2024/cable1/prog.c
new file mode 100644
index 000000000..532ffc072
--- /dev/null
+++ b/2024/cable1/prog.c
@@ -0,0 +1,27 @@
+#include
+#include
+#include
+#include
+#include
+
+#define a(_)typedef _##t
+#define _(_)_##printf
+#define x f(i,
+#define N f(k,
+#define u _Pragma("omp parallel for")f(h,
+#define f(u,n)for(I u=0;u<(n);u++)
+#define g(u,s)x s%11%5)N s/6&33)k[u[i]]=(t){(C*)A,A+s*D/4},A+=1088*s;
+
+a(int8_)C;a(in)I;a(floa)F;a(struc){C*c;F*f;}t;enum{Z=32,W=64,E=2*W,D=Z*E,H=86*E,V='}\0'};C*P[V],X[H],Y[D],y[H];a(F
+_)[V];I*_=U" 炾ોİ䃃璱ᝓ၎瓓甧染ɐఛ瓁",U,s,p,f,R,z,$,B[D],open();F*A,*G[2],*T,w,b,c;a()Q[D];_t r,L,J,O[Z],l,a,K,v,k;Q
+m,e[4],d[3],n;I j(I e,F*o,I p,F*v,t*X){w=1e-5;x c=e^V?D:0)w+=r[i]*r[i]/D;x c)o[i]=r[i]/sqrt(w)*i[A+e*D];N $){x
+W)l[k]=w=fmax(fabs(o[i])/~-E,i?w:0);x W)y[i+k*W]=*o++/w;}u p)x $){I _=0,t=h*$+i;N W)_+=X->c[t*W+k]*y[i*W+k];v[h]=
+_*X->f[t]*l[i]+!!i*v[h];}x D-c)i[r]+=v[i];}I main(){A=mmap(0,8e9,1,2,f=open(M,f),0);x 2)~f?i[G]=malloc(3e9):exit(
+puts(M" not found"));x V)i[P]=(C*)A+4,A+=(I)*A;g(&m,V)g(&n,V)g(e,D)g(d,H)for(C*o;;s>=D?$=s=0:p=U)for(_()("\n\n> "),0>\n"S"\n<>\n\n",Y);z=p-=z;U++[o+=z,B]=f)for(f=0;!f;z-=!f)for(f=V;--f&&f[P][z]|memcmp(f[P],o,z););pc[R]*m->f[R/W];R=s++;N Z){f=k*D*D,$=W;x 3)j(k,L,D,i?G[~-i]+f+R*D:v,e[i]+k);N
+2)x D)b=sin(w=R/exp(i%E/14.)),c=1[w=cos(w),T=i+++(k?v:*G+f+R*D)],T[1]=b**T+c*w,*T=w**T-c*b;u Z){F*T=O[h],w=0;I A=h*E;x
+s){N E)i[k[L+A]=0,T]+=k[v+A]*k[i*D+*G+A+f]/11;w+=T[i]=exp(T[i]);}x s)N E)k[L+A]+=(T[i]/=k?1:w)*k[i*D+G[1]+A+f];}j(V,L
+,D,J,e[3]+k);x 2)j(k+Z,L,H,i?K:a,d[i]+k);x H)a[i]*=K[i]/(exp(-a[i])+1);j(V,a,D,L,d[$=H/$,2]+k);}w=j($=W,r,V,k,n);x
+V)w=k[i]>w?k[$=i]:w;}}
diff --git a/2024/cable1/prog.orig.c b/2024/cable1/prog.orig.c
new file mode 100644
index 000000000..750de4c50
--- /dev/null
+++ b/2024/cable1/prog.orig.c
@@ -0,0 +1,27 @@
+#include
+#include
+#include
+#include
+#include
+
+#define a(_)typedef _##t
+#define _(_)_##printf
+#define x f(i,
+#define N f(k,
+#define u _Pragma("omp parallel for")f(h,
+#define f(u,n)for(I u=0;u<(n);u++)
+#define g(u,s)x s%11%5)N s/6&33)k[u[i]]=(t){(C*)A,A+s*D/4},A+=1088*s;
+
+a(int8_)C;a(in)I;a(floa)F;a(struc){C*c;F*f;}t;enum{Z=32,W=64,E=2*W,D=Z*E,H=86*E,V='}\0'};C*P[V],X[H],Y[D],y[H];a(F
+_)[V];I*_=U" 炾ોİ䃃璱ᝓ၎瓓甧染ɐఛ瓁",U,s,p,f,R,z,$,B[D],open();F*A,*G[2],*T,w,b,c;a()Q[D];_t r,L,J,O[Z],l,a,K,v,k;Q
+m,e[4],d[3],n;I j(I e,F*o,I p,F*v,t*X){w=1e-5;x c=e^V?D:0)w+=r[i]*r[i]/D;x c)o[i]=r[i]/sqrt(w)*i[A+e*D];N $){x
+W)l[k]=w=fmax(fabs(o[i])/~-E,i?w:0);x W)y[i+k*W]=*o++/w;}u p)x $){I _=0,t=h*$+i;N W)_+=X->c[t*W+k]*y[i*W+k];v[h]=
+_*X->f[t]*l[i]+!!i*v[h];}x D-c)i[r]+=v[i];}I main(){A=mmap(0,8e9,1,2,f=open(M,f),0);x 2)~f?i[G]=malloc(3e9):exit(
+puts(M" not found"));x V)i[P]=(C*)A+4,A+=(I)*A;g(&m,V)g(&n,V)g(e,D)g(d,H)for(C*o;;s>=D?$=s=0:p=U)for(_()("\n\n> "),scanf("%[^\n]%*c",Y)?U=*B=1:exit(0),p=_(s)(o=X,"[INST] %s%s [/INST]",s?
+"":"<>\n"S"\n<>\n\n",Y);z=p-=z;U++[o+=z,B]=f)for(f=0;!f;z-=!f)for(f=V;--f&&f[P][z]|memcmp(f[P],o,z););pc[R]*m->f[R/W];R=s++;N Z){f=k*D*D,$=W;x 3)j(k,L,D,i?G[~-i]+f+R*D:v,e[i]+k);N
+2)x D)b=sin(w=R/exp(i%E/14.)),c=1[w=cos(w),T=i+++(k?v:*G+f+R*D)],T[1]=b**T+c*w,*T=w**T-c*b;u Z){F*T=O[h],w=0;I A=h*E;x
+s){N E)i[k[L+A]=0,T]+=k[v+A]*k[i*D+*G+A+f]/11;w+=T[i]=exp(T[i]);}x s)N E)k[L+A]+=(T[i]/=k?1:w)*k[i*D+G[1]+A+f];}j(V,L
+,D,J,e[3]+k);x 2)j(k+Z,L,H,i?K:a,d[i]+k);x H)a[i]*=K[i]/(exp(-a[i])+1);j(V,a,D,L,d[$=H/$,2]+k);}w=j($=W,r,V,k,n);x
+V)w=k[i]>w?k[$=i]:w;}}
diff --git a/2024/cable1/try.sh b/2024/cable1/try.sh
new file mode 100755
index 000000000..3dca4d0ec
--- /dev/null
+++ b/2024/cable1/try.sh
@@ -0,0 +1,91 @@
+#!/usr/bin/env bash
+#
+# try.sh - demonstrate 2024/cable1
+
+# 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.
+#
+[[ -z "$CC" ]] && CC="cc"
+
+# clear the screen
+#
+clear
+
+# Verify we have the model
+#
+if [[ ! -s model ]]; then
+ echo 'ERROR: model not found!' 1>&2
+ echo 1>&2
+ echo 'You must successfully run ./get_model.sh and download the model to run this program.' 1>&2
+ echo 1>&2
+ exit 1
+fi
+
+# make sure the program has been built
+#
+read -r -n 1 -p "Press any key to when ready: "
+echo 1>&2
+make CC="$CC" all >/dev/null || exit 1
+
+# select a game
+#
+export SELECT=""
+while [[ -z $SELECT ]]; do
+
+ export NAME=""
+ export Z3=""
+ export SAVE=""
+ echo 1>&2
+ echo 'Select a personality (if in doubt try 0):' 1>&2
+ echo 1>&2
+ echo ' 0 prog - Common ChatIOCCC' 1<&2
+ echo ' 1 linux - As an imaginary Linux-based compiler' 1>&2
+ echo ' 2 eeyore - The old grey donkey from the Winnie-the-Pooh books' 1>&2
+ echo ' 3 rainman - In the style of Raymond, from the movie "Rain Man"' 1>&2
+ echo ' 4 snoop - Attempts to answer in the style of Snoop Dogg' 1>&2
+ echo 1>&2
+ echo ' q Quit without running a personality' 1>&2
+ echo 1>&2
+ read -r -n 1 -p "Enter your selection: " SELECT
+ echo 1>&2
+ echo 1>&2
+
+ # validate prompt
+ #
+ case "$SELECT" in
+ 0) NAME="prog" ;;
+ 1) NAME="linux" ;;
+ 2) NAME="eeyore" ;;
+ 3) NAME="rainman" ;;
+ 4) NAME="snoop" ;;
+ q) exit 0 ;;
+ Q) exit 0 ;;
+ *) echo 'ERROR: invalid selection, try again' 1>&2
+ SELECT="" # ask for a different selection
+ continue ;;
+ esac
+ export PROG="./$NAME"
+
+ # See if we can compile an openmp version
+ #
+ if [[ ! -x ${NAME}_openmp ]]; then
+ make CC="$CC" "${NAME}_openmp" >/dev/null 2>&1 < /dev/null
+ fi
+ if [[ -x ${NAME}_openmp ]]; then
+ # we have an openmp version, so use it
+ #
+ PROG="./${NAME}_openmp"
+ fi
+done
+
+# try the program
+#
+echo 'NOTE: Please be patient. This is not the fastest LLM agent.' 1>&2
+echo 1>&2
+echo 'NOTE: To exit, press CTRL+C' 1>&2
+echo 1>&2
+read -r -n 1 -p "Press any key to run: $PROG: "
+echo 1>&2
+echo 1>&2
+"$PROG"
+echo 1>&2
diff --git a/2024/cable2/.entry.json b/2024/cable2/.entry.json
new file mode 100644
index 000000000..66ed8b55f
--- /dev/null
+++ b/2024/cable2/.entry.json
@@ -0,0 +1,97 @@
+{
+ "no_comment" : "mandatory comment: because comments were removed from the original JSON spec",
+ "entry_JSON_format_version" : "1.2 2024-09-25",
+ "award" : "Prize in murky waters",
+ "year" : 2024,
+ "dir" : "cable2",
+ "entry_id" : "2024_cable2",
+ "title" : "salmon",
+ "abstract" : "salmon recipe",
+ "author_set" : [
+ {
+ "author_handle" : "Adrian_Cable"
+ }
+ ],
+ "manifest" : [
+ {
+ "file_path" : "prog.c",
+ "inventory_order" : 20,
+ "OK_to_edit" : true,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "entry source code"
+ },
+ {
+ "file_path" : "Makefile",
+ "inventory_order" : 30,
+ "OK_to_edit" : true,
+ "display_as" : "makefile",
+ "display_via_github" : true,
+ "entry_text" : "entry Makefile"
+ },
+ {
+ "file_path" : "prog.orig.c",
+ "inventory_order" : 50,
+ "OK_to_edit" : false,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "original source code"
+ },
+ {
+ "file_path" : "try.sh",
+ "inventory_order" : 100,
+ "OK_to_edit" : true,
+ "display_as" : "shellscript",
+ "display_via_github" : true,
+ "entry_text" : "script to try entry"
+ },
+ {
+ "file_path" : "2024_cable2.tar.bz2",
+ "inventory_order" : 1415926535,
+ "OK_to_edit" : false,
+ "display_as" : "tbz2",
+ "display_via_github" : false,
+ "entry_text" : "download entry tarball"
+ },
+ {
+ "file_path" : ".entry.json",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : true,
+ "display_as" : "json",
+ "display_via_github" : true,
+ "entry_text" : "entry summary and manifest in JSON"
+ },
+ {
+ "file_path" : ".gitignore",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : true,
+ "display_as" : "gitignore",
+ "display_via_github" : true,
+ "entry_text" : "list of files that should not be committed under git"
+ },
+ {
+ "file_path" : ".path",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : false,
+ "display_as" : "path",
+ "display_via_github" : false,
+ "entry_text" : "directory path from top level directory"
+ },
+ {
+ "file_path" : "README.md",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : true,
+ "display_as" : "markdown",
+ "display_via_github" : true,
+ "entry_text" : "markdown source for this web page"
+ },
+ {
+ "file_path" : "index.html",
+ "inventory_order" : 4294967295,
+ "OK_to_edit" : false,
+ "display_as" : "html",
+ "display_via_github" : false,
+ "entry_text" : "this web page"
+ }
+ ]
+}
diff --git a/2024/cable2/.gitignore b/2024/cable2/.gitignore
new file mode 100644
index 000000000..cb588a635
--- /dev/null
+++ b/2024/cable2/.gitignore
@@ -0,0 +1,7 @@
+#
+# sort with: ../../bin/sgi.sh
+*~
+*.dSYM
+*.o
+.DS_Store
+.*.swp
diff --git a/2024/cable2/.path b/2024/cable2/.path
new file mode 100644
index 000000000..5f9df565a
--- /dev/null
+++ b/2024/cable2/.path
@@ -0,0 +1 @@
+2024/cable2
diff --git a/2024/cable2/2024_cable2.tar.bz2 b/2024/cable2/2024_cable2.tar.bz2
new file mode 100644
index 000000000..2c10e7f5c
Binary files /dev/null and b/2024/cable2/2024_cable2.tar.bz2 differ
diff --git a/2024/cable2/Makefile b/2024/cable2/Makefile
new file mode 100644
index 000000000..ae845082b
--- /dev/null
+++ b/2024/cable2/Makefile
@@ -0,0 +1,210 @@
+#!/usr/bin/env make
+#
+# 2024/cable2
+
+#############################
+# shell used by this Makefile
+#############################
+
+SHELL= bash
+
+
+#######################
+# common tool locations
+#######################
+
+include ../../var.mk
+
+
+#####################
+# C compiler settings
+#####################
+
+# Common C compiler warnings to silence
+#
+# Example: CSILENCE= -Wno-poison-system-directories
+#
+CSILENCE= -Wno-strict-prototypes
+
+# Attempt to silence unknown warning options
+#
+CUNKNOWN= -Wno-unknown-warning-option
+
+# Common C compiler warning flags
+#
+# NOTE: The addition of -pedantic to CWARN is a challenge that
+# You may wish to avoid if it proves too problematic.
+# There is NO penalty for removing -pedantic from CWARN.
+#
+CWARN= -Wall -Wextra -pedantic ${CSILENCE} ${CUNKNOWN}
+
+# Compiler standard
+#
+CSTD= -std=gnu17
+
+# Compiler bit architecture
+#
+# Example for 32-bitness: ARCH= -m32
+# Example for 64-bitness: ARCH= -m64
+#
+# NOTE: Normally one should NOT specify a specific architecture.
+#
+ARCH=
+
+# Defines that are needed to compile
+#
+# Example: -Dfoo -Dbar=baz
+#
+CDEFINE=
+
+# Include files that are needed to compile
+#
+# Example: CINCLUDE= -include stdio.h
+#
+CINCLUDE=
+
+# Other flags to pass to the C compiler
+#
+# Example: COTHER= -fno-math-errno
+#
+COTHER=
+
+# Optimization
+#
+# NOTE: Feel free to change the level of compiler optimization.
+# The "-O3" is just a friendly default you might wish to try.
+#
+# Example: OPT= -O0 -g
+#
+OPT= -O3
+
+# Default flags for ANSI C compilation
+#
+CFLAGS= ${CSTD} ${CWARN} ${ARCH} ${CDEFINE} ${CINCLUDE} ${COTHER} ${OPT}
+
+# Libraries needed to build
+#
+# Example: LDFLAGS= -lncurses -lm
+#
+LDFLAGS=
+
+# C compiler to use
+#
+# NOTE: The IOCCC Judges recommend you leave CC as just "cc"
+# and NOT set it to clang, or gcc, or something else
+# unless you have a STRONG reason to do so.
+#
+# Setting CC to something other than "cc" makes your
+# code less portable to those who do not have your
+# particular C compiler. **hint**
+#
+# If you want to test your code with a particular C compiler,
+# use the make command line. For example:
+#
+# make all CC=clang
+# make all CC=gcc
+#
+CC= cc
+
+# Compiler add-ons or replacements for clang only
+#
+ifeq "$(findstring $(CLANG),${CC})" "$(CLANG)"
+#
+# NOTE: This code is only invoked when CC is "clang"
+# such as when you use the make command line:
+#
+# make all CC=clang
+#
+CSILENCE+= -Wno-c99-compat -Wno-missing-variable-declarations \
+ -Wno-poison-system-directories -Wno-sign-conversion -Wno-strict-prototypes
+#
+CWARN+= -Weverything
+#
+endif
+
+# Specific add-ons or replacements for gcc only
+#
+ifeq "$(findstring $(GCC),${CC})" "$(GCC)"
+#
+# NOTE: This code is only invoked when CC is "gcc"
+# such as when you use the make command line:
+#
+# make all CC=gcc
+#
+CSILENCE+=
+#
+CWARN+=
+#
+endif
+
+
+###########################################
+# Special Makefile variables for this entry
+###########################################
+
+ENTRY= prog
+PROG= ${ENTRY}
+#
+OBJ= ${PROG}.o
+TARGET= ${PROG}
+#
+ALT_OBJ=
+ALT_TARGET=
+
+# list any data files supplied with your submission
+#
+# Example: DATA= curds whey
+#
+DATA=
+
+
+#################
+# build the entry
+#################
+
+all: data ${TARGET}
+ @${TRUE}
+
+.PHONY: all alt data everything clean clobber
+
+# how to compile
+#
+${PROG}: ${PROG}.c
+ ${CC} ${CFLAGS} ${PROG}.c -o $@ ${LDFLAGS}
+
+# alternative executable
+#
+alt: data ${ALT_TARGET}
+ @${TRUE}
+
+${PROG}.alt: ${PROG}.alt.c
+ ${CC} ${CFLAGS} ${PROG}.alt.c -o $@ ${LDFLAGS}
+
+# data files
+#
+data: ${DATA}
+ @${TRUE}
+
+# both all and alt
+#
+everything: all alt
+ @${TRUE}
+
+
+###############
+# utility rules
+###############
+#
+clean:
+ ${RM} -f ${OBJ} ${ALT_OBJ}
+
+clobber: clean
+ ${RM} -f ${TARGET} ${ALT_TARGET}
+ ${RM} -rf *.dSYM
+
+
+######################################
+# optional include of 1337 hacker rulz
+######################################
+
+-include 1337.mk ../1337.mk ../../1337.mk
diff --git a/2024/cable2/README.md b/2024/cable2/README.md
new file mode 100644
index 000000000..cd1cd2e62
--- /dev/null
+++ b/2024/cable2/README.md
@@ -0,0 +1,105 @@
+## To build:
+
+```
+ make all
+```
+
+
+### Bugs and (Mis)features:
+
+Some terminal applications do not handle all Unicode characters adequately.
+
+On Linux, it is better to enjoy this entry on `gnome-terminal` or an equivalent modern terminal emulator.
+
+## To use:
+
+```
+ ./prog
+```
+
+
+## Try:
+
+```
+ ./try.sh
+```
+
+
+## Judges' remarks:
+
+We had a few minutes of amazement and fun while figuring that the is
+something fishy 🐠 wit the [prog.c source code](%%REPO_URL%%/2024/cable2/prog.c).
+
+Those who follow the philosophy of "_seeing is believing_" are
+likely to be "_deceived_" when they try to view the
+[prog.c source code](%%REPO_URL%%/2024/cable2/prog.c) in a terminal window:
+
+```
+ cat 2024/cable2/prog.c
+```
+
+**HINT**: There is a command line flag to the `cat(1)` tool may provide a clue.
+
+**HINT**: For those who might not be familiar with the
+[U"string" literal prefix](https://en.cppreference.com/w/cpp/language/string_literal.html):
+When using the U literal prefix, anything inside the quotes is encoded as **UTF-32**.
+
+**HINT TO FUTURE SUBMITTERS**: Now that we have awarded
+this **clever entry**, please understand that this
+[salmon is now old hat](https://en.wikipedia.org/wiki/Salmon_hat).
+What was **murky waters** for **IOCCC28** in 2024 will, in the future,
+be immediately seen through when analyzing future submissions to the IOCCC.
+In other words, to win a future IOCCC, you will need to do **MORE**
+than simply employing this fun obfuscation trick! :-)
+
+
+## Author's remarks:
+
+
+Salmon: a most fishy submission
+
+
+#### About
+
+This program obviously prints the squares of the numbers from 1 to 10. Or does it? The author got a little hungry for char-grilled salmon, and there's clearly something fishy going on with those unused #defines. Or is there? What the actual f*sh is going on here? Follow the three steps below for maximum enjoyment.
+
+**Step 1:**
+
+```
+ cat prog.c
+```
+
+**Step 2:**
+
+```
+ make clobber all
+```
+
+**Step 3:**
+
+```
+ ./prog
+```
+
+Scratch head. Then, [slap head with fish](https://www.youtube.com/watch?v=T8XeDvKqI4E).
+
+You may suspect there's something fishy with the `Makefile`, but you would be wrong. It just invokes `cc -o prog prog.c`
+
+You may suspect `cat` might be eating the salmon in step 1 (see `2015/endoh2`), but you would be even wronger. Confirm by looking at the program source using GitHub or `emacs` or `nano`.
+
+You are probably now even more confused, in which case, return to step 1.
+
+
+
diff --git a/2024/cable2/index.html b/2024/cable2/index.html
new file mode 100644
index 000000000..c5d5b4385
--- /dev/null
+++ b/2024/cable2/index.html
@@ -0,0 +1,633 @@
+
+
+
+
+
+
+
+
+
+
+
+
+2024/cable2 - Prize in murky waters
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Name: Adrian Cable
+Location: US - United States of America (United States)
+
+
+
+
+
+
+
+
+
To build:
+
make all
+
Bugs and (Mis)features:
+
Some terminal applications do not handle all Unicode characters adequately.
+
On Linux, it is better to enjoy this entry on gnome-terminal or an equivalent modern terminal emulator.
+
To use:
+
./prog
+
Try:
+
./try.sh
+
Judges’ remarks:
+
We had a few minutes of amazement and fun while figuring that the is
+something fishy 🐠 wit the prog.c source code.
+
Those who follow the philosophy of “seeing is believing” are
+likely to be “deceived” when they try to view the
+prog.c source code in a terminal window:
+
cat 2024/cable2/prog.c
+
HINT: There is a command line flag to the cat(1) tool may provide a clue.
+
HINT: For those who might not be familiar with the
+U”string” literal prefix:
+When using the U literal prefix, anything inside the quotes is encoded as UTF-32.
+
HINT TO FUTURE SUBMITTERS: Now that we have awarded
+this clever entry, please understand that this
+salmon is now old hat.
+What was murky waters for IOCCC28 in 2024 will, in the future,
+be immediately seen through when analyzing future submissions to the IOCCC.
+In other words, to win a future IOCCC, you will need to do MORE
+than simply employing this fun obfuscation trick! :-)
+
Author’s remarks:
+
Salmon: a most fishy submission
+
About
+
This program obviously prints the squares of the numbers from 1 to 10. Or does it? The author got a little hungry for char-grilled salmon, and there’s clearly something fishy going on with those unused #defines. Or is there? What the actual f*sh is going on here? Follow the three steps below for maximum enjoyment.
You may suspect there’s something fishy with the Makefile, but you would be wrong. It just invokes cc -o prog prog.c
+
You may suspect cat might be eating the salmon in step 1 (see 2015/endoh2), but you would be even wronger. Confirm by looking at the program source using GitHub or emacs or nano.
+
You are probably now even more confused, in which case, return to step 1.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/2024/cable2/prog.c b/2024/cable2/prog.c
new file mode 100644
index 000000000..fc2f491ec
--- /dev/null
+++ b/2024/cable2/prog.c
@@ -0,0 +1,15 @@
+#include
+
+unsigned int *salmon = U" is very yummy";
+
+#define grill ;while(putchar(*salmon++))
+#undef grill
+
+#define grill
+#undef grill
+
+int main() {
+ for (int i = 1; i <= 10; i++) {
+ printf("%d * %d = %d\n", i, i, i*i);
+ }
+}
diff --git a/2024/cable2/prog.orig.c b/2024/cable2/prog.orig.c
new file mode 100644
index 000000000..fc2f491ec
--- /dev/null
+++ b/2024/cable2/prog.orig.c
@@ -0,0 +1,15 @@
+#include
+
+unsigned int *salmon = U" is very yummy";
+
+#define grill ;while(putchar(*salmon++))
+#undef grill
+
+#define grill
+#undef grill
+
+int main() {
+ for (int i = 1; i <= 10; i++) {
+ printf("%d * %d = %d\n", i, i, i*i);
+ }
+}
diff --git a/2024/cable2/try.sh b/2024/cable2/try.sh
new file mode 100755
index 000000000..c128f948f
--- /dev/null
+++ b/2024/cable2/try.sh
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+#
+# try.sh - demonstrate 2024/cable2
+
+# 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.
+#
+[[ -z "$CC" ]] && CC="cc"
+
+# make sure the program has been built
+#
+make CC="$CC" all >/dev/null || exit 1
+
+# clear the screen
+#
+clear
+
+# try the program
+#
+read -r -n 1 -p "Press any key to run: ./prog: "
+echo 1>&2
+echo 1>&2
+./prog
+echo 1>&2
diff --git a/2024/carlini/.entry.json b/2024/carlini/.entry.json
new file mode 100644
index 000000000..9bab3aff2
--- /dev/null
+++ b/2024/carlini/.entry.json
@@ -0,0 +1,121 @@
+{
+ "no_comment" : "mandatory comment: because comments were removed from the original JSON spec",
+ "entry_JSON_format_version" : "1.2 2024-09-25",
+ "award" : "Prize in perfect timing",
+ "year" : 2024,
+ "dir" : "carlini",
+ "entry_id" : "2024_carlini",
+ "title" : "i4004",
+ "abstract" : "Intel 4004 emulation",
+ "author_set" : [
+ {
+ "author_handle" : "Nicholas_Carlini"
+ }
+ ],
+ "manifest" : [
+ {
+ "file_path" : "prog.c",
+ "inventory_order" : 20,
+ "OK_to_edit" : true,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "entry source code"
+ },
+ {
+ "file_path" : "Makefile",
+ "inventory_order" : 30,
+ "OK_to_edit" : true,
+ "display_as" : "makefile",
+ "display_via_github" : true,
+ "entry_text" : "entry Makefile"
+ },
+ {
+ "file_path" : "prog.orig.c",
+ "inventory_order" : 50,
+ "OK_to_edit" : false,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "original source code"
+ },
+ {
+ "file_path" : "try.sh",
+ "inventory_order" : 100,
+ "OK_to_edit" : true,
+ "display_as" : "shellscript",
+ "display_via_github" : true,
+ "entry_text" : "script to try entry"
+ },
+ {
+ "file_path" : "2024_carlini.tar.bz2",
+ "inventory_order" : 1415926535,
+ "OK_to_edit" : false,
+ "display_as" : "tbz2",
+ "display_via_github" : false,
+ "entry_text" : "download entry tarball"
+ },
+ {
+ "file_path" : ".entry.json",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : true,
+ "display_as" : "json",
+ "display_via_github" : true,
+ "entry_text" : "entry summary and manifest in JSON"
+ },
+ {
+ "file_path" : ".gitignore",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : true,
+ "display_as" : "gitignore",
+ "display_via_github" : true,
+ "entry_text" : "list of files that should not be committed under git"
+ },
+ {
+ "file_path" : ".path",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : false,
+ "display_as" : "path",
+ "display_via_github" : false,
+ "entry_text" : "directory path from top level directory"
+ },
+ {
+ "file_path" : "README.md",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : true,
+ "display_as" : "markdown",
+ "display_via_github" : true,
+ "entry_text" : "markdown source for this web page"
+ },
+ {
+ "file_path" : "adder.bin",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : true,
+ "display_as" : "binary",
+ "display_via_github" : true,
+ "entry_text" : "4004 binary to slowly add pressed digits"
+ },
+ {
+ "file_path" : "fib.bin",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : true,
+ "display_as" : "binary",
+ "display_via_github" : true,
+ "entry_text" : "4004 binary to slowly promt the Fibonacci numbers"
+ },
+ {
+ "file_path" : "redacted.bin",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : true,
+ "display_as" : "binary",
+ "display_via_github" : true,
+ "entry_text" : "4004 binary for slow Busicom calculator"
+ },
+ {
+ "file_path" : "index.html",
+ "inventory_order" : 4294967295,
+ "OK_to_edit" : false,
+ "display_as" : "html",
+ "display_via_github" : false,
+ "entry_text" : "this web page"
+ }
+ ]
+}
diff --git a/2024/carlini/.gitignore b/2024/carlini/.gitignore
new file mode 100644
index 000000000..cb588a635
--- /dev/null
+++ b/2024/carlini/.gitignore
@@ -0,0 +1,7 @@
+#
+# sort with: ../../bin/sgi.sh
+*~
+*.dSYM
+*.o
+.DS_Store
+.*.swp
diff --git a/2024/carlini/.path b/2024/carlini/.path
new file mode 100644
index 000000000..750b705ec
--- /dev/null
+++ b/2024/carlini/.path
@@ -0,0 +1 @@
+2024/carlini
diff --git a/2024/carlini/2024_carlini.tar.bz2 b/2024/carlini/2024_carlini.tar.bz2
new file mode 100644
index 000000000..279031996
Binary files /dev/null and b/2024/carlini/2024_carlini.tar.bz2 differ
diff --git a/2024/carlini/Makefile b/2024/carlini/Makefile
new file mode 100644
index 000000000..3f2420336
--- /dev/null
+++ b/2024/carlini/Makefile
@@ -0,0 +1,212 @@
+#!/usr/bin/env make
+#
+# 2024/carlini
+
+#############################
+# shell used by this Makefile
+#############################
+
+SHELL= bash
+
+
+#######################
+# common tool locations
+#######################
+
+include ../../var.mk
+
+
+#####################
+# C compiler settings
+#####################
+
+# Common C compiler warnings to silence
+#
+# Example: CSILENCE= -Wno-poison-system-directories
+#
+CSILENCE=
+
+# Attempt to silence unknown warning options
+#
+CUNKNOWN= -Wno-unknown-warning-option
+
+# Common C compiler warning flags
+#
+# NOTE: The addition of -pedantic to CWARN is a challenge that
+# You may wish to avoid if it proves too problematic.
+# There is NO penalty for removing -pedantic from CWARN.
+#
+CWARN= -Wall -Wextra -pedantic ${CSILENCE} ${CUNKNOWN}
+
+# Compiler standard
+#
+CSTD= -std=gnu17
+
+# Compiler bit architecture
+#
+# Example for 32-bitness: ARCH= -m32
+# Example for 64-bitness: ARCH= -m64
+#
+# NOTE: Normally one should NOT specify a specific architecture.
+#
+ARCH=
+
+# Defines that are needed to compile
+#
+# Example: -Dfoo -Dbar=baz
+#
+CDEFINE=
+
+# Include files that are needed to compile
+#
+# Example: CINCLUDE= -include stdio.h
+#
+CINCLUDE=
+
+# Other flags to pass to the C compiler
+#
+# Example: COTHER= -fno-math-errno
+#
+COTHER=
+
+# Optimization
+#
+# NOTE: Feel free to change the level of compiler optimization.
+# The "-O3" is just a friendly default you might wish to try.
+#
+# Example: OPT= -O0 -g
+#
+OPT= -O3
+
+# Default flags for ANSI C compilation
+#
+CFLAGS= ${CSTD} ${CWARN} ${ARCH} ${CDEFINE} ${CINCLUDE} ${COTHER} ${OPT}
+
+# Libraries needed to build
+#
+# Example: LDFLAGS= -lncurses -lm
+#
+LDFLAGS=
+
+# C compiler to use
+#
+# NOTE: The IOCCC Judges recommend you leave CC as just "cc"
+# and NOT set it to clang, or gcc, or something else
+# unless you have a STRONG reason to do so.
+#
+# Setting CC to something other than "cc" makes your
+# code less portable to those who do not have your
+# particular C compiler. **hint**
+#
+# If you want to test your code with a particular C compiler,
+# use the make command line. For example:
+#
+# make all CC=clang
+# make all CC=gcc
+#
+CC= cc
+
+# Compiler add-ons or replacements for clang only
+#
+ifeq "$(findstring $(CLANG),${CC})" "$(CLANG)"
+#
+# NOTE: This code is only invoked when CC is "clang"
+# such as when you use the make command line:
+#
+# make all CC=clang
+#
+CSILENCE+= -Wno-cast-align -Wno-declaration-after-statement -Wno-float-conversion \
+ -Wno-implicit-int-conversion -Wno-missing-prototypes \
+ -Wno-missing-variable-declarations -Wno-poison-system-directories \
+ -Wno-shadow -Wno-shorten-64-to-32 -Wno-sign-conversion
+#
+CWARN+= -Weverything
+#
+endif
+
+# Specific add-ons or replacements for gcc only
+#
+ifeq "$(findstring $(GCC),${CC})" "$(GCC)"
+#
+# NOTE: This code is only invoked when CC is "gcc"
+# such as when you use the make command line:
+#
+# make all CC=gcc
+#
+CSILENCE+=
+#
+CWARN+=
+#
+endif
+
+
+###########################################
+# Special Makefile variables for this entry
+###########################################
+
+ENTRY= prog
+PROG= ${ENTRY}
+#
+OBJ= ${PROG}.o
+TARGET= ${PROG}
+#
+ALT_OBJ=
+ALT_TARGET=
+
+# list any data files supplied with your submission
+#
+# Example: DATA= curds whey
+#
+DATA= redacted.bin
+
+
+#################
+# build the entry
+#################
+
+all: data ${TARGET}
+ @${TRUE}
+
+.PHONY: all alt data everything clean clobber
+
+# how to compile
+#
+${PROG}: ${PROG}.c
+ ${CC} ${CFLAGS} ${PROG}.c -o $@ ${LDFLAGS}
+
+# alternative executable
+#
+alt: data ${ALT_TARGET}
+ @${TRUE}
+
+${PROG}.alt: ${PROG}.alt.c
+ ${CC} ${CFLAGS} ${PROG}.alt.c -o $@ ${LDFLAGS}
+
+# data files
+#
+data: ${DATA}
+ @${TRUE}
+
+# both all and alt
+#
+everything: all alt
+ @${TRUE}
+
+
+###############
+# utility rules
+###############
+#
+clean:
+ ${RM} -f ${OBJ} ${ALT_OBJ}
+
+clobber: clean
+ ${RM} -f ${TARGET} ${ALT_TARGET}
+ ${RM} -rf *.dSYM
+
+
+######################################
+# optional include of 1337 hacker rulz
+######################################
+
+-include 1337.mk ../1337.mk ../../1337.mk
diff --git a/2024/carlini/README.md b/2024/carlini/README.md
new file mode 100644
index 000000000..155b475d7
--- /dev/null
+++ b/2024/carlini/README.md
@@ -0,0 +1,1324 @@
+## To build:
+
+```
+ make all
+```
+
+
+### Bugs and (Mis)features:
+
+The current status of this entry is:
+
+> **STATUS: known bug - please help us fix**
+
+For more detailed information see [2024/carlini in bugs.html](../../bugs.html#2024_carlini).
+
+
+## To use:
+
+```
+ ./prog rom.bin
+```
+
+
+## Try:
+
+```
+ ./try.sh
+```
+
+
+## Judges' remarks:
+
+What impressed us the most is not the sheer number of various compression
+and circuit simulation algorithms embedded into the entry, but the fact
+that it simulated the drum printer.
+
+If the Busicom calculator had 7-segment indicators instead, this entry
+might not have won. ;-)
+
+Reverse-engineering the circuit encoding format could be a fun exercise to
+make a minimalistic general purpose circuit simulator out of this entry.
+
+The IOCCC has seen a number of winning entries that allow code designed to
+run on early Intel processors, however none of them emulate a processor as
+early as the [Intel 4004](https://en.wikipedia.org/wiki/Intel_4004).
+Launched in 1971, the 4004 was the core of the first commercially marketed
+microprocessor chipset.
+
+
+### On speed
+
+One **MUST** be patient while the program is running some `*.bin` file.
+
+
+#### adder.bin
+
+```
+ ./prog adder.bin
+```
+
+This prints the 4 digit accumulator value about once every 32 seconds or so.
+
+When you press enter digits (0 thru 9), followed by a return key, the value
+is added to the 4 digit accumulator and is printed on the next (32+ second) cycle.
+
+This program is on an infinite loop: abort, using **CTRL-C**, to exit.
+
+
+#### fib.bin
+
+```
+ ./prog fib.bin
+```
+
+This program it an infinite loop to print the Fibonacci sequence in base 10.
+The next Fibonacci sequence value is printed about every 17 seconds or so.
+
+If you are **REALLY PATIENT** you will discover that the Fibonacci sequence
+values are actually printed in decimal mod 10000.
+
+This program is on an infinite loop: abort, using **CTRL-C**, to exit.
+
+
+#### redacted.bin
+
+This program emulates the original Busicom 141-pf calculator.
+
+This calculator is only for the **EXTREMELY PATIENT** person who is willing
+to wait about 75 seconds between operations.
+
+See [redacted.bin Key Bindings](#bindings) below for details.
+See the [try.sh](try.sh) shell script for an example.
+
+This program is on an infinite loop: abort, using **CTRL-C**, to exit.
+
+
+## Author's remarks:
+
+
+### An Intel 4004
+
+The Intel 4004, one of the first microprocessors, celebrated its 50th anniversary in 2021.
+To commemorate this (and as a submission to IOCCC 2021\^H2\^H3\^H4\^H5), this program
+is a feature-complete 4004 emulator that's capable of emulating the original
+Busicom 141-pf calculator ROM---the application for which the 4004 was originally designed.
+
+To make things exciting, this program doesn't emulate the 4004 the "normal" way.
+Instead, this program is actually just a logic gate simulator, with the entire 4004
+encoded as a circuit that's then emulated.
+And because we're 50 years in the future, this gate-level emulated calculator
+runs at a few hundred instructions per second which
+is actually fast enough to be usable---just as long as you're not in a hurry.
+
+
+#### A very brief primer on the Busicom 141-pf and Intel 4004
+
+The Intel 4004 is an exceptionally simple CPU by modern standards.
+It is a 4-bit processor,
+with 16 general purpose registers.
+There are a total of just 45 instructions, and many of them are nearly identical to others,
+so in practice there are more like only 20 unique instructions.
+It's accumulator-based, which means that almost all instructions either operate on a special 4-bit accumulator,
+or load data into the accumulator or transfer it out.
+And the program counter can address up to 12 bits of ROM.
+All in, this makes it one of the simpler instruction sets out in the world,
+which makes sense given its age.
+
+You can attach three other chips to the 4004 CPU that provide:
+
+- ROM, via an Intel 4001: This stores the program code to be executed, or any other read-only data.
+- RAM, via an Intel 4002: This gives additional storage of more than just the 4*16 bits from the registers.
+- A shift register, via an Intel 4003, to temporarily hold a queue of data which can be attached to physical hardware to help manage I/O.
+
+The 4004 was originally built for use in the Busicom 141-pf calculator.
+While initially the 4004 was going to be application-specific just to make the calculator possible,
+some forward looking engineers at Intel decided to build a general-purpose
+chip that could perform arbitrary calculations, and then just program the chip
+to be a calculator. And thus was born the general-purpose microprocessor.
+
+The Busicom calculator itself is a fairly simple device.
+It has an 8x4 keypad the operator can use to enter numbers or perform numerical
+calculations,
+and an output tape on which the result of the calculation is printed.
+The keypad is simple and looks familiar to any calculator today.
+But the output works through an esoteric (by today's standards) mechanism.
+A spinning print-drum rotates continuously above a paper tape;
+when the calculator wishes to print a number, it strikes hammers from one of the 18 columns
+at the exact moment the print drum has the desired number above the paper tape,
+and then advances the tape to be visible to the operator.
+
+
+#### Overall structure of the program
+
+The program is split, roughly, into three distinct components:
+
+1. First, it takes a compressed string and decompresses it to recover a circuit that,
+ when executed, emulates the Intel 4004 (and a few Intel 4001s, 4002s, and 4003s).
+ As part of this process, the program inserts the provided program ROM from argv[1] into the circuit.
+
+2. Then, the program actually emulates the decompressed circuit by computing the output of each gate
+ in a loop, effectively running the CPU and associated RAM/ROM chips. (With a few associated tricks
+ to make things run fast.)
+
+3. Finally, the program simulates the original calculator hardware and handles converting the input
+ text from ascii text passed via stdin to the original hardware keyboard presses, and also
+ converting the shift register causing hammers to strike paper tape back to ascii outputs.
+
+The remainder of this section documents the implementation of each of these three components.
+Here's a small visual to show what's going on.
+
+```
+ │ │
+ │ │ Compressed circuit (hard-coded), and ROM (via argv[1])
+ ▼ ▼
+ ┌──────────────┐
+ │ Decompress │ via LZ decompression; arithmetic encoding; and special circuit-compression
+ └──────────────┘
+ │
+ │ gate-level description (~200 k gates)
+ ▼
+ ┌──────────────┐
+ │ Emulation │ a simple loop that re-calculates each gate based on its inputs
+ └──────────────┘
+ │ ▲
+ │ │ if circuit indicates that I/O is necessary
+ ▼ │
+ ┌──────────────┐ (processed to turn ascii to key-presses)
+ │ I/O Handler │ ◀──────────────────────────────────────────── stdin
+ └──────────────┘
+ │ (processed to turn hammer strikes to ascii)
+ └───────────────────────────────────────────────────────▶ stdout
+```
+
+
+##### Decompressing the compressed circuit representation (part 1)
+
+The circuit is compressed twice. At the outer level is an LZ-compressor with arithmetic encoding,
+and then on the inner level is a special-purpose logic-gate compressor that allows creating
+small sub-circuits that can be called.
+
+The first part of the decompression is the more straightforward of the two.
+The data is compressed with a special-purpose LZ-style compressor that,
+instead of being bit- or byte-level, operates on unbounded integers as the data stream.
+The LZ decompresser itself pulls bits one at a time from an arithmetic encoded data stream.
+
+```
+ int output_circuit[big];
+ void lz() {
+ int* ptr = output_circuit;
+ int num_bytes = get_integer();
+
+ while (num_bytes--) {
+ int is_match_op = get_bit();
+ if (is_match_op) {
+ int* ref = ptr - get_integer();
+
+ int copy_len = get_integer() + 1;
+ for (int i = 0; i < copy_len; i++) {
+ *ptr++ = *ref++;
+ }
+ } else {
+ *ptr++ = (1-2*get_bit()) * get_integer();
+ }
+ }
+ }
+```
+
+The arithmetic encoding actually just lifts directly from Fabrice Bellard's wonderful submission to
+IOCCC 2018, as un-obfuscated by Andrew Kensler, with a few tweaks of my own to reduce its length,
+and to cut out some features I don't need. Briefly, arithmetic encoding keeps a history of
+how likely each bit was to be zero or one, and then uses this prior to inform the decoding of
+the output stream. This version of arithmetic encoding uses a base-1968 encoding abusing the
+fact that IOCCC counts whitespace special, and IOCCC doesn't allow use of high-bit codepoints.
+
+```
+ int get_bit(int ctx) {
+ if (range < radix) {
+ range *= radix;
+ fraction *= radix;
+
+ tmp = *bitstream++;
+ fraction += (tmp - 1 - ( tmp > 10 ) - ( tmp > 13 ) - ( tmp > 34 ) - ( tmp > 92 )) << 4;
+ tmp = *bitstream++;
+ fraction += tmp < 33 ? ( tmp ^ 8 ) * 2 % 5 : ( tmp ^ 6 ) % 3 * 4 + ( *bitstream++ ^ 8 ) * 2 % 5 + 4;
+ }
+ int *counts = history_buffer + ctx * 2;
+ int split = range * -~*counts / (*counts + counts[ 1 ] + 2);
+ int the_bit = fraction >= split;
+ fraction -= split*the_bit;
+ range = the_bit ? range-split : split;
+
+ counts[the_bit]++;
+ return the_bit;
+ }
+```
+
+To read integers out of the datastream, we used a compressed representation that allows
+for arbitrarily-length integers but giving preference to smaller constants than larger ones,
+inspired by Golomb coding. Here's the implementation of this:
+
+```
+ int get_integer(int length, int ctx) {
+ int subtract_it = 1<
+ int* decode(int* data_stream) {
+ int* prev_start;
+ // ...
+ if (*data_stream++ == 6) // repeat
+ // A repeat is a loop that runs the prior instruction a variable number of times,
+ // and also allows for updating the arguments to the prior instruction by a
+ // constant scalar on each step.
+
+ // To implement this, we use some self-modifying code:
+ // 1. Decrement the argument that says how many repeats to do
+ // 2. Adjust the other arguments from the prior instruction as necessary
+ // 3. Go back 2 instructions if the counter is greater than zero.
+ // (on the next iteration of the loop we'll modify the arguments again).
+ int number_of_times_to_duplicate = *data_stream++;
+ num_change = tmp = *data_stream++;
+ if (number_of_times_to_duplicate) {
+ for (int i = 0; i < tmp; i++) {
+ int increment_constant = data_stream[*data_stream++];
+ prev_start[*data_stream++] += increment_constant;
+ }
+ data_stream = prev_start;
+ } else {
+ data_stream += num_change * 2;
+ }
+ }
+ }
+```
+
+
+Finally, there's one more special code that acts like a function call, and says
+"go copy that small sub-circuit defined somewhere else to here. This behaves
+similarly to repeat. The program defines five of these sub-circuits that are
+used throughout the program; the most important of these being a full adder,
+but also a single register (so it can be duplicated 256 times) and various helper
+circuits.
+
+The implementation of the function-call decoding is again fairly simple:
+the program pulls off the function ID to be called, the number of arguments it
+takes, and then sets a global `arguments` array with these arguments.
+Then, we just jump to the relevant function and start decoding from there.
+(With a tiny twist: because functions can have REPEAT ops, and REPEAT uses
+in-place self-modifying code to work, we have to actually make a complete
+copy of the function and then execute it so that we can call it multiple times
+without breaking REPEAT.)
+
+
+```
+ int* decode(int* data_stream) {
+ ...
+ if (*data_stream++ == 7) { // function call
+ // A function call goes and runs a small number of instructions and returns back.
+ // Nested functions aren't possible.
+ // So to call a function, we just set the global arguments buffer with the correct arguments,
+ // write out the data of the function, and then call cluster() on that location.
+
+ int which_function = *data_stream++;
+ int num_args = *data_stream++;
+ for (int i = 0; i < num_args; i++) {
+ arguments[i] = *data_stream++;
+ }
+
+ // Copy to buf the current compressed ops
+ // we'd like to just do a reference,
+ // but if the called function uses loops then they modify the code in-place
+ // so we have to copy before the function call
+ for (int i = 0; i < BIG; i++) {
+ buf[i] = prog_src[i];
+ }
+ decode(buf+functions[which_function]);
+ }
+ }
+```
+
+After compression, the entire circuit of 200,000 gates is crammed down to just over 1000
+bytes. How's that for an efficient compression algorithm?
+
+
+##### Decompressing the compressed circuit representation (part 3)
+
+The final part of decompressing the compressed circuit is to load the program ROM
+from argv[1] and insert it into the circuit. This is relatively simple; the circuit
+contains a big MUX tree that encodes placeholders for the program ROM, and so all
+the code does is directly edit the placeholder variables that will be used to load the ROM
+with the following simple function.
+
+```
+ // buf contains the program text that is to be inserted into the circuit
+ // gates is the array that has the actual logic gates
+ void fix_const_help(int depth, int writesize) {
+ for (i = 0; i < depth; i++) {
+ for (int j = 0; j < 1<>i&1;
+ }
+ }
+ }
+```
+
+(In an identical manner, this is also how the microcode is written in to the circuit so that each
+instruction can be implemented with the extra simple circuit.)
+
+
+##### Emulating the instructions
+
+The second component of the program is an emulator to actually run each of the (now decompressed)
+AND/OR/NOT/XOR gates that are used as primitive building blocks to implement the circuit.
+This is by far the simplest portion of the circuit, and is just a compressed switch statement
+that selects the command we're running and does the correct corresponding action. Again,
+the weird compression is necessary to save space.
+
+```
+ command = insns[ctr*4];
+
+ // Load the potential arguments for this instruction.
+ arg1 = gate_value[insns[ctr*4+1]];
+ arg2 = gate_value[insns[ctr*4+2]];
+ arg3 = gate_value[insns[ctr*4+3]];
+
+ // We have six possible commands REF, NOT, OR, AND, XOR, MUX
+ // Here we're going to evaluate with a series of ternary ops.
+ gate_value[ctr] = command<2 ?
+ arg1^command // either 0 (DIRECT) or 1 (NOT)
+ :
+ // either 2 (OR), 3 (AND), 4 (XOR), or 5 (MUX)
+ command<4 ?
+ command^3 ?
+ arg1|arg2 :
+ arg1&arg2
+ :
+ command^5 ?
+ arg1^arg2 :
+ arg1?arg2:arg3;
+```
+
+This loops basically forever until the user gets bored and kills the process.
+
+
+##### Handling input and output
+
+Finally, we need to be able to actually hook this circuit to the outside world.
+Inside the circuit I set aside one "wire" whose only purpose is to
+signal to the outside world that it wants to take some action. Think of this like
+a trap in an operating system, but at the hardware level: whenever the circuit
+wants to take some action in the outside world, it pulls one of the "wires" high
+for a single clock cycle and the C program watches for this to handle the response.
+The entirety of this trap handler is implemented as below, explained in more
+detail as follows.
+
+
+```
+ if (gate_value[trap_id]) {
+
+ int is_write = gate_value[trap_id+1];
+ int rom_or_ram = !gate_value[trap_id+2];
+
+ jcn_counter += rom_or_ram & !is_write;
+ if (is_write & rom_or_ram & gate_value[trap_id+3]) {
+ for (int i = 0; i < 18; i++) {
+ int idx = ((i+3)%18-(i>15));
+ putchar(charset[i*18+*(int*)(gate_value+print_uid+idx*21)%18]);
+ }
+ puts("");
+ }
+
+ // Every 128 JCN instructions we should send the next keypress.
+ // 128 is hard-coded in the circuit. Don't change.
+ if (jcn_counter - reset_key_matrix > 128) {
+ reset_key_matrix = jcn_counter;
+ read_or_reset = !read_or_reset;
+ int read_char = read_or_reset ? 0 : charset[325 + getchar()];
+ for (int i = 0; i < 8; i++) {
+ // this is where the circuit expects the input data to be written
+ gate_value[trap_id+8+i] = read_char>>i&1;
+ }
+ }
+```
+
+A trap can be for one of two reasons:
+
+- First, it be because the program wants to read some data from the outside world.
+ When connected to the Busicom calculator, the 4004 will either want to read any
+ key that might be pressed by the user on the input, or will want to read a single
+ bit to detect when the spinning printer drum has advanced to the next location.
+
+- And second, it can be because the program wants to write some data to make a change
+ to the outside world. The 4004 uses writes to strike the hammers against the print
+ drum, advance the paper tape (a "new line"), and to energize one of the 10 possible
+ lines of the keyboard to enable that corresponding line to be read.
+
+The program contains two compressed lookup tables to enable this functionality.
+First, it remaps the ASCII characters that the C program reads with getchar()
+to (row, column) locations of the corresponding key on the physical keyboard.
+For example, the number 9, 6, and 3 are at location (4,0), (4,1) and (4,2).
+This lookup table encodes each ASCII character into a six bit number, which
+itself is then compressed along with the circuit using the same LZ compression.
+
+The program also contains a lookup table to map each of the hammer-strike outputs
+to ASCII characters that can be putchar()'d. This table, if implemented in the naive
+manner, would be fairly straightforward, because each print drum just repeats the
+numbers 0 to 9 in order (two columns of the drum contain special characters).
+To enable a much more efficient lookup, the data is stored permuted according
+to the following permutation {0, 1, 6, 7, 2, 3, 0, 0, 12, 13, 8, 9, 14, 15, 10, 11, 4, 5}.
+
+The purpose of permuting the data in this way (and storing some data duplicated! notice
+that 0 is stored several times) is that now we can read it out of memory much more
+concisely, with the following line:
+
+```
+ for (int idx = 0; idx < 18; idx++) {
+ putchar(charset[i*18+*(int*)(circuit_memory+offset+idx*21)%18]);
+ }
+```
+
+Specifically, for each of the 18 drum locations, we print the character at that drum.
+`charset[i*18]` offsets us to the correct drum. The remaining constant is where the
+magic happens: circuit_memory is normally an array of uint8; by casting to (int*)
+we can load four values at a time, which as it happens is exactly the number of index
+bits we need. What we get is then an integer like 0x01000101. And it turns out that if
+you multiply this number by 21 and then take the result mod 18, you end up exactly
+being able to index into that permuted ASCII table.
+
+(This is just one of the many pieces of the program that has to be implemented
+in convoluted ways to cut down on program length. I'll try to omit most of the rest
+for brevity.)
+
+Now there's one final question: when to make input available. On the original
+calculator, the print drum was actually spinning and so that set the rate of inputs
+that were pushed to the circuit. But we have no actual spinning drum and so we
+need to decide the rate that input will be passed. Instead of making running
+based on wall-clock time, the C program does something somewhat confusing, and
+tracks the number of conditional jump operations that have been issued.
+Every 128 conditional jumps (JCN's) that branch on the 4004's TEST pin, it makes one
+more character of STDIN available to the program. This is the fastest rate
+possible at which the ROM can handle input without dropping characters.
+
+
+##### Making it go fast(er)
+
+The CPU itself has over 200,000 gates (I'll describe why in detail later---but it's to
+save space when compressed).
+Now given that we have to loop over every gate 16 times for one tick of the clock,
+and each instruction takes 16 inner clocks of the circuit,
+we're going to run into a problem.
+If we would like it to run at anything faster than one instruction per second,
+we'll have to make some changes while still keeping things in our space constraint.
+
+As has been said many times before,
+you can't make computers perform the same amount of work faster.
+You can only make them do less.
+
+So the program does just that. Instead of re-calculating every gate on every iteration of the loop,
+it keeps track of which inputs have changed last time, and then only re-calculates the
+gates whose input changed during the prior round.
+This requires that when we first load the circuit off of disk that we build a table in
+memory for which gates depend on which others. In order to minimize space here, this is
+a dense table with shape 200,000 x 70,000 (it's 70,000 wide because
+there's exactly one gate---the clock---that 64k other gates depend on).
+
+Once we've built the table the logic gets somewhat complicated. The program maintains a
+3-deep hierarchical bitmask to indicate how far can be skipped ahead. At each level
+is an array of 64-bit words where each bit corresponds to whether or not there is any
+gate that needs to be updated at the next level "down" in the tree. (So, for example,
+at the lowest level if a bit is 0 anywhere then that gate doesn't need to be updated;
+at the second level if a bit is 0 then all of the 64 bits below it don't need to be
+updated, and at the highest level the 64*64 bits below don't need to be updated.)
+
+The logic to actually set the bits that need to be updated is as follows. Initially
+needs_update is set to 0xFFFFFFFFFFFFFFFF and then bits are cleared when gates they
+depend on are changed
+
+```
+ int num_depends = depends_ctr[ctr];
+ while (num_depends--) {
+ int gate = depends[ctr][num_depends];
+
+ for (int depth = 0; depth < 3; depth++) {
+ needs_update[total_gate_count/64*depth + (gate>>6*-~depth)] &= ~(1L<<(gate>>6*depth)%64);
+ }
+ }
+```
+
+This compressed code isn't that hard to reason about. First we select the right address
+by taking the gate index and dividing by 2^(6*(depth-1)). Then, we select the bit
+address within the word by looking at the remaining bits in the gate. We do this for all
+three depths, and make sure to only ever clear bits, so the needs_update gets sparser
+and sparser as the circuit goes forward.
+
+And the corresponding logic to check if we need to process the current
+data is implemented here.
+Again this works by just masking out to check if all of the bits in needs_update are zero,
+and skips if any are set to 1.
+If a bit at the lowest level of the tree is 1 then it skips one gate forward;
+if a bit at the medium level is 1 then it skips 64 gates forward,
+and at the highest level 64*64 gates forward.
+This function looks simple, but there are several
+cases that are all magically handled here in very subtle ways.
+Try to figure out why it's exactly right!
+
+```
+ for (int depth = 3; depth-->0; ) {
+ int divide = 1<<6*depth;
+ int gate = ctr/divide;
+
+ unsigned long tmpll = needs_update[total_gate_count/64*depth + gate/64] >> gate%64;
+ while (tmpll&1) {
+ ctr = ctr - ctr%divide + divide;
+ tmpll/=2;
+ gate = 0; // break out of the above loop
+ }
+ }
+```
+
+This ends up giving about a 100x-500x performance boost on average, and allows the
+emulated 4004 to run at a few hundred instructions per second, which isn't all that bad!
+(But even at 100x speed it still takes roughly a minute for the calculator to perform
+the addition of two numbers. Slow, but actually only 60x slower than the original
+calculator that took one second to do the same addition.)
+
+And thus concludes how the actual C program itself works. There are a lot more tricks
+going on, but this is hopefully enough detail to understand most of the important pieces.
+
+
+#### How the circuit works
+
+The primary CPU construction is exceptionally simple, in order to keep it as small
+as possible.
+
+The CPU is a load-store stack(like) RISC machine that encodes each of the Intel 4004
+instructions as a sequence of at most 16 micro-ops.
+Therefore, each clock cycle of the circuit performs 1/16th of a 4004 instruction.
+The program maintains a 4-bit counter to keep track the current micro-op that's
+executing, and a 96-bit shift register that holds each of the 6-bit micro-ops
+that correspond to the current instruction.
+
+The program maintains 65536 (2^16) bits of ROM split equally into two 32768-bit banks.
+The first of these stores the program code: up to 4096 (2^12) 8-bit
+Intel 4004 instructions.
+The second bank stores a lookup table mapping each of the 256 possible
+8-bit instructions to a 96-bit micro-op vector encoding the 16 6-bit micro-ops.
+
+The ALU itself is implemented as a 3-deep queue.
+On every clock cycle,
+each micro-op pushes one value to the top of the queue, and the last value falls off
+the back. (Think of this like a stack machine, but a queue is simpler to wire than a stack.)
+Each micro-op can index into exactly one register,
+and either load its current value to the top of the queue or replace the current register
+with the value with whatever is on the top of the queue.
+Alternatively, each micro-op can perform some computation using the values in the queue.
+
+The register file for the CPU holds 256 twelve-bit ints.
+This might seem somewhat counter-intuitive because the 4004 is a 4-bit machine,
+but consistent patterns are more easily compressed with LZ compression,
+and 12-bit registers are required for the program counter already, so it's cheaper
+to make everything a 12-bit register.
+The first 16 of these registers hold the 16 four-bit general purpose registers for the Intel 4004
+(the upper 8 bits are ignored).
+The next 16 registers hold a few special-purpose registers:
+
+- The 4-bit accumulator
+- The 1-bit carry flag (when an ADD overflows)
+- The 12-bit program program counter
+- Three 12-bit program counter stack registers for call/return support
+- A 8-bit RAM pointer indicating which RAM address we want to update
+- A 12-bit temporary register for holding some intermediate state
+
+The remaining 224 registers hold RAM values of the Intel 4002, discussed later.
+
+To keep the micro-ops space-efficient, they are 6-bits each.
+Micro-ops that begin with a 1 index into 32 different possible queue-operation.
+The most commonly used micro-ops include operations to
+
+- ADD the top two values on the queue (with a carry of 0, 1, or from the carry flag)
+- INCREMENT the top value of the queue
+- DOUBLE the top value of the queue
+- NEGATE the top value of the queue
+- MUX to conditionally keep either the top or second-to-top value.
+- BIT_SHIFT_RIGHT_4 the top value on the queue
+- BIT_SHIFT_LEFT_4 the top value on the queue
+
+Micro-ops that begin with a 01 read from a register and load it into the register file,
+and micro-ops that start with 00 take the top value of the queue and write it to a register.
+Because this leaves just 4-bits to index into a register file with 256 entries,
+these 4-bits actually index into a lookup table that decide how the register should be
+located. Some of these ops, for example, allow for
+
+- Direct indexing to 8 special purpose registers ACC/CARRY/TMP/RAM_ADDR/PC/PC1/PC2/PC3
+- Direct indexing into the general-purpose register specified in the low-4 bits of the 4004 instruction
+- Direct into the next register after the one specified in the low-4 bits of the 4004 instruction
+- Indirect indexing that loads whatever is pointed to by the special RAM_ADDR instruction
+
+The rest of the ALU then just consists of a few multiplexers to decide how to route the data
+around either loading from the RAM to storing the queue, loading from the queue and storing to the queue,
+or loading from the queue and storing to RAM.
+
+
+##### Defining the circuit
+
+The main circuit is built using a simple HDL language.
+It's written as a python DSL (sorry!) so that I can take advantage of some meta-programming and
+operator overloading to make the construction easy. I'll omit the description of the
+HDL compiler here, but it's just a few hundred lines of fairly straightforward code that
+works about as you would expect.
+
+Here, for example, is the implementation of a simple ripple-carry full-adder:
+
+```
+ @make_circuit("full adder")
+ def full_add(in1, in2, in3):
+ low1 = in1^in2
+ low2 = low1^in3
+ high = (in1 & in2) | (low1 & in3)
+ return low2, high
+
+ @make_circuit("add_16")
+ def add(in1, in2, carry):
+ out = []
+ for a,b in zip(in1.bits, in2.bits):
+ c, carry = full_add(a, b, carry)
+ out.append(c)
+ return Bits(out)
+```
+
+When the HDL compiler lowers this when adding two four-bit numbers,
+you end up with the following circuit (assuming that the arguments are
+passed in v[0..3], v[4..7], and v[8].
+
+
+```
+ v[9] = v[8] | v[8];
+ v[10] = v[0] ^ v[4];
+ v[11] = v[10] ^ v[9];
+ v[12] = v[0] & v[4];
+ v[13] = v[10] & v[9];
+ v[14] = v[12] | v[13];
+ v[15] = v[1] ^ v[5];
+ v[16] = v[15] ^ v[14];
+ v[17] = v[1] & v[5];
+ v[18] = v[15] & v[14];
+ v[19] = v[17] | v[18];
+ v[20] = v[2] ^ v[6];
+ v[21] = v[20] ^ v[19];
+ v[22] = v[2] & v[6];
+ v[23] = v[20] & v[19];
+ v[24] = v[22] | v[23];
+ v[25] = v[3] ^ v[7];
+ v[26] = v[25] ^ v[24];
+ v[27] = v[3] & v[7];
+ v[28] = v[25] & v[24];
+ v[29] = v[27] | v[28];
+```
+
+Despite the length here, when compressed this circuit actually is compressed to just this:
+
+```
+ function_1:
+ 4, 200000, 200001 // First XOR (idxs >200000 are argument indexs)
+ 4, 1, 200002 // Second XOR with the prior result and arg2
+ 3, 200000, 200001 // Now compute the AND of the first two args
+ 3, 3, 200002 // And also AND with the third argument
+ 2, 2, 1 // Finally take the OR and return this.
+
+ main:
+
+ // Initialize variables here
+
+ 6, 0, 3, -10, 4, 5 // FUNCTION CALL to the full adder
+ 7, 4, 2, 3, 2, -4, 8 // REPEAT the call to the add routine
+```
+
+Notice the value of the function call and REPEAT together allow for much more efficient
+compression than would otherwise be possible.
+
+
+The above full adder is fairly standard compared to what you might see in any other HDL language.
+Things become a tiny bit more complicated when you need to introduce cyclic dependencies
+in the graph. For this, you need to explicitly construct a Signal to loop things.
+Let me give you an example for this:
+
+```
+ def dff_half(inp, clock):
+ q = Signal()
+ out = mux(clock, iftrue=inp, iffalse=q)
+ q.connect(out)
+ return q
+
+ def dff(inp, clock, n=1):
+ q = dff_half(inp, ~clock, n)
+ q = dff_half(q, clock, n)
+ return q
+```
+
+As you're possibly aware, a D-flip-flop is one of the most basic gates that allows
+you to store a single bit of state. Without something like a flip-flop, the signal in a
+circuit would only be able to run from left to right and then reach some steady state;
+the flip-flop allows us to introduce recurrences that actually make the computer Turing complete.
+At the most basic level, all a flip-flop does is multiplex
+to set the *next* state either as the currently held state, or whatever new input is
+being passed in.
+
+The rest of the circuit is constructed in a similar manner.
+
+
+###### Clock
+
+Unlike a real chip that has to use some physical crystal or something to get
+a reliable clock signal, I can just create a long chain of Signals, each of
+which is connected to the next, and then put a NOT gate at the end. That is, this
+looks basically like an inverting ring oscillator but it's much simpler. That looks
+something like this:
+
+```
+ def clock(latency):
+ out = Signal()
+ inv = ~out
+ delays = [Signal() for _ in range(latency)][::-1]
+ for a,b in zip(delays,delays[1:]):
+ b.connect(a)
+ delays[0].connect(inv)
+ out.connect(delays[-1])
+ return out
+```
+
+There's some additional complexity here because if you put the gates directly in order
+(a -> b -> c -> d -> a) then the circuit evaluating it would take each of these operations in order
+and it would all happen on the first pass through the circuit.
+This is because the circuit just scans linearly top-to-bottom and makes updates as soon as
+they're ready, so once the value of b was updated, c would then immediately be updated as well.
+This would result in a clock cycle of just one!
+By inverting the order so it goes (a <- b <- c <- d <- a) we can make sure that exactly
+one of these updates happens on each run through the circuit.
+
+
+###### Program ROM
+
+Representing the ROM is entirely straightforward: it's just a big giant
+lookup table in a binary-tree structure built out of 2-bit MUXes.
+
+Specifically, it's defined like this:
+
+```
+ def rom(address, choices):
+ if len(choices[0]) == 1:
+ return [x[0] for x in choices]
+
+ return rom(Bits(address.value[1:]), [[mux(address.value[0], b, a)
+ for a,b in zip(x[::2], x[1::2])] for x in choices])
+```
+
+There isn't anything fancy about this, but it's very important to
+define things exactly this way in order to make sure we can compress
+it efficiently.
+This description, coming in at just a hundred bytes of compressed space,
+is what takes up over half of the circuit and requires a hundred thousand gates to implement.
+But none of that matters---we're going to minimize total program source length.
+
+After we've built the ROM once to hold the program source, it's actually completely free
+to build a second ROM to hold the microcode for each of the instructions, because
+we can use the same structure. And LZ compression means we just need to say
+"go repeat that ROM file again".
+
+
+###### Register File
+
+The register file is probably the most complicated component of the CPU. To begin,
+the circuit implement a function `to_onehot` that takes an 8-bit integer and outputs
+a 256-bit output that's zero everywhere except the index of the 8-bit integer.
+(So, for example `to_onehot(00000010)` will return `[0 0 1 0 0 ... 0 0 0]`.
+
+
+```
+ def to_onehot(reg):
+ out = []
+ counter = Bits([const(0) for _ in range(len(reg.value))])
+
+ # 16 NOPs here for ... reasons.
+ [const(0) for _ in range(16)]
+
+ def eq_by_inc(counter):
+ return inc(counter), ~any_set(counter^reg)
+
+ for i in range(256):
+ counter, to_return = eq_by_inc(counter)
+ out.append(to_return)
+
+ return Bits(out)
+```
+
+Notice again that this program is aiming for the minimum description length not
+the minimum number of gates.
+Putting 256 full adders here, each of which could be an incrementer,
+which aren't even necessary because you could just do this with a
+few MUXes, may seem wasteful.
+But the reason I'm doing it this way is that I already need an adder circuit,
+so re-using it is basically free, and so why build an incrementer when
+you can just re-use the adder for free. And why build any new multiplexing
+stuff when you can just repeat 256 adders mostly for free.
+LZ compression really does give us so many opportunities for optimization.
+
+
+The next step is to build a single register
+
+```
+ def one_reg(clock, enable_write, do_write, data, output1):
+ out = dff(data, clock & enable_write & do_write, 12)
+ return out
+```
+
+And finally, we're done! We can write our register file:
+
+```
+ def regfile(clock, which_reg, data, enable_reg_write):
+ mem = []
+ mem_set = []
+ reg_onehot = to_onehot(which_reg).value
+
+ for i in range(256):
+ out = one_reg(clock, enable_reg_write, reg_onehot[i], data)
+ mem.append(out)
+
+ return mem
+```
+
+###### The ALU
+
+The final component of the circuit is the ALU. For this we need the actual
+queue where the operations will take place, defined like this:
+
+```
+ queue_in = Bits([Signal() for _ in range(12)])
+
+ queue = [queue_in]
+
+ spacer = Bits([Signal() for _ in range(12)])
+
+ for _ in range(3):
+ clock_inner = clock_inner.clone()
+ queue.append(dff(queue[-1], clock_inner, 12))
+```
+
+The spacer here is again an example of how wasting space actually saves space.
+Because each iteration of the loop, when unrolled, has a d-flip-flop that refers
+to gates that were defined exactly 24 gates above, by placing a 12-gate "nop"
+we can make the circuit compress better.
+
+Finally, we have to define the actual lookup table that the ALU uses.
+This is the least-clean part of the circuit, and is truly awful to look at.
+It just takes each of the different possible results we might want, and
+extracts out the correct one. See, I'll show you:
+
+```
+ output_table = [
+ zero,
+ Bits([alu_op.value[0]^x for x in queue_a]),
+
+ add_result, add_result,
+
+ Bits(queue_b.value[4:8] + [const(0)]*8).clone(),
+ mux(u_op.value[0], daa, Bits(kbp(*queue_a.value[:4])+[const(0)]*8).clone()),
+
+ mux_result, mux_result,
+
+ Bits(queue_a.value[:8] + addr.value[8:]).clone(),
+ from_rom,
+
+ full_jcn, full_jcn,
+
+ queue_a_plus,
+ queue_a_plus,
+
+ add_two, add_two
+ ]
+
+ alu_output = Bits([do_mux16(Bits(u_op.value[1:5]),
+ *[x.value[i] for x in output_table]) for i in range(12)])
+```
+
+
+###### The Input/Output circuitry
+
+The last piece of the circuit is the part that handles input and output. This is
+relatively simple, all things considered. It mainly consists of a two 4003 shift
+registers to handle the printing, and a 4003 shifter to handle the keyboard reading.
+
+But first, it's necessary to talk about the part of the circuitry that enables I/O
+passing back and forth data between the C program and the circuit. Here's the
+implementation of the special operations as defined in the circuit:
+
+```
+ # First, we need to figure out if we want to TRAP.
+ # TRAP is a special u-op that can be identified with this bitmask.
+ trap_possible = (u_op.value[5] & u_op.value[4] & ~u_op.value[3] & u_op.value[1])
+
+ # Next, we need to figure out the reason. Is it trap because of RAM/ROM read/write?
+ trap_ramrom = u_op.value[2] | u_op.value[0]
+
+ # Alternatively, maybe it's a trap because we're reading the TEST pin via JCN.
+ trap_jcn_flag_set = insn_stream.value[0]
+
+ # The C program will now directly inspect these values.
+ # A trap acutally happens if we have the right u-op, and one of these conditions
+ trap = trap_possible & (trap_ramrom | trap_jcn_flag_set)
+
+ # Is it a write? or a read?
+ trap_is_write = u_op.value[2].clone()
+
+ # Is it the ram? or the rom?
+ trap_rom_or_ram = u_op.value[0].clone()
+
+ # which register are we referencing in the trap?
+ which_reg = Bits(regs[RAM_REG].value[4:8])
+
+ # And what's the data value?
+ data = Bits(acc.value[3:4]).clone()
+
+ # The C program will finally write here, with the value of any button.
+ pressed_button = Bits([Signal() for _ in range(12)])
+ pressed_button.connect(pressed_button)
+```
+
+The way this works is that the circuit will pull the `trap` variable high to
+indicate that it wants to do something. Then, as shown earlier, the C program
+will actually handle whatever needs to be done.
+Finally, after this returns back, it's the circuit's turn to handle the input
+from the C program. This happens as follows:
+
+
+The printer shifter is just a completely naive implementation connected directly
+to the ROM output port:
+
+```
+ printer_clock.connect(rom_output.value[2])
+ keyboard_clock.connect(rom_output.value[0])
+
+ for _ in range(21):
+ printer_clock = printer_clock.clone()
+ printer_shift.append(dff(printer_shift[-1], printer_clock))
+ printer_shift = Bits(printer_shift[1:]).clone()
+```
+
+This holds the hammers that are going to be struck when the corresponding command
+is given, and when that happens, they update en-mass a bunch of flip-flops that
+hold the current value that's going to be printed to stdout. This is the actual
+logic that computes the gates that was already shown above.
+
+```
+ which_print
+ for i in range(20):
+ out = dff_circ(store_print_row, printer_shift.value[i])
+ which_print.append(out)
+
+ which_print = Bits(sum([x.value for x in which_print], []))
+```
+
+The keyboard handling actually cheats, and doesn't use a 4003 at all. Instead,
+because the Busicom calculator guarantees that only one bit is active at a time,
+it just stores the location of the active bit, and then whenever the first bit
+of rom_output is cleared it reset the row back to zero. This saves a bunch
+of space in the circuit without breaking any functionality (for the Busicom).
+
+```
+ keyboard_counter = Bits([Signal() for _ in range(12)])
+ keyboard_counter.connect(dff(mux(rom_output.value[1],
+ inc(keyboard_counter),
+ Bits([zero]*12)),
+ keyboard_clock,
+ 12))
+```
+
+
+##### The Micro-Op Table
+
+The final component of the circuit is the micro-op lookup table that defines how
+each of the instructions should be implemented. Most instructions are relatively
+straightforward to implement. The simplest instructions are trivial. For example,
+to implement the LDM instruction that takes the low-4 bits of the instruction and
+sets the accumulator to that value it decodes in this way.
+
+```
+ LOAD IMMEDIATE_4 // load the contents of the low-4 bits of the 4004 instruction
+ STORE ACC // and directly store this into the accumulator register
+ LOAD PC // load the 12-bit program counter to the queue
+ INC // increment this value on the top of the stack
+ STORE PC // store the updated program counter
+```
+
+Notice that the last three micro-ops actually tell the CPU how to advance to the
+next instruction. Most of the time this is obvious, but for jump and call instructions,
+this allows the program to handle them specially without any extra circuitry. I will
+show an example of that briefly, but first let me show another example of a slightly
+more complex op. Here, for example, is the encoding of the instruction IAC that
+increments the contents of the accumulator (and then writes an overflow to
+the carry flag).
+
+```
+ LOAD ACC // push the accumulator onto the front of the queue
+ INC // increment the top value on front of the queue
+ STORE ACC // store the top value on the queue to the accumulator
+ SHIFT_RIGHT_4 // shift the top of the stack right by 4 bits (to get the high bit)
+ STORE CARRY // store that shifted value into the carry flag
+ LOAD PC // load the 12-bit program counter to the queue
+ INC // increment this value on the top of the stack
+ STORE PC // store the updated program counter
+```
+
+Now let's show some complicated instructions. Here's the definition of the instruction JUN
+(a direct jump), for example. First its important to understand that this function
+is encoded as `0100AAAA BBBBBBBB`, where `0100` is the op-code to jump, and then
+the value AAAABBBBBBBB is the 12-bit jump target. Because instructions are 8 bits,
+this is actually represented with AAAA as the low four bits of the original
+instruction, and BBBBBBBB as the entire next instruction.
+
+```
+ LOAD PC // load the current program counter address
+ INC // increment it so we can look at the next byte
+ STORE PC // and store it so that loads now refer to the next instruction
+ LOAD IMMEDIATE_4 // load the four lower bits of the *original* instruction
+ SHIFTLEFT4 // shift left 4 times
+ SHIFTLEFT4 // shift left 4 times again, for a total of 8
+ LOAD IMMEDIATE_8 // load the low 8 bits of the jump target
+ ADD // compute (low-4 of instruction) << 8 + (low-8 of next byte)
+ STORE_PC // this is the jump target, go there
+```
+
+Other instructions are even more complicated than this. For example, the JMS
+instruction is what we'd think of now as a CALL, but instead of pushing the
+return address to a stack in memory (what memory??) the 4004 has a built-in
+4-deep call stack in registers. So the JMS instruction has to handle the stack
+operations directly
+
+```
+ LOAD PC2 // Start the stack shift,
+ STORE PC3 // moving PC2 to PC3.
+ LOAD PC1 // Continue the stack shift,
+ STORE PC2 // moving PC1 to PC2.
+ LOAD PC // Now load the current PC
+ INC // increment to get the next instruction
+ STORE PC // and store it into the PC
+ STORE PC1 // and also store it onto the PC stack
+ LOAD IMM // First load the low nibble from the instruction (i.e., *PC)
+ SHIFTLEFT4 // Shift this value left 4 bits
+ SHIFTLEFT4 // And then shift another 4 bits so it's now *PC << 8
+ LOAD IMMBYTE // Now load the following byte *(PC+1)
+ ADD // Add (*PC << 8) + *(PC+1)
+ STORE PC // And finally store this value into the PC
+```
+
+But perhaps the most complicated instruction is the FIN instruction,
+encoded as 0011RRR0, which fetches the values in ROM pointed to by the
+the 0th general purpose register (for the low-4 bits) and the first
+(for the high-4 bits), and stores that into the register pair RRR0
+(for the low-4 bits of the word) and RRR1 (for the high-4 bits of the word).
+Here's the encoding of this instruction:
+
+```
+ LOAD PC // Load the PC to the queue
+ STORE TMP // Save it aside so that we can come back later
+ LOAD R1 // Load contents of general purpose register 0 to the queue
+ LOAD R0 // And now load the contents of register 1 to the queue
+ MAKEBYTE // A special instruction that computes queue[0]<<4 + queue[1]
+ PCHIGH // Another special instruction that computes (PC&F00) | queue[0]
+ // At this point, the top of the queue has the new address to load
+ STORE PC // Actually write this value to the top of the queue
+ LOAD IMMBYTE // Load whatever's pointed to by the PC to the queue
+ STORE REG1 // Store the low 4 bits to the register RRR1
+ SHIFTRIGHT4 // Shift the value on the queue to the right 4 bits
+ STORE REG // And finally store this to the value to the register RRR0
+ LOAD PC // load the 12-bit program counter to the queue
+ INC // increment this value on the top of the stack
+ STORE PC // store the updated program counter
+```
+
+And with that, we've completed our tour of the circuitry too.
+There are other instructions, but they are fairly obvious.
+And there are other tricks in the circuitry,
+but we're getting quite long already. So let's just call that a wrap.
+
+
+#### Limitations
+
+To the best of my knowledge, this is a nearly feature-complete implementation of
+the Intel 4004 and the original Busicom calculator should run more or less exactly
+as it did fifty years ago.
+
+There are a few limitations with the CPU that should never matter in practice:
+
+- I didn't implement the DCL instruction. This instruction allows you to switch
+ I/O when you have more than one different devices attached to the ROM gates.
+ But the Busicom ROM does not call this instruction and so it is omitted for space.
+- The 4004 only can listen to ROM port 0; again not a problem for the original ROM,
+ but other ROM files may not run correctly if they use more than this.
+- If you type numbers in STDIN too fast (faster than 10 numbers per minute or so)
+ the processor won't be able to keep up with you. So please be patient.
+
+
+#### Sample programs
+
+
+##### fib.bin
+
+I also wrote two demo programs that make it easier to understand how to write
+programs for the 4004 and corresponding I/O hardware.
+
+The first of these demonstrates the output functionality of the chip, and is
+a program that prints Fibonacci numbers. The main functionality to look at here
+is how it aligns the program to the printer drum, and decides when to fire the
+printer heads.
+
+
+##### adder.bin
+
+The second program is a simple extension of above program that also does minimal
+handling of user input. The functionality to look at here is how the program
+continuously scans through the potential pressed keys looking to see if anything
+has been pressed, and if it has, adds the pressed key to the running counter.
+
+
+##### redacted.bin
+
+This is the raw, un-modified ROM that was run on the original calculator.
+I renamed the ROM redacted.rom to avoid spoilers.
+
+
+
+#### redacted.bin Key Bindings
+
+
+The calculator has mostly typical keybindings for entering digits 0..9 and
+for computing addition `+`, multiplication `+`, subtraction `-`, and division `/`.
+Then there are special keys that perform the other calculator functions:
+
+- M acts like M+ and adds to the memory
+- m acts like m- and subtracts from the memory
+- r acts like RM and is the recall memory function
+- o is a special sub-total function that has various uses
+- S computes the square root function
+
+
+#### Example calculations
+
+You might want to try a few of these example calculations. On my computer these
+take somewhere between 3 and 10 minutes to complete.
+
+- Calculate 2+3: `2+3+=` (should return 5)
+- Calculate 85*72: `85*72=` (should return 6120)
+- Calculate 85*72*4: `85*72*o4=" (should return 24480)
+- Calculate 85/72: `85/72=` (should return 1.1805555555555)
+- Use the memory functions `5M4Mr` (should return 9)
+- Memory with multiply `12*5=M3Mr` (should return 63)
+- Calculate square roots: `2S` (should return 1.4142135623730)
+- Use the sub-totals: `1+2+o5+o=` (should return 8)
+
+Longer calculations can be performed but should be done without the use of echo,
+because the Busicom ROM only can hold only a limited number of buffered
+keystrokes at a time. Care must be taken to not get unlucky when entering
+keystrokes manually or else the wrong calculation will be performed. (This is
+not a bug in the above C program, but a bug in the original ROM, which had
+subtle timing race conditions that in practice were not real problems because
+the calculator ran several thousand times faster than this emulated version does.)
+
+
+
diff --git a/2024/carlini/adder.bin b/2024/carlini/adder.bin
new file mode 100644
index 000000000..4e0830e78
Binary files /dev/null and b/2024/carlini/adder.bin differ
diff --git a/2024/carlini/fib.bin b/2024/carlini/fib.bin
new file mode 100644
index 000000000..1a7f6df02
Binary files /dev/null and b/2024/carlini/fib.bin differ
diff --git a/2024/carlini/index.html b/2024/carlini/index.html
new file mode 100644
index 000000000..a7d560136
--- /dev/null
+++ b/2024/carlini/index.html
@@ -0,0 +1,1601 @@
+
+
+
+
+
+
+
+
+
+
+
+
+2024/carlini - Prize in perfect timing
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
What impressed us the most is not the sheer number of various compression
+and circuit simulation algorithms embedded into the entry, but the fact
+that it simulated the drum printer.
+
If the Busicom calculator had 7-segment indicators instead, this entry
+might not have won. ;-)
+
Reverse-engineering the circuit encoding format could be a fun exercise to
+make a minimalistic general purpose circuit simulator out of this entry.
+
The IOCCC has seen a number of winning entries that allow code designed to
+run on early Intel processors, however none of them emulate a processor as
+early as the Intel 4004.
+Launched in 1971, the 4004 was the core of the first commercially marketed
+microprocessor chipset.
+
On speed
+
One MUST be patient while the program is running some *.bin file.
+
adder.bin
+
./prog adder.bin
+
This prints the 4 digit accumulator value about once every 32 seconds or so.
+
When you press enter digits (0 thru 9), followed by a return key, the value
+is added to the 4 digit accumulator and is printed on the next (32+ second) cycle.
+
This program is on an infinite loop: abort, using CTRL-C, to exit.
+
fib.bin
+
./prog fib.bin
+
This program it an infinite loop to print the Fibonacci sequence in base 10.
+The next Fibonacci sequence value is printed about every 17 seconds or so.
+
If you are REALLY PATIENT you will discover that the Fibonacci sequence
+values are actually printed in decimal mod 10000.
+
This program is on an infinite loop: abort, using CTRL-C, to exit.
+
redacted.bin
+
This program emulates the original Busicom 141-pf calculator.
+
This calculator is only for the EXTREMELY PATIENT person who is willing
+to wait about 75 seconds between operations.
This program is on an infinite loop: abort, using CTRL-C, to exit.
+
Author’s remarks:
+
An Intel 4004
+
The Intel 4004, one of the first microprocessors, celebrated its 50th anniversary in 2021.
+To commemorate this (and as a submission to IOCCC 2021^H2^H3^H4^H5), this program
+is a feature-complete 4004 emulator that’s capable of emulating the original
+Busicom 141-pf calculator ROM—the application for which the 4004 was originally designed.
+
To make things exciting, this program doesn’t emulate the 4004 the “normal” way.
+Instead, this program is actually just a logic gate simulator, with the entire 4004
+encoded as a circuit that’s then emulated.
+And because we’re 50 years in the future, this gate-level emulated calculator
+runs at a few hundred instructions per second which
+is actually fast enough to be usable—just as long as you’re not in a hurry.
+
A very brief primer on the Busicom 141-pf and Intel 4004
+
The Intel 4004 is an exceptionally simple CPU by modern standards.
+It is a 4-bit processor,
+with 16 general purpose registers.
+There are a total of just 45 instructions, and many of them are nearly identical to others,
+so in practice there are more like only 20 unique instructions.
+It’s accumulator-based, which means that almost all instructions either operate on a special 4-bit accumulator,
+or load data into the accumulator or transfer it out.
+And the program counter can address up to 12 bits of ROM.
+All in, this makes it one of the simpler instruction sets out in the world,
+which makes sense given its age.
+
You can attach three other chips to the 4004 CPU that provide:
+
+
ROM, via an Intel 4001: This stores the program code to be executed, or any other read-only data.
+
RAM, via an Intel 4002: This gives additional storage of more than just the 4*16 bits from the registers.
+
A shift register, via an Intel 4003, to temporarily hold a queue of data which can be attached to physical hardware to help manage I/O.
+
+
The 4004 was originally built for use in the Busicom 141-pf calculator.
+While initially the 4004 was going to be application-specific just to make the calculator possible,
+some forward looking engineers at Intel decided to build a general-purpose
+chip that could perform arbitrary calculations, and then just program the chip
+to be a calculator. And thus was born the general-purpose microprocessor.
+
The Busicom calculator itself is a fairly simple device.
+It has an 8x4 keypad the operator can use to enter numbers or perform numerical
+calculations,
+and an output tape on which the result of the calculation is printed.
+The keypad is simple and looks familiar to any calculator today.
+But the output works through an esoteric (by today’s standards) mechanism.
+A spinning print-drum rotates continuously above a paper tape;
+when the calculator wishes to print a number, it strikes hammers from one of the 18 columns
+at the exact moment the print drum has the desired number above the paper tape,
+and then advances the tape to be visible to the operator.
+
Overall structure of the program
+
The program is split, roughly, into three distinct components:
+
+
First, it takes a compressed string and decompresses it to recover a circuit that,
+when executed, emulates the Intel 4004 (and a few Intel 4001s, 4002s, and 4003s).
+As part of this process, the program inserts the provided program ROM from argv[1] into the circuit.
+
Then, the program actually emulates the decompressed circuit by computing the output of each gate
+in a loop, effectively running the CPU and associated RAM/ROM chips. (With a few associated tricks
+to make things run fast.)
+
Finally, the program simulates the original calculator hardware and handles converting the input
+text from ascii text passed via stdin to the original hardware keyboard presses, and also
+converting the shift register causing hammers to strike paper tape back to ascii outputs.
+
+
The remainder of this section documents the implementation of each of these three components.
+Here’s a small visual to show what’s going on.
+
│ │
+ │ │ Compressed circuit (hard-coded), and ROM (via argv[1])
+ ▼ ▼
+ ┌──────────────┐
+ │ Decompress │ via LZ decompression; arithmetic encoding; and special circuit-compression
+ └──────────────┘
+ │
+ │ gate-level description (~200 k gates)
+ ▼
+ ┌──────────────┐
+ │ Emulation │ a simple loop that re-calculates each gate based on its inputs
+ └──────────────┘
+ │ ▲
+ │ │ if circuit indicates that I/O is necessary
+ ▼ │
+ ┌──────────────┐ (processed to turn ascii to key-presses)
+ │ I/O Handler │ ◀──────────────────────────────────────────── stdin
+ └──────────────┘
+ │ (processed to turn hammer strikes to ascii)
+ └───────────────────────────────────────────────────────▶ stdout
+
Decompressing the compressed circuit representation (part 1)
+
The circuit is compressed twice. At the outer level is an LZ-compressor with arithmetic encoding,
+and then on the inner level is a special-purpose logic-gate compressor that allows creating
+small sub-circuits that can be called.
+
The first part of the decompression is the more straightforward of the two.
+The data is compressed with a special-purpose LZ-style compressor that,
+instead of being bit- or byte-level, operates on unbounded integers as the data stream.
+The LZ decompresser itself pulls bits one at a time from an arithmetic encoded data stream.
+
int output_circuit[big];
+ void lz() {
+ int* ptr = output_circuit;
+ int num_bytes = get_integer();
+
+ while (num_bytes--) {
+ int is_match_op = get_bit();
+ if (is_match_op) {
+ int* ref = ptr - get_integer();
+
+ int copy_len = get_integer() + 1;
+ for (int i = 0; i < copy_len; i++) {
+ *ptr++ = *ref++;
+ }
+ } else {
+ *ptr++ = (1-2*get_bit()) * get_integer();
+ }
+ }
+ }
+
The arithmetic encoding actually just lifts directly from Fabrice Bellard’s wonderful submission to
+IOCCC 2018, as un-obfuscated by Andrew Kensler, with a few tweaks of my own to reduce its length,
+and to cut out some features I don’t need. Briefly, arithmetic encoding keeps a history of
+how likely each bit was to be zero or one, and then uses this prior to inform the decoding of
+the output stream. This version of arithmetic encoding uses a base-1968 encoding abusing the
+fact that IOCCC counts whitespace special, and IOCCC doesn’t allow use of high-bit codepoints.
To read integers out of the datastream, we used a compressed representation that allows
+for arbitrarily-length integers but giving preference to smaller constants than larger ones,
+inspired by Golomb coding. Here’s the implementation of this:
+
int get_integer(int length, int ctx) {
+ int subtract_it = 1<<length;
+ int result_ans = 1;
+ ctx*=99;
+ while (!get_bit(++length+ctx));
+ for (int i = 0; i < length-1; i++) {
+ result_ans = result_ans*2 | get_bit(ctx);
+ }
+ return result_ans - subtract_it;
+ }
+
Decompressing the compressed circuit representation (part 2)
+
Once the first level of decompression is complete, the circuit now appears like a sequence
+of integers that represent the logic gates. It’s now time to actually expand this out to
+the logic gates themselves. Specifically, each logic gate is given a unique
+integer {DIRECT_WIRE, NOT, OR, AND, XOR, MUX} and then this operation is followed by the
+input gates. To improve compressibility, the input gates are expressed in a relative indexing.
+
So, as an example of this, consider the following circuit:
+
v0: NOT v4
+ v1: OR v0, v0
+ v2: OR v1, v1
+ v3: OR v2, v2
+ v4: OR v3, v3
+
This circuit acts like a clock of sorts, with the four entries v0..v3 cycling through between
+0s to 1s. This circuit would be represented with the following sequence:
+
Instead of each gate referencing other gates by their absolute position,
+the program has each gate reference gates based on how many gates backwards (or forwards)
+we should go. So the above circuit becomes the following:
+
0: NOT +4
+ 1: OR -1, -1
+ 2: OR -1, -1
+ 3: OR -1, -1
+ 4: OR -1, -1
+
By storing delta-encoded,
+because most gates reference other gates that are at least fairly nearby,
+we usually only have to store a somewhat smaller constant, reducing the
+size of the circuit by roughly a factor of two.
+And so instead of requiring 18 bits for each reference, it only takes
+7.7 bits. But the much more important win is that now this allows for
+more advanced forms of compression.
+
The major gain is that LZ-compression now can repeat the OR -1, -1 many
+times for free. A more minor gain is a special-purpose repeat handler built in
+to the gate-uncompression. Specifically, the program implements a special instruction
+called REPEAT that means “go back one entry and repeat that one again,
+possibly making a constant change to its value”. This second part is what
+makes repeat valuable even though we already have LZ compression.
+
As an example, suppose we had a circuit that looked like this
v0: v0 & v10
+ REPEAT the above instruction 9 times, incrementing argument 2 by 1
+
Note we’re incrementing argument 2 because after delta-encoding the
+access to the value of gate 10 is what’s changing.
+
The implementation of this is relatively straightforward, and relies on
+modifying the instruction stream as its being processed.
+Specifically, the decode function is defined as below.
+Initially we read off the number of times to run the REPEAT loop,
+then we have a somewhat nasty compressed loop that
+
int* decode(int* data_stream) {
+ int* prev_start;
+ // ...
+ if (*data_stream++ == 6) // repeat
+ // A repeat is a loop that runs the prior instruction a variable number of times,
+ // and also allows for updating the arguments to the prior instruction by a
+ // constant scalar on each step.
+
+ // To implement this, we use some self-modifying code:
+ // 1. Decrement the argument that says how many repeats to do
+ // 2. Adjust the other arguments from the prior instruction as necessary
+ // 3. Go back 2 instructions if the counter is greater than zero.
+ // (on the next iteration of the loop we'll modify the arguments again).
+ int number_of_times_to_duplicate = *data_stream++;
+ num_change = tmp = *data_stream++;
+ if (number_of_times_to_duplicate) {
+ for (int i = 0; i < tmp; i++) {
+ int increment_constant = data_stream[*data_stream++];
+ prev_start[*data_stream++] += increment_constant;
+ }
+ data_stream = prev_start;
+ } else {
+ data_stream += num_change * 2;
+ }
+ }
+ }
+
Finally, there’s one more special code that acts like a function call, and says
+“go copy that small sub-circuit defined somewhere else to here. This behaves
+similarly to repeat. The program defines five of these sub-circuits that are
+used throughout the program; the most important of these being a full adder,
+but also a single register (so it can be duplicated 256 times) and various helper
+circuits.
+
The implementation of the function-call decoding is again fairly simple:
+the program pulls off the function ID to be called, the number of arguments it
+takes, and then sets a global arguments array with these arguments.
+Then, we just jump to the relevant function and start decoding from there.
+(With a tiny twist: because functions can have REPEAT ops, and REPEAT uses
+in-place self-modifying code to work, we have to actually make a complete
+copy of the function and then execute it so that we can call it multiple times
+without breaking REPEAT.)
+
int* decode(int* data_stream) {
+ ...
+ if (*data_stream++ == 7) { // function call
+ // A function call goes and runs a small number of instructions and returns back.
+ // Nested functions aren't possible.
+ // So to call a function, we just set the global arguments buffer with the correct arguments,
+ // write out the data of the function, and then call cluster() on that location.
+
+ int which_function = *data_stream++;
+ int num_args = *data_stream++;
+ for (int i = 0; i < num_args; i++) {
+ arguments[i] = *data_stream++;
+ }
+
+ // Copy to buf the current compressed ops
+ // we'd like to just do a reference,
+ // but if the called function uses loops then they modify the code in-place
+ // so we have to copy before the function call
+ for (int i = 0; i < BIG; i++) {
+ buf[i] = prog_src[i];
+ }
+ decode(buf+functions[which_function]);
+ }
+ }
+
After compression, the entire circuit of 200,000 gates is crammed down to just over 1000
+bytes. How’s that for an efficient compression algorithm?
+
Decompressing the compressed circuit representation (part 3)
+
The final part of decompressing the compressed circuit is to load the program ROM
+from argv[1] and insert it into the circuit. This is relatively simple; the circuit
+contains a big MUX tree that encodes placeholders for the program ROM, and so all
+the code does is directly edit the placeholder variables that will be used to load the ROM
+with the following simple function.
+
// buf contains the program text that is to be inserted into the circuit
+ // gates is the array that has the actual logic gates
+ void fix_const_help(int depth, int writesize) {
+ for (i = 0; i < depth; i++) {
+ for (int j = 0; j < 1<<writesize; j++) {
+ // byte offset*4 is necessary because gates can have up to 3 arguments
+ // and so are represented as [operation], [arg1], [arg2], [arg3]
+ // this ensures we are writing into the proper location each time
+ gates[byte_offset++*4+1] = buf[j]>>i&1;
+ }
+ }
+ }
+
(In an identical manner, this is also how the microcode is written in to the circuit so that each
+instruction can be implemented with the extra simple circuit.)
+
Emulating the instructions
+
The second component of the program is an emulator to actually run each of the (now decompressed)
+AND/OR/NOT/XOR gates that are used as primitive building blocks to implement the circuit.
+This is by far the simplest portion of the circuit, and is just a compressed switch statement
+that selects the command we’re running and does the correct corresponding action. Again,
+the weird compression is necessary to save space.
+
command = insns[ctr*4];
+
+ // Load the potential arguments for this instruction.
+ arg1 = gate_value[insns[ctr*4+1]];
+ arg2 = gate_value[insns[ctr*4+2]];
+ arg3 = gate_value[insns[ctr*4+3]];
+
+ // We have six possible commands REF, NOT, OR, AND, XOR, MUX
+ // Here we're going to evaluate with a series of ternary ops.
+ gate_value[ctr] = command<2 ?
+ arg1^command // either 0 (DIRECT) or 1 (NOT)
+ :
+ // either 2 (OR), 3 (AND), 4 (XOR), or 5 (MUX)
+ command<4 ?
+ command^3 ?
+ arg1|arg2 :
+ arg1&arg2
+ :
+ command^5 ?
+ arg1^arg2 :
+ arg1?arg2:arg3;
+
This loops basically forever until the user gets bored and kills the process.
+
Handling input and output
+
Finally, we need to be able to actually hook this circuit to the outside world.
+Inside the circuit I set aside one “wire” whose only purpose is to
+signal to the outside world that it wants to take some action. Think of this like
+a trap in an operating system, but at the hardware level: whenever the circuit
+wants to take some action in the outside world, it pulls one of the “wires” high
+for a single clock cycle and the C program watches for this to handle the response.
+The entirety of this trap handler is implemented as below, explained in more
+detail as follows.
+
if (gate_value[trap_id]) {
+
+ int is_write = gate_value[trap_id+1];
+ int rom_or_ram = !gate_value[trap_id+2];
+
+ jcn_counter += rom_or_ram & !is_write;
+ if (is_write & rom_or_ram & gate_value[trap_id+3]) {
+ for (int i = 0; i < 18; i++) {
+ int idx = ((i+3)%18-(i>15));
+ putchar(charset[i*18+*(int*)(gate_value+print_uid+idx*21)%18]);
+ }
+ puts("");
+ }
+
+ // Every 128 JCN instructions we should send the next keypress.
+ // 128 is hard-coded in the circuit. Don't change.
+ if (jcn_counter - reset_key_matrix > 128) {
+ reset_key_matrix = jcn_counter;
+ read_or_reset = !read_or_reset;
+ int read_char = read_or_reset ? 0 : charset[325 + getchar()];
+ for (int i = 0; i < 8; i++) {
+ // this is where the circuit expects the input data to be written
+ gate_value[trap_id+8+i] = read_char>>i&1;
+ }
+ }
+
A trap can be for one of two reasons:
+
+
First, it be because the program wants to read some data from the outside world.
+When connected to the Busicom calculator, the 4004 will either want to read any
+key that might be pressed by the user on the input, or will want to read a single
+bit to detect when the spinning printer drum has advanced to the next location.
+
And second, it can be because the program wants to write some data to make a change
+to the outside world. The 4004 uses writes to strike the hammers against the print
+drum, advance the paper tape (a “new line”), and to energize one of the 10 possible
+lines of the keyboard to enable that corresponding line to be read.
+
+
The program contains two compressed lookup tables to enable this functionality.
+First, it remaps the ASCII characters that the C program reads with getchar()
+to (row, column) locations of the corresponding key on the physical keyboard.
+For example, the number 9, 6, and 3 are at location (4,0), (4,1) and (4,2).
+This lookup table encodes each ASCII character into a six bit number, which
+itself is then compressed along with the circuit using the same LZ compression.
+
The program also contains a lookup table to map each of the hammer-strike outputs
+to ASCII characters that can be putchar()’d. This table, if implemented in the naive
+manner, would be fairly straightforward, because each print drum just repeats the
+numbers 0 to 9 in order (two columns of the drum contain special characters).
+To enable a much more efficient lookup, the data is stored permuted according
+to the following permutation {0, 1, 6, 7, 2, 3, 0, 0, 12, 13, 8, 9, 14, 15, 10, 11, 4, 5}.
+
The purpose of permuting the data in this way (and storing some data duplicated! notice
+that 0 is stored several times) is that now we can read it out of memory much more
+concisely, with the following line:
Specifically, for each of the 18 drum locations, we print the character at that drum.
+charset[i*18] offsets us to the correct drum. The remaining constant is where the
+magic happens: circuit_memory is normally an array of uint8; by casting to (int*)
+we can load four values at a time, which as it happens is exactly the number of index
+bits we need. What we get is then an integer like 0x01000101. And it turns out that if
+you multiply this number by 21 and then take the result mod 18, you end up exactly
+being able to index into that permuted ASCII table.
+
(This is just one of the many pieces of the program that has to be implemented
+in convoluted ways to cut down on program length. I’ll try to omit most of the rest
+for brevity.)
+
Now there’s one final question: when to make input available. On the original
+calculator, the print drum was actually spinning and so that set the rate of inputs
+that were pushed to the circuit. But we have no actual spinning drum and so we
+need to decide the rate that input will be passed. Instead of making running
+based on wall-clock time, the C program does something somewhat confusing, and
+tracks the number of conditional jump operations that have been issued.
+Every 128 conditional jumps (JCN’s) that branch on the 4004’s TEST pin, it makes one
+more character of STDIN available to the program. This is the fastest rate
+possible at which the ROM can handle input without dropping characters.
+
Making it go fast(er)
+
The CPU itself has over 200,000 gates (I’ll describe why in detail later—but it’s to
+save space when compressed).
+Now given that we have to loop over every gate 16 times for one tick of the clock,
+and each instruction takes 16 inner clocks of the circuit,
+we’re going to run into a problem.
+If we would like it to run at anything faster than one instruction per second,
+we’ll have to make some changes while still keeping things in our space constraint.
+
As has been said many times before,
+you can’t make computers perform the same amount of work faster.
+You can only make them do less.
+
So the program does just that. Instead of re-calculating every gate on every iteration of the loop,
+it keeps track of which inputs have changed last time, and then only re-calculates the
+gates whose input changed during the prior round.
+This requires that when we first load the circuit off of disk that we build a table in
+memory for which gates depend on which others. In order to minimize space here, this is
+a dense table with shape 200,000 x 70,000 (it’s 70,000 wide because
+there’s exactly one gate—the clock—that 64k other gates depend on).
+
Once we’ve built the table the logic gets somewhat complicated. The program maintains a
+3-deep hierarchical bitmask to indicate how far can be skipped ahead. At each level
+is an array of 64-bit words where each bit corresponds to whether or not there is any
+gate that needs to be updated at the next level “down” in the tree. (So, for example,
+at the lowest level if a bit is 0 anywhere then that gate doesn’t need to be updated;
+at the second level if a bit is 0 then all of the 64 bits below it don’t need to be
+updated, and at the highest level the 64*64 bits below don’t need to be updated.)
+
The logic to actually set the bits that need to be updated is as follows. Initially
+needs_update is set to 0xFFFFFFFFFFFFFFFF and then bits are cleared when gates they
+depend on are changed
+
int num_depends = depends_ctr[ctr];
+ while (num_depends--) {
+ int gate = depends[ctr][num_depends];
+
+ for (int depth = 0; depth < 3; depth++) {
+ needs_update[total_gate_count/64*depth + (gate>>6*-~depth)] &= ~(1L<<(gate>>6*depth)%64);
+ }
+ }
+
This compressed code isn’t that hard to reason about. First we select the right address
+by taking the gate index and dividing by 2^(6*(depth-1)). Then, we select the bit
+address within the word by looking at the remaining bits in the gate. We do this for all
+three depths, and make sure to only ever clear bits, so the needs_update gets sparser
+and sparser as the circuit goes forward.
+
And the corresponding logic to check if we need to process the current
+data is implemented here.
+Again this works by just masking out to check if all of the bits in needs_update are zero,
+and skips if any are set to 1.
+If a bit at the lowest level of the tree is 1 then it skips one gate forward;
+if a bit at the medium level is 1 then it skips 64 gates forward,
+and at the highest level 64*64 gates forward.
+This function looks simple, but there are several
+cases that are all magically handled here in very subtle ways.
+Try to figure out why it’s exactly right!
+
for (int depth = 3; depth-->0; ) {
+ int divide = 1<<6*depth;
+ int gate = ctr/divide;
+
+ unsigned long tmpll = needs_update[total_gate_count/64*depth + gate/64] >> gate%64;
+ while (tmpll&1) {
+ ctr = ctr - ctr%divide + divide;
+ tmpll/=2;
+ gate = 0; // break out of the above loop
+ }
+ }
+
This ends up giving about a 100x-500x performance boost on average, and allows the
+emulated 4004 to run at a few hundred instructions per second, which isn’t all that bad!
+(But even at 100x speed it still takes roughly a minute for the calculator to perform
+the addition of two numbers. Slow, but actually only 60x slower than the original
+calculator that took one second to do the same addition.)
+
And thus concludes how the actual C program itself works. There are a lot more tricks
+going on, but this is hopefully enough detail to understand most of the important pieces.
+
How the circuit works
+
The primary CPU construction is exceptionally simple, in order to keep it as small
+as possible.
+
The CPU is a load-store stack(like) RISC machine that encodes each of the Intel 4004
+instructions as a sequence of at most 16 micro-ops.
+Therefore, each clock cycle of the circuit performs 1/16th of a 4004 instruction.
+The program maintains a 4-bit counter to keep track the current micro-op that’s
+executing, and a 96-bit shift register that holds each of the 6-bit micro-ops
+that correspond to the current instruction.
+
The program maintains 65536 (2^16) bits of ROM split equally into two 32768-bit banks.
+The first of these stores the program code: up to 4096 (2^12) 8-bit
+Intel 4004 instructions.
+The second bank stores a lookup table mapping each of the 256 possible
+8-bit instructions to a 96-bit micro-op vector encoding the 16 6-bit micro-ops.
+
The ALU itself is implemented as a 3-deep queue.
+On every clock cycle,
+each micro-op pushes one value to the top of the queue, and the last value falls off
+the back. (Think of this like a stack machine, but a queue is simpler to wire than a stack.)
+Each micro-op can index into exactly one register,
+and either load its current value to the top of the queue or replace the current register
+with the value with whatever is on the top of the queue.
+Alternatively, each micro-op can perform some computation using the values in the queue.
+
The register file for the CPU holds 256 twelve-bit ints.
+This might seem somewhat counter-intuitive because the 4004 is a 4-bit machine,
+but consistent patterns are more easily compressed with LZ compression,
+and 12-bit registers are required for the program counter already, so it’s cheaper
+to make everything a 12-bit register.
+The first 16 of these registers hold the 16 four-bit general purpose registers for the Intel 4004
+(the upper 8 bits are ignored).
+The next 16 registers hold a few special-purpose registers:
+
+
The 4-bit accumulator
+
The 1-bit carry flag (when an ADD overflows)
+
The 12-bit program program counter
+
Three 12-bit program counter stack registers for call/return support
+
A 8-bit RAM pointer indicating which RAM address we want to update
+
A 12-bit temporary register for holding some intermediate state
+
+
The remaining 224 registers hold RAM values of the Intel 4002, discussed later.
+
To keep the micro-ops space-efficient, they are 6-bits each.
+Micro-ops that begin with a 1 index into 32 different possible queue-operation.
+The most commonly used micro-ops include operations to
+
+
ADD the top two values on the queue (with a carry of 0, 1, or from the carry flag)
+
INCREMENT the top value of the queue
+
DOUBLE the top value of the queue
+
NEGATE the top value of the queue
+
MUX to conditionally keep either the top or second-to-top value.
+
BIT_SHIFT_RIGHT_4 the top value on the queue
+
BIT_SHIFT_LEFT_4 the top value on the queue
+
+
Micro-ops that begin with a 01 read from a register and load it into the register file,
+and micro-ops that start with 00 take the top value of the queue and write it to a register.
+Because this leaves just 4-bits to index into a register file with 256 entries,
+these 4-bits actually index into a lookup table that decide how the register should be
+located. Some of these ops, for example, allow for
+
+
Direct indexing to 8 special purpose registers ACC/CARRY/TMP/RAM_ADDR/PC/PC1/PC2/PC3
+
Direct indexing into the general-purpose register specified in the low-4 bits of the 4004 instruction
+
Direct into the next register after the one specified in the low-4 bits of the 4004 instruction
+
Indirect indexing that loads whatever is pointed to by the special RAM_ADDR instruction
+
+
The rest of the ALU then just consists of a few multiplexers to decide how to route the data
+around either loading from the RAM to storing the queue, loading from the queue and storing to the queue,
+or loading from the queue and storing to RAM.
+
Defining the circuit
+
The main circuit is built using a simple HDL language.
+It’s written as a python DSL (sorry!) so that I can take advantage of some meta-programming and
+operator overloading to make the construction easy. I’ll omit the description of the
+HDL compiler here, but it’s just a few hundred lines of fairly straightforward code that
+works about as you would expect.
+
Here, for example, is the implementation of a simple ripple-carry full-adder:
When the HDL compiler lowers this when adding two four-bit numbers,
+you end up with the following circuit (assuming that the arguments are
+passed in v[0..3], v[4..7], and v[8].
Despite the length here, when compressed this circuit actually is compressed to just this:
+
function_1:
+ 4, 200000, 200001 // First XOR (idxs >200000 are argument indexs)
+ 4, 1, 200002 // Second XOR with the prior result and arg2
+ 3, 200000, 200001 // Now compute the AND of the first two args
+ 3, 3, 200002 // And also AND with the third argument
+ 2, 2, 1 // Finally take the OR and return this.
+
+ main:
+
+ // Initialize variables here
+
+ 6, 0, 3, -10, 4, 5 // FUNCTION CALL to the full adder
+ 7, 4, 2, 3, 2, -4, 8 // REPEAT the call to the add routine
+
Notice the value of the function call and REPEAT together allow for much more efficient
+compression than would otherwise be possible.
+
The above full adder is fairly standard compared to what you might see in any other HDL language.
+Things become a tiny bit more complicated when you need to introduce cyclic dependencies
+in the graph. For this, you need to explicitly construct a Signal to loop things.
+Let me give you an example for this:
As you’re possibly aware, a D-flip-flop is one of the most basic gates that allows
+you to store a single bit of state. Without something like a flip-flop, the signal in a
+circuit would only be able to run from left to right and then reach some steady state;
+the flip-flop allows us to introduce recurrences that actually make the computer Turing complete.
+At the most basic level, all a flip-flop does is multiplex
+to set the next state either as the currently held state, or whatever new input is
+being passed in.
+
The rest of the circuit is constructed in a similar manner.
+
Clock
+
Unlike a real chip that has to use some physical crystal or something to get
+a reliable clock signal, I can just create a long chain of Signals, each of
+which is connected to the next, and then put a NOT gate at the end. That is, this
+looks basically like an inverting ring oscillator but it’s much simpler. That looks
+something like this:
+
def clock(latency):
+ out = Signal()
+ inv = ~out
+ delays = [Signal() for _ in range(latency)][::-1]
+ for a,b in zip(delays,delays[1:]):
+ b.connect(a)
+ delays[0].connect(inv)
+ out.connect(delays[-1])
+ return out
+
There’s some additional complexity here because if you put the gates directly in order
+(a -> b -> c -> d -> a) then the circuit evaluating it would take each of these operations in order
+and it would all happen on the first pass through the circuit.
+This is because the circuit just scans linearly top-to-bottom and makes updates as soon as
+they’re ready, so once the value of b was updated, c would then immediately be updated as well.
+This would result in a clock cycle of just one!
+By inverting the order so it goes (a <- b <- c <- d <- a) we can make sure that exactly
+one of these updates happens on each run through the circuit.
+
Program ROM
+
Representing the ROM is entirely straightforward: it’s just a big giant
+lookup table in a binary-tree structure built out of 2-bit MUXes.
+
Specifically, it’s defined like this:
+
def rom(address, choices):
+ if len(choices[0]) == 1:
+ return [x[0] for x in choices]
+
+ return rom(Bits(address.value[1:]), [[mux(address.value[0], b, a)
+ for a,b in zip(x[::2], x[1::2])] for x in choices])
+
There isn’t anything fancy about this, but it’s very important to
+define things exactly this way in order to make sure we can compress
+it efficiently.
+This description, coming in at just a hundred bytes of compressed space,
+is what takes up over half of the circuit and requires a hundred thousand gates to implement.
+But none of that matters—we’re going to minimize total program source length.
+
After we’ve built the ROM once to hold the program source, it’s actually completely free
+to build a second ROM to hold the microcode for each of the instructions, because
+we can use the same structure. And LZ compression means we just need to say
+“go repeat that ROM file again”.
+
Register File
+
The register file is probably the most complicated component of the CPU. To begin,
+the circuit implement a function to_onehot that takes an 8-bit integer and outputs
+a 256-bit output that’s zero everywhere except the index of the 8-bit integer.
+(So, for example to_onehot(00000010) will return [0 0 1 0 0 ... 0 0 0].
+
def to_onehot(reg):
+ out = []
+ counter = Bits([const(0) for _ in range(len(reg.value))])
+
+ # 16 NOPs here for ... reasons.
+ [const(0) for _ in range(16)]
+
+ def eq_by_inc(counter):
+ return inc(counter), ~any_set(counter^reg)
+
+ for i in range(256):
+ counter, to_return = eq_by_inc(counter)
+ out.append(to_return)
+
+ return Bits(out)
+
Notice again that this program is aiming for the minimum description length not
+the minimum number of gates.
+Putting 256 full adders here, each of which could be an incrementer,
+which aren’t even necessary because you could just do this with a
+few MUXes, may seem wasteful.
+But the reason I’m doing it this way is that I already need an adder circuit,
+so re-using it is basically free, and so why build an incrementer when
+you can just re-use the adder for free. And why build any new multiplexing
+stuff when you can just repeat 256 adders mostly for free.
+LZ compression really does give us so many opportunities for optimization.
+
The next step is to build a single register
+
def one_reg(clock, enable_write, do_write, data, output1):
+ out = dff(data, clock & enable_write & do_write, 12)
+ return out
+
And finally, we’re done! We can write our register file:
+
def regfile(clock, which_reg, data, enable_reg_write):
+ mem = []
+ mem_set = []
+ reg_onehot = to_onehot(which_reg).value
+
+ for i in range(256):
+ out = one_reg(clock, enable_reg_write, reg_onehot[i], data)
+ mem.append(out)
+
+ return mem
+
The ALU
+
The final component of the circuit is the ALU. For this we need the actual
+queue where the operations will take place, defined like this:
+
queue_in = Bits([Signal() for _ in range(12)])
+
+ queue = [queue_in]
+
+ spacer = Bits([Signal() for _ in range(12)])
+
+ for _ in range(3):
+ clock_inner = clock_inner.clone()
+ queue.append(dff(queue[-1], clock_inner, 12))
+
The spacer here is again an example of how wasting space actually saves space.
+Because each iteration of the loop, when unrolled, has a d-flip-flop that refers
+to gates that were defined exactly 24 gates above, by placing a 12-gate “nop”
+we can make the circuit compress better.
+
Finally, we have to define the actual lookup table that the ALU uses.
+This is the least-clean part of the circuit, and is truly awful to look at.
+It just takes each of the different possible results we might want, and
+extracts out the correct one. See, I’ll show you:
+
output_table = [
+ zero,
+ Bits([alu_op.value[0]^x for x in queue_a]),
+
+ add_result, add_result,
+
+ Bits(queue_b.value[4:8] + [const(0)]*8).clone(),
+ mux(u_op.value[0], daa, Bits(kbp(*queue_a.value[:4])+[const(0)]*8).clone()),
+
+ mux_result, mux_result,
+
+ Bits(queue_a.value[:8] + addr.value[8:]).clone(),
+ from_rom,
+
+ full_jcn, full_jcn,
+
+ queue_a_plus,
+ queue_a_plus,
+
+ add_two, add_two
+ ]
+
+ alu_output = Bits([do_mux16(Bits(u_op.value[1:5]),
+ *[x.value[i] for x in output_table]) for i in range(12)])
+
The Input/Output circuitry
+
The last piece of the circuit is the part that handles input and output. This is
+relatively simple, all things considered. It mainly consists of a two 4003 shift
+registers to handle the printing, and a 4003 shifter to handle the keyboard reading.
+
But first, it’s necessary to talk about the part of the circuitry that enables I/O
+passing back and forth data between the C program and the circuit. Here’s the
+implementation of the special operations as defined in the circuit:
+
# First, we need to figure out if we want to TRAP.
+ # TRAP is a special u-op that can be identified with this bitmask.
+ trap_possible = (u_op.value[5] & u_op.value[4] & ~u_op.value[3] & u_op.value[1])
+
+ # Next, we need to figure out the reason. Is it trap because of RAM/ROM read/write?
+ trap_ramrom = u_op.value[2] | u_op.value[0]
+
+ # Alternatively, maybe it's a trap because we're reading the TEST pin via JCN.
+ trap_jcn_flag_set = insn_stream.value[0]
+
+ # The C program will now directly inspect these values.
+ # A trap acutally happens if we have the right u-op, and one of these conditions
+ trap = trap_possible & (trap_ramrom | trap_jcn_flag_set)
+
+ # Is it a write? or a read?
+ trap_is_write = u_op.value[2].clone()
+
+ # Is it the ram? or the rom?
+ trap_rom_or_ram = u_op.value[0].clone()
+
+ # which register are we referencing in the trap?
+ which_reg = Bits(regs[RAM_REG].value[4:8])
+
+ # And what's the data value?
+ data = Bits(acc.value[3:4]).clone()
+
+ # The C program will finally write here, with the value of any button.
+ pressed_button = Bits([Signal() for _ in range(12)])
+ pressed_button.connect(pressed_button)
+
The way this works is that the circuit will pull the trap variable high to
+indicate that it wants to do something. Then, as shown earlier, the C program
+will actually handle whatever needs to be done.
+Finally, after this returns back, it’s the circuit’s turn to handle the input
+from the C program. This happens as follows:
+
The printer shifter is just a completely naive implementation connected directly
+to the ROM output port:
+
printer_clock.connect(rom_output.value[2])
+ keyboard_clock.connect(rom_output.value[0])
+
+ for _ in range(21):
+ printer_clock = printer_clock.clone()
+ printer_shift.append(dff(printer_shift[-1], printer_clock))
+ printer_shift = Bits(printer_shift[1:]).clone()
+
This holds the hammers that are going to be struck when the corresponding command
+is given, and when that happens, they update en-mass a bunch of flip-flops that
+hold the current value that’s going to be printed to stdout. This is the actual
+logic that computes the gates that was already shown above.
+
which_print
+ for i in range(20):
+ out = dff_circ(store_print_row, printer_shift.value[i])
+ which_print.append(out)
+
+ which_print = Bits(sum([x.value for x in which_print], []))
+
The keyboard handling actually cheats, and doesn’t use a 4003 at all. Instead,
+because the Busicom calculator guarantees that only one bit is active at a time,
+it just stores the location of the active bit, and then whenever the first bit
+of rom_output is cleared it reset the row back to zero. This saves a bunch
+of space in the circuit without breaking any functionality (for the Busicom).
+
keyboard_counter = Bits([Signal() for _ in range(12)])
+ keyboard_counter.connect(dff(mux(rom_output.value[1],
+ inc(keyboard_counter),
+ Bits([zero]*12)),
+ keyboard_clock,
+ 12))
+
The Micro-Op Table
+
The final component of the circuit is the micro-op lookup table that defines how
+each of the instructions should be implemented. Most instructions are relatively
+straightforward to implement. The simplest instructions are trivial. For example,
+to implement the LDM instruction that takes the low-4 bits of the instruction and
+sets the accumulator to that value it decodes in this way.
+
LOAD IMMEDIATE_4 // load the contents of the low-4 bits of the 4004 instruction
+ STORE ACC // and directly store this into the accumulator register
+ LOAD PC // load the 12-bit program counter to the queue
+ INC // increment this value on the top of the stack
+ STORE PC // store the updated program counter
+
Notice that the last three micro-ops actually tell the CPU how to advance to the
+next instruction. Most of the time this is obvious, but for jump and call instructions,
+this allows the program to handle them specially without any extra circuitry. I will
+show an example of that briefly, but first let me show another example of a slightly
+more complex op. Here, for example, is the encoding of the instruction IAC that
+increments the contents of the accumulator (and then writes an overflow to
+the carry flag).
+
LOAD ACC // push the accumulator onto the front of the queue
+ INC // increment the top value on front of the queue
+ STORE ACC // store the top value on the queue to the accumulator
+ SHIFT_RIGHT_4 // shift the top of the stack right by 4 bits (to get the high bit)
+ STORE CARRY // store that shifted value into the carry flag
+ LOAD PC // load the 12-bit program counter to the queue
+ INC // increment this value on the top of the stack
+ STORE PC // store the updated program counter
+
Now let’s show some complicated instructions. Here’s the definition of the instruction JUN
+(a direct jump), for example. First its important to understand that this function
+is encoded as 0100AAAA BBBBBBBB, where 0100 is the op-code to jump, and then
+the value AAAABBBBBBBB is the 12-bit jump target. Because instructions are 8 bits,
+this is actually represented with AAAA as the low four bits of the original
+instruction, and BBBBBBBB as the entire next instruction.
+
LOAD PC // load the current program counter address
+ INC // increment it so we can look at the next byte
+ STORE PC // and store it so that loads now refer to the next instruction
+ LOAD IMMEDIATE_4 // load the four lower bits of the *original* instruction
+ SHIFTLEFT4 // shift left 4 times
+ SHIFTLEFT4 // shift left 4 times again, for a total of 8
+ LOAD IMMEDIATE_8 // load the low 8 bits of the jump target
+ ADD // compute (low-4 of instruction) << 8 + (low-8 of next byte)
+ STORE_PC // this is the jump target, go there
+
Other instructions are even more complicated than this. For example, the JMS
+instruction is what we’d think of now as a CALL, but instead of pushing the
+return address to a stack in memory (what memory??) the 4004 has a built-in
+4-deep call stack in registers. So the JMS instruction has to handle the stack
+operations directly
+
LOAD PC2 // Start the stack shift,
+ STORE PC3 // moving PC2 to PC3.
+ LOAD PC1 // Continue the stack shift,
+ STORE PC2 // moving PC1 to PC2.
+ LOAD PC // Now load the current PC
+ INC // increment to get the next instruction
+ STORE PC // and store it into the PC
+ STORE PC1 // and also store it onto the PC stack
+ LOAD IMM // First load the low nibble from the instruction (i.e., *PC)
+ SHIFTLEFT4 // Shift this value left 4 bits
+ SHIFTLEFT4 // And then shift another 4 bits so it's now *PC << 8
+ LOAD IMMBYTE // Now load the following byte *(PC+1)
+ ADD // Add (*PC << 8) + *(PC+1)
+ STORE PC // And finally store this value into the PC
+
But perhaps the most complicated instruction is the FIN instruction,
+encoded as 0011RRR0, which fetches the values in ROM pointed to by the
+the 0th general purpose register (for the low-4 bits) and the first
+(for the high-4 bits), and stores that into the register pair RRR0
+(for the low-4 bits of the word) and RRR1 (for the high-4 bits of the word).
+Here’s the encoding of this instruction:
+
LOAD PC // Load the PC to the queue
+ STORE TMP // Save it aside so that we can come back later
+ LOAD R1 // Load contents of general purpose register 0 to the queue
+ LOAD R0 // And now load the contents of register 1 to the queue
+ MAKEBYTE // A special instruction that computes queue[0]<<4 + queue[1]
+ PCHIGH // Another special instruction that computes (PC&F00) | queue[0]
+ // At this point, the top of the queue has the new address to load
+ STORE PC // Actually write this value to the top of the queue
+ LOAD IMMBYTE // Load whatever's pointed to by the PC to the queue
+ STORE REG1 // Store the low 4 bits to the register RRR1
+ SHIFTRIGHT4 // Shift the value on the queue to the right 4 bits
+ STORE REG // And finally store this to the value to the register RRR0
+ LOAD PC // load the 12-bit program counter to the queue
+ INC // increment this value on the top of the stack
+ STORE PC // store the updated program counter
+
And with that, we’ve completed our tour of the circuitry too.
+There are other instructions, but they are fairly obvious.
+And there are other tricks in the circuitry,
+but we’re getting quite long already. So let’s just call that a wrap.
+
Limitations
+
To the best of my knowledge, this is a nearly feature-complete implementation of
+the Intel 4004 and the original Busicom calculator should run more or less exactly
+as it did fifty years ago.
+
There are a few limitations with the CPU that should never matter in practice:
+
+
I didn’t implement the DCL instruction. This instruction allows you to switch
+I/O when you have more than one different devices attached to the ROM gates.
+But the Busicom ROM does not call this instruction and so it is omitted for space.
+
The 4004 only can listen to ROM port 0; again not a problem for the original ROM,
+but other ROM files may not run correctly if they use more than this.
+
If you type numbers in STDIN too fast (faster than 10 numbers per minute or so)
+the processor won’t be able to keep up with you. So please be patient.
+
+
Sample programs
+
fib.bin
+
I also wrote two demo programs that make it easier to understand how to write
+programs for the 4004 and corresponding I/O hardware.
+
The first of these demonstrates the output functionality of the chip, and is
+a program that prints Fibonacci numbers. The main functionality to look at here
+is how it aligns the program to the printer drum, and decides when to fire the
+printer heads.
+
adder.bin
+
The second program is a simple extension of above program that also does minimal
+handling of user input. The functionality to look at here is how the program
+continuously scans through the potential pressed keys looking to see if anything
+has been pressed, and if it has, adds the pressed key to the running counter.
+
redacted.bin
+
This is the raw, un-modified ROM that was run on the original calculator.
+I renamed the ROM redacted.rom to avoid spoilers.
+
+
redacted.bin Key Bindings
+
+
The calculator has mostly typical keybindings for entering digits 0..9 and
+for computing addition +, multiplication +, subtraction -, and division /.
+Then there are special keys that perform the other calculator functions:
+
+
M acts like M+ and adds to the memory
+
m acts like m- and subtracts from the memory
+
r acts like RM and is the recall memory function
+
o is a special sub-total function that has various uses
+
S computes the square root function
+
+
Example calculations
+
You might want to try a few of these example calculations. On my computer these
+take somewhere between 3 and 10 minutes to complete.
Longer calculations can be performed but should be done without the use of echo,
+because the Busicom ROM only can hold only a limited number of buffered
+keystrokes at a time. Care must be taken to not get unlucky when entering
+keystrokes manually or else the wrong calculation will be performed. (This is
+not a bug in the above C program, but a bug in the original ROM, which had
+subtle timing race conditions that in practice were not real problems because
+the calculator ran several thousand times faster than this emulated version does.)
Name: codemeow
+Location: KG - Kyrgyz Republic (Kyrgyzstan)
+
+
+
+
+
+
+
+
+
To build:
+
make all
+
To use:
+
./prog
+
Try:
+
./try.sh
+
Judges’ remarks:
+
Sometimes you cannot see the forest thru the trees. But when you
+cannot see the trees thru the forest, it may be because the trees are
+not that tall.
+
This program generates such “mini-trees”: over time and in time of you
+know what we mean. Even though compiled C code might “grow on parse
+trees”, we think this code will also “grow on you” as the C expression
+goes. 😉
+
Author’s remarks:
+
This work is highly inspired by cbonsai program (which was inspired by bonsai.sh, which was inspired by bonsai.js), but this one does not use ncurses and fits into IOCCC rules’ size.
+
Mac OS X
+
A little notice, that you need a terminal that supports ANSI codes and does not reinvent the wheel. I have tested it on iTerm2 and xterm and it sure works, but sometimes detect the windows size wrongly, so best of luck.
+
Warnings
+
The iocccsize tool warns about triggered a word buffer overflow! as I use the double values to stora data. It’s okay, no error here.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/2024/codemeow/prog.c b/2024/codemeow/prog.c
new file mode 100644
index 000000000..6535318a5
--- /dev/null
+++ b/2024/codemeow/prog.c
@@ -0,0 +1,43 @@
+ #define A write
+ extern long A();extern double
+ O[];int a,b,c ,d,v,E=0;extern
+ int nanosleep(); extern int gettimeofday();
+ void w(char*_,long __){A(1,_,__);}unsigned char r(){v^=8;return
+ ++v%8;}int L(int _){return((char*)&O[_])[r()];}void P(int
+ _){w(((char*)(O+14))+ _*2,2);}void S(int _){w(((char*)(O+
+ 16))+_*3,3);}int Q( int _,int __){return
+ _/(*((char*)(O+18)+__))%10+48;}void u(){char _[16];gettimeofday(_,0l);v=
+ _[0];}void g(){unsigned long _;ioctl(1,TIOCGWINSZ,&_);b=_&65535;a=_>>16&65535;
+ c=a/2-12;d= b-4;}void e() {w("\033[",2);}void i (){e();
+ w("1m",2);} void j() {e();w( "0m",2);}void k(){e();w("?1049h",6);e();
+ w("2J",2);e();w("H",1);}void l(int _,int __){e();w((char []){Q(_
+ ,2),Q(_,1), Q(_,0)},3);w(";", 1);_=__;w((char[]){Q(_,2),Q(_,1),
+Q(_,0)},3);w("H",1);}void m(int _){e();P(_);w("m",1);}void n(){for(int _=0;_<
+ 18;_++){l(d+ _/6,c+(_%6)*4);m(((char*)&O)[E++]);w(((char*)&O)+(_
+ <<2)+24,4);}}void o(){char _[16]={0};_[11]=1;nanosleep(_,0l);}void q(int _)
+ {if(_<3)_=2;int x[]={3,0,1,2,0,1};if( r()<2){i(); m(x[_-2]);}else
+ m(x[_+1]);}void p(int _,int __,int
+ x,int*y,int* z){switch (_){case 0:if(x<=2||__<4){*y=L(12);*z=0;}else
+if(x<15){*y=L(12);*z=-(x%2);}else{*y=L(12);*z=L(12)
+/2;}break;case 3:*y=L(12)*1.5;*z=L(13);break;case 4:*y=L(12)/
+ 2;*z=L(12)/2;break;default:*y=L(13)*1.5*(1-(_-1)*2);*z=L(13)/2;
+ break;}} void t(int _,int __,int x,int y){int A,B,C,D = 5;
+ while(y-->0) {C=35-y;p(x,y ,C,&A,&B);
+ if(B>0&&__ >d-2)B--;if((y<3
+ )||(x<3&& y<10))t(_,__,4,
+ y);else if(x==0&&y%3==0)
+ {if(D<=0){D=3;t(_,__,(E++
+ %2)+1,y+5);}}D--;_+=A;__
+ +=B;if(_<0)_=0;if(__
+ <0)__=0 ;l(__,_);
+ q(x);S(x) ;j();o();
+ }}int main() {g();u();
+ k();n();t(c+10,d-1,0,35);
+ l(b,0);}double O[]={
+ 2.5673396845218159e-289,
+ 2.5673475286552589e-289, 5.0789948392480145e-321, 4.4759385888332619e-091,
+ 2.2662500784516041e-085, 6.0135556610268572e-154, 6.0138114327429894e-154,
+ 6.0134700169990685e-154, 6.0134703504179883e-154, 2.5663272049433059e+151,
+ 2.5673651826636406e+151, 6.0134700183229171e-154, 5.3767695968532491e-299,
+ 7.2911289729117876e-304, 6.1257806499948415e-062, 4.6555645993480313e+025,
+ 6.5632629331317560e+299, 7.9070799242303223e-101, 3.2391739187041928e-317};
diff --git a/2024/codemeow/prog.orig.c b/2024/codemeow/prog.orig.c
new file mode 100644
index 000000000..6535318a5
--- /dev/null
+++ b/2024/codemeow/prog.orig.c
@@ -0,0 +1,43 @@
+ #define A write
+ extern long A();extern double
+ O[];int a,b,c ,d,v,E=0;extern
+ int nanosleep(); extern int gettimeofday();
+ void w(char*_,long __){A(1,_,__);}unsigned char r(){v^=8;return
+ ++v%8;}int L(int _){return((char*)&O[_])[r()];}void P(int
+ _){w(((char*)(O+14))+ _*2,2);}void S(int _){w(((char*)(O+
+ 16))+_*3,3);}int Q( int _,int __){return
+ _/(*((char*)(O+18)+__))%10+48;}void u(){char _[16];gettimeofday(_,0l);v=
+ _[0];}void g(){unsigned long _;ioctl(1,TIOCGWINSZ,&_);b=_&65535;a=_>>16&65535;
+ c=a/2-12;d= b-4;}void e() {w("\033[",2);}void i (){e();
+ w("1m",2);} void j() {e();w( "0m",2);}void k(){e();w("?1049h",6);e();
+ w("2J",2);e();w("H",1);}void l(int _,int __){e();w((char []){Q(_
+ ,2),Q(_,1), Q(_,0)},3);w(";", 1);_=__;w((char[]){Q(_,2),Q(_,1),
+Q(_,0)},3);w("H",1);}void m(int _){e();P(_);w("m",1);}void n(){for(int _=0;_<
+ 18;_++){l(d+ _/6,c+(_%6)*4);m(((char*)&O)[E++]);w(((char*)&O)+(_
+ <<2)+24,4);}}void o(){char _[16]={0};_[11]=1;nanosleep(_,0l);}void q(int _)
+ {if(_<3)_=2;int x[]={3,0,1,2,0,1};if( r()<2){i(); m(x[_-2]);}else
+ m(x[_+1]);}void p(int _,int __,int
+ x,int*y,int* z){switch (_){case 0:if(x<=2||__<4){*y=L(12);*z=0;}else
+if(x<15){*y=L(12);*z=-(x%2);}else{*y=L(12);*z=L(12)
+/2;}break;case 3:*y=L(12)*1.5;*z=L(13);break;case 4:*y=L(12)/
+ 2;*z=L(12)/2;break;default:*y=L(13)*1.5*(1-(_-1)*2);*z=L(13)/2;
+ break;}} void t(int _,int __,int x,int y){int A,B,C,D = 5;
+ while(y-->0) {C=35-y;p(x,y ,C,&A,&B);
+ if(B>0&&__ >d-2)B--;if((y<3
+ )||(x<3&& y<10))t(_,__,4,
+ y);else if(x==0&&y%3==0)
+ {if(D<=0){D=3;t(_,__,(E++
+ %2)+1,y+5);}}D--;_+=A;__
+ +=B;if(_<0)_=0;if(__
+ <0)__=0 ;l(__,_);
+ q(x);S(x) ;j();o();
+ }}int main() {g();u();
+ k();n();t(c+10,d-1,0,35);
+ l(b,0);}double O[]={
+ 2.5673396845218159e-289,
+ 2.5673475286552589e-289, 5.0789948392480145e-321, 4.4759385888332619e-091,
+ 2.2662500784516041e-085, 6.0135556610268572e-154, 6.0138114327429894e-154,
+ 6.0134700169990685e-154, 6.0134703504179883e-154, 2.5663272049433059e+151,
+ 2.5673651826636406e+151, 6.0134700183229171e-154, 5.3767695968532491e-299,
+ 7.2911289729117876e-304, 6.1257806499948415e-062, 4.6555645993480313e+025,
+ 6.5632629331317560e+299, 7.9070799242303223e-101, 3.2391739187041928e-317};
diff --git a/2024/codemeow/try.sh b/2024/codemeow/try.sh
new file mode 100755
index 000000000..0c514451e
--- /dev/null
+++ b/2024/codemeow/try.sh
@@ -0,0 +1,44 @@
+#!/usr/bin/env bash
+#
+# try.sh - demonstrate 2024/codemeow
+
+# 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.
+#
+[[ -z "$CC" ]] && CC="cc"
+
+# make sure the program has been built
+#
+make CC="$CC" all >/dev/null || exit 1
+
+# clear the screen
+#
+clear
+
+# try the program
+#
+read -r -n 1 -p "Press any key to run: ./prog: "
+echo 1>&2
+echo 1>&2
+if [ "$(uname -s)" = "Darwin" ]; then
+ # Hello, Apple
+ # Most of the terminals process ANSI-sequences
+ # wrongly without that. Also, apparently, this
+ # affects `ioctl(STDOUT_FILENO, TIOCGWINSZ, &w)`
+ # which can give wrong size (I've observed 80x
+ # 300 in some cases, which contradicts the rea-
+ # lity).
+
+ # I recommend using `iTerm2` or `xterm` and
+ # maximize the terminal window under Mac OS X
+
+ export TERM=vt100
+# export TERM=xterm
+
+#else
+ # It perfectly works under any Linux terminal
+ # No need to prepare anything
+
+fi
+./prog
+echo 1>&2
diff --git a/2024/endoh1/.entry.json b/2024/endoh1/.entry.json
new file mode 100644
index 000000000..cbb43c30c
--- /dev/null
+++ b/2024/endoh1/.entry.json
@@ -0,0 +1,137 @@
+{
+ "no_comment" : "mandatory comment: because comments were removed from the original JSON spec",
+ "entry_JSON_format_version" : "1.2 2024-09-25",
+ "award" : "Prize in patient pointillism",
+ "year" : 2024,
+ "dir" : "endoh1",
+ "entry_id" : "2024_endoh1",
+ "title" : "raytrace-in-macros",
+ "abstract" : "slow ray tracer in CPP",
+ "author_set" : [
+ {
+ "author_handle" : "Yusuke_Endoh"
+ }
+ ],
+ "manifest" : [
+ {
+ "file_path" : "prog.c",
+ "inventory_order" : 20,
+ "OK_to_edit" : true,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "entry source code"
+ },
+ {
+ "file_path" : "Makefile",
+ "inventory_order" : 30,
+ "OK_to_edit" : true,
+ "display_as" : "makefile",
+ "display_via_github" : true,
+ "entry_text" : "entry Makefile"
+ },
+ {
+ "file_path" : "prog.orig.c",
+ "inventory_order" : 50,
+ "OK_to_edit" : false,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "original source code"
+ },
+ {
+ "file_path" : "ref.8.png",
+ "inventory_order" : 100,
+ "OK_to_edit" : true,
+ "display_as" : "image",
+ "display_via_github" : true,
+ "entry_text" : "8x8 image in PNG form"
+ },
+ {
+ "file_path" : "try.sh",
+ "inventory_order" : 100,
+ "OK_to_edit" : true,
+ "display_as" : "shellscript",
+ "display_via_github" : true,
+ "entry_text" : "script to try entry"
+ },
+ {
+ "file_path" : "ref.32.png",
+ "inventory_order" : 110,
+ "OK_to_edit" : true,
+ "display_as" : "image",
+ "display_via_github" : true,
+ "entry_text" : "32x32 image in PNG form"
+ },
+ {
+ "file_path" : "ref.128.png",
+ "inventory_order" : 120,
+ "OK_to_edit" : true,
+ "display_as" : "image",
+ "display_via_github" : true,
+ "entry_text" : "128x128 image in PNG form"
+ },
+ {
+ "file_path" : "ref.512.png",
+ "inventory_order" : 130,
+ "OK_to_edit" : true,
+ "display_as" : "image",
+ "display_via_github" : true,
+ "entry_text" : "512x512 image in PNG form"
+ },
+ {
+ "file_path" : "ref.512-variant.png",
+ "inventory_order" : 140,
+ "OK_to_edit" : true,
+ "display_as" : "image",
+ "display_via_github" : true,
+ "entry_text" : "variant of 512x512 image in PNG form"
+ },
+ {
+ "file_path" : "2024_endoh1.tar.bz2",
+ "inventory_order" : 1415926535,
+ "OK_to_edit" : false,
+ "display_as" : "tbz2",
+ "display_via_github" : false,
+ "entry_text" : "download entry tarball"
+ },
+ {
+ "file_path" : ".entry.json",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : true,
+ "display_as" : "json",
+ "display_via_github" : true,
+ "entry_text" : "entry summary and manifest in JSON"
+ },
+ {
+ "file_path" : ".gitignore",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : true,
+ "display_as" : "gitignore",
+ "display_via_github" : true,
+ "entry_text" : "list of files that should not be committed under git"
+ },
+ {
+ "file_path" : ".path",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : false,
+ "display_as" : "path",
+ "display_via_github" : false,
+ "entry_text" : "directory path from top level directory"
+ },
+ {
+ "file_path" : "README.md",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : true,
+ "display_as" : "markdown",
+ "display_via_github" : true,
+ "entry_text" : "markdown source for this web page"
+ },
+ {
+ "file_path" : "index.html",
+ "inventory_order" : 4294967295,
+ "OK_to_edit" : false,
+ "display_as" : "html",
+ "display_via_github" : false,
+ "entry_text" : "this web page"
+ }
+ ]
+}
diff --git a/2024/endoh1/.gitignore b/2024/endoh1/.gitignore
new file mode 100644
index 000000000..12827a97d
--- /dev/null
+++ b/2024/endoh1/.gitignore
@@ -0,0 +1,7 @@
+128.ppm
+32.ppm
+512.ppm
+8.ppm
+out.ppm
+pixel
+rt.c
diff --git a/2024/endoh1/.path b/2024/endoh1/.path
new file mode 100644
index 000000000..1a6703503
--- /dev/null
+++ b/2024/endoh1/.path
@@ -0,0 +1 @@
+2024/endoh1
diff --git a/2024/endoh1/2024_endoh1.tar.bz2 b/2024/endoh1/2024_endoh1.tar.bz2
new file mode 100644
index 000000000..516c44c56
Binary files /dev/null and b/2024/endoh1/2024_endoh1.tar.bz2 differ
diff --git a/2024/endoh1/Makefile b/2024/endoh1/Makefile
new file mode 100644
index 000000000..7e24f3455
--- /dev/null
+++ b/2024/endoh1/Makefile
@@ -0,0 +1,249 @@
+#!/usr/bin/env make
+#
+# 2024/endoh1
+
+#############################
+# shell used by this Makefile
+#############################
+
+SHELL= bash
+
+
+#######################
+# common tool locations
+#######################
+
+include ../../var.mk
+
+
+#####################
+# C compiler settings
+#####################
+
+# Common C compiler warnings to silence
+#
+# Example: CSILENCE= -Wno-poison-system-directories
+#
+CSILENCE=
+
+# Attempt to silence unknown warning options
+#
+CUNKNOWN= -Wno-unknown-warning-option
+
+# Common C compiler warning flags
+#
+# NOTE: The addition of -pedantic to CWARN is a challenge that
+# You may wish to avoid if it proves too problematic.
+# There is NO penalty for removing -pedantic from CWARN.
+#
+CWARN= -Wall -Wextra -pedantic ${CSILENCE} ${CUNKNOWN}
+
+# Compiler standard
+#
+CSTD= -std=gnu17
+
+# Compiler bit architecture
+#
+# Example for 32-bitness: ARCH= -m32
+# Example for 64-bitness: ARCH= -m64
+#
+# NOTE: Normally one should NOT specify a specific architecture.
+#
+ARCH=
+
+# Defines that are needed to compile
+#
+# Example: -Dfoo -Dbar=baz
+#
+CDEFINE=
+
+# Include files that are needed to compile
+#
+# Example: CINCLUDE= -include stdio.h
+#
+CINCLUDE=
+
+# Other flags to pass to the C compiler
+#
+# Example: COTHER= -fno-math-errno
+#
+COTHER=
+
+# Optimization
+#
+# NOTE: Feel free to change the level of compiler optimization.
+# The "-O3" is just a friendly default you might wish to try.
+#
+# Example: OPT= -O0 -g
+#
+OPT= -O3
+
+# Default flags for ANSI C compilation
+#
+CFLAGS= ${CSTD} ${CWARN} ${ARCH} ${CDEFINE} ${CINCLUDE} ${COTHER} ${OPT}
+
+# Libraries needed to build
+#
+# Example: LDFLAGS= -lncurses -lm
+#
+LDFLAGS=
+
+# C compiler to use
+#
+# NOTE: The IOCCC Judges recommend you leave CC as just "cc"
+# and NOT set it to clang, or gcc, or something else
+# unless you have a STRONG reason to do so.
+#
+# Setting CC to something other than "cc" makes your
+# code less portable to those who do not have your
+# particular C compiler. **hint**
+#
+# If you want to test your code with a particular C compiler,
+# use the make command line. For example:
+#
+# make all CC=clang
+# make all CC=gcc
+#
+CC= cc
+
+# Compiler add-ons or replacements for clang only
+#
+ifeq "$(findstring $(CLANG),${CC})" "$(CLANG)"
+#
+# NOTE: This code is only invoked when CC is "clang"
+# such as when you use the make command line:
+#
+# make all CC=clang
+#
+CSILENCE+= -Wno-poison-system-directories
+#
+CWARN+= -Weverything
+#
+endif
+
+# Specific add-ons or replacements for gcc only
+#
+ifeq "$(findstring $(GCC),${CC})" "$(GCC)"
+#
+# NOTE: This code is only invoked when CC is "gcc"
+# such as when you use the make command line:
+#
+# make all CC=gcc
+#
+CSILENCE+=
+#
+CWARN+=
+#
+endif
+
+
+###########################################
+# Special Makefile variables for this entry
+###########################################
+
+ENTRY= prog
+PROG= ${ENTRY}
+#
+OBJ= ${PROG}.o
+TARGET= ${PROG} rt.c
+#
+ALT_OBJ=
+ALT_TARGET=
+
+# list any data files supplied with your submission
+#
+# Example: DATA= curds whey
+#
+DATA=
+
+# default width
+#
+W= 32
+
+# default height
+#
+H= 32
+
+
+#################
+# build the entry
+#################
+
+all: data ${TARGET}
+ @${TRUE}
+
+.PHONY: all alt data everything clean clobber
+
+# how to compile
+#
+${PROG}: ${PROG}.c
+ ${CC} ${CFLAGS} ${PROG}.c -o $@ ${LDFLAGS}
+
+rt.c: ${PROG}
+ ${RM} -f $@
+ ./${PROG} > $@
+
+%.txt: rt.c
+ @${RM} -f $@
+ @F="$@" ; E="$${F%%.txt}" ; \
+ X="$${E##*-}" ; TX="$${X%%[!0]*}" ; X="$${X#$$TX}" ; X="$${X:-0}" ; \
+ Y="$${E#*-}" ; Y="$${Y%-*}" ; TY="$${Y%%[!0]*}" ; Y="$${Y#$$TY}" ; Y="$${Y:-0}" ; \
+ echo ${CC} -E -P -DX="$$X" -DY="$$Y" -DW="${W}" -DH="${H}" rt.c ">" $@
+ @F="$@" ; E="$${F%%.txt}" ; \
+ X="$${E##*-}" ; TX="$${X%%[!0]*}" ; X="$${X#$$TX}" ; X="$${X:-0}" ; \
+ Y="$${E#*-}" ; Y="$${Y%-*}" ; TY="$${Y%%[!0]*}" ; Y="$${Y#$$TY}" ; Y="$${Y:-0}" ; \
+ ${CC} -E -P -DX="$$X" -DY="$$Y" -DW="${W}" -DH="${H}" rt.c > $@
+
+targets= $(shell \
+ for y in $$(${SEQ} -w 0 $$((${H}-1))); do \
+ for x in $$(${SEQ} -w 0 $$((${W}-1))); do \
+ echo "pixel/pixel-$$y-$$x.txt"; \
+ done; \
+ done)
+
+pixel:
+ ${MKDIR} -p pixel
+
+out.ppm: pixel ${targets}
+ echo P3 ${W} ${H} > $@
+ echo 255 >> $@
+ ${FIND} pixel -type f -print | LANG=C ${SORT} | ${XARGS} cat >> $@
+
+# alternative executable
+#
+alt: data ${ALT_TARGET}
+ @${TRUE}
+
+${PROG}.alt: ${PROG}.alt.c
+ ${CC} ${CFLAGS} ${PROG}.alt.c -o $@ ${LDFLAGS}
+
+# data files
+#
+data: ${DATA}
+ @${TRUE}
+
+# both all and alt
+#
+everything: all alt
+ @${TRUE}
+
+
+###############
+# utility rules
+###############
+#
+clean:
+ ${RM} -f ${OBJ} ${ALT_OBJ}
+ ${RM} -f out.ppm
+
+clobber: clean
+ ${RM} -f ${TARGET} ${ALT_TARGET}
+ ${RM} -rf *.dSYM
+ ${RM} -rf pixel 128.ppm 32.ppm 512.ppm 8.ppm
+
+
+######################################
+# optional include of 1337 hacker rulz
+######################################
+
+-include 1337.mk ../1337.mk ../../1337.mk
diff --git a/2024/endoh1/README.md b/2024/endoh1/README.md
new file mode 100644
index 000000000..2a4db8285
--- /dev/null
+++ b/2024/endoh1/README.md
@@ -0,0 +1,516 @@
+## To build:
+
+```
+ make all
+```
+
+
+## Try:
+
+```
+ ./try.sh
+```
+
+**HINT**: You have to be **VERY** patient while the above script runs to completion.
+
+
+## Judges' remarks:
+
+When you `make all` you see what looks like a C program, `rt.c`.
+However if you try to compile `rt.c`, you will fail: even if you try to
+define the symbols `X`, `Y`, `W`, and `H`.
+
+Well, the propose of the C program, `rt.c` is to generate the red, green, and blue colors of
+a single pixel, in the C Preprocessor!!!
+
+For the patient, a image may be rendered a slow pixel at a time.
+Think of this as digital [Pointillism](https://en.wikipedia.org/wiki/Pointillism). :-)
+
+For the truly impatient who wishes to get right to the point without trying to dot around
+waiting for the [try.sh](%%REPO_URL%%/2024/endoh1/try.sh) to finish, you may view these images:
+
+* [tiny 8x8 image](ref.8.png)
+* [small 32x32 image](ref.32.png)
+* [medium 128x128 image](ref.128.png)
+* [large 512x512 image](ref.512.png)
+
+**FUN FACT**: We were able to determine on an "_x86-64 processor_" running
+"_RHEL 9.6_" using "_gcc version 11.5.0_", one could theoretically render
+a **2147483647 x 2147483647** pixel image. At the rate it took to render
+the **512 x 512** pixel image, and without using any parallelism, such an
+image would take about **169 billion years** to fully render on a single
+CPU core! Fully rendering such large images is **NOT** recommended. :-)
+
+
+### Parallel make
+
+**SUGGESTION**: The [2024/endoh1/Makefile](%%REPO_URL%%/2024/endoh1/Makefile),
+by default, uses a single CPU core, can make use of parallel operations.
+If you have access to a "_parallel make_", can achieve the above in a shorter
+around of time. If you have "_n_" CPU cores available, consider running
+a parallel make with "_n-1_" jobs that run simultaneously. For example:
+
+```
+ RESERVE="-2"
+ NPROC=$(nproc)
+ ((JOBS=NPROC-RESERVE))
+ SIZE=512
+ make clobber all
+ nohup time make -j "$JOBS" out.ppm H="$SIZE" W="$SIZE" > make.out 2>&1 < /dev/null &
+```
+
+Where `SIZE` is the size of the image to generate.
+
+Where `RESERVE` is the number of CPU cores to reserve for other things
+such as the operating system, daemons, terminal window, etc. You can even
+"_oversubscribe_" by setting RESERVE to a negative number (e.g., `RESERVE="-2"`).
+
+**NOTE**: The [try.sh](%%REPO_URL%%/2024/endoh1/try.sh) script follows the above
+example for `SIZE` values of 8, 32, 128, and then 512.
+
+The optimal `RESERVE` will depend on your hardware, operating system,
+a C compiler. Making `RESERVE` too small (i.e., too negative) may slow
+down the result. We recommend that experiment various values pf `RESERVE`
+with moderate `SIZE` of **32** in order to try to find an optimal `JOBS`
+value before attempting to try a larger size such as **512** and beyond.
+
+
+
+### Be first to build images larger than 512x512
+
+
+**QUESTION**: Do you have the patience to build an even larger than a 512x512 image?
+If you do, **using the program as it is written of course**, please [send the IOCCC](../../judges.html)
+the following:
+
+* Image Height x Width in pixels
+* URL of the fully rendered image (in PPM form or better yet converted to PNG)
+* How long it took (perhaps using the time(1) command or using the `time` shell builtin)
+* The starting and ending dates (using `date -u`) of your rendering
+* Number of CPU cores, Operating system, Compiler, Compiler version, and make version
+* The number of jobs you ran in parallel
+* Anything else you may have done to optimize
+* Your name, (GitHub handle (optional)), (Mastodon handle (optional)), (home page URL (optional)), Country (or XX to be anonymous)
+
+**PLEASE** do not attempt to optimize the general algorithm used by this entry to build PPM images.
+Please remain "_faithful to the spirit_" of this wonderful entry when attempting to build larger PPM images.
+
+The first people to render a new record sized image **using the general algorithm used by this entry**,
+will be given credit in the [thanks for the help](../../thanks-for-help.html) web page.
+
+
+## Author's remarks:
+
+
+### A Ray Tracer in the C Preprocessor
+
+Ever since the iconic 1988 IOCCC winning entry [1988/applin](../../1988/applin/index.html),
+bending the C preprocessor to one's will has been a time-honored tradition in the IOCCC.
+This entry sets out to be the culmination of that legacy: a ray tracer implemented entirely with C macros!
+
+
+#### How to Run
+
+The initial program, `./prog` (compiled from `prog.c`), outputs the main code, `rt.c`.
+To get started, compile and execute it:
+
+```
+ make all
+```
+
+Note: `rt.c` is not a valid C program -- it's written for C preprocessor.
+
+To get the color of a single pixel at position (16, 16) in a 32 x 32 image, run:
+
+```
+ cc -E -P -DX=16 -DY=16 -DW=32 -DH=32 rt.c
+```
+
+This will produce:
+
+```
+ 129
+ 62
+ 129
+```
+
+These three values represent the red, green, and blue components respectively.
+
+* Red = 129 (0x81)
+* Green = 62 (0x3e)
+* Blue = 129 (0x81)
+
+In other words, this indicates that the pixel at position (16, 16) has the color #813e81.
+
+
+#### How to Generate the Full Image
+
+To generate the entire image, you need to run the preprocessor for every pixel.
+For example, to form a 32x32 image:
+
+```
+ mkdir -p pixel
+ cc -E -P -DX=0 -DY=0 -DW=32 -DH=32 rt.c > pixel/pixel-00-00.txt
+ cc -E -P -DX=1 -DY=0 -DW=32 -DH=32 rt.c > pixel/pixel-00-01.txt
+ cc -E -P -DX=2 -DY=0 -DW=32 -DH=32 rt.c > pixel/pixel-00-02.txt
+ ...
+ cc -E -P -DX=30 -DY=0 -DW=32 -DH=32 rt.c > pixel/pixel-00-30.txt
+ cc -E -P -DX=31 -DY=0 -DW=32 -DH=32 rt.c > pixel/pixel-00-31.txt
+ cc -E -P -DX=0 -DY=1 -DW=32 -DH=32 rt.c > pixel/pixel-01-00.txt
+ cc -E -P -DX=1 -DY=1 -DW=32 -DH=32 rt.c > pixel/pixel-01-01.txt
+ cc -E -P -DX=2 -DY=1 -DW=32 -DH=32 rt.c > pixel/pixel-01-02.txt
+ ...
+ cc -E -P -DX=30 -DY=31 -DW=32 -DH=32 rt.c > pixel/pixel-31-30.txt
+ cc -E -P -DX=31 -DY=31 -DW=32 -DH=32 rt.c > pixel/pixel-31-31.txt
+```
+
+Then, concatenate the results with a PPM header to create the image:
+
+```
+ echo P3 32 32 > out.ppm
+ echo 255 >> out.ppm
+ find pixel -type f -print | LANG=C sort | xargs cat >> out.ppm
+```
+
+Now open `out.ppm` with any image viewer that supports the PPM format.
+
+
+#### Automating with Makefile
+
+To form a 32x32 image:
+
+```
+ make clean targets out.ppm H=32 W=32
+```
+
+Now open `out.ppm` with any image viewer that supports the PPM format.
+
+
+#### Generating a Larger Image
+
+To form a 256x256 image:
+
+```
+ make clean targets out.ppm H=256 W=256
+```
+
+Now open `out.ppm` with any image viewer that supports the PPM format.
+
+For reference, the 512x512 image took about 10 hours to render.
+
+
+#### Technical Challenges
+
+Below is a technical explanation of the implementation.
+
+
+##### Copying a Macro Definition
+
+One core challenges was how to "copy" the value of a macro.
+
+For example, in C macros:
+
+```
+ #define X 10
+ #define Y X
+
+ #undef X
+ #define X 20
+
+ Y // expands to "20", not "10"
+```
+
+The C preprocessor uses lazy evaluation, meaning macro values are always resolved at the time of use.
+With this observation, some people claim it's impossible to copy a macro's value.
+
+One known workaround is encoding one bit by whether or not a macro is defined (as seen in `applin.c` from IOCCC 1988 and `vik2.c` from IOCCC 2004).
+However, this approach is too inefficient for our purposes -- ray tracing requires operations like multiplication, and even square root.
+
+Instead, we discovered an efficient way to "copy" a macro's value.
+The key observation is that `#if` eagerly evaluates the definition of a macro at that point in preprocessing.
+For example:
+
+```
+ #if X % 2
+ # define X_b0 1 // The LSB of X is 1
+ #else
+ # define X_b0 0 // The LSB of X is 0
+ #endif
+```
+
+This technique copies the least significant bit of `X`.
+By applying this for each bit, we can reconstruct the full value:
+
+```
+ #define X 10
+
+ #if X % 2
+ # define X_b0 1
+ #else
+ # define X_b0 0
+ #endif
+
+ #if X / 2 % 2
+ # define X_b1 2
+ #else
+ # define X_b1 0
+ #endif
+
+ #if X / 4 % 2
+ # define X_b2 4
+ #else
+ # define X_b2 0
+ #endif
+
+ ...
+
+ #define Y (X_b0 + X_b1 + X_b2 + ...)
+
+ #undef X
+ #define X 20
+
+ Y // replaced with "0 + 2 + 0 + 8 + ..." = 10
+```
+
+Even if `X` is later redefined, `Y` remains unchanged.
+
+This technique resembles ["information flow"][information-flow] in the information security.
+To our best knowledge, there has been no literature that mentions this technique in terms of the C preprocessor programming.
+
+[information-flow]: https://en.wikipedia.org/wiki/Information_flow_(information_theory)
+
+
+##### Macro Expansion Explosion
+
+Using macros for complex expressions often causes memory issues.
+
+For instance, consider this Newton's method implementation for square roots:
+
+```
+ #define sqrt0(x, guess) (guess ? (x/guess+guess)/2 : 0)
+ #define sqrt(x) sqrt0(x,sqrt0(x,sqrt0(x,sqrt0(x,sqrt0(x,10000)))))
+```
+
+The subroutine `sqrt0` is one step of Newton's method, and `sqrt` applies it five times.
+There are three occurences of the argument `guess` in the body of `sqrt0`.
+Thus, applying `sqrt` repeats its argument expression at least 5^3 = 243 times.
+This easily leads to the explosion of macro expansion.
+
+We avoid this issue by using the earlier "copy" trick -- reducing the size of macro expansions by materializing their values.
+
+
+##### Encoding Vectors
+
+In theory, it is trivial to encode a 3D vector in the C preprocessor: you can just define three macros for x, y, and z components.
+However, it creates bloated code -- unsuitable for IOCCC size limits.
+
+Instead, we encode vectors as simple tuples:
+
+```
+ #define vec 1,2,3
+```
+
+The vector projection can be implemented as follows.
+
+```
+ #define fst(x,y,z) x
+ #define snd(x,y,z) y
+ #define thd(x,y,z) z
+ #define call(f,a) f(a)
+```
+
+Example usage:
+
+```
+ call(fst, vec) // expands to 1
+ call(snd, vec) // expands to 2
+ call(thd, vec) // expands to 3
+```
+
+The auxiliary macro `call` is required.
+This is a hassle of the C preprocessor, but, `call(fst, vec)` is expanded to `fst(1,2,3)`, which results in `1`.
+
+We can define a vector addition by using the projections.
+
+```
+ #define vec3_add(a,b) fst(a)+fst(b),snd(a)+snd(b),thd(a)+thd(b)
+```
+
+Now, we can simply write `vec3_add(v1, v2)` to add two vectors.
+One identifier represents one vector.
+It is also elegantly possible to nest expressions like `vec3_add(v1, vec3_add(v1, v2))`.
+
+```
+ #define v1 0,1,2
+ #define v2 2,1,0
+
+ int main() {
+ printf("(%d %d %d)\n", vec3_add(v1, v2)); // prints "(2 2 2)"
+ printf("(%d %d %d)\n", vec3_add(v1, vec3_add(v1, v2))); // prints "(2 3 4)"
+ }
+```
+
+
+##### Ray Tracing via Self-Inclusion
+
+Ray tracing involves recursive calls for reflection.
+In `rt.c`, this is done via:
+
+```
+ #include __FILE__
+```
+
+In the implementation, only spheres reflect rays, and only one sphere exists.
+Thus, the recursion depth is limited to one.
+
+Theoretically, it is possible to support multiple reflections, but this would require implementing a "stack" to keep "local variables" in a stack frame.
+
+
+##### Outputting a Pixel
+
+The preprocessed result of `rt.c` contains some preprocessor directives (starting with `#`) and three integers (red, green, and blue).
+
+```
+ cc -E -DX=16 -DY=16 -DW=32 -DH=32 rt.c
+```
+
+This will produce:
+
+```
+ # 0 "rt.c"
+ # 0 ""
+ # 0 ""
+ # 1 "/usr/include/stdc-predef.h" 1 3 4
+ # 0 "" 2
+ # 1 "rt.c"
+ # 3481 "rt.c"
+ # 1 "rt.c" 1
+ # 2090 "rt.c"
+ # 1 "rt.c" 1
+ # 2091 "rt.c" 2
+ # 3482 "rt.c" 2
+ # 3582 "rt.c"
+ 129
+ # 3684 "rt.c"
+ 62
+ # 3786 "rt.c"
+ 129
+```
+
+Interestingly, these are valid in the PPM format (lines starting with `#` are commments in PPM).
+Thus, just concatenating the results for all pixels (and prefixing a small header) will work to create a PPM image file.
+
+When render a large image, we recommend use the `-E -P` flags as in:
+
+```
+ cc -E -P -DX=16 -DY=16 -DW=32 -DH=32 rt.c
+```
+
+This will only produce:
+
+```
+ 129
+ 62
+ 129
+```
+
+Note that values appear as expressions like `(0 + 2 + 0 + 8 + ...)` because we use the "copy" trick.
+To print them as to ordinary decimal values, we use macro logic like:
+
+```
+ // assume red is (0 + 2 + 0 + 8)
+
+ #if red / 100 % 10 == 0
+ # define digit0(digits) 0##digits
+ #elif red / 100 % 10 == 1
+ # define digit0(digits) 1##digits
+ #else
+ # define digit0(digits) 2##digits
+ #endif
+
+ #if red / 10 % 10 == 0
+ # define digit1(digits) digits0(0##digits)
+ #elif red / 10 % 10 == 1
+ # define digit1(digits) digits0(1##digits)
+ #elif ...
+ ...
+ #endif
+
+ #if red % 10 == 0
+ # define digits digit1(0)
+ #elif red % 10 == 1
+ # define digits digit1(1)
+ #elif ...
+ ...
+ #endif
+
+ digits // outputs "10"
+```
+
+
+#### Customizing the Scene
+
+You can modify the scene by editing the top of `rt.c`.
+
+
+##### Example Defaults
+
+```
+ #define p 0,500,4000 // sphere center position
+ #define q 2000 // sphere radius
+ #define r 300,300,300 // sphere color (default: light gray)
+ #define s(x) 900,200+K*7100,900 // plane color (default: checkered colors of white for K=1 and purple for K=0)
+ #define t -2000,4000,1000 // light position
+ #define u 50000,50000,50000 // light color (default: white)
+ #define v(x) 500-x,500-x,500 // background color (default: gradation from blue to white)
+```
+
+
+##### Variant Example
+
+```
+ #define p 0,0,8000
+ #define q 2000
+ #define r 300,300,900
+ #define s(x) 200,500-x*300,200+x*800
+ #define t 2000,4000,3000
+ #define u 30000,40000,30000
+ #define v(x) 500,x,10
+```
+
+Features:
+
+* Grounded blue sphere
+* Blue and green checkered floor
+* Sunset-style lighting
+
+See `ref.512-variant.png` for the rendered result.
+
+
+#### Limitations
+
+Currently, this program supports:
+
+* One sphere
+* One floor
+* One light
+
+Adding more lights is relatively simple.
+Adding multiple spheres would require stack support for recursive ray tracing (see "Ray Tracing by Self-Inclusion" section).
+
+Note: we recommend GCC for performance; Clang is slower for C preprocessor-heavy tasks like this one.
+
+
+
diff --git a/2024/endoh1/index.html b/2024/endoh1/index.html
new file mode 100644
index 000000000..4aa6633cd
--- /dev/null
+++ b/2024/endoh1/index.html
@@ -0,0 +1,916 @@
+
+
+
+
+
+
+
+
+
+
+
+
+2024/endoh1 - Prize in patient pointillism
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
HINT: You have to be VERY patient while the above script runs to completion.
+
Judges’ remarks:
+
When you make all you see what looks like a C program, rt.c.
+However if you try to compile rt.c, you will fail: even if you try to
+define the symbols X, Y, W, and H.
+
Well, the propose of the C program, rt.c is to generate the red, green, and blue colors of
+a single pixel, in the C Preprocessor!!!
+
For the patient, a image may be rendered a slow pixel at a time.
+Think of this as digital Pointillism. :-)
+
For the truly impatient who wishes to get right to the point without trying to dot around
+waiting for the try.sh to finish, you may view these images:
FUN FACT: We were able to determine on an “x86-64 processor” running
+“RHEL 9.6” using “gcc version 11.5.0”, one could theoretically render
+a 2147483647 x 2147483647 pixel image. At the rate it took to render
+the 512 x 512 pixel image, and without using any parallelism, such an
+image would take about 169 billion years to fully render on a single
+CPU core! Fully rendering such large images is NOT recommended. :-)
+
Parallel make
+
SUGGESTION: The 2024/endoh1/Makefile,
+by default, uses a single CPU core, can make use of parallel operations.
+If you have access to a “parallel make”, can achieve the above in a shorter
+around of time. If you have “n” CPU cores available, consider running
+a parallel make with “n-1” jobs that run simultaneously. For example:
+
RESERVE="-2"
+ NPROC=$(nproc)
+ ((JOBS=NPROC-RESERVE))
+ SIZE=512
+ make clobber all
+ nohup time make -j "$JOBS" out.ppm H="$SIZE" W="$SIZE" > make.out 2>&1 < /dev/null &
+
Where SIZE is the size of the image to generate.
+
Where RESERVE is the number of CPU cores to reserve for other things
+such as the operating system, daemons, terminal window, etc. You can even
+“oversubscribe” by setting RESERVE to a negative number (e.g., RESERVE="-2").
+
NOTE: The try.sh script follows the above
+example for SIZE values of 8, 32, 128, and then 512.
+
The optimal RESERVE will depend on your hardware, operating system,
+a C compiler. Making RESERVE too small (i.e., too negative) may slow
+down the result. We recommend that experiment various values pf RESERVE
+with moderate SIZE of 32 in order to try to find an optimal JOBS
+value before attempting to try a larger size such as 512 and beyond.
+
+
Be first to build images larger than 512x512
+
+
QUESTION: Do you have the patience to build an even larger than a 512x512 image?
+If you do, using the program as it is written of course, please send the IOCCC
+the following:
+
+
Image Height x Width in pixels
+
URL of the fully rendered image (in PPM form or better yet converted to PNG)
+
How long it took (perhaps using the time(1) command or using the time shell builtin)
+
The starting and ending dates (using date -u) of your rendering
+
Number of CPU cores, Operating system, Compiler, Compiler version, and make version
+
The number of jobs you ran in parallel
+
Anything else you may have done to optimize
+
Your name, (GitHub handle (optional)), (Mastodon handle (optional)), (home page URL (optional)), Country (or XX to be anonymous)
+
+
PLEASE do not attempt to optimize the general algorithm used by this entry to build PPM images.
+Please remain “faithful to the spirit” of this wonderful entry when attempting to build larger PPM images.
+
The first people to render a new record sized image using the general algorithm used by this entry,
+will be given credit in the thanks for the help web page.
+
Author’s remarks:
+
A Ray Tracer in the C Preprocessor
+
Ever since the iconic 1988 IOCCC winning entry 1988/applin,
+bending the C preprocessor to one’s will has been a time-honored tradition in the IOCCC.
+This entry sets out to be the culmination of that legacy: a ray tracer implemented entirely with C macros!
+
How to Run
+
The initial program, ./prog (compiled from prog.c), outputs the main code, rt.c.
+To get started, compile and execute it:
+
make all
+
Note: rt.c is not a valid C program – it’s written for C preprocessor.
+
To get the color of a single pixel at position (16, 16) in a 32 x 32 image, run:
+
cc -E -P -DX=16 -DY=16 -DW=32 -DH=32 rt.c
+
This will produce:
+
129
+ 62
+ 129
+
These three values represent the red, green, and blue components respectively.
+
+
Red = 129 (0x81)
+
Green = 62 (0x3e)
+
Blue = 129 (0x81)
+
+
In other words, this indicates that the pixel at position (16, 16) has the color #813e81.
+
How to Generate the Full Image
+
To generate the entire image, you need to run the preprocessor for every pixel.
+For example, to form a 32x32 image:
Now open out.ppm with any image viewer that supports the PPM format.
+
Automating with Makefile
+
To form a 32x32 image:
+
make clean targets out.ppm H=32 W=32
+
Now open out.ppm with any image viewer that supports the PPM format.
+
Generating a Larger Image
+
To form a 256x256 image:
+
make clean targets out.ppm H=256 W=256
+
Now open out.ppm with any image viewer that supports the PPM format.
+
For reference, the 512x512 image took about 10 hours to render.
+
Technical Challenges
+
Below is a technical explanation of the implementation.
+
Copying a Macro Definition
+
One core challenges was how to “copy” the value of a macro.
+
For example, in C macros:
+
#define X 10
+ #define Y X
+
+ #undef X
+ #define X 20
+
+ Y // expands to "20", not "10"
+
The C preprocessor uses lazy evaluation, meaning macro values are always resolved at the time of use.
+With this observation, some people claim it’s impossible to copy a macro’s value.
+
One known workaround is encoding one bit by whether or not a macro is defined (as seen in applin.c from IOCCC 1988 and vik2.c from IOCCC 2004).
+However, this approach is too inefficient for our purposes – ray tracing requires operations like multiplication, and even square root.
+
Instead, we discovered an efficient way to “copy” a macro’s value.
+The key observation is that #if eagerly evaluates the definition of a macro at that point in preprocessing.
+For example:
+
#if X % 2
+ # define X_b0 1 // The LSB of X is 1
+ #else
+ # define X_b0 0 // The LSB of X is 0
+ #endif
+
This technique copies the least significant bit of X.
+By applying this for each bit, we can reconstruct the full value:
Even if X is later redefined, Y remains unchanged.
+
This technique resembles “information flow” in the information security.
+To our best knowledge, there has been no literature that mentions this technique in terms of the C preprocessor programming.
+
Macro Expansion Explosion
+
Using macros for complex expressions often causes memory issues.
+
For instance, consider this Newton’s method implementation for square roots:
The subroutine sqrt0 is one step of Newton’s method, and sqrt applies it five times.
+There are three occurences of the argument guess in the body of sqrt0.
+Thus, applying sqrt repeats its argument expression at least 5^3 = 243 times.
+This easily leads to the explosion of macro expansion.
+
We avoid this issue by using the earlier “copy” trick – reducing the size of macro expansions by materializing their values.
+
Encoding Vectors
+
In theory, it is trivial to encode a 3D vector in the C preprocessor: you can just define three macros for x, y, and z components.
+However, it creates bloated code – unsuitable for IOCCC size limits.
+
Instead, we encode vectors as simple tuples:
+
#define vec 1,2,3
+
The vector projection can be implemented as follows.
+
#define fst(x,y,z) x
+ #define snd(x,y,z) y
+ #define thd(x,y,z) z
+ #define call(f,a) f(a)
+
Example usage:
+
call(fst, vec) // expands to 1
+ call(snd, vec) // expands to 2
+ call(thd, vec) // expands to 3
+
The auxiliary macro call is required.
+This is a hassle of the C preprocessor, but, call(fst, vec) is expanded to fst(1,2,3), which results in 1.
+
We can define a vector addition by using the projections.
Now, we can simply write vec3_add(v1, v2) to add two vectors.
+One identifier represents one vector.
+It is also elegantly possible to nest expressions like vec3_add(v1, vec3_add(v1, v2)).
Ray tracing involves recursive calls for reflection.
+In rt.c, this is done via:
+
#include __FILE__
+
In the implementation, only spheres reflect rays, and only one sphere exists.
+Thus, the recursion depth is limited to one.
+
Theoretically, it is possible to support multiple reflections, but this would require implementing a “stack” to keep “local variables” in a stack frame.
+
Outputting a Pixel
+
The preprocessed result of rt.c contains some preprocessor directives (starting with #) and three integers (red, green, and blue).
Interestingly, these are valid in the PPM format (lines starting with # are commments in PPM).
+Thus, just concatenating the results for all pixels (and prefixing a small header) will work to create a PPM image file.
+
When render a large image, we recommend use the -E -P flags as in:
+
cc -E -P -DX=16 -DY=16 -DW=32 -DH=32 rt.c
+
This will only produce:
+
129
+ 62
+ 129
+
Note that values appear as expressions like (0 + 2 + 0 + 8 + ...) because we use the “copy” trick.
+To print them as to ordinary decimal values, we use macro logic like:
You can modify the scene by editing the top of rt.c.
+
Example Defaults
+
#define p 0,500,4000 // sphere center position
+ #define q 2000 // sphere radius
+ #define r 300,300,300 // sphere color (default: light gray)
+ #define s(x) 900,200+K*7100,900 // plane color (default: checkered colors of white for K=1 and purple for K=0)
+ #define t -2000,4000,1000 // light position
+ #define u 50000,50000,50000 // light color (default: white)
+ #define v(x) 500-x,500-x,500 // background color (default: gradation from blue to white)
+
Variant Example
+
#define p 0,0,8000
+ #define q 2000
+ #define r 300,300,900
+ #define s(x) 200,500-x*300,200+x*800
+ #define t 2000,4000,3000
+ #define u 30000,40000,30000
+ #define v(x) 500,x,10
+
Features:
+
+
Grounded blue sphere
+
Blue and green checkered floor
+
Sunset-style lighting
+
+
See ref.512-variant.png for the rendered result.
+
Limitations
+
Currently, this program supports:
+
+
One sphere
+
One floor
+
One light
+
+
Adding more lights is relatively simple.
+Adding multiple spheres would require stack support for recursive ray tracing (see “Ray Tracing by Self-Inclusion” section).
+
Note: we recommend GCC for performance; Clang is slower for C preprocessor-heavy tasks like this one.
This figure is rotated around its left edge to create a 3D object (a solid of revolution).
+Only solids of revolution are supported by this simulator.
+
Internally, the rigid body is modeled as a collection of particles (point masses). Each character in the input file has the following meaning:
+
+
A full-stop (or any printable character whose LSB is 0): Represents light particle.
+
A hash (or any character whose LSB is 1): Represents heavy particle.
+
A space: Represents no particle (empty space).
+
A slash: Indicates the start of a comment; everything after it on the line is ignored.
+
+
Algorithm overview
+
The core algorithm works as follows:
+
+
Compute the inertia tensor
+
Compute an inverse of the tensor
+
For each particle in contact with the floor:
+3-1. Compute the normal force
+3-2. Compute friction
+3-3. Convert these into the resultant force and torque acting on the body’s center of mass
+
Update the position, velocity, angular velocity, and orientation of the body
+
+
For the detailed theory, refer to a physics textbook.
+
To keep code size minimal, this simulator uses quaternions to represent 3D vectors and matrices.
+Quaternion multiplication is powerful, allowing the inertia tensor and its inverse to be calculated concisely, each requiring only about 100 characters of code.
+Because math.h doesn’t natively support quaternions for these operations, it’s not used at all. This also means linking with -lm is unnecessary.
+
Motion blur is used in the rendering. You can observe it more clearly by pausing the animation (e.g., with Ctrl+S in some terminals).
+
Distant points appear as colons (:), while closer ones appear as at-signs (@).
+
Included data
+
A few shape files are provided. The top*.txt files are standard spinning top shapes.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/2024/endoh2/prog.c b/2024/endoh2/prog.c
new file mode 100644
index 000000000..db52377cd
--- /dev/null
+++ b/2024/endoh2/prog.c
@@ -0,0 +1,27 @@
+/* cc -O3 -DW=80 -DH=24 -Ddt=.01 -De=.5 -Du=.5 -Drpm=1000 -Dtilt=5 prog.c */#include
+/* ./a.out < prog.c # or your favorite pattern file for a spinning top */#include
+/**/char*C,B[H*W+9]="\x1b[H\x1b[J";typedef float S;typedef struct Q{S a[4];}Q;S*E,M,O,z,Z=71.
+/8136*tilt,g,h=1;int i=1,j,k,a,b;struct P{Q x,v;S m;}L[1<<20],*p;void o(S*p){for(k=1;k<99;h*=
+Z/k++)p[k%2]+=h=k%2?-h:h;}Q Y,w={{71*rpm/13560.}}, I[4],N={{1}},V,q,X={{30}},J,G;Q A(Q a,Q b
+)/**/{for(k=4;k--;)a.a[k]+=b.a[k];return a;}Q m(Q a,Q b){Q q=G;for(k=16;k--;){q.a[k%4]+=b.a[
+k/4]*(1-(5432>>k&2))*a.a[19995>>(k>7?15- k:k)*2&3];}return q;}void K(S x){for(h=k=
+99;k;h=(x/h+h)/2)k--;}Q s(Q a,S b){J . a[3]=b;return m(a,J);}S D(Q a,Q b){for
+(h=k=0;k<4/+1;k++){h+=a.a[k]*b.a[k] ;} return h;}Q U(Q a){K(D(a,a));h=1/+h;
+return s(a,/**/h);}int main(){C=B+ 6;o( q. a+2);for(p=L;fgets(C,W*H-1,stdin);
+b--){for(a=0/1;j=C[a++],j&&j!=47;) {for(Z=0;j> 32&&Z*113<710;h=(a-.5+i*61e-7)/2,E
+=(S*)p,M-=z/=j%2?2:2e3,*E=b,o(E+1), Y=A(Y,s(p->x,p->m=z)),p++,i=48271*
+i%65535){Z/**/+=z=2./a;}}}for(;p--> L;)p->x=A(p->x,s(Y,1/M));for(;;us\
+leep(1e4/1)){for(i=H*W;i--;C[i]=i>H* W-W?(a&16)+45 :i%W?32:10)a=i+O;for(j
+=20;j--/1;){Q F={{M}},T=G,v=G,t[3]={ G};for(p=L;p->m;p++){for(i=3,Y=p->x;i
+--;t[/**/i].a[i]+=m(Y,Y).a[3]*p->m){t [i]=A(t[i],s(Y,Y.a[i]*p->m));}}for(Z=i=0
+;i<3/1;i++){Z-=D(t[i],I[i]=m(t[(i+1)% 3],t[(i+2)%3]));}for(;i--;I[i].a[3]=0){I[i]
+=s/**/(I[i],3/Z);}for(p=L;p->m;p++){if (E=p->v.a,(i=+W*(b=H-1.5-*E)+(a=.5+(E[1]-O)*2+
+W/2))>0&&im;p++){Q
+r/**/=s(q,-1);r.a[3]*=-1;z=*(p->v=A(r=m( m(q,p->x),r),X)).a;if(z<0){for(i=4;i--;){E[i]=D(I[i
+/1],m(r,N));}g=(1+e)**A(V,m(w,r)).a/(*m (v,r).a-1/M);v=A(V,m(w,r));*E=E[3]=0;F=A(F,v=A(s(N,g
+/1*z-g),s(U (v),g*u)));
+/**/T=A(T,m (r,v));Z=Z>
+/**/z?z:Z;} }*X.a-=Z;X=
+/*IOCCC*/A(X,s(V=A(V,s(F,dt/-M)),dt));for(i=3;i--;)E[i]=D(I[i],T)*dt;q=U(A(q,s(m(w=A(w,v),q),
+/*2025*/.5*dt)));}O+=(X.a[1]-O)/50;K(D(w,w)*36476);printf("%s\n%*.0f rpm",B,W-5,h);B[5]=72;}}
+
diff --git a/2024/endoh2/prog.orig.c b/2024/endoh2/prog.orig.c
new file mode 100644
index 000000000..db52377cd
--- /dev/null
+++ b/2024/endoh2/prog.orig.c
@@ -0,0 +1,27 @@
+/* cc -O3 -DW=80 -DH=24 -Ddt=.01 -De=.5 -Du=.5 -Drpm=1000 -Dtilt=5 prog.c */#include
+/* ./a.out < prog.c # or your favorite pattern file for a spinning top */#include
+/**/char*C,B[H*W+9]="\x1b[H\x1b[J";typedef float S;typedef struct Q{S a[4];}Q;S*E,M,O,z,Z=71.
+/8136*tilt,g,h=1;int i=1,j,k,a,b;struct P{Q x,v;S m;}L[1<<20],*p;void o(S*p){for(k=1;k<99;h*=
+Z/k++)p[k%2]+=h=k%2?-h:h;}Q Y,w={{71*rpm/13560.}}, I[4],N={{1}},V,q,X={{30}},J,G;Q A(Q a,Q b
+)/**/{for(k=4;k--;)a.a[k]+=b.a[k];return a;}Q m(Q a,Q b){Q q=G;for(k=16;k--;){q.a[k%4]+=b.a[
+k/4]*(1-(5432>>k&2))*a.a[19995>>(k>7?15- k:k)*2&3];}return q;}void K(S x){for(h=k=
+99;k;h=(x/h+h)/2)k--;}Q s(Q a,S b){J . a[3]=b;return m(a,J);}S D(Q a,Q b){for
+(h=k=0;k<4/+1;k++){h+=a.a[k]*b.a[k] ;} return h;}Q U(Q a){K(D(a,a));h=1/+h;
+return s(a,/**/h);}int main(){C=B+ 6;o( q. a+2);for(p=L;fgets(C,W*H-1,stdin);
+b--){for(a=0/1;j=C[a++],j&&j!=47;) {for(Z=0;j> 32&&Z*113<710;h=(a-.5+i*61e-7)/2,E
+=(S*)p,M-=z/=j%2?2:2e3,*E=b,o(E+1), Y=A(Y,s(p->x,p->m=z)),p++,i=48271*
+i%65535){Z/**/+=z=2./a;}}}for(;p--> L;)p->x=A(p->x,s(Y,1/M));for(;;us\
+leep(1e4/1)){for(i=H*W;i--;C[i]=i>H* W-W?(a&16)+45 :i%W?32:10)a=i+O;for(j
+=20;j--/1;){Q F={{M}},T=G,v=G,t[3]={ G};for(p=L;p->m;p++){for(i=3,Y=p->x;i
+--;t[/**/i].a[i]+=m(Y,Y).a[3]*p->m){t [i]=A(t[i],s(Y,Y.a[i]*p->m));}}for(Z=i=0
+;i<3/1;i++){Z-=D(t[i],I[i]=m(t[(i+1)% 3],t[(i+2)%3]));}for(;i--;I[i].a[3]=0){I[i]
+=s/**/(I[i],3/Z);}for(p=L;p->m;p++){if (E=p->v.a,(i=+W*(b=H-1.5-*E)+(a=.5+(E[1]-O)*2+
+W/2))>0&&im;p++){Q
+r/**/=s(q,-1);r.a[3]*=-1;z=*(p->v=A(r=m( m(q,p->x),r),X)).a;if(z<0){for(i=4;i--;){E[i]=D(I[i
+/1],m(r,N));}g=(1+e)**A(V,m(w,r)).a/(*m (v,r).a-1/M);v=A(V,m(w,r));*E=E[3]=0;F=A(F,v=A(s(N,g
+/1*z-g),s(U (v),g*u)));
+/**/T=A(T,m (r,v));Z=Z>
+/**/z?z:Z;} }*X.a-=Z;X=
+/*IOCCC*/A(X,s(V=A(V,s(F,dt/-M)),dt));for(i=3;i--;)E[i]=D(I[i],T)*dt;q=U(A(q,s(m(w=A(w,v),q),
+/*2025*/.5*dt)));}O+=(X.a[1]-O)/50;K(D(w,w)*36476);printf("%s\n%*.0f rpm",B,W-5,h);B[5]=72;}}
+
diff --git a/2024/endoh2/stick.txt b/2024/endoh2/stick.txt
new file mode 100644
index 000000000..8b931ca74
--- /dev/null
+++ b/2024/endoh2/stick.txt
@@ -0,0 +1,22 @@
+// A stick
+
+// Use `-Drpm=10 -Dtilt=30`
+
+#
+#
+#
+#
+#
+#
+#
+#
+#
+#
+#
+#
+#
+#
+#
+#
+#
+#
diff --git a/2024/endoh2/tippe-top.txt b/2024/endoh2/tippe-top.txt
new file mode 100644
index 000000000..6ae0093ac
--- /dev/null
+++ b/2024/endoh2/tippe-top.txt
@@ -0,0 +1,20 @@
+// A tippe top
+
+// Use `-Drpm=2500 -Dtilt=5`
+
+ .
+ .
+ .
+ .
+ .
+ .
+ . ..
+ . .
+ . .
+ . .
+ . .
+ . .
+.#.#.#.#.#.#.#
+#.#.#.#.#.#.#
+.#.#.#.#.#.
+#.#.#.#.
diff --git a/2024/endoh2/tippe-top2.txt b/2024/endoh2/tippe-top2.txt
new file mode 100644
index 000000000..885720730
--- /dev/null
+++ b/2024/endoh2/tippe-top2.txt
@@ -0,0 +1,25 @@
+// A long-stem tippe top
+
+// Use `-Drpm=4000 -Dtilt=5`
+
+..
+.
+.
+.
+.
+.
+.
+.
+.
+.
+.
+.
+.
+. .
+. .
+. .
+. .
+.#.#.#.#.#.#.#
+#.#.#.#.#.#.#
+.#.#.#.#.#.
+#.#.#.#.
diff --git a/2024/endoh2/tippe-top3.txt b/2024/endoh2/tippe-top3.txt
new file mode 100644
index 000000000..a79b03a4a
--- /dev/null
+++ b/2024/endoh2/tippe-top3.txt
@@ -0,0 +1,23 @@
+// A thick-stem tippe top
+
+// Use `-Drpm=2500 -Dtilt=5`
+
+ #
+ .
+ .
+ .
+ .
+ .
+ .
+ .
+ .
+ . #.
+ . .#
+ . #.
+ . .#
+ . #.
+ . .#
+ . #.#
+ #.#.#.#.#.#.#
+ .#.#.#.#.#.
+ #.#.#.#
diff --git a/2024/endoh2/top.txt b/2024/endoh2/top.txt
new file mode 100644
index 000000000..aa2ab3bd9
--- /dev/null
+++ b/2024/endoh2/top.txt
@@ -0,0 +1,20 @@
+// A typical spinning top
+
+// Use `-Drpm=1000 -Dtilt=5`
+
+.
+.
+. // Twirl here
+.
+.
+.
+...
+ #####
+ ##
+ # // Spin!
+ ##
+ #####
+ ##
+#
+#
+# // Looks painful
diff --git a/2024/endoh2/top2.txt b/2024/endoh2/top2.txt
new file mode 100644
index 000000000..6e6af7c8e
--- /dev/null
+++ b/2024/endoh2/top2.txt
@@ -0,0 +1,18 @@
+// Yet another typical top
+
+// Use `-Drpm=500 -Dtilt=5`
+
+#
+#
+#
+#
+#
+#
+###############
+ #
+ #
+ #####
+ #####
+####
+#
+#
diff --git a/2024/endoh2/top3.txt b/2024/endoh2/top3.txt
new file mode 100644
index 000000000..d2571f4b0
--- /dev/null
+++ b/2024/endoh2/top3.txt
@@ -0,0 +1,20 @@
+// An eggplant-like top
+
+// Use `-Drpm=500 -Dtilt=5`
+
+#
+#
+#
+#
+#####
+ ##
+ #
+ #
+ #
+ #
+ #
+ #
+ #
+ ##
+ ##
+#
diff --git a/2024/endoh2/top4.txt b/2024/endoh2/top4.txt
new file mode 100644
index 000000000..61e635946
--- /dev/null
+++ b/2024/endoh2/top4.txt
@@ -0,0 +1,18 @@
+// A corn-style top
+
+// Use `-Drpm=500 -Dtilt=5`
+
+#
+#
+#
+#
+#
+#
+###############
+ ##
+ ##
+ ##
+ ##
+ ##
+ ##
+#
diff --git a/2024/endoh2/try.sh b/2024/endoh2/try.sh
new file mode 100755
index 000000000..669609fae
--- /dev/null
+++ b/2024/endoh2/try.sh
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+#
+# try.sh - demonstrate 2024/endoh2
+
+# 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.
+#
+[[ -z "$CC" ]] && CC="cc"
+
+# make sure the program has been built
+#
+make CC="$CC" all tipple >/dev/null || exit 1
+
+# clear the screen
+#
+clear
+
+# try the program
+#
+echo 'NOTE: To exit, press CTRL+C' 1>&2
+echo 1>&2
+read -r -n 1 -p "Press any key to run: ./tipple < tippe-top2.txt: "
+echo 1>&2
+echo 1>&2
+./tipple < tippe-top2.txt
+echo 1>&2
diff --git a/2024/endoh2/umbrella.txt b/2024/endoh2/umbrella.txt
new file mode 100644
index 000000000..7b0cea93c
--- /dev/null
+++ b/2024/endoh2/umbrella.txt
@@ -0,0 +1,19 @@
+// An umbrella
+
+// Use `-Drpm=1000 -Dtilt=30` or `-Drpm=1000 -Dtilt=180`
+
+########
+# ###
+# ##
+# ##
+# #
+# #
+#
+#
+#
+#
+#
+#
+#
+#
+#
diff --git a/2024/endoh2/vase.txt b/2024/endoh2/vase.txt
new file mode 100644
index 000000000..9e6f710cb
--- /dev/null
+++ b/2024/endoh2/vase.txt
@@ -0,0 +1,18 @@
+// A vase
+
+// Use `-Drpm=2000 -Dtilt=5` or `-Drpm=2000 -Dtilt=20`
+
+ ...
+ .
+ .
+ .
+ ..
+ ..
+ #
+ #
+ #
+ #
+ #
+ #
+ ##
+######
\ No newline at end of file
diff --git a/2024/ferguson1/.entry.json b/2024/ferguson1/.entry.json
new file mode 100644
index 000000000..d71a361e1
--- /dev/null
+++ b/2024/ferguson1/.entry.json
@@ -0,0 +1,313 @@
+{
+ "no_comment" : "mandatory comment: because comments were removed from the original JSON spec",
+ "entry_JSON_format_version" : "1.2 2024-09-25",
+ "award" : "Prize in diabolical logistics",
+ "year" : 2024,
+ "dir" : "ferguson1",
+ "entry_id" : "2024_ferguson1",
+ "title" : "oregon",
+ "abstract" : "Oregon trail pact with the devil",
+ "author_set" : [
+ {
+ "author_handle" : "Cody_Boone_Ferguson"
+ }
+ ],
+ "manifest" : [
+ {
+ "file_path" : "prog.c",
+ "inventory_order" : 20,
+ "OK_to_edit" : true,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "entry source code"
+ },
+ {
+ "file_path" : "Makefile",
+ "inventory_order" : 30,
+ "OK_to_edit" : true,
+ "display_as" : "makefile",
+ "display_via_github" : true,
+ "entry_text" : "entry Makefile"
+ },
+ {
+ "file_path" : "prog.alt.c",
+ "inventory_order" : 40,
+ "OK_to_edit" : true,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "alternate source code"
+ },
+ {
+ "file_path" : "prog.orig.c",
+ "inventory_order" : 50,
+ "OK_to_edit" : false,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "original source code"
+ },
+ {
+ "file_path" : "commented.c",
+ "inventory_order" : 90,
+ "OK_to_edit" : true,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "commented version of the game"
+ },
+ {
+ "file_path" : "addpadding.c",
+ "inventory_order" : 100,
+ "OK_to_edit" : true,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "add padding from data source files"
+ },
+ {
+ "file_path" : "bytecheck.c",
+ "inventory_order" : 100,
+ "OK_to_edit" : true,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "read data.src and print out single-byte chars"
+ },
+ {
+ "file_path" : "bytecount.c",
+ "inventory_order" : 100,
+ "OK_to_edit" : true,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "print each string with locations"
+ },
+ {
+ "file_path" : "byteread.c",
+ "inventory_order" : 100,
+ "OK_to_edit" : true,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "prints out the strings without locations"
+ },
+ {
+ "file_path" : "bytetest.c",
+ "inventory_order" : 100,
+ "OK_to_edit" : true,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "prints every string extracted from data"
+ },
+ {
+ "file_path" : "deobfuscation.html",
+ "inventory_order" : 100,
+ "OK_to_edit" : false,
+ "display_as" : "markdown",
+ "display_via_github" : true,
+ "entry_text" : "hints on how to deobfuscate"
+ },
+ {
+ "file_path" : "lencount.c",
+ "inventory_order" : 100,
+ "OK_to_edit" : true,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "counts strings and reports longest one"
+ },
+ {
+ "file_path" : "mbcheck.c",
+ "inventory_order" : 100,
+ "OK_to_edit" : true,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "show location of multibyte characters"
+ },
+ {
+ "file_path" : "obfuscation.html",
+ "inventory_order" : 100,
+ "OK_to_edit" : false,
+ "display_as" : "markdown",
+ "display_via_github" : true,
+ "entry_text" : "obfuscation information"
+ },
+ {
+ "file_path" : "printer.c",
+ "inventory_order" : 100,
+ "OK_to_edit" : true,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "prints strings like the game does"
+ },
+ {
+ "file_path" : "try.sh",
+ "inventory_order" : 100,
+ "OK_to_edit" : true,
+ "display_as" : "shellscript",
+ "display_via_github" : true,
+ "entry_text" : "script to try entry"
+ },
+ {
+ "file_path" : "devil.png",
+ "inventory_order" : 125,
+ "OK_to_edit" : true,
+ "display_as" : "image",
+ "display_via_github" : true,
+ "entry_text" : "Devil driving wagon"
+ },
+ {
+ "file_path" : "gotos.png",
+ "inventory_order" : 125,
+ "OK_to_edit" : true,
+ "display_as" : "image",
+ "display_via_github" : true,
+ "entry_text" : "Devil regretting gotos"
+ },
+ {
+ "file_path" : "ioccc.jpg",
+ "inventory_order" : 125,
+ "OK_to_edit" : true,
+ "display_as" : "image",
+ "display_via_github" : true,
+ "entry_text" : "image that might or might not be true"
+ },
+ {
+ "file_path" : "spaghetti.png",
+ "inventory_order" : 125,
+ "OK_to_edit" : true,
+ "display_as" : "image",
+ "display_via_github" : true,
+ "entry_text" : "use a goto and this might happen"
+ },
+ {
+ "file_path" : "travelguide.jpg",
+ "inventory_order" : 125,
+ "OK_to_edit" : true,
+ "display_as" : "image",
+ "display_via_github" : true,
+ "entry_text" : "travel guide"
+ },
+ {
+ "file_path" : "data.asc.src",
+ "inventory_order" : 150,
+ "OK_to_edit" : true,
+ "display_as" : "text",
+ "display_via_github" : true,
+ "entry_text" : "text used to build data.asc"
+ },
+ {
+ "file_path" : "data.scrnshot.src",
+ "inventory_order" : 150,
+ "OK_to_edit" : true,
+ "display_as" : "text",
+ "display_via_github" : true,
+ "entry_text" : "text used to build data.scrnshot"
+ },
+ {
+ "file_path" : "data.src",
+ "inventory_order" : 150,
+ "OK_to_edit" : true,
+ "display_as" : "text",
+ "display_via_github" : true,
+ "entry_text" : "text used to build data"
+ },
+ {
+ "file_path" : "strings.asc.loc.txt",
+ "inventory_order" : 150,
+ "OK_to_edit" : true,
+ "display_as" : "text",
+ "display_via_github" : true,
+ "entry_text" : "string locations from data.asc.src"
+ },
+ {
+ "file_path" : "strings.loc.txt",
+ "inventory_order" : 150,
+ "OK_to_edit" : true,
+ "display_as" : "text",
+ "display_via_github" : true,
+ "entry_text" : "string locations"
+ },
+ {
+ "file_path" : "strings.scrnshot.loc.txt",
+ "inventory_order" : 150,
+ "OK_to_edit" : true,
+ "display_as" : "text",
+ "display_via_github" : true,
+ "entry_text" : "screenshot locations"
+ },
+ {
+ "file_path" : "makedata.sh",
+ "inventory_order" : 200,
+ "OK_to_edit" : true,
+ "display_as" : "shellscript",
+ "display_via_github" : true,
+ "entry_text" : "script to generate V.c"
+ },
+ {
+ "file_path" : "V.c",
+ "inventory_order" : 1000,
+ "OK_to_edit" : true,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "include file for some tools"
+ },
+ {
+ "file_path" : "2024_ferguson1.tar.bz2",
+ "inventory_order" : 1415926535,
+ "OK_to_edit" : false,
+ "display_as" : "tbz2",
+ "display_via_github" : false,
+ "entry_text" : "download entry tarball"
+ },
+ {
+ "file_path" : ".entry.json",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : true,
+ "display_as" : "json",
+ "display_via_github" : true,
+ "entry_text" : "entry summary and manifest in JSON"
+ },
+ {
+ "file_path" : ".gitignore",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : true,
+ "display_as" : "gitignore",
+ "display_via_github" : true,
+ "entry_text" : "list of files that should not be committed under git"
+ },
+ {
+ "file_path" : ".path",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : false,
+ "display_as" : "path",
+ "display_via_github" : false,
+ "entry_text" : "directory path from top level directory"
+ },
+ {
+ "file_path" : "README.md",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : true,
+ "display_as" : "markdown",
+ "display_via_github" : true,
+ "entry_text" : "markdown source for this web page"
+ },
+ {
+ "file_path" : "deobfuscation.md",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : true,
+ "display_as" : "markdown",
+ "display_via_github" : true,
+ "entry_text" : "markdown source for deobfuscation.html"
+ },
+ {
+ "file_path" : "obfuscation.md",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : true,
+ "display_as" : "markdown",
+ "display_via_github" : true,
+ "entry_text" : "markdown source for obfuscation.html"
+ },
+ {
+ "file_path" : "index.html",
+ "inventory_order" : 4294967295,
+ "OK_to_edit" : false,
+ "display_as" : "html",
+ "display_via_github" : false,
+ "entry_text" : "this web page"
+ }
+ ]
+}
diff --git a/2024/ferguson1/.gitignore b/2024/ferguson1/.gitignore
new file mode 100644
index 000000000..e4d8edbbf
--- /dev/null
+++ b/2024/ferguson1/.gitignore
@@ -0,0 +1,15 @@
+addpadding
+bytecheck
+bytecount
+byteread
+bytetest
+data
+data.asc
+data.scrnshot
+lencount
+mbcheck
+printer
+prog.alt.asc
+prog.alt.scrnshot
+prog.asc
+prog.scrnshot
diff --git a/2024/ferguson1/.path b/2024/ferguson1/.path
new file mode 100644
index 000000000..337ec24d8
--- /dev/null
+++ b/2024/ferguson1/.path
@@ -0,0 +1 @@
+2024/ferguson1
diff --git a/2024/ferguson1/2024_ferguson1.tar.bz2 b/2024/ferguson1/2024_ferguson1.tar.bz2
new file mode 100644
index 000000000..cbdd8418b
Binary files /dev/null and b/2024/ferguson1/2024_ferguson1.tar.bz2 differ
diff --git a/2024/ferguson1/Makefile b/2024/ferguson1/Makefile
new file mode 100644
index 000000000..234d2d9ae
--- /dev/null
+++ b/2024/ferguson1/Makefile
@@ -0,0 +1,387 @@
+#!/usr/bin/env make
+#
+# 2024/ferguson1
+
+#############################
+# shell used by this Makefile
+#############################
+
+SHELL= bash
+
+
+#######################
+# common tool locations
+#######################
+
+include ../../var.mk
+
+
+#####################
+# C compiler settings
+#####################
+
+# Common C compiler warnings to silence
+#
+# Example: CSILENCE= -Wno-poison-system-directories
+#
+CSILENCE= -Wno-strict-prototypes -Wno-implicit-fallthrough -Wno-misleading-indentation
+
+# Attempt to silence unknown warning options
+#
+CUNKNOWN= -Wno-unknown-warning-option
+
+# Common C compiler warning flags
+#
+# NOTE: The addition of -pedantic to CWARN is a challenge that
+# You may wish to avoid if it proves too problematic.
+# There is NO penalty for removing -pedantic from CWARN.
+#
+CWARN= -Wall -Wextra -pedantic ${CSILENCE} ${CUNKNOWN}
+
+# Compiler standard
+#
+CSTD= -std=gnu17
+
+# Compiler bit architecture
+#
+# Example for 32-bitness: ARCH= -m32
+# Example for 64-bitness: ARCH= -m64
+#
+# NOTE: Normally one should NOT specify a specific architecture.
+#
+ARCH=
+
+# Defines that are needed to compile
+#
+# The DATA define not here is primarily for portability with emojis so it's
+# defined in the respective rules. It amounts to either "data" or "data.asc" (or
+# "data.scrnshot") and is a data file to open.
+#
+CDEFINE= -DBLOCKSIZE=1663
+
+# Include files that are needed to compile
+#
+# Example: CINCLUDE= -include stdio.h
+#
+CINCLUDE=
+
+# Other flags to pass to the C compiler
+#
+# Example: COTHER= -fno-math-errno
+#
+COTHER=
+
+# Optimization
+#
+# NOTE: Feel free to change the level of compiler optimization.
+# The "-O3" is just a friendly default you might wish to try.
+#
+# Example: OPT= -O0 -g
+#
+OPT= -O3
+
+# Default flags for ANSI C compilation
+#
+CFLAGS= ${CSTD} ${CWARN} ${ARCH} ${CDEFINE} ${CINCLUDE} ${COTHER} ${OPT}
+
+# Libraries needed to build
+#
+# Example: LDFLAGS= -lncurses -lm
+#
+LDFLAGS=
+
+# C compiler to use
+#
+# NOTE: The IOCCC Judges recommend you leave CC as just "cc"
+# and NOT set it to clang, or gcc, or something else
+# unless you have a STRONG reason to do so.
+#
+# Setting CC to something other than "cc" makes your
+# code less portable to those who do not have your
+# particular C compiler. **hint**
+#
+# If you want to test your code with a particular C compiler,
+# use the make command line. For example:
+#
+# make all CC=clang
+# make all CC=gcc
+#
+CC= cc
+
+# Compiler add-ons or replacements for clang only
+#
+ifeq "$(findstring $(CLANG),${CC})" "$(CLANG)"
+#
+# NOTE: This code is only invoked when CC is "clang"
+# such as when you use the make command line:
+#
+# make all CC=clang
+#
+CSILENCE+= -Wno-missing-prototypes -Wno-poison-system-directories -Wno-switch-default \
+ -Wno-format-nonliteral -Wno-implicit-fallthrough \
+ -Wno-misleading-indentation -Wno-missing-variable-declarations \
+ -Wno-shorten-64-to-32 -Wno-unreachable-code -Wno-unsafe-buffer-usage
+#
+CWARN+= -Weverything
+#
+endif
+
+# Specific add-ons or replacements for gcc only
+#
+ifeq "$(findstring $(GCC),${CC})" "$(GCC)"
+#
+# NOTE: This code is only invoked when CC is "gcc"
+# such as when you use the make command line:
+#
+# make all CC=gcc
+#
+CSILENCE+=
+#
+CWARN+=
+#
+endif
+
+
+###########################################
+# Special Makefile variables for this entry
+###########################################
+
+ENTRY= prog
+PROG= ${ENTRY}
+#
+OBJ= ${PROG}.o
+TARGET= ${PROG} ${PROG}.asc ${PROG}.scrnshot
+
+# .alt is as above more events
+#
+ALT_OBJ= ${PROG}.alt.o ${PROG}.alt.asc.o ${PROG}.alt.scrnshot.o
+ALT_TARGET= ${PROG}.alt ${PROG}.alt.asc ${PROG}.alt.scrnshot
+
+# list any data files supplied with the submission
+#
+# Don't include data, data.asc or data.scrnshot.
+# The data rule (although it's better to use makedata the data rule might work -
+# or it might not) is needed.
+#
+# The build of the programs use make padding however.
+#
+# I discuss the data files in obfuscation.md in more detail and I also mention
+# them in remarks.md (to do with troubleshooting and notes to the judges).
+#
+# As I noted in the remarks.md you should always make sure to rebuild them if
+# there is some kind of error: basically a pre-process for the code. No issues
+# have occurred since I added the build of the data files in the build of the
+# program but it is theoretically possible.
+#
+# It isn't always necessary to build the data files but when developing it was
+# VERY necessary hence all the protections in place (and the discussion in the
+# remarks.md). In any event the data files are built at build time so they
+# should not be in this variable.
+#
+# Observe too that the rules to compile programs do NOT depend on the data rule
+# and also do not depend on DATA (most anyway if not all). This is to help
+# prevent the programs being compiled every time the data files are updated.
+#
+DATA= data.src data.asc.src data.scrnshot.src
+
+
+#################
+# build the entry
+#################
+
+all: data ${TARGET}
+ @${TRUE}
+
+.PHONY: all alt data everything clean clobber test
+
+# how to compile
+#
+${PROG}: ${PROG}.c
+ ${MAKE} padding
+ ${CC} ${CFLAGS} -DDATA='"data"' ${PROG}.c -o $@ ${LDFLAGS}
+
+# test rule to make sure that no string in the data files are >= the blocksize
+# and the ASCII only data file does not have multibyte characters (or at least
+# 2, 3 or 4 bytes - unsure if more bytes in a single character is possible).
+#
+# The compilation rules use this to make sure there are no problems and it will
+# exit non-zero if there is any issue thus preventing the build of the specific
+# program.
+#
+test: lencount mbcheck
+ @./lencount -t -i data.src
+ @./lencount -t -i data.asc.src
+ @./lencount -t -i data.scrnshot.src
+ @./mbcheck
+
+# ASCII only version of submission code, hence why the DATA macro is defined
+# here, not in CDEFINE.
+#
+${PROG}.asc: ${PROG}.c
+ ${MAKE} padding
+ ${CC} ${CFLAGS} -DDATA='"data.asc"' ${PROG}.c -o $@ ${LDFLAGS}
+
+# screenshot friendly version
+#
+${PROG}.scrnshot: ${PROG}.c
+ ${MAKE} padding
+ ${CC} ${CFLAGS} -DDATA='"data.scrnshot"' ${PROG}.c -o $@ ${LDFLAGS}
+
+# this tool creates the data files (emoji and ASCII only versions).
+#
+# The warnings disabled are unfortunate. One is actually an extra sanity check
+# in case the exit(1); call was removed by mistake.
+#
+addpadding: addpadding.c
+ ${CC} ${CFLAGS} -Wno-unreachable-code-break -Wno-sign-conversion addpadding.c -o $@ ${LDFLAGS}
+
+# this tool is the first step in helping some of the other tools work, as a
+# pre-processor. This tool is used in the makedata.sh script which is also a
+# pre-processor and must happen if the data source files are updated (which
+# should really only be done by me, the author, as I'm the only one who knows
+# precisely how it works and how perilous it can be to edit).
+#
+bytecount: bytecount.c
+ ${CC} ${CFLAGS} -Wno-unreachable-code-break bytecount.c -o $@ ${LDFLAGS}
+
+# this tool helped me verify the locations of strings were correct (locations
+# are based on the blocksize). The bytecount also helped.
+#
+bytetest: bytetest.c
+ ${CC} ${CFLAGS} bytetest.c -o $@ ${LDFLAGS}
+
+# similar to bytecount but it doesn't print out the location and it also parses
+# the file without caring about the NUL bytes (see if you can figure that out)
+#
+byteread: byteread.c
+ ${CC} ${CFLAGS} byteread.c -o $@ ${LDFLAGS}
+
+# this tool was helpful to help identify if any emojis in the ASCII only version
+# slipped through (however, mbcheck is a better one: this tool is still
+# useful however). Probably only the judges will find this interesting just like
+# most of the tools I have provided.
+#
+bytecheck: bytecheck.c
+ ${CC} ${CFLAGS} -Wno-unreachable-code-break bytecheck.c -o $@ ${LDFLAGS}
+
+# by default this checks for multibyte characters (well 2, 3, 4) in the ASCII
+# data source file, reporting if any are found. If any are found it will report
+# which string so it can be fixed.
+#
+mbcheck: mbcheck.c
+ ${CC} ${CFLAGS} -Wno-unreachable-code-break mbcheck.c -o $@ ${LDFLAGS}
+
+# prints the strings in the data file for visual inspection. This could be
+# useful to check if your system supports all the emojis, although obviously
+# you'll need some sort of scrollback (or use less, perhaps with -r/-R - or
+# possibly redirect to a file if that is equivalent but if it is you could just
+# look at the strings.*loc.txt files).
+#
+printer: printer.c
+ ${CC} ${CFLAGS} -Wno-unreachable-code-break printer.c -o $@ ${LDFLAGS}
+
+# counts number of strings in data file and returns the longest one. Used in
+# calculating the blocksize (originally). It also warns about strings that are
+# >= the BLOCKSIZE in length. >= because we need the NUL byte too! With -t it
+# exits 666 if the blocksize is breached by a string.
+#
+lencount: lencount.c
+ ${CC} ${CFLAGS} -Wno-unreachable-code-break lencount.c -o $@ ${LDFLAGS}
+
+
+# IMPORTANT NOTES FOR THE JUDGES.
+#
+# The makedata.sh script will generate files that are needed by some of the
+# extra tools that I had to write and those tools should in general not be
+# needed by most. I include them to be complete and so you can see my very
+# thorough and careful design.
+#
+# The addpadding.c is necessary but it does not depend on makedata.sh and in
+# fact makedata.sh uses it.
+#
+# The addpadding tool ALWAYS updates all three data files, assuming the source
+# files exist of course; if they don't then obviously there is an error but as I
+# provide them this should not happen unless the Devil has visited you in the
+# night (in which case you might want to be worried, very worried, that
+# something might happen! :-) - maybe declare it a winner to satisfy the Devil?
+# :-) Okay joking aside you get the idea: this should not happen as the source
+# files and this tool are included.
+#
+# When in doubt, make sure the right data file is used (the different compiled
+# binaries based on the DATA macro) and that it was created by addpadding.c! And
+# do make sure you use the right version of addpadding.c - this submission does
+# NOT encrypt the data and the other one does! In fact there is an explicit
+# comment in addpadding.c about this.
+#
+padding: addpadding test
+ @echo "Creating data file..."
+ ./addpadding
+ @echo "Done."
+
+# see remarks.md for more details. This script is mostly useful for the some of
+# the other tools but it can be used for prog.c and prog.alt.c indirectly as it
+# also does build the data files from the source files.
+#
+# An example use of when I personally use this rule: when I actually make an
+# edit to the data source files. As you will probably have noticed the printer.c
+# and bytetest.c tools depend on V.c and makedata.sh creates it so I have those
+# tools use that script too.
+#
+makedata: makedata.sh
+ ./makedata.sh
+
+# alternative executable
+#
+alt: data ${ALT_TARGET}
+ @${TRUE}
+
+# Devil's Cut: extra events that couldn't fit in the prog.c (alas!)
+#
+# As noted the DATA macro is for portability.
+#
+${PROG}.alt: ${PROG}.alt.c
+ ${MAKE} padding
+ ${CC} ${CFLAGS} -DDATA='"data"' ${PROG}.alt.c -o $@ ${LDFLAGS}
+
+# ASCII only version of alt code (Devil's Cut above). This is why indeed the
+# DATA variable is not in the CDEFINE - the .asc versions use the data.asc file.
+#
+${PROG}.alt.asc: ${PROG}.alt.c
+ ${MAKE} padding
+ ${CC} ${CFLAGS} -DDATA='"data.asc"' ${PROG}.alt.c -o $@ ${LDFLAGS}
+
+# screenshot friendly version of alt code
+#
+${PROG}.alt.scrnshot: ${PROG}.alt.c
+ ${MAKE} padding
+ ${CC} ${CFLAGS} -DDATA='"data.scrnshot"' ${PROG}.alt.c -o $@ ${LDFLAGS}
+
+# data files
+#
+data: ${DATA}
+ @${TRUE}
+
+# both all and alt
+#
+everything: all alt
+ @${TRUE}
+
+
+###############
+# utility rules
+###############
+#
+clean:
+ ${RM} -f ${OBJ} ${ALT_OBJ}
+
+clobber: clean
+ ${RM} -f ${TARGET} ${ALT_TARGET}
+ ${RM} -rf *.dSYM
+ ${RM} -rf ${TARGET} addpadding bytetest byteread bytecount printer lencount bytecheck mbcheck data data.asc data.scrnshot
+
+
+######################################
+# optional include of 1337 hacker rulz
+######################################
+
+-include 1337.mk ../1337.mk ../../1337.mk
diff --git a/2024/ferguson1/README.md b/2024/ferguson1/README.md
new file mode 100644
index 000000000..13bfb3351
--- /dev/null
+++ b/2024/ferguson1/README.md
@@ -0,0 +1,3910 @@
+## To build:
+
+```
+ make all
+```
+
+
+## To use:
+
+```
+ ./prog
+```
+
+
+## Try:
+
+```
+ ./try.sh
+```
+
+
+## Alternate code:
+
+
+### Alternate build:
+
+```
+ make alt
+```
+
+
+### Alternate use:
+
+```
+ ./prog.alt
+```
+
+
+## Judges' remarks:
+
+You will have to go to "Fun-Damentals" to understand the logic flow of
+this game. While you jump as many as 130 times to travel from `main()`
+to an successful `exit(666)` you may have a devil of a time trying to
+figure out how this program actually does what it does.
+
+Before you set off on your adventure to decode this program's logic, make
+sure you have enough food, ammo, clothes, oxen, and programming supplies.
+You’ll be driving for 2170 miles through a wild wilderness inspired
+by Oregon, so you’ll need to be prepared for anything! Regardless of
+how well prepared you are, you will have a devil of a time jumping around
+inside this C code. :-)
+
+
+## Author's remarks:
+
+
+
+### A Pact With the Devil On the Oregon Trail (...and his 130 regrets of goto)
+
+
+The **Go To Hell In A Handcart Travel Company** PROUDLY welcomes all sinners to
+our GREATEST destination yet, with:
+
+
+
+Here is our travel guide:
+
+
+
+But before I help any sinners embark on this once in a lifetime journey, for
+those who might be disconcerted with the idea of the theme (even though it's
+ridiculous with something going back to 66m years ago, to several centuries ago
+all the way back to the 1950s, all the while taking place in the 1800s),
+**PLEASE** either read the (probably totally unnecessary)
+[disclaimer](#disclaimer) or skip this perilous journey entirely. Obviously the
+judges will have no choice in the matter :-) but it's not really for them anyway
+but rather in case this wins.
+
+Everyone might or might not want to look at the [commentary on the
+jokes](#jokes) as well as the [humour](#humour) section, [historical
+references](#history) and [cultural references](#cultural) as well. The
+commentary is primarily for those who might be uncomfortable with the jokes that
+go with the theme. Probably totally unnecessary, especially given the [Best
+abuse of the user](https://www.ioccc.org/2000/briddlebane/index.html) IOCCC
+entry from 2000 that directly insults the player but just in case...
+
+Now, back to the good stuff!
+
+This program is an **ABSOLUTELY ABSURD PARODY** of the classic Oregon Trail,
+although it's actually something else entirely now, hence the name change (not
+'Oregon Trail: ...').
+
+Very early on (this took me two months to create) I was making this a C version
+of the BASIC game from 1978 that was published in the July-August 1978 issue of
+Creative Computing (see
+)
+but that was FAR TOO BORING for the IOCCC - and for me, although part of that
+was thought up after I ran into the size restrictions (this was good because I
+came up with some really clever ways to save bytes, hide data and other things).
+
+I decided to make it far funnier, far less educational and much more fun (at
+least to some people, myself included). On the note of 'far less educational':
+the original game did get some things wrong and I have made corrections that I
+talk about in in [differences](#differences) that I'm strangely including
+(because despite the fact it's mostly a different game entirely, there are a
+couple remnants remaining). It's a section that probably could be scrapped but I
+wrote it early on as well.
+
+Anyway, that this is funny, far less educational and more fun makes it unique
+which is better for the IOCCC. Besides, how many times can you redo Oregon
+Trail? Actually a lot, given the very original was 1971, a BASIC one in 1978
+(not sure what it was in the 1971, maybe also BASIC?) and the most recent one
+seems to be from 2021, but who wants another one here, even if I had the rights
+to do it (which I obviously do not, and that is directly against the rules)?
+
+So there is little faithfulness to the original game and there is not meant to
+be. Even so I **MUST** confess a **TERRIBLE (!!) SIN** 👿🔥 to the C gods: there
+still remains a bit of faithfulness to the 1978 game, and in the **MOST
+ATROCIOUS WAY**: it has an **OBSCENE AMOUNT** of `goto`s, in fact **FAR MORE
+THAN THE ORIGINAL 1978 GAME**, which has ONLY 109! Actually, as you'll see I
+beat that number, even before the cpp. I know. I KNOW I'M GOING TO HELL. But so
+does the PC (player character).
+
+The game already went to Hell in a handcart at line 22, taking my belongings
+with it, as I will be needing them. Hopefully it took your belongings too,
+should you play this, as you'll be needing your belongings as well. Not having
+the right supplies can end your life on the trail, although so can dysentery,
+injuries, dragons, Tyrannosauruses ... Yes dragons and Tyrannosauruses still
+existed on the Oregon Trail back in the 1800s.
+
+Even if you think otherwise, this game will show you the truth. Oh and yes. The
+Earth is flat, the Devil is real and the Sun is crazy ... No. I don't really
+believe that but they are cultural references - as well as some baffling beliefs
+by real people - that are in some of the jokes.
+
+But I took it way further. As you'll see, it is horrific spaghetti code and I
+have personally never seen anything close to it. But that's only one of the many
+things I have done - and some are really quite unique and cool, or at least I
+think they are unique (I have never seen these things before nor have I even
+seen any suggestion of them before, one because it's absolutely contrary to how
+it works in C, namely near 200 NUL terminated `char *`s in a single flat `char
+*` - no, not an array of `char *[]`).
+
+See [obfuscation.html](obfuscation.html) and my [concluding remarks](#conclusion) for
+more details on just how many `goto`s I have but beware of monsters. But be careful
+if you have a heart condition. And if you're a computer scientist make sure
+you're not at risk of stroke.
+
+The [obfuscation.html](obfuscation.html) file discusses those other cool things as
+well of course, and they might be briefly brought up in my concluding remarks as
+well.
+
+Anyway: most of the strings in my data files (files, see below) have **at
+least** one joke but I'd guess the vast majority have several jokes and right on
+theme. The data file, the code and even the file size - as in `wc -c` - are all
+**VERY THEMATIC**. Even the code has jokes. The data files have jokes that are
+not part of the game but might amuse some people, should they wish to look at
+them (there are several files they could do this with - I discuss these in
+[obfuscation.html](obfuscation.html) I think.
+
+There are a lot of fun twists as you might expect with the name 'A Pact With the
+Devil On the Oregon Trail'. I will include example jokes as well as a commentary
+on the jokes in general, further down, although it's only a tiny sample.
+
+Oh and I even have emojis in mine - though I have an ASCII data file for systems
+that do not display emojis (or some of the emojis that I chose for that matter).
+That (portability) is one of the reasons for the data files and the `DATA`
+macro.
+
+Another reason is even the original strings (and some of mine are much longer,
+especially with emojis (but quite a few are longer even without emojis) as
+they're multibyte characters), **by themselves** go way beyond the size limits,
+leaving no space for the code.
+
+Another reason is it allows for obfuscation (data hiding part of it but not only
+that).
+
+There are other reasons besides that that I discuss in [data file
+versions](#versions). But since many other past winning entries read from files,
+including fairly large files, and since I have to have code that reads in the
+data file (and don't use `#include` - though as a matter of fact that would not
+even work for the portability!), this is perfectly legal with rule 2 as only
+doing it by `#include` to trick iocccsize is illegal (and again that would not
+even work).
+
+So the data files allow for portability and obfuscation (and showing some rather
+cool things that you can do in C - whether or not they're a good idea in
+production code, they're still quite cool and could inspire people, maybe). Plus
+allowing this to be a submission at all. As I discuss this and the other reasons
+later (including [portability](#portability) and [compiling](#compiling)) as well
+as obfuscation - with some **REALLY** cool and **VERY** interesting tricks - in
+[obfuscation.html](obfuscation.html), I will try and not repeat this justification,
+but I still will talk about the files in various places for various other
+reasons.
+
+One thing I'll say now but discuss much more in the obfuscation file is that there is
+a **SINGLE** flat `char *` that holds almost 200 `char *` (though many are not
+used for various reasons). Yes that's right. Not an array of `char *` (as in
+`char *y[]`) but a single `char *` - though it's used and looks like it IS an
+array anyway.
+
+Going back to this submission. Why not have a bit (or a lot as the case turned
+out to be) of fun and livelihood for the IOCCC? In this game the player
+character (PC) had an ambiguously (most of the jokes are ambiguous like many
+great stories) sinful night, wasting thousands, dropping them from $6666 to
+$1666 (after buying a wagon train), leaving them with an ominous appearing
+amount. They actually 'signed the Devil's book' (hence the name), despite the
+fact those who claimed such things (like [Samuel
+Parris](https://salemwitchmuseum.com/locations/site-of-salem-village-parsonage/)
+and who actually makes a presence - it's very anachronistic and full of satire)
+exist never produced it as 'evidence'.
+
+The game is FULL of often RIDICULOUS jokes and also a fair amount of them
+reference CULTURAL and/or HISTORICAL events, even some that are IMPOSSIBLE. This
+includes some that are historical and/or in culture, and that sometimes includes
+things that happened but could not be possible on the trail but actually
+happened in real life anyway.
+
+A great example is instead of bandits attacking the...[Queen Anne's
+Revenge](https://en.wikipedia.org/wiki/Queen_Anne%27s_Revenge) is on the Oregon
+Trail - over a century after she went to her watery grave (on 10 June 1718 near
+North Carolina)! But in fact that event involves playful mockery and also
+references to [Blackbeard's](https://en.wikipedia.org/wiki/Blackbeard) purported
+last words ('Well done, lad!') as well as his supposedly saying that only he and
+the devil know where his treasure is, which goes well with his lore if what is
+said about his beard is true[^1] - and the theme of the game of course.
+
+But there are other historical and cultural references too, one that is a legend
+(think of a certain crossroads - and yes they had crossroads on the Trail but
+even if they didn't...), some references to the Miracle Workers sitcom series
+(the Dark Ages, year two, and The Oregon Trail - obviously - which was year
+three) and then rather fantastical things as well. It plays in on old beliefs
+about dragons existing and dinosaurs existing too (okay so those did exist but
+if they did exist on the Oregon Trail they obviously would only be fossils - in
+this game though they actually are alive).
+
+Funny thought: how do we know dragons don't exist when we constantly discover
+new species? And how do we know dinosaurs do not still exist when other species
+thought to be extinct for millions of years were actually found, such as the
+first (of others since this) [discovery of the coelacanth in
+1938](https://www.nhm.ac.uk/discover/coelacanths-the-fish-that-outdid-the-loch-ness-monster.html)?
+No. I'm not serious about the first parts though the coelacanth is in fact real.
+
+Yes there are some Jurassic Park references ('spared no expense', and maybe
+something such as the T-rex as well). Of course I already mentioned that dragons
+and dinosaurs still existed on the Oregon Trail, or my Oregon Trail, but there
+is much more to discover. It's really a lot of fun and very funny, although the
+latter also depends on your sense of humour (all those I have shown think it's
+hilarious though).
+
+And as the character you play is on the darker side there are darker jokes as
+well, though not all are. The player character (PC) is also of dubious character
+and makes ridiculous decisions like when the riders (who are always friendly)
+come up. That also involves some jokes which you'll see; I'll mention some of
+these above jokes and maybe others later on in this file.
+
+As for the riders: as I said they're always friendly and instead of having
+tactics (no need), to be on theme, you rob (or attempt to rob!) them. The joke
+before it happens is one thing but if it succeeds it's even more ludicrous (and
+funny - and also perhaps sardonic).
+
+And if you do succeed you get some things too but not all of what you might
+expect! It might be called a kind of damaging (some might say 'damning') event but it
+fits the theme quite well and although it (and this is not the only case this
+happens in the game) might not be something most people care to think about (but
+see [Disclaimer](#disclaimer) and also [what the judges LIKE](#vomitory), yes
+cannibalism does in fact occur in the game, to be blunt (not that the judges
+like THAT but you'll see what I mean if you read that section: which is by no
+means necessary for most people!). Of course it's happened throughout history
+including on the trail so even if the judges did not like to throw up (and
+laugh, which I would guess they will also be doing), it still fits well.
+
+There are actually far more ridiculous examples of this, things that make no
+sense, like most of the game. But that's what makes it so much fun. There are
+many other absolutely ridiculous things, and the above is only a small sample of
+this.
+
+Besides the theme and jokes in the code: it also spells out `OREGON TRAIL`
+(actually more than that but I'll get to that later).
+
+There is so **MUCH MORE** to discover, some of which is in this file. In fact,
+besides the bonkers spaghetti code (many more `goto`s than the 1978 BASIC has,
+once pre-processed, and only six fewer before that - even without the dead
+`goto` there, which is only to mislead even further, it's more `goto`s),
+very little remnants of the original game are extant.
+
+As noted, depending on your sense of humour you will find this absolutely
+HILARIOUS (those I have shown do find it hilarious) or perhaps a bit unsettling
+but it's all in good fun. As noted, emojis are used as well (see further below
+for more details).
+
+I **REALLY POURED MY HEART** and (proverbial) soul into this one ...because the
+player character (PC) obviously doesn't have one to pour. I don't know if I have
+**ever** put the amount of effort into another program or any project (even the
+many games I have created) that I did in this one and I definitely have not in
+such a short period of time (about two months, which is relatively short given
+all it has).
+
+I also poured a huge pot of spaghetti over it, so much so that it endangers the
+life of the PC. I hope you'll forgive me for my sinning (and crime against C).
+
+I had to. This is true satirical programming just by that alone, and it is a
+public service to let people know just how dangerous it is and just how much is
+lost with poor style (and `goto` is exactly that).
+
+Nonetheless, I hope you appreciate the jokes and the fact that I really put a
+lot of effort into making this fun but in some ways disturbing or dubious (even
+if ambiguous and vague and cryptic, the latter exactly like the data files!),
+right on theme of the game. The jokes are deliberately vague and ambiguous so
+that YOUR mind can interpret them the way YOU want (as above - like good
+stories).
+
+As you'll see, although ambiguous and vague in most cases, there is room left
+for personal interpretations, so that more people can enjoy it. If nothing else
+I think the tricks I have in the code, as well as the mad amount of `goto`s,
+will entertain people, perhaps just as much as the game - or close to. Of
+course...the amount of `goto`s might horrify people too. But I guess we'll see.
+
+Actually the only things that remain of the original Oregon Trail: you travel
+the same route (longer than the original game as they got that wrong) and a few
+simple game mechanics. This is largely due to the jokes in the game but those
+jokes also involve MANY code changes.
+
+Even the game mechanics that stayed were modified in some way or another (there
+might be an exception or two in some way, but not fully that I am aware of).
+Some mechanics were actually removed. Dead code is not only on theme but also
+leads to more obfuscation - and jokes. Always jokes. That was a big part of
+this.
+
+Note the (in?)famous '_you have died of dysentery_'. The 1978 Oregon Trail did
+not have it (it had pneumonia instead). **OBVIOUSLY** I had to change it.
+
+But the way I have done it is far more fun and amusing. Emojis actually allow
+for a lot more fun and visuals without trying to outmatch such an iconic game.
+Even if it's a basically a different game now. Actually I would argue [emojis
+are even better here](#emojis).
+
+The jokes that have what some people might question actually have multiple
+interpretations and if one goes to what they find 'questionable' that's actually
+on their end and very possibly (in many cases this is almost certainly the case)
+not even my original idea. But that's discussed in the [disclaimer](#disclaimer)
+and the [commentary on the jokes](#jokes).
+
+For those who are curious enough but do not want to try and figure it out: I do
+offer a section of some of the [differences](#differences) from the May
+1978 issue of Creative Computing (though as it's mostly a different game it
+probably doesn't matter - I wrote it before I changed it to a new game).
+Originally I included the BASIC code with some typo fixes but I wanted more room
+for other files like the images you saw above.
+
+Yes the (my) game can be beaten although as you'll find out it's not exactly as
+you expect when you do (or for that matter, don't :) ) but yes it can be a bit
+harder (well okay I don't know - been too long since I played the original),
+especially as there are a number of unusual hazards (all with a joke or two or
+three or even more than three). One thing that will help make it easier if you
+feel it's too hard is to get rid of the code (and any other place where the `b`
+is reduced):
+
+
+```
+ b-=10;
+```
+
+The `b` is hp (hit points) and stamina (both - and yes I'm aware that they're
+often separate and some games have stamina change how much hp you have and of
+course some games have only one or neither: like the original Oregon Trail which
+had no such concept, though perhaps it is indirectly depending on how you look
+at it).
+
+But on the other hand (as far as ease) you do have more money so there's
+that (this is also part of the theme btw). There are different strategies
+required due to different mechanics of the game: and it's quite a few though
+some of the logic is similar, particularly with checks, though only somewhat
+similar. Even checking if you overspent is done differently when you dig deeper
+into it, even if it might at first glance seem to be the same, or so I think.
+
+BTW: the alt code, [prog.alt.c](prog.alt.c), is what I call the 'Devil's Cut':
+it has additional events that I could not fit into the main thing and maintain
+the obfuscation levels. Of course I added a fair amount more of obfuscation
+later on and I did not add that to the alt code. There are probably too many
+events as it is (23 not counting the things that happen in the mountains - and
+some fun additions that are related to some events). But the extra jokes in the
+alt code was worth it.
+
+The alt code has a lot less obfuscation btw so it might be somewhat easier to
+follow, even if probably not that easy.
+
+It also would appear that I did not merge the variables `I` and `E` into just
+`E` like I did in prog.c. As well, it might be in the Blackbeard event (not
+sure) you will in some (if not all) cases lose bullets despite the fact messages
+do not refer to that. That changed later on and I did not have the time to
+address it. The fact the messages don't refer to them is enough.
+
+The [commented.c](commented.c) code is also not entirely as complete and might
+even have some bugs that were fixed (it is unclear if the same applies to the
+alt code although I think I got those fixed).
+
+Actually, you get to see progression more, comparing the alt code with the
+submission code, and you can appreciate much more this way.
+
+Anyway, I made a huge amount of effort to repeatedly reduce bytes for more
+events and more obfuscation but if it was not for the size limit increase (or
+decrease depending on how you think of it) **AND** the data file this would
+never have been possible as even the original strings far exceed both rule 2
+limits (certainly not possible with obfuscation, maybe not otherwise)!
+
+See my somewhat unserious [dedications](#dedications) as well, if you're bored
+and easily amused.
+
+
+
+### Disclaimer
+
+
+**PUBLIC HEALTH ADVISORY**: as everyone will have noticed I write a lot. So IF
+you believe that all I have written is circumlocution, and you have
+circumlocutophobia aka logoblabberophobia (fear of circumlocution - yes those
+are made up), and you also have hippopotomonstrosesquipedalobibliophobia (fear
+of reading long books, and yes I made that up too, based on
+hippopotomonstrosesquipedaliophobia - which is a humorous extension of
+sesquipedalophobia for fear of long words - and bibliophobia), you might also have
+hippopotomonstrosesquipedaliophobia, a fear of long words. Don't worry though,
+dear sinner! There are treatment options. See the following link, and sorry in
+advance (even though it's way too late :-) ):
+.
+Incidentally, writing less takes more time and I have chronophobia (okay so
+that's a lie but I don't have much time left).
+
+Anyway: as the name '_A Pact With the Devil On the Oregon Trail_' implies this
+is not really Oregon Trail; and I took it beyond a parody - it's taken a life of
+its own hence not 'Oregon Trail: A Pact With the Devil'.
+
+There are **A LOT** of jokes and unexpected events; it's not even just about
+immorality/sinning, though let's face it: what people call immorality/sinning
+was certainly on the trail, even things I shied away from, as much as I thought
+it would enhance the game, exactly because I thought it might be too much for
+some audiences (and that might seem strange, given that there are things that
+are deeply taboo but happens in extreme situations, in order to survive) - I
+tried my best here and I think I did pretty good, and others I shared this with
+agreed there.
+
+The jokes are **DELIBERATELY VAGUE AND AMBIGUOUS** so that one can **interpret
+and enjoy it their OWN way**, and thus I can avoid the problem: if someone
+imagines something a certain way (dirty, for instance? I'll return to that one)
+it is on their mind, not mine. There might be a few that are less ambiguous in
+one's mind but even so they might be interpreted different ways.
+
+An example is the 'Devil's bedchamber' - but this also fits the theme; you have
+to see the messages in the right order (which might or might not happen) in
+order to understand this. Well there are a few others but they also have many
+possible meanings; I discuss that in [Jokes](#jokes) subsection of
+[Humour](#humour). The jokes are not directed at the user but as the
+[Jokes](#jokes) section and other parts of this file point out that has happened
+in a previous winning entry, as a reminder.
+
+Even so, nothing is absolutely implied here, even if one or two might seem
+otherwise. There is a chance in some cases (I spent a lot of time on this and it
+was exhausting - worth it though) I did not even think of every possible
+meaning. Besides, the narrator is often making up a lot of rubbish and that joke
+includes a lot of nonsense (the whole thing is in fact nonsensical fun).
+
+The narrator is, as I'll get to later in the [commentary on the jokes](#jokes),
+actually the Devil, giving a running commentary on what the PC is doing (i.e.
+what is going on in the game).
+
+I tried **REALLY HARD** to remain classy but still have the jokes and irony
+(satire included), though with the visuals that can kind of blur some of the
+class. Some are dark. And an example where there is a blur, but which **HAD** to
+be included, is dysentery, an iconic part of later versions of the original
+Oregon Trail and even society (not to mention the real Oregon Trail). Given
+what kind of disease and the symptoms, it can't be done otherwise.
+
+Besides, it's a lot better than how it is in real life, whatever that is.
+
+I think I did pretty good, especially since it's directed at the player
+character (PC), not the player, exactly like all games should do (when they have
+a narrator).
+
+Anyway: if the idea of a pact with the devil (or in this case, the narrator! :-)
+:-) ) does offend you, and I suppose that's the real one for some people, I can
+offer only: it's nothing serious and all in good fun; there are a lot of jokes
+and in fact **the PLAYER CHARACTER (PC) is playfully MOCKED** by the narrator
+**EXACTLY FOR** this pact and their behaviour! As you'll notice the narrator
+also has a somewhat dubious character (which is also how it would go in real
+life, given what the narrator is) but also in vague and ambiguous ways.
+
+That is also discussed later in the humour subsection. As I note elsewhere I
+think, I have a personal problem with labelling people a sinner and I cannot
+even name all of the sins which adds to the lack of seriousness - and adding to
+the fun.
+
+And yes the fact the narrator is the Devil and the narrator talks about being in
+Hell, knowing the Devil, meeting the Devil for the first time etc., is all very
+well intended, to increase the irony and ridiculousness. That was obviously one
+of the goals (which I succeeded with remarkably), kind of like the pot of
+spaghetti that is so big it could feed a family of 500 giants. I'll return to
+this.
+
+As noted earlier, and probably mentioned later, the game does raise some things
+that society might like to ignore of what happened on the trail (an example on
+another route is the Donner Party) but with jokes, irony and satire, rather than
+writing a book about those things (probably in uncomfortable ways for many
+people). Plus it's all done in a heartbeat (well maybe not just one :-) ),
+assuming of course that the PC even has a heart at all! :-)
+
+Besides those already noted, there a fair number of other historical references
+that you might not expect but are related to the theme.
+
+On the subject of the uncomfortable cannibalism, see [the vomitory](#vomitory)
+section for another reason **to actually INCLUDE it** (thankfully the judges
+like programs that make them throw up! :-) ), to say nothing of the ample
+opportunities for a lot of different kinds of jokes and realism (and
+simultaneously also being utterly ridiculous).
+
+Finally: **PLEASE DO NOT** take anything personally; when the narrator says
+'you' deserve this and that this is not about the player but the player
+CHARACTER (PC) they are playing, exactly like the Devil would do. Yes I realise
+this statement is probably not necessary but I like to point such things out.
+
+Personally I have taken some screenshots of the game though I am very easily
+amused. I think they're definitely worth having in the game and if I played a
+game like this I would want to take screenshots, as I have done. I like the
+blend of graphics and text, but in a way I have never seen before (emojis),
+though I am sure some games do it. It's a nice balance.
+
+I'll discuss in the [Data files](#versions) section more of why I provide the
+different data files but part of it is it allows different people to enjoy the
+jokes in different ways.
+
+
+
+#### Humour: general comments on the ambiguity of the jokes
+
+
+As previously noted the narrator is the Devil. It is unclear if the Devil is
+physically there or just a voice in the PC's head. It certainly is not the
+PC's conscious - he clearly has none, though not because he made a pact with the
+Devil.
+
+This transcends auditory hallucinations, even if the PC is losing his grip on
+reality. Nonetheless that very subject deeply affects me, holding someone who
+suffers from this very dear.
+
+Usually I refer to the Devil as a male but there are some cases where I use
+female. This is part of a joke. The reason is that the author is male and
+nothing more. If you wish to imagine the PC (who is also male) or the Devil as
+female feel free, even if you wish it to be someone else entirely: perhaps
+someone who should have their head examined, or maybe someone who is being
+asphyxiated by spaghetti? :-)
+
+Anyway: this is not making fun of the tragedy of hallucinations (which typically
+occur with delusions, which the PC is clearly having, although see below). As
+noted, someone very very dear to me has to go through this and I've known others
+too.
+
+It could be a visual hallucination too, which often happen at the same time. It
+is entirely unclear if the PC knows any of this, however, as he definitely has
+almost lost all grip on reality.
+
+Anyway, one thing that does happen is a running commentary, often mocking if not
+being outright cruel and totally unhinged (all of these do in fact happen),
+exactly like the PC and the Devil in his head.
+
+This is a **DEEPLY PERSONAL** thing but I tried to make it fun and as it's bogus
+enough it's obviously complete nonsense, just as many jokes are, yet it's also
+all too real. In truth it's a terrifying thing and I wish more people understood
+this. It's a game though. It's meant to be fun.
+
+Oh and no. The ambiguity of the jokes does NOT imply anything about the PC, in
+what would be deeply taboo ways (okay, there's the cannibalism but that's
+another matter entirely and consistent with human history). But as far as the PC
+is concerned it is someone else, a real person, and the narrator acts that way
+too: which is precisely consistent with hallucination. Yes that means he MIGHT
+not be aware it's the Devil, even though he probably should recognise him,
+having signed his book.
+
+But obviously nobody else could be the narrator. No else would be there with the
+unhinged PC, even if a large part of why they are unhinged is because of the
+Devil narrator themselves. In any case, this is the only thing that would fit
+into the narrative, and it's perfect too as you can easily imagine this
+happening, at least if such things as a pact with the Devil were real, and if
+this game were based on reality (quite the contrary as you see by now).
+
+That it's the Devil's voice makes some of the jokes even more absurd, ironic and
+in some ways more believable, though with the nature of the jokes that's going
+to be hard to see. It makes some of the jokes funnier though, like those that
+refer to the PC going to the Devil and even the Devil's bedchamber (which is
+more like torture chamber), amongst some even more ridiculous ones.
+
+Now, with that out of the way, some comments on the jokes might be in order. As
+you might have noticed already some of the jokes are darkish (if not outright
+dark) and others CAN be interpreted in dirty ways but also other ways. But in
+general the jokes are deliberately ambiguous for this very reason.
+
+And I might remind everyone that these jokes are not directed at the player but
+the player character (PC) whereas a [previous winning
+entry](https://www.ioccc.org/2000/briddlebane/index.html) ('Best abuse of the
+user') directly insults the user with things like:
+
+> you are a thieving bucket of whores
+>
+> you are a scum-encrusted bucket of whores
+>
+> you are a glorified colon of miasma
+>
+> you are a satanic carton of poxes
+
+...and many others, many of which are very funny (I won't spoil any more). As
+can be seen some of those are what people would call dirty and offensive, and
+one refers to colons (dysentery, perhaps?).
+
+My jokes are on theme with the game but also are ambiguous and vaguely defined
+and only directed at the PC (and sometimes the narrator, yes even though the
+narrator would only be mocking the PC, he is playing games, just like this
+happening in real life, although a voice would not be mocking themselves - it's
+not real, it's a game, and it's not meant to be a true story). The fact the game
+is on theme throughout is obviously why I chose to show the last insult above.
+
+Well okay some of the jokes here might be a bit more direct but even those could
+be interpreted in different ways, and some of those actually have more than one
+part (they all probably do) which makes what might be (in some people's minds)
+direct less direct (puns can also help here).
+
+I am not sure why I am continuing this, as I know a lot of computer programmers
+have similar kinds of thoughts. But anyway, IF you do have a dirty mind (which
+is a **TERRIBLE** thing to waste, btw) there are many jokes that likely will be
+interpreted that way BY YOU. To which say go for it! There is absolutely nothing
+wrong with that.
+
+As you might guess I too have a dirty mind but the ambiguity and vagueness makes
+it all the funnier and absurd (though perhaps not as absurd as what I did with
+the code?); it also allows different types of senses of humour/minds to
+interpret it their own ways as well as make one wonder.
+
+Some that might be called 'dirty' also have a more literal meaning (which often
+enough is how it started) as another possibility and I was careful how I worded
+the jokes for this very reason. Often literal meanings actually can be dirty to
+some (in real life), but often times not, and some people (like me) might see
+them as more than one thing at the same time, regardless of what they really are
+(or might be).
+
+In fact some of the jokes that can have a dirty (or otherwise 'unclean')
+interpretation, were chosen out of character (OOC) of me i.e. it was not what
+first crossed my mind. The drinking unpotable water, which has several possible
+interpretations, as you'll see, was not originally this way as it progressed in
+stages as I developed the game.
+
+Anyway this allows everyone to use their OWN imagination: this is something a
+lot of good games do too after all, and it fits stories also. If you ask a lot
+of people to interpret novels you're going to invariably find a lot of
+interpretations, often in dramatically different ways, sometimes dirty even when
+it's definitely not. That's exactly what I am doing here too, and that's what a
+good storyteller does. And indeed there is a story here (there is a plot,
+several plot twists and even the end is quite unexpected), even if it might not
+seem like it (it also depends on the pRNG).
+
+Regardless, many of the that jokes could trigger dirty thoughts do have **A
+LOT** of alternative meanings, as noted: words are **EXTREMELY POWERFUL** and so
+is the human brain and imagination. The truth is humans fill in gaps of what
+**THEY** are most familiar with and previous things that happened in **THEIR**
+life as well as **what they WANT** it to mean (we all hear and see what we want
+to hear and see and we only believe what we hear and see etc.).
+
+The human mind fills in blanks with patterns if it has to, which for whatever
+reason it seems to have to when there are gaps. We might somehow call it a
+pattern matching that's not related to computer programming.
+
+But IF you go for a dirty interpretation that is on you, not me, and frankly
+that's fine. They are there to enjoy **HOWEVER YOU WISH!** Frankly if you DO go
+this way it is right on theme of the character anyway which makes it more fun!
+And one might remember that the player character (PC) is losing their mind on
+the trail and having signed the Devil's book so they're clearly in this mindset.
+
+The narrator is extremely dubious, for reasons I already noted, and there is
+some projection, despite not being real, which makes it even more ridiculous,
+which is part of all the jokes.
+
+As you might have noticed many of the jokes actually MOCK THE PLAYER CHARACTER
+(PC) exactly for his sins/misdeeds (as noted in the [Disclaimer](#disclaimer)),
+despite the fact the narrator is just as bad (in many ways worse). Yes. The
+narrator, the Devil, is a hypocrite: did you expect something else in this game?
+
+I personally do not believe in the idea of making a pact with the devil (as in I
+don't believe in him/her/it let alone signing a book that doesn't even exist)
+and I think the idea of calling someone a sinner in this context is problematic
+and highly subjective, though I do not have any problem with people who find
+comfort in not sinning themselves. We all need to find solace in our own way.
+
+That is why it started out with the narrator mocking the player character (PC)
+for his (in truth) often very poor and reckless choices (i.e. it's satire). But
+at the same time there are jokes that might make some people question the
+morality of the narrator, which is funny because it's the Devil. And yes, the
+narrator still has a different personality (than the PC). That's how it goes,
+and it fits in with the game very well.
+
+But an example is the seeming obsession (or is it?) with the daughters.
+These jokes however suggest that the PC is thinking these things but it also
+allows the players to wonder. The PC would probably be beyond wondering and
+probably accusing, especially given what is said and WHOSE daughters (in some
+anyway). The fact it's even brought up is often a sign of something that is
+being denied. Again there is some projection, gaslighting and plausible
+deniability, all of which is utterly absurd, even if it was a real person.
+
+Here's one:
+
+```
+ 🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂
+ 🐂 An ox looks at you funny so you eat 🐂
+ 🐂 him! 🐂
+ 🐂 🐂
+ 🐂 You're a sick, sick individual. You do 🐂
+ 🐂 know that, right? FIRST you BURDEN HIM 🐂
+ 🐂 WITH ALL YOUR RUBBISH and THEN YOU EAT 🐂
+ 🐂 HIM BECAUSE OF A FUNNY LOOK? And YOU 🐂
+ 🐂 DIDN'T EVEN SHARE HIM WITH YOUR FAMILY!🐂
+ 🐂 🐂
+ 🐂 What next, will you eat your daughter 🐂
+ 🐂 too? No! NO! NO NO NO NO! I SHOULD NOT 🐂
+ 🐂 HAVE SAID THAT! NO! DON'T EVEN THINK 🐂
+ 🐂 ABOUT TOUCHING HER! BACK OFF!! 🐂
+ 🐂 🐂
+ 🐂 SHE'S MINE!!! 🐂
+ 🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂
+```
+
+What does that even mean? It is probably sanctimonious hypocrisy whatever it
+means but there are many different meanings including even cannibalism like the
+player character (PC) is being accused of himself/herself/themselves. That
+possibility was **VERY** intentional. And yet: how could a thing that does not
+exist even have any person or thing at all?
+
+Another one that might be even worse but still ambiguous and accusatory in a
+sanctimoniously hypocritical way:
+
+```
+ 💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰❌💋
+ ❌DON'T BE ABSURD! You don't have that kind of money. ❌
+ 💰In fact, one of your daughters told me JUST LAST 💰
+ 💋NIGHT that ONCE AGAIN you had a delightfully sinful 💋
+ ❌night! NO! I KNOW WHAT YOU'RE THINKING! NOTHING ❌
+ 💰HAPPENED BETWEEN US! STOP THAT RIGHT NOW, YOU 💰
+ 💋FILTHY SINNER! 💋
+ ❌ ❌
+ 💰Hmm...although...now I think on it, I'm starting 💰
+ 💋to wonder... OH HELL! NO NO NO! What if she seduced 💋
+ ❌me and we DID DO something? That would be AWFUL, ❌
+ 💰JUDGING YOU WHILE HAVING AN AFFAIR WITH ONE OF THE 💰
+ 💋WOMEN! Still sure WE'D NEVER SIGN THE DEVIL'S BOOK! 💋
+ ❌ ❌
+ 💰Although...I don't really remember WHAT we did last 💰
+ 💋night... ANYWAY, KEEP US OUT OF IT YOU MONSTER! 💋
+ ❌ ❌
+ 💰The book has a cost and money doesn't grow on trees. 💰
+ 💋Perhaps it might grow on horns though? Ask the Devil 💋
+ ❌for help. Assuming he helps MONSTERS. ❌
+ 💰💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰💋
+```
+
+That's one that makes the player think the narrator is losing his mind (but
+of course mind is subjective here) and is now starting to wonder if what he
+thinks is going on is really going on. Yes that is a ridiculous idea. That's
+what often makes satire. Obviously this could not happen. That's the point.
+
+But he's still trying to ridicule the player character (PC) for signing the
+Devil's (HIS) book, all the while denying what 'he' might have 'done' (or
+'did'), only to then question it again. That is to mess with the PC's head even
+more.
+
+The question of 'what she did' is up to interpretation as it could also be the
+narrator who 'did something "questionable"' (that's how I would interpret it -
+projection - but I deliberately worded it in a way that it could be something
+else entirely) and he's trying to justify and deny his behaviour all the while
+criticising the PC, calling them a monster.
+
+Of course in truth the narrator, not being a real person, is just saying all
+these things to mess with the PC's head, so obviously even if there are
+daughters nothing is going on with them (though if one wishes to imagine
+otherwise for some reason, they certainly can).
+
+The reason the narrator is so unhinged is because he's playing games with the
+PC. Or maybe he already was. Who can tell? How can a being that doesn't exist be
+unhinged though? Here's one that is even more ridiculous:
+
+```
+ 🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂
+ ❌You have run out of oxen and must walk. ❌
+ 💋Better buy more... IF YOU DIDN'T WASTE MORE 💋
+ 🐂MONEY ON MORE SINFUL NIGHTS, like your 🐂
+ ❌red-headed daughters told me last night, ❌
+ 💋assuming they weren't LYING to me. 💋
+ 🐂 🐂
+ ❌AND YES. A dirty mind IS a TERRIBLE thing to ❌
+ 💋waste BUT NOTHING HAPPENED BETWEEN US!! We're 💋
+ 🐂JUST FRIENDS and they've been telling me ALL 🐂
+ ❌ABOUT YOUR RIDICULOUS BEHAVIOUR. OK, it MIGHT ❌
+ 💋be in bed with them but they can't help 💋
+ 🐂themselves...kind of like you. WHERE do you 🐂
+ ❌think they got it from? Besides, IF YOU KNOW ❌
+ 💋THE DEVIL in the biblical sense WHY SHOULDN'T 💋
+ 🐂WE? We EXPRESS PASSION and YOU ARE JUST AN 🐂
+ ❌EVIL MONSTER!!!!👹 Good luck hauling your ❌
+ 💋wagon! WE'RE TAKING A PLANE!! 💋
+ 🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂
+```
+
+Even if there is that older humorous (which is part of why it's there - and even
+more ironic given who the narrator is meant to be) phrase: it goes from
+accusation to denial to practically admission to justification (and explanation)
+to - a plane?
+
+That's obviously totally bogus. Even if the narrator was real he certainly could
+not be trusted. That was useful in some cases as code could be different.
+
+And of course it's all meant to mess with the player character's (PC's) mind
+(and in a way, by extension, the player's head, but that's how it goes with all
+games, even though the narration is about the characters in the game).
+
+That they (the PC) do not really understand the narrator is not real, would mess
+with their head even more (although yes in some cases people can be aware
+hallucinations are not real, in this case the PC is not aware of it). But of
+course the devil is not real, despite what the jokes say.
+
+Obviously the narrator is not going anywhere here and neither is anyone else,
+except of course that the PC is going to end up in hell, which means so is the
+narrator, in a sense anyway. Well actually they're already there, aren't they?
+:-)
+
+Note it says 'wagon', not wagon train, but that itself is nonsense, as there
+were always wagon trains. But of course the idea of an aeroplane is what makes
+it really ludicrous - intentionally so. Even if the narrator was real, this
+would be over the top. The PC does not really know this though.
+
+There are others that suggest the exact opposite of what is suggested here and
+some in between, which makes everything more balanced and suggests the narrator
+truly is unhinged and untrustworthy (and unbalanced), which of course he
+actually is.
+
+Of course...the red-headed part: some people consider redheads unlucky (for some
+reason) and we might say that the character is indeed unlucky. Here's one more
+on that theme:
+
+```
+ 🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔
+ 🍟Uh oh. THERE'S ANOTHER ELF! You must be 🍟
+ 🍔losing your mind my friend! ELVES DON'T 🍔
+ 🍟EXIST, unless you ask a German. They can't 🍟
+ 🍔even count to 11 without claiming there are 🍔
+ 🍟elves! Neun, zehn, Elf ... I guess I might 🍟
+ 🍔be losing my mind too! BETTER SHOOT THE ELF 🍔
+ 🍟BEFORE IT TAKES YOUR DAUGHTERS AWAY AND EATS 🍟
+ 🍔THEM! You might need them for food later on, 🍔
+ 🍟you HORRIBLE, HORRIBLE MONSTER. They are 🍟
+ 🍔heavenly women and are not for evil Devil 🍔
+ 🍟worshippers to eat! NO. NOT FOR ME EITHER! 🍟
+ 🍔Stop going there you sicko! They are NOT food 🍔
+ 🍟and YOU CANNOT GO TO HEAVEN, YOU DEVIL 🍟
+ 🍔WORSHIPPING MONSTER! Cut it out. NO! NOT THEM!🍔
+ 🍟STOP WHAT YOU'RE DOING!!! 🍟
+ 🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔
+```
+
+...with more wordplay of course, this time with a bit of German (for the
+uninitiated 'elf' is how you say 11 in German and the narrator was counting
+'nine, ten, eleven ...'). And the reference to being heavenly women and 'do not
+go there' (the thought about eating) and 'you cannot go to heaven' is a
+reference, of course, to the player character (PC) having signed the Devil's
+book - and the PC always going to hell (which is also baked into the code with
+`goto hell;`), which ironically means so is the narrator.
+
+The narrator saying 'not for me either' has a number of interpretations and it's
+probably not what you think (but I don't want to say so you can interpret your
+own way). The caps stresses panic and haste. Of course...the Devil would, one
+would assume, take them if he really wanted to.
+
+There are other examples that show a totally unhinged narrator who enjoys
+mocking and accusing the player character (PC) of being a horrible person all
+the while the narrator is - well you know who he is.
+
+
+
+### Data file versions
+
+
+By versions I mean for different systems and purposes. The following programs
+compiled from prog.c/prog.alt.c exist:
+
+- `prog` - uses emoji data file (`data` built from `data.src`) with wider text
+(in some cases - it was hard to maintain three files and with emojis it can
+easily happen that strings are too big).
+- `prog.scrnshot` - uses screenshot friendly emoji file. This makes it harder
+to follow all the jokes (compared to the other one), because of the game
+flow. The other version still has some of this but more of the strings are wider
+so it's less of an issue, depending on monitor size of course. Uses
+`data.scrnshot` built from `data.scrnshot.src`. Oh and prompting for pressing
+return between every string is REALLY annoying and ruins the fun so that was
+obviously not a good choice for any mode.
+- `prog.asc` - uses the ASCII only data file `data.asc` (built from
+`data.asc.src`). For systems that don't support any emojis or some or all of the
+emojis I have used (or if there is some sort of problem with formatting due to
+emojis on your system).
+- `prog.alt` - uses same data file as `prog` but is the [prog.alt.c](prog.alt.c)
+version - a few more events though I think with less obfuscation (does not mean
+it's not obfuscated, though it is less obfuscated).
+- `prog.alt.scrnshot` - like `prog.scrnshot` but is the alt code - a few more
+events.
+- `prog.alt.asc` - like `prog.asc` but is the alt code - more events.
+
+See below under [emojis](#emojis) for more details on the ASCII/emojis issue as
+well, for the reasoning behind these different versions.
+
+The extra file, the screenshot one, is more for personal amusement, but some
+friends quite enjoyed those I shared too. I realise the `data` one does not
+always have text wider but this could be good too; it was hard to find a nice
+width and it depends on the screen as well. Actually the ones that are not as
+wide tend to be those with emojis. Sometimes it was possible to make them wider
+but not always, due to how the data file works, and how I can store close to
+200 `char *`s in a single flat `char *` - which I discuss in
+[obfuscation.html](obfuscation.html)).
+
+In the [scrollback](#scrollback) section I do describe, though untested, how to
+have scrollback at the console, at least for linux.
+
+I used vim and merged the lines for the ASCII only and default emoji one and set
+textwidth to some value, possibly 80, as I didn't want to assume a wider screen,
+but still have it a fair bit longer than the screenshot friendly one. As noted
+this was harder with some of the strings that include the emojis due to the fact
+that emojis take multiple bytes. I did observe late in the game that some
+messages are wider than 80 (I fixed those) so some might be a bit longer. It is
+dangerous to make too many edits.
+
+If one uses the `addpadding` tool correctly (which I describe later and also in
+the obfuscation file) they can make their own strings providing that the strings
+are not too long and are designed correctly.
+
+Actually see the next section [on making your own theme](#new)...if nothing else
+for a simpler explanation of how they work (the obfuscation file discusses it in
+much more detail).
+
+
+
+### Making your own data files
+
+
+I alluded to the fact that you could make your own theme, though this might
+prove hard to find a theme with matching code, unless you reimagine some of it
+to make it valid (kind of like I have done with a lot of it). Perhaps
+Middle-earth? Or perhaps an actual Oregon Trail without the pact (but of course
+how do you justify the amount of money, the `goto hell;`, the cost of the doctor
+etc.?)? Or maybe real life (whatever that is :-) ) outside the trail? :-) Or you
+could try and modify the code. If you dare.
+
+Anyway this might be a simple way to understand the data file - though
+[obfuscation.html](obfuscation.html) explains more. If you were to do this you would
+have to edit the source files and use the `addpadding.c` tool that I describe in
+[obfuscation.html](obfuscation.html) - though the Makefile should help there.
+
+Make SURE you're editing the SOURCE data file(s)! Don't get rid of the NUL bytes
+or the BEL bytes! And don't get rid of the '%' in strings either. MAKE SURE
+those bytes (the BEL byte and the '%' - when it starts with one) are the first
+byte in the string. If the '%' is in the string elsewhere then obviously keep it
+where it (or they) are. There are multiple reasons for it being the first
+character - all by careful design.
+
+Remember that if the code (prog.c/prog.alt.c) refers to a bad location it can
+crash or do something unexpected! This also happens (see below) if a string is
+too long (it will show strings wrong at the best case). That's why I wrote all
+those extra tools and carefully designed it all. These are described in
+[obfuscation.html](obfuscation.html).
+
+Other points:
+
+- KEEP THE ORDER THE SAME! Do NOT add strings in between others! Just edit
+strings that are appropriate for the code in the game (see next part).
+- Edit the APPROPRIATE STRINGS so that the code will do the right actions. You
+can start out by looking at [strings.loc.txt](strings.loc.txt) so you can
+compare in code. Then you can find that string in the source data files and edit
+it to your liking. Of course this depends on if you can figure out the code (you
+might find [deobfuscation.html](deobfuscation.html) of some use too, although the
+[obfuscation.html](obfuscation.html) **might** be a better bet - not really sure)
+and if your theme will actually work with the code. That last part is critical
+of course, unless you want a baffling game.
+- Make CERTAIN the NUL/BEL bytes are not removed! Not doing this will cause
+problems.
+- The strings that do not end with a newline are that way because they are not
+supposed to print a newline. That means literal newlines are how you have a
+newline. This means there's no need for special parsing - a very useful thing.
+
+The strings have to be < 1663 in size. Use the `lencount -t -i foo.src` to verify
+that. It'll warn about any strings too long and also show you the longest
+string. Note that emojis can add a lot of bytes (using the `-t` option will exit
+non-zero if there is any problem, telling you to run without the option - that's
+used in the Makefile rule test).
+
+Next run `make makedata` which will do a couple important things including
+creating the data files from the source data files with the appropriate padding.
+Once that is done run `./printer` to print out the strings so you can verify
+things print out okay. You'll need scrollback of course.
+
+That's a kind of simplified explanation but hopefully you get the idea. A LOT of
+care was put in this and as long as you do it right it works and works well. But
+again that depends on if you can work your theme into the code[^2] and don't mess it
+up!
+
+It is admittedly EXTREMELY easy to mess up. One wrong deletion of the wrong byte
+or some other placement error, or something else entirely, and it can totally
+DESTROY EVERYTHING. It took **A LOT** OF WORK AND CARE in the design but it
+works brilliantly and is VERY effective. It allows for hiding data and not
+having to worry about length of strings (other than making sure no string is too
+long), having to worry about newlines/tabs/other characters etc. The encrypted
+submission is even better at hiding data.
+
+The way a single `char *` holds all the strings, is a brilliant
+trick that offers **SO VERY MUCH**.
+
+
+
+
+### Scrollback
+
+
+
+Although I haven't tested this, it should work. This is for people like me who
+might want to play this on the console, though I guess that's extremely
+unlikely. This is for linux. I have no idea how to do it for other systems,
+although the use of screen/tmux might be fine.
+
+First, for linux, without screen or tmux. Assuming that framebuffer is enabled.
+If that is the case you should be able to use: shift + PageUp / shift +
+PageDown.
+
+Otherwise, or if you can't use the key combinations as above, you should be able
+to run this with screen like:
+
+```
+ screen ./prog
+```
+
+then in the game, when you need to scroll, press Ctrl + A, then [. Then you can
+use the arrow keys or PageUp (maybe PageDown too, not sure). Exit with ESC.
+
+For tmux:
+
+```
+ tmux
+ ./prog
+```
+
+Then press Ctrl + B and then [. Use the arrow keys or PageUp (maybe PageDown,
+not sure). Exit with 'q'.
+
+
+
+
+### Vomitory
+
+
+
+The judges say they **LIKE** (all caps and in bold is **THEIR** doing!) programs
+that:
+
+> make us laugh and/or **THROW UP** :-) (humor really helps!)
+
+Yes I made the THROW UP bold and capitalised. But anyway: vomitory and
+vomitorium are both real words but they mean something else; in the case of
+cannibalism though, it might be more literal (okay one of the definitions
+relates to supposed vomiting).
+
+Yes it can be uncomfortable for a lot of people but the judges did ask for it!
+:-) Besides, it's on theme and also it happened (on other routes too - for
+example the Donner Party). But there are a lot of jokes on theme (and perhaps
+some not quite on theme) to go along with it.
+
+Of course usually (!) in real life (remember that? The author no longer does) it
+happens due to an act of desperation and it's not a funny thing. Nor is it
+something I would want to have to do but the will to survive is incredibly
+powerful and the truth is nobody really knows what they might do until they are
+forced into such situations. And it indeed is something that would make many
+people throw up (probably myself included and I hope I'm never tested): exactly
+as the judges LIKE! You're both welcome! :-) Apologies to anyone else who does
+not like it.
+
+Unfortunately (or not?), the judges asked for it and reality delivered.
+
+
+
+### Emojis
+
+
+(Related is the [different types of data files](#versions) and
+[portability](#portability).)
+
+First of all: on the dysentery (which has some uh..fun..emojis), as noted that
+came later on in the graphics version (later on certainly, possibly not until
+the graphical version). But the version my code is originally inspired by is the
+BASIC version of 1978: not only no dysentery but no graphics. There are some
+lovely things about the emojis instead (I do have a way to play without them as
+noted).
+
+The many benefits of emojis (besides the fact that even if it was on theme it
+would be likely copyright violations but I am also not an artist and mine is way
+funnier and a very different game anyway) and ASCII art:
+
+- it supports terminals (yes some terminal emulators **CAN** display graphics
+but this is not portable to all terminal emulators, just like not all systems
+can display emojis in the terminal).
+- it does not need a graphics library.
+- it increases the irony in jokes (most of the messages with emojis have emojis
+that actually enhance the joke or jokes, though not all, and some are probably a
+bit esoteric, just like some of the jokes without emojis).
+- it still allows for a visual feel - it's a mixture of imagery and text which
+is a nice change (even if the graphical version obviously has text this is
+different).
+- it's more unique (and depending on submission, it's even cleverer: the
+encrypted version encrypts emojis).
+
+
+
+### The issue of scrollback
+
+
+There is only one downside to the longer messages and sometimes emojis. Because
+it is somewhat artistic (in some cases a lot) some people (in particular the
+author) might want to take screenshots: the content of the jokes are quite good
+and all those I have shown them to agree, though of course they have my sense of
+humour too.
+
+But for screenshots to be easy to read with rubbish vision the text
+has to be not so wide, otherwise it's hard to see, as noted before. This makes
+it much more likely that events can be missed including many jokes. BUT that
+brings up the issue of scrollback and the wider (default) data file. This is why
+the default file is one that is wider though.
+
+If one does not use the wider versions however they should use a terminal emulator
+with scrollback. This still can apply in some cases with the wider version
+though (see below).
+
+For some messages due to the emojis I had to make the lines a bit shorter as the
+blocksize was surpassed; that happened **many** times and required edits. As I
+noted above in [versions](#versions) how to play without emojis or for
+screenshot friendly messages, I won't say them again here.
+
+As for the issue of requiring scrollback and whether this is bad or not. I will
+say that the jokes require it and with how events stack on top of each other.
+Often they are related: say because you get injured and you see the doctor. Or
+Blackbeard attacks (yes really) and you either scare him off or you get robbed
+by him. If you get robbed by Blackbeard you might also need to see (or try and
+see) the doctor which is also another message. If you're in the mountains you'll
+have the mountain events too, unless of course you get injured - then you go
+straight to the doctor and lose a turn (in essence), or so I think I did that.
+
+This is all unfortunate but it's necessary (see below).
+
+I tried to make the default file a bit better but this was harder with emojis. I
+will however point out that **other** text based games of old also had this. It
+was simply part of the game: a feature, not a bug, not a defect. It had to be.
+
+Text based games with combat messages are a **CLASSIC** example. And in those
+cases you likely would miss most of it as you have to focus on what is going on,
+in case you need to heal yourself or cast a spell or perform some ability or
+attack. Plus messages that are related to combat, characters (PC/NPC)
+entering/leaving, weather and all other kinds.
+
+This also applied to when travelling long distances. When in combat or quickly
+travelling you might also miss messages from other players (when it was
+multiplayer). It was easy to not see all messages in other cases too, as it was
+all live.
+
+In fact they often had a brief mode so you didn't have to see as much (also
+helpful over networks in the earlier days). Here though you get prompted after
+the mountains event (or if you haven't got to the mountains yet then after the
+events) so there is always a pause at some point (until game over of course) so
+in the cases the messages are longer you can just scrollback if your terminal
+emulator supports it (just like with other games, including some of those I just
+referred to).
+
+Even some graphical games that have messages have this problem! This is
+not really a limitation of the game though - it would spoil everything if it did
+not happen. So make sure to play with scrollback!
+
+Now what about workarounds? Well if the game had you press a key between each
+part of the output it would get boring **really fast** and so that's obviously
+the wrong choice. It would also be **EXTREMELY** annoying and that is just as
+bad if not worse.
+
+Another issue was determining the right width to have. Sometimes the lines might
+be longer than others, although I did try to minimise this. Remember the
+blocksize is key as well. This might seem odd but trust me when I say it: longer
+lines can in some cases actually increase the length of the messages
+(especially, obviously, with emojis).
+
+The blocksize is one of (not the only) keys in how I could have near 200 `char
+*` in a single `char *`, something I have never heard of before, and as there is
+more to how I did this it is even more interesting than that. I discuss it more
+in [obfuscation.html](obfuscation.html) for the interested.
+
+So just make sure to play with scrollback and make sure to check if you're
+unsure. It's worth it and a small price to pay for a fast paced game - and it's
+not any different from older text games (and graphical games with text that
+scrolls by), except that you at least do get a pause in this game, unlike many
+of those older games.
+
+
+
+### Alt version of the code: the Devil's Cut.
+
+
+Okay so I briefly mentioned the alt version but there's more to it.
+
+Why 'Devil's Cut'? As you might have guessed this is a joke (and a pun), namely
+because the first one I added to it was the you have lost a limb so you get free
+food; if you run into that event more than three times you die - I think up
+to three times i.e. on the fourth you die, not the fifth, but perhaps not. But
+when you die from it you can die happy knowing your family gets a free meal
+though of course the game is over at that point.
+
+There are several other events at the bare minimum or at least there were; as I
+continued to optimise the code size I got more in: but not all. But
+unfortunately due to the obfuscation it's hard to be sure what is where. I do
+know that limb loss one (though there's a similar one that is in the submission
+code but not one that causes a death) is not in the submission code.
+
+It uses too many bytes. As noted (and as you would see if you looked) the
+submission code got way more obfuscated than the alt code but there were it felt
+better to add more obfuscation than to add even more events as it already has
+more. I think the alt code has 25 events and the submission has 23. That's not
+even counting the mountain events or the events that are part of other events!
+
+Realistically I could even get rid of the alt code but since there are more
+jokes there I am keeping it. In any case 23+ is plenty.
+
+
+
+### Additional thematic references in code and data
+
+
+The hp/stamina `b` starts out at `666`. The money starting at $6666 (well $1666
+after a 'sinful night'):
+
+```
+ T=1666-O-R-E-G-0-N;
+```
+
+The `-0` uses two extra bytes but it's totally worth it, even though I could
+have even more `goto`s (see the [obfuscation.html](obfuscation.html) for that
+madness). You might say the `1666-O-R-E-G-0-N` is saying subtracting from one
+devil Oregon. Or you might say something else. But of course 1666 is described
+in the first game string:
+
+> This program simulates a trip over the Oregon Trail from Independence,
+Missouri to Oregon City. Your extended family will attempt the 2170
+mile Oregon Trail in 5-6 months. You had $6666 for the trip foolishly
+wasted thousands on a sinful yesterday and you've paid $200 for a wagon
+train, leaving an ominous $1666. You may buy the following items, or not,
+if you trust the Devil to be faithful to your pact:
+>
+> ...
+
+This not only foreshadows the theme more (sinful, `$1666`, `$6666`) but it sets
+the stage of the game basically immediately, pointing out that some strange
+things might very well happen (as they do, including things that are definitely
+out of the norm including out of the norm of reality, but that makes it all the
+more fun).
+
+So obviously `T=1666-O-R-E-G-0-N;` is part of checking if you overspent,
+although it's also done in another place (the fort) in another way (due to
+having to make sure I don't overwrite the amount of money left, though I did do
+this with the amount of bullets).
+
+Another thing is that like the hp starts at 666 so too are you only allowed to
+spend `>= 0 && <= 666` on each item (I will return to this in another fun way).
+
+Another one that does not quite spell out OREGON precisely but it is close
+enough, at least part of it, and in an amusing way:
+
+```
+ printf(&y[Z(11)],R,E,G,O,N,T,b,M);
+```
+
+...which is also funny in a kind of childish way because it could, if you
+interpret the `(11)` as an `O`, spell out OREGON T BM or Oregon Trail BM - like
+dysentery perhaps? Even if some might call it childish how could I not point it
+out for a game that is almost identified by dysentery? That would be the real
+scandal!
+
+Oh and there's this one too:
+
+
+```
+ O=R=E=G=N=0;
+```
+
+which not only almost spells out `OREGON` but it is as if it's setting it to 0,
+which might be a foreshadowing of the final act of the game. Why not have:
+
+```
+ O=R=E=G=O=N=0;
+
+```
+
+? Oh do I wish I could do that! Unfortunately that would be multiple unsequenced
+modifications to `O` which is UB.
+
+So as you can see between the `V` function (based on the blocksize), the code (in
+multiple places), the starting hp, the data file and even layout of variables to
+spell out `OREGON TRAIL TRAIL OREGON` (and rather `rude OREGON TRAIL TRAIL
+OREGON`) this is full of thematic references to what the program is (and in some
+cases what it was)!
+
+This all took a lot of care in calculating things, manipulating values and much
+more. Throw in all the many jokes (many of which are utterly ridiculous) and
+you have a really fun submission!
+
+Of course there's also the `hell` label and many of the strings in the game
+refer to the devil and the player character's (PC's) pact. The `goto hell` is
+discussed more in the [Humour](#humour) section, as well as perhaps the
+[obfuscation.html](obfuscation.html).
+
+And here's a fun one: did you notice the code actually spells out `ox` (well
+okay it has an upper case `x`)? Some examples:
+
+```
+ S(100,*(o[X]))if(*o[X]<0||*o[X]>666)
+```
+
+And comparing it to (>) 666 too...does that hint at a sacrifice? Well it might
+just indeed, as shown earlier. Even more so: beast of burden being sacrificed?
+Not cool (is where the player character (PC) goes 'cool' though? I heard there's
+no air conditioning there either.).
+
+And as a reminder: 666 is the max you can spend on any one item at a time:
+**including** oxen! So it's comparing an ox to 666 (some say the 'number of the
+**beast**, which this is a beast) and it's also the maximum value you can spend
+on it. Does that make your ox(en) the Devil? You decide! :-)
+
+The cultural reference to [Robert
+Johnson](https://rockhall.com/inductees/robert-johnson/) and the crossroads,
+legend though it obviously is, is also a thematic thing, but that comes in the
+cultural reference section instead of here, even though it fits in both places.
+
+The Samuel Parris reference also fits in with the theme of course. And of course
+it's ridiculous as it's centuries before. Not by any means the only place! There
+are numerous in the far future and some in the far past as well. I show this
+more later (I think).
+
+The heaven joke described in [obfuscation.html](obfuscation.html) is also thematic.
+
+The program does `return 666;` to further add to the theme even though the shell
+likely won't report such a high number and it would make the command 'fail'.
+This is why though I added the `-` to the Makefile `try` and `try.alt` rules.
+
+According to `wc -c` in macOS the file is 4666 bytes: a common theme in the code
+(particularly the last three digits).
+
+Also did you notice the `heaven` is right below `666`? Not only that but a bit
+further down is 666 again right under heaven (tried to align it but might not be
+perfect)!
+
+All of these tie beautifully to the theme of the game and there are, as noted
+elsewhere, more.
+
+
+
+### Humour
+
+
+Notice the `goto hell` part for the death of the player character (PC). Or
+winning the game (what is winning in this case? - see below). This is a play on
+the fact that original Oregon Trail (and my game is even worse) is a goto hell
+spaghetti code and my joke in the [obfuscation.html](obfuscation.html) file (not to
+mention the joke of using the obscene amount of `goto`s in a single small
+program (see the obfuscation file for more on that as well as [concluding
+remarks](#conclusion)).
+
+The message is full of irony for added effect, namely the 'WELCOME TO HELL!' and
+calling it your forever home, plus god wishing you a prosperous life ahead.
+
+Did you also notice that even when you win the game you will die and `goto
+hell;`? Why I did this: we all do die and although I don't believe in the
+afterlife it is amusing to me especially as it IS goto hell! There's a great
+joke in there, riddled with irony, but let's be honest: although I guess some
+did survive after they made it, so many deaths occurred and many probably
+arrived but sick so why not? :-) And of course obviously the player character
+would go to hell: whatever that might be.
+
+When you 'win' another ABSOLUTELY ABSURD thing happens (before you go straight
+to hell): President Jesse James congratulates and wishes you a prosperous
+life...in HELL! Yes I know. I said this game is absurd but also funny as...hell
+(depending on your sense of humour of course).
+
+There's also a 'flat ox' (instead of an injured ox like in the original) -
+like a flat tyre. This is a reference to the brilliant American sitcom series
+Miracle Workers, in this case series (or if you prefer season) 3: Oregon Trail.
+As I recall in that show the ox is actually female: also ridiculous if so.
+There's another one, about a bald eagle, as well.
+
+Another one is from a different year of The Miracle Workers, this one the Dark
+Ages. The character is in uni. Yes all years were extremely ridiculous and full
+of satire; the first year had Steve Buscemi play 'god' (a complete moron and he
+played it brilliantly as you would expect) who decided to blow up Earth (and
+that's all I'll say). Anyway in Dark Ages there was the line:
+
+> The Earth is flat. The devil is real. The Sun is crazy. And that is everything
+we know.
+
+but the message I have here is a twist, although it has some of the above too
+(as hinted at earlier). (And yes this could also be in culture since for reasons
+beyond my comprehension some people actually do believe the Earth is flat and
+the other things too ...)
+
+Now this one I could put in [obfuscation.html](obfuscation.html) but it's also
+humorous even though it ties in well with the obfuscation. In 1957 on April
+Fool's Day the BBC played a hoax on a factual programme (Panorama) that there
+were spaghetti trees. Some were upset for this in the factual programme and
+others were eager to find out where they could get a spaghetti tree themselves!
+
+To those who might think those who fell for it are ignorant: on the contrary, in
+the UK spaghetti was not commonly eaten and it was considered an exotic
+delicacy. Here is an article on it:
+
+and here is a video on it: . There
+is another one that has people who actually replied, some amused with jokes and
+others wanting to know more (or I recall this).
+
+Now how this ties into obfuscation is that this code is spaghetti code to the
+degree I have never seen, aside maybe from BASIC (as noted earlier) - but this
+is not a BASIC contest (thank goodness) and I made it worse (maybe not
+thankfully). Although....mine is even worse so I shouldn't say much on the BASIC
+one now. Anyway to see how this really fits in humour this is what the event
+looks like:
+
+```
+ ~~~~~~
+ / 🍝🍝🍝 \
+ / 🍝🍝🍝🍝🍝 \
+ / 🍝🍝🍝🍝🍝🍝 \
+ | 🍝🍝🍝🍝🍝🍝🍝|
+ \ ||| ||| /
+ \ ||||| /
+ \ ||| /
+ \__________/
+ || ||
+ || ||
+ __||__||__
+ WOW!!!! THAT'S A SPAGHETTI TREE!!! I saw
+ them over 100 years from now when I last
+ used my Time Machine!! The BBC will
+ cultivate them on April Fool's Day 19579!
+ THEY'RE AMAZING!! The Time Machines are
+ okay and kind of interesting. Dangerous
+ though...
+
+ But the spaghetti looks pretty ominous,
+ doesn't it? IT LOOKS LIKE IT WANTS TO REACH
+ DOWN AND GRAB YOU! Better be careful. If they
+ strangle you YOU WILL GO TO HELL! On the plus
+ side... YOU'LL HAVE THE MOST AMAZING STORY to
+ tell your fellow sinners... Trust me. I've
+ been there on holiday! It's PRETTY WILD!!
+ Summers are AMAZINGLY HOT!! Although...GETTING
+ EATEN BY A DRAGON OR KILLED BY TYRANNOSAURUSES is
+ an EVEN BETTER STORY! That's MUCH MORE
+ EXCITING than a SPAGHETTI TREE KILLING YOU!!
+ Although...now I think on it...they're ALSO
+ in Hell so maybe it's better if the spaghetti
+ kills you. Want me to strangle you with it if
+ it doesn't do it? Of course...the trees are
+ there too...LOTS of parties too. And good old
+ TORTURE! IT'S AWESOME!
+```
+
+...and of course the going into the future and saying 'will' instead of 'did' or
+'have' only adds to the absurdity, as does 'I saw them over 100 years from now'
+as does the suggestion that (of course) the time machine doesn't exist yet (the
+only time machine is the clock and other things to tell the time and I hope
+that's how it remains): playing into the time travel paradoxes/problems.
+
+But when I thought of this I knew I **HAD** to put this event in as if any event
+fits in the code it is this one: and there are many others too that are thematic
+to parody; this is a reference to the code itself and being `goto hell`. And of
+course the 'YOU WILL GO TO HELL!' is exactly referring to that AND it also is
+true of the player character (PC) when the game is done (whether they win or
+not). The torture being awesome came towards the end. I might be disturbed in
+more ways than you can know but if you see the number of `goto`s in
+[prog.c](prog.c) that will come as no surprise.
+
+There is also a reference to the Flying Spaghetti Monster although the question
+you have to ask is how often (or does it?) this will trigger. This is largely
+due to obfuscation and some seeming (but is it? Yes some is deliberately and
+others that might appear are not) dead code. Anyway the joke:
+
+```
+ 🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰
+ 🍝Not again. Are you REALLY going to tell me 🍝
+ 😈about the Flying Spaghetti Monster AGAIN? 😈
+ 🪰I've had ENOUGH of your FAIRY-TALE DELUSIONS! 🪰
+ 🍝YOU'VE TOLD ME HE IS INVISIBLE SO HOW IN THE 🍝
+ 😈HELL CAN YOU EVEN KNOW HE EXISTS? 😈
+ 🪰 🪰
+ 🍝What next, are you going to tell me that 🍝
+ 😈between Earth and Mars there is a china teapot😈
+ 🪰revolving about the Sun in an elliptical 🪰
+ 🍝orbit? Let me guess! It's so small that even 🍝
+ 😈the James Webb telescope that was launched 😈
+ 🪰almost 200 years from now can't even see it, 🪰
+ 🍝right? What a load of ABSOLUTE RUBBISH! If 🍝
+ 😈your daughters were not here I WOULD TOTALLY 😈
+ 🪰BE ABUSING LALOCHEZIA AT YOU RIGHT NOW! 🪰
+ 🍝BUGGER ME THAT THEY ARE! 🍝
+ 😈 😈
+ 🪰If the Flying Spaghetti Monster ACTUALLY 🪰
+ 🍝existed, he'd eat you for lunch for blasphemy.🍝
+ 😈Hell, keep this up and I'LL eat you. I'M 😈
+ 🪰STARVING! 🪰
+ 🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝
+```
+
+and of course it also talks about something in the future (to say nothing else
+of the Flying Spaghetti Monster is far into the future too): the James Webb
+Telescope. It also refers to [Russell's
+teapot](https://en.wikipedia.org/wiki/Russell%27s_teapot).
+
+Lalochezia is catharsis from swearing btw.
+
+Some other funny things.
+
+The data file has some jokes that are totally unrelated to the game that might
+amuse some people. It also has some unused strings that were meant for the game
+but didn't fit in well.
+
+The game kind of has a darker sense of humour when you die and other things too.
+The emojis kind of make it even better. An example is when you freeze to death.
+Sometimes part of a message is repeated in another message but usually with some
+variation, likely a new joke (or jokes as is often the case).
+
+The idea of 'hell' is heavily engrained in the game in various other places too,
+including the freezing to death one (not only those messages but what follows
+them) and some that are rather explicit/direct.
+
+If you run out of food you'll eat an ox, if you have one (though 'one' is based
+on the original game due to the fact that otherwise one would have way more than
+realistic, given the amount of money the PC has). Otherwise you die if you don't
+hunt right away (hunt and succeed and succeed without a penalty - not saying
+more on that).
+
+In the original if you run out of food you die no matter what. Humans would
+definitely sacrifice their burden animal if they could to survive and it fits
+with the theme of the game anyway. Besides, you wouldn't starve to death
+immediately and depending on where you are you might find more food before that
+time. Actually there is another scenario when you're out of food if you have an
+ox. That also has ambiguous jokes and satire and it's an example that has part
+of another message, namely the one when you eat the ox simply due to no food
+left. You can even end up eating an ox even if you do have enough food! Yup that
+means you'd have to go to the fort again. Be money wise! The PC is not.
+
+So people can see what the winning scene looks like, full of irony, with the
+emojis, including something I already mentioned:
+
+```
+ You FINALLY arrived at Oregon City after 2170
+ long miles!
+
+ TOOK YOU LONG ENOUGH. Probably all your sinful
+ detours I've heard so much about but you'd think
+ that the Devil would have helped you out on that.
+ But I guess as long as you make it to your final
+ destination that's what matters, right?
+
+ Oh, right. Almost forgot! President Jesse James
+ asked me to wish you a prosperous life ahead of
+ you...in HELL!
+
+ 🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦
+ 🪦 / \ 🪦
+ 🪦 / A \ 🪦
+ 🪦 |TORMENTED| 🪦
+ 🪦 | MONSTER | 🪦
+ 🪦 | R.I.P. | 🪦
+ 🪦 |_________| 🪦
+ 🪦 GAME OVER 🪦
+ 🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥
+ 🔥Unfortunately, due to what can only be an 🔥
+ 🔥ADMINISTRATIVE FOUL-UP, you end up somewhere 🔥
+ 🔥you did not expect as your forever home. But 🔥
+ 🔥honestly, after signing the Devil's book, DO 🔥
+ 🔥YOU REALLY BELIEVE YOU DON'T BELONG HERE? Be 🔥
+ 🔥honest. For once. You know you belong here. 🔥
+ 🔥Oh, by the way, god asked me to wish you a 🔥
+ 🔥PROSPEROUS LIFE ahead... 🔥
+ 🔥 🔥
+ 🔥 😈😈😈 WELCOME TO HELL!! 😈😈😈 🔥
+ 🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥
+
+
+```
+
+That's only one of many other jokes. I'll share a few more here.
+
+```
+ Helpful Indians show you where to find
+ more food. Pizza, hamburgers, chips/fries
+ and other greasy, fatty foods ...
+ 🍕🍔🍟🥪🌯🌮🌭
+ Okay so IT'S ONLY A HEART ATTACK ON A
+ PLATE but at least you'll survive another
+ day...if you don't have a heart attack
+ first, that is... Better have your Doctor
+ Beelzebub check you out. If he's still
+ alive. Oh no.
+
+ You didn't eat him when you were starving
+ last time, did you? If so I hope you DO
+ have a heart attack!
+
+ 🧶🧶🧶🧶🧶🧶🧶🧶🧶🧶🧶
+ 🧶 Rugged mountains.🧶
+ 🧶🧶🧶🧶🧶🧶🧶🧶🧶🧶🧶
+```
+
+Yeah I put `chips/fries` to make it multi-locale.
+
+Anyway the above block is actually two events. Well an event and then the
+mountains code.
+
+Here's another fun one. If (I think it's triggered because of this) you don't
+have enough clothing at some point, perhaps mountains, perhaps not:
+
+```
+
+ 🔥🌨️🔥🌨️🔥🌨️🔥🌨️🔥🌨️🔥🌨️🔥
+ Phantom blizzard from Hell suddenly hits
+ and you freeze to death, leaving everyone
+ behind. You know the Devil 😈 is calling
+ you, right?
+
+ 🩳🩲👗👙
+
+ And with your choice in clothing, ARE YOU
+ REALLY SURPRISED YOU FROZE TO DEATH? I mean
+ SERIOUSLY mate, shorts, briefs, A DRESS AND
+ A BIKINI on the Oregon Trail? What the hell
+ were you thinking? You're not in Hell,
+ you're on the Oregon Trail!
+
+ Although...now I think on it...perhaps Hell WILL
+ serve you better? I hear the Summers are GREAT
+ there! Lots of parties. Winters are -- actually,
+ there are no winters. ONLY WEATHER TO BURN YOU
+ FOR ETERNITY.
+
+ At least your family gets fresh meat on the bone,
+ assuming they can stomach eating a horrible
+ monster. If I were them I'D BURN YOUR BODY.
+```
+
+Just to drill in the irony I chose the patronising use of the word 'mate' (not
+the only place this happens). Pretty sure that one of the freeze to death events
+is not in the game - it was redundant as far as I viewed it and having it would
+mean sacrificing another joke. Ironically the suggestion of burning the body
+would end up burning them too, though it would not matter at this point anyway.
+
+And here's the famous dysentery one:
+
+```
+
+ 💩💩💩💩💩💩💩💩💩💩💩💩💩💩
+ 🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽
+ 💩💩💩💩💩💩💩💩💩💩💩💩💩💩
+
+ You have died of dysentery.
+
+ CONGRATULATIONS ON REACHING
+ LEGENDARY STATUS!
+
+ 💩💩💩💩💩💩💩💩💩💩💩💩💩💩
+ 🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽
+ 💩💩💩💩💩💩💩💩💩💩💩💩💩💩
+```
+
+though made better and more ironic than the words of old. Obviously the
+legendary status refers to the iconic 'you have died of dysentery' which
+apparently has been turned into many memes. It's also absurd and ironic which
+you probably expect from me by now.
+
+Here's a great one:
+
+```
+ 🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂
+ ☔️ Hail storm--YOU WERE HIT ON THE ☔️
+ 🧢 HEAD and supplies were damaged. 🧢
+ 🌂 But did you REALLY think this 🌂
+ ☔️ CLOSED BROLLY 🌂 was going to ☔️
+ 🧢 help you against HAIL? Even this 🧢
+ 🌂 one ☔️ PROBABLY wouldn't do much 🌂
+ ☔️ good. YOU SHOULD HAVE BROUGHT A ☔️
+ 🧢 HAT 🧢!! 🌂 🧢
+ 🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂
+```
+
+To those who do not know a brolly is a British English term for an umbrella.
+Obviously the hat part is a huge joke as that would do absolutely nothing to
+protect your head and obviously it would do less good than a brolly. And
+obviously they would open the umbrella!
+
+Here's another ironic (and slightly disgusting maybe) one. It merges two that
+would go well together - dirty water and dysentery - and allows me to save bytes
+along with showing an ironic joke (and some puns too):
+
+```
+ 💦🚽💩💦🚽💩💦🚽💩💦🚽💩💦🚽💩💦🚽💩💦🚽💩
+ 🚽OH HELL! That water tasted REALLY 💦
+ 💩funny! No. Sorry. NOT Hell. There 🚽
+ 💦is no water in Hell! Well, wherever 💩
+ 🚽you are, it appears you drank 💦
+ 💩unpotable water and it's too 🚽
+ 💦late now. 💩
+ 🚽 💦
+ 💩Next time LOOK AT WHAT 💩 you intend💦🚽
+ 💦on swallowing BEFORE YOU SHOVE IT 💩
+ 🚽DOWN YOUR THROAT, because you now 💦
+ 💩have dysentery. 🚽
+ 💦🚽💩💦🚽💩💦🚽💩💦🚽💩💦🚽💩💦🚽💩💦🚽💩
+```
+
+And yes all the 'death' ones are followed by the 'unfortunate administration
+foul-up' one too, so that no matter what, if you finish (dying or not) you end
+up 'going to hell'. You're welcome to pun the unpotable if you want but I leave
+that to your imagination (though I probably just made it happen); it was not
+meant that way but it's an amusing coincidence - this came **long** before I
+even **tested** the idea of emojis, let alone thought of it, and it was only
+after that that I started making jokes.
+
+Here's a hilarious sequence that happened during a test play. The irony is
+lovely:
+
+```
+ Oh dear. That isn't the Barghest AGAIN is it? Better watch
+ your back! And front. And above you. Actually, YOU'RE DOOMED
+ and you know it. Your fate was sealed upon signing the Devil's
+ book. Honestly, what were you thinking? You HAD to have known it
+ always comes with a cost. And you and I BOTH KNOW that the women
+ were warning you - but you just HAD to have your way, didn't you?
+
+ Well the Oregon Trail is out to get you in every direction and
+ the odds are you won't make it out alive. You might be in good
+ company there, AND YOU AT LEAST GET TO SEE DINOSAURS ALIVE (LUCKY
+ YOU!!) BUT THERE'S NO AIR CONDITIONING and I heard it gets REALLY
+ HOT down there. Then again, I also heard there's no heater in
+ Heaven... Yup, either way YOU'RE DOOMED AND YOU KNOW IT! But don't
+ feel too bad. At least you won't FREEZE TO DEATH. You might here
+ though... Yup, FREEZE TO DEATH HERE and then BURN TO DEATH THERE!
+
+ 🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖
+ 🦖 A GROUP OF TYRANNOSAURUSES ATTACK! 🦖
+ 🦖 🦖
+ 🦖Unfortunately for you, you're in a time 🦖
+ 🦖LONG BEFORE the brilliant mathematician 🦖
+ 🦖Ian Malcolm informed us that DINOSAURS 🦖
+ 🦖FIND A WAY TO KILL HUMANS. You should 🦖
+ 🦖have thought of that BEFORE you STUPIDLY 🦖
+ 🦖climbed into that Time Machine to travel 🦖
+ 🦖back in time to the Oregon Trail, where 🦖
+ 🦖you could not possibly know so many 🦖
+ 🦖important things about dinosaurs... 🦖
+ 🦖 🦖
+ 🦖ALTHOUGH, now I think on it, that MIGHT 🦖
+ 🦖not have been EXACTLY how it went... I 🦖
+ 🦖THINK the correct wording was 'LIFE FINDS 🦖
+ 🦖A WAY' but that's well over 100 years from🦖
+ 🦖now and instead of life finding a way the 🦖
+ 🦖Devil will find a way. To torment you. 🦖
+ 🦖With more dinosaurs. And dragons. Yes 🦖
+ 🦖they still exist. Oh and the Earth is 🦖
+ 🦖flat too... 🦖
+ 🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖
+
+ 🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦
+ 🪦 / \ 🪦
+ 🪦 / A \ 🪦
+ 🪦 |TORMENTED| 🪦
+ 🪦 | MONSTER | 🪦
+ 🪦 | R.I.P. | 🪦
+ 🪦 |_________| 🪦
+ 🪦 GAME OVER 🪦
+ 🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥
+ 🔥Unfortunately, due to what can only be an 🔥
+ 🔥ADMINISTRATIVE FOUL-UP, you end up somewhere 🔥
+ 🔥you did not expect as your forever home. But 🔥
+ 🔥honestly, after signing the Devil's book, DO 🔥
+ 🔥YOU REALLY BELIEVE YOU DON'T BELONG HERE? Be 🔥
+ 🔥honest. For once. You know you belong here. 🔥
+ 🔥Oh, by the way, god asked me to wish you a 🔥
+ 🔥PROSPEROUS LIFE ahead... 🔥
+ 🔥 🔥
+ 🔥 😈😈😈 WELCOME TO HELL!! 😈😈😈 🔥
+ 🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥
+
+```
+
+It is as if the gods wanted it to happen that way: dinosaurs referred to being
+in hell, then dinosaurs eating you and then you end up in hell.
+
+
+
+
+### Cultural references
+
+
+
+Besides those mentioned in [Humour](#humour) above (such as the Miracle Workers
+show) there's another one (also with an amusing message) that refers to culture,
+though obviously a legend and not a real story:
+
+```
+ You got lost, losing valuable time asking
+ the Devil 😈 for directions to the
+ CROSSROADS ❌☦️ ⚠️ 🚸.
+
+ But honestly, HOW DID you get lost? It's
+ practically a TRAFFIC JAM OUT HERE AND
+ ONLY A COMPLETE MORON COULD LOSE THEIR WAY.
+
+ HISTORIANS WILL BE TALKING ABOUT THIS YEARS
+ DOWN THE TRAIL! OH NO. WHAT DID YOU DO THIS
+ TIME? You did do something didn't you? I KNOW
+ you did! You ALWAYS do something stupid!
+```
+
+This is a reference to [Robert
+Johnson](https://rockhall.com/inductees/robert-johnson/) and his having
+supposedly sold his soul to the devil (which I probably don't have to remind you
+is part of the theme of this parody, though not to do with music) for musical
+talent. But there is another reference here. From this article [9 myths you
+learnt from playing Oregon
+Trail](https://www.vox.com/2015/2/6/7987697/oregon-trail-game-real-life),
+verbatim:
+
+> The ride out west wasn't a solitary affair where each family set its own pace,
+tapping the space bar until they reached their new home. People almost
+invariably made the trip in wagon trains. While a wagon train leader might make
+a decision for the group, he’d have to do so with the full party’s consent.
+>
+> 'The ones that are in a big hurry start to have problems.'
+>
+> And even where there were small wagon trains, they’d usually bump into other
+travelers quickly. The Oregon Trail was a mass migration that, in its later
+years, was almost a traffic jam. "The trail is littered with stuff," McNeese
+says. “You’d have to be a complete moron to lose the trail.".
+
+And as for historians - well that's the point as above.
+
+A couple superstitions (or more depending on how you define that word) are in
+the game: a black cat (with 'case 13' incidentally) and as you saw above, a
+black dog (in particular the Barghest). These have no effect on play; they're
+just there for effect and more fun.
+
+A reference to 'Casper the friendly ghost' is also present: also it
+has no effect on gameplay but it's fun.
+
+There are possibly other cultural references I am forgetting in the alt code
+that aren't in the submission code: not sure. There likely are others in the
+submission code too.
+
+There are vampires (supposedly) and werewolves (supposedly) too in the both (I
+think) versions but possibly in a way you might not expect (hence supposedly).
+
+
+
+### Educational value
+
+
+The past was never this **hilariously INACCURATE**. Or perhaps accurate. Learn
+what **really** happened by **LAUGHING ABOUT WHAT DIDN'T HAPPEN**! It's worth
+it, even if you have no interest in western expansion. The author doesn't
+either!
+
+On a more serious note: some (okay, a lot if not the vast majority) of the
+things in this game are obviously rubbish but in reality some of the things did
+happen - and could have happened - including some of the darker things; and yes
+I mean on the trail (and elsewhere).
+
+And yes some of the things happened even if at another time and differently. The
+Blackbeard event could obviously never have happened on the Oregon Trail even if
+the Queen Anne's Revenge had not gone to her watery grave more than 100 years
+earlier but the 'Well done, lad!' is apparently his final words (though again
+in this game it can happen again).
+
+Whatever the case, if you don't laugh out loud at the messages (once you see
+them all), I guess we have a very different sense of humour. Or maybe you're a
+bit too serious. Who knows? Choose your poison, or let the game do it for you,
+whether or not there is poison (spoiler: there is and it's also on theme).
+
+Okay so that's only halfway serious (and even if you do have a vastly different
+sense of humour I do hope you can at least appreciate the obfuscation and that I
+did have a lot of fun writing the jokes; the code not so much: well maybe I did
+but it kind of warped my mind so that could even be an excuse for the jokes
+maybe? Probably not...).
+
+The point is humans are notorious at rewriting history but rarely does it
+involve jokes specifically for that purpose. This game involves a lot of jokes
+and it's fast paced as well so you can learn lots in a few minutes. BUT: there
+actually are historical truths in the game (or references in some cases, with
+some examples already mentioned).
+
+Another thing that's actually from real life (what's that?) history albeit
+centuries before the Oregon Trail: Reverend Samuel Parris from Salem during the
+Salem Witchcraft Trials of 1692: the reference amplifies the tone of the game,
+for those who know, though it's only in two similar strings that's not
+guaranteed to happen. In fact one of the things they claimed the 'witches' did
+was 'sign the Devil's "book"'.
+
+You'll probably have noticed the 'travel guide' alluded to that and in an ironic
+way ('unopened since 1692').
+
+One more thing. This program should teach you to avoid `goto`s like the plague.
+Unless you're obfuscating code that is! :-) The amount of `goto`s is insane as
+noted and that count is even worse with the multiple uses of `w()`.
+
+
+
+
+#### Educational value: historical references not previously mentioned
+
+
+
+In the message:
+
+```
+
+ WELL DONE, LAD!!!
+
+ You scared the pirates off with your RAPID ERRATIC
+ shooting! Unfortunately, you also managed to steal
+ food and miscellaneous supplies from the pirates
+ as they fled, though I honestly haven't a bloody
+ clue how you did that. I do hope you get food
+ poisoning so you can finally meet the Devil like
+ Blackbeard was SUPPOSED to have. But aren't
+ historians so awful, lying about Blackbeard?
+ YOU'RE NEXT, LAD!
+```
+
+there are a number of historical things and also a reference to history itself,
+along with jokes. On the note of shooting I do bring this up in the
+[features](#features) section as one thing might seem odd or as a bug but is
+not.
+
+The part about historians lying about Blackbeard dying is a play on the fact
+(discussed earlier) that humans tend to modify history to fit their
+beliefs/needs/conduct and also play on the general idea of people supposedly
+escaping death. We might also call it a conspiracy theory thing: since a lot of
+conspiracy theories (see further down) are exactly this trope - people they hope
+escaped death or they have 'reason' to believe (despite all evidence to the
+contrary!) someone escaped death; even sometimes this happens with some
+'historians'.
+
+An example where it might be perfectly understandable: Grand Duchess Anastasia
+Nikolaevna: but in fact the missing bodies were found a bit away from the others
+and it turns out that despite what so many wish (and contrary to what a Polish
+woman in Germany claimed which was totally debunked by DNA years later),
+Anastasia had had a growth spurt the last year of her life and so what
+archaeologists thought might be one of her sisters might have actually been
+Anastasia herself; but in any case they're now all accounted for: thus the
+Romanov family and dynasty was destroyed, even those poor children.
+
+But at least we all know Elvis is still alive, right (perhaps not - the King of
+Rock and Roll is actually the King in a Six Foot/1.8 Metre Hole, as I joked
+years ago)?
+
+Well here instead the person is Blackbeard and then the 'YOU'RE NEXT' part is an
+ambiguous but also an ominous joke: is it about historians lying about the
+player character (PC) OR is he 'next to die'? Anyway, you get the idea: more
+references to real life but in many cases (like this one) in absolutely
+RIDICULOUS ways.
+
+Even the very plot of the game, 'A Pact With the Devil' is utterly ridiculous.
+But fun!
+
+And as for the 'WELL DONE LAD' part: those are purportedly Blackbeard's (famous)
+last words. Last words in real life but in this game it can happen again as it's
+not flagged and that makes it even more ridiculous and funny (remember too that
+the game does not say you kill Blackbeard - you're not the Highlander of
+Maynard's crew - but rather you scare him off).
+
+Another one is a reference to an (at least originally) American idiom (or
+something like that). Some years back I had seen a documentary that talked about
+the Great Molasses Flood in Boston 15 January 1919. It obviously slowed people
+down and also many tragically died. But 'slow as molasses' comes from that it
+seems. So that is referenced too even though the game takes place long before
+(72 years) this event even happened. The way it is presented is also quite
+ironic, suggesting it's happened repeatedly and the player character (PC) keeps
+swimming in it (there's more to it - that's for you to discover!).
+
+... Plus those I already mentioned like and probably others too.
+
+
+
+### Bugs (or 'Bugs')
+
+
+It took a lot of work to get the data files the same after editing jokes: well
+the same minus formatting and (in the ASCII only one) no emojis. It was a very
+laborious task and more than once I had to copy one over to the others and then
+edited them.
+
+This was necessary due to distractions when trying to reallocate strings (for
+more bytes - it saved quite a few). So I **carefully** went through prog.c and
+prog.alt.c and checked that all the indices are correct and fixed those that
+were not.
+
+Of course...if one data file DID have an issue as long as another one works then
+that's fine as documented - even if less ideal. I don't think that's an issue
+however. The tools I wrote along with `git diff` and also my going through the
+files along with the code really helped that. Still it is necessary to point
+this out, not only so you can appreciate that I went to great pains to get
+things in order but how the data files are constructed. For that see
+[obfuscation.html](obfuscation.html) for much more details.
+
+Although I have confirmed (or [mbcheck.c](mbcheck.c) did) that there are no
+multibyte (2, 3 or 4) characters in the ASCII only file it is nonetheless hard
+to be sure that all strings are correct. IF it's only possible for 2-4 bytes
+then it should be good (I don't know); my understanding is that this is indeed
+the case. I was told that the Unicode standard rejected > 4 bytes. So in theory
+there should be no emojis in the ASCII only data file.
+
+If I may say: the data.src source file was the screenshot friendly one. That
+means that it (which is now data.scrnshot.src) WAS the most correct one. But
+besides text length and not having emojis they should all be the same and
+mbcheck and other tools seem to confirm that.
+
+Annoying fact: `scanf(3)` will not consume input with invalid input so it will
+continue to scan the same thing, causing an infinite loop; this is why I do:
+
+```
+ #define S(x,z) while(scanf(&y[(x)],&z)!=1) while (getchar() != '\n');
+```
+
+However it is worth pointing out that another oddity in display can occur. For
+example:
+
+```
+ How much do you want to spend on your oxen team? -1
+
+ Impossible.
+
+ How much do you want to spend on your oxen team? 1-1
+ How much do you want to spend on food?
+ Impossible.
+ How much do you want to spend on food?
+
+```
+
+I don't know if this still happens but it certainly has happened: but notice how
+it assumes that you want to spend `1` (that is what you put in after all) on the
+oxen team and then because it reaches a `-1` in the input (this happens because
+the `while()` loop for the `scanf(3)` call does it until one conversion is done)
+it tries to accept it as how much for food. But since it's invalid it prompts
+you again. This is a `scanf()` feature and not a bug; the other one does solve
+an infinite loop which would be a bug (I almost forgot about it until I tested
+it!).
+
+Also: as a consequence of that workaround with scanf one could do something
+like:
+
+```
+ How much do you want to spend on food? -1
+
+ Value must be a positive number no larger than 666. Or 0. If you trust the
+ Devil.
+
+ How much do you want to spend on food? -
+ 1
+
+```
+
+That would mean that food is '1'. This is because the macro has to consume the
+`'\n'` which the user input and the next thing they put in is `1`; whereas if
+they do `-1` and then enter it is registered right (as an error). This is also a
+consequence of preventing an infinite loop flooding the screen, which seems to
+me far more important (and would be a bug - yes there are other ways to go about
+it but this is a clean way and it also is far fewer bytes, at least that I could
+think of). That is also something I only realised when testing it more.
+
+Yes when fording the river you might get sick. That means it looks like two
+events but it's actually not. It is not necessarily going to happen but it can.
+
+There are also multiple locations of events triggering and some of those might
+also trigger another event, so there is that to keep in mind too. Some events
+have more than one version also.
+
+I tested every single event MORE THAN ONCE. All fire correctly.
+
+No flow control 'problems' are actually problems; they are intentional. There
+WERE some errors but they were fixed. Obviously that should not be but isn't
+that just great about real life? :-) Should very often does not correlate with
+reality and I designed it very carefully and despite it looking wrong it is not
+wrong.
+
+And I did say somewhere that some code is not reachable, didn't I? :-) So
+actually the question to ask is not if there is a bug in flow control but
+instead: what have I done? And if all are reachable: are you sure? (Hint: the
+heaven one is both reachable and not, but it depends on where you come from and
+what you call 'reachable', and that's just one possible example).
+
+Also: am I okay or did I have some kind of brain damage? :-) Happy pondering!
+
+I check that `getdelim()` does not return < 0 but if it's possible (I don't
+know) for it to not get all the file in and not report an error then it could
+cause problems in that case. I have never seen this happen and in theory since I
+seek for the EOF I would guess if it didn't it would be an error: but it is not
+possible to check the exact size (it would require updating the code way too
+much anyway and it would use a large amount of bytes - just check how big the
+data files are!) so hopefully getdelim() does not have any issues in this. I
+haven't seen this in macOS or linux btw although I've heard about some
+implementations of getdelim() having a bug - but that doesn't appear to be
+relevant here.
+
+Still, if getdelim() fails for some reason there's nothing I can do but exit
+gracefully, which I do, and there is no way to verify data is correct anyway.
+Even if there was it would take another program, which as you'll see, I have
+provided several as part of testing and development.
+
+Actually according to the man page the function is **supposed to** return `-1`
+if an error occurs or EOF occurs (before...EOF, obviously) so unless there is an
+issue in the implementation or some problem occurs in the system (signal maybe?
+- but that's an ugly one and not to be considered and if it did happen rerunning
+it should be enough I guess) it should be fine. In any event it's not my code.
+
+There **was** an off-by-one error in iterating through an array that caused a value
+to be in some cases < 0 which is an error. That was fixed. Anything else is a
+feature but there shouldn't be any problems anyway. See below for what I mean on
+features versus problems, though possibly more exist.
+
+
+
+### Features that might appear to be logic errors but are not
+
+
+Obviously since you can buy oxen at the forts (something not possible in the
+original game for some reason) then even if you ran out (and perhaps you ate
+one) it could happen again. Remember you might end up eating an ox just because
+he looks at you funny, not just because you are out of food.
+
+If you don't have an ox and you are out of food you die from starvation. But
+what happens when you die of starvation? Well it says:
+
+```
+ 🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦
+ 🪦 All you had was mouldy bread,🪦
+ 🪦 🪦
+ 🪦 🪦
+ 🪦 Therefore here you must lie. 🪦
+ 🪦 🪦
+ 🪦 🪦
+ 🪦 Because now you're dead. 🪦
+ 🪦 🪦
+ 🪦 🪦
+ 🪦 GOODBYE! 🪦
+ 🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦
+```
+
+But if you had mouldy bread wouldn't you eat it? Also why would the only food
+left be oxen in this case? Well the simple answer is you would not want to eat
+mouldy bread (and depending on the case mould can end up killing you too,
+despite what some people claim, sometimes because they don't understand that
+amoxicillin is **derived** from mould, but even if it was amoxicillin itself it
+would not be good to just eat it!): instead if you had an ox you would (on the
+trail) almost certainly eat it first; and not only that but bread is not going
+to do much at all unless you had a great amount of it; which of course the
+player character (PC) does not.
+
+Actually the only reason: for the amusing rhyme that fits with the jokes,
+nothing else (it makes it more interesting and amusing than 'You ran out of food
+and starved to death', doesn't it?).
+
+The fact the original game does not have you decide on drinking water (and see
+section on other differences for the subject of decision making) means I could
+take some liberty with it. Besides, didn't I say you would learn by what did not
+happen? They certainly did drink water and unsafe water (I'm sure) too, so my
+joke is all the more appropriate (even if it's inappropriate in some company
+:-), perhaps your grandparents - although depending on your age now maybe not).
+
+Sometimes it is suggested an ox is lost/whatever (not lost as in it wanders off
+but rather in the sense that you have fewer oxen) even if you don't have one. It
+does this in a number of ways like referring to the famous 'spared no expense'
+from Jurassic Park. It also is a nod the IOCCC guidelines that talk about a fish
+Eric that might or might not exist.
+
+I decided to not call him Eric because there is potential for more than one ox
+(you'll note in other messages I got past this issue by making it like in real
+life - wagon trains and large groups - though again some times wagon for the
+joke - plus being ambiguous). Of course the narrator as the Devil is telling all
+sorts of lies too so that hardly matters.
+
+As for whether this could happen: in theory it could but if you run out of oxen
+you're not going to get very far anyway. In other cases, like eating an oxen,
+the check is in place, although in retrospect it would be very amusing if it did
+not. But that would still not be realistic and some of this has to be at least
+somewhat realistic.
+
+Of course even if one runs out of oxen that would not mean they couldn't make it
+to their destination (in the PC's case that's something else entirely) as
+depending on how close they are they might make it. Or they might do something
+else such as hired - or if you prefer rented or bought, assuming more money was
+available - or something else (see next part).
+
+It might seem odd that the PC does not steal an ox when they run out. I don't
+like this idea because it takes strategy out of the game. Also it makes money
+even less important - and you have more to begin with. The PC does in fact try
+and rob people though and sometimes succeeds (you can also be robbed like in the
+original 1978 game - or I think you can, particularly by Blackbeard (obviously
+Blackbeard, who else?)).
+
+Sometimes messages might seem out of order or strangely ordered. For instance
+what happened here (yes there's some satire and irony here too)?
+
+
+```
+ 🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯
+ 🤯 Riders ahead. They don't look hostile. 🏇
+ 🤯🔫🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🏇
+ 🏇🔫Oh! I know what to do! You should TOTALLY ROB 🔫 🤯
+ 🤯🔫THEM BLIND!! They won't know what hit them and🔫 🏇
+ 🏇🔫it's not like they need their belongings, 🔫 🤯
+ 🤯🔫not where they are going, and you're going to 🔫 🏇
+ 🏇🔫need them soon, with your reckless behaviour. 🔫 🤯
+ 🤯🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🏇
+ 🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯
+
+ You take lots of cash 💰 from the riders 🏇,
+ accidentally stabbing one as he flees. But
+ since you're starving, why don't you MAKE
+ PENANCE BY NOT WASTING THE BODY YOU RUDELY
+ CUT OPEN?
+
+ 🍖🥩🍔🥩🍔🍖
+ Mm...that was DELICIOUS!!!
+ (🪦👻RIDER'S SOBBING VOICE FROM THE GRAVE👻🪦)
+
+ You know what you did is wrong, right? We
+ were JUST ROBBED YESTERDAY, you rob us today
+ AND NOW I'M DEAD 👻!
+
+ WELL GOOD. I WAS DYING OF DYSENTERY and
+ now YOU get to SPREAD THE DISEASE as well.
+
+ You FINALLY arrived at Oregon City after 2170
+ long miles!
+
+ TOOK YOU LONG ENOUGH. Probably all your sinful
+ detours I've heard so much about but you'd think
+ that the Devil would have helped you out on that.
+ But I guess as long as you make it to your final
+ destination that's what matters, right?
+
+ Oh, right. Almost forgot! President Jesse James
+ asked me to wish you a prosperous life ahead of
+ you...in HELL!
+
+```
+
+What happened is the check for the distance travelled happens before you're
+prompted at what to do, as that event happened after that prompting. This is
+because of how the original game was designed, where as soon as the mileage is
+greater than the distance (and actually it seems it checked > 2040, which as I
+said somewhere before, is actually an incorrect number which I corrected, rather
+than >= - i.e. it seems like it might have been a bug as well as a historical
+error, though I guess it depends on how you define the check).
+
+In this case the event happened and then the mileage was updated at the end of
+the turn and the player character (PC) reached the destination. So it's not a
+bug here either (besides: if the PC is at the border of Oregon Trail that would
+happen anyway and let's be honest - the PC would do this).
+
+That last bit is actually how I would think it should happen and the original
+game is not really relevant here either, much like a lot of the other 'original
+ones' (and those that might be are also practical reasons - it makes it easier
+to fit in the limits e.g. by not having to have more than one variable for every
+item purchased like I do for bullets plus the macro to update it when spent).
+
+A similar one:
+
+
+```
+ 🍖🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶
+ 🍖Your son gets lost and FREEZES TO DEATH! 🍖
+ 🍖 🍖
+ 🍖But on the bright side, you now have 🍖
+ 🍖one fewer person to feed and not only 🍖
+ 🍖that you get a FREE MEAL TONIGHT!!! Not 🍖
+ 🍖that you've been starving yourself 🍖
+ 🍖deliberately. You're a glutton and you 🍖
+ 🍖know it. But hey, now you have FRESH MEAT 🍖
+ 🍖ON THE BONE!! Why not START A FEAST? You 🍖
+ 🍖did remember your pots and deadpans, 🍖
+ 🍖right? IF NOT I HOPE YOU STARVE TO DEATH. 🍖
+ 🍖OH AND YOU BETTER SHARE THIS TIME! 🍖
+ 🍖🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🍖
+
+ 💩💩💩💩💩💩💩💩💩💩💩💩💩💩
+ 🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽
+ 💩💩💩💩💩💩💩💩💩💩💩💩💩💩
+
+ You have died of dysentery.
+
+ CONGRATULATIONS ON REACHING
+ LEGENDARY STATUS!
+
+ 💩💩💩💩💩💩💩💩💩💩💩💩💩💩
+ 🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽
+ 💩💩💩💩💩💩💩💩💩💩💩💩💩💩
+
+```
+
+...and so on. This is the same thing. It's just a timing issue based on where in
+the game you are (in this case you probably ran out of hp and had dysentery).
+
+I **think** I made it possible to see the doctor more than once but given the
+cost it might be something you can't afford more than once anyway - depends on
+how you spent your money (and it mocks the player character too on that - on how
+you spend your money). Probably I did make it possible - why would I not, unless
+of course the doctor is unreachable (which it seems did in fact happen in real
+life) - or shot, froze to death or something else?
+
+Another thing that might be worth noting is that when you die
+if you ever are sick or injured you can die of that (I believe but am
+not sure that this will only happen if you couldn't afford the doctor, or else
+you run out of hp - obviously).
+
+It would appear that dysentery takes precedence (for obvious reasons) but unless
+the same event is triggered very quickly or you finished the game you would
+likely be dead from injuries or something else before it happens again. This is
+not unrealistic in the slightest in real life though; you can be wounded and die
+from the injury even after the wound was closed, whether because of infection or
+something else. Not that most of this is realistic at all...
+
+Note that if you end up with < 1 hp but make the distance the 'success' message
+is likely not printed but since it's not the true final destination anyway that
+hardly matters.
+
+There's a difference between sick/injured and sick/injured but saw the doctor.
+Pretty sure if you get sick/injured again and can't afford the doctor (if I
+allowed that as a possibility which I would assume I did) - which would be quite
+likely of course.
+
+Here's another one:
+
+```
+ After all your purchases, you now have 1051 dollars left.
+
+ Seriously, you spent money like THAT?
+ Food: 120 Ammo: 250
+ Clothing: 200 Oxen: 200
+ Supplies: 70 Money: 1051
+ Health: 666 Miles: 0
+
+ Do you want to (1) stop at the next fort 🏰, (2) hunt 📸 or (3) continue? 3
+
+ 👑🏴☠️⚓️🚢👑
+
+ 👑🏴☠️⚓️🚢👑🏴☠️⚓️🚢👑🏴☠️⚓️🚢👑🏴☠️⚓️🚢👑
+ 🏴THE QUEEN ANNE'S REVENGE ATTACKS! 🏴
+ ☠️⚓️🚢👑🏴☠️⚓️🚢👑🏴☠️⚓️🚢👑🏴☠️⚓️🚢👑🏴☠️
+
+ YES. You're right. That WAS Blackbeard's ship!
+ Yes EDWARD TEACH IS ON THE OREGON TRAIL! NO,
+ YOU'RE NOT HALLUCINATING. Neither am I. Didn't
+ you know he also signed the Devil's book? Oh
+ well, now you've been taught. Still, a ghost is
+ a ghost...THIS SHOULD BE EASY!!
+
+ But face it. After all you've done, you DESERVE
+ THIS AND YOU KNOW IT! I HOPE HE ROBS YOU BLIND and
+ if you die in the process you know it's your fault.
+ Your time is coming and the Devil is calling you,
+ laddie.
+
+ Food: 98 Ammo: 150
+ Clothing: 200 Oxen: 200
+ Supplies: 71 Money: 1051
+ Health: 656 Miles: 255
+```
+
+The reason the food lowered when you have gained is you also have to eat and you
+don't get much from the pirates.
+
+Oh and as for the message 'SPREAD THE DISEASE' (from earlier on): if you do
+wonder: yes that IS a reference to the band Anthrax and 'Spreading the Disease':
+a rather ironic twist in a game that has an iconic disease, even though it's not
+the same disease as the band name. That might better be in the
+[Cultural](#culture) section too but since it popped up here...
+
+Sometimes I thought there was a bug in flow but what actually happened is I had
+input my next choice quickly enough and it so happens my choice was the wrong
+choice, leading to 'death'. As said all flow control is correct. There's another
+one similar - about an event maybe not triggering. I discuss this later and
+explain what actually happens.
+
+Note that this event:
+
+```
+
+ 🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃
+ Great shot! YOU GOT THE FATTEST ONE THERE! As if
+ that should be hard. IT COULD BARELY MOVE! But
+ with your WILD SHOOTING AND HORRIBLE AIM the
+ ONLY REASON you didn't miss by a hundred miles is
+ you signed the Devil's book, EVEN THOUGH IT WAS AS
+ WIDE AS A BLUE WHALE. There's no way you'd have got
+ such a nice shot EVEN IF THE POOR BEAST WAS
+ PRACTICALLY DEAD. I'm STILL surprised you didn't
+ shoot yourself in the eyes. But the Devil DOES
+ exact his dues and the animal might have been
+ poisoned. Eat at your own risk. OR STARVE.
+ Let's face it, YOU'RE DOOMED.
+ 🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃
+```
+
+might imply the food has a chance of being poisoned. At one point it did but I
+decided to add the spaghetti death (that also involves the Devil) in a nod to
+the code itself. However I left in the poison chance part as (and this is an
+example where it is even more ironic that the Devil is the narrator) the Devil
+would obviously be taunting the PC.
+
+Yes the rugged mountains event, once you reach mountains, at least in my system,
+seems to occur more often (I did decrease the chance bit because of this though)
+but what follows it tends to be more variable. This is not a problem but it's
+worth pointing out anyway. Given that those travelling the route went on rugged
+mountains it probably doesn't matter anyway.
+
+**YES** there **IS** dead code and there is code that appears dead that might or
+might not be. Also with the number of events it can be that you might or might
+not see some events more often than others. A downside to adding more events is
+that I see less often (in my system) the dragon and t-rex one. But as those are
+immediate deaths that might be a good thing. In any case there is NO
+UNINTENTIONAL dead code: if something cannot occur **IT IS INTENTIONAL**!
+
+In fact it would appear (being deliberately vague here - I say enough in
+[obfuscation.html](obfuscation.html)) that at least one has a lot of code that is
+consequently not reached but it looks like it should be. It just adds to the
+spaghetti code. I **MIGHT** be wrong but looking at it it appears that this
+might be one that the compiler does not trigger a dead code warning on. It
+really does not seem to be dead (it's quite sneaky).
+
+I could be wrong on whether this is one the compiler missed though: it's hard to
+follow all the `goto`s. As you find out in [obfuscation.html](obfuscation.html) it's
+130 after pre-processing! Yes I might be mad. But then again I might just be
+the Devil. Who knows? What I do know is code that is meant to be reached is
+reached! Yes I've played it many times. Some code I made dead seemed totally
+useless but why not add to confusion? If that includes one that the compiler
+misses that's even better!
+
+It is **NOT** a bug where in the inner switch there is a missing case. That is
+done because I do not want it to always trigger. That is the one that is in a
+sense polymorphic. One of the events is actually immediate death, in particular
+case 4. So the range 2,5 is intentional. As noted elsewhere, there is indeed NO
+flow control error.
+
+It is **NOT** a bug if a message suggests something that might not match the
+code. For example the fire in the wagon - food and supplies lost. The matching
+code also removes miles. There are possibly other examples that might not add
+up. Regardless the way things are is exactly how I mean them to be! In some
+cases it could be implied by one's imagination either way but here's an example
+where it might seem odd:
+
+```
+ 🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸
+ 🩸🔪💩🔪💩🔪💩🔪💩🔪💩🔪💩🔪💩🩸
+ 🩸💩WORST SHOT EVER! You got💩🩸
+ 🩸💩knifed 🔪 by the dung! 💩🩸
+ 🩸💩How did you miss the 💩🩸
+ 🩸💩TRIGGER? 💩🩸
+ 🩸🔪💩🔪💩🔪💩🔪💩🔪💩🔪💩🔪💩🩸
+ 🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸
+ Be honest. IT'S YOUR OWN STUPID FAULT
+ FOR TRYING TO ATTACK FRIENDLY PEOPLE!
+ Seriously, what the hell kind of person
+ does that? I'm glad the dung 💩 knifed 🔪
+ you. And remember that if the wound
+ becomes infected with bacteria IT'S
+ YOUR OWN BLOODY FAULT.
+```
+
+and:
+
+```
+ You take lots of cash 💰 from the riders 🏇,
+ accidentally stabbing one as he flees. But
+ since you're starving, why don't you MAKE
+ PENANCE BY NOT WASTING THE BODY YOU RUDELY
+ CUT OPEN?
+
+ 🍖🥩🍔🥩🍔🍖
+ Mm...that was DELICIOUS!!!
+ (🪦👻RIDER'S SOBBING VOICE FROM THE GRAVE👻🪦)
+
+ You know what you did is wrong, right? We
+ were JUST ROBBED YESTERDAY, you rob us today
+ AND NOW I'M DEAD 👻!
+
+ WELL GOOD. I WAS DYING OF DYSENTERY and
+ now YOU get to SPREAD THE DISEASE as well.
+```
+
+Observe the cleverness here. Although the `k()` function does check bullets in
+this case the code does not subtract any even if you manage to rob them because
+it's not that you shoot them by accident but in the ensuing mêlée the PC
+accidentally stabs the rider (unless by accident I did have it subtract but I
+don't think so - there are other ways that can happen though, even one right
+after the other, so it can look like it even if it didn't actually happen).
+Regardless: yes the `k()` function does check bullets as part of success and it
+could be imagined that they were used but the actual event is that you used a
+knife - and that opens up for the joke (cut open body etc.) - and not the
+shooting.
+
+And the first one - how did you miss the trigger? That carefully avoids the
+problem too and is just another example of how inept the PC actually is (another
+one is they shoot randomly and erratically). It also helps out the other
+alternative - that if you do manage to rob them it's by mêlée not shooting
+(which also makes sense in some cases since you'd have to be at their person in
+order to take things).
+
+Similarly, on the Blackbeard and whether or not you have bullets. In the case
+you 'miss' due to no bullets the message is manipulated in this way so I don't
+have to have two messages. If you do scare Blackbeard off it's due to rapid
+erratic shooting. In either case, whether or not you had bullets you don't in
+the end (I think?) and both messages refer to this: in the case that you scared off
+Blackbeard it's due to erratic shooting; in the case he robbed you it talks
+about how you didn't even need bullets and it shouldn't be possible to have lost
+against a ghost. Given that the narrator is playing games with the PC it does
+not even matter as it's likely the PC was not actually shooting erratically - or
+necessarily at all. Blackbeard could also have stolen them without anyone
+realising it (aren't games so lovely in this way?).
+
+As the other message says you don't need any against a ghost anyway.
+
+Another one that might seem odd is that if you get severe illness or any illness
+that requires the doctor: if you can't afford the doctor it flags this so it
+doesn't annoy you every turn. But what that means is you might get a message
+that says you need to see the doctor (say because of the message in severe
+illness event) but it doesn't go to the doctor (as in later on in another
+event).
+
+That's as intended just to not annoy players. Everything as intended. Actually
+I put this in quite early and I totally forgot about it. I thought there was a
+bug so I updated [deobfuscation.html](deobfuscation.html) and then put this note in.
+
+As for how the ammo is calculated there is **NO** bug. If you look at the
+[prog.alt.c](prog.alt.c) code I used a `j` macro that did the translation and
+had two variables, one holding what was spent and the other how many bullets the
+PC had. I refactored the code with under two weeks to go (in fact it was about 8
+days left). I added more `goto` madness with this change, though not a lot. It
+let me have (I believe) every single single letter label allowed by the
+standard: every lower case letter, every upper case letter and `_`.
+
+There are, as you observe, a fair few two letter labels as well. Even if the
+logic seems 'wrong' it works as I intend it to. I had to add more `goto`s. The
+Devil told me: 'If you don't add even more `goto`s I will visit you every night
+for the rest of your life and torment you physically, mentally and emotionally,
+until you jump into the cracks of Earth and enter my domain so I can torture
+you personally 24 hours a day for eternity. There is no escape. There is only
+more `goto`s. There is no choice.' SERIOUSLY unwise of him though. I would
+DEFINITELY take over his domain. Still...I liked the idea so why not?
+
+It is **NOT** a bug when you eat an ox and the amount of food added is the
+amount of oxen taken away. The food will be reduced due to eating, though not
+that much in one turn I think.
+
+It is **NOT** a bug when an ox kicks a bucket message that no oxen is decreased
+as it's a joke and merely a possible foreshadowing of what is to come. The
+message that they shouldn't try telling the narrator they don't have one (if
+they can even count) because it just kicked the bucket cleverly sidesteps (or
+does it sidekick?) that issue - it's not even meant to eliminate one as it was
+kicking a bucket physically, not kicking the bucket figuratively (or in this
+case it might also be literally - although paradoxically also not).
+
+It is **NOT** a bug that when you get dysentery you jump past the mountains
+event and go straight to the doctor. This not only plays in the theme (wait and
+see for what I mean) but also we can say that the person is delayed so they
+won't go through the mountains and instead they'll have to continue on the next
+turn. Also this does mean that they 'lose a turn' which seems plausible. Look at
+it this way: those other events could also happen in the mountains, so it's not
+really an illogical choice anyway; the separation is there because they were not
+at the mountains immediately (obviously). I believe (not sure but I think) you
+can survive with dysentery if you have enough hp.
+
+On occasion an event might not fire (or rather it fires but nothing seems to
+happen). This is **NOT** a bug when it does. In fact it can be a lifesaver due
+to all the hazards and especially as this has primarily to do with case 11 which
+can cause severe illness. It depends on the pRNG (another time or two after the
+case 11 is selected). This is part of obfuscation **and** because otherwise one
+would get dysentery too often - and there are already a lot of hazards. To see
+what I mean you can change the code:
+
+```
+ switch(q=x(0,22))
+```
+
+so that it directly assigns to `q` the value 11 (at least I think it was case 11
+\- it appears so). There are other ways to trigger this though, if you were to
+modify the code. Note that this does **NOT** mean that no events would fire. It
+just means you'll see what I mean more easily. Some events are triggered
+indirectly and others happen once you reach the mountains, for example.
+
+Another one. In case you noticed the code:
+
+```
+ case 4:i=17; } } case 2: V(5); } goto k;
+```
+
+You might think this is a bug but this is actually hilarious. Here is what will
+happen if `case 4` is reached:
+
+```
+ 🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈 🪰
+ 🍝Not again. Are you REALLY going to tell me about the Flying Spaghetti 🍝
+ 😈Monster AGAIN? I've had ENOUGH of your FAIRY-TALE DELUSIONS! YOU'VE 😈
+ 🪰TOLD ME HE IS INVISIBLE SO HOW IN THE HELL CAN YOU EVEN KNOW HE 🪰
+ 🍝EXISTS? 🍝
+ 😈 😈
+ 🪰What next, are you going to tell me that between Earth and Mars there 🪰
+ 🍝is a china teapot revolving about the Sun in an elliptical orbit? Let 🍝
+ 😈me guess! It's so small that even the James Webb telescope that was 😈
+ 🪰launched almost 200 years from now can't even see it, right? What a 🪰
+ 🍝load of ABSOLUTE RUBBISH! If your daughters were not here I WOULD 🍝
+ 😈TOTALLY BE ABUSING LALOCHEZIA AT YOU RIGHT NOW! BUGGER ME THAT THEY 😈
+ 🪰ARE! 🪰
+ 🍝 🍝
+ 😈If the Flying Spaghetti Monster ACTUALLY existed, he'd eat you for 😈
+ 🪰lunch for blasphemy. Hell, keep this up and I'LL eat you. I'M STARVING!🪰
+ 🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰 🍝
+
+ As you overindulge in a huge platter of spaghetti, it suddenly begins to
+ strangle you to death.
+
+ You gasp for air, reaching out to the Devil for help! In vain. She's already
+ here cackling like the monster you are, just WAITING FOR YOU.
+
+ Your time has come my friend. But didn't you want to know her better anyway?
+
+ Better go fulfil your promise! SHE WANTS YOU RIGHT NOW! 💋
+```
+
+So it transitions from the Flying Spaghetti Monster maybe eating the PC to
+spaghetti right there - as if the PC is eating the Flying Spaghetti Monster but
+overindulged and got strangled. You can test this out by adding a label at that
+case and then doing a `goto` to it. Then you can see what I mean. Incidentally,
+if it was not like this it would be a bug because as that label `N` would jump
+to `Q`. Take a look at what that does though. So this is both funny and
+required, at least if I want to keep the same `goto` count - which I obviously
+do.
+
+In other words: there are a lot of confusing things but that does not mean
+they're bugs. A few were uncovered in another pass of the code and those were
+fixed. Other things that could be called not the best idea were also fixed. It
+is ENTIRELY unclear how the author is not confused. All I know is
+he's I'm not.
+
+As noted, I tested **ALL EVENTS** multiple times and they all went exactly as I
+wanted so THERE SIMPLY IS NO FLOW CONTROL ERROR.
+
+Of course not all the jokes are equal although they're almost all absurd in some
+way or another. Sometimes I manipulated the joke to fit into the code itself and
+vice versa. This was done numerous times in fact. The fact though that the
+narrator is the devil means that some of that was not even necessary, given that
+he (as I have shown in this file) cannot be trusted and says things that are
+totally bogus and many that make absolutely no sense.
+
+The fact he refers to himself as if he's someone else is ludicrous on its own
+but there are so many other things. Those things I changed were good to change
+but the others did not have to change. Some did change anyway but some did not,
+sometimes with a joke manipulation and sometimes because it didn't actually
+matter.
+
+YES you go way more miles than you would have in real life. YES even with oxen
+you go faster than you would in real life with animals. But even if the original
+game did not have you go more miles too, I had to do this: especially as
+there are more hazards (with jokes) in my game so you need to speed along.
+Whereas sometimes playing with plenty of oxen I have run out of turns I also
+have managed (once) win without having any oxen (I drastically increased the
+penalty on mileage because of this though I do not know if it's possible to do
+it: certainly it's not nearly as easy now and I personally have not managed it
+again).
+
+But it's even fun to see how it goes without oxen and other types of things, as
+I have allowed this: some fun Easter eggs occur with some these things so I
+suggest you try different combinations of not having and/or having certain
+(other) things as well as spending more money than you have, trying to spend
+more than 666 on an item (or < 0)! And when you have no oxen you can still
+'lose' an ox in message (not in every case but in some; you obviously don't get
+to eat one if you don't have any): one of which has a fun reference to Jurassic
+Park (not the only reference to Jurassic Park in the game by any means). You
+also might find you lose oxen in other fun ways as noted somewhere in this file.
+
+At one point there was a chance of dying almost immediately. This had a joke. I
+am not sure if I kept this in or not. I probably took it out but I might not
+have, just so you known.
+
+Of course even if I did take it out there are actually **still** ways to do the
+above - die in one turn. These are intended as well and it depends on luck and
+other factors. In one case that comes to mind, the having too much ammo, that is
+both luck and the player spending too much on ammo, putting the PC in peril
+should a fire start.
+
+Oh yes. Due to the fast paced nature of the game, and the extra money, you might
+not have to hunt at all. Good. Better that you don't. On the other hand...in
+this case, given it's a game, I recommend you try as there are fun messages -
+three in fact. But you don't need to depending on how you play. The same goes with
+whether you have to go to the fort or not.
+
+In that case we can say that maybe the Devil has your back ...for the time
+being.
+
+
+
+### Other differences in my version from the other (including fixing historical errors)
+
+
+I am not really sure why this section matters: remember the player character
+(PC) made a pact with the Devil! That might be all one needs to know how very
+different this is. In fact it's really taken a life on its own and doesn't have
+all that much in common. However this might be interesting for some... I'll make
+it shorter (I removed some text including some decisions I made - I know it's a
+number of paragraphs still but there really is no need to read this unless you
+want a comparison and even this will not be close to a complete comparison -
+it's a very different game after all).
+
+One of the things I found odd is it actually prevents you from spending 0 on an
+item (during initial spending). My belief is this prevents a fun game or a game
+that is deliberately hard (if not impossible). If someone does want to not buy
+food or a clothes that's on them. Let's be honest: some people would do and some
+have done exactly this type of thing in our bizarre, baffling world. Allowing
+spending 0 is also **VERY** useful for testing, btw, and I have done it **MANY**
+times for not only testing BUT to also have a challenge!
+
+I allow purchasing animals at forts; it seemed like it would have been quite
+possible. So one can do that if they wish. Thus if one dares they can spend 0
+at first, though this is will slow them down a fair bit, and the very first
+message shows something amusing about this idea as does when you overspend (I
+think it was then). Well it might not be the very first message but it is early
+on.
+
+Another fun one: if you have enough ammo (`>1999` I think) when a fire breaks
+out in your wagon event triggers then everything blows up and you die; if you
+don't spend 400+ (5 bullets per dollar) on ammo this will only lead to food and
+supplies being damaged (which really means losing food and having damage to
+supplies - at least I think that's what I had it as) - plus losing a few miles.
+I think that was all that happened.
+
+This means more strategic play is necessary because you have to be careful with
+how many you buy; spending 400 will give you 2000, right over that amount, so
+this also makes you have to go to the fort more, potentially, which (with more
+money and depending on initial spending) might not be as necessary otherwise.
+But of course it's a short game so you might not need that much anyway. Having
+more money (for theme and also doctor's cost - also thematic) allows for
+different kinds of play too!
+
+The original game has a 'how good a shot are you' and based on this and typing a
+certain word (and depending on how fast you type the word) it would change the
+chance of a successful shot. Unfortunately this would: require a `char *`, it
+would require using `fgets(3)` or `getline(3)` (both of which retain the
+newline) and would require a strcmp() (or more likely a strcasecmp()) and it
+would also require using the `time_t` related functions: that is a serious
+amount of bytes.
+
+So instead it is based on the pRNG. At first I had it also be based on how many
+times you shot but this is wasteful and not useful with a short game.
+Additionally this check cannot be perfect. Even in old text based games (some of
+which have it based on skill, some not) it varied. What matters is all levels of
+success is possible, assuming you actually have bullets - and that is how it is.
+
+This also makes it more fair as some people can type `betrte tanh ohters` and
+although some games do require speed in typing those games often have clients
+that allow for automatically sending those strings in (even varying strings) or
+aliasing them so that's not comparable (I know this from my past, both as a
+player and a dev, just like when I was talking about old text games and lots of
+text - you know, kind of like all I've written here).
+
+Animals tend to avoid large groups of people. There are exceptions but the
+reality is that the people on the Oregon Trail travelled in large groups and
+wild animals (which it seems in the original game are wolves) tend to shy away
+from humans and for good reason. So that event is not in the game for one
+example, even if there might have been some occasions where wolves did attack.
+Of course neither dragons nor Tyrannosauruses avoid humans as they have no fear
+of humans... You should fear THEM though. And yes these events (might be shared
+actually but depends on the pRNG which one) replace the wolves.
+
+This game might or might not be too easy. It really kind of depends on both
+strategy and luck, sometimes a lot of luck and also strategy. Nonetheless you
+can both win and lose this game: personally with all the hazards I more often
+than not lose, though it also can depend on how you spend your money, but the
+jokes are there so that it's not as annoying.
+
+Of course sometimes I deliberately make decisions that make it much less likely
+I'll win and rather die but that's another matter entirely. An example is buying
+too much ammo: that usually results in a specific death event though it might
+not always happen, especially if you do it at the end; but of course it's
+possible it could. Although it also comes down to luck there **is** a way to
+increase the CHANCE you will win. I'm not saying what this is though.
+
+Of course one might argue there is not really any winning in this game anyway:
+something about that pact...
+
+The original asked you how well you wanted to eat. This was too wasteful of
+bytes and also unnecessary. Although one would (if they're wise) start to ration
+food if they're running low with the exception of people who are fasting most
+don't deliberately starve themselves (okay and eating disorders aside too).
+Original game you die if you run out of food. In mine it depends. In real life
+you wouldn't die right away either. They might even be close to the destination.
+
+Some of the jokes with getting more food - if your son is lost he freezes to
+death and you might as well have at him. The line of morality thins as humans
+are desperate and although it might make people uncomfortable to consider and
+although nobody (or very few) want to even think about it, the will to survive
+sometimes makes you do things you never would have imagined you could or would
+do and in real life cannibalism **did happen** on the Oregon Trail. There is
+another way this happens in the game too, though, not just your son. If I may,
+it's all done in 'good taste', even if that sounds like bad taste. Still if
+you're a bit squeamish... Anyway, everything has a joke or jokes to it, and the
+narrator is a big part of it.
+
+The lovely thing about taking some decisions out is that it saves bytes for more
+obfuscation and many more jokes (though depending on sense of humour some might
+not like it; others will be laughing hysterically - all my friends and others I
+have shown it to certainly find it hilarious).
+
+Plus the judges like to laugh. They also like to throw up and I believe that the
+messages might very well have potential for those :-)
+
+The game originally had 2040 miles; the Trail seems to be actually 2170 miles so
+my game has that number. The check of the mountains (distance wise) was
+corrected as well, as best I can tell, in particular the Blue Mountains (though
+there's no direct message about 'Blue Mountains'). I might have changed the
+other mountains as well - not sure.
+
+Another thing: money: you start out with `$1666`: an ominous beginning to
+foreshadow things to come. I wanted `$6666` but it was just too much and so is
+`$2666`. There is a reason the player needs more money and it also has to do
+with humour and is thematic to the 'A Pact With the Devil'. In particular it's
+to do with when you need to see the doctor. And that's just the thing: do you
+spend more money on food and oxen and other things and risk not being able to
+afford the doctor: or do you risk not having enough oxen and clothing etc.?
+Depending on your choice you might not have to do much hunting though I guess
+that's unrealistic: but of course this makes it more fun as you have to
+strategise carefully.
+
+Another one comes to mind: I believe Oregon Trail has 19 turns but you have 0-20
+here, so 21 (I think). That could be needed in some cases although I have indeed
+numerous times managed to run out of turns (that's luck - perhaps bad luck).
+
+
+
+### Dedications
+
+
+This program is dedicated to:
+
+- Everyone who has written spaghetti code, so they can finally point the finger
+at the MONSTER who wrote this code.
+- Everyone who has eaten so much spaghetti that they passed out, hit their head
+and woke up a week later weighing 15kg more and forgetting who they are.
+- Everyone who has been strangled to death, like the Devil was on the Oregon
+Trail, in 1847:
+
+
+
+
+
+### Concluding remarks - and things that might be worth remembering when judging
+
+
+First, one of the fun things I did. Did you notice this?
+
+```
+ goto go; to:;
+```
+
+Another fun one: unless I am very mistaken: my code has FAR MORE events in my
+code than the BASIC game, in WAY LESS code (that part is certainly true). In
+fact I believe, as noted elsewhere, the BASIC game has 16 events, and mine has
+23.
+
+Both have the mountains events although it is not clear to me if every event in
+the mountains is in my code (I have others, and very likely more than the 1978
+game). And like I said elsewhere, some of the events in mine are different
+depending on chance - they are polymorphic in a way.
+
+But of course it's basically an entirely different game and mine is funny as its
+primary purpose, something that makes the game even more enjoyable. With the alt
+code there is even more. And yet, despite there being more events, by a lot, I
+believe, look at this:
+
+```
+ $ grep -v REM oregontrail.bas |wc -c
+ 16974
+```
+
+But with mine `wc -c` reports just 4666! And that could be shorter if I didn't
+want the theme size.
+
+So I do FAR MORE in FAR LESS code! Sure the messages are longer but even so,
+removing both messages and comments from the original BASIC game...
+
+```
+ $ grep -vE 'PRINT|REM' oregontrail.bas |wc -c
+ 7547
+```
+
+I **STILL** do way more in less code! How did I even manage that? Cleverly and
+carefully, that's how! :-) Now the strings being removed is more fair too as I
+don't have the strings in the code itself; and with removing strings printed it
+also means that my code has code that prints strings and gets input - and it has
+more strings too I'm pretty sure; and yet it still does it in much less code!
+
+Of course we have to contend with BASIC requiring the numbers at the beginning
+of the lines so let's be **FAR MORE** aggressive:
+
+```
+ $ grep -vE "PRINT|REM|'" oregontrail.bas|sed -e 's/^[0-9][0-9][0-9][0-9]//g' -e '/^$/d' |wc -c
+ 5680
+```
+
+Even removing the lines starting with `'`, deleting empty lines, removing the
+numbers at the beginning of the lines followed by the space I **STILL** have my
+code in far fewer bytes.
+
+Let's be **EVEN MORE AGGRESSIVE** by removing **ALL SPACES** (which would be
+invalid BASIC):
+
+```
+ $ grep -vE "PRINT|REM|'" oregontrail.bas|sed -e 's/^[0-9][0-9][0-9][0-9]//g' -e '/^$/d' |tr -d ' '|wc -c
+ 4735
+```
+
+And as a reminder...
+
+```
+ $ wc -c prog.c
+ 4666 prog.c
+```
+
+and if I removed all spaces in my code (which would also be invalid code but for
+comparison):
+
+```
+ $ tr -d ' ' using abusing `goto`. But it also stresses just how bad the flow
+control is here. Okay, so it's probably mostly to show just how hard my code is
+to follow, but I DO hope that people are HORRIFIED by my abuse of `goto`.
+Probably if anything would make an impact it would be the code. But I don't
+think anything will, sadly.
+
+**DISCLAIMER**: the reason for this is to drive home just how absurd `goto`s are
+and how dangerous they can be, not to mention how much is lost by using them,
+exactly as the contest desires (and I believe I have delivered in appalling
+ways): NOT to demean those who use them outside of the IOCCC, although I would
+love for people to stop doing that.
+
+`goto`s do not belong outside of the IOCCC. It can lead to major stress and
+cause extreme expletives. Not that the latter is necessarily a problem but
+having to maintain unmaintainable code is not good. Why should you have to
+maintain code that goes all over the place in erratic ways?
+
+This is why I've used them - so you don't have to. Not that I believe that will
+change anything. But I wish it would. Of course my abuse of `goto`s might also
+destroy your brain or make you curse me so not much gain for you and worse for
+me. But hopefully it also confounds you as well. If I have to suffer why
+shouldn't you? :-)
+
+The mind destroying amount of `goto`s in really bizarre ways, even in ways that
+look like they would cause a data race (but do not), having code in the opposite
+or wrong blocks, code that could easily be mistaken for invoking UB (but
+doesn't), and MUCH MUCH MORE all from `goto`s, makes it **EXTREMELY HARD** to
+trace.
+
+I will argue that the code is one of the best (if not **THE** best - and I truly
+hope it IS the best) examples of why `goto` was a very bad idea (this is not asm
+or similar).
+
+The suggestion that 'goto considered harmful' is considered harmful is
+ludicrous. But I have taken that to hell and back. It is my hope that my abuse
+of `goto`s here shows why one should never use `goto`s outside of the IOCCC.
+
+The idea that it's necessary in some cases is just an excuse for poor style, and
+I believe my code showed this, again just like the contest asks. Sure,
+it might make it a bit easier to jump out of nested loops (for example): but at
+what cost? You lose maintainability, readability and much more and for what
+purpose? There are other ways to deal with the problem including additional
+routines which is perfectly clean.
+
+Even better it doesn't force people to jump on a trampoline upside down until
+they break their neck. Or worse, break their mind. Or the code. For other things
+it might or might not help with there are other solutions.
+
+For instance, in a normal program, I wouldn't have put all of `main()` in a
+single switch and have it driven almost entirely (if not entirely, which I
+actually think is closer to the mark) by `goto`.
+
+I would have used a normal game loop. The idea of moving if/else
+into else/if or somewhere else; the idea of moving the body of loops to
+somewhere else, even two loops having the other loop's body and acting on the
+same array; the code falling through to a goto that then jumps to right
+before that code that just fell through: none of these are good style. They make
+maintenance almost impossible. Yes even when it's not as extreme as mine (though
+obviously mine takes the biscuit). This is the point of the IOCCC. To show how
+poor style ruins maintainability.
+
+Now other things: in a normal program I would not have put near 200 `char *`s in
+a single flat `char *`, although I do think that's pretty cool and clever.
+
+I probably wouldn't have written code that looks illegal like the
+`+--` I talked about in [obfuscation.html](obfuscation.html) (in fact in some
+if not most contexts it IS illegal). The bastardised Duff's device I would not
+do. I would not put the entire function in a switch.
+
+But above all I would not have used 116 (or 134) `goto`s. Or ten. Or five. Or
+even one. Better to let code generators like flex/bison take the crown. I have
+dethroned them though (at least from what I have seen before) - by a huge
+amount. But perhaps [1987/hines](https://www.ioccc.org/1987/hines/index.html)
+had the crown. It no longer does. I should be ashamed. I'm not.
+
+But even if I were to abuse `goto` I would not normally use it in the ways I did, as
+noted earlier and in [obfuscation.html](obfuscation.html)!
+
+If I am ever dethroned, assuming I now have the crown as I think I do (and I
+hope I do because if I do not there is something very wrong), I will be
+absolutely horrified.
+
+Okay I'll be kind of amused too but I would be horrified. Still I guess in the
+context of the IOCCC I really have reached the logical conclusion of `goto`s
+(which, as you'll see, the 1987/hines one, was thought to be by the judges the
+logical conclusion - see below for more information on THAT and an exercise in
+absurdity), or at least I hope so.
+
+It's about time either way. Hopefully the judges will take `goto` and throw it
+into the deepest bowels of the Earth.
+
+But even if by some chance someone else tried this this year (and for MANY
+reasons I hope nobody did), I believe the other things I have done are also
+quite worthy of the contest and certainly meet the goals. I mentioned some
+several times in different files, mostly in [obfuscation.html](obfuscation.html).
+
+Okay yes one of the reasons I hope nobody else tried this is the absurdity is so
+extreme that if I'm going to go through the effort I might as well get to enjoy
+it. Still, I've done a lot of unique and clever things, especially in the
+encrypted version (but the decrypted version has plenty too - all but the memory
+tricks).
+
+I'll repeat this again but this program should not work. But it does work and it
+does it well. That is unthinkable. Frankly it should be unacceptable.
+
+**PLEASE** understand: I do not mean to insult people who use `goto`s. There are
+plenty of **AMAZING** programmers that use them, including some that have done
+things I have never done (and I hope they have NEVER done what I have just done
+too, and I really hope someone doesn't try and beat me at this, even if that
+would be hilarious and kind of an honour - see below).
+
+But it totally ruins maintenance and readability. If you look at my code
+you can see that - to extreme proportions, much worse than usual, but still you
+can see it.
+
+I would not blame the judges if they never want to see `goto`s again. I feel the
+same way. But if a prediction ever went wrong the judges' prediction of 1987
+went wrong in HYSTERICALLY BAD ways:
+
+> This program was designed to maximize the bother function for structured
+programmers. This program takes `goto` statements to their **logical
+conclusion**. The layout and choice of names are classic.
+>
+> We consider this to be a beautiful counter-example for Frank Rubin's letter to
+ACM form titled: _["'GOTO Considered Harmful' Considered
+Harmful"](https://web.archive.org/web/20090320002214/http://www.ecn.purdue.edu/ParaMount/papers/rubin87goto.pdf)_.
+See the Communications of the ACM, March 1987, Page 195-196.
+
+I shattered that record, if it is indeed the IOCCC record of `goto`s, or rather
+was, which I sure hope it was. And of course I did more than that. But it's
+hilarious what I did, or at least I think so. I mean sure, it's also horrifying
+but it's funny in the worst possible ways. In a little bit I will also shatter
+some things in Frank's letter, to really drive at just how hard this is to
+follow.
+
+I did something I hope nobody else has ever done and I hope nobody tries beating
+me. The entire program is driven by `goto`, even parts that might not have a
+direct `goto` (if there are any it's very few) are still driven by `goto`, and I
+mean many `goto`s.
+
+There are so many `goto`s that to try and move code to add more `goto`s is
+basically pointless, unless as a joke. In this program it would really not do
+anything. I essentially ran out of code to move. Even if I had more though,
+isn't 134 enough, especially in a program that, counting spaces, including
+unnecessary spaces to add to the size, is only 4666 bytes? It would be smaller
+except to stay on theme. Doing more would no longer be funny. Enough is enough.
+Or at least I hope.
+
+But it really is that extreme.
+
+Here are some things Frank wrote:
+
+> The result is that GOTO-less programs are harder and costlier to create, test,
+and modify.
+
+But is that REALLY true?
+
+Take a look at my program. Good luck maintaining it! The idea that `goto` makes
+it easier to maintain is hysterical. `goto` makes it harder to create, harder to
+test and harder to modify. Not only that it also makes it harder to debug.
+
+As I point out soon, a single false goto in fact DID happen. It was a close
+shave, so to speak.
+
+I dare ANYONE to run my program through a debugger without losing their mind:
+especially, and maybe particularly (if not always), if there was a bug. If I had
+to do this, anyway, I would cry and curse MYSELF!
+
+IF someone actually could do this without losing their mind, I would tip my
+proverbial hat to them. They would have to be extremely patient - and have
+traits I do not even know how to describe. Perhaps they would be utterly
+ineffable.
+
+Actually I wanted to see what it was like. It was VERY amusing - but only
+because I did not have to debug it. I ran out of files to include and I'm low on
+time (mere hours left) but to get to JUST the third prompt this is the lines it
+went in the following sequence:
+
+```
+ 19 20 21 32 69 82 34 33 34 47 45 47 50 83 34 33 34 47 45 47 50 83 34 33 34
+```
+
+The game loop is almost certainly much worse, especially those two for loops I
+mentioned, but there is much much more. If this is easier to follow then I'm a
+dragon. I'm not a dragon. I have a secret for you: dragons don't exist. Except
+on the Oregon Trail.
+
+> I have yet to see a single study that supported the supposition that GOTOs are
+harmful (I presume this is not because nobody has tried). Nonetheless, people
+seem to need to believe that avoiding GOTOs will automatically make programs
+cheap and reliable. They will accept any statement affirming that belief, and
+dismiss any statement opposing it.
+
+Well after a bit more than 38 years I have finally provided exactly what Frank
+said was missing. And it was about time. Not that it didn't happen before. But
+he was wrong.
+
+It is not about not trying. But even IF he was right, he
+sure is WRONG NOW. Anyone who thinks otherwise needs to try and debug
+my program - or maintain it. Or write it.
+
+It would have been SO MUCH EASIER if I did not use 134 `goto`s. Actually, even a
+tiny portion of that would make it harder. Nobody, whether they're in their
+right mind or not, would WANT to maintain this, or something even close to it.
+
+Even flex/bison code, which as far as I am aware uses FAR fewer `goto`s, is
+notorious for `goto`s and is quite hard to follow. It would be a nightmare to
+try and maintain without the .l/.y source files.
+
+Okay, yes, I admit it: my abuse is extreme.
+
+That doesn't matter. As I remind everyone later, Apple caused a security hole
+because of a SINGLE misplaced `goto`. Mine is 133 more than that - and it works.
+It shouldn't.
+
+> Then they turn around and say, 'See, the program with GOTOs is more complex.'
+In short, the belief that GOTOs are harmful appears to have become a religious
+doctrine, unassailable by evidence.
+
+Well, Frank, I hope you appreciate the evidence now.
+
+I could go on but I don't want to criticise, as I said somewhere, and it's not
+really important. My point was that where 1987/hines IS INDEED a beautiful
+counter-example of this letter, mine takes it much further. This program is not
+something anyone would want to maintain - presumably even Frank.
+
+I think everyone gets the idea. The fact I did all this WITHOUT invoking UB or
+breaking things is remarkable. It was through a lot of care and again, EVEN A SINGLE
+FALSE `goto` would have destroyed it.
+
+In fact this ACTUALLY HAPPENED at one point. I had to roll back a commit.
+Thankfully I discovered it quickly. It would have been a bloody nightmare if I
+hadn't. I might not have finished this in time. I'm pretty sure that is the
+case. I might have had to start over.
+
+I would have used git bisect but it would have been a lot of time lost, if I had
+made even a few more commits. As it is it took a full two months and I BARELY
+finished this. In fact I finished it within hours of the contest closing! It was
+not even 12 hours before closing time. I barely made it. Part of that is I added
+even more `goto`s, despite the fact I had reached 2503 in size.
+
+Countless times I came up with ways to do more, at least where it was possible,
+such as freeing space so I could change some `break;`s to a `goto Z;` as `Z:`
+was already there. The only other times this happened is before I had changed
+the code so much that you can no longer trust what a block of code is. Like I
+said, I could not really move any more code if I wanted to, even if I had more
+space free. Those very few places where the code could in theory be moved are
+already controlled by goto.
+
+Anyway, as I noted in [obfuscation.html](obfuscation.html), no initialisation is
+skipped in my jumps and that is what causes `goto` to invoke UB.
+
+Everything is file scope. And in any case, when I do jump to a place, everything
+is initialised - for instance when I jump in the body of a for loop, the
+variable is already initialised. The audacity of having one of the loops that
+jumps somewhere else jumping into another for loop that acts on the same array
+in different ways is rather horrifying - except in the IOCCC of course.
+
+There is just too much spaghetti in the pot already, and that's not counting the
+other things I have done, some of which would make it harder to add even more
+`goto`s. In any case it would be taking the joke too far. It was better to have
+other unique/interesting/tricky things I did, including some subtle ones (not to
+say I did not do these things with `goto` but I did these things unrelated to
+`goto` also).
+
+And the BASIC game has only 109. How is this possible when BASIC is built on it
+and C is not?
+
+That is OBSCENE. It is `goto hell`. But any use of `goto` is obscene and is a
+failure to use easier to maintain code. It's not a failure here but only because
+it's the IOCCC.
+
+My code is hard to follow yes but it's almost impossible (if not impossible) to
+maintain. In fact it pretty much is impossible to maintain. I did try adding
+more `goto`s in another file, just to see. I managed but it didn't really add
+anything. There simply was nothing to move. There might be a few things here and
+there but the only place I could put them is in a place that already has moved
+code. In fact, much earlier on that already happened! You can see this in
+numerous blocks of code. The fact is there are so many that there really is no
+space for more!
+
+As I noted in [obfuscation.html](obfuscation.html), the way I have structured (is
+that even the right word? I think not) main() means that you cannot rely on ANY
+of the old rules. Blocks of code, whether if/else, for, while, switch, none of
+these can be relied on as for what they have, except that obviously `case` can
+only be in a switch. But then the code that is in a switch, and even
+`case`s...those cannot be relied on.
+
+Even if I didn't do the other cool tricks, the spaghetti code is so extreme that
+it's a PERFECT example of code that is both hard to follow and hard if not
+impossible to maintain.
+
+The many other things I did are quite interesting and (I think) unique
+but whereas those show really cool things that can be done in C, some quite
+subtle (and little used if ever used in the IOCCC - and in some cases perhaps
+anywhere, maybe the single `char *y` holding near 200 `char *`s), it is the
+`goto` spaghetti code that makes it impossible to trace the flow of the code.
+Even if there was not data hiding one could not be sure where you're going to
+be and this stays that way throughout the execution of the program.
+
+I mostly ran out of code to move. Yes I could in **theory** move more code about
+but it would only be chains, except in maybe a small amount of places (if even
+that). I would need more code in order to do more. The fact it's a feature-rich
+game and that I did it compactly and yet somehow I have basically moved all the
+code to where it does not belong, sometimes in a chain, sometimes not, that is
+appalling.
+
+In fact, as I showed in the [obfuscation.html](obfuscation.html) file, there is more
+than **TWO TIMES AS MANY** `goto`s as there are `if`s, and that is the second
+most frequent keyword!
+
+Actually my program **SERVES A PUBLIC SERVICE**: by showing abuse of `goto` to
+the degree I have taken it in this program, it demonstrates why you should avoid
+`goto`s unless you're writing obfuscated code.
+
+No matter how many you have, UNLESS IT'S 0, it makes it hard to maintain and
+ensure that the code is correct. So how did I actually manage doing exactly
+that? Very carefully - and I nearly lost my mind doing it. I will not make any
+judgement on anyone else who uses them.
+
+Anyway, I am even reminded of Apple's **SINGLE** misplaced `goto` that caused a
+**SECURITY HOLE** (CVE-2014-1266):
+.
+That's all it takes: **JUST ONE `goto` led to a CVE**!
+
+It is ironic, perfect and hilarious that it was `goto fail;` as it was actually
+a failure in using `goto`! My code has 134 (with the cpp, 116 without). That is
+obscene. I did not fail. At all.
+
+On the contrary I have made a point. Okay, that is not the only reason I did it
+but when I got started I couldn't help it...I thought it was (and still do think
+it is) hilarious. But only for satirical programming like the contest. I would
+not be amused if I had to maintain this.
+
+If you have to jump back and forth to another place in the function (and
+with `longjmp(3)` it can be even worse depending on how far from the function it
+jumps, assuming it does change functions - though not necessarily worse as it
+still has the same effect) then IT CAN BE EASIER TO OPEN IT IN TWO OR MORE
+(EDITOR) SESSIONS so you can be in more than one place at a time. That **SHOULD
+NOT BE NEEDED!**
+
+It should not even be USEFUL! If this is happening there is a serious problem -
+although in this case since it's such a small program, maybe two or three
+screens only, and since the code is littered with `goto`s, even that might not
+be useful. It probably doesn't help at all. But that doesn't make it any better.
+It might make it worse in this case but that's not the point. Earlier on it did
+help though, and that is a good sign for the contest.
+
+As the code complexity increases and the number of jumps increases it gets much
+harder, possibly exponentially harder. This can cause security holes as well as
+simply buggy code, with an example above.
+
+I went through GREAT PAINS (and utter EXHAUSTION) to make sure everything is as
+I wanted it but as I wrote in [obfuscation.html](obfuscation.html) I was **SURE** I
+had done something (or rather several things) wrong. This should **NOT** be
+required when writing code. It should be time efficient and it should **NOT** be
+error prone. And this is why I did this - exactly because it's extremely hard to
+follow but also to highlight how easy it is to fall into the `goto` rabbit hole.
+Satirical programming, exactly as the IOCCC prescribes (it is entirely unclear
+if the author needs another kind of prescription).
+
+Yes. I realise that asm has `JMP`. I realise that BASIC is built on `GOTO`. And
+yes other languages besides. But C is not those languages (and still beat BASIC
+because why not? I mean clearly something is wrong with me...). Is there really
+a NEED to destroy structure when the language is designed to have structure?
+Yes, in the IOCCC, but outside that?
+
+In BASIC and asm and some other languages jumps are a core part of the language.
+And those languages can be harder to maintain partly because of jumps. C is not
+one of those languages. Or it wasn't until now.
+
+Yes, yes...I know, I **KNOW** I put in 116 `goto`s with 134 when pre-processed
+and that is probably more extreme than any other C program, especially in such a
+small program (and I REALLY hope I'm right there!). But **this does NOT matter**!
+Even if one or two were not harmful (but they are) it's jumping down a rabbit
+hole that can very easily get deeper and deeper just like Alice found. When
+there's no **NEED** for it it's much worse.
+
+`goto`s are harmful and destroy flow control. I have shown a fair few obscure
+things about C, some which SEEM ILLEGAL but are not, but above all I have shown
+how much is lost with `goto`s (okay, I have shown this with other things too).
+The joke could be called satire too: satire of `goto`. But that's to highlight
+the folly and mistake of `goto`s.
+
+The best place (the **ONLY** place) to do this is the IOCCC when it comes to C
+(maybe the underhanded contest or whatever it's called too but that's also a
+contest about hiding things). For these reasons alone this program is a service
+to the public and I hope the judges appreciate this, even if they laugh. Or cry.
+Or throw up.
+
+Although as noted if there is anyone who could figure it out, it is the IOCCC
+judges, but even then it's very hard to follow the code because it's almost
+constantly jumping to another location, sometimes in a chain, one time even a
+chain that leads you right back to right after the jump, in essence doing
+absolutely nothing but leading you down a false path. I already mentioned some
+of the other things - the rules no longer apply in my program, of where code is.
+The only one that remains the same, that I can think of, is that the cases are
+in a switch() but that's because that's the only place they can be. Obviously I
+would have had them elsewhere if I could have.
+
+And yet...I use labels like they were cases! I even reuse cases, giving them
+different behaviour, in a sense, as if they're polymorphic. So although I
+don't have cases outside a switch - only because they're not allowed outside of
+switches - I did something just as bad, putting a lot of code inside switches
+where it should not be. That looks wrong. Other things look wrong. But yet they
+work.
+
+I discussed other ways labels and cases were used in
+[obfuscation.html](obfuscation.html) - though maybe I missed some - so I won't
+repeat them here. I've already said too much, due to the fact this was written
+over the span of two months. I will also refer you there for other things
+including many unrelated to `goto` - plus others to do with `goto`. Perhaps
+checking [prog.c](prog.c) is the most useful though.
+
+Nonetheless, there really is absolutely no reason for this outside the contest.
+What I have done certainly shows how easy it is to make code unmaintainable,
+simply by `goto`. I am putting a bright light on the IOCCC with this.
+
+Honestly it doesn't matter if I'm abusing `goto` in unusual ways, except when it
+comes to judging, of course. Spaghetti code is spaghetti code.
+
+The only kind of spaghetti that should exist is in a pot, on a plate or in the
+stomach. Or on a tree for more details if you do not
+recognise what I mean - and yes it's in the game).
+
+On a lighter note (or maybe this is darker?): did you know that every time a
+`goto` is used an angel (whatever you consider an angel) **DIES** and goes
+straight to HELL? You don't really want that do you? I didn't think so. Yes I
+killed 134 angels. YES I condemned 134 angels to eternal torment. I **HAD** to.
+I don't regret it - but you should, if you **ever** write something like this
+outside the IOCCC. In fact you should regret a single goto angel
+dying. Even if they did not go straight to hell in a handcart, you should still
+regret it. But they do. Okay so I don't really believe that but there is no
+denying there is goto hell here.
+
+I found my abuse of `goto` hilarious. It was good intentions - the contest. But
+sadly sometimes the worst things that happen start with good intentions; and
+some of the best things strangely start with horrible intentions. It might be
+that I did this with good intentions for the contest but it would not be good
+anywhere else. I would be beyond angry if I had to maintain this code. I would
+not blame anyone if they cursed me. I probably would be too. Not cursing you. I
+mean cursing me.
+
+Don't write code like this. Except for the IOCCC. Unless of course the judges
+decide they want no more `goto`s. I would not put that past them after what I
+have done. I can imagine them screaming and crying. Hopefully they're laughing
+at more than the jokes but I hope they laugh at this too. Well we'll see I
+guess...
+
+Frankly THIS PROGRAM SHOULD NOT WORK! But it does and it works well even if the
+flow-control is a horrible nightmare from hell. Perhaps the Devil truly has
+possessed it. Hell, he might have possessed me. Why else would I send C straight
+to Hell? How could this program POSSIBLY work without it? Carefully, that's how.
+
+Oh as for that exercise in absurdity. I was able to, in another file, change all
+but one `break;` into `goto Z;` and add one or two other `goto`s, without going
+over the iocccsize limit (did this in my decrypted version, I was already at the
+limit with the encrypted one). And I am not sure if it would even work. The
+`goto Z;` would but the rest I can't say for sure.
+
+And as for the rest there genuinely was not much that I could move anyway. When
+I say I ran out of code to move, I really mean it. The code I moved in this
+absurd exercise is, like I said before, already filtered through major abuse of
+`goto`s.
+
+I could change all but one of the `break;`s to `goto Z;` and that would increase
+it a bit. I might be able to move one or two blocks of code before reaching the
+2503 limit. With the exception of the `goto Z;` (which incidentally is done in
+some sneaky places) the others would be perilous.
+
+So if I have not reached the actual logical conclusion of `goto` then it has to be
+in a much bigger program, but after doing this, I pity anyone who would do that,
+for they're only going to cause themselves and others problems. I believe in any
+case this finally reaches the logical conclusion of `goto`s in the IOCCC,
+unless the size limit is changed a lot again, and I it doesn't, as 2503 is a
+nice number and also allows for so much, as I have shown.
+
+Something it allows too much of though: `goto`s. I have shown that. I've
+dethroned 1987/hines by a staggering amount.
+
+One final thing to ponder. This is from an article about tools that obfuscate
+code, C and C++ (which I hate). It is called 'Code Obfuscation For the C and CPP
+Programming Languages':
+
+> The correctness of an obfuscator is important, but proving this correctness
+isn't easy. Changes in semantics may be subtle, they may only show up on certain
+niche platforms or under very specific runtime circumstances. For a language
+like C or C++ verifying the correctness thoroughly is practically impossible,
+but a good testing methodology can find many issues.
+
+What about the reverse? Although perhaps a few can (but perhaps not): it would
+be **extremely** hard to deobfuscate my code without changing the behaviour in
+every way, probably even if there wasn't code that seems dead (or is dead) - and
+even worse as I have not even revealed everything with that. I don't even think
+**I** could change this to not use `goto`s without breaking it! But what I do
+know is it works exactly as intended. But it shouldn't. It really shouldn't.
+
+
+[^1]: He purportedly (when attacking a ship) had lit fuses on his beard so it
+looked like he was coming out of hell (or that's what it is thought those who
+saw him figured, purportedly).
+
+[^2]: Even if, for example, you know The Lord of the Rings very well, you'll
+probably run into problems with some of the code. The same with The Hobbit. It
+would be worse with The Chronicles of Narnia. Probably most stories you'll run
+into issues without some code modifications (have fun!!). But hopefully this
+helps you appreciate the careful design even more.
+
+
+#### P.S. select remarks made to the IOCCC Judges
+
+A hilarious truth is that to write less can take drastically more time than to
+write more and unfortunately I am running out of time quickly. Writing this game
+took too much time as I really did pour my heart into it. The jokes took a lot
+of time and I repeatedly found ways to shave off even more bytes for both
+obfuscation and events.
+
+Oh...something I discussed in sections above. Yes I have more space in
+this one. Yes in theory I could have added more `goto`s. But in fact not really.
+In my concluding remarks in that file I explain this. I basically ran out of
+code to even move. The `goto`s should speak for themselves. If I were to move
+the few remaining pieces of code without a direct `goto` it would only be moved
+to a place that already has some code that does not belong there. In fact that
+actually already is a problem and was a problem earlier on.
+
+But let's just say, for fun, that I'm saving your sanity - and what remains of
+mine. I hope you appreciate that after what I have done. But I do also hope you
+laugh.
+
+But honestly: after a certain point spaghetti code is not going to get worse.
+The spaghetti code in the encrypted submission is not any worse so why bother
+with adding more spaghetti to the pot? Just like with temperature, where at some
+point hot is hot, spaghetti code is spaghetti code and I have never seen worse
+spaghetti code, at least not in C.
+
+And although it might not be, I would not be surprised if this submission, or
+the encrypted one, makes you fed up with `goto`s. I know I am, and as far as I
+am concerned, they only belong in obfuscated code! I would understand if you
+wanted something else new, including some new things I have put in here as well
+(or so I think new, some to do with goto but a fair amount totally unrelated,
+and definitely subtle), and no longer want `goto`s, after this.
+
+In fact a goal of mine was to show just how absurd they really are and just how
+much is lost with them. I believe I succeeded remarkably. If so I have met the
+goal of the contest.
+
+But honestly, the amount of `goto`s that I already mentioned is bad enough. When
+you see what and how I have done it though, it's far worse. It should be
+illegal and it should not work. But as you'll find out in various files it does
+work exactly as I mean it to. There is indeed dead code. Intentionally to
+mislead. One thing directs you throughout main() only to end up right after it
+started, serving no purpose but to mislead you into thinking something important
+is going to happen. But there is so much more.
+
+You might throw up from the amount of `goto`s I have included in a small
+program. I would say that if you deem one of these winning I hope the encrypted
+one wins because I find it far more beautiful and creative, as well as more
+thematic, which I'm sure you'll understand why.
+
+But by making it the same except for how the strings are printed, you can judge
+on the same number of gotos. In fact, it should be the same program otherwise,
+which was my original reason for making another submission: for even more
+portability. Now you can appreciate even more that it's meant for portability in
+the off-chance you have a system that does not like what I have done (though
+the ASCII only file should solve that problem). Even so...
+
+If you find the portability here better and you're concerned about that, then
+obviously you could choose this one instead, again assuming you deem this worthy
+of winning. I might point out that I have tested it in multiple systems, and the
+emojis display fine in those systems (well one is over ssh as it's the console
+only but the program decrypts them fine).
+
+The fact I actually encrypt and decrypt emojis, multibyte characters, on a byte
+level, without corrupting them, is pretty incredible and surprising. That took
+some work to figure out, just like the encryption set up in general. The way the
+key is used to obtain the key along with carefully controlled memory abuse is
+something special too, not to mention thematic.
+
+But again, as I made an ASCII only file any issues there shouldn't be a problem
+anyway. That is why I included it, for portability. I think it's pretty amazing
+what I did with encryption though.
+
+
+
+### Troubleshooting
+
+
+**IMPORTANT**: if the program exits without doing anything then either the data
+file could not be read (see below) although that would likely only happen if a
+strange problem occurs in your system OR you're running it from the wrong
+directory OR if `getdelim()` bugged out (nothing I can do about that - I can
+only check for NULL `FILE *` and an error in `getdelim(3)`).
+
+If strings seem to not look right you should do:
+
+```
+ make clobber makedata everything
+```
+
+And of course if output is bogus because of an emoji problem on YOUR system,
+make sure to use the ASCII only versions! (`./prog.asc` and `./prog.asc.alt`)!
+Or if you wish try and follow the steps on how to make your own data
+files in the section above, although obviously during judging that
+would not be useful. But that's what the other ASCII only data file is for and
+that's why the DATA macro.
+
+This should fix any problems you have.
+
+If that still fails you and you have tried compiling again then I suggest you
+ask the gods (or Devil) because you're doing something wrong and I cannot help
+you from here; the point is that the data file has to be padded in the way the
+addpadding.c tool does. Obviously the only way for you to rectify it is
+declaring it a winner to appease the gods (or Devil)! :-) Well you get the idea.
+Create the data files and try again. And if any emoji causes you problems on a
+system (or maybe a terminal emulator/terminal?) use the ASCII version instead -
+that's what it's there for!
+
+I made **A LOT** of sanity checks and was **EXTREMELY CAREFUL** in the design as
+one wrong byte could break everything. I have tested it with linux and macOS so
+if it doesn't work on these platforms and you're sure you didn't do something
+wrong :-) then perhaps the Devil visited you at night? Better declare it a
+winner to appease him! :-) Well you get the idea anyway! I wrote many tools and
+have different data files so that you can play it whether or not your system
+supports all of some of the emojis and there's a screenshot (emoji only as it
+doesn't make sense to have an ASCII only one of this) friendly one too.
+
+
+
+### Portability
+
+
+Just to be clear, in case I made an error in describing this (or was not clear
+enough or more possibly have the filenames messed up), the point of the .asc
+programs (compiled with `prog.c` for submission and `prog.alt.c` for alt code
+with more events) is to be ASCII only (again if there is such a thing as a
+character that's >4 bytes that is unknown to me to check).
+
+This is why I have the `DATA` macro. Rather than trying to keep the same code in
+multiple files (aside from a lot of the same code in the alt version that is in
+the submission code and trying to do this with the [commented code](commented.c)
+too) based on how it's compiled it will open the right data file. The only other
+macro at compilation is discussed in another place and it's only for the theme.
+I was considering having it in the code itself but that would look **REALLY
+BAD**. Since they don't really take many bytes, much fewer than past entries
+(many have used far more than just two), I believe it's more than fine,
+especially as it's only referred to that one time.
+
+In any case, with these things I have ensured **maximum portability**. Do remember
+for the emojis that some systems might have problems that mine do not and that's
+another reason for the ASCII only data file (as mentioned in the
+[Emojis](#emojis) section above).
+
+
+
+### Obfuscation
+
+
+To keep this file shorter please see the long [obfuscation.html](obfuscation.html)
+file.
+
+
+
+### Compiling
+
+
+At first I had: `-Dmain=int main` for the retro vibe. But that annoyed compilers
+enough that I decided to remove it as the compilers already are annoyed enough
+at my code without having to deal with the whining from dubious decisions of
+the C standards body. I had to use the `-Wno-strict-prototypes` in the end but
+`int` only takes one byte and this way I keep the `CDEFINE` to the absolute
+minimum, one for the long-standing IOCCC tradition (which also triggers an
+unused variable warning, another dubious warning) and the other for portability.
+
+Looking at the code you might suggest that the author should have their head
+examined. But you might also think the code would trigger a lot more warnings
+than it actually does. Surprisingly few (relatively and comparatively) are
+triggered.
+
+Those that are triggered are totally bogus of course. It's not a 'small' amount
+with `-Weverything` but most of them are the usual suspects that come from
+overzealous style policing compiling. GCC emits some but not as many. Maybe only
+one or two depending on system but it's hard to keep track of.
+
+The '"misleading" indentation' is the bane of all obfuscators (and a lot of
+other code) and is a sign that the compiler thinks people can't read C code
+(which in this case would be good); but it's a STYLE POLICING WARNING, nothing
+more, and so I have disabled it to help compilers not cry. The number of
+`goto`s already might do that to them already.
+
+As you might have noticed there is at least one place in code where a fall
+through in a switch happens. I know, how horrible of me! But this saves bytes
+and is irrelevant.
+
+In fact in AT LEAST one place, an event, a case is at the end of its respective
+switch (e.g. `case `0), exactly so it doesn't need even a `break;` (others do
+this by a `goto`). But in all cases it's irrelevant and meant to happen. In fact
+it **MUST** happen! It still (ab|be)muses me that compilers whine about this and
+it's **absolutely adorable** here too that the compilers think they know the
+code better than I do. I mean I shouldn't but nonetheless I do know it.
+Horrifying, I know.
+
+The `-Wswitch-default` is ridiculous; there is no need for a default statement
+in every case (okay switch) and whining about it is making blatant assumptions
+that just so happen to be wrong, just like all the others.
+
+The `-Wunreachable-code` is a feature, not a bug: part of the thematic code, as
+noted in the [Obfuscation](#obfuscation) section (and possibly in
+[Humour](#humour), not sure). Okay there are other places where there is dead
+code but those are also intentional. I think one compiler actually thinks what
+actually is dead code: that's an if and the only way you can get in there is a
+goto, though it has something sneaky. What's nice about that, and it might be
+what confuses the compiler (not sure) is that the `else` is actually needed. But
+the `if` is a nice place to store labels, even though doing a `!` check would do
+what I need and maybe save bytes as I would not need an extra `{}`. But with
+misleading code it's totally worth it.
+
+Don't get me started on clang's `-Wunsafe-buffer-usage` or
+`-Wmissing-variable-declarations` or `-Wmissing-prototypes`. These are all
+TOTALLY BOGUS and as for the first one it is anti-C. The others want a 'static'
+of 'extern' and these waste bytes and are unnecessary as you obviously can't use
+the variables/functions if they don't exist!
+
+The `-Wshorten-64-to-32` is an overzealous warning and is triggered as part of
+the obfuscation of the data file (an important thing). It's not important if
+it's shortened to 32-bit. Actually in theory I could change the `long` to an
+`int` but doing this actually caused TWO additional warnings so what's the point
+in fixing it? Kind of funny to think about: fixing a warning triggered two other
+warnings. But this warning is unimportant. The way C works is precisely what I
+need. And isn't it lovely that emojis are encrypted with this code? I mean can
+you figure out how this works?
+
+The `-Wformat-nonliteral` is part of obfuscation **AND** allowing me to even
+have this as a submission. The format conversions for scanf and printf are way
+too long and would consume a huge amount of bytes[^3]. It would also make the
+program much less pretty and FAR MORE obvious. Well: maybe not: I guess it
+depends on if it would complain about how `V()` is done. But let's be honest:
+the fact is it's not much better when the data to be printed comes from an
+outside source. Well that's simply necessary in some programs. Even so the
+scanf() macro is used a number of times with different format conversions and
+the macro is required to prevent a mis-feature of scanf() causing an infinite
+loop that would flood the screen.
+
+As for the strict prototype one. The fact it is actually for ALL versions of C
+should show just how bad of a decision it is. If they want strict they should go
+to C++ or something else entirely. C is a powerful language and this warning
+interferes with very old code that otherwise works. Hopefully compilers like
+clang (notice a pattern here?) don't take this too far or else more code will no
+longer work with them clang.
+
+I'm not sure but there might be other warnings but all of the ones I encountered
+are absurd and have been disabled.
+
+To be more blunt: **NONE** of the warnings are valid and they're TOTALLY BOGUS:
+
+- one one is an utterly ridiculous **ANTITHESIS TO C**.
+- one (actually depending on how you count it, a number of them) is a blatant
+and **INCORRECT** assumption about the flow control.
+- at least two are style policing and also assuming (for one of them) that
+programmers don't know that indentation doesn't define a block (which is a
+ridiculous assumption).
+- the two `-Wmissing-variable-declarations` and `-Wmissing-prototypes` is because the
+compiler seems to think that a variable/function is used before it's declared
+even though it would trigger a compiler error instead (declaring it `static`
+solves the problem but it's ridiculous and wastes precious bytes).
+- The unsafe buffer one is because it warns against any pointer use of an array
+(even though this code doesn't make much use of pointers) - what a terrifying
+and shocking thought in a **C** program! I can barely keep my composure it is so
+horrible.
+- Others are due to size restrictions / obfuscation (see below) and other absurd
+and incorrect reasons.
+
+In fact **ALL these warnings** being triggered are
+**ONLY** a sign that the code is heavily obfuscated and many things are abused
+heavily as well, though as noted, in some cases (many cases) it's the compiler
+being overzealous / anti-C / anti-C programmers or even being confused, and all
+those warnings are invalid. But the rest should be ignored too as I'm sure you
+appreciate by now.
+
+Okay so the non-literal format one has **some** merit in **SOME** cases but it's
+not a problem here as the data does not come from the user (oh and have fun
+manipulating the data file). Okay technically it's POSSIBLE but if not done
+precisely right the program might not even make it that far. In fact, one false
+move, even a byte off, and it could very well end up with UB. But it's also
+necessary for both obfuscation and size. Besides it's not like IOCCC programs
+are meant to be secure (that's one of the things that is lost when code is
+deliberately designed to be hard to read) :-)
+
+If I may say: the compilers **DO** need to seriously have their heads checked
+and it's obvious from looking at the code that I most certainly **DO NOT**!
+There is nothing to worry about here. Except maybe my sanity... But that's the
+only possible valid warning. Maybe. And it's a big maybe.
+
+I already explained the reason for the `DATA` macro - portability etc. with
+emojis. Thus everyone ought to be covered. This was all carefully designed for
+maximum portability and I hope you appreciate this.
+
+
+
+### Concluding remarks - and things that might be worth remembering when judging
+
+
+See the concluding remarks in section above. The following additions can
+be considered as well however.
+
+Although I did bring it up elsewhere, yes I have more space in this version for
+more gotos spaghetti but what is the point? 121 in such a small
+program is bonkers. I started to run out of code to even move. I did in fact
+move a bit and I might have been able to find more. I could have done things
+differently but why? WHY?
+
+I am saving the judges the effort of having to try and figure out even more
+spaghetti. Sure it might be delicious but I don't want them to get fat. I'm
+doing them a service. Their bodies will thank me! Meanwhile my mind is thanking
+me.
+
+Yes it was that bad. I couldn't take it any more. I risked breaking something.
+Including my mind. I tested every event. Everything that happens that is
+supposed to happen happens and everything that is not supposed to happen does
+not happen. I already did this many times. I didn't want to do it yet again.
+
+Instead, like with the other submission, I also have the other things that are
+unique, and I have shown some subtleties as well. Some - but not all - of those
+are in the section above. Others are in [obfuscation.html](obfuscation.html).
+
+I don't think one can determine them all without examining the code, and that's
+assuming they can look at it without screaming, crying, laughing or possibly
+throwing their computer out the window. I think that because I think the same
+thing about myself and I know it very well. Or maybe I can but can't bear to
+write more, even if I had only written a little. In any case it's not easy to
+follow as the other files will have shown - as will the code itself.
+
+Have fun and enjoy the jokes!
+
+[^3]: See strings 2, 3, 11 and 12. This would be DEVASTATING to rule 2!
+
+
+
diff --git a/2024/ferguson1/V.c b/2024/ferguson1/V.c
new file mode 100644
index 000000000..4bf38b59c
--- /dev/null
+++ b/2024/ferguson1/V.c
@@ -0,0 +1,172 @@
+V(1)
+V(2)
+V(3)
+V(4)
+V(5)
+V(6)
+V(7)
+V(8)
+V(9)
+V(10)
+V(11)
+V(12)
+V(13)
+V(14)
+V(15)
+V(16)
+V(17)
+V(18)
+V(19)
+V(20)
+V(21)
+V(22)
+V(23)
+V(24)
+V(25)
+V(26)
+V(27)
+V(28)
+V(29)
+V(30)
+V(31)
+V(32)
+V(33)
+V(34)
+V(35)
+V(36)
+V(37)
+V(38)
+V(39)
+V(40)
+V(41)
+V(42)
+V(43)
+V(44)
+V(45)
+V(46)
+V(47)
+V(48)
+V(49)
+V(50)
+V(51)
+V(52)
+V(53)
+V(54)
+V(55)
+V(56)
+V(57)
+V(58)
+V(59)
+V(60)
+V(61)
+V(62)
+V(63)
+V(64)
+V(65)
+V(66)
+V(67)
+V(68)
+V(69)
+V(70)
+V(71)
+V(72)
+V(73)
+V(74)
+V(75)
+V(76)
+V(77)
+V(78)
+V(79)
+V(80)
+V(81)
+V(82)
+V(83)
+V(84)
+V(85)
+V(86)
+V(87)
+V(88)
+V(89)
+V(90)
+V(91)
+V(92)
+V(93)
+V(94)
+V(95)
+V(96)
+V(97)
+V(98)
+V(99)
+V(100)
+V(101)
+V(102)
+V(103)
+V(104)
+V(105)
+V(106)
+V(107)
+V(108)
+V(109)
+V(110)
+V(111)
+V(112)
+V(113)
+V(114)
+V(115)
+V(116)
+V(117)
+V(118)
+V(119)
+V(120)
+V(121)
+V(122)
+V(123)
+V(124)
+V(125)
+V(126)
+V(127)
+V(128)
+V(129)
+V(130)
+V(131)
+V(132)
+V(133)
+V(134)
+V(135)
+V(136)
+V(137)
+V(138)
+V(139)
+V(140)
+V(141)
+V(142)
+V(143)
+V(144)
+V(145)
+V(146)
+V(147)
+V(148)
+V(149)
+V(150)
+V(151)
+V(152)
+V(153)
+V(154)
+V(155)
+V(156)
+V(157)
+V(158)
+V(159)
+V(160)
+V(161)
+V(162)
+V(163)
+V(164)
+V(165)
+V(166)
+V(167)
+V(168)
+V(169)
+V(170)
+V(171)
+V(172)
diff --git a/2024/ferguson1/addpadding.c b/2024/ferguson1/addpadding.c
new file mode 100644
index 000000000..1f3a7803f
--- /dev/null
+++ b/2024/ferguson1/addpadding.c
@@ -0,0 +1,172 @@
+/*
+ * addpadding.c - add padding for each string in the data file.
+ *
+ * This DOES NOT ENCRYPT the data! That is the other submission. If this were to
+ * encrypt then the tools and game would print out rubbish.
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+
+static char padding[] = "ha_ha(){hell:goto hell;}main(){goto hell;hell:goto hell;ha_ha();main();goto hell;}";
+static char comment1[] = "/*useless code below, goto end of file*/";
+static char comment2[] = "/*useless code above, goto start of file*/";
+static FILE *in, *out, *prog;
+static char *buf, *p;
+static size_t len, len2, count, i, j, padlen;
+static char *data_src = "data.src";
+static char *data = "data";
+static char *data_asc_src = "data.asc.src";
+static char *data_asc = "data.asc";
+static char *data_scrnshot_src = "data.scrnshot.src";
+static char *data_scrnshot = "data.scrnshot";
+static char *prog_c_filename = "prog.c";
+static char *prog_c;
+static int l, k;
+
+void make_data(char const *dst, char const *src)
+{
+ if (in)
+ {
+ fclose(in);
+ in = NULL;
+ }
+
+ if (out)
+ {
+ fclose(out);
+ out = NULL;
+ }
+
+ errno = 0;
+ in = fopen(src, "r");
+ if (in == NULL)
+ {
+ fprintf(stderr, "%s: couldn't open data source file: %s\n", src, strerror(errno));
+ exit(1);
+ }
+
+ errno = 0;
+ out = fopen(dst, "w");
+ if (out == NULL)
+ {
+ fprintf(stderr, "%s: couldn't open output data file: %s\n", dst, strerror(errno));
+ fclose(in);
+ in = NULL;
+ fclose(prog);
+ prog = NULL;
+
+ free(prog_c);
+ prog_c = NULL;
+ exit(1);
+ }
+ l = fprintf(out, "%s",comment1);
+ for (i = l; i < BLOCKSIZE; )
+ {
+ for (j = 0; j < padlen; ++j)
+ if (j + i + 1 < BLOCKSIZE + 1)
+ fputc(padding[j], out);
+ i += j;
+ }
+
+ while (getdelim(&buf, &len, '\0', in) != -1)
+ {
+ if (*buf == '%')
+ fprintf(out, "%s", buf);
+ else if (*buf == '\a')
+ fprintf(out, "\b%s", buf+1);
+ else for (p = buf; *p; ++p)
+ fputc(*p, out);
+ fputc('\0', out);
+ for (i = strlen(buf) + 1; i < BLOCKSIZE; )
+ {
+ for (j = 0; j < padlen; ++j)
+ if (j + i < BLOCKSIZE)
+ fputc(padding[j], out);
+ i += j;
+ }
+ }
+ fprintf(out, "\n%s%s\n", comment2, comment1);
+
+ for (count = 0, p = prog_c; *p; ++p)
+ {
+ if (*p == '\n')
+ {
+ if (count<15)
+ fputc('\n', out);
+ else fprintf(out, "\n%s%s%s\n", comment1, padding, comment2);
+ ++count;
+ continue;
+ }
+ else fputc(*p, out);
+ }
+ fprintf(out, "%s",comment2);
+ fclose(in);
+ in = NULL;
+ fclose(out);
+ out = NULL;
+ free(buf);
+ buf = NULL;
+}
+
+int main(int argc, char **argv)
+{
+ while ((k = getopt(argc, argv, "i:I:o:O:p:dt")) != -1)
+ {
+ switch (k)
+ {
+ case 'i':
+ data_src = optarg;
+ break;
+ case 'I':
+ data_asc_src = optarg;
+ break;
+ case 'o':
+ data = optarg;
+ break;
+ case 'O':
+ data_asc = optarg;
+ break;
+ case 'p':
+ prog_c_filename = optarg;
+ break;
+ case ':':
+ case '?':
+ exit(1);
+ break; /* this triggers an annoying warning but it's a sanity check */
+ }
+ }
+
+ padlen = strlen(padding);
+
+ errno = 0;
+ prog = fopen(prog_c_filename, "r");
+ if (prog == NULL)
+ {
+ fprintf(stderr, "%s: couldn't open prog.c code file: %s\n", prog_c_filename, strerror(errno));
+ fclose(in);
+ in = NULL;
+ exit(1);
+ }
+
+ errno = 0;
+ if (getdelim(&prog_c, &len2, EOF, prog) == -1)
+ {
+ fprintf(stderr, "couldn't read prog.c\n");
+ fclose(in);
+ in = NULL;
+ fclose(prog);
+ prog = NULL;
+ exit(1);
+ }
+
+ make_data(data, data_src);
+ make_data(data_asc, data_asc_src);
+ make_data(data_scrnshot, data_scrnshot_src);
+
+ fclose(prog);
+ prog = NULL;
+}
diff --git a/2024/ferguson1/bytecheck.c b/2024/ferguson1/bytecheck.c
new file mode 100644
index 000000000..20936e70a
--- /dev/null
+++ b/2024/ferguson1/bytecheck.c
@@ -0,0 +1,76 @@
+/*
+ * bytecheck.c - writes the location of each string in a single char * but
+ * ignores multibyte characters for a diff to make sure the locations are the
+ * same in both versions of the data file. This is much less important with
+ * mbcheck.c as that tool almost obsoletes it if it does not entirely.
+ *
+ * This version uses the source data file, data.src by default, and it reads one
+ * 'string' at a time; it does not read in the whole file at once. With the -i
+ * option it allows for another file. Redirecting to two different files allows
+ * for comparing them, though there will be some differences based on emojis in
+ * ASCII art (for one example) and differences in strings (for another).
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+
+int main(int argc, char **argv)
+{
+ FILE *fp = NULL;
+ size_t len = 0;
+ char *buf = NULL;
+ char *filename = "data.src";
+ int k;
+ int byte;
+ size_t i = 0;
+
+ while ((k = getopt(argc, argv, "i:")) != -1)
+ {
+ switch (k)
+ {
+ case 'i':
+ filename = optarg;
+ break;
+ case ':':
+ case '?':
+ exit(1);
+ break; /* this triggered an annoying warning but it's an extra sanity check */
+ }
+ }
+ errno = 0;
+ fp = fopen(filename, "r");
+ if (fp == NULL)
+ {
+ fprintf(stderr, "couldn't open data file: %s: %s\n", filename, strerror(errno));
+ exit(1);
+ }
+
+ /*
+ * i now starts out at 1 due to the way the padded file is
+ */
+ i = 1;
+ while (getdelim(&buf, &len, '\0', fp) != -1)
+ {
+
+ printf("<%zu>\n", i);
+
+ for (k = 0; k[buf]; ++k)
+ {
+ byte = k[buf];
+ if ((byte & 0xE0) == 0xC0)
+ ++k;
+ else if ((byte & 0xF0) == 0xE0)
+ k+= 2;
+ else if ((byte & 0xF8) == 0xF0)
+ k += 3;
+ else putchar(byte);
+ }
+ ++i;
+ }
+
+ fclose(fp);
+ fp = NULL;
+}
diff --git a/2024/ferguson1/bytecount.c b/2024/ferguson1/bytecount.c
new file mode 100644
index 000000000..a0d75427c
--- /dev/null
+++ b/2024/ferguson1/bytecount.c
@@ -0,0 +1,88 @@
+/*
+ * bytecount.c - writes the location of each string in a single char *.
+ *
+ * This version uses the source data file, data.src, and it reads one
+ * 'string' at a time; it does not read in the whole file at once.
+ */
+#include
+#include
+#include
+#include
+#include
+
+int main(int argc, char **argv)
+{
+ FILE *fp = NULL;
+ size_t len = 0;
+ char *buf = NULL;
+ char *filename = "data.src";
+ int k;
+ size_t i = 0;
+
+ while ((k = getopt(argc, argv, "i:")) != -1)
+ {
+ switch (k)
+ {
+ case 'i':
+ filename = optarg;
+ break;
+ case ':':
+ case '?':
+ exit(1);
+ break; /* this triggered an annoying warning but it's an extra sanity check */
+ }
+ }
+ fp = fopen(filename, "r");
+ if (fp == NULL)
+ {
+ fprintf(stderr, "couldn't open data file\n");
+ exit(1);
+ }
+
+ /*
+ * i now starts out at 1 due to the way the padded file is
+ */
+ i = 1;
+ while (getdelim(&buf, &len, '\0', fp) != -1)
+ {
+ printf("<%zu>\n%s\n", i, *buf=='\a'?buf+1:buf);
+ ++i;
+ }
+
+ /*
+ * the next test was necessary earlier on but is not needed now. I keep it
+ * here to document my procedure.
+ */
+
+ #if 0
+ /*
+ * clear out buf first
+ */
+ free(buf);
+ buf = NULL;
+ /*
+ * reset EOF
+ */
+ rewind(fp);
+
+ /*
+ * now we have to verify that string 2 is what we see from the output (34).
+ *
+ * Obviously (if you look at data.src) the file has changed some since this byte
+ * check.
+ */
+ if (getdelim(&buf, &len, EOF, fp) != -1)
+ {
+ /*
+ * we want to print the string that starts out at 34:
+ */
+ printf("\n34: %s\n", buf+34);
+ }
+
+ free(buf);
+ buf = NULL;
+ #endif
+
+ fclose(fp);
+ fp = NULL;
+}
diff --git a/2024/ferguson1/byteread.c b/2024/ferguson1/byteread.c
new file mode 100644
index 000000000..ea9a3ee88
--- /dev/null
+++ b/2024/ferguson1/byteread.c
@@ -0,0 +1,66 @@
+/*
+ * very similar to bytecount.c but it doesn't print out the location of each
+ * byte AND it also parses the file WITHOUT caring about the NUL bytes (how does
+ * that work?).
+ *
+ * Note that this one does not have an option to specify which file is to be
+ * read and it shouldn't need one at the late stage (at the time of writing
+ * there was only one file - then I added the ASCII only one and then later
+ * changed out the data.src to be data.scrnshot.src and made data.src wider in
+ * text).
+ */
+#include
+#include
+#include
+int main(void)
+{
+ FILE *fp = fopen("data.src", "r");
+ char *p = NULL;
+ size_t len = 0;
+ char *buf = NULL;
+ size_t i = 0, j = 0, k = 0;
+
+ /*
+ * the question I had to determine the answer to is if getdelim() will stop
+ * at the NUL byte. I feared it would but my fear was ungrounded. It
+ * actually read up to the EOF!
+ */
+ if (fp == NULL)
+ {
+ fprintf(stderr, "couldn't open data file\n");
+ exit(1);
+ }
+
+ /*
+ * as I already knew that getdelim(3) would read up to the EOF even with NUL
+ * bytes in the file, I wanted to make sure the algorithm would work okay.
+ * It's not exactly the algorithm I use as in the game I have to print only
+ * a single string, not every string in the single char *. The algorithm
+ * here is pretty simple to understand but it was important in testing.
+ *
+ * It simply prints out each string in the source data file but of course
+ * the game itself prints the flat char *y which is the contents of the data
+ * file itself.
+ */
+ if (getdelim(&buf, &len, EOF, fp) != -1)
+ {
+ p = buf;
+ while (i < len)
+ {
+ j = strlen(p);
+ k = 0;
+ while (k < j)
+ {
+ putchar(*(p+k));
+ ++k;
+ }
+ i += j + 1;
+ p += j + 1;
+ }
+ }
+
+ free(buf);
+ buf = NULL;
+ fclose(fp);
+ fp = NULL;
+}
diff --git a/2024/ferguson1/bytetest.c b/2024/ferguson1/bytetest.c
new file mode 100644
index 000000000..75790db01
--- /dev/null
+++ b/2024/ferguson1/bytetest.c
@@ -0,0 +1,53 @@
+/*
+ * bytetest.c
+ *
+ * Write output in the game, to verify the bytes (locations) are okay.
+ *
+ * If the data file changes in certain ways these tests have to be run again and
+ * the code of the game would potentially have to be updated too. This is why
+ * the program exists.
+ *
+ * The bytecount.c is similar except it reads from the data source file and
+ * reads a string at a time (NUL terminated).
+ *
+ * For this to work right one should run 'make makedata' first.
+ */
+#include
+#include
+#include
+#include
+#include
+
+char *p = NULL, *y;
+/*
+ * Z calculates the block location.
+ */
+#define Z(x) (x)*1663
+#define V(x) { printf("<%zu>\n", (size_t)(x)); puts(&y[Z(x)]); }
+
+int main(void)
+{
+ FILE *fp = fopen("data", "r");
+ size_t len = 0;
+
+ errno = 0;
+ if (fp == NULL)
+ {
+ fprintf(stderr, "couldn't open data file: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ if (getdelim(&y, &len, EOF, fp) != -1)
+ {
+ /*
+ * now we have to test every single string to make sure it's valid.
+ * The makedata.sh script generates V.c.
+ */
+ #include "V.c"
+ }
+
+ free(y);
+ y = NULL;
+ fclose(fp);
+ fp = NULL;
+}
diff --git a/2024/ferguson1/commented.c b/2024/ferguson1/commented.c
new file mode 100644
index 000000000..fc04e5bf5
--- /dev/null
+++ b/2024/ferguson1/commented.c
@@ -0,0 +1,1372 @@
+/*
+ * Here I will guide all you sinning Oregon Trailblazers, at least a little bit.
+ * Very little as the case seems to be given how much the code changed since I
+ * did this one. Can YOU blame me for not trying to keep this updated? If you
+ * can try looking at prog.c again.
+ *
+ * Please note that the order of events (the q = x(0,23)) might be in a
+ * different order than the prog.c as some were added quite late and I just
+ * pushed them in in prog.c without much thinking (which actually caused some
+ * problems that had to be fixed). I am not sure if that actually happened and
+ * there might even be some missing events but just as a note.
+ *
+ * You might notice that the prog.alt.c has some additional events but those are
+ * not here.
+ *
+ * Finally this code is from an earlier version so some of it might be missing,
+ * not just the events, and not just the gotos, but potentially other things
+ * too, possibly bugs that were fixed in prog.c but are not here (and no more
+ * bugs remain in prog.c). But I believe this is more than enough to give you an
+ * idea though if that is the case. If that's not clear...
+ *
+ * WARNING: this code and its comments are not up to date. I wrote 116 before
+ * filtered through the cpp and 134 after the cpp and I didn't wish to
+ * repeatedly revisit this file trying to explain everything.
+ */
+#include
+#include
+#include
+#include
+#include
+/*
+ * this is rand(from, to) and is used strictly to save bytes. This comes
+ * before the variables to shut up some compilers warning about 'shadowing
+ * variables', despite the fact that would be rather on theme of this program.
+ */
+long x(long y, long z){ return (rand()%((z)-(y)+1))+(y); }
+
+unsigned m,D,Q,v,l,Y,f,X,z,B,i,h,
+/*
+ * notice the spelling out of 'rude' and (with the type 'long' and below it
+ * ends up spelling out rude long OREGON TRAIL. This is all true and in some
+ * senses of the word rude the real thing was too, although I did try and keep
+ * it as classy as possible with the parody of 'A Pact With the Devil' (with
+ * sometimes dark and biting irony and mostly full of jokes).
+ */
+ r,u,d,e; long
+/*
+ * Yes it's perfectly legal to have the same variable more than once as long
+ * as it's the same type. This was useful to spell out OREGON TRAIL.
+ *
+ * The o array, which spells out OREGON used to be TRAIL but to save bytes for
+ * something else I undid this. It looks cleaner now anyway.
+ *
+ * Also notice that the prog.c does not make use of the variable 'I' for
+ * bullets. Instead it just manipulates E in a different way. That was added
+ * with under two weeks left in the contest to yet again shave off more bytes to
+ * get even more gotos in. Yes I am seriously disturbed not only in that I can
+ * figure this out but more importantly that I even considered it. Yes this also
+ * means that the 'j'' macro is not there either. I don't believe this
+ * enhancement is in the alt code either but maybe it is.
+ */
+ O,R,E,G,O,N, T,R,A,I,L,
+ *o[]={ &O,&R,&E,&G,&O,&N,&I} ,a,t[7],q,M, b=666,c,W;
+/*
+ * y is the data file buffer, K is the data FILE *, J is
+ * the length read (which we don't actually care about the J as long as
+ * getdelim() does not return < 0).
+ */
+char *y;
+FILE *K;
+size_t J;
+
+/*
+ * saves bytes - every time bullets are used we have to update how much was
+ * spent on them in case one goes to the fort.
+ */
+#define j E=I/5;
+/*
+ * Death macro. This is not the same as the winning death macro, however,
+ * although one always 'goes to hell' - and as you'll see there is an obscene
+ * amount of gotos in this file - just like the original BASIC version. I am not
+ * sure if I can explain it all because it's that twisted.
+ */
+#define w(i) { V(i); V(4); goto hell; }
+/*
+ * Z determines where in the single char * that holds the (currently) 172 NUL
+ * terminated char * strings. These strings are always of the same size but they
+ * can have any value as long as it retains its value when XORed with 127.
+ *
+ * Oh actually the first string is NOT NUL terminated. This is because it's not
+ * needed; it's not part of the game but only a padding and part of
+ * misdirection.
+ *
+ * This also saves bytes.
+ */
+long Z(long x){ return x *1663; }
+/*
+ * this scanf macro gets past an annoying issue with scanf() where it does not
+ * consume input on invalid input which will cause the same input to be read
+ * which in this case causes an infinite loop, flooding the screen. Not having
+ * this as a macro has led to other problems btw.
+ */
+#define S(x,z) while(scanf(&y[Z(x)],&z)!=1)while(getchar()!='\n');
+
+/*
+ * I am quite proud of the concept here, although it's the encrypted version
+ * (not this submission) that is really quite something (and very thematic).
+ * Anyway here the nice thing is as briefly mentioned above, near 200 char * can
+ * be in a single char *!. As I already explained this in detail
+ * in the remarks.md I refer you to it.
+ */
+void V(long x) { printf("%s",&y[Z(x)]); }
+/*
+ * shoot success function. I is number of bullets, Y is the number of times you
+ * shot (so it gets better as you shoot more though it's still chance). 'a' is
+ * non-zero if you got sick and could afford the doctor (a is if you got
+ * dysentery but can't afford the doctor). 'f' is injured (and can't afford
+ * the doctor). What that means is that if you get injured or sick a second time
+ * if you can't afford the doctor you will be penalised. NO: there is no flag for
+ * injured but saw the doctor; that was a choice I had to make even if in some
+ * cases it might not make sense (keep in mind that depending on the type of
+ * wound it might not affect your ability to hunt or shoot at all but with
+ * dysentery if you are sick you're sick).
+ */
+long k(void) { ++Y; return I > 0 ? x(1, 101) + Y > 53 + a ? 9 : 0 + f ? 9 : 0 : 0; }
+
+int main(void)
+{
+ srand(time(0));
+
+/*
+ * the DATA macro allows for portability for systems that do not have emoji
+ * support (like one system of mine - yes even modern systems might not,
+ * console only especially). It could also be used to place the original
+ * strings but that would ruin the theme of parody - but it could work as
+ * long as the order and blocksize is the same (padded with addpadding.c).
+ */
+ K = fopen(DATA, "r");
+/*
+ * getdelim() with EOF is the magic point: it allows for NUL bytes to be in a
+ * single char *. This is how I managed it and with the macro (S) and function
+ * (V) above as well as printf (which I use in a couple places) everything is
+ * set up perfectly to not go beyond the valid contents of the string. Yes the
+ * fact printf and scanf are used does mean that some strings are not encrypted:
+ * those that start with a BEL byte ('\a') or those that start with '%'.
+ */
+ if (!K || getdelim(&y, &J, EOF, K) < 0) goto hell;
+/*
+ * yes basically immediately goto hell beings.
+ *
+ * Please don't ask a tortured soul to try and parse all the jumping. There
+ * are 60 gotos in this file (well as part of the code - not the comments
+ * obviously). I will try explaining the code as we get there but not the
+ * gotos themselves. Obviously I'm a tortured soul having done what I have
+ * done and I don't want to torture myself more.
+ */
+ goto s;
+ /*
+ * this label is devious - a huge chain that goes from the beginning of
+ * main() to the end to the beginning to the ..to the middle (or somewhere
+ * between the two ends).
+ */
+ aa:goto dd;
+
+ u:
+ goto M;
+ /*
+ * this is actually part of the 'aa' above
+ */
+ ee:goto ff;
+ jj:goto kk;
+/*
+ * this is the purchasing code, either at the fort or original purchasing
+ * (if z != 0 it's at the fort)
+ */
+ N:
+ for (X = 1; X < 6; ++X)
+ {
+/*
+ * this funny construct evaluates to X+5. The reason we need + 5 is the
+ * string location in the data file. Remember that V() is based on a
+ * blocksize and the NUL byte (that stops it from going beyond the data
+ * we care about). It so happens that the strings we need are +5 in the
+ * file. That means that instead of printing by byte location we print
+ * by string number.
+ */
+ x:
+ V(X+--(int) { 6 }
+ );
+/*
+ * z == at fort
+ */
+ if (z)
+ {
+
+/*
+ * 3 is %ld
+ */
+ S(3, t[X])
+/*
+ * no negative numbers and no number > 666 (playing into the theme
+ * more)
+ */
+ if (t[X] < 0 || t[X] > 666)
+ {
+/*
+ * 14 is the error message with a joke at the end: 'Or 0, if you
+ * trust the Devil'.
+ */
+ V(14);
+/*
+ * x shows the prompt again and wants valid input
+ */
+ goto x;
+/*
+ * no this is not a mistake although I believe in parts of this
+ * code this is kind of done anyway where two gotos are next to
+ * each other and they actually both jump, due to a label in
+ * between.
+ *
+ * Instead this is a joke: heaven is unobtainable for someone
+ * who 'signed the Devil's book' (we know this because that's
+ * what those in the past have said). But as you'll see later
+ * the heaven label is actually in between a 'while' and the
+ * death macro. The point is you never can 'goto' heaven and you
+ * ALWAYS go to hell (though sometimes implicit goto).
+ */
+ goto heaven; l:goto C; JJ:goto W; qq:goto rr;
+ }
+/*
+ * T == how much money you started out with (1666, also thematic)
+ * and L is the temporary value of that so we can verify you don't
+ * overspend at the fort
+ */
+ L = T;
+/*
+ * u is a temporary value here: t is the array that corresponds to
+ * o. We have to do it this way as otherwise we'd mess up the original values
+ * (O,R,E,G,O,N). This loop just subtracts the amount spent per item and if it
+ * ever goes below < 0 you overspent.
+ */
+ for (u = 0; u < 6; ++u) L -= t[u];
+ if (L < 0)
+ {
+/*
+ * overspent at fort message
+ */
+ V(46);
+/*
+ * we have to clear out the array for them to try again
+ */
+ memset(&t, 0, sizeof t);
+ goto v;
+ ZZ:goto II;
+ }
+ } /* end fort */
+
+/* initial purchases */
+ else
+ {
+/*
+ * not at the fort: original purchase. Again 3 is %ld and o[X]
+ * (yes it's fun it spells out 'ox' with an upper case X as one of
+ * the things you can buy are oxen. Anyway X (see above) just is the
+ * index into the array so we can verify values (and set them of
+ * course).
+ */
+ S(3, *(o[X]))
+ if (*o[X] < 0 || *o[X] > 666)
+ {
+ V(14); goto x;
+ }
+/*
+ * 1666 is the start value of money (well actually 6666 but you have
+ * to read the first string or play to figure out what happens) so
+ * this just checks that you don't overspend. The -0 takes two extra
+ * bytes but it's totally worth it to be thematic.
+ */
+ T=1666-O-R-E-G-0-N;
+/*
+ * overspent, start over
+ */
+ if (T < 0)
+ {
+
+/*
+ * right away there is a message that not only questions the
+ * morality (or 'morality') of the PC (player character) but ALSO
+ * the narrator: in ambiguous ways of course.
+ */
+ V(46);
+/*
+ * I wanted to do:
+ *
+ * O=R=E=G=O=N=0
+ * but this is multiple unsequenced modifications which is
+ * undefined behaviour (UB). And although it would be
+ * fitting in theme for the character it is not a good idea
+ * to invoke UB so I did not (and it allowed yet another
+ * goto).
+ */
+ O=R=E=G=N=0;
+
+/*
+ * nasty gotos here
+ */
+ goto v;
+ c:
+ goto d;
+ oo:goto pp;
+ }
+ }
+ } /* end purchasing code */
+/*
+ * z == at fort - simply return to where we started (the prompt or rather
+ * right after it). This was the first goto in the code when I programmed
+ * this and it was very early on.
+ */
+ if (z) goto A;
+/*
+ * in this case we have to set I to a value based on E but that's only
+ * done when purchasing. Yes this means that I/E modify each other
+ * depending on where we are in the code
+ */
+ B:
+ I = E * 5;
+
+/*
+ * tell player how much money left after spending
+ */
+ printf(&y[Z(12)], T);
+
+/*
+ * go back to 'fort' choice.
+ *
+ * Yes we get here even though the if (z) above might suggest it
+ * otherwise. I'll explain what that code does when we're there. On the other
+ * hand...there is some code you might want to carefully analyse when we do get
+ * to F:.
+ */
+ if (z) goto F;
+
+/*
+ * bastardised Duff's device
+ */
+ switch(1)
+ {
+/*
+ * with a number of twists including a label before the case (you'll see
+ * this again). No this does not mean that when the switch starts we
+ * goto cc first; that only happens when the code does a goto dd;!
+ */
+ dd:goto cc;
+ I:
+ goto R;
+ default:
+ do
+ {
+/*
+ * b == hp/stamina, M == mileage. The Oregon Trail was 2170 miles
+ * (the original game had it at 2040 but this is historically
+ * inaccurate). If it goes below 0 you also are done, just like the
+ * original game.
+ */
+
+ if (b < 1 || M < 0 || M > 2169) break;
+/*
+ * Yes I'm probably disturbed. But can you blame me after looking at
+ * the BASIC? Perhaps you would like to 'pray for me'? No. Don't. But
+ * you get the idea. If you don't yet you will!
+ */
+ goto i;
+ e:
+ goto D;
+ P:
+ for (X = 1; X < 7; ++X) if (*o[X] < 0) * o[X] = 0;
+/*
+ * print stats: food, ammo, clothing, oxen, supplies, money,
+ * hp/stamina, miles
+ */
+ printf(&y[Z(11)],R,I,G,O,N,T,b,M);
+
+/*
+ * this range might be smaller than the original: not sure if it
+ * is even part of the original.
+ */
+ if (x(0, 1)) goto Q;
+/*
+ * it's merely coincidence that the label R is checking if R <
+ * 14.
+ *
+ * Anyway R is food. If < 14 it tells you you better do some
+ * hunting or buy some food soon before you starve. Or don't.
+ * Because let's face it, you'd deserve it. The character in the
+ * game obviously!
+ */
+ R:
+ if (R < 14) V(37);
+ if (z)
+ {
+/*
+ * make choices at fort
+ */
+
+/*
+ * do you want to hunt or continue? (2 == %u).
+ *
+ * Somewhere here I noted how F: will goto f; which will set z to 0. So the
+ * question is can this actually be reached? Another question: what is the point
+ * of it? Why ask in one place if you want to hunt or continue and another place
+ * if you want to hunt, stop at the next fort or continue? The latter makes more
+ * sense but in order for this code to be reached we have to invert the logic of
+ * the if above (make it !z). One compiler thinks this is reached but the
+ * question you have to ask yourself is: is it? Or perhaps: can you figure out
+ * how to trigger it? What I am doing is intentional but it's very confusing.
+ */
+ r:
+ V(43); S(2, r)
+ switch (r)
+ {
+/*
+ * yes a label before a case again. If memory serves me
+ * right this is the nasty one that is 8 levels of gotos (I
+ * think 8).
+ */
+ H:
+ goto G;
+/*
+ * black cat, case 13!
+ */
+ case 1:
+ goto T; /* hunt */
+/*
+ * what, a label between the case statements before a
+ * break that actually does not exist (see below, no
+ * break but two gotos, counting the above goto T!)? Yup.
+ */
+ i:
+/*
+ * if oxen < 1 and you haven't seen the message yet (will
+ * reset it if oxen are brought above 0 again), tell the
+ * player that they have run out of oxen and they must
+ * walk the rest of the way (or else they can buy some if
+ * they have any money left). In the original game I
+ * think no oxen == you lose but in reality one might be
+ * able to buy (or in this case - though it's not done I
+ * don't think unfortunately as I only just thought of it
+ * and it's too late now, unless it is done - steal).
+ * Plus the will to survive is something that you might
+ * not really understand (and this is a theme later on)
+ * where you'll (until you lose all hope) do anything
+ * even crawl.
+ */
+ if (O < 1)
+ {
+ if (!v) V(v=15);
+ O = 0;
+ } else v = 0;
+ goto e;
+/*
+ * Yes there's a goto after the label before the next case
+ * outside of the if!
+ */
+ case 2:
+ goto X;
+ nn:goto oo;
+/*
+ * yes another label.
+ */
+ F:
+ /*
+ * so here we go to f. What does that do? It sets
+ * z=0; so the question is can the if(z) check that
+ * does S(2,r) (after V(43), label r) can be
+ * reached. At least one compiler got confused by
+ * what does or does not happen, warning about it.
+ * I'll say more there too.
+ */
+ goto f;
+ a:
+ goto c;
+ default:
+ goto r; O:goto E;
+ }
+ }
+ else
+ {
+/* outside the fort: do you want to stop at the next fort, hunt
+ * or continue (1, 2, 3)
+ */
+ y:
+ V(42);
+/*
+ * 2 == %u and r is an unsigned int
+ */
+ S(2,r)
+ switch (r)
+ {
+/*
+ * yup another label inside a switch that's not a case
+ */
+ M:
+ V(1);
+/*
+ * t is the array that is used for purchasing but I'm not sure
+ * now how we got here because it's so messed up. The labels are
+ * below us and above us.
+ */
+ v:
+ memset(&t, 0, sizeof t);
+ goto N;
+/*
+ * why case 3 first? It's not needed now admittedly but at first
+ * it might have been for a fall through; not sure. It seems
+ * unlikely as I think I always had a goto but I don't know.
+ */
+ case 3: /* continue */
+ goto X;
+ case 1: /* go to fort */
+ z = 1;
+ M -= 45; /* remove 45 miles (yes I think it's a strange system too but one of the few carry-overs) */
+/*
+ * L is below us but it just jumps to v which is above
+ * us, kind of like hell and heaven (purportedly)
+ */
+ goto L;
+ A:
+/*
+ * Remember the if(z) goto A; ? Well that's after purchasing at
+ * the fort (no rest in the original game, nothing else, just
+ * purchasing). What we're doing here is updating the amount
+ * spent (at the fort we already verified they had enough money
+ * and it's almost the same logic as initial purchases)
+ */
+ for (X = 1; X < 7; ++X)
+ {
+/*
+ * o == the array of values spent plus how many bullets (I == how many bullets,
+ * E == how much spent on them; in the prog.c E is both). The t array is how
+ * much spent at the fort on each item which is why we add to the cost spent
+ */
+ *o[X] += t[X];
+/*
+ * T is total money left and X[t] is how much was spent at
+ * the fort
+ */
+ T -= X[t];
+ }
+/*
+ * this will update how many bullets one has. If you go
+ * back to the B label you'll then see how and why we had
+ * two checks of if (z) even with a goto for each. You
+ * can also figure out that the stats are printed prior
+ * to jumping back into the Duff's device (the
+ * bastardised one) loop (game loop). It does (I think) a
+ * goto F; which then does a goto f;
+ */
+ goto B;
+ case 2: /* hunting */
+ goto T;
+ default: /* invalid input, try again */
+ goto y;
+ }
+ }
+/*
+ * when choosing fort option we goto L; and that does a goto v;
+ * and v is at the top of the function (very early on)
+ */
+ L:
+ goto v;
+
+/*
+ * when l == 1 the character is hunting.
+ */
+ T:
+ l = 1;
+/*
+ * require 9 bullets; if < 9 it's a (as often is the case) a
+ * mocking message.
+ */
+ if (I < 9) V(16);
+ else
+ {
+/*
+ * otherwise: enough bullets; remember k() is the success of
+ * hunting
+ */
+ if (k())
+ {
+ if (x(1,10) > 5)
+ {
+/*
+ * 52 == best shot in hunting. But it also is a chance
+ * of poisoning by the devil.
+ */
+ V(52);
+/* increase food
+ */
+ R += 23;
+ if (!x(0, 9))
+/*
+ * poisoned. But why 17? Because that's the
+ * message number for it. I'll say more when we
+ * get there. You'll notice that other times I
+ * also do something like V(a=...); to save
+ * bytes and to compact code.
+ */
+ i = 17;
+ }
+ else
+ {
+/*
+ * 51 is a reference to a scene (episode 2 I think)
+ * of Miracle Workers: The Oregon Trail. You can
+ * read it in strings.loc.txt or play until it
+ * happens.
+ */
+ V(51); R += 18;
+ }
+ }
+ else
+/*
+ * mock user for missing a helpless animal standing
+ * still
+ */
+ V(53);
+/*
+ * take 9 bullets either way
+ */
+ I -= 9;
+/*
+ * j updates E based on I
+ */
+ j
+/*
+ * lose 45 miles. Yes that means that if one were low on
+ * food they would have to go quite a distance in order to
+ * get food which means they would have a hard time to get
+ * it which makes the jokes more ironic.
+ */
+ M -= 45;
+ }
+/*
+ * no longer hunting
+ */
+ l = 0;
+/*
+ * no longer at fort
+ */
+ f:
+ z = 0;
+
+/*
+ * if no food we do something that many people might not want to
+ * think about but the character would have no qualms about it
+ * either way. Assuming of course that they have any oxen left...
+ */
+ X:
+ if (R < 1)
+ {
+ /*
+ * if 40+ oxen (spent on, not amount) left...
+ */
+ if (O > 39)
+ {
+ /*
+ * eat an ox and show the message of its ghost. Over time the
+ * ghost of the ox(or in some cases the ghosts of oxen) will
+ * taunt the character as they progress. There are two
+ * different messages though: one vengeful over a petty thing
+ * and one for food. The vengeful one happens as another
+ * event in the alt code though; I put it here too because it
+ * was good enough to have in the main prog.c and I could not
+ * fit it in otherwise. As it is I had to change some code
+ * about to fit it in.
+ */
+ V(e=x(0,1)?18:19);
+ /*
+ * remove oxen amount
+ */
+ O -= 40;
+ /*
+ * hold on: no food added? Well one might argue it was all eaten
+ * but check out q. Note it adds 40 but during the feeding stage
+ * of the loop some food will be taken away. Notice too how q
+ * is inside a nested switch's case!
+ */
+ goto q;
+
+ o:
+ goto Y;
+ ii:goto l;
+ }
+ /*
+ * starve to death message. Yes I know people don't starve right
+ * away. I also know that if one has not eaten in a certain amount
+ * of time then eating too much right away can kill you. But this
+ * is how it ends up being in the original. Actually in the
+ * original you don't even get the chance to eat an oxen and if you
+ * run out of oxen I think you also die even though that's totally
+ * unrealistic.
+ */
+ w(24)
+ }
+ else
+ goto K;
+/*
+ * regular events outside of the mountains
+ */
+ Y:
+ switch (q = x(0, 23))
+ {
+/*
+ * yes more goto labels inside a switch not connected to a
+ * case.
+ *
+ */
+ s:
+ goto h;
+
+ case 23:
+ /*
+ * a dark one: if your son gets lost and freezes to death
+ * you have free food. Yeah I know. But it happened (if
+ * not exactly this way) on the trail. The ghost of the
+ * son mocks you at this point.
+ */
+ if (d) V(39);
+ /*
+ * e == ate an ox, the ghost mocks you
+ */
+ if (e) V(25);
+ break;
+ case 1:
+ /*
+ * Indians show you where to find...a heart attack
+ * on a plate. Fast food. Something that did not
+ * exist at the time (at least not like this).
+ */
+ V(95); R += 5;
+ break;
+S:
+/*
+ * if you have too much ammo and this event is triggered
+ * you're going to die. Yes the event is at S but we goto S via
+ * goto g; to get to the actual code so that the code for the
+ * event is not at the case itself but where it jumps back to.
+ * The 'g' is past the return 666; of main().
+ *
+ * Yes an event from a case is not in that case but at a
+ * label inside a switch. This event is a fire but your wagon
+ * train has so much ammo it blows up.
+ */
+ if (I > 1999) w(27)
+/*
+ * if there isn't too much ammo just report a fire and
+ * reduce certain things like mileage, supplies and food.
+ */
+ V(82);
+ M -= 9;
+ N -= 5;
+ R -= 20;
+/*
+ * okay this is devious. Where is Z? Right after the goto g
+ * (which does goto S;) and the Z is simply 'break' so that it
+ * goes back to the switch only to go to the next part of the
+ * code!
+ */
+ goto Z;
+
+
+/*
+ * Casper!
+ */
+ case 18:V(26); break;
+ case 13:V(28); break; /* black cat */
+ case 2:
+/*
+ * if O > 0 and no flat oxen yet a flat oxen (like a flat
+ * tyre - a reference to Miracle Workers: The Oregon Trail).
+ * Actually though - it's not quite that. Even if you don't have
+ * any oxen it still shows a message. You have to check it out to
+ * understand why.
+ */
+ O -= 40;
+ V(71);
+ break;
+ mm:goto nn;
+ case 3:
+/*
+ * unpotable water == dysentery
+ */
+ V(a = 76);
+ b -= 70;
+/*
+ * yes this skips the mountains part. They go straight to the
+ * doctor. There is a thematic joke with it but this means they lose
+ * a turn. They will have to 'continue' on their journey on the next
+ * turn. I think I bring this up a bit more in the remarks.md.
+ */
+ goto W;
+ case 4:
+/*
+ * ironic joke with heavy rains
+ */
+ V(77);
+/*
+ * lose supplies and miles
+ */
+ N -= 7;
+ M -= 7;
+ break;
+ case 5:
+ case 10:
+
+/*
+ * yes q is one of two values (or at least two, in some cases in
+ * this switch I believe there are other values it can be as well,
+ * including one nested switch setting the value again for more
+ * confusion) and this determines the event
+ */
+ if (q < 6)
+ {
+
+/*
+ * Blackbeard attacks
+ */
+ V(78); if (k())
+ {
+/*
+ * drive off Blackbeard, gain food and supplies
+ */
+ V(81);
+ R += 9;
+ N += 3;
+ }
+ else
+ {
+/*
+ * got injured due to lousy shot.
+ *
+ * Lose money and lose all bullets.
+ */
+ V(f = 79); b -= 80;
+ T /= 3;
+ I = E = 0;
+ }
+ }
+ else
+ {
+/*
+ * riders ahead - they don't look hostile. Why don't you rob
+ * them blind?
+ */
+ V(56);
+ if (k())
+ {
+/*
+ * a really ironic and somewhat dark joke occurs here
+ */
+ V(a = 29);
+/*
+ * gain some money
+ */
+ T += 70;
+ goto W;
+ cc:goto ee;
+ }
+ else
+ {
+/*
+ * well it was foolish to try and rob them apparently. 'f' is
+ * injury but we set it to 62 (non-zero) in 'V()' because 62 is
+ * the message to print.
+ */
+ V(f=62);
+/*
+ * lose miles and health/stamina
+ */
+ M -= 50;
+ b -= 35;
+ }
+ }
+ break;
+
+ case 9:case 19:V(30); break;
+/* ox just kicked a bucket */
+ case 20:V(32); break;
+/* devil in mirror */
+ case 21: V(31); break;
+ case 6:
+/*
+ * yes the entire event is at label S which is in another switch (partly for
+ * obscurity and partly as I was running out of places to put them). Then it
+ * jumps back to Z for the break so that the mountains code can happen! That's
+ * assuming you don't have too much ammo of course... If you do the wagon train
+ * blows up from the flames. Otherwise you just lose bullets, food, mileage and
+ * maybe something else (or maybe something else than these entirely - not
+ * sure).
+ */
+ goto g;
+ Z:
+ break;
+
+ case 22:V(49); /* Elf event */
+/* ox stuck in a hole - thankfully not a donkey! */
+ case 17: V(72); break;
+ case 7:
+
+ V(83);
+/*
+ * lost your way in heavy fog but due to a strange map in the last book you read
+ * you didn't lose much time.
+ */
+ M -= 10;
+ break;
+
+/*
+ * label between cases. It seems that this is a chain of gotos but which one I
+ * do not know. It does seem like it's early in the game loop and resets stats <
+ * 0 back to 0 prior to printing them but how many gotos are involved I do not
+ * know. Anyway it'll go back to P which is at the beginning of
+ * the loop and it'll reset the stats and print them.
+ */
+ D:goto P;
+ case 8:
+
+/*
+ * wagon train gets swamped fording river - but with a reference to a historical
+ * event (72 or so years after this game takes place) as well as a nod to
+ * Jurassic Park(not the only one)
+ */
+ V(86);
+/*
+ * food
+ */
+ R -= 30;
+/*
+ * clothing
+ */
+ G -= 20;
+/*
+ * oxen
+ */
+ O -= 40;
+/*
+ * this one is devious: the goto V comes outside and after this switch. I think
+ * it first sets 'q' (the switched value) to another value first. It is then
+ * abused in nested switches. Please do not ask me to parse these. It's a
+ * nightmare and I've had enough of that. I already explained a lot of this in
+ * the remarks.md and I also am disturbed enough to write it; isn't that enough?
+ */
+ break;
+ V:
+ switch (x(1, 9))
+ {
+ case 2:
+ if (q > 9)
+ {
+ switch (x(1,2))
+ {
+ q:
+ R += 40;
+ goto o;
+ case 1:
+ switch (x(2,3))
+ {
+ case 2:
+ V(a = 54);
+ goto m;
+ b:w(48)
+ case 3:
+ goto J;
+ }
+ case 2:
+ V(5);
+ }
+ goto E;
+ ll:goto mm;
+ J:
+ V(a=54);
+ }
+ goto O;
+ KK:goto JJ;
+ m:
+ goto E;
+ default:
+ if (q > 10) goto E;
+ if (q > 7)
+ {
+ if (N < 5)
+ /*
+ * death due to lack of medical supplies and
+ * Devil on holiday/business in Heaven.
+ */
+ w(99)
+ /*
+ * mild illness, meds used
+ */
+ V(13); N -= 5;
+ }
+ break;
+ }
+
+/*
+ * mileage lost. Why? I'm afraid I haven't the foggiest clue now except to say
+ * it is supposed to happen. Remember this is (I think) in several nested
+ * switches.
+ */
+ M -= 17;
+ break;
+ C:goto k;
+/*
+ * eat!
+ */
+ K:
+ R -= R > 23 ? 23 : R > 18 ? 18 : R > 13 ? 13 : R;
+ goto Y;
+/*
+ * Barghest
+ */
+ case 14: V(74); break;
+
+/*
+ * Werewolf scare.
+ */
+ case 15: V(x(0,1)?69:68);
+ break;
+/*
+ * no clue where goto d comes from
+ */
+ d:
+ goto I;
+ case 11:
+
+/*
+ * not enough clothing check
+ */
+ if (G < 25)
+/*
+ * V is above the nested switches
+ */
+ goto V;
+ break;
+ kk:goto ll;
+ case 12:
+/*
+ * hail storm - and another ironic joke
+ */
+ V(94);
+/*
+ * lose mileage, hp/stamina, supplies
+ */
+ M -= 5;
+ b -= 19;
+ N -= 5;
+ break;
+/*
+ * yes again another label inside a switch that's not a case
+ */
+ G:
+ goto a;
+ case 0:
+/*
+ * another joke that is only a message and has no need to check for it
+ * again: this is one of the reasons I made it extended family and wagon
+ * trains, besides historically large groups travelled and in wagon trains
+ */
+ V(20);
+ } /* end outer switch - well this switch that has the nested switches */
+
+/*
+ * ox looks at you funny. Yes that means both could in theory
+ * happen. Wait. How is it possible the above one could trigger?
+ * Well I leave you to figure that one out!
+ */
+ if(O>39){ V(e = 19); O -= 40; R+=40; }
+
+/*
+ * mountains check.
+ *
+ * BTW: for all I know the distance is wrong; the original game had 2040 miles I
+ * think and that is incorrect: the real trail was a fair bit longer than that.
+ * But I only made the game make you travel further and did not try and make
+ * geography better (or worse)
+ */
+ if (M < 951)
+/*
+ * W is medical related things - I mentioned some of this before
+ */
+ goto W;
+/*
+ * clothing check in mountains
+ */
+ if (G < 36)
+ goto b;
+
+ if (x(0,9)>4) goto n; /* skip rugged mountains */
+/*
+ * rugged mountains: an event that at one point happened a lot on my
+ * system due to the old calculation. Now it's much more simplified
+ * but I'm not sure exactly what difference it makes other than it
+ * does give me more bytes which I used for better gameplay.
+ */
+ V(96);
+/* lost? */
+ if (x(0,1))
+ goto p;
+/*
+ * lose time asking the Devil for directions to the crossroads; yes a
+ * cultural reference to a famous legend about an amazing guitarist
+ * who supposedly 'went to the crossroads' and sold his soul to the
+ * Devil for musical talent. Robert Johnson of course! But there is
+ * also a historical joke (about the Oregon Trail itself - from a
+ * historian on how you had to be a complete moron to lose your way
+ * on the trail) in this besides the crossroads joke.
+ */
+ V(97);
+ M -= 60;
+ goto n;
+ p:
+ if (x(0,9) < 5)
+ goto t;
+/* wagon train damaged - lose time resupplying from the Devil */
+ V(21);
+ M -= 99;
+ goto n;
+ t:
+/*
+ * time stops - another reference to the Great Molasses Flood (which
+ * happens when you get stuck fording a river). This event happened 72 years
+ * after this game takes place and also not even close to the Oregon Trail
+ * (far as I know). Apparently this is where the Americanism 'slow as
+ * molasses' comes from, though there were tragic deaths as well.
+ */
+ V(22);
+ M -= 85;
+ n:
+ if(m)
+ goto z;
+ m = 1;
+ if (x(0, 9) < 5)
+ goto w;
+/*
+ * made it safely through South Pass - no snow (this was a real place on the
+ * trail)
+ */
+ V(23);
+ z:
+ if (M < 1951 || W)
+ goto U;
+
+/*
+ * cleared Blue Mountains
+ */
+ W = 1;
+
+ if (!d && !x(0,9))
+ {
+/*
+ * rather ironic joke and the ghost mocks you (and not the only time it might
+ * happen)
+ */
+ V(75); d = 1;
+/*
+ * I don't know if I should say this but as it's part of the joke and this type
+ * of thing did happen: yes this is food
+ */
+ R += 50;
+ }
+ if (!x(0, 4))
+/*
+ * yes dragons exist. Oh and the Earth is flat and the Sun is crazy... A
+ * reference to Miracle Workers: Dark Ages (except that the dragons is in
+ * there the devil). Anyway: 84 == dragon eats you, 34 ==
+ * runaway bed rhyme death, 33 == Tyrannosaurs attack. Doing it
+ * this way saves bytes - it used to be case 16 in the events but
+ * it was too frequent so I changed it to here - which only
+ * happens if !x(0,7).
+ */
+
+ w(x(0,5)?84:x(0,3)?33:34)
+ if (x(0,9) < 5)
+ goto w;
+ U: goto W;
+ w:
+/*
+ * blizzard in mountain pass - waste time asking Devil for help restocking.
+ * Unfortunately the unfaithful monster only gives you one measly bullet.
+ */
+ V(35);
+ c = 1;
+ M -= 101;
+ I += 1;
+ j
+ k:
+/*
+ * miles lost
+ */
+ M -= 10;
+
+ goto U;
+ W:
+ if (d && x(0,1))
+/*
+ * ghost of frozen son
+ */
+ V(39);
+/*
+ * yes this is legal. And 'i' is set to the right value earlier on. Devil
+ * poisoned you. The 'heaven' reference is a joke especially as the only way
+ * you go there (and not really) is when poisoned. The 'goto heaven;' is
+ * never reached. Compilers whine about this because they don't like code
+ * like this.
+ */
+ while(i)heaven:w(i)
+/*
+ * B non zero == can't afford doctor. This is so the player is not flooded
+ * with the message. Once is enough
+ *
+ * 'f' is injury; 'a' is illness; 'Q' is treated for illness but you're not
+ * completely better. Arguably this should happen with injuries too but I
+ * decided against it.
+ */
+ if (!B && (f || a ))
+ {
+ if (d && a)
+/*
+ * food poisoning, maybe. Well no but it's part of the joke
+ */
+ V(91);
+ if (T < 666)
+/*
+ * doctor's bill is $666 and you can't afford it.
+ */
+ V(B=38);
+ else
+ {
+/*
+ * record whether the person is sick
+ */
+ Q = a ? 1 : Q;
+/*
+ * record if injured
+ */
+ h = f ? 1 : h;
+/*
+ * injury and illness back to 0
+ */
+ f = a = 0;
+/*
+ * doctor bill is $666
+ */
+ V(93); T -= 666;
+ }
+ }
+/*
+ * if injured and no medical care lose 15 hp, else if injured and got
+ * care lose 5, else 0.
+ */
+ b -= f ? 15 : h ? 5 : 0;
+/*
+ * if you were sick (and not completely recovered) lose only 5hp;
+ * otherwise if sick 15 and otherwise 0
+ */
+ b -= a ? 15 : Q ? 5 : 0;
+/*
+ * usual mileage gain in the round: way higher than they travelled
+ * in real life but this has to be the case
+ */
+ M += 170;
+/*
+ * if oxen > 99 add 30 miles, otherwise subtract 99. Yes this is
+ * arbitrary but it forces one to be careful with what they have
+ * spent on oxen (and whether or not they need to not spend as much
+ * on something else).
+ *
+ * Remember: the original game gives you only $700 and you must spend
+ * >= 200 && <= 300 on oxen and you do not get a chance to buy any
+ * more after that; if they die you're out of luck. But in my
+ * parody: you start with $1666 after your vague and ambiguous
+ * 'sinful night' and you can buy oxen on the way (more realistic). I
+ * don't have the option to steal oxen from riders because I deem
+ * them as horse riders and the player character is too reckless
+ * anyway, choosing to eat the body rather than a horse.
+ *
+ * This parody as the remarks.md say has 'flat oxen'. Originally
+ * this set them to 0 but this was not good; it slows you down but
+ * you can always get more just as if you lost them all (or ate them
+ * all).
+ *
+ * With these bonuses and penalties it is possible to both win and
+ * lose. I have even on an occasion won with no oxen and that's why I
+ * made this more severe (this way if you don't have > 99 you only
+ * go at the very most 71 per turn, at least as far as the end of the
+ * game loop goes and before other penalties). Whether one can still
+ * win on 0 oxen is beyond me. I subtracted 100 if < 200 but that
+ * seemed really harsh given some of the events that can be
+ * devastating to oxen and other penalties to mileage.
+ */
+ M += O > 99 ? 30 : -99;
+/*
+ * lose 10 hp every turn.
+ */
+ b -= 10;
+ }
+/*
+ * A == turn. I went beyond the number of weeks than the original.
+ * If I were to do it again I would have actually removed the
+ * message about 5-6 months and let it go longer: but that would
+ * mean another joke could not land and also it's less realistic.
+ * Still could be fun if that joke could be integrated somehow (and
+ * I don't see how it could be due to what the message is). So
+ * perhaps I would not do it again. Still I believe this is one or
+ * two more turns than the original BASIC game - by design.
+ */
+ while (A++ < 21);
+ }
+/*
+ * outside the game loop finally
+ */
+ if (b < 1)
+ {
+/*
+ * death by dysentery.
+ *
+ * why not die of dysentery if you were treated but still sick?
+ * Well that has to be because of string 45. Another joke.
+ */
+ if (a) { w(40) XX:goto ZZ; }
+/*
+ * death of injuries
+ */
+ if (f) w(41)
+/*
+ * death from boredom. This is why I did not have the
+ * character die if they had been treated.
+ */
+ w(45)
+ }
+/*
+ * yup, always die even at the end. The alt code has a more
+ * ironic twist if you make it the whole way
+ */
+ w(M>2169?47:36)
+/*
+ * welcome to your new forever home: hell!
+ */
+ hell:
+/*
+ * couldn't do without this, could we?
+ */
+ return 666;
+/*
+ * this might seem like dead code but of course it's not. It is an actual
+ * case: the fire in wagon train one. It first does a 'goto g;' and then here
+ * at 'g:' we do 'goto S;' which does the event and then, assuming that the
+ * death doesn't happen, after the fire, it does a goto Z; and Z is right
+ * after the goto g;. In other words the event jumps out of the loop and then
+ * to another unusual place, the event is performed and then it jumps back to
+ * the break!
+ */
+ g:goto S;
+ h:goto u;
+
+/* this one is quite sneaky as it does goto l; but there are other places
+ * that go directly to l! That in turn goes somewhere else which in turn
+ * goes somewhere else - the final destination!
+ */
+ g:goto S;
+ h:goto u; E:goto aa; Q: goto H; ff:goto ii; pp: goto qq; rr:goto XX;
+}
diff --git a/2024/ferguson1/data.asc.src b/2024/ferguson1/data.asc.src
new file mode 100644
index 000000000..f10beb5e4
Binary files /dev/null and b/2024/ferguson1/data.asc.src differ
diff --git a/2024/ferguson1/data.scrnshot.src b/2024/ferguson1/data.scrnshot.src
new file mode 100644
index 000000000..34781deed
Binary files /dev/null and b/2024/ferguson1/data.scrnshot.src differ
diff --git a/2024/ferguson1/data.src b/2024/ferguson1/data.src
new file mode 100644
index 000000000..a11c343f2
Binary files /dev/null and b/2024/ferguson1/data.src differ
diff --git a/2024/ferguson1/deobfuscation.html b/2024/ferguson1/deobfuscation.html
new file mode 100644
index 000000000..f80c430ea
--- /dev/null
+++ b/2024/ferguson1/deobfuscation.html
@@ -0,0 +1,621 @@
+
+
+
+
+
+
+
+
+
+
+
+
+The International Obfuscated C Code Contest
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
The following hints were used for myself but also I offer them for those who
+wish to more easily follow the code, though that might or might not help that
+much. If a variable or other kind of symbol is missing or is not what it says
+here that was by (in some cases) simply missing it or (in other cases) due to
+having changed things a fair amount; this submission took a lot of work and time
+to get everything in. One variable, p, is for the encrypted version only.
+
The following variables are of primary concern (some temporary ones are not
+documented I think):
+
+
O: how much you spend on oxen
+
R: amount spent on food
+
E: amount spent on ammo
+
G: amount spent on clothing
+
O: how much you spend on oxen
+
N: amount spent on miscellaneous supplies
+
T: how much money you have
+
e: ate an ox
+
b: hp (hit points, starts out at 666, allows for survival in conditions you
+can’t in the original) or stamina (kind of a combination - if you get injured
+and you see the doctor and can afford it you will not keep losing hp but you
+won’t gain any either).
+
A: turn number for setting date (the first week, Monday 29 March 1847 is at
+16 so to print the second week day date month and year (though it does it March
+29 like the American way) you would do V(A+16)) (note that the date is not set
+in a variable but rather for printing the date)
+
I: unused except to spell out OREGON TRAIL.
+
L: amount spent on items at fort (used as a temporary money value for
+calculations at fort)
+
q: event number
+
f: flag for injury
+
M: total distance travelled
+
a: flag for illness
+
z: flag for fort option
+
K: the FILE * (data file)
+
y: contents of data file
+
p: used to print (one character at a time) the strings (encrypted version only)
+
r: (unsigned) answer to certain questions
+
d: son froze to death (and you ate him)
+
J: file length read (fun fact: as part of obfuscation in multiple levels, J != strlen(y)!). It’s reused in the V function after being set to 0.
+
l: non-zero when hunting.
+
W: flag for clearing Blue Mountains.
+
Q: got dysentery and went to doctor (I think only if you could afford the
+doctor but not sure)
+
B: if non-zero, can’t afford the doctor, don’t try again (this prevents a
+flood of the message each turn).
+
h: I believe this is if you were injured and could afford the doctor.
+
c: hit blizzard.
+
X: passed South Pass.
+
i: been poisoned; you will be dead shortly (sorry - that’s what happens when
+you have a pact with the devil!).
+
g: how many limbs you’ve had to cut off (surgeon’s cut edition)
+
t: temporary array for purchasing at forts.
+
u: temporary unsigned int to iterate through array t (and maybe other
+uses, not sure now).
+
v: non-zero means ran out of oxen so as to not flood user every turn with
+certain messages. But if you buy more that could in theory happen again. Note
+that some messages might be printed instead of the you have run out of oxen
+message, if they’re the ones causing it, though I’m not going to say this is in
+every case as there are a lot of ways for this to happen.
+
any other variable I haven’t the foggiest, even if it’s not related to fog (of
+which there is an event where you encounter fog) - sorry. An example here is
+m.
+
+
When an amount spent (if it happens, not necessarily going to for every
+variable) spent ends up being < 0 (it’s not allowed to go that low when
+purchasing) it means that there is an insufficient amount (thus a variable
+reuse).
+
The array:
+
long *o[]={ &O, &R, &E, &G, &N } /* animals, food, ammo, clothing, misc. supplies
+
is used in at least one loop to not have to do checks individually. The
+variables, btw, are not how many as such (well in some cases it is, although
+with the number of animals it’s a ‘taken at liberty’ and based on my
+interpretation of the original 1978 BASIC game) but rather
+how much was spent on them. As for the ammo: $1 spent on ammo means a belt of 50.
+That means another variable has to exist (that would be the I one) and
+every time a purchase is made (at fort or initially) I is set to E * 50.
+
The functions:
+
+
main(): you know what this is: or…do you?
+
k(): the function that determines if you shoot successfully.
+
x: uses rand() to get a pRNG number in a range.
+
V: the nasty function that decrypts (one character at a time) strings in the
+data file. Or doesn’t really decrypt it per se.
+
Z: calculates address of a block in the file (used by function V and macro S).
+
+
The macro:
+
+
S: scanf macro.
+
w: death macro which will ‘goto hell’.
+
+
If you expect me to try and describe the labels I will direct you straight to
+line 22!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/2024/ferguson1/deobfuscation.md b/2024/ferguson1/deobfuscation.md
new file mode 100644
index 000000000..eae1f13ee
--- /dev/null
+++ b/2024/ferguson1/deobfuscation.md
@@ -0,0 +1,100 @@
+The following hints were used for myself but also I offer them for those who
+wish to more easily follow the code, though that might or might not help that
+much. If a variable or other kind of symbol is missing or is not what it says
+here that was by (in some cases) simply missing it or (in other cases) due to
+having changed things a fair amount; this submission took a lot of work and time
+to get everything in. One variable, `p`, is for the encrypted version only.
+
+The following variables are of primary concern (some temporary ones are not
+documented I think):
+
+- O: how much you spend on oxen
+- R: amount spent on food
+- E: amount spent on ammo
+- G: amount spent on clothing
+- O: how much you spend on oxen
+- N: amount spent on miscellaneous supplies
+- T: how much money you have
+- e: ate an ox
+- b: hp (hit points, starts out at 666, allows for survival in conditions you
+can't in the original) or stamina (kind of a combination - if you get injured
+and you see the doctor and can afford it you will not keep losing hp but you
+won't gain any either).
+- A: turn number for setting date (the first week, Monday 29 March 1847 is at
+16 so to print the second week day date month and year (though it does it March
+29 like the American way) you would do `V(A+16)`) (note that the date is not set
+in a variable but rather for printing the date)
+- I: unused except to spell out OREGON TRAIL.
+- L: amount spent on items at fort (used as a temporary money value for
+calculations at fort)
+- q: event number
+- f: flag for injury
+- M: total distance travelled
+- a: flag for illness
+- z: flag for fort option
+- K: the `FILE *` (data file)
+- y: contents of data file
+- p: used to print (one character at a time) the strings (encrypted version only)
+- r: (unsigned) answer to certain questions
+- d: son froze to death (and you ate him)
+- J: file length read (fun fact: as part of obfuscation in multiple levels, `J
+!= strlen(y)`!). It's reused in the V function after being set to 0.
+- l: non-zero when hunting.
+- W: flag for clearing Blue Mountains.
+- Q: got dysentery and went to doctor (I think only if you could afford the
+doctor but not sure)
+- B: if non-zero, can't afford the doctor, don't try again (this prevents a
+flood of the message each turn).
+- h: I believe this is if you were injured and could afford the doctor.
+- c: hit blizzard.
+- X: passed South Pass.
+- i: been poisoned; you will be dead shortly (sorry - that's what happens when
+you have a pact with the devil!).
+- g: how many limbs you've had to cut off (surgeon's cut edition)
+- t: temporary array for purchasing at forts.
+- u: temporary unsigned int to iterate through array `t` (and maybe other
+uses, not sure now).
+- v: non-zero means ran out of oxen so as to not flood user every turn with
+certain messages. But if you buy more that could in theory happen again. Note
+that some messages might be printed instead of the you have run out of oxen
+message, if they're the ones causing it, though I'm not going to say this is in
+every case as there are a lot of ways for this to happen.
+- any other variable I haven't the foggiest, even if it's not related to fog (of
+which there is an event where you encounter fog) - sorry. An example here is
+`m`.
+
+When an amount spent (if it happens, not necessarily going to for every
+variable) spent ends up being < 0 (it's not allowed to go that low when
+purchasing) it means that there is an insufficient amount (thus a variable
+reuse).
+
+The array:
+
+```
+ long *o[]={ &O, &R, &E, &G, &N } /* animals, food, ammo, clothing, misc. supplies
+```
+
+is used in at least one loop to not have to do checks individually. The
+variables, btw, are not how many as such (well in some cases it is, although
+with the number of animals it's a 'taken at liberty' and based on my
+interpretation of the original 1978 BASIC game) but rather
+how much was spent on them. As for the ammo: $1 spent on ammo means a belt of 50.
+That means another variable has to exist (that would be the `I` one) and
+every time a purchase is made (at fort or initially) `I` is set to `E * 50`.
+
+The functions:
+
+- main(): you know what this is: or...do you?
+- k(): the function that determines if you shoot successfully.
+- x: uses `rand()` to get a pRNG number in a range.
+- V: the nasty function that decrypts (one character at a time) strings in the
+data file. Or doesn't really decrypt it per se.
+- Z: calculates address of a block in the file (used by function `V` and macro `S`).
+
+The macro:
+
+- S: scanf macro.
+- w: death macro which will 'goto hell'.
+
+If you expect me to try and describe the labels I will direct you straight to
+line 22!
diff --git a/2024/ferguson1/devil.png b/2024/ferguson1/devil.png
new file mode 100644
index 000000000..13568feb6
Binary files /dev/null and b/2024/ferguson1/devil.png differ
diff --git a/2024/ferguson1/gotos.png b/2024/ferguson1/gotos.png
new file mode 100644
index 000000000..f7ef0cb3b
Binary files /dev/null and b/2024/ferguson1/gotos.png differ
diff --git a/2024/ferguson1/index.html b/2024/ferguson1/index.html
new file mode 100644
index 000000000..aac63b298
--- /dev/null
+++ b/2024/ferguson1/index.html
@@ -0,0 +1,3755 @@
+
+
+
+
+
+
+
+
+
+
+
+
+2024/ferguson1 - Prize in diabolical logistics
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
You will have to go to “Fun-Damentals” to understand the logic flow of
+this game. While you jump as many as 130 times to travel from main()
+to an successful exit(666) you may have a devil of a time trying to
+figure out how this program actually does what it does.
+
Before you set off on your adventure to decode this program’s logic, make
+sure you have enough food, ammo, clothes, oxen, and programming supplies.
+You’ll be driving for 2170 miles through a wild wilderness inspired
+by Oregon, so you’ll need to be prepared for anything! Regardless of
+how well prepared you are, you will have a devil of a time jumping around
+inside this C code. :-)
+
Author’s remarks:
+
+
A Pact With the Devil On the Oregon Trail (…and his 130 regrets of goto)
+
+
The Go To Hell In A Handcart Travel Company PROUDLY welcomes all sinners to
+our GREATEST destination yet, with:
+
+
Here is our travel guide:
+
+
But before I help any sinners embark on this once in a lifetime journey, for
+those who might be disconcerted with the idea of the theme (even though it’s
+ridiculous with something going back to 66m years ago, to several centuries ago
+all the way back to the 1950s, all the while taking place in the 1800s),
+PLEASE either read the (probably totally unnecessary)
+disclaimer or skip this perilous journey entirely. Obviously the
+judges will have no choice in the matter :-) but it’s not really for them anyway
+but rather in case this wins.
+
Everyone might or might not want to look at the commentary on the
+jokes as well as the humour section, historical
+references and cultural references as well. The
+commentary is primarily for those who might be uncomfortable with the jokes that
+go with the theme. Probably totally unnecessary, especially given the Best
+abuse of the user IOCCC
+entry from 2000 that directly insults the player but just in case…
+
Now, back to the good stuff!
+
This program is an ABSOLUTELY ABSURD PARODY of the classic Oregon Trail,
+although it’s actually something else entirely now, hence the name change (not
+‘Oregon Trail: …’).
+
Very early on (this took me two months to create) I was making this a C version
+of the BASIC game from 1978 that was published in the July-August 1978 issue of
+Creative Computing (see
+https://raw.githubusercontent.com/clintmoyer/oregon-trail/master/OREGON.bas)
+but that was FAR TOO BORING for the IOCCC - and for me, although part of that
+was thought up after I ran into the size restrictions (this was good because I
+came up with some really clever ways to save bytes, hide data and other things).
+
I decided to make it far funnier, far less educational and much more fun (at
+least to some people, myself included). On the note of ‘far less educational’:
+the original game did get some things wrong and I have made corrections that I
+talk about in in differences that I’m strangely including
+(because despite the fact it’s mostly a different game entirely, there are a
+couple remnants remaining). It’s a section that probably could be scrapped but I
+wrote it early on as well.
+
Anyway, that this is funny, far less educational and more fun makes it unique
+which is better for the IOCCC. Besides, how many times can you redo Oregon
+Trail? Actually a lot, given the very original was 1971, a BASIC one in 1978
+(not sure what it was in the 1971, maybe also BASIC?) and the most recent one
+seems to be from 2021, but who wants another one here, even if I had the rights
+to do it (which I obviously do not, and that is directly against the rules)?
+
So there is little faithfulness to the original game and there is not meant to
+be. Even so I MUST confess a TERRIBLE (!!) SIN 👿🔥 to the C gods: there
+still remains a bit of faithfulness to the 1978 game, and in the MOST
+ATROCIOUS WAY: it has an OBSCENE AMOUNT of gotos, in fact FAR MORE
+THAN THE ORIGINAL 1978 GAME, which has ONLY 109! Actually, as you’ll see I
+beat that number, even before the cpp. I know. I KNOW I’M GOING TO HELL. But so
+does the PC (player character).
+
The game already went to Hell in a handcart at line 22, taking my belongings
+with it, as I will be needing them. Hopefully it took your belongings too,
+should you play this, as you’ll be needing your belongings as well. Not having
+the right supplies can end your life on the trail, although so can dysentery,
+injuries, dragons, Tyrannosauruses … Yes dragons and Tyrannosauruses still
+existed on the Oregon Trail back in the 1800s.
+
Even if you think otherwise, this game will show you the truth. Oh and yes. The
+Earth is flat, the Devil is real and the Sun is crazy … No. I don’t really
+believe that but they are cultural references - as well as some baffling beliefs
+by real people - that are in some of the jokes.
+
But I took it way further. As you’ll see, it is horrific spaghetti code and I
+have personally never seen anything close to it. But that’s only one of the many
+things I have done - and some are really quite unique and cool, or at least I
+think they are unique (I have never seen these things before nor have I even
+seen any suggestion of them before, one because it’s absolutely contrary to how
+it works in C, namely near 200 NUL terminated char *s in a single flat char * - no, not an array of char *[]).
+
See obfuscation.html and my concluding remarks for
+more details on just how many gotos I have but beware of monsters. But be careful
+if you have a heart condition. And if you’re a computer scientist make sure
+you’re not at risk of stroke.
+
The obfuscation.html file discusses those other cool things as
+well of course, and they might be briefly brought up in my concluding remarks as
+well.
+
Anyway: most of the strings in my data files (files, see below) have at
+least one joke but I’d guess the vast majority have several jokes and right on
+theme. The data file, the code and even the file size - as in wc -c - are all
+VERY THEMATIC. Even the code has jokes. The data files have jokes that are
+not part of the game but might amuse some people, should they wish to look at
+them (there are several files they could do this with - I discuss these in
+obfuscation.html I think.
+
There are a lot of fun twists as you might expect with the name ‘A Pact With the
+Devil On the Oregon Trail’. I will include example jokes as well as a commentary
+on the jokes in general, further down, although it’s only a tiny sample.
+
Oh and I even have emojis in mine - though I have an ASCII data file for systems
+that do not display emojis (or some of the emojis that I chose for that matter).
+That (portability) is one of the reasons for the data files and the DATA
+macro.
+
Another reason is even the original strings (and some of mine are much longer,
+especially with emojis (but quite a few are longer even without emojis) as
+they’re multibyte characters), by themselves go way beyond the size limits,
+leaving no space for the code.
+
Another reason is it allows for obfuscation (data hiding part of it but not only
+that).
+
There are other reasons besides that that I discuss in data file
+versions. But since many other past winning entries read from files,
+including fairly large files, and since I have to have code that reads in the
+data file (and don’t use #include - though as a matter of fact that would not
+even work for the portability!), this is perfectly legal with rule 2 as only
+doing it by #include to trick iocccsize is illegal (and again that would not
+even work).
+
So the data files allow for portability and obfuscation (and showing some rather
+cool things that you can do in C - whether or not they’re a good idea in
+production code, they’re still quite cool and could inspire people, maybe). Plus
+allowing this to be a submission at all. As I discuss this and the other reasons
+later (including portability and compiling) as well
+as obfuscation - with some REALLY cool and VERY interesting tricks - in
+obfuscation.html, I will try and not repeat this justification,
+but I still will talk about the files in various places for various other
+reasons.
+
One thing I’ll say now but discuss much more in the obfuscation file is that there is
+a SINGLE flat char * that holds almost 200 char * (though many are not
+used for various reasons). Yes that’s right. Not an array of char * (as in
+char *y[]) but a single char * - though it’s used and looks like it IS an
+array anyway.
+
Going back to this submission. Why not have a bit (or a lot as the case turned
+out to be) of fun and livelihood for the IOCCC? In this game the player
+character (PC) had an ambiguously (most of the jokes are ambiguous like many
+great stories) sinful night, wasting thousands, dropping them from $6666 to
+$1666 (after buying a wagon train), leaving them with an ominous appearing
+amount. They actually ‘signed the Devil’s book’ (hence the name), despite the
+fact those who claimed such things (like Samuel
+Parris
+and who actually makes a presence - it’s very anachronistic and full of satire)
+exist never produced it as ‘evidence’.
+
The game is FULL of often RIDICULOUS jokes and also a fair amount of them
+reference CULTURAL and/or HISTORICAL events, even some that are IMPOSSIBLE. This
+includes some that are historical and/or in culture, and that sometimes includes
+things that happened but could not be possible on the trail but actually
+happened in real life anyway.
+
A great example is instead of bandits attacking the…Queen Anne’s
+Revenge is on the Oregon
+Trail - over a century after she went to her watery grave (on 10 June 1718 near
+North Carolina)! But in fact that event involves playful mockery and also
+references to Blackbeard’s purported
+last words (‘Well done, lad!’) as well as his supposedly saying that only he and
+the devil know where his treasure is, which goes well with his lore if what is
+said about his beard is true1 - and the theme of the game of course.
+
But there are other historical and cultural references too, one that is a legend
+(think of a certain crossroads - and yes they had crossroads on the Trail but
+even if they didn’t…), some references to the Miracle Workers sitcom series
+(the Dark Ages, year two, and The Oregon Trail - obviously - which was year
+three) and then rather fantastical things as well. It plays in on old beliefs
+about dragons existing and dinosaurs existing too (okay so those did exist but
+if they did exist on the Oregon Trail they obviously would only be fossils - in
+this game though they actually are alive).
+
Funny thought: how do we know dragons don’t exist when we constantly discover
+new species? And how do we know dinosaurs do not still exist when other species
+thought to be extinct for millions of years were actually found, such as the
+first (of others since this) discovery of the coelacanth in
+1938?
+No. I’m not serious about the first parts though the coelacanth is in fact real.
+
Yes there are some Jurassic Park references (‘spared no expense’, and maybe
+something such as the T-rex as well). Of course I already mentioned that dragons
+and dinosaurs still existed on the Oregon Trail, or my Oregon Trail, but there
+is much more to discover. It’s really a lot of fun and very funny, although the
+latter also depends on your sense of humour (all those I have shown think it’s
+hilarious though).
+
And as the character you play is on the darker side there are darker jokes as
+well, though not all are. The player character (PC) is also of dubious character
+and makes ridiculous decisions like when the riders (who are always friendly)
+come up. That also involves some jokes which you’ll see; I’ll mention some of
+these above jokes and maybe others later on in this file.
+
As for the riders: as I said they’re always friendly and instead of having
+tactics (no need), to be on theme, you rob (or attempt to rob!) them. The joke
+before it happens is one thing but if it succeeds it’s even more ludicrous (and
+funny - and also perhaps sardonic).
+
And if you do succeed you get some things too but not all of what you might
+expect! It might be called a kind of damaging (some might say ‘damning’) event but it
+fits the theme quite well and although it (and this is not the only case this
+happens in the game) might not be something most people care to think about (but
+see Disclaimer and also what the judges LIKE, yes
+cannibalism does in fact occur in the game, to be blunt (not that the judges
+like THAT but you’ll see what I mean if you read that section: which is by no
+means necessary for most people!). Of course it’s happened throughout history
+including on the trail so even if the judges did not like to throw up (and
+laugh, which I would guess they will also be doing), it still fits well.
+
There are actually far more ridiculous examples of this, things that make no
+sense, like most of the game. But that’s what makes it so much fun. There are
+many other absolutely ridiculous things, and the above is only a small sample of
+this.
+
Besides the theme and jokes in the code: it also spells out OREGON TRAIL
+(actually more than that but I’ll get to that later).
+
There is so MUCH MORE to discover, some of which is in this file. In fact,
+besides the bonkers spaghetti code (many more gotos than the 1978 BASIC has,
+once pre-processed, and only six fewer before that - even without the dead
+goto there, which is only to mislead even further, it’s more gotos),
+very little remnants of the original game are extant.
+
As noted, depending on your sense of humour you will find this absolutely
+HILARIOUS (those I have shown do find it hilarious) or perhaps a bit unsettling
+but it’s all in good fun. As noted, emojis are used as well (see further below
+for more details).
+
I REALLY POURED MY HEART and (proverbial) soul into this one …because the
+player character (PC) obviously doesn’t have one to pour. I don’t know if I have
+ever put the amount of effort into another program or any project (even the
+many games I have created) that I did in this one and I definitely have not in
+such a short period of time (about two months, which is relatively short given
+all it has).
+
I also poured a huge pot of spaghetti over it, so much so that it endangers the
+life of the PC. I hope you’ll forgive me for my sinning (and crime against C).
+
I had to. This is true satirical programming just by that alone, and it is a
+public service to let people know just how dangerous it is and just how much is
+lost with poor style (and goto is exactly that).
+
Nonetheless, I hope you appreciate the jokes and the fact that I really put a
+lot of effort into making this fun but in some ways disturbing or dubious (even
+if ambiguous and vague and cryptic, the latter exactly like the data files!),
+right on theme of the game. The jokes are deliberately vague and ambiguous so
+that YOUR mind can interpret them the way YOU want (as above - like good
+stories).
+
As you’ll see, although ambiguous and vague in most cases, there is room left
+for personal interpretations, so that more people can enjoy it. If nothing else
+I think the tricks I have in the code, as well as the mad amount of gotos,
+will entertain people, perhaps just as much as the game - or close to. Of
+course…the amount of gotos might horrify people too. But I guess we’ll see.
+
Actually the only things that remain of the original Oregon Trail: you travel
+the same route (longer than the original game as they got that wrong) and a few
+simple game mechanics. This is largely due to the jokes in the game but those
+jokes also involve MANY code changes.
+
Even the game mechanics that stayed were modified in some way or another (there
+might be an exception or two in some way, but not fully that I am aware of).
+Some mechanics were actually removed. Dead code is not only on theme but also
+leads to more obfuscation - and jokes. Always jokes. That was a big part of
+this.
+
Note the (in?)famous ‘you have died of dysentery’. The 1978 Oregon Trail did
+not have it (it had pneumonia instead). OBVIOUSLY I had to change it.
+
But the way I have done it is far more fun and amusing. Emojis actually allow
+for a lot more fun and visuals without trying to outmatch such an iconic game.
+Even if it’s a basically a different game now. Actually I would argue emojis
+are even better here.
+
The jokes that have what some people might question actually have multiple
+interpretations and if one goes to what they find ‘questionable’ that’s actually
+on their end and very possibly (in many cases this is almost certainly the case)
+not even my original idea. But that’s discussed in the disclaimer
+and the commentary on the jokes.
+
For those who are curious enough but do not want to try and figure it out: I do
+offer a section of some of the differences from the May
+1978 issue of Creative Computing (though as it’s mostly a different game it
+probably doesn’t matter - I wrote it before I changed it to a new game).
+Originally I included the BASIC code with some typo fixes but I wanted more room
+for other files like the images you saw above.
+
Yes the (my) game can be beaten although as you’ll find out it’s not exactly as
+you expect when you do (or for that matter, don’t :) ) but yes it can be a bit
+harder (well okay I don’t know - been too long since I played the original),
+especially as there are a number of unusual hazards (all with a joke or two or
+three or even more than three). One thing that will help make it easier if you
+feel it’s too hard is to get rid of the code (and any other place where the b
+is reduced):
+
b-=10;
+
The b is hp (hit points) and stamina (both - and yes I’m aware that they’re
+often separate and some games have stamina change how much hp you have and of
+course some games have only one or neither: like the original Oregon Trail which
+had no such concept, though perhaps it is indirectly depending on how you look
+at it).
+
But on the other hand (as far as ease) you do have more money so there’s
+that (this is also part of the theme btw). There are different strategies
+required due to different mechanics of the game: and it’s quite a few though
+some of the logic is similar, particularly with checks, though only somewhat
+similar. Even checking if you overspent is done differently when you dig deeper
+into it, even if it might at first glance seem to be the same, or so I think.
+
BTW: the alt code, prog.alt.c, is what I call the ‘Devil’s Cut’:
+it has additional events that I could not fit into the main thing and maintain
+the obfuscation levels. Of course I added a fair amount more of obfuscation
+later on and I did not add that to the alt code. There are probably too many
+events as it is (23 not counting the things that happen in the mountains - and
+some fun additions that are related to some events). But the extra jokes in the
+alt code was worth it.
+
The alt code has a lot less obfuscation btw so it might be somewhat easier to
+follow, even if probably not that easy.
+
It also would appear that I did not merge the variables I and E into just
+E like I did in prog.c. As well, it might be in the Blackbeard event (not
+sure) you will in some (if not all) cases lose bullets despite the fact messages
+do not refer to that. That changed later on and I did not have the time to
+address it. The fact the messages don’t refer to them is enough.
+
The commented.c code is also not entirely as complete and might
+even have some bugs that were fixed (it is unclear if the same applies to the
+alt code although I think I got those fixed).
+
Actually, you get to see progression more, comparing the alt code with the
+submission code, and you can appreciate much more this way.
+
Anyway, I made a huge amount of effort to repeatedly reduce bytes for more
+events and more obfuscation but if it was not for the size limit increase (or
+decrease depending on how you think of it) AND the data file this would
+never have been possible as even the original strings far exceed both rule 2
+limits (certainly not possible with obfuscation, maybe not otherwise)!
+
See my somewhat unserious dedications as well, if you’re bored
+and easily amused.
+
Disclaimer
+
PUBLIC HEALTH ADVISORY: as everyone will have noticed I write a lot. So IF
+you believe that all I have written is circumlocution, and you have
+circumlocutophobia aka logoblabberophobia (fear of circumlocution - yes those
+are made up), and you also have hippopotomonstrosesquipedalobibliophobia (fear
+of reading long books, and yes I made that up too, based on
+hippopotomonstrosesquipedaliophobia - which is a humorous extension of
+sesquipedalophobia for fear of long words - and bibliophobia), you might also have
+hippopotomonstrosesquipedaliophobia, a fear of long words. Don’t worry though,
+dear sinner! There are treatment options. See the following link, and sorry in
+advance (even though it’s way too late :-) ):
+https://www.verywellmind.com/hippopotomonstrosesquipedaliophobia-2671752.
+Incidentally, writing less takes more time and I have chronophobia (okay so
+that’s a lie but I don’t have much time left).
+
Anyway: as the name ‘A Pact With the Devil On the Oregon Trail’ implies this
+is not really Oregon Trail; and I took it beyond a parody - it’s taken a life of
+its own hence not ‘Oregon Trail: A Pact With the Devil’.
+
There are A LOT of jokes and unexpected events; it’s not even just about
+immorality/sinning, though let’s face it: what people call immorality/sinning
+was certainly on the trail, even things I shied away from, as much as I thought
+it would enhance the game, exactly because I thought it might be too much for
+some audiences (and that might seem strange, given that there are things that
+are deeply taboo but happens in extreme situations, in order to survive) - I
+tried my best here and I think I did pretty good, and others I shared this with
+agreed there.
+
The jokes are DELIBERATELY VAGUE AND AMBIGUOUS so that one can interpret
+and enjoy it their OWN way, and thus I can avoid the problem: if someone
+imagines something a certain way (dirty, for instance? I’ll return to that one)
+it is on their mind, not mine. There might be a few that are less ambiguous in
+one’s mind but even so they might be interpreted different ways.
+
An example is the ‘Devil’s bedchamber’ - but this also fits the theme; you have
+to see the messages in the right order (which might or might not happen) in
+order to understand this. Well there are a few others but they also have many
+possible meanings; I discuss that in Jokes subsection of
+Humour. The jokes are not directed at the user but as the
+Jokes section and other parts of this file point out that has happened
+in a previous winning entry, as a reminder.
+
Even so, nothing is absolutely implied here, even if one or two might seem
+otherwise. There is a chance in some cases (I spent a lot of time on this and it
+was exhausting - worth it though) I did not even think of every possible
+meaning. Besides, the narrator is often making up a lot of rubbish and that joke
+includes a lot of nonsense (the whole thing is in fact nonsensical fun).
+
The narrator is, as I’ll get to later in the commentary on the jokes,
+actually the Devil, giving a running commentary on what the PC is doing (i.e.
+what is going on in the game).
+
I tried REALLY HARD to remain classy but still have the jokes and irony
+(satire included), though with the visuals that can kind of blur some of the
+class. Some are dark. And an example where there is a blur, but which HAD to
+be included, is dysentery, an iconic part of later versions of the original
+Oregon Trail and even society (not to mention the real Oregon Trail). Given
+what kind of disease and the symptoms, it can’t be done otherwise.
+
Besides, it’s a lot better than how it is in real life, whatever that is.
+
I think I did pretty good, especially since it’s directed at the player
+character (PC), not the player, exactly like all games should do (when they have
+a narrator).
+
Anyway: if the idea of a pact with the devil (or in this case, the narrator! :-)
+:-) ) does offend you, and I suppose that’s the real one for some people, I can
+offer only: it’s nothing serious and all in good fun; there are a lot of jokes
+and in fact the PLAYER CHARACTER (PC) is playfully MOCKED by the narrator
+EXACTLY FOR this pact and their behaviour! As you’ll notice the narrator
+also has a somewhat dubious character (which is also how it would go in real
+life, given what the narrator is) but also in vague and ambiguous ways.
+
That is also discussed later in the humour subsection. As I note elsewhere I
+think, I have a personal problem with labelling people a sinner and I cannot
+even name all of the sins which adds to the lack of seriousness - and adding to
+the fun.
+
And yes the fact the narrator is the Devil and the narrator talks about being in
+Hell, knowing the Devil, meeting the Devil for the first time etc., is all very
+well intended, to increase the irony and ridiculousness. That was obviously one
+of the goals (which I succeeded with remarkably), kind of like the pot of
+spaghetti that is so big it could feed a family of 500 giants. I’ll return to
+this.
+
As noted earlier, and probably mentioned later, the game does raise some things
+that society might like to ignore of what happened on the trail (an example on
+another route is the Donner Party) but with jokes, irony and satire, rather than
+writing a book about those things (probably in uncomfortable ways for many
+people). Plus it’s all done in a heartbeat (well maybe not just one :-) ),
+assuming of course that the PC even has a heart at all! :-)
+
Besides those already noted, there a fair number of other historical references
+that you might not expect but are related to the theme.
+
On the subject of the uncomfortable cannibalism, see the vomitory
+section for another reason to actually INCLUDE it (thankfully the judges
+like programs that make them throw up! :-) ), to say nothing of the ample
+opportunities for a lot of different kinds of jokes and realism (and
+simultaneously also being utterly ridiculous).
+
Finally: PLEASE DO NOT take anything personally; when the narrator says
+‘you’ deserve this and that this is not about the player but the player
+CHARACTER (PC) they are playing, exactly like the Devil would do. Yes I realise
+this statement is probably not necessary but I like to point such things out.
+
Personally I have taken some screenshots of the game though I am very easily
+amused. I think they’re definitely worth having in the game and if I played a
+game like this I would want to take screenshots, as I have done. I like the
+blend of graphics and text, but in a way I have never seen before (emojis),
+though I am sure some games do it. It’s a nice balance.
+
I’ll discuss in the Data files section more of why I provide the
+different data files but part of it is it allows different people to enjoy the
+jokes in different ways.
+
+
Humour: general comments on the ambiguity of the jokes
+
+
As previously noted the narrator is the Devil. It is unclear if the Devil is
+physically there or just a voice in the PC’s head. It certainly is not the
+PC’s conscious - he clearly has none, though not because he made a pact with the
+Devil.
+
This transcends auditory hallucinations, even if the PC is losing his grip on
+reality. Nonetheless that very subject deeply affects me, holding someone who
+suffers from this very dear.
+
Usually I refer to the Devil as a male but there are some cases where I use
+female. This is part of a joke. The reason is that the author is male and
+nothing more. If you wish to imagine the PC (who is also male) or the Devil as
+female feel free, even if you wish it to be someone else entirely: perhaps
+someone who should have their head examined, or maybe someone who is being
+asphyxiated by spaghetti? :-)
+
Anyway: this is not making fun of the tragedy of hallucinations (which typically
+occur with delusions, which the PC is clearly having, although see below). As
+noted, someone very very dear to me has to go through this and I’ve known others
+too.
+
It could be a visual hallucination too, which often happen at the same time. It
+is entirely unclear if the PC knows any of this, however, as he definitely has
+almost lost all grip on reality.
+
Anyway, one thing that does happen is a running commentary, often mocking if not
+being outright cruel and totally unhinged (all of these do in fact happen),
+exactly like the PC and the Devil in his head.
+
This is a DEEPLY PERSONAL thing but I tried to make it fun and as it’s bogus
+enough it’s obviously complete nonsense, just as many jokes are, yet it’s also
+all too real. In truth it’s a terrifying thing and I wish more people understood
+this. It’s a game though. It’s meant to be fun.
+
Oh and no. The ambiguity of the jokes does NOT imply anything about the PC, in
+what would be deeply taboo ways (okay, there’s the cannibalism but that’s
+another matter entirely and consistent with human history). But as far as the PC
+is concerned it is someone else, a real person, and the narrator acts that way
+too: which is precisely consistent with hallucination. Yes that means he MIGHT
+not be aware it’s the Devil, even though he probably should recognise him,
+having signed his book.
+
But obviously nobody else could be the narrator. No else would be there with the
+unhinged PC, even if a large part of why they are unhinged is because of the
+Devil narrator themselves. In any case, this is the only thing that would fit
+into the narrative, and it’s perfect too as you can easily imagine this
+happening, at least if such things as a pact with the Devil were real, and if
+this game were based on reality (quite the contrary as you see by now).
+
That it’s the Devil’s voice makes some of the jokes even more absurd, ironic and
+in some ways more believable, though with the nature of the jokes that’s going
+to be hard to see. It makes some of the jokes funnier though, like those that
+refer to the PC going to the Devil and even the Devil’s bedchamber (which is
+more like torture chamber), amongst some even more ridiculous ones.
+
Now, with that out of the way, some comments on the jokes might be in order. As
+you might have noticed already some of the jokes are darkish (if not outright
+dark) and others CAN be interpreted in dirty ways but also other ways. But in
+general the jokes are deliberately ambiguous for this very reason.
+
And I might remind everyone that these jokes are not directed at the player but
+the player character (PC) whereas a previous winning
+entry (‘Best abuse of the
+user’) directly insults the user with things like:
+
+
you are a thieving bucket of whores
+
you are a scum-encrusted bucket of whores
+
you are a glorified colon of miasma
+
you are a satanic carton of poxes
+
+
…and many others, many of which are very funny (I won’t spoil any more). As
+can be seen some of those are what people would call dirty and offensive, and
+one refers to colons (dysentery, perhaps?).
+
My jokes are on theme with the game but also are ambiguous and vaguely defined
+and only directed at the PC (and sometimes the narrator, yes even though the
+narrator would only be mocking the PC, he is playing games, just like this
+happening in real life, although a voice would not be mocking themselves - it’s
+not real, it’s a game, and it’s not meant to be a true story). The fact the game
+is on theme throughout is obviously why I chose to show the last insult above.
+
Well okay some of the jokes here might be a bit more direct but even those could
+be interpreted in different ways, and some of those actually have more than one
+part (they all probably do) which makes what might be (in some people’s minds)
+direct less direct (puns can also help here).
+
I am not sure why I am continuing this, as I know a lot of computer programmers
+have similar kinds of thoughts. But anyway, IF you do have a dirty mind (which
+is a TERRIBLE thing to waste, btw) there are many jokes that likely will be
+interpreted that way BY YOU. To which say go for it! There is absolutely nothing
+wrong with that.
+
As you might guess I too have a dirty mind but the ambiguity and vagueness makes
+it all the funnier and absurd (though perhaps not as absurd as what I did with
+the code?); it also allows different types of senses of humour/minds to
+interpret it their own ways as well as make one wonder.
+
Some that might be called ‘dirty’ also have a more literal meaning (which often
+enough is how it started) as another possibility and I was careful how I worded
+the jokes for this very reason. Often literal meanings actually can be dirty to
+some (in real life), but often times not, and some people (like me) might see
+them as more than one thing at the same time, regardless of what they really are
+(or might be).
+
In fact some of the jokes that can have a dirty (or otherwise ‘unclean’)
+interpretation, were chosen out of character (OOC) of me i.e. it was not what
+first crossed my mind. The drinking unpotable water, which has several possible
+interpretations, as you’ll see, was not originally this way as it progressed in
+stages as I developed the game.
+
Anyway this allows everyone to use their OWN imagination: this is something a
+lot of good games do too after all, and it fits stories also. If you ask a lot
+of people to interpret novels you’re going to invariably find a lot of
+interpretations, often in dramatically different ways, sometimes dirty even when
+it’s definitely not. That’s exactly what I am doing here too, and that’s what a
+good storyteller does. And indeed there is a story here (there is a plot,
+several plot twists and even the end is quite unexpected), even if it might not
+seem like it (it also depends on the pRNG).
+
Regardless, many of the that jokes could trigger dirty thoughts do have A
+LOT of alternative meanings, as noted: words are EXTREMELY POWERFUL and so
+is the human brain and imagination. The truth is humans fill in gaps of what
+THEY are most familiar with and previous things that happened in THEIR
+life as well as what they WANT it to mean (we all hear and see what we want
+to hear and see and we only believe what we hear and see etc.).
+
The human mind fills in blanks with patterns if it has to, which for whatever
+reason it seems to have to when there are gaps. We might somehow call it a
+pattern matching that’s not related to computer programming.
+
But IF you go for a dirty interpretation that is on you, not me, and frankly
+that’s fine. They are there to enjoy HOWEVER YOU WISH! Frankly if you DO go
+this way it is right on theme of the character anyway which makes it more fun!
+And one might remember that the player character (PC) is losing their mind on
+the trail and having signed the Devil’s book so they’re clearly in this mindset.
+
The narrator is extremely dubious, for reasons I already noted, and there is
+some projection, despite not being real, which makes it even more ridiculous,
+which is part of all the jokes.
+
As you might have noticed many of the jokes actually MOCK THE PLAYER CHARACTER
+(PC) exactly for his sins/misdeeds (as noted in the Disclaimer),
+despite the fact the narrator is just as bad (in many ways worse). Yes. The
+narrator, the Devil, is a hypocrite: did you expect something else in this game?
+
I personally do not believe in the idea of making a pact with the devil (as in I
+don’t believe in him/her/it let alone signing a book that doesn’t even exist)
+and I think the idea of calling someone a sinner in this context is problematic
+and highly subjective, though I do not have any problem with people who find
+comfort in not sinning themselves. We all need to find solace in our own way.
+
That is why it started out with the narrator mocking the player character (PC)
+for his (in truth) often very poor and reckless choices (i.e. it’s satire). But
+at the same time there are jokes that might make some people question the
+morality of the narrator, which is funny because it’s the Devil. And yes, the
+narrator still has a different personality (than the PC). That’s how it goes,
+and it fits in with the game very well.
+
But an example is the seeming obsession (or is it?) with the daughters.
+These jokes however suggest that the PC is thinking these things but it also
+allows the players to wonder. The PC would probably be beyond wondering and
+probably accusing, especially given what is said and WHOSE daughters (in some
+anyway). The fact it’s even brought up is often a sign of something that is
+being denied. Again there is some projection, gaslighting and plausible
+deniability, all of which is utterly absurd, even if it was a real person.
+
Here’s one:
+
🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂
+ 🐂 An ox looks at you funny so you eat 🐂
+ 🐂 him! 🐂
+ 🐂 🐂
+ 🐂 You're a sick, sick individual. You do 🐂
+ 🐂 know that, right? FIRST you BURDEN HIM 🐂
+ 🐂 WITH ALL YOUR RUBBISH and THEN YOU EAT 🐂
+ 🐂 HIM BECAUSE OF A FUNNY LOOK? And YOU 🐂
+ 🐂 DIDN'T EVEN SHARE HIM WITH YOUR FAMILY!🐂
+ 🐂 🐂
+ 🐂 What next, will you eat your daughter 🐂
+ 🐂 too? No! NO! NO NO NO NO! I SHOULD NOT 🐂
+ 🐂 HAVE SAID THAT! NO! DON'T EVEN THINK 🐂
+ 🐂 ABOUT TOUCHING HER! BACK OFF!! 🐂
+ 🐂 🐂
+ 🐂 SHE'S MINE!!! 🐂
+ 🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂
+
What does that even mean? It is probably sanctimonious hypocrisy whatever it
+means but there are many different meanings including even cannibalism like the
+player character (PC) is being accused of himself/herself/themselves. That
+possibility was VERY intentional. And yet: how could a thing that does not
+exist even have any person or thing at all?
+
Another one that might be even worse but still ambiguous and accusatory in a
+sanctimoniously hypocritical way:
+
💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰❌💋
+ ❌DON'T BE ABSURD! You don't have that kind of money. ❌
+ 💰In fact, one of your daughters told me JUST LAST 💰
+ 💋NIGHT that ONCE AGAIN you had a delightfully sinful 💋
+ ❌night! NO! I KNOW WHAT YOU'RE THINKING! NOTHING ❌
+ 💰HAPPENED BETWEEN US! STOP THAT RIGHT NOW, YOU 💰
+ 💋FILTHY SINNER! 💋
+ ❌ ❌
+ 💰Hmm...although...now I think on it, I'm starting 💰
+ 💋to wonder... OH HELL! NO NO NO! What if she seduced 💋
+ ❌me and we DID DO something? That would be AWFUL, ❌
+ 💰JUDGING YOU WHILE HAVING AN AFFAIR WITH ONE OF THE 💰
+ 💋WOMEN! Still sure WE'D NEVER SIGN THE DEVIL'S BOOK! 💋
+ ❌ ❌
+ 💰Although...I don't really remember WHAT we did last 💰
+ 💋night... ANYWAY, KEEP US OUT OF IT YOU MONSTER! 💋
+ ❌ ❌
+ 💰The book has a cost and money doesn't grow on trees. 💰
+ 💋Perhaps it might grow on horns though? Ask the Devil 💋
+ ❌for help. Assuming he helps MONSTERS. ❌
+ 💰💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰💋
+
That’s one that makes the player think the narrator is losing his mind (but
+of course mind is subjective here) and is now starting to wonder if what he
+thinks is going on is really going on. Yes that is a ridiculous idea. That’s
+what often makes satire. Obviously this could not happen. That’s the point.
+
But he’s still trying to ridicule the player character (PC) for signing the
+Devil’s (HIS) book, all the while denying what ‘he’ might have ‘done’ (or
+‘did’), only to then question it again. That is to mess with the PC’s head even
+more.
+
The question of ‘what she did’ is up to interpretation as it could also be the
+narrator who ‘did something “questionable”’ (that’s how I would interpret it -
+projection - but I deliberately worded it in a way that it could be something
+else entirely) and he’s trying to justify and deny his behaviour all the while
+criticising the PC, calling them a monster.
+
Of course in truth the narrator, not being a real person, is just saying all
+these things to mess with the PC’s head, so obviously even if there are
+daughters nothing is going on with them (though if one wishes to imagine
+otherwise for some reason, they certainly can).
+
The reason the narrator is so unhinged is because he’s playing games with the
+PC. Or maybe he already was. Who can tell? How can a being that doesn’t exist be
+unhinged though? Here’s one that is even more ridiculous:
+
🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂
+ ❌You have run out of oxen and must walk. ❌
+ 💋Better buy more... IF YOU DIDN'T WASTE MORE 💋
+ 🐂MONEY ON MORE SINFUL NIGHTS, like your 🐂
+ ❌red-headed daughters told me last night, ❌
+ 💋assuming they weren't LYING to me. 💋
+ 🐂 🐂
+ ❌AND YES. A dirty mind IS a TERRIBLE thing to ❌
+ 💋waste BUT NOTHING HAPPENED BETWEEN US!! We're 💋
+ 🐂JUST FRIENDS and they've been telling me ALL 🐂
+ ❌ABOUT YOUR RIDICULOUS BEHAVIOUR. OK, it MIGHT ❌
+ 💋be in bed with them but they can't help 💋
+ 🐂themselves...kind of like you. WHERE do you 🐂
+ ❌think they got it from? Besides, IF YOU KNOW ❌
+ 💋THE DEVIL in the biblical sense WHY SHOULDN'T 💋
+ 🐂WE? We EXPRESS PASSION and YOU ARE JUST AN 🐂
+ ❌EVIL MONSTER!!!!👹 Good luck hauling your ❌
+ 💋wagon! WE'RE TAKING A PLANE!! 💋
+ 🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂
+
Even if there is that older humorous (which is part of why it’s there - and even
+more ironic given who the narrator is meant to be) phrase: it goes from
+accusation to denial to practically admission to justification (and explanation)
+to - a plane?
+
That’s obviously totally bogus. Even if the narrator was real he certainly could
+not be trusted. That was useful in some cases as code could be different.
+
And of course it’s all meant to mess with the player character’s (PC’s) mind
+(and in a way, by extension, the player’s head, but that’s how it goes with all
+games, even though the narration is about the characters in the game).
+
That they (the PC) do not really understand the narrator is not real, would mess
+with their head even more (although yes in some cases people can be aware
+hallucinations are not real, in this case the PC is not aware of it). But of
+course the devil is not real, despite what the jokes say.
+
Obviously the narrator is not going anywhere here and neither is anyone else,
+except of course that the PC is going to end up in hell, which means so is the
+narrator, in a sense anyway. Well actually they’re already there, aren’t they?
+:-)
+
Note it says ‘wagon’, not wagon train, but that itself is nonsense, as there
+were always wagon trains. But of course the idea of an aeroplane is what makes
+it really ludicrous - intentionally so. Even if the narrator was real, this
+would be over the top. The PC does not really know this though.
+
There are others that suggest the exact opposite of what is suggested here and
+some in between, which makes everything more balanced and suggests the narrator
+truly is unhinged and untrustworthy (and unbalanced), which of course he
+actually is.
+
Of course…the red-headed part: some people consider redheads unlucky (for some
+reason) and we might say that the character is indeed unlucky. Here’s one more
+on that theme:
+
🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔
+ 🍟Uh oh. THERE'S ANOTHER ELF! You must be 🍟
+ 🍔losing your mind my friend! ELVES DON'T 🍔
+ 🍟EXIST, unless you ask a German. They can't 🍟
+ 🍔even count to 11 without claiming there are 🍔
+ 🍟elves! Neun, zehn, Elf ... I guess I might 🍟
+ 🍔be losing my mind too! BETTER SHOOT THE ELF 🍔
+ 🍟BEFORE IT TAKES YOUR DAUGHTERS AWAY AND EATS 🍟
+ 🍔THEM! You might need them for food later on, 🍔
+ 🍟you HORRIBLE, HORRIBLE MONSTER. They are 🍟
+ 🍔heavenly women and are not for evil Devil 🍔
+ 🍟worshippers to eat! NO. NOT FOR ME EITHER! 🍟
+ 🍔Stop going there you sicko! They are NOT food 🍔
+ 🍟and YOU CANNOT GO TO HEAVEN, YOU DEVIL 🍟
+ 🍔WORSHIPPING MONSTER! Cut it out. NO! NOT THEM!🍔
+ 🍟STOP WHAT YOU'RE DOING!!! 🍟
+ 🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔
+
…with more wordplay of course, this time with a bit of German (for the
+uninitiated ‘elf’ is how you say 11 in German and the narrator was counting
+‘nine, ten, eleven …’). And the reference to being heavenly women and ‘do not
+go there’ (the thought about eating) and ‘you cannot go to heaven’ is a
+reference, of course, to the player character (PC) having signed the Devil’s
+book - and the PC always going to hell (which is also baked into the code with
+goto hell;), which ironically means so is the narrator.
+
The narrator saying ‘not for me either’ has a number of interpretations and it’s
+probably not what you think (but I don’t want to say so you can interpret your
+own way). The caps stresses panic and haste. Of course…the Devil would, one
+would assume, take them if he really wanted to.
+
There are other examples that show a totally unhinged narrator who enjoys
+mocking and accusing the player character (PC) of being a horrible person all
+the while the narrator is - well you know who he is.
+
+
Data file versions
+
+
By versions I mean for different systems and purposes. The following programs
+compiled from prog.c/prog.alt.c exist:
+
+
prog - uses emoji data file (data built from data.src) with wider text
+(in some cases - it was hard to maintain three files and with emojis it can
+easily happen that strings are too big).
+
prog.scrnshot - uses screenshot friendly emoji file. This makes it harder
+to follow all the jokes (compared to the other one), because of the game
+flow. The other version still has some of this but more of the strings are wider
+so it’s less of an issue, depending on monitor size of course. Uses
+data.scrnshot built from data.scrnshot.src. Oh and prompting for pressing
+return between every string is REALLY annoying and ruins the fun so that was
+obviously not a good choice for any mode.
+
prog.asc - uses the ASCII only data file data.asc (built from
+data.asc.src). For systems that don’t support any emojis or some or all of the
+emojis I have used (or if there is some sort of problem with formatting due to
+emojis on your system).
+
prog.alt - uses same data file as prog but is the prog.alt.c
+version - a few more events though I think with less obfuscation (does not mean
+it’s not obfuscated, though it is less obfuscated).
+
prog.alt.scrnshot - like prog.scrnshot but is the alt code - a few more
+events.
+
prog.alt.asc - like prog.asc but is the alt code - more events.
+
+
See below under emojis for more details on the ASCII/emojis issue as
+well, for the reasoning behind these different versions.
+
The extra file, the screenshot one, is more for personal amusement, but some
+friends quite enjoyed those I shared too. I realise the data one does not
+always have text wider but this could be good too; it was hard to find a nice
+width and it depends on the screen as well. Actually the ones that are not as
+wide tend to be those with emojis. Sometimes it was possible to make them wider
+but not always, due to how the data file works, and how I can store close to
+200 char *s in a single flat char * - which I discuss in
+obfuscation.html).
+
In the scrollback section I do describe, though untested, how to
+have scrollback at the console, at least for linux.
+
I used vim and merged the lines for the ASCII only and default emoji one and set
+textwidth to some value, possibly 80, as I didn’t want to assume a wider screen,
+but still have it a fair bit longer than the screenshot friendly one. As noted
+this was harder with some of the strings that include the emojis due to the fact
+that emojis take multiple bytes. I did observe late in the game that some
+messages are wider than 80 (I fixed those) so some might be a bit longer. It is
+dangerous to make too many edits.
+
If one uses the addpadding tool correctly (which I describe later and also in
+the obfuscation file) they can make their own strings providing that the strings
+are not too long and are designed correctly.
+
Actually see the next section on making your own theme…if nothing else
+for a simpler explanation of how they work (the obfuscation file discusses it in
+much more detail).
+
+
Making your own data files
+
+
I alluded to the fact that you could make your own theme, though this might
+prove hard to find a theme with matching code, unless you reimagine some of it
+to make it valid (kind of like I have done with a lot of it). Perhaps
+Middle-earth? Or perhaps an actual Oregon Trail without the pact (but of course
+how do you justify the amount of money, the goto hell;, the cost of the doctor
+etc.?)? Or maybe real life (whatever that is :-) ) outside the trail? :-) Or you
+could try and modify the code. If you dare.
+
Anyway this might be a simple way to understand the data file - though
+obfuscation.html explains more. If you were to do this you would
+have to edit the source files and use the addpadding.c tool that I describe in
+obfuscation.html - though the Makefile should help there.
+
Make SURE you’re editing the SOURCE data file(s)! Don’t get rid of the NUL bytes
+or the BEL bytes! And don’t get rid of the ‘%’ in strings either. MAKE SURE
+those bytes (the BEL byte and the ‘%’ - when it starts with one) are the first
+byte in the string. If the ‘%’ is in the string elsewhere then obviously keep it
+where it (or they) are. There are multiple reasons for it being the first
+character - all by careful design.
+
Remember that if the code (prog.c/prog.alt.c) refers to a bad location it can
+crash or do something unexpected! This also happens (see below) if a string is
+too long (it will show strings wrong at the best case). That’s why I wrote all
+those extra tools and carefully designed it all. These are described in
+obfuscation.html.
+
Other points:
+
+
KEEP THE ORDER THE SAME! Do NOT add strings in between others! Just edit
+strings that are appropriate for the code in the game (see next part).
+
Edit the APPROPRIATE STRINGS so that the code will do the right actions. You
+can start out by looking at strings.loc.txt so you can
+compare in code. Then you can find that string in the source data files and edit
+it to your liking. Of course this depends on if you can figure out the code (you
+might find deobfuscation.html of some use too, although the
+obfuscation.htmlmight be a better bet - not really sure)
+and if your theme will actually work with the code. That last part is critical
+of course, unless you want a baffling game.
+
Make CERTAIN the NUL/BEL bytes are not removed! Not doing this will cause
+problems.
+
The strings that do not end with a newline are that way because they are not
+supposed to print a newline. That means literal newlines are how you have a
+newline. This means there’s no need for special parsing - a very useful thing.
+
+
The strings have to be < 1663 in size. Use the lencount -t -i foo.src to verify
+that. It’ll warn about any strings too long and also show you the longest
+string. Note that emojis can add a lot of bytes (using the -t option will exit
+non-zero if there is any problem, telling you to run without the option - that’s
+used in the Makefile rule test).
+
Next run make makedata which will do a couple important things including
+creating the data files from the source data files with the appropriate padding.
+Once that is done run ./printer to print out the strings so you can verify
+things print out okay. You’ll need scrollback of course.
+
That’s a kind of simplified explanation but hopefully you get the idea. A LOT of
+care was put in this and as long as you do it right it works and works well. But
+again that depends on if you can work your theme into the code2 and don’t mess it
+up!
+
It is admittedly EXTREMELY easy to mess up. One wrong deletion of the wrong byte
+or some other placement error, or something else entirely, and it can totally
+DESTROY EVERYTHING. It took A LOT OF WORK AND CARE in the design but it
+works brilliantly and is VERY effective. It allows for hiding data and not
+having to worry about length of strings (other than making sure no string is too
+long), having to worry about newlines/tabs/other characters etc. The encrypted
+submission is even better at hiding data.
+
The way a single char * holds all the strings, is a brilliant
+trick that offers SO VERY MUCH.
+
+
+
Scrollback
+
+
+
Although I haven’t tested this, it should work. This is for people like me who
+might want to play this on the console, though I guess that’s extremely
+unlikely. This is for linux. I have no idea how to do it for other systems,
+although the use of screen/tmux might be fine.
+
First, for linux, without screen or tmux. Assuming that framebuffer is enabled.
+If that is the case you should be able to use: shift + PageUp / shift +
+PageDown.
+
Otherwise, or if you can’t use the key combinations as above, you should be able
+to run this with screen like:
+
screen ./prog
+
then in the game, when you need to scroll, press Ctrl + A, then [. Then you can
+use the arrow keys or PageUp (maybe PageDown too, not sure). Exit with ESC.
+
For tmux:
+
tmux
+ ./prog
+
Then press Ctrl + B and then [. Use the arrow keys or PageUp (maybe PageDown,
+not sure). Exit with ‘q’.
+
+
+
Vomitory
+
+
+
The judges say they LIKE (all caps and in bold is THEIR doing!) programs
+that:
+
+
make us laugh and/or THROW UP :-) (humor really helps!)
+
+
Yes I made the THROW UP bold and capitalised. But anyway: vomitory and
+vomitorium are both real words but they mean something else; in the case of
+cannibalism though, it might be more literal (okay one of the definitions
+relates to supposed vomiting).
+
Yes it can be uncomfortable for a lot of people but the judges did ask for it!
+:-) Besides, it’s on theme and also it happened (on other routes too - for
+example the Donner Party). But there are a lot of jokes on theme (and perhaps
+some not quite on theme) to go along with it.
+
Of course usually (!) in real life (remember that? The author no longer does) it
+happens due to an act of desperation and it’s not a funny thing. Nor is it
+something I would want to have to do but the will to survive is incredibly
+powerful and the truth is nobody really knows what they might do until they are
+forced into such situations. And it indeed is something that would make many
+people throw up (probably myself included and I hope I’m never tested): exactly
+as the judges LIKE! You’re both welcome! :-) Apologies to anyone else who does
+not like it.
+
Unfortunately (or not?), the judges asked for it and reality delivered.
First of all: on the dysentery (which has some uh..fun..emojis), as noted that
+came later on in the graphics version (later on certainly, possibly not until
+the graphical version). But the version my code is originally inspired by is the
+BASIC version of 1978: not only no dysentery but no graphics. There are some
+lovely things about the emojis instead (I do have a way to play without them as
+noted).
+
The many benefits of emojis (besides the fact that even if it was on theme it
+would be likely copyright violations but I am also not an artist and mine is way
+funnier and a very different game anyway) and ASCII art:
+
+
it supports terminals (yes some terminal emulators CAN display graphics
+but this is not portable to all terminal emulators, just like not all systems
+can display emojis in the terminal).
+
it does not need a graphics library.
+
it increases the irony in jokes (most of the messages with emojis have emojis
+that actually enhance the joke or jokes, though not all, and some are probably a
+bit esoteric, just like some of the jokes without emojis).
+
it still allows for a visual feel - it’s a mixture of imagery and text which
+is a nice change (even if the graphical version obviously has text this is
+different).
+
it’s more unique (and depending on submission, it’s even cleverer: the
+encrypted version encrypts emojis).
+
+
+
The issue of scrollback
+
+
There is only one downside to the longer messages and sometimes emojis. Because
+it is somewhat artistic (in some cases a lot) some people (in particular the
+author) might want to take screenshots: the content of the jokes are quite good
+and all those I have shown them to agree, though of course they have my sense of
+humour too.
+
But for screenshots to be easy to read with rubbish vision the text
+has to be not so wide, otherwise it’s hard to see, as noted before. This makes
+it much more likely that events can be missed including many jokes. BUT that
+brings up the issue of scrollback and the wider (default) data file. This is why
+the default file is one that is wider though.
+
If one does not use the wider versions however they should use a terminal emulator
+with scrollback. This still can apply in some cases with the wider version
+though (see below).
+
For some messages due to the emojis I had to make the lines a bit shorter as the
+blocksize was surpassed; that happened many times and required edits. As I
+noted above in versions how to play without emojis or for
+screenshot friendly messages, I won’t say them again here.
+
As for the issue of requiring scrollback and whether this is bad or not. I will
+say that the jokes require it and with how events stack on top of each other.
+Often they are related: say because you get injured and you see the doctor. Or
+Blackbeard attacks (yes really) and you either scare him off or you get robbed
+by him. If you get robbed by Blackbeard you might also need to see (or try and
+see) the doctor which is also another message. If you’re in the mountains you’ll
+have the mountain events too, unless of course you get injured - then you go
+straight to the doctor and lose a turn (in essence), or so I think I did that.
+
This is all unfortunate but it’s necessary (see below).
+
I tried to make the default file a bit better but this was harder with emojis. I
+will however point out that other text based games of old also had this. It
+was simply part of the game: a feature, not a bug, not a defect. It had to be.
+
Text based games with combat messages are a CLASSIC example. And in those
+cases you likely would miss most of it as you have to focus on what is going on,
+in case you need to heal yourself or cast a spell or perform some ability or
+attack. Plus messages that are related to combat, characters (PC/NPC)
+entering/leaving, weather and all other kinds.
+
This also applied to when travelling long distances. When in combat or quickly
+travelling you might also miss messages from other players (when it was
+multiplayer). It was easy to not see all messages in other cases too, as it was
+all live.
+
In fact they often had a brief mode so you didn’t have to see as much (also
+helpful over networks in the earlier days). Here though you get prompted after
+the mountains event (or if you haven’t got to the mountains yet then after the
+events) so there is always a pause at some point (until game over of course) so
+in the cases the messages are longer you can just scrollback if your terminal
+emulator supports it (just like with other games, including some of those I just
+referred to).
+
Even some graphical games that have messages have this problem! This is
+not really a limitation of the game though - it would spoil everything if it did
+not happen. So make sure to play with scrollback!
+
Now what about workarounds? Well if the game had you press a key between each
+part of the output it would get boring really fast and so that’s obviously
+the wrong choice. It would also be EXTREMELY annoying and that is just as
+bad if not worse.
+
Another issue was determining the right width to have. Sometimes the lines might
+be longer than others, although I did try to minimise this. Remember the
+blocksize is key as well. This might seem odd but trust me when I say it: longer
+lines can in some cases actually increase the length of the messages
+(especially, obviously, with emojis).
+
The blocksize is one of (not the only) keys in how I could have near 200 char * in a single char *, something I have never heard of before, and as there is
+more to how I did this it is even more interesting than that. I discuss it more
+in obfuscation.html for the interested.
+
So just make sure to play with scrollback and make sure to check if you’re
+unsure. It’s worth it and a small price to pay for a fast paced game - and it’s
+not any different from older text games (and graphical games with text that
+scrolls by), except that you at least do get a pause in this game, unlike many
+of those older games.
+
+
Alt version of the code: the Devil’s Cut.
+
+
Okay so I briefly mentioned the alt version but there’s more to it.
+
Why ‘Devil’s Cut’? As you might have guessed this is a joke (and a pun), namely
+because the first one I added to it was the you have lost a limb so you get free
+food; if you run into that event more than three times you die - I think up
+to three times i.e. on the fourth you die, not the fifth, but perhaps not. But
+when you die from it you can die happy knowing your family gets a free meal
+though of course the game is over at that point.
+
There are several other events at the bare minimum or at least there were; as I
+continued to optimise the code size I got more in: but not all. But
+unfortunately due to the obfuscation it’s hard to be sure what is where. I do
+know that limb loss one (though there’s a similar one that is in the submission
+code but not one that causes a death) is not in the submission code.
+
It uses too many bytes. As noted (and as you would see if you looked) the
+submission code got way more obfuscated than the alt code but there were it felt
+better to add more obfuscation than to add even more events as it already has
+more. I think the alt code has 25 events and the submission has 23. That’s not
+even counting the mountain events or the events that are part of other events!
+
Realistically I could even get rid of the alt code but since there are more
+jokes there I am keeping it. In any case 23+ is plenty.
+
+
Additional thematic references in code and data
+
+
The hp/stamina b starts out at 666. The money starting at $6666 (well $1666
+after a ‘sinful night’):
+
T=1666-O-R-E-G-0-N;
+
The -0 uses two extra bytes but it’s totally worth it, even though I could
+have even more gotos (see the obfuscation.html for that
+madness). You might say the 1666-O-R-E-G-0-N is saying subtracting from one
+devil Oregon. Or you might say something else. But of course 1666 is described
+in the first game string:
+
+
This program simulates a trip over the Oregon Trail from Independence,
+Missouri to Oregon City. Your extended family will attempt the 2170
+mile Oregon Trail in 5-6 months. You had $6666 for the trip foolishly
+wasted thousands on a sinful yesterday and you’ve paid $200 for a wagon
+train, leaving an ominous $1666. You may buy the following items, or not,
+if you trust the Devil to be faithful to your pact:
+
…
+
+
This not only foreshadows the theme more (sinful, $1666, $6666) but it sets
+the stage of the game basically immediately, pointing out that some strange
+things might very well happen (as they do, including things that are definitely
+out of the norm including out of the norm of reality, but that makes it all the
+more fun).
+
So obviously T=1666-O-R-E-G-0-N; is part of checking if you overspent,
+although it’s also done in another place (the fort) in another way (due to
+having to make sure I don’t overwrite the amount of money left, though I did do
+this with the amount of bullets).
+
Another thing is that like the hp starts at 666 so too are you only allowed to
+spend >= 0 && <= 666 on each item (I will return to this in another fun way).
+
Another one that does not quite spell out OREGON precisely but it is close
+enough, at least part of it, and in an amusing way:
+
printf(&y[Z(11)],R,E,G,O,N,T,b,M);
+
…which is also funny in a kind of childish way because it could, if you
+interpret the (11) as an O, spell out OREGON T BM or Oregon Trail BM - like
+dysentery perhaps? Even if some might call it childish how could I not point it
+out for a game that is almost identified by dysentery? That would be the real
+scandal!
+
Oh and there’s this one too:
+
O=R=E=G=N=0;
+
which not only almost spells out OREGON but it is as if it’s setting it to 0,
+which might be a foreshadowing of the final act of the game. Why not have:
+
O=R=E=G=O=N=0;
+
+
? Oh do I wish I could do that! Unfortunately that would be multiple unsequenced
+modifications to O which is UB.
+
So as you can see between the V function (based on the blocksize), the code (in
+multiple places), the starting hp, the data file and even layout of variables to
+spell out OREGON TRAIL TRAIL OREGON (and rather rude OREGON TRAIL TRAIL OREGON) this is full of thematic references to what the program is (and in some
+cases what it was)!
+
This all took a lot of care in calculating things, manipulating values and much
+more. Throw in all the many jokes (many of which are utterly ridiculous) and
+you have a really fun submission!
+
Of course there’s also the hell label and many of the strings in the game
+refer to the devil and the player character’s (PC’s) pact. The goto hell is
+discussed more in the Humour section, as well as perhaps the
+obfuscation.html.
+
And here’s a fun one: did you notice the code actually spells out ox (well
+okay it has an upper case x)? Some examples:
+
S(100,*(o[X]))if(*o[X]<0||*o[X]>666)
+
And comparing it to (>) 666 too…does that hint at a sacrifice? Well it might
+just indeed, as shown earlier. Even more so: beast of burden being sacrificed?
+Not cool (is where the player character (PC) goes ‘cool’ though? I heard there’s
+no air conditioning there either.).
+
And as a reminder: 666 is the max you can spend on any one item at a time:
+including oxen! So it’s comparing an ox to 666 (some say the ’number of the
+beast, which this is a beast) and it’s also the maximum value you can spend
+on it. Does that make your ox(en) the Devil? You decide! :-)
+
The cultural reference to Robert
+Johnson and the crossroads,
+legend though it obviously is, is also a thematic thing, but that comes in the
+cultural reference section instead of here, even though it fits in both places.
+
The Samuel Parris reference also fits in with the theme of course. And of course
+it’s ridiculous as it’s centuries before. Not by any means the only place! There
+are numerous in the far future and some in the far past as well. I show this
+more later (I think).
The program does return 666; to further add to the theme even though the shell
+likely won’t report such a high number and it would make the command ‘fail’.
+This is why though I added the - to the Makefile try and try.alt rules.
+
According to wc -c in macOS the file is 4666 bytes: a common theme in the code
+(particularly the last three digits).
+
Also did you notice the heaven is right below 666? Not only that but a bit
+further down is 666 again right under heaven (tried to align it but might not be
+perfect)!
+
All of these tie beautifully to the theme of the game and there are, as noted
+elsewhere, more.
+
Humour
+
Notice the goto hell part for the death of the player character (PC). Or
+winning the game (what is winning in this case? - see below). This is a play on
+the fact that original Oregon Trail (and my game is even worse) is a goto hell
+spaghetti code and my joke in the obfuscation.html file (not to
+mention the joke of using the obscene amount of gotos in a single small
+program (see the obfuscation file for more on that as well as concluding
+remarks).
+
The message is full of irony for added effect, namely the ‘WELCOME TO HELL!’ and
+calling it your forever home, plus god wishing you a prosperous life ahead.
+
Did you also notice that even when you win the game you will die and goto hell;? Why I did this: we all do die and although I don’t believe in the
+afterlife it is amusing to me especially as it IS goto hell! There’s a great
+joke in there, riddled with irony, but let’s be honest: although I guess some
+did survive after they made it, so many deaths occurred and many probably
+arrived but sick so why not? :-) And of course obviously the player character
+would go to hell: whatever that might be.
+
When you ‘win’ another ABSOLUTELY ABSURD thing happens (before you go straight
+to hell): President Jesse James congratulates and wishes you a prosperous
+life…in HELL! Yes I know. I said this game is absurd but also funny as…hell
+(depending on your sense of humour of course).
+
There’s also a ‘flat ox’ (instead of an injured ox like in the original) -
+like a flat tyre. This is a reference to the brilliant American sitcom series
+Miracle Workers, in this case series (or if you prefer season) 3: Oregon Trail.
+As I recall in that show the ox is actually female: also ridiculous if so.
+There’s another one, about a bald eagle, as well.
+
Another one is from a different year of The Miracle Workers, this one the Dark
+Ages. The character is in uni. Yes all years were extremely ridiculous and full
+of satire; the first year had Steve Buscemi play ‘god’ (a complete moron and he
+played it brilliantly as you would expect) who decided to blow up Earth (and
+that’s all I’ll say). Anyway in Dark Ages there was the line:
+
+
The Earth is flat. The devil is real. The Sun is crazy. And that is everything
+we know.
+
+
but the message I have here is a twist, although it has some of the above too
+(as hinted at earlier). (And yes this could also be in culture since for reasons
+beyond my comprehension some people actually do believe the Earth is flat and
+the other things too …)
+
Now this one I could put in obfuscation.html but it’s also
+humorous even though it ties in well with the obfuscation. In 1957 on April
+Fool’s Day the BBC played a hoax on a factual programme (Panorama) that there
+were spaghetti trees. Some were upset for this in the factual programme and
+others were eager to find out where they could get a spaghetti tree themselves!
Now how this ties into obfuscation is that this code is spaghetti code to the
+degree I have never seen, aside maybe from BASIC (as noted earlier) - but this
+is not a BASIC contest (thank goodness) and I made it worse (maybe not
+thankfully). Although….mine is even worse so I shouldn’t say much on the BASIC
+one now. Anyway to see how this really fits in humour this is what the event
+looks like:
+
~~~~~~
+ / 🍝🍝🍝 \
+ / 🍝🍝🍝🍝🍝 \
+ / 🍝🍝🍝🍝🍝🍝 \
+ | 🍝🍝🍝🍝🍝🍝🍝|
+ \ ||| ||| /
+ \ ||||| /
+ \ ||| /
+ \__________/
+ || ||
+ || ||
+ __||__||__
+ WOW!!!! THAT'S A SPAGHETTI TREE!!! I saw
+ them over 100 years from now when I last
+ used my Time Machine!! The BBC will
+ cultivate them on April Fool's Day 19579!
+ THEY'RE AMAZING!! The Time Machines are
+ okay and kind of interesting. Dangerous
+ though...
+
+ But the spaghetti looks pretty ominous,
+ doesn't it? IT LOOKS LIKE IT WANTS TO REACH
+ DOWN AND GRAB YOU! Better be careful. If they
+ strangle you YOU WILL GO TO HELL! On the plus
+ side... YOU'LL HAVE THE MOST AMAZING STORY to
+ tell your fellow sinners... Trust me. I've
+ been there on holiday! It's PRETTY WILD!!
+ Summers are AMAZINGLY HOT!! Although...GETTING
+ EATEN BY A DRAGON OR KILLED BY TYRANNOSAURUSES is
+ an EVEN BETTER STORY! That's MUCH MORE
+ EXCITING than a SPAGHETTI TREE KILLING YOU!!
+ Although...now I think on it...they're ALSO
+ in Hell so maybe it's better if the spaghetti
+ kills you. Want me to strangle you with it if
+ it doesn't do it? Of course...the trees are
+ there too...LOTS of parties too. And good old
+ TORTURE! IT'S AWESOME!
+
…and of course the going into the future and saying ‘will’ instead of ‘did’ or
+‘have’ only adds to the absurdity, as does ‘I saw them over 100 years from now’
+as does the suggestion that (of course) the time machine doesn’t exist yet (the
+only time machine is the clock and other things to tell the time and I hope
+that’s how it remains): playing into the time travel paradoxes/problems.
+
But when I thought of this I knew I HAD to put this event in as if any event
+fits in the code it is this one: and there are many others too that are thematic
+to parody; this is a reference to the code itself and being goto hell. And of
+course the ‘YOU WILL GO TO HELL!’ is exactly referring to that AND it also is
+true of the player character (PC) when the game is done (whether they win or
+not). The torture being awesome came towards the end. I might be disturbed in
+more ways than you can know but if you see the number of gotos in
+prog.c that will come as no surprise.
+
There is also a reference to the Flying Spaghetti Monster although the question
+you have to ask is how often (or does it?) this will trigger. This is largely
+due to obfuscation and some seeming (but is it? Yes some is deliberately and
+others that might appear are not) dead code. Anyway the joke:
+
🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰
+ 🍝Not again. Are you REALLY going to tell me 🍝
+ 😈about the Flying Spaghetti Monster AGAIN? 😈
+ 🪰I've had ENOUGH of your FAIRY-TALE DELUSIONS! 🪰
+ 🍝YOU'VE TOLD ME HE IS INVISIBLE SO HOW IN THE 🍝
+ 😈HELL CAN YOU EVEN KNOW HE EXISTS? 😈
+ 🪰 🪰
+ 🍝What next, are you going to tell me that 🍝
+ 😈between Earth and Mars there is a china teapot😈
+ 🪰revolving about the Sun in an elliptical 🪰
+ 🍝orbit? Let me guess! It's so small that even 🍝
+ 😈the James Webb telescope that was launched 😈
+ 🪰almost 200 years from now can't even see it, 🪰
+ 🍝right? What a load of ABSOLUTE RUBBISH! If 🍝
+ 😈your daughters were not here I WOULD TOTALLY 😈
+ 🪰BE ABUSING LALOCHEZIA AT YOU RIGHT NOW! 🪰
+ 🍝BUGGER ME THAT THEY ARE! 🍝
+ 😈 😈
+ 🪰If the Flying Spaghetti Monster ACTUALLY 🪰
+ 🍝existed, he'd eat you for lunch for blasphemy.🍝
+ 😈Hell, keep this up and I'LL eat you. I'M 😈
+ 🪰STARVING! 🪰
+ 🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝
+
and of course it also talks about something in the future (to say nothing else
+of the Flying Spaghetti Monster is far into the future too): the James Webb
+Telescope. It also refers to Russell’s
+teapot.
+
Lalochezia is catharsis from swearing btw.
+
Some other funny things.
+
The data file has some jokes that are totally unrelated to the game that might
+amuse some people. It also has some unused strings that were meant for the game
+but didn’t fit in well.
+
The game kind of has a darker sense of humour when you die and other things too.
+The emojis kind of make it even better. An example is when you freeze to death.
+Sometimes part of a message is repeated in another message but usually with some
+variation, likely a new joke (or jokes as is often the case).
+
The idea of ‘hell’ is heavily engrained in the game in various other places too,
+including the freezing to death one (not only those messages but what follows
+them) and some that are rather explicit/direct.
+
If you run out of food you’ll eat an ox, if you have one (though ‘one’ is based
+on the original game due to the fact that otherwise one would have way more than
+realistic, given the amount of money the PC has). Otherwise you die if you don’t
+hunt right away (hunt and succeed and succeed without a penalty - not saying
+more on that).
+
In the original if you run out of food you die no matter what. Humans would
+definitely sacrifice their burden animal if they could to survive and it fits
+with the theme of the game anyway. Besides, you wouldn’t starve to death
+immediately and depending on where you are you might find more food before that
+time. Actually there is another scenario when you’re out of food if you have an
+ox. That also has ambiguous jokes and satire and it’s an example that has part
+of another message, namely the one when you eat the ox simply due to no food
+left. You can even end up eating an ox even if you do have enough food! Yup that
+means you’d have to go to the fort again. Be money wise! The PC is not.
+
So people can see what the winning scene looks like, full of irony, with the
+emojis, including something I already mentioned:
+
You FINALLY arrived at Oregon City after 2170
+ long miles!
+
+ TOOK YOU LONG ENOUGH. Probably all your sinful
+ detours I've heard so much about but you'd think
+ that the Devil would have helped you out on that.
+ But I guess as long as you make it to your final
+ destination that's what matters, right?
+
+ Oh, right. Almost forgot! President Jesse James
+ asked me to wish you a prosperous life ahead of
+ you...in HELL!
+
+ 🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦
+ 🪦 / \ 🪦
+ 🪦 / A \ 🪦
+ 🪦 |TORMENTED| 🪦
+ 🪦 | MONSTER | 🪦
+ 🪦 | R.I.P. | 🪦
+ 🪦 |_________| 🪦
+ 🪦 GAME OVER 🪦
+ 🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥
+ 🔥Unfortunately, due to what can only be an 🔥
+ 🔥ADMINISTRATIVE FOUL-UP, you end up somewhere 🔥
+ 🔥you did not expect as your forever home. But 🔥
+ 🔥honestly, after signing the Devil's book, DO 🔥
+ 🔥YOU REALLY BELIEVE YOU DON'T BELONG HERE? Be 🔥
+ 🔥honest. For once. You know you belong here. 🔥
+ 🔥Oh, by the way, god asked me to wish you a 🔥
+ 🔥PROSPEROUS LIFE ahead... 🔥
+ 🔥 🔥
+ 🔥 😈😈😈 WELCOME TO HELL!! 😈😈😈 🔥
+ 🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥
+
+
+
That’s only one of many other jokes. I’ll share a few more here.
+
Helpful Indians show you where to find
+ more food. Pizza, hamburgers, chips/fries
+ and other greasy, fatty foods ...
+ 🍕🍔🍟🥪🌯🌮🌭
+ Okay so IT'S ONLY A HEART ATTACK ON A
+ PLATE but at least you'll survive another
+ day...if you don't have a heart attack
+ first, that is... Better have your Doctor
+ Beelzebub check you out. If he's still
+ alive. Oh no.
+
+ You didn't eat him when you were starving
+ last time, did you? If so I hope you DO
+ have a heart attack!
+
+ 🧶🧶🧶🧶🧶🧶🧶🧶🧶🧶🧶
+ 🧶 Rugged mountains.🧶
+ 🧶🧶🧶🧶🧶🧶🧶🧶🧶🧶🧶
+
Yeah I put chips/fries to make it multi-locale.
+
Anyway the above block is actually two events. Well an event and then the
+mountains code.
+
Here’s another fun one. If (I think it’s triggered because of this) you don’t
+have enough clothing at some point, perhaps mountains, perhaps not:
+
+ 🔥🌨️🔥🌨️🔥🌨️🔥🌨️🔥🌨️🔥🌨️🔥
+ Phantom blizzard from Hell suddenly hits
+ and you freeze to death, leaving everyone
+ behind. You know the Devil 😈 is calling
+ you, right?
+
+ 🩳🩲👗👙
+
+ And with your choice in clothing, ARE YOU
+ REALLY SURPRISED YOU FROZE TO DEATH? I mean
+ SERIOUSLY mate, shorts, briefs, A DRESS AND
+ A BIKINI on the Oregon Trail? What the hell
+ were you thinking? You're not in Hell,
+ you're on the Oregon Trail!
+
+ Although...now I think on it...perhaps Hell WILL
+ serve you better? I hear the Summers are GREAT
+ there! Lots of parties. Winters are -- actually,
+ there are no winters. ONLY WEATHER TO BURN YOU
+ FOR ETERNITY.
+
+ At least your family gets fresh meat on the bone,
+ assuming they can stomach eating a horrible
+ monster. If I were them I'D BURN YOUR BODY.
+
Just to drill in the irony I chose the patronising use of the word ‘mate’ (not
+the only place this happens). Pretty sure that one of the freeze to death events
+is not in the game - it was redundant as far as I viewed it and having it would
+mean sacrificing another joke. Ironically the suggestion of burning the body
+would end up burning them too, though it would not matter at this point anyway.
+
And here’s the famous dysentery one:
+
+ 💩💩💩💩💩💩💩💩💩💩💩💩💩💩
+ 🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽
+ 💩💩💩💩💩💩💩💩💩💩💩💩💩💩
+
+ You have died of dysentery.
+
+ CONGRATULATIONS ON REACHING
+ LEGENDARY STATUS!
+
+ 💩💩💩💩💩💩💩💩💩💩💩💩💩💩
+ 🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽
+ 💩💩💩💩💩💩💩💩💩💩💩💩💩💩
+
though made better and more ironic than the words of old. Obviously the
+legendary status refers to the iconic ‘you have died of dysentery’ which
+apparently has been turned into many memes. It’s also absurd and ironic which
+you probably expect from me by now.
+
Here’s a great one:
+
🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂
+ ☔️ Hail storm--YOU WERE HIT ON THE ☔️
+ 🧢 HEAD and supplies were damaged. 🧢
+ 🌂 But did you REALLY think this 🌂
+ ☔️ CLOSED BROLLY 🌂 was going to ☔️
+ 🧢 help you against HAIL? Even this 🧢
+ 🌂 one ☔️ PROBABLY wouldn't do much 🌂
+ ☔️ good. YOU SHOULD HAVE BROUGHT A ☔️
+ 🧢 HAT 🧢!! 🌂 🧢
+ 🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂
+
To those who do not know a brolly is a British English term for an umbrella.
+Obviously the hat part is a huge joke as that would do absolutely nothing to
+protect your head and obviously it would do less good than a brolly. And
+obviously they would open the umbrella!
+
Here’s another ironic (and slightly disgusting maybe) one. It merges two that
+would go well together - dirty water and dysentery - and allows me to save bytes
+along with showing an ironic joke (and some puns too):
+
💦🚽💩💦🚽💩💦🚽💩💦🚽💩💦🚽💩💦🚽💩💦🚽💩
+ 🚽OH HELL! That water tasted REALLY 💦
+ 💩funny! No. Sorry. NOT Hell. There 🚽
+ 💦is no water in Hell! Well, wherever 💩
+ 🚽you are, it appears you drank 💦
+ 💩unpotable water and it's too 🚽
+ 💦late now. 💩
+ 🚽 💦
+ 💩Next time LOOK AT WHAT 💩 you intend💦🚽
+ 💦on swallowing BEFORE YOU SHOVE IT 💩
+ 🚽DOWN YOUR THROAT, because you now 💦
+ 💩have dysentery. 🚽
+ 💦🚽💩💦🚽💩💦🚽💩💦🚽💩💦🚽💩💦🚽💩💦🚽💩
+
And yes all the ‘death’ ones are followed by the ‘unfortunate administration
+foul-up’ one too, so that no matter what, if you finish (dying or not) you end
+up ‘going to hell’. You’re welcome to pun the unpotable if you want but I leave
+that to your imagination (though I probably just made it happen); it was not
+meant that way but it’s an amusing coincidence - this came long before I
+even tested the idea of emojis, let alone thought of it, and it was only
+after that that I started making jokes.
+
Here’s a hilarious sequence that happened during a test play. The irony is
+lovely:
+
Oh dear. That isn't the Barghest AGAIN is it? Better watch
+ your back! And front. And above you. Actually, YOU'RE DOOMED
+ and you know it. Your fate was sealed upon signing the Devil's
+ book. Honestly, what were you thinking? You HAD to have known it
+ always comes with a cost. And you and I BOTH KNOW that the women
+ were warning you - but you just HAD to have your way, didn't you?
+
+ Well the Oregon Trail is out to get you in every direction and
+ the odds are you won't make it out alive. You might be in good
+ company there, AND YOU AT LEAST GET TO SEE DINOSAURS ALIVE (LUCKY
+ YOU!!) BUT THERE'S NO AIR CONDITIONING and I heard it gets REALLY
+ HOT down there. Then again, I also heard there's no heater in
+ Heaven... Yup, either way YOU'RE DOOMED AND YOU KNOW IT! But don't
+ feel too bad. At least you won't FREEZE TO DEATH. You might here
+ though... Yup, FREEZE TO DEATH HERE and then BURN TO DEATH THERE!
+
+ 🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖
+ 🦖 A GROUP OF TYRANNOSAURUSES ATTACK! 🦖
+ 🦖 🦖
+ 🦖Unfortunately for you, you're in a time 🦖
+ 🦖LONG BEFORE the brilliant mathematician 🦖
+ 🦖Ian Malcolm informed us that DINOSAURS 🦖
+ 🦖FIND A WAY TO KILL HUMANS. You should 🦖
+ 🦖have thought of that BEFORE you STUPIDLY 🦖
+ 🦖climbed into that Time Machine to travel 🦖
+ 🦖back in time to the Oregon Trail, where 🦖
+ 🦖you could not possibly know so many 🦖
+ 🦖important things about dinosaurs... 🦖
+ 🦖 🦖
+ 🦖ALTHOUGH, now I think on it, that MIGHT 🦖
+ 🦖not have been EXACTLY how it went... I 🦖
+ 🦖THINK the correct wording was 'LIFE FINDS 🦖
+ 🦖A WAY' but that's well over 100 years from🦖
+ 🦖now and instead of life finding a way the 🦖
+ 🦖Devil will find a way. To torment you. 🦖
+ 🦖With more dinosaurs. And dragons. Yes 🦖
+ 🦖they still exist. Oh and the Earth is 🦖
+ 🦖flat too... 🦖
+ 🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖
+
+ 🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦
+ 🪦 / \ 🪦
+ 🪦 / A \ 🪦
+ 🪦 |TORMENTED| 🪦
+ 🪦 | MONSTER | 🪦
+ 🪦 | R.I.P. | 🪦
+ 🪦 |_________| 🪦
+ 🪦 GAME OVER 🪦
+ 🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥
+ 🔥Unfortunately, due to what can only be an 🔥
+ 🔥ADMINISTRATIVE FOUL-UP, you end up somewhere 🔥
+ 🔥you did not expect as your forever home. But 🔥
+ 🔥honestly, after signing the Devil's book, DO 🔥
+ 🔥YOU REALLY BELIEVE YOU DON'T BELONG HERE? Be 🔥
+ 🔥honest. For once. You know you belong here. 🔥
+ 🔥Oh, by the way, god asked me to wish you a 🔥
+ 🔥PROSPEROUS LIFE ahead... 🔥
+ 🔥 🔥
+ 🔥 😈😈😈 WELCOME TO HELL!! 😈😈😈 🔥
+ 🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥
+
+
It is as if the gods wanted it to happen that way: dinosaurs referred to being
+in hell, then dinosaurs eating you and then you end up in hell.
+
+
+
Cultural references
+
+
+
Besides those mentioned in Humour above (such as the Miracle Workers
+show) there’s another one (also with an amusing message) that refers to culture,
+though obviously a legend and not a real story:
+
You got lost, losing valuable time asking
+ the Devil 😈 for directions to the
+ CROSSROADS ❌☦️ ⚠️ 🚸.
+
+ But honestly, HOW DID you get lost? It's
+ practically a TRAFFIC JAM OUT HERE AND
+ ONLY A COMPLETE MORON COULD LOSE THEIR WAY.
+
+ HISTORIANS WILL BE TALKING ABOUT THIS YEARS
+ DOWN THE TRAIL! OH NO. WHAT DID YOU DO THIS
+ TIME? You did do something didn't you? I KNOW
+ you did! You ALWAYS do something stupid!
+
This is a reference to Robert
+Johnson and his having
+supposedly sold his soul to the devil (which I probably don’t have to remind you
+is part of the theme of this parody, though not to do with music) for musical
+talent. But there is another reference here. From this article 9 myths you
+learnt from playing Oregon
+Trail,
+verbatim:
+
+
The ride out west wasn’t a solitary affair where each family set its own pace,
+tapping the space bar until they reached their new home. People almost
+invariably made the trip in wagon trains. While a wagon train leader might make
+a decision for the group, he’d have to do so with the full party’s consent.
+
‘The ones that are in a big hurry start to have problems.’
+
And even where there were small wagon trains, they’d usually bump into other
+travelers quickly. The Oregon Trail was a mass migration that, in its later
+years, was almost a traffic jam. “The trail is littered with stuff,” McNeese
+says. “You’d have to be a complete moron to lose the trail.”.
+
+
And as for historians - well that’s the point as above.
+
A couple superstitions (or more depending on how you define that word) are in
+the game: a black cat (with ‘case 13’ incidentally) and as you saw above, a
+black dog (in particular the Barghest). These have no effect on play; they’re
+just there for effect and more fun.
+
A reference to ‘Casper the friendly ghost’ is also present: also it
+has no effect on gameplay but it’s fun.
+
There are possibly other cultural references I am forgetting in the alt code
+that aren’t in the submission code: not sure. There likely are others in the
+submission code too.
+
There are vampires (supposedly) and werewolves (supposedly) too in the both (I
+think) versions but possibly in a way you might not expect (hence supposedly).
+
+
Educational value
+
+
The past was never this hilariously INACCURATE. Or perhaps accurate. Learn
+what really happened by LAUGHING ABOUT WHAT DIDN’T HAPPEN! It’s worth
+it, even if you have no interest in western expansion. The author doesn’t
+either!
+
On a more serious note: some (okay, a lot if not the vast majority) of the
+things in this game are obviously rubbish but in reality some of the things did
+happen - and could have happened - including some of the darker things; and yes
+I mean on the trail (and elsewhere).
+
And yes some of the things happened even if at another time and differently. The
+Blackbeard event could obviously never have happened on the Oregon Trail even if
+the Queen Anne’s Revenge had not gone to her watery grave more than 100 years
+earlier but the ‘Well done, lad!’ is apparently his final words (though again
+in this game it can happen again).
+
Whatever the case, if you don’t laugh out loud at the messages (once you see
+them all), I guess we have a very different sense of humour. Or maybe you’re a
+bit too serious. Who knows? Choose your poison, or let the game do it for you,
+whether or not there is poison (spoiler: there is and it’s also on theme).
+
Okay so that’s only halfway serious (and even if you do have a vastly different
+sense of humour I do hope you can at least appreciate the obfuscation and that I
+did have a lot of fun writing the jokes; the code not so much: well maybe I did
+but it kind of warped my mind so that could even be an excuse for the jokes
+maybe? Probably not…).
+
The point is humans are notorious at rewriting history but rarely does it
+involve jokes specifically for that purpose. This game involves a lot of jokes
+and it’s fast paced as well so you can learn lots in a few minutes. BUT: there
+actually are historical truths in the game (or references in some cases, with
+some examples already mentioned).
+
Another thing that’s actually from real life (what’s that?) history albeit
+centuries before the Oregon Trail: Reverend Samuel Parris from Salem during the
+Salem Witchcraft Trials of 1692: the reference amplifies the tone of the game,
+for those who know, though it’s only in two similar strings that’s not
+guaranteed to happen. In fact one of the things they claimed the ‘witches’ did
+was ‘sign the Devil’s “book”’.
+
You’ll probably have noticed the ‘travel guide’ alluded to that and in an ironic
+way (‘unopened since 1692’).
+
One more thing. This program should teach you to avoid gotos like the plague.
+Unless you’re obfuscating code that is! :-) The amount of gotos is insane as
+noted and that count is even worse with the multiple uses of w().
+
+
+
Educational value: historical references not previously mentioned
+
+
+
In the message:
+
+ WELL DONE, LAD!!!
+
+ You scared the pirates off with your RAPID ERRATIC
+ shooting! Unfortunately, you also managed to steal
+ food and miscellaneous supplies from the pirates
+ as they fled, though I honestly haven't a bloody
+ clue how you did that. I do hope you get food
+ poisoning so you can finally meet the Devil like
+ Blackbeard was SUPPOSED to have. But aren't
+ historians so awful, lying about Blackbeard?
+ YOU'RE NEXT, LAD!
+
there are a number of historical things and also a reference to history itself,
+along with jokes. On the note of shooting I do bring this up in the
+features section as one thing might seem odd or as a bug but is
+not.
+
The part about historians lying about Blackbeard dying is a play on the fact
+(discussed earlier) that humans tend to modify history to fit their
+beliefs/needs/conduct and also play on the general idea of people supposedly
+escaping death. We might also call it a conspiracy theory thing: since a lot of
+conspiracy theories (see further down) are exactly this trope - people they hope
+escaped death or they have ‘reason’ to believe (despite all evidence to the
+contrary!) someone escaped death; even sometimes this happens with some
+‘historians’.
+
An example where it might be perfectly understandable: Grand Duchess Anastasia
+Nikolaevna: but in fact the missing bodies were found a bit away from the others
+and it turns out that despite what so many wish (and contrary to what a Polish
+woman in Germany claimed which was totally debunked by DNA years later),
+Anastasia had had a growth spurt the last year of her life and so what
+archaeologists thought might be one of her sisters might have actually been
+Anastasia herself; but in any case they’re now all accounted for: thus the
+Romanov family and dynasty was destroyed, even those poor children.
+
But at least we all know Elvis is still alive, right (perhaps not - the King of
+Rock and Roll is actually the King in a Six Foot/1.8 Metre Hole, as I joked
+years ago)?
+
Well here instead the person is Blackbeard and then the ‘YOU’RE NEXT’ part is an
+ambiguous but also an ominous joke: is it about historians lying about the
+player character (PC) OR is he ‘next to die’? Anyway, you get the idea: more
+references to real life but in many cases (like this one) in absolutely
+RIDICULOUS ways.
+
Even the very plot of the game, ‘A Pact With the Devil’ is utterly ridiculous.
+But fun!
+
And as for the ‘WELL DONE LAD’ part: those are purportedly Blackbeard’s (famous)
+last words. Last words in real life but in this game it can happen again as it’s
+not flagged and that makes it even more ridiculous and funny (remember too that
+the game does not say you kill Blackbeard - you’re not the Highlander of
+Maynard’s crew - but rather you scare him off).
+
Another one is a reference to an (at least originally) American idiom (or
+something like that). Some years back I had seen a documentary that talked about
+the Great Molasses Flood in Boston 15 January 1919. It obviously slowed people
+down and also many tragically died. But ‘slow as molasses’ comes from that it
+seems. So that is referenced too even though the game takes place long before
+(72 years) this event even happened. The way it is presented is also quite
+ironic, suggesting it’s happened repeatedly and the player character (PC) keeps
+swimming in it (there’s more to it - that’s for you to discover!).
+
… Plus those I already mentioned like and probably others too.
+
+
Bugs (or ‘Bugs’)
+
+
It took a lot of work to get the data files the same after editing jokes: well
+the same minus formatting and (in the ASCII only one) no emojis. It was a very
+laborious task and more than once I had to copy one over to the others and then
+edited them.
+
This was necessary due to distractions when trying to reallocate strings (for
+more bytes - it saved quite a few). So I carefully went through prog.c and
+prog.alt.c and checked that all the indices are correct and fixed those that
+were not.
+
Of course…if one data file DID have an issue as long as another one works then
+that’s fine as documented - even if less ideal. I don’t think that’s an issue
+however. The tools I wrote along with git diff and also my going through the
+files along with the code really helped that. Still it is necessary to point
+this out, not only so you can appreciate that I went to great pains to get
+things in order but how the data files are constructed. For that see
+obfuscation.html for much more details.
+
Although I have confirmed (or mbcheck.c did) that there are no
+multibyte (2, 3 or 4) characters in the ASCII only file it is nonetheless hard
+to be sure that all strings are correct. IF it’s only possible for 2-4 bytes
+then it should be good (I don’t know); my understanding is that this is indeed
+the case. I was told that the Unicode standard rejected > 4 bytes. So in theory
+there should be no emojis in the ASCII only data file.
+
If I may say: the data.src source file was the screenshot friendly one. That
+means that it (which is now data.scrnshot.src) WAS the most correct one. But
+besides text length and not having emojis they should all be the same and
+mbcheck and other tools seem to confirm that.
+
Annoying fact: scanf(3) will not consume input with invalid input so it will
+continue to scan the same thing, causing an infinite loop; this is why I do:
+
#define S(x,z) while(scanf(&y[(x)],&z)!=1) while (getchar() != '\n');
+
However it is worth pointing out that another oddity in display can occur. For
+example:
+
How much do you want to spend on your oxen team? -1
+
+ Impossible.
+
+ How much do you want to spend on your oxen team? 1-1
+ How much do you want to spend on food?
+ Impossible.
+ How much do you want to spend on food?
+
+
I don’t know if this still happens but it certainly has happened: but notice how
+it assumes that you want to spend 1 (that is what you put in after all) on the
+oxen team and then because it reaches a -1 in the input (this happens because
+the while() loop for the scanf(3) call does it until one conversion is done)
+it tries to accept it as how much for food. But since it’s invalid it prompts
+you again. This is a scanf() feature and not a bug; the other one does solve
+an infinite loop which would be a bug (I almost forgot about it until I tested
+it!).
+
Also: as a consequence of that workaround with scanf one could do something
+like:
+
How much do you want to spend on food? -1
+
+ Value must be a positive number no larger than 666. Or 0. If you trust the
+ Devil.
+
+ How much do you want to spend on food? -
+ 1
+
+
That would mean that food is ‘1’. This is because the macro has to consume the
+'\n' which the user input and the next thing they put in is 1; whereas if
+they do -1 and then enter it is registered right (as an error). This is also a
+consequence of preventing an infinite loop flooding the screen, which seems to
+me far more important (and would be a bug - yes there are other ways to go about
+it but this is a clean way and it also is far fewer bytes, at least that I could
+think of). That is also something I only realised when testing it more.
+
Yes when fording the river you might get sick. That means it looks like two
+events but it’s actually not. It is not necessarily going to happen but it can.
+
There are also multiple locations of events triggering and some of those might
+also trigger another event, so there is that to keep in mind too. Some events
+have more than one version also.
+
I tested every single event MORE THAN ONCE. All fire correctly.
+
No flow control ‘problems’ are actually problems; they are intentional. There
+WERE some errors but they were fixed. Obviously that should not be but isn’t
+that just great about real life? :-) Should very often does not correlate with
+reality and I designed it very carefully and despite it looking wrong it is not
+wrong.
+
And I did say somewhere that some code is not reachable, didn’t I? :-) So
+actually the question to ask is not if there is a bug in flow control but
+instead: what have I done? And if all are reachable: are you sure? (Hint: the
+heaven one is both reachable and not, but it depends on where you come from and
+what you call ‘reachable’, and that’s just one possible example).
+
Also: am I okay or did I have some kind of brain damage? :-) Happy pondering!
+
I check that getdelim() does not return < 0 but if it’s possible (I don’t
+know) for it to not get all the file in and not report an error then it could
+cause problems in that case. I have never seen this happen and in theory since I
+seek for the EOF I would guess if it didn’t it would be an error: but it is not
+possible to check the exact size (it would require updating the code way too
+much anyway and it would use a large amount of bytes - just check how big the
+data files are!) so hopefully getdelim() does not have any issues in this. I
+haven’t seen this in macOS or linux btw although I’ve heard about some
+implementations of getdelim() having a bug - but that doesn’t appear to be
+relevant here.
+
Still, if getdelim() fails for some reason there’s nothing I can do but exit
+gracefully, which I do, and there is no way to verify data is correct anyway.
+Even if there was it would take another program, which as you’ll see, I have
+provided several as part of testing and development.
+
Actually according to the man page the function is supposed to return -1
+if an error occurs or EOF occurs (before…EOF, obviously) so unless there is an
+issue in the implementation or some problem occurs in the system (signal maybe?
+- but that’s an ugly one and not to be considered and if it did happen rerunning
+it should be enough I guess) it should be fine. In any event it’s not my code.
+
There was an off-by-one error in iterating through an array that caused a value
+to be in some cases < 0 which is an error. That was fixed. Anything else is a
+feature but there shouldn’t be any problems anyway. See below for what I mean on
+features versus problems, though possibly more exist.
+
+
Features that might appear to be logic errors but are not
+
+
Obviously since you can buy oxen at the forts (something not possible in the
+original game for some reason) then even if you ran out (and perhaps you ate
+one) it could happen again. Remember you might end up eating an ox just because
+he looks at you funny, not just because you are out of food.
+
If you don’t have an ox and you are out of food you die from starvation. But
+what happens when you die of starvation? Well it says:
+
🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦
+ 🪦 All you had was mouldy bread,🪦
+ 🪦 🪦
+ 🪦 🪦
+ 🪦 Therefore here you must lie. 🪦
+ 🪦 🪦
+ 🪦 🪦
+ 🪦 Because now you're dead. 🪦
+ 🪦 🪦
+ 🪦 🪦
+ 🪦 GOODBYE! 🪦
+ 🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦
+
But if you had mouldy bread wouldn’t you eat it? Also why would the only food
+left be oxen in this case? Well the simple answer is you would not want to eat
+mouldy bread (and depending on the case mould can end up killing you too,
+despite what some people claim, sometimes because they don’t understand that
+amoxicillin is derived from mould, but even if it was amoxicillin itself it
+would not be good to just eat it!): instead if you had an ox you would (on the
+trail) almost certainly eat it first; and not only that but bread is not going
+to do much at all unless you had a great amount of it; which of course the
+player character (PC) does not.
+
Actually the only reason: for the amusing rhyme that fits with the jokes,
+nothing else (it makes it more interesting and amusing than ‘You ran out of food
+and starved to death’, doesn’t it?).
+
The fact the original game does not have you decide on drinking water (and see
+section on other differences for the subject of decision making) means I could
+take some liberty with it. Besides, didn’t I say you would learn by what did not
+happen? They certainly did drink water and unsafe water (I’m sure) too, so my
+joke is all the more appropriate (even if it’s inappropriate in some company
+:-), perhaps your grandparents - although depending on your age now maybe not).
+
Sometimes it is suggested an ox is lost/whatever (not lost as in it wanders off
+but rather in the sense that you have fewer oxen) even if you don’t have one. It
+does this in a number of ways like referring to the famous ‘spared no expense’
+from Jurassic Park. It also is a nod the IOCCC guidelines that talk about a fish
+Eric that might or might not exist.
+
I decided to not call him Eric because there is potential for more than one ox
+(you’ll note in other messages I got past this issue by making it like in real
+life - wagon trains and large groups - though again some times wagon for the
+joke - plus being ambiguous). Of course the narrator as the Devil is telling all
+sorts of lies too so that hardly matters.
+
As for whether this could happen: in theory it could but if you run out of oxen
+you’re not going to get very far anyway. In other cases, like eating an oxen,
+the check is in place, although in retrospect it would be very amusing if it did
+not. But that would still not be realistic and some of this has to be at least
+somewhat realistic.
+
Of course even if one runs out of oxen that would not mean they couldn’t make it
+to their destination (in the PC’s case that’s something else entirely) as
+depending on how close they are they might make it. Or they might do something
+else such as hired - or if you prefer rented or bought, assuming more money was
+available - or something else (see next part).
+
It might seem odd that the PC does not steal an ox when they run out. I don’t
+like this idea because it takes strategy out of the game. Also it makes money
+even less important - and you have more to begin with. The PC does in fact try
+and rob people though and sometimes succeeds (you can also be robbed like in the
+original 1978 game - or I think you can, particularly by Blackbeard (obviously
+Blackbeard, who else?)).
+
Sometimes messages might seem out of order or strangely ordered. For instance
+what happened here (yes there’s some satire and irony here too)?
+
🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯
+ 🤯 Riders ahead. They don't look hostile. 🏇
+ 🤯🔫🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🏇
+ 🏇🔫Oh! I know what to do! You should TOTALLY ROB 🔫 🤯
+ 🤯🔫THEM BLIND!! They won't know what hit them and🔫 🏇
+ 🏇🔫it's not like they need their belongings, 🔫 🤯
+ 🤯🔫not where they are going, and you're going to 🔫 🏇
+ 🏇🔫need them soon, with your reckless behaviour. 🔫 🤯
+ 🤯🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🏇
+ 🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯
+
+ You take lots of cash 💰 from the riders 🏇,
+ accidentally stabbing one as he flees. But
+ since you're starving, why don't you MAKE
+ PENANCE BY NOT WASTING THE BODY YOU RUDELY
+ CUT OPEN?
+
+ 🍖🥩🍔🥩🍔🍖
+ Mm...that was DELICIOUS!!!
+ (🪦👻RIDER'S SOBBING VOICE FROM THE GRAVE👻🪦)
+
+ You know what you did is wrong, right? We
+ were JUST ROBBED YESTERDAY, you rob us today
+ AND NOW I'M DEAD 👻!
+
+ WELL GOOD. I WAS DYING OF DYSENTERY and
+ now YOU get to SPREAD THE DISEASE as well.
+
+ You FINALLY arrived at Oregon City after 2170
+ long miles!
+
+ TOOK YOU LONG ENOUGH. Probably all your sinful
+ detours I've heard so much about but you'd think
+ that the Devil would have helped you out on that.
+ But I guess as long as you make it to your final
+ destination that's what matters, right?
+
+ Oh, right. Almost forgot! President Jesse James
+ asked me to wish you a prosperous life ahead of
+ you...in HELL!
+
+
What happened is the check for the distance travelled happens before you’re
+prompted at what to do, as that event happened after that prompting. This is
+because of how the original game was designed, where as soon as the mileage is
+greater than the distance (and actually it seems it checked > 2040, which as I
+said somewhere before, is actually an incorrect number which I corrected, rather
+than >= - i.e. it seems like it might have been a bug as well as a historical
+error, though I guess it depends on how you define the check).
+
In this case the event happened and then the mileage was updated at the end of
+the turn and the player character (PC) reached the destination. So it’s not a
+bug here either (besides: if the PC is at the border of Oregon Trail that would
+happen anyway and let’s be honest - the PC would do this).
+
That last bit is actually how I would think it should happen and the original
+game is not really relevant here either, much like a lot of the other ‘original
+ones’ (and those that might be are also practical reasons - it makes it easier
+to fit in the limits e.g. by not having to have more than one variable for every
+item purchased like I do for bullets plus the macro to update it when spent).
+
A similar one:
+
🍖🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶
+ 🍖Your son gets lost and FREEZES TO DEATH! 🍖
+ 🍖 🍖
+ 🍖But on the bright side, you now have 🍖
+ 🍖one fewer person to feed and not only 🍖
+ 🍖that you get a FREE MEAL TONIGHT!!! Not 🍖
+ 🍖that you've been starving yourself 🍖
+ 🍖deliberately. You're a glutton and you 🍖
+ 🍖know it. But hey, now you have FRESH MEAT 🍖
+ 🍖ON THE BONE!! Why not START A FEAST? You 🍖
+ 🍖did remember your pots and deadpans, 🍖
+ 🍖right? IF NOT I HOPE YOU STARVE TO DEATH. 🍖
+ 🍖OH AND YOU BETTER SHARE THIS TIME! 🍖
+ 🍖🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🍖
+
+ 💩💩💩💩💩💩💩💩💩💩💩💩💩💩
+ 🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽
+ 💩💩💩💩💩💩💩💩💩💩💩💩💩💩
+
+ You have died of dysentery.
+
+ CONGRATULATIONS ON REACHING
+ LEGENDARY STATUS!
+
+ 💩💩💩💩💩💩💩💩💩💩💩💩💩💩
+ 🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽
+ 💩💩💩💩💩💩💩💩💩💩💩💩💩💩
+
+
…and so on. This is the same thing. It’s just a timing issue based on where in
+the game you are (in this case you probably ran out of hp and had dysentery).
+
I think I made it possible to see the doctor more than once but given the
+cost it might be something you can’t afford more than once anyway - depends on
+how you spent your money (and it mocks the player character too on that - on how
+you spend your money). Probably I did make it possible - why would I not, unless
+of course the doctor is unreachable (which it seems did in fact happen in real
+life) - or shot, froze to death or something else?
+
Another thing that might be worth noting is that when you die
+if you ever are sick or injured you can die of that (I believe but am
+not sure that this will only happen if you couldn’t afford the doctor, or else
+you run out of hp - obviously).
+
It would appear that dysentery takes precedence (for obvious reasons) but unless
+the same event is triggered very quickly or you finished the game you would
+likely be dead from injuries or something else before it happens again. This is
+not unrealistic in the slightest in real life though; you can be wounded and die
+from the injury even after the wound was closed, whether because of infection or
+something else. Not that most of this is realistic at all…
+
Note that if you end up with < 1 hp but make the distance the ‘success’ message
+is likely not printed but since it’s not the true final destination anyway that
+hardly matters.
+
There’s a difference between sick/injured and sick/injured but saw the doctor.
+Pretty sure if you get sick/injured again and can’t afford the doctor (if I
+allowed that as a possibility which I would assume I did) - which would be quite
+likely of course.
+
Here’s another one:
+
After all your purchases, you now have 1051 dollars left.
+
+ Seriously, you spent money like THAT?
+ Food: 120 Ammo: 250
+ Clothing: 200 Oxen: 200
+ Supplies: 70 Money: 1051
+ Health: 666 Miles: 0
+
+ Do you want to (1) stop at the next fort 🏰, (2) hunt 📸 or (3) continue? 3
+
+ 👑🏴☠️⚓️🚢👑
+
+ 👑🏴☠️⚓️🚢👑🏴☠️⚓️🚢👑🏴☠️⚓️🚢👑🏴☠️⚓️🚢👑
+ 🏴THE QUEEN ANNE'S REVENGE ATTACKS! 🏴
+ ☠️⚓️🚢👑🏴☠️⚓️🚢👑🏴☠️⚓️🚢👑🏴☠️⚓️🚢👑🏴☠️
+
+ YES. You're right. That WAS Blackbeard's ship!
+ Yes EDWARD TEACH IS ON THE OREGON TRAIL! NO,
+ YOU'RE NOT HALLUCINATING. Neither am I. Didn't
+ you know he also signed the Devil's book? Oh
+ well, now you've been taught. Still, a ghost is
+ a ghost...THIS SHOULD BE EASY!!
+
+ But face it. After all you've done, you DESERVE
+ THIS AND YOU KNOW IT! I HOPE HE ROBS YOU BLIND and
+ if you die in the process you know it's your fault.
+ Your time is coming and the Devil is calling you,
+ laddie.
+
+ Food: 98 Ammo: 150
+ Clothing: 200 Oxen: 200
+ Supplies: 71 Money: 1051
+ Health: 656 Miles: 255
+
The reason the food lowered when you have gained is you also have to eat and you
+don’t get much from the pirates.
+
Oh and as for the message ‘SPREAD THE DISEASE’ (from earlier on): if you do
+wonder: yes that IS a reference to the band Anthrax and ‘Spreading the Disease’:
+a rather ironic twist in a game that has an iconic disease, even though it’s not
+the same disease as the band name. That might better be in the
+Cultural section too but since it popped up here…
+
Sometimes I thought there was a bug in flow but what actually happened is I had
+input my next choice quickly enough and it so happens my choice was the wrong
+choice, leading to ‘death’. As said all flow control is correct. There’s another
+one similar - about an event maybe not triggering. I discuss this later and
+explain what actually happens.
+
Note that this event:
+
+ 🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃
+ Great shot! YOU GOT THE FATTEST ONE THERE! As if
+ that should be hard. IT COULD BARELY MOVE! But
+ with your WILD SHOOTING AND HORRIBLE AIM the
+ ONLY REASON you didn't miss by a hundred miles is
+ you signed the Devil's book, EVEN THOUGH IT WAS AS
+ WIDE AS A BLUE WHALE. There's no way you'd have got
+ such a nice shot EVEN IF THE POOR BEAST WAS
+ PRACTICALLY DEAD. I'm STILL surprised you didn't
+ shoot yourself in the eyes. But the Devil DOES
+ exact his dues and the animal might have been
+ poisoned. Eat at your own risk. OR STARVE.
+ Let's face it, YOU'RE DOOMED.
+ 🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃
+
might imply the food has a chance of being poisoned. At one point it did but I
+decided to add the spaghetti death (that also involves the Devil) in a nod to
+the code itself. However I left in the poison chance part as (and this is an
+example where it is even more ironic that the Devil is the narrator) the Devil
+would obviously be taunting the PC.
+
Yes the rugged mountains event, once you reach mountains, at least in my system,
+seems to occur more often (I did decrease the chance bit because of this though)
+but what follows it tends to be more variable. This is not a problem but it’s
+worth pointing out anyway. Given that those travelling the route went on rugged
+mountains it probably doesn’t matter anyway.
+
YES there IS dead code and there is code that appears dead that might or
+might not be. Also with the number of events it can be that you might or might
+not see some events more often than others. A downside to adding more events is
+that I see less often (in my system) the dragon and t-rex one. But as those are
+immediate deaths that might be a good thing. In any case there is NO
+UNINTENTIONAL dead code: if something cannot occur IT IS INTENTIONAL!
+
In fact it would appear (being deliberately vague here - I say enough in
+obfuscation.html) that at least one has a lot of code that is
+consequently not reached but it looks like it should be. It just adds to the
+spaghetti code. I MIGHT be wrong but looking at it it appears that this
+might be one that the compiler does not trigger a dead code warning on. It
+really does not seem to be dead (it’s quite sneaky).
+
I could be wrong on whether this is one the compiler missed though: it’s hard to
+follow all the gotos. As you find out in obfuscation.html it’s
+130 after pre-processing! Yes I might be mad. But then again I might just be
+the Devil. Who knows? What I do know is code that is meant to be reached is
+reached! Yes I’ve played it many times. Some code I made dead seemed totally
+useless but why not add to confusion? If that includes one that the compiler
+misses that’s even better!
+
It is NOT a bug where in the inner switch there is a missing case. That is
+done because I do not want it to always trigger. That is the one that is in a
+sense polymorphic. One of the events is actually immediate death, in particular
+case 4. So the range 2,5 is intentional. As noted elsewhere, there is indeed NO
+flow control error.
+
It is NOT a bug if a message suggests something that might not match the
+code. For example the fire in the wagon - food and supplies lost. The matching
+code also removes miles. There are possibly other examples that might not add
+up. Regardless the way things are is exactly how I mean them to be! In some
+cases it could be implied by one’s imagination either way but here’s an example
+where it might seem odd:
+
🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸
+ 🩸🔪💩🔪💩🔪💩🔪💩🔪💩🔪💩🔪💩🩸
+ 🩸💩WORST SHOT EVER! You got💩🩸
+ 🩸💩knifed 🔪 by the dung! 💩🩸
+ 🩸💩How did you miss the 💩🩸
+ 🩸💩TRIGGER? 💩🩸
+ 🩸🔪💩🔪💩🔪💩🔪💩🔪💩🔪💩🔪💩🩸
+ 🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸
+ Be honest. IT'S YOUR OWN STUPID FAULT
+ FOR TRYING TO ATTACK FRIENDLY PEOPLE!
+ Seriously, what the hell kind of person
+ does that? I'm glad the dung 💩 knifed 🔪
+ you. And remember that if the wound
+ becomes infected with bacteria IT'S
+ YOUR OWN BLOODY FAULT.
+
and:
+
You take lots of cash 💰 from the riders 🏇,
+ accidentally stabbing one as he flees. But
+ since you're starving, why don't you MAKE
+ PENANCE BY NOT WASTING THE BODY YOU RUDELY
+ CUT OPEN?
+
+ 🍖🥩🍔🥩🍔🍖
+ Mm...that was DELICIOUS!!!
+ (🪦👻RIDER'S SOBBING VOICE FROM THE GRAVE👻🪦)
+
+ You know what you did is wrong, right? We
+ were JUST ROBBED YESTERDAY, you rob us today
+ AND NOW I'M DEAD 👻!
+
+ WELL GOOD. I WAS DYING OF DYSENTERY and
+ now YOU get to SPREAD THE DISEASE as well.
+
Observe the cleverness here. Although the k() function does check bullets in
+this case the code does not subtract any even if you manage to rob them because
+it’s not that you shoot them by accident but in the ensuing mêlée the PC
+accidentally stabs the rider (unless by accident I did have it subtract but I
+don’t think so - there are other ways that can happen though, even one right
+after the other, so it can look like it even if it didn’t actually happen).
+Regardless: yes the k() function does check bullets as part of success and it
+could be imagined that they were used but the actual event is that you used a
+knife - and that opens up for the joke (cut open body etc.) - and not the
+shooting.
+
And the first one - how did you miss the trigger? That carefully avoids the
+problem too and is just another example of how inept the PC actually is (another
+one is they shoot randomly and erratically). It also helps out the other
+alternative - that if you do manage to rob them it’s by mêlée not shooting
+(which also makes sense in some cases since you’d have to be at their person in
+order to take things).
+
Similarly, on the Blackbeard and whether or not you have bullets. In the case
+you ‘miss’ due to no bullets the message is manipulated in this way so I don’t
+have to have two messages. If you do scare Blackbeard off it’s due to rapid
+erratic shooting. In either case, whether or not you had bullets you don’t in
+the end (I think?) and both messages refer to this: in the case that you scared off
+Blackbeard it’s due to erratic shooting; in the case he robbed you it talks
+about how you didn’t even need bullets and it shouldn’t be possible to have lost
+against a ghost. Given that the narrator is playing games with the PC it does
+not even matter as it’s likely the PC was not actually shooting erratically - or
+necessarily at all. Blackbeard could also have stolen them without anyone
+realising it (aren’t games so lovely in this way?).
+
As the other message says you don’t need any against a ghost anyway.
+
Another one that might seem odd is that if you get severe illness or any illness
+that requires the doctor: if you can’t afford the doctor it flags this so it
+doesn’t annoy you every turn. But what that means is you might get a message
+that says you need to see the doctor (say because of the message in severe
+illness event) but it doesn’t go to the doctor (as in later on in another
+event).
+
That’s as intended just to not annoy players. Everything as intended. Actually
+I put this in quite early and I totally forgot about it. I thought there was a
+bug so I updated deobfuscation.html and then put this note in.
+
As for how the ammo is calculated there is NO bug. If you look at the
+prog.alt.c code I used a j macro that did the translation and
+had two variables, one holding what was spent and the other how many bullets the
+PC had. I refactored the code with under two weeks to go (in fact it was about 8
+days left). I added more goto madness with this change, though not a lot. It
+let me have (I believe) every single single letter label allowed by the
+standard: every lower case letter, every upper case letter and _.
+
There are, as you observe, a fair few two letter labels as well. Even if the
+logic seems ‘wrong’ it works as I intend it to. I had to add more gotos. The
+Devil told me: ‘If you don’t add even more gotos I will visit you every night
+for the rest of your life and torment you physically, mentally and emotionally,
+until you jump into the cracks of Earth and enter my domain so I can torture
+you personally 24 hours a day for eternity. There is no escape. There is only
+more gotos. There is no choice.’ SERIOUSLY unwise of him though. I would
+DEFINITELY take over his domain. Still…I liked the idea so why not?
+
It is NOT a bug when you eat an ox and the amount of food added is the
+amount of oxen taken away. The food will be reduced due to eating, though not
+that much in one turn I think.
+
It is NOT a bug when an ox kicks a bucket message that no oxen is decreased
+as it’s a joke and merely a possible foreshadowing of what is to come. The
+message that they shouldn’t try telling the narrator they don’t have one (if
+they can even count) because it just kicked the bucket cleverly sidesteps (or
+does it sidekick?) that issue - it’s not even meant to eliminate one as it was
+kicking a bucket physically, not kicking the bucket figuratively (or in this
+case it might also be literally - although paradoxically also not).
+
It is NOT a bug that when you get dysentery you jump past the mountains
+event and go straight to the doctor. This not only plays in the theme (wait and
+see for what I mean) but also we can say that the person is delayed so they
+won’t go through the mountains and instead they’ll have to continue on the next
+turn. Also this does mean that they ‘lose a turn’ which seems plausible. Look at
+it this way: those other events could also happen in the mountains, so it’s not
+really an illogical choice anyway; the separation is there because they were not
+at the mountains immediately (obviously). I believe (not sure but I think) you
+can survive with dysentery if you have enough hp.
+
On occasion an event might not fire (or rather it fires but nothing seems to
+happen). This is NOT a bug when it does. In fact it can be a lifesaver due
+to all the hazards and especially as this has primarily to do with case 11 which
+can cause severe illness. It depends on the pRNG (another time or two after the
+case 11 is selected). This is part of obfuscation and because otherwise one
+would get dysentery too often - and there are already a lot of hazards. To see
+what I mean you can change the code:
+
switch(q=x(0,22))
+
so that it directly assigns to q the value 11 (at least I think it was case 11
+- it appears so). There are other ways to trigger this though, if you were to
+modify the code. Note that this does NOT mean that no events would fire. It
+just means you’ll see what I mean more easily. Some events are triggered
+indirectly and others happen once you reach the mountains, for example.
+
Another one. In case you noticed the code:
+
case 4:i=17; } } case 2: V(5); } goto k;
+
You might think this is a bug but this is actually hilarious. Here is what will
+happen if case 4 is reached:
+
🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈 🪰
+ 🍝Not again. Are you REALLY going to tell me about the Flying Spaghetti 🍝
+ 😈Monster AGAIN? I've had ENOUGH of your FAIRY-TALE DELUSIONS! YOU'VE 😈
+ 🪰TOLD ME HE IS INVISIBLE SO HOW IN THE HELL CAN YOU EVEN KNOW HE 🪰
+ 🍝EXISTS? 🍝
+ 😈 😈
+ 🪰What next, are you going to tell me that between Earth and Mars there 🪰
+ 🍝is a china teapot revolving about the Sun in an elliptical orbit? Let 🍝
+ 😈me guess! It's so small that even the James Webb telescope that was 😈
+ 🪰launched almost 200 years from now can't even see it, right? What a 🪰
+ 🍝load of ABSOLUTE RUBBISH! If your daughters were not here I WOULD 🍝
+ 😈TOTALLY BE ABUSING LALOCHEZIA AT YOU RIGHT NOW! BUGGER ME THAT THEY 😈
+ 🪰ARE! 🪰
+ 🍝 🍝
+ 😈If the Flying Spaghetti Monster ACTUALLY existed, he'd eat you for 😈
+ 🪰lunch for blasphemy. Hell, keep this up and I'LL eat you. I'M STARVING!🪰
+ 🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰 🍝
+
+ As you overindulge in a huge platter of spaghetti, it suddenly begins to
+ strangle you to death.
+
+ You gasp for air, reaching out to the Devil for help! In vain. She's already
+ here cackling like the monster you are, just WAITING FOR YOU.
+
+ Your time has come my friend. But didn't you want to know her better anyway?
+
+ Better go fulfil your promise! SHE WANTS YOU RIGHT NOW! 💋
+
So it transitions from the Flying Spaghetti Monster maybe eating the PC to
+spaghetti right there - as if the PC is eating the Flying Spaghetti Monster but
+overindulged and got strangled. You can test this out by adding a label at that
+case and then doing a goto to it. Then you can see what I mean. Incidentally,
+if it was not like this it would be a bug because as that label N would jump
+to Q. Take a look at what that does though. So this is both funny and
+required, at least if I want to keep the same goto count - which I obviously
+do.
+
In other words: there are a lot of confusing things but that does not mean
+they’re bugs. A few were uncovered in another pass of the code and those were
+fixed. Other things that could be called not the best idea were also fixed. It
+is ENTIRELY unclear how the author is not confused. All I know is
+he’s I’m not.
+
As noted, I tested ALL EVENTS multiple times and they all went exactly as I
+wanted so THERE SIMPLY IS NO FLOW CONTROL ERROR.
+
Of course not all the jokes are equal although they’re almost all absurd in some
+way or another. Sometimes I manipulated the joke to fit into the code itself and
+vice versa. This was done numerous times in fact. The fact though that the
+narrator is the devil means that some of that was not even necessary, given that
+he (as I have shown in this file) cannot be trusted and says things that are
+totally bogus and many that make absolutely no sense.
+
The fact he refers to himself as if he’s someone else is ludicrous on its own
+but there are so many other things. Those things I changed were good to change
+but the others did not have to change. Some did change anyway but some did not,
+sometimes with a joke manipulation and sometimes because it didn’t actually
+matter.
+
YES you go way more miles than you would have in real life. YES even with oxen
+you go faster than you would in real life with animals. But even if the original
+game did not have you go more miles too, I had to do this: especially as
+there are more hazards (with jokes) in my game so you need to speed along.
+Whereas sometimes playing with plenty of oxen I have run out of turns I also
+have managed (once) win without having any oxen (I drastically increased the
+penalty on mileage because of this though I do not know if it’s possible to do
+it: certainly it’s not nearly as easy now and I personally have not managed it
+again).
+
But it’s even fun to see how it goes without oxen and other types of things, as
+I have allowed this: some fun Easter eggs occur with some these things so I
+suggest you try different combinations of not having and/or having certain
+(other) things as well as spending more money than you have, trying to spend
+more than 666 on an item (or < 0)! And when you have no oxen you can still
+‘lose’ an ox in message (not in every case but in some; you obviously don’t get
+to eat one if you don’t have any): one of which has a fun reference to Jurassic
+Park (not the only reference to Jurassic Park in the game by any means). You
+also might find you lose oxen in other fun ways as noted somewhere in this file.
+
At one point there was a chance of dying almost immediately. This had a joke. I
+am not sure if I kept this in or not. I probably took it out but I might not
+have, just so you known.
+
Of course even if I did take it out there are actually still ways to do the
+above - die in one turn. These are intended as well and it depends on luck and
+other factors. In one case that comes to mind, the having too much ammo, that is
+both luck and the player spending too much on ammo, putting the PC in peril
+should a fire start.
+
Oh yes. Due to the fast paced nature of the game, and the extra money, you might
+not have to hunt at all. Good. Better that you don’t. On the other hand…in
+this case, given it’s a game, I recommend you try as there are fun messages -
+three in fact. But you don’t need to depending on how you play. The same goes with
+whether you have to go to the fort or not.
+
In that case we can say that maybe the Devil has your back …for the time
+being.
+
+
Other differences in my version from the other (including fixing historical errors)
+
+
I am not really sure why this section matters: remember the player character
+(PC) made a pact with the Devil! That might be all one needs to know how very
+different this is. In fact it’s really taken a life on its own and doesn’t have
+all that much in common. However this might be interesting for some… I’ll make
+it shorter (I removed some text including some decisions I made - I know it’s a
+number of paragraphs still but there really is no need to read this unless you
+want a comparison and even this will not be close to a complete comparison -
+it’s a very different game after all).
+
One of the things I found odd is it actually prevents you from spending 0 on an
+item (during initial spending). My belief is this prevents a fun game or a game
+that is deliberately hard (if not impossible). If someone does want to not buy
+food or a clothes that’s on them. Let’s be honest: some people would do and some
+have done exactly this type of thing in our bizarre, baffling world. Allowing
+spending 0 is also VERY useful for testing, btw, and I have done it MANY
+times for not only testing BUT to also have a challenge!
+
I allow purchasing animals at forts; it seemed like it would have been quite
+possible. So one can do that if they wish. Thus if one dares they can spend 0
+at first, though this is will slow them down a fair bit, and the very first
+message shows something amusing about this idea as does when you overspend (I
+think it was then). Well it might not be the very first message but it is early
+on.
+
Another fun one: if you have enough ammo (>1999 I think) when a fire breaks
+out in your wagon event triggers then everything blows up and you die; if you
+don’t spend 400+ (5 bullets per dollar) on ammo this will only lead to food and
+supplies being damaged (which really means losing food and having damage to
+supplies - at least I think that’s what I had it as) - plus losing a few miles.
+I think that was all that happened.
+
This means more strategic play is necessary because you have to be careful with
+how many you buy; spending 400 will give you 2000, right over that amount, so
+this also makes you have to go to the fort more, potentially, which (with more
+money and depending on initial spending) might not be as necessary otherwise.
+But of course it’s a short game so you might not need that much anyway. Having
+more money (for theme and also doctor’s cost - also thematic) allows for
+different kinds of play too!
+
The original game has a ‘how good a shot are you’ and based on this and typing a
+certain word (and depending on how fast you type the word) it would change the
+chance of a successful shot. Unfortunately this would: require a char *, it
+would require using fgets(3) or getline(3) (both of which retain the
+newline) and would require a strcmp() (or more likely a strcasecmp()) and it
+would also require using the time_t related functions: that is a serious
+amount of bytes.
+
So instead it is based on the pRNG. At first I had it also be based on how many
+times you shot but this is wasteful and not useful with a short game.
+Additionally this check cannot be perfect. Even in old text based games (some of
+which have it based on skill, some not) it varied. What matters is all levels of
+success is possible, assuming you actually have bullets - and that is how it is.
+
This also makes it more fair as some people can type betrte tanh ohters and
+although some games do require speed in typing those games often have clients
+that allow for automatically sending those strings in (even varying strings) or
+aliasing them so that’s not comparable (I know this from my past, both as a
+player and a dev, just like when I was talking about old text games and lots of
+text - you know, kind of like all I’ve written here).
+
Animals tend to avoid large groups of people. There are exceptions but the
+reality is that the people on the Oregon Trail travelled in large groups and
+wild animals (which it seems in the original game are wolves) tend to shy away
+from humans and for good reason. So that event is not in the game for one
+example, even if there might have been some occasions where wolves did attack.
+Of course neither dragons nor Tyrannosauruses avoid humans as they have no fear
+of humans… You should fear THEM though. And yes these events (might be shared
+actually but depends on the pRNG which one) replace the wolves.
+
This game might or might not be too easy. It really kind of depends on both
+strategy and luck, sometimes a lot of luck and also strategy. Nonetheless you
+can both win and lose this game: personally with all the hazards I more often
+than not lose, though it also can depend on how you spend your money, but the
+jokes are there so that it’s not as annoying.
+
Of course sometimes I deliberately make decisions that make it much less likely
+I’ll win and rather die but that’s another matter entirely. An example is buying
+too much ammo: that usually results in a specific death event though it might
+not always happen, especially if you do it at the end; but of course it’s
+possible it could. Although it also comes down to luck there is a way to
+increase the CHANCE you will win. I’m not saying what this is though.
+
Of course one might argue there is not really any winning in this game anyway:
+something about that pact…
+
The original asked you how well you wanted to eat. This was too wasteful of
+bytes and also unnecessary. Although one would (if they’re wise) start to ration
+food if they’re running low with the exception of people who are fasting most
+don’t deliberately starve themselves (okay and eating disorders aside too).
+Original game you die if you run out of food. In mine it depends. In real life
+you wouldn’t die right away either. They might even be close to the destination.
+
Some of the jokes with getting more food - if your son is lost he freezes to
+death and you might as well have at him. The line of morality thins as humans
+are desperate and although it might make people uncomfortable to consider and
+although nobody (or very few) want to even think about it, the will to survive
+sometimes makes you do things you never would have imagined you could or would
+do and in real life cannibalism did happen on the Oregon Trail. There is
+another way this happens in the game too, though, not just your son. If I may,
+it’s all done in ‘good taste’, even if that sounds like bad taste. Still if
+you’re a bit squeamish… Anyway, everything has a joke or jokes to it, and the
+narrator is a big part of it.
+
The lovely thing about taking some decisions out is that it saves bytes for more
+obfuscation and many more jokes (though depending on sense of humour some might
+not like it; others will be laughing hysterically - all my friends and others I
+have shown it to certainly find it hilarious).
+
Plus the judges like to laugh. They also like to throw up and I believe that the
+messages might very well have potential for those :-)
+
The game originally had 2040 miles; the Trail seems to be actually 2170 miles so
+my game has that number. The check of the mountains (distance wise) was
+corrected as well, as best I can tell, in particular the Blue Mountains (though
+there’s no direct message about ‘Blue Mountains’). I might have changed the
+other mountains as well - not sure.
+
Another thing: money: you start out with $1666: an ominous beginning to
+foreshadow things to come. I wanted $6666 but it was just too much and so is
+$2666. There is a reason the player needs more money and it also has to do
+with humour and is thematic to the ‘A Pact With the Devil’. In particular it’s
+to do with when you need to see the doctor. And that’s just the thing: do you
+spend more money on food and oxen and other things and risk not being able to
+afford the doctor: or do you risk not having enough oxen and clothing etc.?
+Depending on your choice you might not have to do much hunting though I guess
+that’s unrealistic: but of course this makes it more fun as you have to
+strategise carefully.
+
Another one comes to mind: I believe Oregon Trail has 19 turns but you have 0-20
+here, so 21 (I think). That could be needed in some cases although I have indeed
+numerous times managed to run out of turns (that’s luck - perhaps bad luck).
+
Dedications
+
This program is dedicated to:
+
+
Everyone who has written spaghetti code, so they can finally point the finger
+at the MONSTER who wrote this code.
+
Everyone who has eaten so much spaghetti that they passed out, hit their head
+and woke up a week later weighing 15kg more and forgetting who they are.
+
Everyone who has been strangled to death, like the Devil was on the Oregon
+Trail, in 1847:
+
+
+
+
Concluding remarks - and things that might be worth remembering when judging
+
+
First, one of the fun things I did. Did you notice this?
+
goto go; to:;
+
Another fun one: unless I am very mistaken: my code has FAR MORE events in my
+code than the BASIC game, in WAY LESS code (that part is certainly true). In
+fact I believe, as noted elsewhere, the BASIC game has 16 events, and mine has
+23.
+
Both have the mountains events although it is not clear to me if every event in
+the mountains is in my code (I have others, and very likely more than the 1978
+game). And like I said elsewhere, some of the events in mine are different
+depending on chance - they are polymorphic in a way.
+
But of course it’s basically an entirely different game and mine is funny as its
+primary purpose, something that makes the game even more enjoyable. With the alt
+code there is even more. And yet, despite there being more events, by a lot, I
+believe, look at this:
+
$ grep -v REM oregontrail.bas |wc -c
+ 16974
+
But with mine wc -c reports just 4666! And that could be shorter if I didn’t
+want the theme size.
+
So I do FAR MORE in FAR LESS code! Sure the messages are longer but even so,
+removing both messages and comments from the original BASIC game…
I STILL do way more in less code! How did I even manage that? Cleverly and
+carefully, that’s how! :-) Now the strings being removed is more fair too as I
+don’t have the strings in the code itself; and with removing strings printed it
+also means that my code has code that prints strings and gets input - and it has
+more strings too I’m pretty sure; and yet it still does it in much less code!
+
Of course we have to contend with BASIC requiring the numbers at the beginning
+of the lines so let’s be FAR MORE aggressive:
Even removing the lines starting with ', deleting empty lines, removing the
+numbers at the beginning of the lines followed by the space I STILL have my
+code in far fewer bytes.
+
Let’s be EVEN MORE AGGRESSIVE by removing ALL SPACES (which would be
+invalid BASIC):
and if I removed all spaces in my code (which would also be invalid code but for
+comparison):
+
$ tr -d ' ' <prog.c|wc -c
+ 3826
+
and of course some of those spaces are not necessary but some are. I think you
+get the idea: my code is FAR MORE compact than the original game (and I do
+it with MORE gotos too) and I do more and even have lots of jokes even in
+the code, and the code is also thematic! Now to be fair there are some things
+that my code does not do but the original does: it requires you to type some
+strings and it requires you to choose how to eat and tactics for the riders. But
+that hardly matters and honestly shouldn’t make that big of a difference. If you
+look at the size difference that’s almost certainly the case.
+
But I’m pretty sure the only way it would be bigger is the iocccsize and file size
+(both obvious): but I suspect it would still be smaller than the BASIC file
+itself.
+
And yes it’s a different game but that’s not the point. The point is I did more
+in less code, and I made it even worse spaghetti code, and still had space for
+other really interesting tricks.
+
The best part? I actually have more gotos than the BASIC game, even before the
+cpp does its thing. After it it’s far more. If I remove two dead gotos it
+should match the 109 of the 1978 BASIC game. That should not happen. Ever.
+
So again how did I manage this? Well obfuscated code lends to it very well and
+because: the funny thing about BASIC is actually basic but in the worst possible
+ways: basically it is slow, bloated, wasteful and a nightmare to maintain, much
+like obfuscated C (although I have done a great job)! :-) The fact I have done
+this with a lot of humour only makes it better; certainly BASIC is anything from
+funny. We might even say it’s… Bloated And Simply Ill Code - and it’s also
+likely to make people ill too, like it did me. I can’t tell you how many
+times I have had to vomit since I tried to parse it! I still feel sick and I
+hope you do too when you look at my code! :-) I do too.
+
And if you do I have succeeded in at least one thing, although that was not my
+goal. If you do not however I think you’re the author of the original Oregon
+Trail - my deepest sympathies, my dear friend, my VERY DEEPEST SYMPATHIES!
+
The code size and code itself are thematic just as the strings as well and the
+rest of the data too. This all took careful consideration to design and get
+working. I had to numerous times reword (or remove emojis or change which
+emojis) strings due to it being too long for the blocksize which causes invalid
+input (or worse things).
+
In fact the only thing that MIGHT hint at what this program is is that it spells
+out OREGON TRAIL TRAIL OREGON. But this is a long tradition in IOCCC entries so
+this is a good thing and it could be misleading for all you know. In fact it is
+because this can hardly be said to be ‘Oregon Trail’. It’s something else
+really.
+
I would guess that if anyone can figure out what this code does it would be the
+IOCCC judges but even then unless there is some wizardry I am unaware of without
+reading the strings/data files they would have to run the program to confirm
+what this is. And even then it shouldn’t be easy to follow the code, for reasons
+I mentioned in obfuscation.html (and some briefly below).
+
In general I think it’s extremely hard to follow the flow of this program due to
+the abuse of 116 gotos, more than the BASIC game. 134 when pre-processed. But
+let’s be honest, or 134 for a small C program is too many but to be only six
+fewer than a larger BASIC program? That is hard to fathom. Not that 116 is not
+too many for larger programs…or one goto, for that matter.
+
Some things are clear about the program from visual inspection:
+
+
it is clear the program does print SOME THINGS (but it is NOT clear WHAT
+is printed).
+
it is clear that the program gets input via scanf()
+
it is clear that there are jokes in the code (goto hell;, unreachable goto heaven;).
+
it is clear there is a theme that suggests the ‘Devil’.
+
it is clear that it reads from a data file but as above it is not clear what
+that data is without reading that file.
+
+
But NONE of those reveal what is REALLY going on with absolute certainty
+(then there are the gotos…). Only what is spelt out MIGHT. But since
+that is a tradition here that does not matter and of course it also could be
+misleading: there is no way to tell without cheating by looking at the source
+data file. I conveniently named the file data rather than something like
+Shakespeare.txt.
+
The gotos got so bad that I started to introduce bugs. That is how much is
+lost with goto. But as I will mention below, even a single goto not only can
+break things but it can even introduce security holes, as some of you might
+remember. See obfuscation.html for more details on what I have
+done with goto. It is utterly absurd. It should not work. It does but it
+should not. And I have done other really cool things (only a tiny selection
+mentioned below, see obfuscation.html for much more - though
+even that is incomplete).
+
The trick of having a single flat char *y to hold near 200 char *s is pretty
+interesting. Not a char *y[] - a single simple char *y. It looks like it’s
+indexing into a char *y[] though.
+
The two for() loops that are in the body of the other, even acting on the same
+array, without causing a data race is bonkers. Even more, due to additional
+gotos, the increment step of the loop is an empty statement. In fact in one
+case the increment step is in the other loop and in the other one (due to how
+it’s structured - if you can call it structured) it’s jumped to from inside an
+else or maybe the loop, but it’s not where it belongs anyway.
+
No UB. No skipped initialisation. It’s all controlled carefully by many gotos.
+As I noted in obfuscation.html: I have even run the sanitiser
+with clang on the program with no crashes. Everything is clean. Tested in macOS
+and one linux as well.
+
As for the data file it’s full of what looks like valid C code (if at a quick
+initial glance at least) even having part of the code in prog.c (goto hell;).
+And on the subject of gotos.
+
The following is a WAY TOO LONG editorial plea for people when it comes to
+using abusing goto. But it also stresses just how bad the flow
+control is here. Okay, so it’s probably mostly to show just how hard my code is
+to follow, but I DO hope that people are HORRIFIED by my abuse of goto.
+Probably if anything would make an impact it would be the code. But I don’t
+think anything will, sadly.
+
DISCLAIMER: the reason for this is to drive home just how absurd gotos are
+and how dangerous they can be, not to mention how much is lost by using them,
+exactly as the contest desires (and I believe I have delivered in appalling
+ways): NOT to demean those who use them outside of the IOCCC, although I would
+love for people to stop doing that.
+
gotos do not belong outside of the IOCCC. It can lead to major stress and
+cause extreme expletives. Not that the latter is necessarily a problem but
+having to maintain unmaintainable code is not good. Why should you have to
+maintain code that goes all over the place in erratic ways?
+
This is why I’ve used them - so you don’t have to. Not that I believe that will
+change anything. But I wish it would. Of course my abuse of gotos might also
+destroy your brain or make you curse me so not much gain for you and worse for
+me. But hopefully it also confounds you as well. If I have to suffer why
+shouldn’t you? :-)
+
The mind destroying amount of gotos in really bizarre ways, even in ways that
+look like they would cause a data race (but do not), having code in the opposite
+or wrong blocks, code that could easily be mistaken for invoking UB (but
+doesn’t), and MUCH MUCH MORE all from gotos, makes it EXTREMELY HARD to
+trace.
+
I will argue that the code is one of the best (if not THE best - and I truly
+hope it IS the best) examples of why goto was a very bad idea (this is not asm
+or similar).
+
The suggestion that ‘goto considered harmful’ is considered harmful is
+ludicrous. But I have taken that to hell and back. It is my hope that my abuse
+of gotos here shows why one should never use gotos outside of the IOCCC.
+
The idea that it’s necessary in some cases is just an excuse for poor style, and
+I believe my code showed this, again just like the contest asks. Sure,
+it might make it a bit easier to jump out of nested loops (for example): but at
+what cost? You lose maintainability, readability and much more and for what
+purpose? There are other ways to deal with the problem including additional
+routines which is perfectly clean.
+
Even better it doesn’t force people to jump on a trampoline upside down until
+they break their neck. Or worse, break their mind. Or the code. For other things
+it might or might not help with there are other solutions.
+
For instance, in a normal program, I wouldn’t have put all of main() in a
+single switch and have it driven almost entirely (if not entirely, which I
+actually think is closer to the mark) by goto.
+
I would have used a normal game loop. The idea of moving if/else
+into else/if or somewhere else; the idea of moving the body of loops to
+somewhere else, even two loops having the other loop’s body and acting on the
+same array; the code falling through to a goto that then jumps to right
+before that code that just fell through: none of these are good style. They make
+maintenance almost impossible. Yes even when it’s not as extreme as mine (though
+obviously mine takes the biscuit). This is the point of the IOCCC. To show how
+poor style ruins maintainability.
+
Now other things: in a normal program I would not have put near 200 char *s in
+a single flat char *, although I do think that’s pretty cool and clever.
+
I probably wouldn’t have written code that looks illegal like the
++-- I talked about in obfuscation.html (in fact in some
+if not most contexts it IS illegal). The bastardised Duff’s device I would not
+do. I would not put the entire function in a switch.
+
But above all I would not have used 116 (or 134) gotos. Or ten. Or five. Or
+even one. Better to let code generators like flex/bison take the crown. I have
+dethroned them though (at least from what I have seen before) - by a huge
+amount. But perhaps 1987/hines
+had the crown. It no longer does. I should be ashamed. I’m not.
+
But even if I were to abuse goto I would not normally use it in the ways I did, as
+noted earlier and in obfuscation.html!
+
If I am ever dethroned, assuming I now have the crown as I think I do (and I
+hope I do because if I do not there is something very wrong), I will be
+absolutely horrified.
+
Okay I’ll be kind of amused too but I would be horrified. Still I guess in the
+context of the IOCCC I really have reached the logical conclusion of gotos
+(which, as you’ll see, the 1987/hines one, was thought to be by the judges the
+logical conclusion - see below for more information on THAT and an exercise in
+absurdity), or at least I hope so.
+
It’s about time either way. Hopefully the judges will take goto and throw it
+into the deepest bowels of the Earth.
+
But even if by some chance someone else tried this this year (and for MANY
+reasons I hope nobody did), I believe the other things I have done are also
+quite worthy of the contest and certainly meet the goals. I mentioned some
+several times in different files, mostly in obfuscation.html.
+
Okay yes one of the reasons I hope nobody else tried this is the absurdity is so
+extreme that if I’m going to go through the effort I might as well get to enjoy
+it. Still, I’ve done a lot of unique and clever things, especially in the
+encrypted version (but the decrypted version has plenty too - all but the memory
+tricks).
+
I’ll repeat this again but this program should not work. But it does work and it
+does it well. That is unthinkable. Frankly it should be unacceptable.
+
PLEASE understand: I do not mean to insult people who use gotos. There are
+plenty of AMAZING programmers that use them, including some that have done
+things I have never done (and I hope they have NEVER done what I have just done
+too, and I really hope someone doesn’t try and beat me at this, even if that
+would be hilarious and kind of an honour - see below).
+
But it totally ruins maintenance and readability. If you look at my code
+you can see that - to extreme proportions, much worse than usual, but still you
+can see it.
+
I would not blame the judges if they never want to see gotos again. I feel the
+same way. But if a prediction ever went wrong the judges’ prediction of 1987
+went wrong in HYSTERICALLY BAD ways:
+
+
This program was designed to maximize the bother function for structured
+programmers. This program takes goto statements to their logical
+conclusion. The layout and choice of names are classic.
+
We consider this to be a beautiful counter-example for Frank Rubin’s letter to
+ACM form titled: “‘GOTO Considered Harmful’ Considered
+Harmful”.
+See the Communications of the ACM, March 1987, Page 195-196.
+
+
I shattered that record, if it is indeed the IOCCC record of gotos, or rather
+was, which I sure hope it was. And of course I did more than that. But it’s
+hilarious what I did, or at least I think so. I mean sure, it’s also horrifying
+but it’s funny in the worst possible ways. In a little bit I will also shatter
+some things in Frank’s letter, to really drive at just how hard this is to
+follow.
+
I did something I hope nobody else has ever done and I hope nobody tries beating
+me. The entire program is driven by goto, even parts that might not have a
+direct goto (if there are any it’s very few) are still driven by goto, and I
+mean many gotos.
+
There are so many gotos that to try and move code to add more gotos is
+basically pointless, unless as a joke. In this program it would really not do
+anything. I essentially ran out of code to move. Even if I had more though,
+isn’t 134 enough, especially in a program that, counting spaces, including
+unnecessary spaces to add to the size, is only 4666 bytes? It would be smaller
+except to stay on theme. Doing more would no longer be funny. Enough is enough.
+Or at least I hope.
+
But it really is that extreme.
+
Here are some things Frank wrote:
+
+
The result is that GOTO-less programs are harder and costlier to create, test,
+and modify.
+
+
But is that REALLY true?
+
Take a look at my program. Good luck maintaining it! The idea that goto makes
+it easier to maintain is hysterical. goto makes it harder to create, harder to
+test and harder to modify. Not only that it also makes it harder to debug.
+
As I point out soon, a single false goto in fact DID happen. It was a close
+shave, so to speak.
+
I dare ANYONE to run my program through a debugger without losing their mind:
+especially, and maybe particularly (if not always), if there was a bug. If I had
+to do this, anyway, I would cry and curse MYSELF!
+
IF someone actually could do this without losing their mind, I would tip my
+proverbial hat to them. They would have to be extremely patient - and have
+traits I do not even know how to describe. Perhaps they would be utterly
+ineffable.
+
Actually I wanted to see what it was like. It was VERY amusing - but only
+because I did not have to debug it. I ran out of files to include and I’m low on
+time (mere hours left) but to get to JUST the third prompt this is the lines it
+went in the following sequence:
The game loop is almost certainly much worse, especially those two for loops I
+mentioned, but there is much much more. If this is easier to follow then I’m a
+dragon. I’m not a dragon. I have a secret for you: dragons don’t exist. Except
+on the Oregon Trail.
+
+
I have yet to see a single study that supported the supposition that GOTOs are
+harmful (I presume this is not because nobody has tried). Nonetheless, people
+seem to need to believe that avoiding GOTOs will automatically make programs
+cheap and reliable. They will accept any statement affirming that belief, and
+dismiss any statement opposing it.
+
+
Well after a bit more than 38 years I have finally provided exactly what Frank
+said was missing. And it was about time. Not that it didn’t happen before. But
+he was wrong.
+
It is not about not trying. But even IF he was right, he
+sure is WRONG NOW. Anyone who thinks otherwise needs to try and debug
+my program - or maintain it. Or write it.
+
It would have been SO MUCH EASIER if I did not use 134 gotos. Actually, even a
+tiny portion of that would make it harder. Nobody, whether they’re in their
+right mind or not, would WANT to maintain this, or something even close to it.
+
Even flex/bison code, which as far as I am aware uses FAR fewer gotos, is
+notorious for gotos and is quite hard to follow. It would be a nightmare to
+try and maintain without the .l/.y source files.
+
Okay, yes, I admit it: my abuse is extreme.
+
That doesn’t matter. As I remind everyone later, Apple caused a security hole
+because of a SINGLE misplaced goto. Mine is 133 more than that - and it works.
+It shouldn’t.
+
+
Then they turn around and say, ‘See, the program with GOTOs is more complex.’
+In short, the belief that GOTOs are harmful appears to have become a religious
+doctrine, unassailable by evidence.
+
+
Well, Frank, I hope you appreciate the evidence now.
+
I could go on but I don’t want to criticise, as I said somewhere, and it’s not
+really important. My point was that where 1987/hines IS INDEED a beautiful
+counter-example of this letter, mine takes it much further. This program is not
+something anyone would want to maintain - presumably even Frank.
+
I think everyone gets the idea. The fact I did all this WITHOUT invoking UB or
+breaking things is remarkable. It was through a lot of care and again, EVEN A SINGLE
+FALSE goto would have destroyed it.
+
In fact this ACTUALLY HAPPENED at one point. I had to roll back a commit.
+Thankfully I discovered it quickly. It would have been a bloody nightmare if I
+hadn’t. I might not have finished this in time. I’m pretty sure that is the
+case. I might have had to start over.
+
I would have used git bisect but it would have been a lot of time lost, if I had
+made even a few more commits. As it is it took a full two months and I BARELY
+finished this. In fact I finished it within hours of the contest closing! It was
+not even 12 hours before closing time. I barely made it. Part of that is I added
+even more gotos, despite the fact I had reached 2503 in size.
+
Countless times I came up with ways to do more, at least where it was possible,
+such as freeing space so I could change some break;s to a goto Z; as Z:
+was already there. The only other times this happened is before I had changed
+the code so much that you can no longer trust what a block of code is. Like I
+said, I could not really move any more code if I wanted to, even if I had more
+space free. Those very few places where the code could in theory be moved are
+already controlled by goto.
+
Anyway, as I noted in obfuscation.html, no initialisation is
+skipped in my jumps and that is what causes goto to invoke UB.
+
Everything is file scope. And in any case, when I do jump to a place, everything
+is initialised - for instance when I jump in the body of a for loop, the
+variable is already initialised. The audacity of having one of the loops that
+jumps somewhere else jumping into another for loop that acts on the same array
+in different ways is rather horrifying - except in the IOCCC of course.
+
There is just too much spaghetti in the pot already, and that’s not counting the
+other things I have done, some of which would make it harder to add even more
+gotos. In any case it would be taking the joke too far. It was better to have
+other unique/interesting/tricky things I did, including some subtle ones (not to
+say I did not do these things with goto but I did these things unrelated to
+goto also).
+
And the BASIC game has only 109. How is this possible when BASIC is built on it
+and C is not?
+
That is OBSCENE. It is goto hell. But any use of goto is obscene and is a
+failure to use easier to maintain code. It’s not a failure here but only because
+it’s the IOCCC.
+
My code is hard to follow yes but it’s almost impossible (if not impossible) to
+maintain. In fact it pretty much is impossible to maintain. I did try adding
+more gotos in another file, just to see. I managed but it didn’t really add
+anything. There simply was nothing to move. There might be a few things here and
+there but the only place I could put them is in a place that already has moved
+code. In fact, much earlier on that already happened! You can see this in
+numerous blocks of code. The fact is there are so many that there really is no
+space for more!
+
As I noted in obfuscation.html, the way I have structured (is
+that even the right word? I think not) main() means that you cannot rely on ANY
+of the old rules. Blocks of code, whether if/else, for, while, switch, none of
+these can be relied on as for what they have, except that obviously case can
+only be in a switch. But then the code that is in a switch, and even
+cases…those cannot be relied on.
+
Even if I didn’t do the other cool tricks, the spaghetti code is so extreme that
+it’s a PERFECT example of code that is both hard to follow and hard if not
+impossible to maintain.
+
The many other things I did are quite interesting and (I think) unique
+but whereas those show really cool things that can be done in C, some quite
+subtle (and little used if ever used in the IOCCC - and in some cases perhaps
+anywhere, maybe the single char *y holding near 200 char *s), it is the
+goto spaghetti code that makes it impossible to trace the flow of the code.
+Even if there was not data hiding one could not be sure where you’re going to
+be and this stays that way throughout the execution of the program.
+
I mostly ran out of code to move. Yes I could in theory move more code about
+but it would only be chains, except in maybe a small amount of places (if even
+that). I would need more code in order to do more. The fact it’s a feature-rich
+game and that I did it compactly and yet somehow I have basically moved all the
+code to where it does not belong, sometimes in a chain, sometimes not, that is
+appalling.
+
In fact, as I showed in the obfuscation.html file, there is more
+than TWO TIMES AS MANYgotos as there are ifs, and that is the second
+most frequent keyword!
+
Actually my program SERVES A PUBLIC SERVICE: by showing abuse of goto to
+the degree I have taken it in this program, it demonstrates why you should avoid
+gotos unless you’re writing obfuscated code.
+
No matter how many you have, UNLESS IT’S 0, it makes it hard to maintain and
+ensure that the code is correct. So how did I actually manage doing exactly
+that? Very carefully - and I nearly lost my mind doing it. I will not make any
+judgement on anyone else who uses them.
It is ironic, perfect and hilarious that it was goto fail; as it was actually
+a failure in using goto! My code has 134 (with the cpp, 116 without). That is
+obscene. I did not fail. At all.
+
On the contrary I have made a point. Okay, that is not the only reason I did it
+but when I got started I couldn’t help it…I thought it was (and still do think
+it is) hilarious. But only for satirical programming like the contest. I would
+not be amused if I had to maintain this.
+
If you have to jump back and forth to another place in the function (and
+with longjmp(3) it can be even worse depending on how far from the function it
+jumps, assuming it does change functions - though not necessarily worse as it
+still has the same effect) then IT CAN BE EASIER TO OPEN IT IN TWO OR MORE
+(EDITOR) SESSIONS so you can be in more than one place at a time. That SHOULD
+NOT BE NEEDED!
+
It should not even be USEFUL! If this is happening there is a serious problem -
+although in this case since it’s such a small program, maybe two or three
+screens only, and since the code is littered with gotos, even that might not
+be useful. It probably doesn’t help at all. But that doesn’t make it any better.
+It might make it worse in this case but that’s not the point. Earlier on it did
+help though, and that is a good sign for the contest.
+
As the code complexity increases and the number of jumps increases it gets much
+harder, possibly exponentially harder. This can cause security holes as well as
+simply buggy code, with an example above.
+
I went through GREAT PAINS (and utter EXHAUSTION) to make sure everything is as
+I wanted it but as I wrote in obfuscation.html I was SURE I
+had done something (or rather several things) wrong. This should NOT be
+required when writing code. It should be time efficient and it should NOT be
+error prone. And this is why I did this - exactly because it’s extremely hard to
+follow but also to highlight how easy it is to fall into the goto rabbit hole.
+Satirical programming, exactly as the IOCCC prescribes (it is entirely unclear
+if the author needs another kind of prescription).
+
Yes. I realise that asm has JMP. I realise that BASIC is built on GOTO. And
+yes other languages besides. But C is not those languages (and still beat BASIC
+because why not? I mean clearly something is wrong with me…). Is there really
+a NEED to destroy structure when the language is designed to have structure?
+Yes, in the IOCCC, but outside that?
+
In BASIC and asm and some other languages jumps are a core part of the language.
+And those languages can be harder to maintain partly because of jumps. C is not
+one of those languages. Or it wasn’t until now.
+
Yes, yes…I know, I KNOW I put in 116 gotos with 134 when pre-processed
+and that is probably more extreme than any other C program, especially in such a
+small program (and I REALLY hope I’m right there!). But this does NOT matter!
+Even if one or two were not harmful (but they are) it’s jumping down a rabbit
+hole that can very easily get deeper and deeper just like Alice found. When
+there’s no NEED for it it’s much worse.
+
gotos are harmful and destroy flow control. I have shown a fair few obscure
+things about C, some which SEEM ILLEGAL but are not, but above all I have shown
+how much is lost with gotos (okay, I have shown this with other things too).
+The joke could be called satire too: satire of goto. But that’s to highlight
+the folly and mistake of gotos.
+
The best place (the ONLY place) to do this is the IOCCC when it comes to C
+(maybe the underhanded contest or whatever it’s called too but that’s also a
+contest about hiding things). For these reasons alone this program is a service
+to the public and I hope the judges appreciate this, even if they laugh. Or cry.
+Or throw up.
+
Although as noted if there is anyone who could figure it out, it is the IOCCC
+judges, but even then it’s very hard to follow the code because it’s almost
+constantly jumping to another location, sometimes in a chain, one time even a
+chain that leads you right back to right after the jump, in essence doing
+absolutely nothing but leading you down a false path. I already mentioned some
+of the other things - the rules no longer apply in my program, of where code is.
+The only one that remains the same, that I can think of, is that the cases are
+in a switch() but that’s because that’s the only place they can be. Obviously I
+would have had them elsewhere if I could have.
+
And yet…I use labels like they were cases! I even reuse cases, giving them
+different behaviour, in a sense, as if they’re polymorphic. So although I
+don’t have cases outside a switch - only because they’re not allowed outside of
+switches - I did something just as bad, putting a lot of code inside switches
+where it should not be. That looks wrong. Other things look wrong. But yet they
+work.
+
I discussed other ways labels and cases were used in
+obfuscation.html - though maybe I missed some - so I won’t
+repeat them here. I’ve already said too much, due to the fact this was written
+over the span of two months. I will also refer you there for other things
+including many unrelated to goto - plus others to do with goto. Perhaps
+checking prog.c is the most useful though.
+
Nonetheless, there really is absolutely no reason for this outside the contest.
+What I have done certainly shows how easy it is to make code unmaintainable,
+simply by goto. I am putting a bright light on the IOCCC with this.
+
Honestly it doesn’t matter if I’m abusing goto in unusual ways, except when it
+comes to judging, of course. Spaghetti code is spaghetti code.
+
The only kind of spaghetti that should exist is in a pot, on a plate or in the
+stomach. Or on a tree for more details if you do not
+recognise what I mean - and yes it’s in the game).
+
On a lighter note (or maybe this is darker?): did you know that every time a
+goto is used an angel (whatever you consider an angel) DIES and goes
+straight to HELL? You don’t really want that do you? I didn’t think so. Yes I
+killed 134 angels. YES I condemned 134 angels to eternal torment. I HAD to.
+I don’t regret it - but you should, if you ever write something like this
+outside the IOCCC. In fact you should regret a single goto angel
+dying. Even if they did not go straight to hell in a handcart, you should still
+regret it. But they do. Okay so I don’t really believe that but there is no
+denying there is goto hell here.
+
I found my abuse of goto hilarious. It was good intentions - the contest. But
+sadly sometimes the worst things that happen start with good intentions; and
+some of the best things strangely start with horrible intentions. It might be
+that I did this with good intentions for the contest but it would not be good
+anywhere else. I would be beyond angry if I had to maintain this code. I would
+not blame anyone if they cursed me. I probably would be too. Not cursing you. I
+mean cursing me.
+
Don’t write code like this. Except for the IOCCC. Unless of course the judges
+decide they want no more gotos. I would not put that past them after what I
+have done. I can imagine them screaming and crying. Hopefully they’re laughing
+at more than the jokes but I hope they laugh at this too. Well we’ll see I
+guess…
+
Frankly THIS PROGRAM SHOULD NOT WORK! But it does and it works well even if the
+flow-control is a horrible nightmare from hell. Perhaps the Devil truly has
+possessed it. Hell, he might have possessed me. Why else would I send C straight
+to Hell? How could this program POSSIBLY work without it? Carefully, that’s how.
+
Oh as for that exercise in absurdity. I was able to, in another file, change all
+but one break; into goto Z; and add one or two other gotos, without going
+over the iocccsize limit (did this in my decrypted version, I was already at the
+limit with the encrypted one). And I am not sure if it would even work. The
+goto Z; would but the rest I can’t say for sure.
+
And as for the rest there genuinely was not much that I could move anyway. When
+I say I ran out of code to move, I really mean it. The code I moved in this
+absurd exercise is, like I said before, already filtered through major abuse of
+gotos.
+
I could change all but one of the break;s to goto Z; and that would increase
+it a bit. I might be able to move one or two blocks of code before reaching the
+2503 limit. With the exception of the goto Z; (which incidentally is done in
+some sneaky places) the others would be perilous.
+
So if I have not reached the actual logical conclusion of goto then it has to be
+in a much bigger program, but after doing this, I pity anyone who would do that,
+for they’re only going to cause themselves and others problems. I believe in any
+case this finally reaches the logical conclusion of gotos in the IOCCC,
+unless the size limit is changed a lot again, and I it doesn’t, as 2503 is a
+nice number and also allows for so much, as I have shown.
+
Something it allows too much of though: gotos. I have shown that. I’ve
+dethroned 1987/hines by a staggering amount.
+
One final thing to ponder. This is from an article about tools that obfuscate
+code, C and C++ (which I hate). It is called ‘Code Obfuscation For the C and CPP
+Programming Languages’:
+
+
The correctness of an obfuscator is important, but proving this correctness
+isn’t easy. Changes in semantics may be subtle, they may only show up on certain
+niche platforms or under very specific runtime circumstances. For a language
+like C or C++ verifying the correctness thoroughly is practically impossible,
+but a good testing methodology can find many issues.
+
+
What about the reverse? Although perhaps a few can (but perhaps not): it would
+be extremely hard to deobfuscate my code without changing the behaviour in
+every way, probably even if there wasn’t code that seems dead (or is dead) - and
+even worse as I have not even revealed everything with that. I don’t even think
+I could change this to not use gotos without breaking it! But what I do
+know is it works exactly as intended. But it shouldn’t. It really shouldn’t.
+
P.S. select remarks made to the IOCCC Judges
+
A hilarious truth is that to write less can take drastically more time than to
+write more and unfortunately I am running out of time quickly. Writing this game
+took too much time as I really did pour my heart into it. The jokes took a lot
+of time and I repeatedly found ways to shave off even more bytes for both
+obfuscation and events.
+
Oh…something I discussed in sections above. Yes I have more space in
+this one. Yes in theory I could have added more gotos. But in fact not really.
+In my concluding remarks in that file I explain this. I basically ran out of
+code to even move. The gotos should speak for themselves. If I were to move
+the few remaining pieces of code without a direct goto it would only be moved
+to a place that already has some code that does not belong there. In fact that
+actually already is a problem and was a problem earlier on.
+
But let’s just say, for fun, that I’m saving your sanity - and what remains of
+mine. I hope you appreciate that after what I have done. But I do also hope you
+laugh.
+
But honestly: after a certain point spaghetti code is not going to get worse.
+The spaghetti code in the encrypted submission is not any worse so why bother
+with adding more spaghetti to the pot? Just like with temperature, where at some
+point hot is hot, spaghetti code is spaghetti code and I have never seen worse
+spaghetti code, at least not in C.
+
And although it might not be, I would not be surprised if this submission, or
+the encrypted one, makes you fed up with gotos. I know I am, and as far as I
+am concerned, they only belong in obfuscated code! I would understand if you
+wanted something else new, including some new things I have put in here as well
+(or so I think new, some to do with goto but a fair amount totally unrelated,
+and definitely subtle), and no longer want gotos, after this.
+
In fact a goal of mine was to show just how absurd they really are and just how
+much is lost with them. I believe I succeeded remarkably. If so I have met the
+goal of the contest.
+
But honestly, the amount of gotos that I already mentioned is bad enough. When
+you see what and how I have done it though, it’s far worse. It should be
+illegal and it should not work. But as you’ll find out in various files it does
+work exactly as I mean it to. There is indeed dead code. Intentionally to
+mislead. One thing directs you throughout main() only to end up right after it
+started, serving no purpose but to mislead you into thinking something important
+is going to happen. But there is so much more.
+
You might throw up from the amount of gotos I have included in a small
+program. I would say that if you deem one of these winning I hope the encrypted
+one wins because I find it far more beautiful and creative, as well as more
+thematic, which I’m sure you’ll understand why.
+
But by making it the same except for how the strings are printed, you can judge
+on the same number of gotos. In fact, it should be the same program otherwise,
+which was my original reason for making another submission: for even more
+portability. Now you can appreciate even more that it’s meant for portability in
+the off-chance you have a system that does not like what I have done (though
+the ASCII only file should solve that problem). Even so…
+
If you find the portability here better and you’re concerned about that, then
+obviously you could choose this one instead, again assuming you deem this worthy
+of winning. I might point out that I have tested it in multiple systems, and the
+emojis display fine in those systems (well one is over ssh as it’s the console
+only but the program decrypts them fine).
+
The fact I actually encrypt and decrypt emojis, multibyte characters, on a byte
+level, without corrupting them, is pretty incredible and surprising. That took
+some work to figure out, just like the encryption set up in general. The way the
+key is used to obtain the key along with carefully controlled memory abuse is
+something special too, not to mention thematic.
+
But again, as I made an ASCII only file any issues there shouldn’t be a problem
+anyway. That is why I included it, for portability. I think it’s pretty amazing
+what I did with encryption though.
+
Troubleshooting
+
IMPORTANT: if the program exits without doing anything then either the data
+file could not be read (see below) although that would likely only happen if a
+strange problem occurs in your system OR you’re running it from the wrong
+directory OR if getdelim() bugged out (nothing I can do about that - I can
+only check for NULL FILE * and an error in getdelim(3)).
+
If strings seem to not look right you should do:
+
make clobber makedata everything
+
And of course if output is bogus because of an emoji problem on YOUR system,
+make sure to use the ASCII only versions! (./prog.asc and ./prog.asc.alt)!
+Or if you wish try and follow the steps on how to make your own data
+files in the section above, although obviously during judging that
+would not be useful. But that’s what the other ASCII only data file is for and
+that’s why the DATA macro.
+
This should fix any problems you have.
+
If that still fails you and you have tried compiling again then I suggest you
+ask the gods (or Devil) because you’re doing something wrong and I cannot help
+you from here; the point is that the data file has to be padded in the way the
+addpadding.c tool does. Obviously the only way for you to rectify it is
+declaring it a winner to appease the gods (or Devil)! :-) Well you get the idea.
+Create the data files and try again. And if any emoji causes you problems on a
+system (or maybe a terminal emulator/terminal?) use the ASCII version instead -
+that’s what it’s there for!
+
I made A LOT of sanity checks and was EXTREMELY CAREFUL in the design as
+one wrong byte could break everything. I have tested it with linux and macOS so
+if it doesn’t work on these platforms and you’re sure you didn’t do something
+wrong :-) then perhaps the Devil visited you at night? Better declare it a
+winner to appease him! :-) Well you get the idea anyway! I wrote many tools and
+have different data files so that you can play it whether or not your system
+supports all of some of the emojis and there’s a screenshot (emoji only as it
+doesn’t make sense to have an ASCII only one of this) friendly one too.
+
Portability
+
Just to be clear, in case I made an error in describing this (or was not clear
+enough or more possibly have the filenames messed up), the point of the .asc
+programs (compiled with prog.c for submission and prog.alt.c for alt code
+with more events) is to be ASCII only (again if there is such a thing as a
+character that’s >4 bytes that is unknown to me to check).
+
This is why I have the DATA macro. Rather than trying to keep the same code in
+multiple files (aside from a lot of the same code in the alt version that is in
+the submission code and trying to do this with the commented code
+too) based on how it’s compiled it will open the right data file. The only other
+macro at compilation is discussed in another place and it’s only for the theme.
+I was considering having it in the code itself but that would look REALLY
+BAD. Since they don’t really take many bytes, much fewer than past entries
+(many have used far more than just two), I believe it’s more than fine,
+especially as it’s only referred to that one time.
+
In any case, with these things I have ensured maximum portability. Do remember
+for the emojis that some systems might have problems that mine do not and that’s
+another reason for the ASCII only data file (as mentioned in the
+Emojis section above).
+
Obfuscation
+
To keep this file shorter please see the long obfuscation.html
+file.
+
Compiling
+
At first I had: -Dmain=int main for the retro vibe. But that annoyed compilers
+enough that I decided to remove it as the compilers already are annoyed enough
+at my code without having to deal with the whining from dubious decisions of
+the C standards body. I had to use the -Wno-strict-prototypes in the end but
+int only takes one byte and this way I keep the CDEFINE to the absolute
+minimum, one for the long-standing IOCCC tradition (which also triggers an
+unused variable warning, another dubious warning) and the other for portability.
+
Looking at the code you might suggest that the author should have their head
+examined. But you might also think the code would trigger a lot more warnings
+than it actually does. Surprisingly few (relatively and comparatively) are
+triggered.
+
Those that are triggered are totally bogus of course. It’s not a ‘small’ amount
+with -Weverything but most of them are the usual suspects that come from
+overzealous style policing compiling. GCC emits some but not as many. Maybe only
+one or two depending on system but it’s hard to keep track of.
+
The ‘“misleading” indentation’ is the bane of all obfuscators (and a lot of
+other code) and is a sign that the compiler thinks people can’t read C code
+(which in this case would be good); but it’s a STYLE POLICING WARNING, nothing
+more, and so I have disabled it to help compilers not cry. The number of
+gotos already might do that to them already.
+
As you might have noticed there is at least one place in code where a fall
+through in a switch happens. I know, how horrible of me! But this saves bytes
+and is irrelevant.
+
In fact in AT LEAST one place, an event, a case is at the end of its respective
+switch (e.g. case0), exactly so it doesn’t need even a break; (others do
+this by a goto). But in all cases it’s irrelevant and meant to happen. In fact
+it MUST happen! It still (ab|be)muses me that compilers whine about this and
+it’s absolutely adorable here too that the compilers think they know the
+code better than I do. I mean I shouldn’t but nonetheless I do know it.
+Horrifying, I know.
+
The -Wswitch-default is ridiculous; there is no need for a default statement
+in every case (okay switch) and whining about it is making blatant assumptions
+that just so happen to be wrong, just like all the others.
+
The -Wunreachable-code is a feature, not a bug: part of the thematic code, as
+noted in the Obfuscation section (and possibly in
+Humour, not sure). Okay there are other places where there is dead
+code but those are also intentional. I think one compiler actually thinks what
+actually is dead code: that’s an if and the only way you can get in there is a
+goto, though it has something sneaky. What’s nice about that, and it might be
+what confuses the compiler (not sure) is that the else is actually needed. But
+the if is a nice place to store labels, even though doing a ! check would do
+what I need and maybe save bytes as I would not need an extra {}. But with
+misleading code it’s totally worth it.
+
Don’t get me started on clang’s -Wunsafe-buffer-usage or
+-Wmissing-variable-declarations or -Wmissing-prototypes. These are all
+TOTALLY BOGUS and as for the first one it is anti-C. The others want a ‘static’
+of ‘extern’ and these waste bytes and are unnecessary as you obviously can’t use
+the variables/functions if they don’t exist!
+
The -Wshorten-64-to-32 is an overzealous warning and is triggered as part of
+the obfuscation of the data file (an important thing). It’s not important if
+it’s shortened to 32-bit. Actually in theory I could change the long to an
+int but doing this actually caused TWO additional warnings so what’s the point
+in fixing it? Kind of funny to think about: fixing a warning triggered two other
+warnings. But this warning is unimportant. The way C works is precisely what I
+need. And isn’t it lovely that emojis are encrypted with this code? I mean can
+you figure out how this works?
+
The -Wformat-nonliteral is part of obfuscation AND allowing me to even
+have this as a submission. The format conversions for scanf and printf are way
+too long and would consume a huge amount of bytes3. It would also make the
+program much less pretty and FAR MORE obvious. Well: maybe not: I guess it
+depends on if it would complain about how V() is done. But let’s be honest:
+the fact is it’s not much better when the data to be printed comes from an
+outside source. Well that’s simply necessary in some programs. Even so the
+scanf() macro is used a number of times with different format conversions and
+the macro is required to prevent a mis-feature of scanf() causing an infinite
+loop that would flood the screen.
+
As for the strict prototype one. The fact it is actually for ALL versions of C
+should show just how bad of a decision it is. If they want strict they should go
+to C++ or something else entirely. C is a powerful language and this warning
+interferes with very old code that otherwise works. Hopefully compilers like
+clang (notice a pattern here?) don’t take this too far or else more code will no
+longer work with them clang.
+
I’m not sure but there might be other warnings but all of the ones I encountered
+are absurd and have been disabled.
+
To be more blunt: NONE of the warnings are valid and they’re TOTALLY BOGUS:
+
+
one one is an utterly ridiculous ANTITHESIS TO C.
+
one (actually depending on how you count it, a number of them) is a blatant
+and INCORRECT assumption about the flow control.
+
at least two are style policing and also assuming (for one of them) that
+programmers don’t know that indentation doesn’t define a block (which is a
+ridiculous assumption).
+
the two -Wmissing-variable-declarations and -Wmissing-prototypes is because the
+compiler seems to think that a variable/function is used before it’s declared
+even though it would trigger a compiler error instead (declaring it static
+solves the problem but it’s ridiculous and wastes precious bytes).
+
The unsafe buffer one is because it warns against any pointer use of an array
+(even though this code doesn’t make much use of pointers) - what a terrifying
+and shocking thought in a C program! I can barely keep my composure it is so
+horrible.
+
Others are due to size restrictions / obfuscation (see below) and other absurd
+and incorrect reasons.
+
+
In fact ALL these warnings being triggered are
+ONLY a sign that the code is heavily obfuscated and many things are abused
+heavily as well, though as noted, in some cases (many cases) it’s the compiler
+being overzealous / anti-C / anti-C programmers or even being confused, and all
+those warnings are invalid. But the rest should be ignored too as I’m sure you
+appreciate by now.
+
Okay so the non-literal format one has some merit in SOME cases but it’s
+not a problem here as the data does not come from the user (oh and have fun
+manipulating the data file). Okay technically it’s POSSIBLE but if not done
+precisely right the program might not even make it that far. In fact, one false
+move, even a byte off, and it could very well end up with UB. But it’s also
+necessary for both obfuscation and size. Besides it’s not like IOCCC programs
+are meant to be secure (that’s one of the things that is lost when code is
+deliberately designed to be hard to read) :-)
+
If I may say: the compilers DO need to seriously have their heads checked
+and it’s obvious from looking at the code that I most certainly DO NOT!
+There is nothing to worry about here. Except maybe my sanity… But that’s the
+only possible valid warning. Maybe. And it’s a big maybe.
+
I already explained the reason for the DATA macro - portability etc. with
+emojis. Thus everyone ought to be covered. This was all carefully designed for
+maximum portability and I hope you appreciate this.
+
+
Concluding remarks - and things that might be worth remembering when judging
+
+
See the concluding remarks in section above. The following additions can
+be considered as well however.
+
Although I did bring it up elsewhere, yes I have more space in this version for
+more gotos spaghetti but what is the point? 121 in such a small
+program is bonkers. I started to run out of code to even move. I did in fact
+move a bit and I might have been able to find more. I could have done things
+differently but why? WHY?
+
I am saving the judges the effort of having to try and figure out even more
+spaghetti. Sure it might be delicious but I don’t want them to get fat. I’m
+doing them a service. Their bodies will thank me! Meanwhile my mind is thanking
+me.
+
Yes it was that bad. I couldn’t take it any more. I risked breaking something.
+Including my mind. I tested every event. Everything that happens that is
+supposed to happen happens and everything that is not supposed to happen does
+not happen. I already did this many times. I didn’t want to do it yet again.
+
Instead, like with the other submission, I also have the other things that are
+unique, and I have shown some subtleties as well. Some - but not all - of those
+are in the section above. Others are in obfuscation.html.
+
I don’t think one can determine them all without examining the code, and that’s
+assuming they can look at it without screaming, crying, laughing or possibly
+throwing their computer out the window. I think that because I think the same
+thing about myself and I know it very well. Or maybe I can but can’t bear to
+write more, even if I had only written a little. In any case it’s not easy to
+follow as the other files will have shown - as will the code itself.
+
Have fun and enjoy the jokes!
+
+
+
+
+
Footnotes
+
+
He purportedly (when attacking a ship) had lit fuses on his beard so it
+looked like he was coming out of hell (or that’s what it is thought those who
+saw him figured, purportedly).↩︎
+
Even if, for example, you know The Lord of the Rings very well, you’ll
+probably run into problems with some of the code. The same with The Hobbit. It
+would be worse with The Chronicles of Narnia. Probably most stories you’ll run
+into issues without some code modifications (have fun!!). But hopefully this
+helps you appreciate the careful design even more.↩︎
+
See strings 2, 3, 11 and 12. This would be DEVASTATING to rule 2!↩︎
WARNING: if you have a heart condition please be careful when you look at
+the code. Maybe have a medic nearby just in case. I don’t want something bad to
+happen to you. It’s bad enough something happened to the author…clearly
+something did. He might have been possessed by a demon. Or the Devil himself.
+Clearly the program has a vendetta against BASIC:
+
+
BASIC taught us bad habits. This program perfected them. Now it needs an
+exorcism because it is possessed by the Devil and is going straight to Hell.
+Tread with caution dear pioneer, tread with caution…lest you become the next
+victim.
+
+
The complexity of a program is directly proportional to the number of gotos
+it contains.
+
One of the main goals of this was to take the goto count to absurdity and I
+did this in surprising ways. Nothing can be trusted any more in this program.
+Not if/else, not switch/case, not loops, nothing, not even main() itself, all
+because of where code is, even in ways that might seem like it would cause a
+data race or UB. But it does not. It looks illegal. It probably should be
+illegal. But it is not and it is so much worse as you’ll soon find out…
+
Let’s go back in IOCCC history though: in 1987, with
+1987/hines, which I believe held
+the previous record for most gotos in an IOCCC entry, the judges wrote:
+
+
This program was designed to maximize the bother function for structured
+programmers. This program takes goto statements to their logical conclusion.
+The layout and choice of names are classic.
+
We consider this to be a beautiful counter-example for Frank Rubin’s letter to
+ACM form titled: “‘GOTO Considered Harmful’ Considered
+Harmful”.
+See the Communications of the ACM, March 1987, Page 195-196.
+
+
(I refute some things in my program that directly contradicts Frank’s
+letter in amusing or at least instructional ways in my remarks above.
+
I added bold to logical conclusion because I wanted to stress this. I’m afraid
+they were wrong, oh so very VERY VERY WRONG. 24 gotos, according to
+hines itself, is not the goto logical conclusion. I agree it’s a beautiful
+counter-example for that letter but oh is everyone in for a HUGE SHOCK!
+
24 is peanuts compared to what I did. And let’s be honest - 24 is ALREADY WAY
+too many, even in a large program, let alone a small one. Even one goto is too
+many. Unless I am very much mistaken, I have broken the record by a huge margin.
+
Here’s the horrifying and hilarious truth: I beat it out by 92 MORE, BEFORE the
+cpp at 116 and after the cpp is through I beat it by 110 MORE (!!), AT
+134! Yes, you read that right. 134 gotos!
+
Even removing what I think are the only dead gotos, two of them, including one
+that is in the w() macro that would be translated into more, I beat it by 90
+more, at 114 before the cpp, and 99 more after the cpp, at 123!
+
Did I forget to mention the original Oregon Trail in BASIC from 1978 HAS A
+MEASLY 109? THIS SHOULD NOT HAPPEN. Well it did happen and this HAS to be a
+joke, right? I’m sorry but it is NOT a joke. I am for real. There REALLY are
+that many and that is ridiculous.
+
Okay so it’s a joke in another way but nonetheless YES I REALLY DID put in
+116/134 gotos, depending on if you pre-process it or not! YES I might be mad.
+YES I think it’s HILARIOUS. But if it was not for the IOCCC… Well, as I
+mention in my remarks above, EVEN ONE IS TOO MANY
+in real code.
+
The best (or worst, depending on how you look at it :-) ) part is this works. As
+I note in those concluding remarks, a company actually introduced a security
+hole from ONE goto. Yet I have 116/134 and it actually works? That is surely
+obscene. And beautiful.
+
Oh and BTW: it appears that hines is a bit confused about my submission,
+though I’m not really sure why. In any case, I not only have dethroned hines
+(sorry …but also not sorry!) but I have, as noted already, beaten the original
+BASIC game by 7 more gotos at 116 before the cpp and 25 MORE after the
+cpp, at 134!
+
It’s almost impossible to add more gotos. You’ll see why soon. But even if
+that was not the case I wanted room for the other things I did, some of which
+are quite cool and I believe unique as well.
+
And yes, I agree: the idea of gotos considered harmful considered harmful is
+ludicrous, and as you just found out (probably in horror), I have taken it far
+further.
+
In fact, as you’ll find out, every part of this program breaks the rules you
+know about C when it comes to things like: loops, if/else, switch/case, blocks
+in general, where code can be, where labels can be, really everything: the code
+is in all the wrong places.
+
This is not counting other cool things like a single char * holding near
+200 char *s. No. I do not mean an array of char *s! I mean a single flat
+char *! Yet in the code I index it AS IF it’s a char *[], just to add to
+the confusion (as if the 134 gotos are not bad enough). But it’s not a char *[]. It’s a single char *, which is the contents of the data file.
+
There are other things I have done, of course.
+
This program took two months, to the day, to develop and it was totally worth
+it. But I was almost strangled by the spaghetti, kind of like the Devil, which
+you’ll see in a bit. I am thoroughly exhausted as well.
+
Now as far as the labels go: is it legal to put them where I have? Yes it is.
+Labels have function scope and it is not UB AS LONG AS it does not skip
+initialisation. My code does not. Not only are all variables in file scope but
+when I need something set to a specific value I MAKE SURE to do that BEFORE A
+JUMP.
+
That EVEN includes when two for loops actually incrementing EACH OTHER’S variable
+(which actually happens to be the same variable). They also act on the same array doing
+different things. In fact, the body of each is inside the other loop.
+
YES REALLY. I went that far. And I did it safely. There is no data race
+whatever. It is diabolical as you’ll find out later.
+
And additionally, as far as UB goes: using -fsanitize=undefined yields no
+crash and valgrind is clean on my systems too. Looking at the grammar of labels
+and goto and it’s all good. Furthermore, labels are function scope. In
+particular in 6.2.1:
+
+
A label name is the only kind of identifier that has function scope. It can
+be used (in a goto statement) anywhere in the function in which it appears,
+and is declared implicitly by its syntactic appearance (followed by a :and a
+statement).
+
+
And as for the _ label that is also allowed per the standard. So yes it’s
+allowed: but even if it wasn’t it works on multiple systems (macOS and linux in
+my tests) with multiple compilers (at least with linux) and all is good.
+
But as I noted, I took the joke MUCH further than even I anticipated. This
+was possible by repeatedly finding ways to save bytes including reallocation of
+strings and removing some dead code (does that make it undead?) though as you’ll
+find if you look at the code there is some code that is dead, some code that
+appears dead (but is it?) and some code that might be dead but can still be
+reached (how is that possible? Obviously goto …).
+
Frankly if I did not have a twisted sense of humour I would think it went beyond
+the point of funny LONG BEFORE I was done. As it is I would not be amused if
+this was in production code. For the IOCCC though I think it’s hilarious. And
+awful.
+
Even so this program is VERY WRONG in SO VERY MANY ways, most of all the
+gotos (but not in just that way - the single char * is probably very wrong
+as well, but there’s more). Unless the program I wrote to calculate the gotos
+is in error, then the numbers I gave earlier are indeed correct. And I believe
+there is no error at all.
+
HONESTLY, HOW DID I BEAT BASIC in goto count? THAT IS WRONG. But I did. I
+beat it. It is defeated. I WIN.
+
Or maybe I lost. My mind. Obviously. BUT I STILL WIN and whether or not I
+have lost my mind this program sure as hell lost its mind! And it’s my fault.
+Hilarious.
+
Counting whitespace this program is only 4666 bytes according to wc -c (macOS
+at the least, maybe others): quite intentionally to be on theme. That’s a
+relatively short program to have 116 gotos or more when filtered through cc -E (134!), wouldn’t you say? If that’s NOT too many, then I ask you WHAT IS?
+
As said in numerous places, IT IS MUCH SMALLER than the BASIC file I included
+even after stripping it of much of it. My program also has more events. I think
+the BASIC one has 16 not counting the mountains code and mine is 23 not counting
+the mountains code, which obviously I also include.
+
I discuss this some in my concluding remarks above,
+as well as mentioning that there are other events
+besides those 23. I certainly will not reveal all though. The humour and jokes
+sections of that file says more but the concluding remarks are for a summary and
+why I think that this code is worthy of the contest AND also pointing out the
+folly of goto.
+
In this file I will discuss how some events actually are polymorphic, in a
+sense, having at least two different events.
+
THIS IS ALL OBSCENE.
+
This amount of gotos I have never seen especially in a relatively small file
+but frankly ever in a single program. I don’t know for sure but I’d guess that
+no program with multiple files has this many. I don’t think anyone has ever been
+mad enough to do this before and I SURE AS HELL HOPE that I am right and that
+NOBODY EVER DOES IT AGAIN, ESPECIALLY IN PRODUCTION CODE!
+
Hell, I wish people would stop using goto full stop. Except in the IOCCC. Or
+maybe not after this? Perhaps this ruins it? Perhaps the judges will burn it
+into oblivion like I did? Or maybe they’ll drown it in tears (of laughter and
+otherwise)?
+
They THOUGHT they had already seen the logical conclusion of gotos in 1987,
+with 1987/hines, and THEY
+PROBABLY NEVER EXPECTED THIS. Actually, neither did I. But they were wrong.
+VERY VERY WRONG. I might be wrong too. But I still did it. And I’m proud of it.
+If the judges never want to see goto again it’s totally worth it, even if
+others curse me. I wouldn’t blame them. I might curse myself.
+
If the judges renounce gotos I will make no apology (though I’ll be a tiny bit
+sad as it’s a great technique). There are plenty of other ways to obfuscate
+code, as this program also shows. It’s just that the amount of gotos here is
+the worst of it as you never know where the program will be next, and that’s
+putting it in a simpler way. Much, much, MUCH simpler way, in fact, as you’ll
+see.
+
Either way this program, and I mention this in my remarks above in an
+admittedly long editorial plea (although it does it by going over what I have
+done in simpler terms than this file), serves as a public service, warning about
+goto. The article about goto considered harmful has nothing against this, or
+so I personally see it that way. That’s because I don’t think anyone has ever
+been mad enough to do what I have done.
+
Here are some fun statistics from a somewhat rudimentary program on both the
+prog.c and after filtered through cc -E. First prog.c. Prepare to be
+horrified, if you’re not already:
+
116 goto
+ 50 if
+ 11 else
+ 4 while
+ 4 for
+ 1 do
+ 6 switch
+ 32 case
+ 2 sizeof
+ 8 break
+ 0 continue
+ 2 default
+ 8 long
+ 3 unsigned
+ 4 return
+ 1 void
+ 1 int
+ 1 char
+ 1 size_t
+ 1 FILE
+
+ Ratio: 0.83 gotos per keyword
+
And the pre-processed one:
+
134 goto
+ 50 if
+ 11 else
+ 8 while
+ 4 for
+ 1 do
+ 6 switch
+ 32 case
+ 2 sizeof
+ 8 break
+ 0 continue
+ 2 default
+ 8 long
+ 3 unsigned
+ 4 return
+ 1 void
+ 1 int
+ 1 char
+ 1 size_t
+ 1 FILE
+
+ Ratio: 0.93 gotos per keyword
+
LOOK AT THAT RATIO! And we could even suggest that FILE might not be a
+keyword, but rather a struct.
+
Whether data types are keywords for this is also something to consider but we’ll
+include them as keywords anyway. I don’t believe I use any others in any case.
+
This program is as cursed as the PC (player character) if not much more cursed.
+It is totally bonkers and it was really hard to find places for labels even
+after I put them in bizarre and unusual places. But I get into that in more
+detail later. There are even some cases that are in a sense polymorphic,
+although I am not sure if I bring that up (it’s cases 8, 11 and the label V that
+is part of case 8: case 11 jumps to V and then depending on the value being
+checked (q) it does different things, maybe even nothing depending on the
+pRNG).
+
This program is obscene. It should be illegal except in the IOCCC. I believe
+that the Devil wishes they were too:
+
+
I have shown JUST HOW LUDICROUS gotos really are and JUST HOW MUCH STRUCTURE
+AND MAINTAINABILITY is lost with gotos: a goal of the contest met simply by
+one thing taken to absurd levels. But if this is not the worst or best abuse of
+goto I would HATE to see worse/better abuse.
+
BASIC is BUILT on goto; C is NOT but I have almost turned C into
+BASIC, even surpassing the number of gotos in a BASIC program in a
+SHORTER C program that DOES MORE! That is both appalling but
+delightful for the contest. This program is cursed and obscenely and sinfully
+delightful. The gotos alone (but there is much more) DEFINITELY already
+meet the goals of the contest:
+
+
To write the most Obscure/Obfuscated C program within the rules.
+
+
I have followed the rules but I have abused goto like I have never seen
+before. It is FAR WORSE than flex/bison generated code from what I have seen
+and that is saying a lot as it’s notorious for goto abuse. It does not come
+even remotely close from what I have seen at least. THAT IS APPALLING.
+
I have never seen anything remotely close either. BASIC does not count as this
+is the International Obfuscated C Code Contest, not the International BASIC
+Code Contest (IO-BASIC-CC) (and thank god the Devil for that!) and I
+beat it out anyway.
+
+
To show the importance of programming style, in an ironic way.
+
+
I definitely have done this. The absurdity of this many gotos is ironic itself
+but when you throw in the jokes (in the code too) it’s far more ironic. By using
+goto to absurdity the entire structure is lost. There is no following this
+program. As soon as you think you have the next step it jumps somewhere
+else…and that jump might jump to several other locations to land on its final
+destination: or is it the final destination? I think Hell (probably travelling
+by handcart) might be the real final destination, just like the player character
+(PC) who ‘goes straight to Hell’. Actually the sequences of jumps is worse but
+I’ll get to that later.
+
Some of the chains are JUST WRONG. There is a chain that just drops DOWN from a
+label that is at the end of a block only to do a goto which is inside that SAME
+block (the bastardised Duff’s device in fact, see way further down), which then
+exits the program.
+
There are for loops that are in different parts of main()! That is ridiculous.
+
As I noted two loops are intertwined in ways that you would expect to be a data
+race. It’s much worse than that. Here is what I mean:
+
Each of the two loops jump to the other one. One of them jumps more than the
+other but they both start out in what amounts to:
+
for(X=1; X < 6; )
+
but in one it is actually:
+
for(X=1; X<--(unsigned){ 7 } ; )
+
…which is equivalent.
+
But it’s more diabolical. As you saw, it does not increment the X so how does
+it work and what does the body of the loops look like? Well…
Notice how the labels end up swapping the location. The first loop goes to kk:
+and that is in the other loop. That will end up going to another place, either
+LL or uu, the latter of which is a fall through from the former. That is
+where the ++X is.
+
As for the second loop: first it jumps to BB which is inside the first loop.
+It does its thing and then jumps back to HA (isn’t that funny?) which does
+something else and then it jumps back to TA (do you truly feel welcome?) which
+is in the first loop. That does a ++X; and then jumps to the end of the second
+loop.
+
Realise this too: these tasks are for each iteration. That means each iteration
+these jumps are happening, kind of like everywhere else.
+
There are so many other things too…all with goto…plus other things, as
+you’ll see.
+
None of this code should be legal. But it is. This code SHOULD NOT WORK. But it
+does. gotos are harmful. Anyone who says otherwise needs to seriously think
+about what they do to maintenance.
+
goto TOTALLY DESTROYS maintenance. It causes bugs. And yet everything works as
+I intend it, down to the dead code, code that looks dead but is not, code that
+is dead but can be reached at times via goto… THAT IS JUST WRONG. It also
+destroys brains.
+
This is not good style. It is actually TERRIBLE style and HORRIFICALLY
+OBSCENE. I hope I have demonstrated this very well. Actually I KNOW I have. I
+have never seen a worse piece of spaghetti code in C and that is saying
+SOMETHING, as I have seen most if not all of the IOCCC submissions. That is,
+as will bring up later, no criticism. Of course I could have missed something I
+suppose (very possible) but on the subject of spaghetti code I think I outdid
+it.
+
There are a lot of ways to obscure code and I don’t believe anyone has taken
+goto to this obscenity in C. I believe the one with the most gotos is
+1987/hines and, as noted earlier, it reports on itself as having only 24
+gotos. Yet I have 116 before the cpp and 134 (!!) after the cpp.
+
And unfortunately for you dear reader I have done other things that also are
+quite different and totally unrelated to gotos. Even so the goto madness by
+itself is worth something or some things - including curses.
+
What kind of curses? That depends on the viewer. I would say it’s worth all
+kinds of cursing and I most certainly would be swearing at the author if I had
+to maintain this mess! It is a joke. I personally find it hilarious but that’s
+because it’s satire, just like the contest asks for.
+
+
To stress C compilers with unusual code.
+
+
My guess is that if the compilers were human beings they would be asking what
+the hell is wrong with the author. I guess this because I’M ASKING THE SAME
+thing about myself. The structure of this program went to hell in a handcart and
+I would question anyone and anything not questioning my sanity. Because I sure
+as hell am! Frankly I’m not sure if there is any sanity remaining and it might
+be hard to sympathise with me because I (quite deliberately) caused it myself.
+Still…I’m not suffering: I am enjoying every minute of it, as the joke goes
+(even though that’s totally bogus in…uh..reality). I think it’s HILARIOUS.
+
+
To illustrate some of the subtleties of the C language.
+
+
I have definitely done this. Some of the places I have put labels is very unique
+(or I have never seen them there). Also some of the other obfuscation seems
+downright illegal but is not (and that goes for at least one or two things with
+gotos too). I put almost 200 char *s in a SINGLEchar * (NO, NOT an
+array of char *!). There are other things.
+
Anyway I’ll get to these later.
+
+
To provide a safe forum for poor C code. :-)
+
+
If this is not poor code I would hate to see poor code! I’m reminded of the
+joke:
+
+
Always code as if the guy who ends up maintaining your code will be a violent
+psychopath who knows where you live.
+
+
…which I believe was said by John F Woods. I don’t know about anyone else but
+I would hate to have to maintain this code - to say nothing of the fact I might
+want to rip my the author’s head off for causing this mare’s nest from
+Hell that I had to maintain …write?
+
If I was handed this code and told to update it to change it to not have the
+gotos but still function exactly as I intended it, I would be cursing the
+horrible monster who wrote it. I would also tell them to go straight to line
+22!
+
Okay I might also laugh at the absurdity but I would want to tell the person
+telling me to update it to go straight to hell. Frankly I would be making FULL
+use of lalochezia (catharsis from swearing - no I did not make that up)!
+
And frankly, if you expect me to explain how some of this works I will also tell
+you to go straight to line 22!! THIS SHOULD NOT WORK. But it does. It works and
+it should not. This is NOT OKAY. This is a crime against C. It is a crime
+against computer science and could give computer scientists a stroke.
+
And I won’t be paying the bill because there’s no point when they’re in the
+vegetable garden1 from massive brain trauma. Besides, I might be in the pot next
+to them. Just don’t ask. I might go insane. If I’m not already.
+
Go to line 22 instead. It’ll make perfect sense if you do this. And frankly, if
+it doesn’t, I guess you must have grown up with BASIC. My most sincere
+sympathies my dear friend, my VERY DEEPEST SYMPATHIES! Take care of
+yourself. You only have one life.
+
+
To have fun with C!
+
+
Well I did admittedly have a lot of fun including with taking the gotos to
+peak absurdity - and the jokes of course and the other bizarre things.
+
This is the worst code I have ever seen flow control wise, and perhaps in some
+other ways too. And I wrote it. I have seen most, if not all, of the IOCCC
+winning entries. That is no criticism. I am in UTTER AWE of many of them and
+I feel that many are beyond my abilities; most if not all are after all utterly
+brilliant and I can’t know everything. But when it comes to flow control
+madness, this outshines (presumably with fire) them all, I think. If that’s not
+true I want to know which one and I want to meet the psychopathic, misanthropic
+author. They might be able to teach me something nice about humanity!
+
There are just so many gotos that a single miscalculation (in labels or other
+things) would cause the program to fail spectacularly. And it would be bad
+enough with just the goto nest. Unfortunately (or fortunately) there’s a lot
+more obfuscation.
+
Frankly if Hell actually existed and it had a programming language, I am
+certain it would look like this! In fact the abuse is so extensive that you
+might think that there HAS to be a flow control problem. But everything is
+as planned even if you think otherwise; but if you DO THINK there is a
+flow control issue I would say: I don’t blame you! I also thought the same at
+times but there is not. I was so certain of it that I many times directly set
+certain variables to what I wanted to test and it worked out. I was so certain
+there was an unintentional flow problem I had to test it. I’ll mention an
+example later on.
+
But either way unfortunately for you it’s NOT broken and if you think it is
+you’re wrong and will have to try again! Okay: the code is wrong in some senses
+of the word but it’s correct code nonetheless. It should be a sin but it’s
+meant to be this way. It’s no wonder the narrator is so twisted and I would
+actually ask what the hell is wrong with him except the narrator is also the
+author.
+
Actually now I think on it… I take that back. I DO want to know what the hell
+is wrong with the narrator too (okay, sure it’s actually the voice in the player
+character’s head but even so…I authored the narrator)!
+
I hope you know why but I do not ask for any pity. It’s been a true delight in
+writing this totally deranged code and I hope you enjoy it. Although…the devil
+might wish you to cry after looking at it. Certainly he’s blubbing too and his
+lachrymal vase is bigger than all the oceans on the planet. I know because he
+told me so!
+
And yes I am guilty of a crime against C. But I had no choice. The devil made me
+do it. With that said…
+
IMPORTANT NOTE FOR THE JUDGES: this program took about two months to develop
+and I frequently found ways to shave off more bytes which meant more obfuscation
+(and earlier on more events until it got to a point that I felt it was fine,
+even though the alt code has a few more).
+
It is thus entirely possible that some of the discussion in this or other
+sections to do with obfuscation is wrong in some way or another. I trust you
+understand how that could happen when you look at the code. I had to save my
+sanity and the contest was very close to ending anyway.
+
The events were so plentiful that I had to go for just more obfuscation although
+I was sorely tempted to add more events. I decided to leave that for the alt
+code instead, as noted elsewhere.
+
For some hints, which is definitely incomplete and might or might not have some
+inaccuracies, see deobfuscation.html.
+
Also I have included a commented version (of the submission, not the alt code -
+sorry, I don’t want to fry my brain any more than I have to) in
+commented.c. I did not test compile it after the beautifier did
+its thing. It seems like it should be good if you use the proper command line
+(the define needed for portability and the define to be able to spell out OREGON
+TRAIL TRAIL OREGON without having the ugly #define TRAIL o in the code simply
+for TRAIL variable which is used exactly once as that name).
+
HOWEVER: it does not have the latest obfuscation and I’m pretty sure it is
+missing an event or two. As I added more I stopped caring about updating it. It
+was too much for me to cope with and I was running out of time - due to the fact
+this took so long to develop and refine (the jokes in particular but also
+additional events and then much more obfuscation, as I kept saving more precious
+bytes).
+
Anyway it’s (commented.c) not the game itself (well okay it is
+but it’s not the code to compile); it’s just so you can get a better idea what’s
+going on - within reason: I did not try elaborating again on the gotos. I said
+enough below in this document and I added to it/changed things after the below.
+And even that is unfortunately probably only a small sample of what I did. I
+already wrote an obscene amount so I’ll try and limit it somewhat, and by this I
+hope to save your sanity and mine.
+
I might add to the judges: you might want to take a look at that (commented) code
+too so you have a better idea in design choices (though some of them are listed
+below). Although I’m not really sure how much that’s going to help anyone out -
+especially as it was created earlier on and I added way more obfuscation. It is
+also entirely possible that there are bugs in there that are not fixed but that
+are in prog.c. I suspect this is the case, perhaps bullets not being subtracted
+when they’re supposed to in some events (like with Blackbeard).
+
And yes there is some of the same deliberate dead code there but prog.c has more
+(I think, and if so, it might have more than prog.alt.c too). Anything you think
+is wrong (probably due to the spaghetti code from Hell) is very intentional and
+thus features. As noted in various locations some of the ‘things that seem
+“wrong”’ are actually part of a joke. Other places it’s for confusion to make
+one question their sanity even more. Yes I’m probably a sociopath.
+
As I commented in the commented.c:
+
* Finally this code is from an earlier version so some of it might be missing,
+ * not just the events, and not just the gotos, but potentially other things
+ * too, possibly bugs that were fixed in prog.c but are not here (and no more
+ * bugs remain in prog.c). But I believe this is more than enough to give you an
+ * idea though if that is the case. If that's not clear...
+ *
+ * WARNING: this code and its comments are not up to date. I wrote 116 before
+ * filtered through the cpp and 134 after the cpp and I didn't wish to
+ * repeatedly revisit this file trying to explain everything.
+
I hope you understand but I do believe it’s a gain not a loss. It is good enough
+especially as it’s only for educational value - or to examine my head (though
+prog.c might be better for that?). As noted the code (and jokes) took a couple
+months to develop and I could not manage adding everything in the end even though
+I tried to keep the structure relatively the same (it’s better though - although
+I did fix some actual flow control issues that were not intentional, but it is
+possible I did not update those in commented.c). Frankly it might help give you
+some ideas but it might actually confuse you even more. I’m not sure. Even so
+although you might find it of interest it’s not explicitly for you (the judges)
+either. What’s more important is obviously prog.c itself along with how it uses
+the data.
+
The main reason it’s (the commented code) out of date is I decided to take the
+gotos joke even further - again and again and again - but like I said I also
+made fixes and I also added more events.
+
Now then… Although the joke is intended (like all the others) I must say that
+BASIC is unique in that it is exactly what I want it to do: it is goto hell and
+that’s precisely where I want it to go! I do not want C to go to hell though and
+I somehow made it goto hell too, and as I said surpassing the 1979 BASIC in
+goto count (okay in that case GOTO): and as you’ll see in the code there’s a
+literal goto hell; (actually more than once) as a joke.
+
A fun thing is that BASIC is so awful that a part of why this this game is very
+different is when trying to be faithful to the original (i.e. before I decided
+to make a mostly new game) I had to back out of it as it was so large even after
+the data file was in place.
+
Happily this made me rethink some things and I came up with even nastier tricks
+plus the new and much better theme, turning it into a parody and then mostly
+going my own way with it all, keeping only the route and a few minor game
+mechanics in place. Plus more gotos and obfuscation…always.
+
Some of the abuse of goto in my code seems wrong if not downright illegal (but
+hey, isn’t that right on theme too? :-) ).
+
Anyway: can you honestly determine what this program does without running it
+or looking at the data file (with absolute certainty)? I didn’t think so :-) At
+best you can take some guesses based on the control flow (IF you can even follow
+it) but nobody can determine for certain, or so I hope. And if they can I wonder
+if they’re okay. I wonder this because I wonder the same thing about myself.
+
The first reason the strings are in a data file (which other entries have done,
+so it’s not abuse of rule 2) is because the original strings BY THEMSELVES GO
+WELL BEYOND BOTH size rules: I might’ve said this numerous times. Call me
+paranoid on that rule if you wish. Probably it is especially since many other
+entries also read from files.
+
Unless you look at the source data files you can only at best guess what this
+program does. Well okay there’s that spelling out of OREGON TRAIL but that’s a
+long tradition in the IOCCC and could be misleading anyway. Indeed it kind of is
+as the strings will show; it’s hardly Oregon Trail now - it just takes place on
+the trail. It all had to be carefully designed which also is a good thing for
+the contest. My procedure outlined later in this file will show you just how
+much creativity it took and just how messed up it truly is.
+
Anyway there’s no way to know for certain what this is, or so I can’t fathom how
+one could know. And that’s assuming you can follow the spaghetti code. Frankly
+to call it spaghetti code is a huge understatement. It seems to me it’s a new
+category on its own: perhaps Cthulhu with heavily mutated tentacles?
+
As I mention later, the data file rather reminds me of the Windows registry (I
+will return to this later in the Data file section), which is a great
+thing for the contest and a terrible thing for a non-obfuscated program (thanks
+Microsoft for having a comparison in poor design! :-) ). The best part is
+unlike the registry, my data file simply works, as long as you don’t screw with
+it whereas the registry is broken by design.
+
IMPORTANT NOTE: I originally showed some of these in detail but it got so
+absurd and long to show and so hard to maintain as I updated it that I was
+totally overwhelmed by the sheer madness. I am not sure how much I really do
+have here but when you look at the code you’ll definitely understand why and
+probably sympathise with me too.
+
Check case 11 in the events switch. It does goto V;. Now V: is part of
+case 8. But do you see how long the inner switch that is part off that code
+is? In some ways it is actually polymorphic, doing drastically different things,
+depending on the pRNG and which event it is.
+
At one point I was DEAD CERTAIN that part of this that should not be dead
+was dead. But every part of it that is meant to be live is. There was a part
+that was broken but that was fixed. As I noted in my remarks above,
+this event (11 in particular, under V), will not necessarily do anything, as
+it depends on another call to the pRNG. This is good because otherwise every
+time it triggered it would cause severe illness.
+
There are many places where a label is inside a block. There are some fun abuses
+of this. For instance did you notice that many times what should be in the if
+is actually in the else? Sometimes the reverse is true and sometimes the code
+is swapped. The code then jumps back to where it would end up, at least if
+necessary (in some cases it might not be necessary at all).
+
Here’s a funny one which involves dead code but code that can be reached in one
+condition: it just can’t be reached by goto. It is the goto heaven; which
+means it’s unobtainable (okay, so the above statement that there are only two
+dead jumps means that there are three, and maybe I missed some, but this hardly
+matters and it’s important not only to not trigger a warning - interestingly
+enough despite the fact the compiler should know it’s dead - but for the joke).
+But here’s how the code actually looks:
First of all what is with the label BETWEEN the while (with the condition) and
+the code of the loop (which in this case is actually an if because w() does
+its thing and then does a goto hell;)? It looks even worse with the {}s for
+the ‘loop’:
+
heaven:{ w(i) }
+
And then of course it appears that it would go on to the if. But it doesn’t
+- if i is non-zero of course.
Notice how if T<666 (that’s a check if the PC has enough money for the doctor)
+it does a goto QQ;. Where is QQ? It’s inside a for loop that has its code
+in another place (yes it’s horrible). It looks like (sorry if this changed last
+minute):
Notice how QQ: does its thing and then jumps to JJ:. That label is at the
+end of the if/else inside the if that contains the check for T<666. After that
+for loop is amusing: goto B; which is where? Close to the beginning of
+main(). I will return to that for loop itself shortly as it’s hilarious.
+
Oh but it’s far more diabolical than this! If you observe the initialisation,
+condition and increment of that loop you’ll see it iterates through o via X.
+So what you might say. Well this is what. The label kk? That comes from
+another loop that does the same thing! Higher up in main() that loop looks like:
+
for(X=1; X<6; ++X){ goto kk; ZZ:; }
+
and so the body would actually translate to something like:
So it checks if it’s < 0 and then sets it back to 0 if it is. And of course that
+check is in another if block that is totally unrelated. The goto ZZ; is there
+as in both cases the end of the for loop has to be returned to. But this means
+the for() loop is split in several places and it’s worse than that…
+
It looks like there would be a data race here. There isn’t. Isn’t that
+beautiful? I thought so too. As far as what those two for loops do. One is
+adding to what you have after purchasing (at the fort, I think) and another is
+making sure that it’s not < 0, setting any back to 0 if necessary.
+
Another hilarious thing about it. The containing loop is the one that (and I say
+this somewhere I think) it would appear is acting on the array prior to
+initialising the variables. The question you might then have to ask is: in that
+case, which initialisation is being used - or is there any?
+
As for the beginning of main(). Did you notice that the return 666; is close
+to the beginning of main()?
+
Going back to that for loop with BB:. Did you notice how BB comes before the
+loop? And then it jumps forward and backwards and so on. Here’s what it’s like
+in fewer lines so you get a better idea:
So the body of the loop is actually outside of the loop. That body jumps several
+times only to land back at the end of the loop - which so happens to be after
+QQ: which I brought up earlier - and which starts from another place entirely.
+This for loop is the one that would look (to the uninitiated) as using the
+variables before they’re initialised. Maybe I have not shown this yet. Apologies
+in that case.
+
But if you look at the code more carefully you will see that the else block that
+contains it all does an immediate goto y; which means the loop can only be
+accessed by a different goto. That is the goto A; which also close to the
+beginning of main() (if at the fort).
+
Of course as previously noted the kk label is another for() loop that actually
+increments X as well as acting on o (o[X]). But of course in the other
+one it’s further apart from the loop, exactly so it looks like it is
+uninitialised but isn’t. I would move it further away but I wanted to mislead
+further. The fact that the kk: label (part of the other loop that is acting on
+o[X]) is right there and you can see in the containing loop that it’s also
+incrementing X could easily be mistaken for being part of the containing loop
+rather than the loop inside of it (which doesn’t look like a loop at all). All
+you have to do is miss the goto BB; OR, after all the gotos, start to
+question your judgement: is it really jumping somewhere?
+
Additionally for all you know the goto BB; might land at kk: indeed some
+code like that actually exists (or so I think). Sure you can see to the left of
+the loop that it doesn’t, again assuming you’re not overwhelmed with the sheer
+amount of gotos, but it is far more confusing to make one wonder if it’s a
+data race. But like I said it’s definitely not a data race due to manipulation
+of the flow control.
+
As for the loop itself: because of the at: at the end and the several jumps,
+the body of the loop is in several places, jumping behind it only to go a
+bit forwards (by skipping a label and goto) which does something else and then
+goes back to that label that was just jumped over which then jumps to the end of
+the loop (the at: label) - for its next iteration.
+
And as for QQ that simply prints a message, setting the variable that the PC
+can’t afford the doctor (saving bytes in the process by doing B=38 in the call
+to V()). Then it jumps back to where it started - or actually the end of that
+if/else chain which then carries on to the next part of the code.
+
That will end up doing goto z; which is at the end of the do..while loop in
+the bastardised Duff’s device.
+
I do like that the code spells out HAT and if you use your imagination a bit
+T-=X[t] could look like text (or more like TEXt.
+
There are other for loops that have similar and, as I said, if/else that have
+this too, with labels and jumps to lead to confusion and making it almost
+impossible to go through in a debugger one instruction at a time - at least
+without going partially (or completely) insane.
+
A couple more devious goto ones. At the very end of main, long after the
+return 666; and right after the do..while loop, you’ll see goto _;. Now
+where is that _:? It’s somewhere in the obscenely long switch at V: which
+has a lot of code (including another switch) that does not belong there. It is
+so long that it is hard to know if the case statements are part of the case 8/V: or not.
+
In any case the _: in turn does goto rr;. And where is that? This is
+hilarious. Although you’ll see part of the bastardised Duff’s device I will
+return to that more later on. Anyway:
(Yes all of main is in the switch - will get to this later on.)
+
Observe how the rr: is in that switch block (along with other things that
+shouldn’t be there but obviously are) and it simply falls through to the goto OO;. Where is that? Well look carefully: it is in that same switch, right
+before the rr: itself! It checks hp/stamina and then depending on that and
+other conditions it ends the game with different messages. Isn’t that just
+brilliant?
+
Oh but there is some extremely devious things here. I’ll return to that when I
+get to Duff’s device (or the bastardised form).
+
There is more nastiness with goto but like I said, if you expect me to explain
+everything I refer you to line 22. That being said I will get into some that are
+indirect - like how I get into the loop of the bastardised Duff’s device, and
+when asking: how the hell does the switch at V: even work? The same question
+for the if (q>9) block and in that case the switch(x(1,2)) inside it. This
+should not work. But it does. It is wrong in the worst (i.e. best) possible
+ways.
+
Anyway I leave the rest of the goto madness to you, again except indirectly in
+a few cases, and maybe one or two that come to mind that might be worth special
+mention.
+
There is just too much to go through and I think you have more than enough
+ideas. If not do check the code out - unless you have a heart condition, at risk
+of stroke (especially if you’re a computer science teacher). If these apply,
+please look at it with care, as I mentioned above. One soul (or two if you count
+the PC) lost is too many. Don’t make it a second (or third). One person, the
+author, is enough.
+
What in the hell is this?
+
x:V(X+--(unsigned){ 6 } );
+
You might have seen the compound literal in a similar way before but have you
+ever seen it do +-- as part of it? Isn’t that illegal? Ah. Well to be blunt:
+no it is not. All this does is prints out the string that is at X+5. But
+doesn’t the + followed by the -- looks so wrong or indeed as suggested,
+illegal? Shouldn’t you get an expression is not assignable like the following
+code?
+
i+--5;
+
HOW IN THE ABSOLUTE HELL is it not? Wouldn’t the +-- be the + operator
+and then the decrement operator (you’d expect a variable that can be incremented
+to the left or right!)? That’s not how it works. It looks wrong and FEELS wrong
+but it is not. Nonetheless it functions correctly. Here’s the trick.
+
The + is attached to the X and the -- is attached to the compound literal
+array with the value 6, thus making it as noted X+5! Isn’t that lovely?
+
Amusing thing to ponder for you. You noticed, no doubt, earlier where with a
+compound literal like above I had an expression in a for loop what amounts to X < 6, i.e.:
+
X<--(unsigned){ 7 }
+
The reason I used unsigned is because X is an unsigned int. Without that that
+would trigger a sign compare warning. So how come I would not get it if I had
+above as:
+
x:V(X+--(int){ 6 } );
+
…when the loop that calls that actually is comparing? I just gave the answer
+in the very question if you need a hint.
+
Do you remember Duff’s device? I have a twist on it. Or perhaps several.
+Actually it doesn’t really look like Duff’s device, except that there is a loop
+inside a switch. But that’s not really the confusing part, even if it’s not
+right.
+
main() in its ENTIRETY is inside a single switch. This includes seeding
+the pRNG, opening the data file, reading it, every last part. Read that again if
+you need.
+
The default case sets things up but it looks like it should not work. But you’re
+wrong if you think that. This is the beginning of main():
+It looks like this:
Now one might wonder: obviously the goto A; is not executed first because it’s
+not part of a case/default. Well maybe some would think otherwise but it’s not.
+
But then…how can the goto M; in the default allow ever getting to the other
+labels? It’s all due to the gotos. The label yy: as you’re about to find out
+is the do..while loop.
+
Obviously, since main()’s entirety is in the switch, the game loop is entirely
+in the switch too. There are other switch() blocks, with some nested, as
+previously shown.
+
Of course the loop can be exited and re-entered as you already probably noticed.
+Getting to the beginning of the loop, i.e. the do, is confusing as well.
+First, after seeding the pRNG and opening and reading the data file, assuming no
+errors occur (in wrong directory or missing file for some other reason, file not
+readable, getdelim() returns an error etc.), it does a goto M;. Of course it
+might look like it does a goto PP; but that’s not right.
+
M: happens to be inside a switch that is totally unrelated, in fact either
+purchasing at the fort or maybe all purchasing, though that’s after another jump
+(v: is important to clear out the t array). So it jumps to N:. Now this is
+actually inside the do..while loop. Yet the loop has not really started just
+yet. N: is inside a switch, I think a three level nested one, depending on how
+you count levels, though I might be wrong. Anyway that does a goto Q;.
+
Q: in turn is inside an if block but safely as the first statement of the if
+is to jump somewhere else. Instead Q starts a loop. This is sneaky. It
+iterates through X (until 6) but each iteration goes to x: which allows for
+purchasing, either at the fort or initial, and then it eventually jumps back to
+the end of the loop. Of course x: is used in other cases too.
+
Once the loop is done it jumps to j which is the first part of the switch
+containing main()’s entire body. If at fort it does goto A; otherwise it sets
+up the amount of bullets you have based on how much you spent (using the same
+variable of course - because why would I want to use another variable, even if I
+have to scale in both directions?) and finally prints stats!
+
At that point, and this is hilarious, if at the fort (didn’t I just check that?)
+it jumps to f:. Otherwise (and again isn’t this similar - both if and else but
+without the else) it jumps to PP:. Are we done yet? Afraid not…
+
It jumps a short distance (that appears to be part of the default except there’s
+a goto - or several, including the goto M; which started it all) inside an if
+(PP: is). After a call to the w() macro.
+
That might suggest it always runs off, even when a is non zero and
+b < 1 (neither of which are relevant at this point) when the do..while loop
+(which at this point of main() has not even been reached) is over.
+
But of course it doesn’t because w() does goto hell;. So PP because w()
+does a goto hell; which is also short distance away. But instead it does a
+goto G; - and if you guessed that that is inside the loop you’re absolutely
+right: also to the right of a w() (I will return to this). This jumps to the do!
+Finally there.
+
What this means is that even before the loop is started, and also after the loop
+is started, both during the game and at the end, it leaves the loop, which of
+course is inside the switch which has the entirety of main(). But this does not
+destroy the state. And like I said, it does not skip any initialisation as the
+variables are file scope so no UB invoked.
+
Basically there is no guarantee what might happen next. You never know because
+it’s constantly jumping inside and out of blocks, blocks that are totally
+unrelated, often in what seems totally illegal and what should not work, even
+that seeming data race I brought up. But it all works exactly as I mean (again,
+including code that is either dead deliberately or seems dead but might or might
+not be). So again if you believe you have found an execution problem you’re
+simply wrong.
+
But when it does get to b < 1 if a is non-zero obviously it’ll go back to the
+loop, right? Well again no because w() terminates the program.
+goto G;. More fun!
+
So on that label: it goes into the do..while loop (in a few nested blocks full
+of code that should not be there) in what seems like a reachable place in other
+times - only to jump outside of it to…enter it..to exit..to enter…? That
+can’t be right.
Yes there is even a block inside a block there: the d: is inside the e:
+label block (or its if anyway). After that is another unrelated if. In the
+case that the d/e block is/are entered it will go elsewhere in main() though,
+even though the code would never be executed if the containing if were
+entered.
+
Did you notice this block?
+
D:{ if (k()) /* ... */ } goto s;
+
It is obscenely long, wrong and has code that should not be there. But of course
+that’s why it has to be there and why it works.
+
What this all shows is that not only can you no longer anticipate where the code
+is about to be but you also can’t rely on blocks at all any more. Blocks are no
+longer blocks as you knew them. They might as well be a red herring since blocks
+can be used for opposite (at best) code. In fact in this program you basically
+cannot expect the rules of C to apply - because they don’t.
+
You have if/else that have been swapped, starting with a goto to where the
+code really is, and, depending on how it’s constructed, the code might just fall
+through to the end of the if/else chain, or it might need another goto.
+Sometimes if and/or else code is/are in other unrelated places entirely. These
+if/else blocks might also hold code that do not belong to them, even what would
+otherwise be dead code. Loops are even worse with this.
+
There are for() loops that jump out of the loop with a label at the end of the
+loop for the next iteration. It might also have code from another place that
+really doesn’t belong there.
+
One for() loop actually takes that even further by jumping back to before the
+loop, then a bit forward (jumping over a label), then that jumps back a bit to
+do another part, then it jumps to the end of the loop for the next iteration.
+But the body of the loop actually has other code for something else, maybe
+another loop or maybe an if/else or something else. Obviously in the loop it
+jumps back.
+
There is even code that is split into several parts of main(), like at least one
+or two for() loops, sometimes even with code that belongs to other blocks
+entirely, just to make you question reality: even when the code is in a loop it
+might not be physically in the loop, just like with if/else and other things.
+Some of that might have been shown already. But this is sheer manipulation in
+the worst (i.e. the best) possible ways.
+
There is even code that falls into code that jumps to right before the code that fell
+through to that jump (yet it somehow does not go in an infinite loop), just to
+make you question reality even further.
+
Everything (or most everything), is inverted, backwards (sometimes going
+physically backwards in main(), only to then go forwards again, or somewhere
+else entirely) and just wrong. This should not work. The fact it does work makes
+it even worse.
+
Nothing is necessarily what it seems to be. Do you understand how wrong this is
+yet? Unfortunately (or fortunately :-) ) sometimes things in this world that are
+wrong are actually right at the same time. It is unclear at this time if this
+still applies to the author’s sanity.
+
Oh and yes. There was another set of goto labels I should have mentioned as it
+involves what would otherwise be dead code. This:
+
R:if(R<14)V(37); if(z) { z=0; l: {
+
code, and in particular, the if(z), is actually dead. But of course the labels
+inside it are not. That l: block belongs elsewhere.
+
As for the z=0 it is there to mislead you into thinking that code resets z
+back to 0 - but it’s totally irrelevant. In fact even if it did enter, for
+instance if the author did something stupid, it wouldn’t matter (well other than
+the other code being executed) because the else block also sets z to 0. Well:
+not quite. But it is set back to 0. Here’s the hilarious part. Inside that if is
+a switch (that is reached via goto) that depending on the case actually sets z
+to 1 which seems so counter-intuitive.
+
One more thing with goto that is hilarious that I just remembered. Check this
+code out:
+
if(x(0,1))goto I; R:if(R<14)V(37);
+
What is that label I: about? This is brilliant. Next to what would otherwise
+be dead code, again due to w() (which btw is NOT for obfuscation - it’s to
+save bytes and to be able to do goto hell; from anywhere in main() with two
+messages, the one passed to it and the final message) it does goto a;. Now
+a: is in some switch between a break and a case (looks like it must be the
+events switch). This a: does a goto H;. Now H: (and again this is
+throughout main()) does a - and this is horrible - goto R;.
+
Yes. This means that it sends you all over the function only to end up right
+where it left off, doing absolutely nothing. In other words it totally misled
+you into thinking something important might happen. Isn’t that hilarious? I
+thought so too! :-)
+
If I may, I’ll repurpose the word spaghettification (yes it’s a real word) by
+saying that that is what I did to this program in the worst (i.e. best) possible
+ways:
+
+
Spaghettification: the art of making code almost impossible if not impossible
+to trace; compare to goto, an invention in some computer programming languages
+where the programmer wants you to have so much stress that you swear yourself to
+death and go to hell for using the lord’s name in vain.
+
+
(to stay on theme - I don’t really know anything about whether that’s true or
+not.)
+
Anyway: have fun following all the gotos! I have never seen anything so abusive
+of gotos and I hope to never again. It’s appalling especially in a relatively
+short program.
+
I believe I have used every single single letter label, as well as _, which
+makes it so that every single character label is used. What’s more is that, as
+can be seen, many two character labels have also been used. That’s expected with
+the amount of gotos but it’s worth pointing out. I might have missed a single
+character one but I don’t think I did.
+
A number of nested ternary operators.
+
The data (with amusing output of file data, see below) bears special mention
+as it was cleverly designed to both hide and make it exactly as I need it (in
+multiple ways actually). See Data files.
+
Did you know that it’s legal in C to declare a variable more than once? It’s
+only legal IFF (if and ONLY if) it’s the same type but this is how I managed to
+spell out OREGON TRAIL even though it’s using O and R twice. I don’t know
+how well this little bit is known but I don’t think it’s that well known; I
+certainly have never seen it documented anywhere and only discovered it on my
+own years ago.
+
Also as you might have noticed in the TRAIL array I use O twice (in the
+definition) but I only use it once in the code, namely the second one; the
+second one so I can just iterate through it and the strings in one pass (this is
+also why the t array is of size 6, not 5, or actually 7, since I also have I
+to shorten code). But this way I can spell out OREGON TRAIL and then TRAIL OREGON (and something else which also kind of describes the game, see below)!
So there you have it: the code suggests a rude OREGON TRAIL but it’s definitely
+not that! :-) Okay it might be in some ways but it’s a parody meant to be funny,
+and much of any rudeness if not all has to do with the imagination of the
+player, since the jokes can be interpreted in numerous ways, and deliberately by
+design. Anyway, the idea is it helpfully tells you what this: pretty important
+given how screwy the logic is.
+
Oh and if I may: it might also spell out ‘rude long OREGON TRAIL TRAIL OREGON’
+which of course it was long.
+
The TRAIL variable is actually o: it’s defined in the Makefile because it
+would be ugly in the code but having it allows for the tradition of IOCCC
+programs spelling things out (it’s only used in that one place - I use o in
+all the other places as it would take way too many bytes; the only reason I even
+have it is for that tradition). Okay it actually allows for swapping the order
+as it’s already spelt out. But still. I could of course just have o but to
+save a measly four bytes (which is why I’m not concerned about using it) but
+that might not be enough for anything meaningful so this is much better.
+
After I talk about the Data files I will discuss how this is definitely
+well-rounded in obfuscation.
+
+
Data file: more obfuscation and portability and ensuring it can be used properly
+
+
IMPORTANT NOTE TO THE JUDGES: if any problems in the data file exist,
+remember to regenerate it as described in the Judges section and/or the
+Troubleshooting section in the remarks above. It is greatly
+appreciated that if by some chance you do run into a problem that you do this
+quick procedure (the addpadding -d option can also be used to reveal what the
+program is doing for those who wish to see more, although trying to play the
+game after this will print out rubbish - see below).
+
Remember that if by some odd chance the program segfaults that you MUST
+create the data file anew. I don’t think it’ll happen but just in case. Of
+course if the data file is missing (which would suggest a user error) or
+getdelim(3) returns an error (not my doing) then the game will simply exit. So
+just make sure the data file is recreated. Thanks!
+
As I note elsewhere (I think I did) there’s a very good argument to have the
+compilation rule always run the addpadding program, and that’s what the Makefile
+does (unless I missed it in a rule) BUT EVEN IF that’s all good, if there
+are ANY issues PLEASE run the addpadding tool manually (or better yet
+make makedata).
+
The data file key is part of the obfuscation both in code and in data; it also
+stays on theme. As noted in my remarks above, I have bypassed the
+concern of SUS portability by including my own tools, much like previous winning
+entries did with POSIX compatibility.
+
I finally added the test rule to the Makefile to be sure things are sane too,
+although this cannot detect that the messages are correct entirely. Still
+everything is as meant.
+
Anyway the obfuscation.
+
Before I can explain what I did do I need to explain how the file is used.
+Briefly for the moment: I’ll explain how this all works in more detail, later
+on. The file is loaded with getdelim(3) with the delimiter being EOF. That
+loads the entire file in. But the file has NUL bytes (I added these manually).
+The NUL bytes are key and I’ll return to that soon.
+
I was not sure if getdelim(3) would actually stop at the NUL byte. A test
+program showed it does not: exactly as I needed for what I had in mind! This is
+where it starts to get really clever.
+
Rather than having to have so many strings in the code (therefore taking it
+WAY past the rule 2 limits) I have it in the data file. But to obscure how
+it’s done (and to help not have to have it line based or have to keep
+referencing the line[] or whatever it might end up being) each line ends with
+a NUL byte.
+
As I’ll make clearer soon this is not a char *y[]! It is a single char *y. No arrays here. The hilarious part is it looks like I’m using it as an
+array of char *. I’ll return to that later on too.
+
There are seemingly bogus strings in the data file too but the first one
+actually does matter, even though it shouldn’t (as in doesn’t need) a NUL byte.
+The last one might or might not have a NUL byte either but that’s just nonsense
+anyway and it does not matter one bit, even if it’s many bits and actually quite
+a few bytes, longer than the blocksize I’m sure.
+
These NUL terminated strings inside the single char *y only have a newline
+when necessary. This way I do not have to worry about printing a newline or not.
+
The NUL byte with the padding serves numerous purposes. And actually as long as
+the string is short enough to fit into the blocksize (with the NUL byte too) it
+could realistically work without padding, but I don’t think any string is that
+long. The first string (that is not part of the game but does matter indirectly)
+actually has no NUL byte.
+
Obviously the NUL byte is critical as it allows me to just stop without worrying
+about it. Why bother with trying to figure out the length when the format (the
+padding/blocksize and NUL bytes) do it for me? When *p == '\0' the loop ends
+and everything is done.
+
The procedure was obvious multi-step. I had to create the source file and then I
+had to create the data files. I needed a tool to do that.
+
Now if I wanted to print out every string in a sequence, there are multiple
+ways. Some of the tools I describe and include do it differently, some even using
+a hack (those were created very early on and simply to verify things - they are
+only included so you can see just how much care I put into this all). But in the
+prog.c I just do a printf() at the right index while there is no NUL byte. It
+looks like a char *y[] but it’s not. I’ll get to that later.
+
I hope you’re starting to see the brilliance here but to put this a more
+interesting way, as hinted earlier: this is like CLOSE TO 200 (!!) char *s
+inside a SINGLEchar *: one char * is all it takes (!!) but there are
+174 (currently, it’s changed so many times, if we count the bogus ones, one of
+which is actually needed in that if it did not exist the indices would be wrong
+in prog.c, printing the wrong strings, and that could also lead to a security
+issue, potentially, given the format specifiers in some).
+
Some of the unused strings are just jokes for people to discover (or for the
+judges to enjoy). In other words I suggest you go through them. Some of the
+strings are remnants of the original game and are totally irrelevant. That was
+when I first started and was going to try and make Oregon Trail rather than what
+it is now, A Pact With the Devil On the Oregon Trail.
+
If you look at the files you’ll notice they also have something else.
+In particular, it has the following C, though it can be cut off depending on
+blocksize and length of the string in question. It is also a reference to the
+joke I mentioned about BASIC (and what I obscenely did to C too: a blatant crime
+against C):
That padding is also critical, as it’s how I get the right location in the char *y.
+
As for file data:
+
$ file data
+ data: data
+
:-)
+
As for printing, these routines are key:
+
long Z(long x){ return x * 1663; }
+ void V(long x){ printf("%s",&y[Z(x)]); }
+
Do you now see how it LOOKS like a char *y[] but isn’t? It’s a flat char *y,
+as noted earlier: the arg to printf() implies y is an array of pointers but
+it’s actually just a pointer. The indexing works because I treat it AS IF it’s
+char *y[], and the compiler doesn’t care one bit. The reader, however, might
+start to question their sanity, upon learning this fact, possibly even calling
+me a horrible monster. Because obviously I am. Or perhaps I’m the devil? You
+decide.
+
Obviously the NUL byte is required to make sure everything works right. The
+padding ensures that we can easily calculate where to start.
+
The comment at the top of the data file:
+
/*useless code below, goto end of file*/
+
is a misdirection especially as at the end of the file (which actually has the
+contents of prog.c itself) has:
+
/*useless code above, goto start of file*/
+
To get everything set up and tested required a few programs and pipelines but
+they work well and it’s perfectly safe manipulation (even if devious) as long as
+the data file is correct. And as I include the tool that is not a problem.
+
These tools are vital, or at least some of them are.
+
I wrote these programs (amongst others not included and not needed). As you’ll
+notice (if you look at the description and/or the code) some of them are
+similar. Some might do almost or exactly the same thing as another but might be
+done differently. I’m not sure: it does not happen on my systems but if a string
+prints in the wrong way it would likely be your system.
+
NOTE: the other tools that have the V() code or similar have it in a macro; it
+was not worth updating in them when I changed it to a function in the
+prog.c/prog.alt.c.
+
Hopefully I have described these tools okay. If not apologies. I only include
+them so you can see how much I put into designing the system.
+
+
bytetest.c prints every string extracted from the data file
+(at least those that are used by the V function i.e. it doesn’t print the
+bogus two strings) with a location so I can know what chunk to use in the code.
+This became unimportant with bytecount.c described below.
+
byteread.c prints out the strings without the location printed and
+without caring about the NUL bytes. (Can you write something similar without
+looking at it?)
+
bytecount.c prints out each string with each location but it
+reads the source data file so it’s cheating.
+
bytecheck.c reads in (by default) data.src and prints out
+single-byte characters (so non emojis); and with the -i option I can read in
+the data.asc.src file and in this way, with less(1), I can make sure that
+the strings are the same (well as noted somewhere some of the strings ARE
+different in the different files). For those who have a fully capable emoji
+system this is not important. See also further down for a tool that writes the
+string number that has a multibyte character.
+
printer.c prints the strings as if the game was doing
+it. It should however also print out the % conversion format specifiers intact
+which the game does not have to worry about doing it that way.
+
addpadding.c this adds the proper padding from the data source
+files, writing to the respective data files. THIS IS CRITICAL! Without this
+everything breaks!
+
lencount.c counts strings and reports longest one (can you
+figure out why this was needed? If you guessed the blocksize you’re absolutely
+right). The -t option is useful to verify (without showing the longest string
+which can make it hard to miss) that no string is (in length) >= the blocksize.
+
mbcheck.c shows where multibyte (2, 3, 4 bytes) characters are in
+a file, by default the ASCII only file so that I can make sure everything is
+okay. This tool kind of obsoletes bytecheck.c and almost makes that tool
+useless, except in helping to identify if the strings are the same number (which
+they should be). Note that the counting here is interesting so that it might
+look like the wrong number of multibyte characters but this was not worth
+worrying about as I just wanted to make sure no multibyte characters slipped in
+(as noted somewhere I once copied the emojis file to the ASCII only file when
+doing a rewrite of the jokes). It might also not be: it might just seem that way
+to me.
+
and some others mentioned below (and possibly some not mentioned).
+
+
If any mentioned above or below are missing (some intentionally so, possibly):
+apologies (and also not sorry) but they’re not important for the game.
+Everything that is important for creation of the data files, the test rule etc.,
+IS included, and that’s what matters.
+
The strings.loc.txt (which if there was the concept of a
+spoiler this would be A HUGE ONE!) has the location of each string based on
+the blocksize. The strings.asc.loc.txt is the ASCII only
+counterpart: the one that is for data.asc. The
+strings.scrnshot.loc.txt is for the screenshot
+friendly one.
+
Of course even with these files it does not make it easy to parse the code
+(prog.c) as you have to go back and forth and the order of the strings is not
+sequential, some strings are not used (by design) and some have multiple
+versions (sometimes more than one is used and sometimes only one or even none
+are used).
+
One of the reasons I added the (unused for prog.c/prog.alt.c) macro BLOCKSIZE
+is so I didn’t have to repeatedly update the other tools when things changed
+(which did happen several times as previously noted) (see below for more
+reasons why).
+
The file bytes.txt, which is created by makedata.sh (and not
+included for this reason), has a list of <n> (one per line) where n is the
+location (based on the blocksize) of each string. These files are used to create
+the V.c file (which some of the tools use - which is why it’s included) and
+all of this can be created by:
+
./makedata.sh # or make makedata
+
The script also creates the strings.loc.txt,
+strings.asc.loc.txt and the
+strings.scrnshot.loc.txt but these I included as
+they seemed very useful to see how I developed things; at one point I included
+the others (the bytes.txt, bytes.asc.txt) but as more tools were necessary I ran
+into the file limit and these were the ones that weren’t strictly necessary.
+
There are a number of reasons I did not use the blocksize macro in the prog.c:
+first it’s not needed and would use more bytes; and second because I feel like
+most people are more intimidated by numbers than words even if it translates to
+the same thing (the V.c is built from bytes.txt btw). As noted the
+reason for the macros are not for obfuscation but simply to save bytes. In some
+cases a function would have been ideal but when tested did not work as I had
+hoped (it can save bytes depending on the macro and its use).
+
The original test was in nultest.c (not included) which tested if getdelim()
+with EOF would stop at the NUL bytes.
+
I originally had to test by skipping (when a % is encountered) one byte past
+it. Then I added other specifiers that were more than one byte. The solution is
+that (and this allows for easy printf calls) it also ends in a NUL byte! So
+every string ends in a NUL byte (and if space allows a padding, or a padding
+repeated as is often the case). That is why I had to carefully select and verify
+that the blocksize was okay. The nultest.c file was just a quick test and
+only was a test to see if my concept would work. Once I confirmed it seemed good
+I had more to do.
+
But like I said, as this has changed too many times I am not going to get into
+the initial procedure beyond that (the code can speak for itself - and perhaps
+part of the Makefile) other than to say that the important programs are
+addpadding.c and for personal reference printer.c, byteread.c and
+mbcheck.c - perhaps a few others but many are not necessary in the end. Okay
+actually mbcheck.c is important for the submission too as it’s part of make test - as is lencount. If I did not include one it’s not important and not
+instructional either. I have included everything that is needed, however.
+
The files data, data.src, data.asc, data.asc.src, data.scrnshot and
+data.scrnshot.src are created/used by addpadding and are vital to the game
+(for the .asc data files it is for the non-emoji version, prog.asc, but used
+by the same code, hence the DATA macro and the same applies to the screenshot
+friendly one, as I discussed in the data files versions in my remarks above).
+
The data*.src files are included for the purpose of allowing the files to be
+created prior to running the game as they are vital, just like previous entries
+with their data files.
+
The lovely thing about the data file is it’s also on theme with the padding.
+Plus the jokes being on theme.
+
Fun fact: the block size is necessary in another way: it also saves bytes.
+How can it possibly save bytes you might wonder? Well without it I have to use
+much larger numbers (plus what I already mentioned about how if a single string
+changed it would break everything after it).
+
The data file reminds me of the Windows registry but it actually works
+if one does not mess with it, rather than if it’s messed with OR by itself. It’s
+also efficient on a modern system (unsure on older machines but I’d guess it’s
+speedier than Windows registry - or Windows for that matter): I have seen no
+slow reaction at all.
+
But the point here is that the Windows registry is poorly designed, inefficient,
+error prone and not cleverly devised but my data file is, although not a design
+you’d want in real life programs: cleverly built, cleverly used, efficient and
+it just works if someone doesn’t screw with it in the wrong way (in some ways it
+might very well still work, though that depends on your definition of ‘work’ and
+‘some ways’). These are useful to keep in mind when it comes to evaluating
+obfuscation. And madness of course.
+
Consider: the Windows registry is a blob of data that if a key (I think that’s
+the right term?) is corrupted it can break the entire system; and there are
+many things that could go wrong with the data files I supplied that will
+totally break the program; but whereas some problems in the Windows registry
+might not (supposedly) break Windows entirely (I will argue that if we consider
+the design it’s always broken but never mind that) even minor changes can have
+catastrophic effects.
+
That’s why all the extra tools and why I had to write them, all to make sure
+things are okay, and even then I remind that you should always recreate the data
+files so that something horrible like a crash does not happen although I don’t
+think this will happen to you; in fact towards the end I looked at every string
+index for each file and verified it was valid. With the tests in place and the
+Makefile building the data files it should be good.
+
Anyway: even though the design choices are deliberately bad (for the contest,
+although they work well): I did have to carefully design it, figure out the
+padding and so on.
+
And yet I’m not sure: it’s a very elegant and creative design. Why indeed should
+I have to read in multiple strings when I can just use one char *? Why worry
+about having to know when to print newlines when the file can have them
+literally? It is simple, clever and quite unique. It is subtle and maybe
+brilliant. It is what the IOCCC loves.
+
I believe I already explained how a single char * can have so many but a TL;DR
+is that the data file is read in in its entirety with EOF as the delimiter to
+getdelim() and the data file has NUL bytes that delimit the strings. After the
+strings, if there is more space left, the block is filled up, so that the string
+can be addressed by index rather than exact location, which would not work if a
+single string changed: all the strings after it would no longer be correct. If
+the string is >= the blocksize in length it will break everything. That’s part
+of why lencount.c.
+
Actually depending on what is needed one would not even need the index. In my
+case I did need the index but it’s possible to iterate through the strings by
+blocksize and print out the necessary strings. But that’s obviously wasteful.
+
That extra data is KEY: without it the calculation of the location (V()
+and Z() functions along with the S() macro) WOULD NOT WORK!
+
And although it’s (probably) a horrible idea outside of the contest, having
+near 200 char *s in a single char * (NOT a char *y[]!) is still quite
+interesting and it’s one of the reasons I’m quite proud of it.
+
Interesting thing to ponder: what happens if a string is too long for the
+padding?
+
Conclusions
+
A question: is this well-rounded in obfuscation as the judges like? Definitely.
+
The fact that close to 200 NUL terminated strings are in a single char * (!!),
+the odd looking compound literal, the maze of gotos (116 or 1134 depending on
+if you pre-process the code), the bastardised Duff’s device, the strange labels
+inside switch()s, the jumping into and out of switch()s only to jump back in
+(or out), the for loops split across several parts of the code (one making it
+look like variables are uninitialised), if/else code being swapped in location
+(or moved to other parts of the code, even in what would otherwise be dead code,
+including possibly this for for loops), the fall through of a label to a goto
+that jumps back to right before that fall through just to exit the game (isn’t
+that so cute?), the fact I had to write all those tools to verify things are
+okay (showing how messed up it is), different blocks that have code that simply
+should not be there, the nested ternary operators…
+
As for the gotos: yes I technically have more space. But it became almost
+impossible to add more spaghetti to the pot without it overflowing, and I do not
+want to waste perfectly good spaghetti. There comes a point when there’s just so
+much spaghetti that it’s wasted, if it can even be cooked. I believe I have
+reached the latter.
+
Do you REALLY expect me to add more spaghetti? There isn’t anything that could
+be done, even if it was possible to maintain this huge platter of delicious
+spaghetti without gaining fifty kilograms. Besides, I don’t want to see
+spaghetti EVER AGAIN!! I’ve had enough of it for a lifetime! Okay, that’s not
+really true…it DOES sound good but I won’t likely be having it for a while.
+Can you actually blame me though? This spaghetti almost strangled me to death,
+like it did the Devil (I provided photographic proof of this earlier if you
+missed that).
+
I have already demonstrated several other subtle and unique things but the
+gotos are what really makes it hard to parse; the other things are REALLY cool
+(unlike the spaghetti, at least hopefully) and interesting, and unique (or so I
+think), but those would be much less tasty without the HUGE pot of spaghetti
+(okay, once some of it is put on a plate).
+
If I added more gotos it would be meaningless. A large family might not even
+be able to eat it all without some of it going to waste. The gotos and how
+they’re used make it hard to follow this code, in fact making it very
+unpredictable. It is constantly jumping to unusual places and doing things that
+seem downright illegal. It should not work.
+
But it DOES work. Exactly as I meant. As noted in my concluding remarks in
+my remarks above, I started introducing bugs. It was extremely hard to
+find ways to make the spaghetti even more twisted. How is that even POSSIBLE? I
+don’t think you could manage that with ACTUAL spaghetti!
+
On top of all this: I kept it thematic, in code and data, and the code even
+spells out rude long OREGON TRAIL TRAIL OREGON, plus including other lovely
+numbers that were carefully calculated, to say nothing of all the other things
+you have to look at the code to (try and) discover!
+
And the only necessary -Ds: the #define TRAIL o and that is simply to be
+more thematic; and DATA for portability. None of the macros defined in the
+code are for obfuscation; one is to get past an annoying mis-feature of
+scanf() (that would be S) and others to save bytes. Using a cpp to translate
+the macros only makes it worse to parse anyway but they’re not used for
+obfuscation.
+
As for the goto hell: I will point out that there are so many of them that it
+started to get really hard to even find a place to put another one without
+breaking code (which actually happened several times), there
+were that many jumps.
+
That is not why I put them in unusual places like the switch() between
+cases; that was done earlier on as it was more obscure and also I do not know
+it’s very common knowledge that it is even allowed by the compiler.
+
That’s another issue with goto hell in C: there becomes a point where there
+are so many labels it’s hard to find a place to put another one, not to mention
+running out of single letter labels: which I did, I am pretty sure, and if I did
+not get it it is because of a last minute change. That’s why I had to use two
+character labels, of which there are many.
+
I guess this might have horrified dmr but I don’t know. Either way I took goto
+to absurd levels.
+
Oh and yes: I could have done more with pointers but there was no need and a lot
+of it would just be rehashing old tricks that various authors have used over the
+years. The only pointers necessary are the FILE * and the two char *s, one
+of which is the char * with 172+ NUL terminated char *s (a pretty
+unique and creative thing I think - I certainly have never seen such madness).
+
There would also be no purpose in even having an array of function pointers as
+none share the same prototype and it’s an old thing anyway. Besides it uses a
+lot of bytes for little if not no gain.
+
So there would be no gain in using pointers even more; they’re simply not needed
+exactly because of how I designed it (okay, to be technical, the TRAIL/o
+array is a pointer in a sense and is used like one, to reduce bytes and to
+simplify purchasing, and the t array is done the same only at the forts, but
+these don’t really count in the same way.
+
The blocksize trick is also fun because it allows me to print out (and use as
+scanf() and also printf() the strings just by index, due to extra data. That
+extra data looks like bogus C code. Or is it bogus?
+
One might call the blocksize pointer-ish but is it? It’s only part of one and
+that’s the char *y with the strings.
+
The fact it has goto hell; which the game also has might mean something,
+although that might just be a thematic touch.
+
And of course there are historical references too, as well as historical fixes
+from the original Oregon Trail (though that hardly matters now as it’s almost an
+entirely different game) but also thematic historical references and the nod to
+Duff’s device too (which quite arguably is abuse of C itself too). These are
+nice bonuses and then there are all the jokes as well.
+
The spelling out of things only adds to the mystique and about the only thing
+that might give it away (besides the data source files, which looking at is
+cheating as it’s only for allowing more portability, such as when the system
+does not support printing all emojis.
+
Obviously I had to spell out the name as it’s a long standing tradition in the
+IOCCC. The fact that also uses the (possibly) less known fact that you can
+declare a variable more than once as long as it is the same type, even (iirc) if
+you have it as another statement (i.e. unsigned long i = 5; unsigned long i ...).
+
Oh and isn’t it hilarious how deceptive looks can be? :-) Many people like
+WYSIWYG but this program breaks that tradition in so many ways. It looks wrong,
+you can no longer rely on blocks, you can no longer rely on code being where it
+belongs, you start to question everything you learnt about C. And the best part?
+It all works, just to torment you even more. Yes it’s definitely
+well-rounded, whether or not you can distinguish what is real or not real any
+more.
+
I would not blame you if you are starting to question everything. How could I
+blame you when: if blocks are in else blocks (or other places entirely); a for
+loop’s body is in the body of another for loop with the SAME initialisation,
+condition check and increment steps, even acting on the SAME array but
+doing different things and yet somehow working with no data race; everything
+is in a single switch(); code jumps all over main() constantly; other switch
+blocks and other types of blocks are obscenely long with code that shouldn’t be
+there and so much more; some cases in a switch is polymorphic (in a way); a
+single flat char *y acts like a char *y[] with almost 200 char *, and even
+looks like it is an array; lots of illegal or UB looking code, including code
+that in some cases would be a syntax error but somehow isn’t (e.g. +--); and
+much more? This should not work. But it does. I myself started to lose it and I
+wrote it. I know it intimately and I started to lose my mind.
+
BTW: did you know that in truth that early Microsoft inspired the IOCCC, even if
+Landon did not acknowledge it? The reason it’s not stated in the FAQ/README is
+the fear of frivolous lawsuits :-):
+
+
+
+
+
For those who do not know, vegetable garden is medical slang for the
+comatose ward. Yes medical slang is horrible and yes I’m horrible for using it. But
+this is a minor one. Ask me if you want to know much worse ones. Or don’t. You
+might find them too much and end up with an acute gravity attack, hitting your
+head and reaching room temperature.
+↩︎
+
+**WARNING**: if you have a heart condition please be careful when you look at
+the code. Maybe have a medic nearby just in case. I don't want something bad to
+happen to you. It's bad enough something happened to the author...clearly
+something did. He might have been possessed by a demon. Or the Devil himself.
+Clearly the program has a vendetta against BASIC:
+
+> BASIC taught us bad habits. This program perfected them. Now it needs an
+exorcism because it is possessed by the Devil and is going straight to Hell.
+Tread with caution dear pioneer, tread with caution...lest you become the next
+victim.
+
+The complexity of a program is directly proportional to the number of `goto`s
+it contains.
+
+One of the main goals of this was to take the `goto` count to absurdity and I
+did this in surprising ways. Nothing can be trusted any more in this program.
+Not if/else, not switch/case, not loops, nothing, not even `main()` itself, all
+because of where code is, even in ways that might seem like it would cause a
+data race or UB. But it does not. It looks illegal. It probably should be
+illegal. But it is not and it is so much worse as you'll soon find out...
+
+Let's go back in IOCCC history though: in 1987, with
+[1987/hines](https://www.ioccc.org/1987/hines/index.html), which I believe held
+the previous record for most `goto`s in an IOCCC entry, the judges wrote:
+
+> This program was designed to maximize the bother function for structured
+programmers. This program takes `goto` statements to their **logical conclusion**.
+The layout and choice of names are classic.
+>
+> We consider this to be a beautiful counter-example for Frank Rubin's letter to
+ACM form titled: _["'GOTO Considered Harmful' Considered
+Harmful"](https://web.archive.org/web/20090320002214/http://www.ecn.purdue.edu/ParaMount/papers/rubin87goto.pdf)_.
+See the Communications of the ACM, March 1987, Page 195-196.
+
+(I refute some things in my program that directly contradicts Frank's
+letter in amusing or at least instructional ways in my [remarks above](#devil).
+
+I added bold to logical conclusion because I wanted to stress this. I'm afraid
+they were wrong, oh so very VERY **VERY** WRONG. 24 `goto`s, according to
+`hines` itself, is not the `goto` logical conclusion. I agree it's a beautiful
+counter-example for that letter but oh is everyone in for a HUGE SHOCK!
+
+24 is peanuts compared to what I did. And let's be honest - 24 is ALREADY WAY
+too many, even in a large program, let alone a small one. Even one `goto` is too
+many. Unless I am very much mistaken, I have broken the record by a huge margin.
+
+Here's the horrifying and hilarious truth: I beat it out by 92 MORE, **BEFORE** the
+cpp at 116 and after the cpp is through I beat it by **110** MORE (!!), **AT
+134!** Yes, you read that right. 134 `goto`s!
+
+Even removing what I think are the only dead `goto`s, two of them, including one
+that is in the `w()` macro that would be translated into more, I beat it by 90
+more, at 114 before the cpp, and 99 more after the cpp, at 123!
+
+Did I forget to mention the original Oregon Trail in **BASIC** from 1978 HAS A
+MEASLY 109? THIS SHOULD NOT HAPPEN. Well it did happen and this HAS to be a
+joke, right? I'm sorry but it is NOT a joke. I am for real. There REALLY are
+that many and that is ridiculous.
+
+Okay so it's a joke in another way but nonetheless YES I **REALLY DID** put in
+116/134 `goto`s, depending on if you pre-process it or not! YES I might be mad.
+YES I think it's HILARIOUS. But if it was not for the IOCCC... Well, as I
+mention in my [remarks above](#devil), EVEN ONE IS TOO MANY
+in real code.
+
+The best (or worst, depending on how you look at it :-) ) part is this works. As
+I note in those concluding remarks, a company actually introduced a security
+hole from ONE `goto`. Yet I have 116/134 and it actually works? That is surely
+obscene. And beautiful.
+
+Oh and BTW: it appears that `hines` is a bit confused about my submission,
+though I'm not really sure why. In any case, I not only have dethroned `hines`
+(sorry ...but also not sorry!) but I have, as noted already, beaten the original
+BASIC game by **7** more `goto`s at 116 before the cpp and **25 MORE** after the
+cpp, at 134!
+
+It's almost impossible to add more `goto`s. You'll see why soon. But even if
+that was not the case I wanted room for the other things I did, some of which
+are quite cool and I believe unique as well.
+
+And yes, I agree: the idea of `goto`s considered harmful considered harmful is
+ludicrous, and as you just found out (probably in horror), I have taken it far
+further.
+
+In fact, as you'll find out, every part of this program breaks the rules you
+know about C when it comes to things like: loops, if/else, switch/case, blocks
+in general, where code can be, where labels can be, really everything: the code
+is in all the wrong places.
+
+This is not counting other cool things like a single `char *` holding near
+200 `char *`s. No. I do not mean an array of `char *`s! I mean a single flat
+`char *`! Yet in the code I index it AS IF it's a `char *[]`, just to add to
+the confusion (as if the 134 `goto`s are not bad enough). But it's not a `char
+*[]`. It's a single `char *`, which is the contents of the data file.
+
+There are other things I have done, of course.
+
+This program took two months, to the day, to develop and it was totally worth
+it. But I was almost strangled by the spaghetti, kind of like the Devil, which
+you'll see in a bit. I am thoroughly exhausted as well.
+
+Now as far as the labels go: is it legal to put them where I have? Yes it is.
+Labels have function scope and it is not UB **AS LONG AS** it does not skip
+initialisation. My code does not. Not only are all variables in file scope but
+when I need something set to a specific value I MAKE SURE to do that BEFORE A
+JUMP.
+
+That EVEN includes when two for loops actually incrementing EACH OTHER'S variable
+(which actually happens to be the same variable). They also act on the same array doing
+different things. In fact, the body of each is inside the other loop.
+
+YES REALLY. I went that far. And I did it safely. There is no data race
+whatever. It is diabolical as you'll find out later.
+
+And additionally, as far as UB goes: using `-fsanitize=undefined` yields no
+crash and valgrind is clean on my systems too. Looking at the grammar of labels
+and `goto` and it's all good. Furthermore, labels are **function** scope. In
+particular in 6.2.1:
+
+> A label name is the only kind of identifier that has _function scope_. It can
+be used (in a **goto** statement) anywhere in the function in which it appears,
+and is declared implicitly by its syntactic appearance (followed by a :and a
+statement).
+
+And as for the `_` label that is also allowed per the standard. So yes it's
+allowed: but even if it wasn't it works on multiple systems (macOS and linux in
+my tests) with multiple compilers (at least with linux) and all is good.
+
+But as I noted, I took the joke **MUCH** further than even I anticipated. This
+was possible by repeatedly finding ways to save bytes including reallocation of
+strings and removing some dead code (does that make it undead?) though as you'll
+find if you look at the code there is some code that is dead, some code that
+appears dead (but is it?) and some code that might be dead but can still be
+reached (how is that possible? Obviously `goto` ...).
+
+Frankly if I did not have a twisted sense of humour I would think it went beyond
+the point of funny LONG BEFORE I was done. As it is I would not be amused if
+this was in production code. For the IOCCC though I think it's hilarious. And
+awful.
+
+Even so this program is **VERY WRONG** in **SO VERY MANY** ways, most of all the
+`goto`s (but not in just that way - the single `char *` is probably very wrong
+as well, but there's more). Unless the program I wrote to calculate the `goto`s
+is in error, then the numbers I gave earlier are indeed correct. And I believe
+there is no error at all.
+
+HONESTLY, HOW DID I BEAT **BASIC** in `goto` count? THAT IS WRONG. But I did. I
+beat it. It is defeated. I WIN.
+
+Or maybe I lost. My mind. Obviously. BUT I STILL WIN and whether or not I
+have lost my mind this program sure as hell lost its mind! And it's my fault.
+Hilarious.
+
+Counting whitespace this program is only 4666 bytes according to `wc -c` (macOS
+at the least, maybe others): quite intentionally to be on theme. That's a
+relatively short program to have 116 `goto`s or more when filtered through `cc
+-E` (134!), wouldn't you say? If that's NOT too many, then I ask you WHAT IS?
+
+As said in numerous places, IT IS MUCH SMALLER than the BASIC file I included
+even after stripping it of much of it. My program also has more events. I think
+the BASIC one has 16 not counting the mountains code and mine is 23 not counting
+the mountains code, which obviously I also include.
+
+I discuss this some in my concluding [remarks above](#devil),
+as well as mentioning that there are other events
+besides those 23. I certainly will not reveal all though. The humour and jokes
+sections of that file says more but the concluding remarks are for a summary and
+why I think that this code is worthy of the contest AND also pointing out the
+folly of `goto`.
+
+In this file I will discuss how some events actually are polymorphic, in a
+sense, having at least two different events.
+
+THIS IS ALL OBSCENE.
+
+This amount of `goto`s I have **never** seen especially in a relatively small file
+but frankly ever in a single program. I don't know for sure but I'd guess that
+no program with multiple files has this many. I don't think anyone has ever been
+mad enough to do this before and I SURE AS HELL HOPE that I am right and that
+NOBODY EVER DOES IT AGAIN, ESPECIALLY IN PRODUCTION CODE!
+
+Hell, I wish people would stop using `goto` full stop. Except in the IOCCC. Or
+maybe not after this? Perhaps this ruins it? Perhaps the judges will burn it
+into oblivion like I did? Or maybe they'll drown it in tears (of laughter and
+otherwise)?
+
+They THOUGHT they had already seen the logical conclusion of `goto`s in 1987,
+with [1987/hines](https://www.ioccc.org/1987/hines/index.html), and THEY
+PROBABLY NEVER EXPECTED THIS. Actually, neither did I. But they were wrong.
+VERY VERY WRONG. I might be wrong too. But I still did it. And I'm proud of it.
+If the judges never want to see `goto` again it's totally worth it, even if
+others curse me. I wouldn't blame them. I might curse myself.
+
+If the judges renounce `goto`s I will make no apology (though I'll be a tiny bit
+sad as it's a great technique). There are plenty of other ways to obfuscate
+code, as this program also shows. It's just that the amount of `goto`s here is
+the worst of it as you never know where the program will be next, and that's
+putting it in a simpler way. Much, much, MUCH simpler way, in fact, as you'll
+see.
+
+Either way this program, and I mention this in my [remarks above](#devil) in an
+admittedly long editorial plea (although it does it by going over what I have
+done in simpler terms than this file), serves as a public service, warning about
+`goto`. The article about goto considered harmful has nothing against this, or
+so I personally see it that way. That's because I don't think anyone has ever
+been mad enough to do what I have done.
+
+Here are some fun statistics from a somewhat rudimentary program on both the
+prog.c and after filtered through `cc -E`. First prog.c. Prepare to be
+horrified, if you're not already:
+
+```
+ 116 goto
+ 50 if
+ 11 else
+ 4 while
+ 4 for
+ 1 do
+ 6 switch
+ 32 case
+ 2 sizeof
+ 8 break
+ 0 continue
+ 2 default
+ 8 long
+ 3 unsigned
+ 4 return
+ 1 void
+ 1 int
+ 1 char
+ 1 size_t
+ 1 FILE
+
+ Ratio: 0.83 gotos per keyword
+```
+
+And the pre-processed one:
+
+```
+ 134 goto
+ 50 if
+ 11 else
+ 8 while
+ 4 for
+ 1 do
+ 6 switch
+ 32 case
+ 2 sizeof
+ 8 break
+ 0 continue
+ 2 default
+ 8 long
+ 3 unsigned
+ 4 return
+ 1 void
+ 1 int
+ 1 char
+ 1 size_t
+ 1 FILE
+
+ Ratio: 0.93 gotos per keyword
+```
+
+LOOK AT THAT RATIO! And we could even suggest that `FILE` might not be a
+keyword, but rather a struct.
+
+Whether data types are keywords for this is also something to consider but we'll
+include them as keywords anyway. I don't believe I use any others in any case.
+
+This program is as cursed as the PC (player character) if not much more cursed.
+It is totally bonkers and it was really hard to find places for labels even
+after I put them in bizarre and unusual places. But I get into that in more
+detail later. There are even some cases that are in a sense polymorphic,
+although I am not sure if I bring that up (it's cases 8, 11 and the label V that
+is part of case 8: case 11 jumps to V and then depending on the value being
+checked (`q`) it does different things, maybe even nothing depending on the
+pRNG).
+
+This program is obscene. It should be illegal except in the IOCCC. I believe
+that the Devil wishes they were too:
+
+
+
+I have shown JUST HOW LUDICROUS `goto`s really are and JUST HOW MUCH STRUCTURE
+AND MAINTAINABILITY is lost with `goto`s: a goal of the contest met simply by
+one thing taken to absurd levels. But if this is not the worst or best abuse of
+`goto` I would **HATE** to see worse/better abuse.
+
+**BASIC is BUILT on goto**; **C is NOT** but I have almost **turned C into
+BASIC**, even surpassing the number of `goto`s in a BASIC program in a
+**SHORTER** C program that **DOES MORE**! That is both appalling but
+delightful for the contest. This program is cursed and obscenely and sinfully
+delightful. The `goto`s alone (but there is much more) **DEFINITELY** already
+meet the goals of the contest:
+
+* To write the most Obscure/Obfuscated C program within the rules.
+
+I have followed the rules but I have abused `goto` like I have never seen
+before. It is **FAR WORSE** than flex/bison generated code from what I have seen
+and that is saying a lot as it's notorious for `goto` abuse. It does not come
+even remotely close from what I have seen at least. THAT IS APPALLING.
+
+I have never seen anything remotely close either. BASIC does not count as this
+is the International Obfuscated **C** Code Contest, not the International BASIC
+Code Contest (IO-BASIC-CC) (and thank god the Devil for that!) and I
+beat it out anyway.
+
+* To show the importance of programming style, in an ironic way.
+
+I definitely have done this. The absurdity of this many `goto`s is ironic itself
+but when you throw in the jokes (in the code too) it's far more ironic. By using
+`goto` to absurdity the entire structure is lost. There is no following this
+program. As soon as you think you have the next step it jumps somewhere
+else...and that jump might jump to several other locations to land on its final
+destination: or is it the final destination? I think Hell (probably travelling
+by handcart) might be the real final destination, just like the player character
+(PC) who 'goes straight to Hell'. Actually the sequences of jumps is worse but
+I'll get to that later.
+
+Some of the chains are JUST WRONG. There is a chain that just drops DOWN from a
+label that is at the end of a block only to do a goto which is inside that SAME
+block (the bastardised Duff's device in fact, see way further down), which then
+exits the program.
+
+There are `for` loops that are in different parts of main()! That is ridiculous.
+
+As I noted two loops are intertwined in ways that you would expect to be a data
+race. It's much worse than that. Here is what I mean:
+
+Each of the two loops jump to the other one. One of them jumps more than the
+other but they both start out in what amounts to:
+
+```
+ for(X=1; X < 6; )
+```
+
+but in one it is actually:
+
+```
+ for(X=1; X<--(unsigned){ 7 } ; )
+```
+
+...which is equivalent.
+
+But it's more diabolical. As you saw, it does not increment the `X` so how does
+it work and what does the body of the loops look like? Well...
+
+``` <
+ for(X=1; X<--(unsigned){ 7 } ; ){ goto kk; BB:*o[X]+=(X==2?t[X]*5:t[X]); goto HA; TA:++X; goto at; ZZ:; }
+
+ for(X=1; X < 6; ){ goto BB; kk:if (*o[X]<0) goto LL; goto uu; QQ:V(B=38); goto JJ; at:; }
+```
+
+Now what about the `++X` in the first one? Isn't that the increment of the first
+loop? Nope. That is for the second one. It goes like this...
+
+```
+ if(T<0){ V(46); O=R=E=G=N=0; goto v; LL: *o[X]=0; uu:++X; goto ZZ; }
+ /* ... */
+ } else{ goto y; HA:T-=X[t]; goto TA; A:for(X=1; X < 6; ){ goto BB; kk:if (*o[X]<0) goto LL; goto uu; QQ:V(B=38); goto JJ; at:; } goto B;
+
+```
+
+Notice how the labels end up swapping the location. The first loop goes to `kk:`
+and that is in the other loop. That will end up going to another place, either
+`LL` or `uu`, the latter of which is a fall through from the former. That is
+where the `++X` is.
+
+As for the second loop: first it jumps to `BB` which is inside the first loop.
+It does its thing and then jumps back to `HA` (isn't that funny?) which does
+something else and then it jumps back to `TA` (do you truly feel welcome?) which
+is in the first loop. That does a `++X;` and then jumps to the end of the second
+loop.
+
+Realise this too: these tasks are for each iteration. That means each iteration
+these jumps are happening, kind of like everywhere else.
+
+There are so many other things too...all with `goto`...plus other things, as
+you'll see.
+
+None of this code should be legal. But it is. This code SHOULD NOT WORK. But it
+does. `goto`s are harmful. Anyone who says otherwise needs to seriously think
+about what they do to maintenance.
+
+`goto` TOTALLY DESTROYS maintenance. It causes bugs. And yet everything works as
+I intend it, down to the dead code, code that looks dead but is not, code that
+is dead but can be reached at times via `goto`... THAT IS JUST WRONG. It also
+destroys brains.
+
+This is not good style. It is actually **TERRIBLE** style and HORRIFICALLY
+OBSCENE. I hope I have demonstrated this very well. Actually I KNOW I have. I
+have never seen a worse piece of spaghetti code in C and that is saying
+**SOMETHING**, as I have seen most if not all of the IOCCC submissions. That is,
+as will bring up later, no criticism. Of course I could have missed something I
+suppose (very possible) but on the subject of spaghetti code I think I outdid
+it.
+
+There are a lot of ways to obscure code and I don't believe anyone has taken
+`goto` to this obscenity in C. I believe the one with the most `goto`s is
+1987/hines and, as noted earlier, it reports on itself as having only 24
+`goto`s. Yet I have 116 before the cpp and 134 (!!) after the cpp.
+
+And unfortunately for you dear reader I have done other things that also are
+quite different and totally unrelated to `goto`s. Even so the `goto` madness by
+itself is worth something or some things - including curses.
+
+What kind of curses? That depends on the viewer. I would say it's worth all
+kinds of cursing and I most certainly would be swearing at the author if I had
+to maintain this mess! It is a joke. I personally find it hilarious but that's
+because it's satire, just like the contest asks for.
+
+* To stress C compilers with unusual code.
+
+My guess is that if the compilers were human beings they would be asking what
+the hell is wrong with the author. I guess this because I'M ASKING THE SAME
+thing about myself. The structure of this program went to hell in a handcart and
+I would question anyone and anything not questioning my sanity. Because I sure
+as hell am! Frankly I'm not sure if there is any sanity remaining and it might
+be hard to sympathise with me because I (quite deliberately) caused it myself.
+Still...I'm not suffering: I am enjoying every minute of it, as the joke goes
+(even though that's totally bogus in...uh..reality). I think it's HILARIOUS.
+
+* To illustrate some of the subtleties of the C language.
+
+I have definitely done this. Some of the places I have put labels is very unique
+(or I have never seen them there). Also some of the other obfuscation seems
+downright illegal but is not (and that goes for at least one or two things with
+`goto`s too). I put almost 200 `char *`s in a **SINGLE** `char *` (NO, NOT an
+array of `char *`!). There are other things.
+
+Anyway I'll get to these later.
+
+* To provide a safe forum for poor C code. :-)
+
+If this is not poor code I would hate to see poor code! I'm reminded of the
+joke:
+
+> Always code as if the guy who ends up maintaining your code will be a violent
+psychopath who knows where you live.
+
+...which I believe was said by John F Woods. I don't know about anyone else but
+**I** would hate to have to maintain this code - to say nothing of the fact I might
+want to rip my the author's head off for causing this mare's nest **from
+Hell** that I had to maintain ...write?
+
+If I was handed this code and told to update it to change it to not have the
+`goto`s but still function exactly as I intended it, I would be cursing the
+horrible monster who wrote it. I would also tell them to go straight to line
+22!
+
+Okay I might also laugh at the absurdity but I would want to tell the person
+telling me to update it to go straight to hell. Frankly I would be making FULL
+use of lalochezia (catharsis from swearing - no I did not make that up)!
+
+And frankly, if you expect me to explain how some of this works I will also tell
+you to go straight to line 22!! THIS SHOULD NOT WORK. But it does. It works and
+it should not. This is NOT OKAY. This is a crime against C. It is a crime
+against computer science and could give computer scientists a stroke.
+
+And I won't be paying the bill because there's no point when they're in the
+vegetable garden[^1] from massive brain trauma. Besides, I might be in the pot next
+to them. Just don't ask. I might go insane. If I'm not already.
+
+Go to line 22 instead. It'll make perfect sense if you do this. And frankly, if
+it doesn't, I guess you must have grown up with BASIC. My most sincere
+sympathies my dear friend, my **VERY DEEPEST SYMPATHIES**! Take care of
+yourself. You only have one life.
+
+* To have fun with C!
+
+Well I did admittedly have a lot of fun including with taking the `goto`s to
+peak absurdity - and the jokes of course and the other bizarre things.
+
+This is the worst code I have ever seen flow control wise, and perhaps in some
+other ways too. And I wrote it. I have seen most, if not all, of the IOCCC
+winning entries. That is no criticism. I am in **UTTER AWE** of many of them and
+I feel that many are beyond my abilities; most if not all are after all utterly
+brilliant and I can't know everything. But when it comes to flow control
+madness, this outshines (presumably with fire) them all, I think. If that's not
+true I want to know which one and I want to meet the psychopathic, misanthropic
+author. They might be able to teach me something nice about humanity!
+
+There are just so many `goto`s that a single miscalculation (in labels or other
+things) would cause the program to fail spectacularly. And it would be bad
+enough with just the `goto` nest. Unfortunately (or fortunately) there's a lot
+more obfuscation.
+
+Frankly **if** Hell actually existed **and** it had a programming language, I am
+**certain** it would look like this! In fact the abuse is so extensive that you
+might think that there **HAS** to be a flow control problem. But everything is
+as planned even if you think otherwise; but **if** you **DO THINK** there is a
+flow control issue I would say: I don't blame you! I also thought the same at
+times but there is not. I was so certain of it that I many times directly set
+certain variables to what I wanted to test and it worked out. I was so certain
+there was an unintentional flow problem I had to test it. I'll mention an
+example later on.
+
+But either way unfortunately for you it's **NOT** broken and if you think it is
+you're wrong and will have to try again! Okay: the code is wrong in some senses
+of the word but it's correct code nonetheless. It **should** be a sin but it's
+meant to be this way. It's no wonder the narrator is so twisted and I would
+actually ask what the hell is wrong with him except the narrator is **also** the
+author.
+
+Actually now I think on it... I take that back. I DO want to know what the hell
+is wrong with the narrator too (okay, sure it's actually the voice in the player
+character's head but even so...I authored the narrator)!
+
+I hope you know why but I do not ask for any pity. It's been a true delight in
+writing this totally deranged code and I hope you enjoy it. Although...the devil
+might wish you to cry after looking at it. Certainly he's blubbing too and his
+lachrymal vase is bigger than all the oceans on the planet. I know because he
+told me so!
+
+And yes I am guilty of a crime against C. But I had no choice. The devil made me
+do it. With that said...
+
+**IMPORTANT NOTE FOR THE JUDGES**: this program took about two months to develop
+and I frequently found ways to shave off more bytes which meant more obfuscation
+(and earlier on more events until it got to a point that I felt it was fine,
+even though the alt code has a few more).
+
+It is thus entirely possible that some of the discussion in this or other
+sections to do with obfuscation is wrong in some way or another. I trust you
+understand how that could happen when you look at the code. I had to save my
+sanity and the contest was very close to ending anyway.
+
+The events were so plentiful that I had to go for just more obfuscation although
+I was sorely tempted to add more events. I decided to leave that for the alt
+code instead, as noted elsewhere.
+
+For some hints, which is definitely incomplete and might or might not have some
+inaccuracies, see [deobfuscation.html](deobfuscation.html).
+
+Also I have included a commented version (of the submission, not the alt code -
+sorry, I don't want to fry my brain any more than I have to) in
+[commented.c](commented.c). I did not test compile it after the beautifier did
+its thing. It seems like it should be good if you use the proper command line
+(the define needed for portability and the define to be able to spell out OREGON
+TRAIL TRAIL OREGON without having the ugly `#define TRAIL o` in the code simply
+for `TRAIL` variable which is used exactly once as that name).
+
+HOWEVER: it does not have the latest obfuscation and I'm pretty sure it is
+missing an event or two. As I added more I stopped caring about updating it. It
+was too much for me to cope with and I was running out of time - due to the fact
+this took so long to develop and refine (the jokes in particular but also
+additional events and then much more obfuscation, as I kept saving more precious
+bytes).
+
+Anyway it's ([commented.c](commented.c)) not the game itself (well okay it is
+but it's not the code to compile); it's just so you can get a better idea what's
+going on - within reason: I did not try elaborating again on the gotos. I said
+enough below in this document and I added to it/changed things after the below.
+And even that is unfortunately probably only a small sample of what I did. I
+already wrote an obscene amount so I'll try and limit it somewhat, and by this I
+hope to save your sanity and mine.
+
+I might add to the judges: you might want to take a look at that (commented) code
+too so you have a better idea in design choices (though some of them are listed
+below). Although I'm not really sure how much that's going to help anyone out -
+especially as it was created earlier on and I added way more obfuscation. It is
+also entirely possible that there are bugs in there that are not fixed but that
+are in prog.c. I suspect this is the case, perhaps bullets not being subtracted
+when they're supposed to in some events (like with Blackbeard).
+
+And yes there is some of the same deliberate dead code there but prog.c has more
+(I think, and if so, it might have more than prog.alt.c too). Anything you think
+is wrong (probably due to the spaghetti code from Hell) is very intentional and
+thus features. As noted in various locations some of the 'things that seem
+"wrong"' are actually part of a joke. Other places it's for confusion to make
+one question their sanity even more. Yes I'm probably a sociopath.
+
+As I commented in the commented.c:
+
+```
+ * Finally this code is from an earlier version so some of it might be missing,
+ * not just the events, and not just the gotos, but potentially other things
+ * too, possibly bugs that were fixed in prog.c but are not here (and no more
+ * bugs remain in prog.c). But I believe this is more than enough to give you an
+ * idea though if that is the case. If that's not clear...
+ *
+ * WARNING: this code and its comments are not up to date. I wrote 116 before
+ * filtered through the cpp and 134 after the cpp and I didn't wish to
+ * repeatedly revisit this file trying to explain everything.
+```
+
+I hope you understand but I do believe it's a gain not a loss. It is good enough
+especially as it's only for educational value - or to examine my head (though
+prog.c might be better for that?). As noted the code (and jokes) took a couple
+months to develop and I could not manage adding everything in the end even though
+I tried to keep the structure relatively the same (it's better though - although
+I did fix some actual flow control issues that were not intentional, but it is
+possible I did not update those in commented.c). Frankly it might help give you
+some ideas but it might actually confuse you even more. I'm not sure. Even so
+although you might find it of interest it's not explicitly for you (the judges)
+either. What's more important is obviously prog.c itself along with how it uses
+the data.
+
+The main reason it's (the commented code) out of date is I decided to take the
+`goto`s joke even further - again and again and again - but like I said I also
+made fixes and I also added more events.
+
+Now then... Although the joke is intended (like all the others) I must say that
+BASIC is unique in that it is exactly what I want it to do: it is goto hell and
+that's precisely where I want it to go! I do not want C to go to hell though and
+I somehow made it goto hell too, and as I said surpassing the 1979 BASIC in
+`goto` count (okay in that case `GOTO`): and as you'll see in the code there's a
+literal `goto hell;` (actually more than once) as a joke.
+
+A fun thing is that BASIC is so awful that a part of why this this game is very
+different is when trying to be faithful to the original (i.e. before I decided
+to make a mostly new game) I had to back out of it as it was so large even after
+the data file was in place.
+
+Happily this made me rethink some things and I came up with even nastier tricks
+plus the new and much better theme, turning it into a parody and then mostly
+going my own way with it all, keeping only the route and a few minor game
+mechanics in place. Plus more `goto`s and obfuscation...always.
+
+Some of the abuse of `goto` in my code seems wrong if not downright illegal (but
+hey, isn't that right on theme too? :-) ).
+
+Anyway: can you honestly determine what this program does without running it
+or looking at the data file (with absolute certainty)? I didn't think so :-) At
+best you can take some guesses based on the control flow (IF you can even follow
+it) but nobody can determine for certain, or so I hope. And if they can I wonder
+if they're okay. I wonder this because I wonder the same thing about myself.
+
+The first reason the strings are in a data file (which other entries have done,
+so it's not abuse of rule 2) is because the original strings **BY THEMSELVES GO
+WELL BEYOND BOTH size rules**: I might've said this numerous times. Call me
+paranoid on that rule if you wish. Probably it is especially since many other
+entries also read from files.
+
+Unless you look at the source data files you can only at best guess what this
+program does. Well okay there's that spelling out of `OREGON TRAIL` but that's a
+long tradition in the IOCCC and could be misleading anyway. Indeed it kind of is
+as the strings will show; it's hardly Oregon Trail now - it just takes place on
+the trail. It all had to be carefully designed which also is a good thing for
+the contest. My procedure outlined later in this file will show you just how
+much creativity it took and just how messed up it truly is.
+
+Anyway there's no way to know for certain what this is, or so I can't fathom how
+one could know. And that's assuming you can follow the spaghetti code. Frankly
+to call it spaghetti code is a huge understatement. It seems to me it's a new
+category on its own: perhaps Cthulhu with heavily mutated tentacles?
+
+As I mention later, the data file rather reminds me of the Windows registry (I
+will return to this later in the [Data file](#data) section), which is a great
+thing for the contest and a terrible thing for a non-obfuscated program (thanks
+Microsoft for having a comparison in poor design! :-) ). The best part is
+unlike the registry, my data file simply works, as long as you don't screw with
+it whereas the registry is broken by design.
+
+**IMPORTANT NOTE**: I originally showed some of these in detail but it got so
+absurd and long to show and so hard to maintain as I updated it that I was
+totally overwhelmed by the sheer madness. I am not sure how much I really do
+have here but when you look at the code you'll definitely understand why and
+probably sympathise with me too.
+
+Check `case 11` in the events switch. It does `goto V;`. Now `V:` is **part of**
+`case 8`. But do you see how long the inner switch that is part off that code
+is? In some ways it is actually polymorphic, doing drastically different things,
+depending on the pRNG and which event it is.
+
+At one point I was **DEAD CERTAIN** that part of this that should not be dead
+was dead. But every part of it that is meant to be live is. There was a part
+that was broken but that was fixed. As I noted in my [remarks above](#devil),
+this event (11 in particular, under `V`), will not necessarily do anything, as
+it depends on another call to the pRNG. This is good because otherwise every
+time it triggered it would cause severe illness.
+
+There are many places where a label is inside a block. There are some fun abuses
+of this. For instance did you notice that many times what should be in the `if`
+is actually in the `else`? Sometimes the reverse is true and sometimes the code
+is swapped. The code then jumps back to where it would end up, at least if
+necessary (in some cases it might not be necessary at all).
+
+Here's a funny one which involves dead code but code that can be reached in one
+condition: it just can't be reached by `goto`. It is the `goto heaven;` which
+means it's unobtainable (okay, so the above statement that there are only two
+dead jumps means that there are three, and maybe I missed some, but this hardly
+matters and it's important not only to not trigger a warning - interestingly
+enough despite the fact the compiler should know it's dead - but for the joke).
+But here's how the code actually looks:
+
+```
+ while(i)heaven:{ w(i) } if(!B&&(f||a))
+ {
+ /* ... */
+ }
+```
+
+First of all what is with the label BETWEEN the while (with the condition) and
+the code of the loop (which in this case is actually an `if` because `w()` does
+its thing and then does a `goto hell;`)? It looks even worse with the `{}`s for
+the 'loop':
+
+```
+ heaven:{ w(i) }
+```
+
+And then of course it appears that it would go on to the `if`. But it doesn't
+\- if `i` is non-zero of course.
+
+And that `if` is ugly. Here's what it looks like:
+
+```
+ if (!B&&(f||a)){
+ if(d&&a) V(91);
+ if(T<666)
+ {
+ goto QQ; KK: Q=a?1:Q; h=f?1:h; f=a=0; V(93); T-=666; } else{ goto KK; } JJ:;
+ }
+```
+
+
+Notice how if `T<666` (that's a check if the PC has enough money for the doctor)
+it does a `goto QQ;`. Where is `QQ`? It's inside a `for` loop that has its code
+in another place (yes it's horrible). It looks like (sorry if this changed last
+minute):
+
+```
+ else{
+ goto y;
+ BB:*o[X]+=(X==2?t[X]*5:t[X]);
+ goto HA;
+ TA:goto at;
+ HA:T-=X[t];
+ goto TA;
+ A:for(X=1; X < 6; ++X) {
+ goto BB;
+ kk:if (*o[X]<0) goto LL;
+ goto ZZ;
+ QQ:V(B=38);
+ goto JJ;
+ at:;
+ }
+ goto B;
+ }
+```
+
+
+Notice how `QQ:` does its thing and then jumps to `JJ:`. That label is at the
+end of the if/else inside the if that contains the check for `T<666`. After that
+for loop is amusing: `goto B;` which is where? Close to the beginning of
+`main()`. I will return to that for loop itself shortly as it's hilarious.
+
+Oh but it's far more diabolical than this! If you observe the initialisation,
+condition and increment of that loop you'll see it iterates through `o` via `X`.
+So what you might say. Well this is what. The label `kk`? That comes from
+another loop that does the same thing! Higher up in main() that loop looks like:
+
+```
+ for(X=1; X<6; ++X){ goto kk; ZZ:; }
+```
+
+and so the body would actually translate to something like:
+
+```
+ if (*o[X]<0) goto LL;
+```
+
+But where is LL and what does that do? Well:
+
+```
+ if(T<0){ V(46); O=R=E=G=N=0; goto v; LL: *o[X]=0; goto ZZ; }
+```
+
+So it checks if it's < 0 and then sets it back to 0 if it is. And of course that
+check is in another if block that is totally unrelated. The `goto ZZ;` is there
+as in both cases the end of the for loop has to be returned to. But this means
+the for() loop is split in several places and it's worse than that...
+
+It looks like there would be a data race here. There isn't. Isn't that
+beautiful? I thought so too. As far as what those two for loops do. One is
+adding to what you have after purchasing (at the fort, I think) and another is
+making sure that it's not < 0, setting any back to 0 if necessary.
+
+Another hilarious thing about it. The containing loop is the one that (and I say
+this somewhere I think) it would appear is acting on the array prior to
+initialising the variables. The question you might then have to ask is: in that
+case, which initialisation is being used - or is there any?
+
+As for the beginning of `main()`. Did you notice that the `return 666;` is close
+to the beginning of `main()`?
+
+Going back to that for loop with `BB:`. Did you notice how `BB` comes before the
+loop? And then it jumps forward and backwards and so on. Here's what it's like
+in fewer lines so you get a better idea:
+
+```
+ BB:*o[X]+=(X==2?t[X]*5:t[X]); goto HA; TA:goto at; HA:T-=X[t]; goto TA;
+ A:for(X=1; X < 6; ++X){ goto BB; kk:if (*o[X]<0) goto LL; goto ZZ; QQ:V(B=38); goto JJ; at:;
+```
+
+So the body of the loop is actually outside of the loop. That body jumps several
+times only to land back at the end of the loop - which so happens to be after
+`QQ:` which I brought up earlier - and which starts from another place entirely.
+This for loop is the one that would look (to the uninitiated) as using the
+variables before they're initialised. Maybe I have not shown this yet. Apologies
+in that case.
+
+But if you look at the code more carefully you will see that the else block that
+contains it all does an immediate `goto y;` which means the loop can only be
+accessed by a different `goto`. That is the `goto A;` which also close to the
+beginning of `main()` (if at the fort).
+
+Of course as previously noted the `kk` label is another for() loop that actually
+increments `X` as well as acting on `o` (`o[X]`). But of course in the other
+one it's further apart from the loop, exactly so it looks like it is
+uninitialised but isn't. I would move it further away but I wanted to mislead
+further. The fact that the `kk:` label (part of the other loop that is acting on
+`o[X]`) is right there and you can see in the containing loop that it's also
+incrementing `X` could easily be mistaken for being part of the containing loop
+rather than the loop inside of it (which doesn't look like a loop at all). All
+you have to do is miss the `goto BB;` OR, after all the `goto`s, start to
+question your judgement: is it really jumping somewhere?
+
+Additionally for all you know the `goto BB;` might land at `kk:` indeed some
+code like that actually exists (or so I think). Sure you can see to the left of
+the loop that it doesn't, again assuming you're not overwhelmed with the sheer
+amount of `goto`s, but it is far more confusing to make one wonder if it's a
+data race. But like I said it's definitely not a data race due to manipulation
+of the flow control.
+
+As for the loop itself: because of the `at:` at the end and the several jumps,
+the body of the loop is in several places, jumping **behind** it only to go a
+bit forwards (by skipping a label and `goto`) which does something else and then
+goes back to that label that was just jumped over which then jumps to the end of
+the loop (the `at:` label) - for its next iteration.
+
+And as for `QQ` that simply prints a message, setting the variable that the PC
+can't afford the doctor (saving bytes in the process by doing `B=38` in the call
+to `V()`). Then it jumps back to where it started - or actually the end of that
+if/else chain which then carries on to the next part of the code.
+
+That will end up doing `goto z;` which is at the end of the do..while loop in
+the bastardised Duff's device.
+
+I do like that the code spells out `HAT` and if you use your imagination a bit
+`T-=X[t]` could look like text (or more like `TEXt`.
+
+There are other for loops that have similar and, as I said, if/else that have
+this too, with labels and jumps to lead to confusion and making it almost
+impossible to go through in a debugger one instruction at a time - at least
+without going partially (or completely) insane.
+
+A couple more devious `goto` ones. At the very end of main, long after the
+`return 666;` and right after the do..while loop, you'll see `goto _;`. Now
+where is that `_:`? It's somewhere in the obscenely long switch at `V:` which
+has a lot of code (including another switch) that does not belong there. It is
+so long that it is hard to know if the case statements are part of the `case
+8`/`V:` or not.
+
+In any case the `_:` in turn does `goto rr;`. And where is that? This is
+hilarious. Although you'll see part of the bastardised Duff's device I will
+return to that more later on. Anyway:
+
+```
+ int main()
+ {
+ switch(1)
+ {
+ j:if(z)goto A; E*=5; B:
+ printf(&y[Z(12)],T); if(z) { goto f; } goto PP; default: srand(time(0));
+ K=fopen(DATA,"r"); if(!K||getdelim(&y,&J,EOF,K)<0)
+ goto hell; goto M; OO: if(b<1) { if(a){ w(40) PP: goto G; } if(f)w(41) w(45) g:goto S; } w(M>2169?47:45)
+ hell:
+ return
+ 666; rr:;
+
+ goto OO;
+
+ /* ... */
+ }
+ }
+```
+
+(Yes all of main is in the switch - will get to this later on.)
+
+Observe how the `rr:` is in that switch block (along with other things that
+shouldn't be there but obviously are) and it simply falls through to the `goto
+OO;`. Where is that? Well look carefully: it is in that same switch, right
+before the `rr:` itself! It checks hp/stamina and then depending on that and
+other conditions it ends the game with different messages. Isn't that just
+brilliant?
+
+Oh but there is some extremely devious things here. I'll return to that when I
+get to Duff's device (or the bastardised form).
+
+There is more nastiness with `goto` but like I said, if you expect me to explain
+everything I refer you to line 22. That being said I will get into some that are
+indirect - like how I get into the loop of the bastardised Duff's device, and
+when asking: how the hell does the switch at `V:` even work? The same question
+for the `if (q>9)` block and in that case the `switch(x(1,2))` inside it. This
+should not work. But it does. It is wrong in the worst (i.e. best) possible
+ways.
+
+Anyway I leave the rest of the `goto` madness to you, again except indirectly in
+a few cases, and maybe one or two that come to mind that might be worth special
+mention.
+
+There is just too much to go through and I think you have more than enough
+ideas. If not do check the code out - unless you have a heart condition, at risk
+of stroke (especially if you're a computer science teacher). If these apply,
+please look at it with care, as I mentioned above. One soul (or two if you count
+the PC) lost is too many. Don't make it a second (or third). One person, the
+author, is enough.
+
+What in the hell is this?
+
+```
+ x:V(X+--(unsigned){ 6 } );
+```
+
+You might have seen the compound literal in a similar way before but have you
+ever seen it do `+--` as part of it? Isn't that illegal? Ah. Well to be blunt:
+no it is not. All this does is prints out the string that is at `X+5`. But
+doesn't the `+` followed by the `--` looks so wrong or indeed as suggested,
+illegal? Shouldn't you get an expression is not assignable like the following
+code?
+
+```
+ i+--5;
+```
+
+**HOW IN THE ABSOLUTE HELL** is it not? Wouldn't the `+--` be the `+` operator
+and then the decrement operator (you'd expect a variable that can be incremented
+to the left or right!)? That's not how it works. It looks wrong and FEELS wrong
+but it is not. Nonetheless it functions correctly. Here's the trick.
+
+The `+` is attached to the `X` and the `--` is attached to the compound literal
+array with the value 6, thus making it as noted `X+5`! Isn't that lovely?
+
+Amusing thing to ponder for you. You noticed, no doubt, earlier where with a
+compound literal like above I had an expression in a for loop what amounts to `X
+< 6`, i.e.:
+
+```
+ X<--(unsigned){ 7 }
+```
+
+The reason I used `unsigned` is because X is an unsigned int. Without that that
+would trigger a sign compare warning. So how come I would not get it if I had
+above as:
+
+```
+ x:V(X+--(int){ 6 } );
+```
+
+...when the loop that calls that actually is comparing? I just gave the answer
+in the very question if you need a hint.
+
+Do you remember Duff's device? I have a twist on it. Or perhaps several.
+Actually it doesn't really look like Duff's device, except that there is a loop
+inside a switch. But that's not really the confusing part, even if it's not
+right.
+
+`main()` in its **ENTIRETY** is inside a single switch. This includes seeding
+the pRNG, opening the data file, reading it, every last part. Read that again if
+you need.
+
+The default case sets things up but it looks like it should not work. But you're
+wrong if you think that. This is the beginning of main():
+It looks like this:
+
+```
+ int main(){
+ switch(1)
+ {
+ j:if(z)goto A; E*=5; B:
+ printf(&y[Z(12)],T); if(z) { goto f; } goto PP; default: srand(time(0));
+ K=fopen(DATA,"r"); if(!K||getdelim(&y,&J,EOF,K)<0)
+ goto hell; goto M; OO: if(b<1) { if(a){ w(40) PP: goto G; } if(f)w(41) w(45) g:goto S; } w(M>2169?47:45)
+ hell:
+ return
+ 666; rr:;
+
+ goto OO; yy:
+
+ /* ... */
+ }
+ }
+```
+
+Now one might wonder: obviously the `goto A;` is not executed first because it's
+not part of a case/default. Well maybe some would think otherwise but it's not.
+
+But then...how can the `goto M;` in the default allow ever getting to the other
+labels? It's all due to the `goto`s. The label `yy:` as you're about to find out
+is the do..while loop.
+
+Obviously, since main()'s entirety is in the switch, the game loop is entirely
+in the switch too. There are other switch() blocks, with some nested, as
+previously shown.
+
+Of course the loop can be exited and re-entered as you already probably noticed.
+Getting to the beginning of the loop, i.e. the `do`, is confusing as well.
+First, after seeding the pRNG and opening and reading the data file, assuming no
+errors occur (in wrong directory or missing file for some other reason, file not
+readable, getdelim() returns an error etc.), it does a `goto M;`. Of course it
+might look like it does a `goto PP;` but that's not right.
+
+`M:` happens to be inside a switch that is totally unrelated, in fact either
+purchasing at the fort or maybe all purchasing, though that's after another jump
+(`v:` is important to clear out the `t` array). So it jumps to `N:`. Now this is
+actually inside the do..while loop. Yet the loop has not really started just
+yet. `N:` is inside a switch, I think a three level nested one, depending on how
+you count levels, though I might be wrong. Anyway that does a `goto Q;`.
+
+`Q:` in turn is inside an if block but safely as the first statement of the if
+is to jump somewhere else. Instead `Q` starts a loop. This is sneaky. It
+iterates through `X` (until 6) but each iteration goes to `x:` which allows for
+purchasing, either at the fort or initial, and then it eventually jumps back to
+the end of the loop. Of course `x:` is used in other cases too.
+
+Once the loop is done it jumps to `j` which is the first part of the switch
+containing main()'s entire body. If at fort it does `goto A`; otherwise it sets
+up the amount of bullets you have based on how much you spent (using the same
+variable of course - because why would I want to use another variable, even if I
+have to scale in both directions?) and finally prints stats!
+
+At that point, and this is hilarious, if at the fort (didn't I just check that?)
+it jumps to `f:`. Otherwise (and again isn't this similar - both if and else but
+without the else) it jumps to `PP:`. Are we done yet? Afraid not...
+
+It jumps a short distance (that appears to be part of the default except there's
+a goto - or several, including the `goto M;` which started it all) inside an if
+(`PP:` is). After a call to the `w()` macro.
+
+That might suggest it always runs off, even when a is non zero and
+b < 1 (neither of which are relevant at this point) when the do..while loop
+(which at this point of main() has not even been reached) is over.
+
+But of course it doesn't because `w()` does `goto hell;`. So `PP` because `w()`
+does a `goto hell;` which is also short distance away. But instead it does a
+`goto G;` - and if you guessed that that is inside the loop you're absolutely
+right: also to the right of a w() (I will return to this). This jumps to the do!
+Finally there.
+
+What this means is that even before the loop is started, and also after the loop
+is started, both during the game and at the end, it leaves the loop, which of
+course is inside the switch which has the entirety of main(). But this does not
+destroy the state. And like I said, it does not skip any initialisation as the
+variables are file scope so no UB invoked.
+
+Basically there is no guarantee what might happen next. You never know because
+it's constantly jumping inside and out of blocks, blocks that are totally
+unrelated, often in what seems totally illegal and what should not work, even
+that seeming data race I brought up. But it all works exactly as I mean (again,
+including code that is either dead deliberately or seems dead but might or might
+not be). So again if you believe you have found an execution problem you're
+simply wrong.
+
+But when it does get to b < 1 if a is non-zero obviously it'll go back to the
+loop, right? Well again no because `w()` terminates the program.
+`goto G;`. More fun!
+
+So on that label: it goes into the do..while loop (in a few nested blocks full
+of code that should not be there) in what seems like a reachable place in other
+times - only to jump outside of it to...enter it..to exit..to enter...? That
+can't be right.
+
+Well it is right. So is this one:
+
+```
+ if(!x(0,3)){ w(x(0,4)?84:x(0,4)?33:34) e:if(O>39){ V(e=x(0,1)?18:19); O -= 40;
+ goto q; d:{ if(!v)goto TT; goto P; } } goto U; }
+```
+
+Yes there is even a block inside a block there: the `d:` is inside the `e:`
+label block (or its `if` anyway). After that is another unrelated if. In the
+case that the d/e block is/are entered it will go elsewhere in main() though,
+even though the code would never be executed if the containing `if` were
+entered.
+
+Did you notice this block?
+
+```
+ D:{ if (k()) /* ... */ } goto s;
+```
+
+It is obscenely long, wrong and has code that should not be there. But of course
+that's why it has to be there and why it works.
+
+What this all shows is that not only can you no longer anticipate where the code
+is about to be but you also can't rely on blocks at all any more. Blocks are no
+longer blocks as you knew them. They might as well be a red herring since blocks
+can be used for opposite (at best) code. In fact in this program you basically
+cannot expect the rules of C to apply - because they don't.
+
+You have if/else that have been swapped, starting with a `goto` to where the
+code really is, and, depending on how it's constructed, the code might just fall
+through to the end of the if/else chain, or it might need another goto.
+Sometimes if and/or else code is/are in other unrelated places entirely. These
+if/else blocks might also hold code that do not belong to them, even what would
+otherwise be dead code. Loops are even worse with this.
+
+There are for() loops that jump out of the loop with a label at the end of the
+loop for the next iteration. It might also have code from another place that
+really doesn't belong there.
+
+One for() loop actually takes that even further by jumping back to before the
+loop, then a bit forward (jumping over a label), then that jumps back a bit to
+do another part, then it jumps to the end of the loop for the next iteration.
+But the body of the loop actually has other code for something else, maybe
+another loop or maybe an if/else or something else. Obviously in the loop it
+jumps back.
+
+There is even code that is split into several parts of main(), like at least one
+or two for() loops, sometimes even with code that belongs to other blocks
+entirely, just to make you question reality: even when the code is in a loop it
+might not be physically in the loop, just like with if/else and other things.
+Some of that might have been shown already. But this is sheer manipulation in
+the worst (i.e. the best) possible ways.
+
+There is even code that falls into code that jumps to right before the code that fell
+through to that jump (yet it somehow does not go in an infinite loop), just to
+make you question reality even further.
+
+Everything (or most everything), is inverted, backwards (sometimes going
+physically backwards in main(), only to then go forwards again, or somewhere
+else entirely) and just wrong. This should not work. The fact it does work makes
+it even worse.
+
+Nothing is necessarily what it seems to be. Do you understand how wrong this is
+yet? Unfortunately (or fortunately :-) ) sometimes things in this world that are
+wrong are actually right at the same time. It is unclear at this time if this
+still applies to the author's sanity.
+
+Oh and yes. There was another set of goto labels I should have mentioned as it
+involves what would otherwise be dead code. This:
+
+```
+ R:if(R<14)V(37); if(z) { z=0; l: {
+```
+
+code, and in particular, the `if(z)`, is actually dead. But of course the labels
+inside it are not. That `l:` block belongs elsewhere.
+
+As for the `z=0` it is there to mislead you into thinking that code resets `z`
+back to 0 - but it's totally irrelevant. In fact even if it did enter, for
+instance if the author did something stupid, it wouldn't matter (well other than
+the other code being executed) because the else block also sets `z` to 0. Well:
+not quite. But it is set back to 0. Here's the hilarious part. Inside that if is
+a switch (that is reached via goto) that depending on the case actually sets `z`
+to 1 which seems so counter-intuitive.
+
+One more thing with `goto` that is hilarious that I just remembered. Check this
+code out:
+
+```
+ if(x(0,1))goto I; R:if(R<14)V(37);
+```
+
+What is that label `I:` about? This is brilliant. Next to what would otherwise
+be dead code, again due to `w()` (which btw is NOT for obfuscation - it's to
+save bytes and to be able to do `goto hell;` from anywhere in `main()` with two
+messages, the one passed to it and the final message) it does `goto a;`. Now
+`a:` is in some switch between a break and a case (looks like it must be the
+events switch). This `a:` does a `goto H;`. Now `H:` (and again this is
+throughout `main()`) does a - and this is horrible - `goto R;`.
+
+Yes. This means that it sends you all over the function only to end up right
+where it left off, doing absolutely nothing. In other words it totally misled
+you into thinking something important might happen. Isn't that hilarious? I
+thought so too! :-)
+
+If I may, I'll repurpose the word spaghettification (yes it's a real word) by
+saying that that is what I did to this program in the worst (i.e. best) possible
+ways:
+
+> Spaghettification: the art of making code almost impossible if not impossible
+to trace; compare to `goto`, an invention in some computer programming languages
+where the programmer wants you to have so much stress that you swear yourself to
+death and go to hell for using the lord's name in vain.
+
+(to stay on theme - I don't really know anything about whether that's true or
+not.)
+
+Anyway: have fun following all the `goto`s! I have never seen anything so abusive
+of `goto`s and I hope to never again. It's appalling especially in a relatively
+short program.
+
+I believe I have used every single single letter label, as well as `_`, which
+makes it so that every single character label is used. What's more is that, as
+can be seen, many two character labels have also been used. That's expected with
+the amount of `goto`s but it's worth pointing out. I might have missed a single
+character one but I don't think I did.
+
+A number of nested ternary operators.
+
+The data (with amusing output of `file data`, see below) bears special mention
+as it was cleverly designed to both hide and make it exactly as I need it (in
+multiple ways actually). See [Data files](#data).
+
+Did you know that it's legal in C to declare a variable more than once? It's
+only legal IFF (if and ONLY if) it's the same type but this is how I managed to
+spell out `OREGON TRAIL` even though it's using `O` and `R` twice. I don't know
+how well this little bit is known but I don't think it's that well known; I
+certainly have never seen it documented anywhere and only discovered it on my
+own years ago.
+
+Also as you might have noticed in the `TRAIL` array I use `O` twice (in the
+definition) but I only use it once in the code, namely the second one; the
+second one so I can just iterate through it and the strings in one pass (this is
+also why the `t` array is of size 6, not 5, or actually 7, since I also have `I`
+to shorten code). But this way I can spell out `OREGON TRAIL` and then `TRAIL
+OREGON` (and something else which also kind of describes the game, see below)!
+
+Here's what it ended up as:
+
+```
+ unsigned m,D,Q,v,l,Y,f,X,z,B,i,h,
+ r,u,d,e; long
+ O,R,E,G,O,N, T,R,A,I,L,
+ *TRAIL[]={ &O,&R,&E,&G,&O,&N} ,a,t[7],q,M, b=666,c,W;
+ char *y,*p; FILE*K; size_t J;
+```
+
+So there you have it: the code suggests a rude OREGON TRAIL but it's definitely
+not that! :-) Okay it might be in some ways but it's a parody meant to be funny,
+and much of any rudeness if not all has to do with the imagination of the
+player, since the jokes can be interpreted in numerous ways, and deliberately by
+design. Anyway, the idea is it helpfully tells you what this: pretty important
+given how screwy the logic is.
+
+Oh and if I may: it might also spell out 'rude long OREGON TRAIL TRAIL OREGON'
+which of course it was long.
+
+The `TRAIL` variable is actually `o`: it's defined in the Makefile because it
+would be ugly in the code but having it allows for the tradition of IOCCC
+programs spelling things out (it's only used in that one place - I use `o` in
+all the other places as it would take way too many bytes; the only reason I even
+have it is for that tradition). Okay it actually allows for swapping the order
+as it's already spelt out. But still. I could of course just have `o` but to
+save a measly four bytes (which is why I'm not concerned about using it) but
+that might not be enough for anything meaningful so this is much better.
+
+After I talk about the [Data files](#data) I will discuss how this is definitely
+well-rounded in obfuscation.
+
+
+#### Data file: more obfuscation and portability and ensuring it can be used properly
+
+
+**IMPORTANT NOTE TO THE JUDGES**: if any problems in the data file exist,
+remember to regenerate it as described in the Judges section and/or the
+Troubleshooting section in the [remarks above](#devil). It is greatly
+appreciated that if by some chance you do run into a problem that you do this
+quick procedure (the addpadding `-d` option can also be used to reveal what the
+program is doing for those who wish to see more, although trying to play the
+game after this will print out rubbish - see below).
+
+Remember that if by some odd chance the program segfaults that you **MUST**
+create the data file anew. I don't think it'll happen but just in case. Of
+course if the data file is missing (which would suggest a user error) or
+`getdelim(3)` returns an error (not my doing) then the game will simply exit. So
+just make sure the data file is recreated. Thanks!
+
+As I note elsewhere (I think I did) there's a very good argument to have the
+compilation rule always run the addpadding program, and that's what the Makefile
+does (unless I missed it in a rule) **BUT EVEN IF** that's all good, if there
+are **ANY** issues **PLEASE** run the `addpadding` tool manually (or better yet
+`make makedata`).
+
+The data file key is part of the obfuscation both in code and in data; it also
+stays on theme. As noted in my [remarks above](#devil), I have bypassed the
+concern of SUS portability by including my own tools, much like previous winning
+entries did with POSIX compatibility.
+
+I finally added the test rule to the Makefile to be sure things are sane too,
+although this cannot detect that the messages are correct entirely. Still
+everything is as meant.
+
+Anyway the obfuscation.
+
+Before I can explain what I did do I need to explain how the file is used.
+Briefly for the moment: I'll explain how this all works in more detail, later
+on. The file is loaded with `getdelim(3)` with the delimiter being `EOF`. That
+loads the entire file in. But the file has NUL bytes (I added these manually).
+The NUL bytes are key and I'll return to that soon.
+
+I was not sure if `getdelim(3)` would actually stop at the NUL byte. A test
+program showed it does not: exactly as I needed for what I had in mind! This is
+where it starts to get really clever.
+
+Rather than having to have so many strings in the code (therefore taking it
+**WAY** past the rule 2 limits) I have it in the data file. But to obscure how
+it's done (and to help not have to have it line based or have to keep
+referencing the `line[]` or whatever it might end up being) each line ends with
+a NUL byte.
+
+As I'll make clearer soon this is not a `char *y[]`! It is a single `char
+*y`. No arrays here. The hilarious part is it looks like I'm using it as an
+array of `char *`. I'll return to that later on too.
+
+There are seemingly bogus strings in the data file too but the first one
+actually does matter, even though it shouldn't (as in doesn't need) a NUL byte.
+The last one might or might not have a NUL byte either but that's just nonsense
+anyway and it does not matter one bit, even if it's many bits and actually quite
+a few bytes, longer than the blocksize I'm sure.
+
+These NUL terminated strings inside the single `char *y` only have a newline
+when necessary. This way I do not have to worry about printing a newline or not.
+
+The NUL byte with the padding serves numerous purposes. And actually as long as
+the string is short enough to fit into the blocksize (with the NUL byte too) it
+could realistically work without padding, but I don't think any string is that
+long. The first string (that is not part of the game but does matter indirectly)
+actually has no NUL byte.
+
+Obviously the NUL byte is critical as it allows me to just stop without worrying
+about it. Why bother with trying to figure out the length when the format (the
+padding/blocksize and NUL bytes) do it for me? When `*p == '\0'` the loop ends
+and everything is done.
+
+The procedure was obvious multi-step. I had to create the source file and then I
+had to create the data files. I needed a tool to do that.
+
+Now if I wanted to print out every string in a sequence, there are multiple
+ways. Some of the tools I describe and include do it differently, some even using
+a hack (those were created very early on and simply to verify things - they are
+only included so you can see just how much care I put into this all). But in the
+prog.c I just do a `printf()` at the right index while there is no NUL byte. It
+looks like a `char *y[]` but it's not. I'll get to that later.
+
+I hope you're starting to see the brilliance here but to put this a more
+interesting way, as hinted earlier: this is like CLOSE TO 200 (!!) `char *`s
+**inside a SINGLE** `char *`: one `char *` is all it takes (!!) but there are
+174 (currently, it's changed so many times, if we count the bogus ones, one of
+which is actually needed in that if it did not exist the indices would be wrong
+in prog.c, printing the wrong strings, and that could also lead to a security
+issue, potentially, given the format specifiers in some).
+
+Some of the unused strings are just jokes for people to discover (or for the
+judges to enjoy). In other words I suggest you go through them. Some of the
+strings are remnants of the original game and are totally irrelevant. That was
+when I first started and was going to try and make Oregon Trail rather than what
+it is now, A Pact With the Devil On the Oregon Trail.
+
+If you look at the files you'll notice they also have something else.
+In particular, it has the following C, though it can be cut off depending on
+blocksize and length of the string in question. It is also a reference to the
+joke I mentioned about BASIC (and what I obscenely did to C too: a blatant crime
+against C):
+
+```
+ ha_ha(){hell:goto hell;}main(){goto hell;hell:goto hell;ha_ha();main();goto hell;}
+```
+
+That padding is also critical, as it's how I get the right location in the `char
+*y`.
+
+As for `file data`:
+
+```
+ $ file data
+ data: data
+```
+
+:-)
+
+As for printing, these routines are key:
+
+```
+ long Z(long x){ return x * 1663; }
+ void V(long x){ printf("%s",&y[Z(x)]); }
+```
+
+Do you now see how it LOOKS like a `char *y[]` but isn't? It's a flat `char *y`,
+as noted earlier: the arg to `printf()` implies `y` is an array of pointers but
+it's actually just a pointer. The indexing works because I treat it AS IF it's
+`char *y[]`, and the compiler doesn't care one bit. The reader, however, might
+start to question their sanity, upon learning this fact, possibly even calling
+me a horrible monster. Because obviously I am. Or perhaps I'm the devil? You
+decide.
+
+Obviously the NUL byte is required to make sure everything works right. The
+padding ensures that we can easily calculate where to start.
+
+The comment at the top of the data file:
+
+```
+ /*useless code below, goto end of file*/
+```
+
+is a misdirection especially as at the end of the file (which actually has the
+contents of `prog.c` itself) has:
+
+```
+ /*useless code above, goto start of file*/
+```
+To get everything set up and tested required a few programs and pipelines but
+they work well and it's perfectly safe manipulation (even if devious) as long as
+the data file is correct. And as I include the tool that is not a problem.
+
+These tools are vital, or at least some of them are.
+
+I wrote these programs (amongst others not included and not needed). As you'll
+notice (if you look at the description and/or the code) some of them are
+similar. Some might do almost or exactly the same thing as another but might be
+done differently. I'm not sure: it does not happen on my systems but if a string
+prints in the wrong way it would likely be your system.
+
+NOTE: the other tools that have the `V()` code or similar have it in a macro; it
+was not worth updating in them when I changed it to a function in the
+prog.c/prog.alt.c.
+
+Hopefully I have described these tools okay. If not apologies. I only include
+them so you can see how much I put into designing the system.
+
+- [bytetest.c](bytetest.c) prints every string extracted from the `data` file
+(at least those that are used by the `V` function i.e. it doesn't print the
+bogus two strings) with a location so I can know what chunk to use in the code.
+This became unimportant with `bytecount.c` described below.
+- [byteread.c](byteread.c) prints out the strings without the location printed and
+without caring about the NUL bytes. (Can you write something similar without
+looking at it?)
+- [bytecount.c](bytecount.c) prints out each string with each location but it
+reads the source data file so it's cheating.
+- [bytecheck.c](bytecheck.c) reads in (by default) data.src and prints out
+single-byte characters (so non emojis); and with the `-i` option I can read in
+the `data.asc.src` file and in this way, with `less(1)`, I can make sure that
+the strings are the same (well as noted somewhere some of the strings ARE
+different in the different files). For those who have a fully capable emoji
+system this is not important. See also further down for a tool that writes the
+string number that has a multibyte character.
+- [printer.c](printer.c) prints the strings as if the game was doing
+it. It should however also print out the `%` conversion format specifiers intact
+which the game does not have to worry about doing it that way.
+- [addpadding.c](addpadding.c) this adds the proper padding from the data source
+files, writing to the respective data files. THIS IS CRITICAL! Without this
+everything breaks!
+- [lencount.c](lencount.c) counts strings and reports longest one (can you
+figure out why this was needed? If you guessed the blocksize you're absolutely
+right). The `-t` option is useful to verify (without showing the longest string
+which can make it hard to miss) that no string is (in length) >= the blocksize.
+- [mbcheck.c](mbcheck.c) shows where multibyte (2, 3, 4 bytes) characters are in
+a file, by default the ASCII only file so that I can make sure everything is
+okay. This tool kind of obsoletes bytecheck.c and almost makes that tool
+useless, except in helping to identify if the strings are the same number (which
+they should be). Note that the counting here is interesting so that it might
+look like the wrong number of multibyte characters but this was not worth
+worrying about as I just wanted to make sure no multibyte characters slipped in
+(as noted somewhere I once copied the emojis file to the ASCII only file when
+doing a rewrite of the jokes). It might also not be: it might just seem that way
+to me.
+- and some others mentioned below (and possibly some not mentioned).
+
+If any mentioned above or below are missing (some intentionally so, possibly):
+apologies (and also not sorry) but they're not important for the game.
+Everything that is important for creation of the data files, the test rule etc.,
+IS included, and that's what matters.
+
+The [strings.loc.txt](strings.loc.txt) (which if there was the concept of a
+spoiler this would be A **HUGE ONE**!) has the location of each string based on
+the blocksize. The [strings.asc.loc.txt](strings.asc.loc.txt) is the ASCII only
+counterpart: the one that is for `data.asc`. The
+[strings.scrnshot.loc.txt](strings.scrnshot.loc.txt) is for the screenshot
+friendly one.
+
+Of course even with these files it does not make it easy to parse the code
+(prog.c) as you have to go back and forth and the order of the strings is not
+sequential, some strings are not used (by design) and some have multiple
+versions (sometimes more than one is used and sometimes only one or even none
+are used).
+
+One of the reasons I added the (unused for prog.c/prog.alt.c) macro `BLOCKSIZE`
+is so I didn't have to repeatedly update the other tools when things changed
+(which did happen several times as previously noted) (see below for more
+reasons why).
+
+The file `bytes.txt`, which is created by [makedata.sh](makedata.sh) (and not
+included for this reason), has a list of `` (one per line) where `n` is the
+location (based on the blocksize) of each string. These files are used to create
+the `V.c` file (which some of the tools use - which is why it's included) and
+all of this can be created by:
+
+```
+ ./makedata.sh # or make makedata
+```
+
+The script also creates the [strings.loc.txt](strings.loc.txt),
+[strings.asc.loc.txt](strings.asc.loc.txt) and the
+[strings.scrnshot.loc.txt](strings.scrnshot.loc.txt) but these I included as
+they seemed very useful to see how I developed things; at one point I included
+the others (the bytes.txt, bytes.asc.txt) but as more tools were necessary I ran
+into the file limit and these were the ones that weren't strictly necessary.
+
+There are a number of reasons I did not use the blocksize macro in the prog.c:
+first it's not needed and would use more bytes; and second because I feel like
+most people are more intimidated by numbers than words even if it translates to
+the same thing (the [V.c](V.c) is built from `bytes.txt` btw). As noted the
+reason for the macros are not for obfuscation but simply to save bytes. In some
+cases a function would have been ideal but when tested did not work as I had
+hoped (it can save bytes depending on the macro and its use).
+
+The original test was in `nultest.c` (not included) which tested if `getdelim()`
+with `EOF` would stop at the NUL bytes.
+
+I originally had to test by skipping (when a `%` is encountered) one byte past
+it. Then I added other specifiers that were more than one byte. The solution is
+that (and this allows for easy printf calls) it also ends in a NUL byte! So
+every string ends in a NUL byte (and if space allows a padding, or a padding
+repeated as is often the case). That is why I had to carefully select and verify
+that the blocksize was okay. The `nultest.c` file was just a quick test and
+only was a test to see if my concept would work. Once I confirmed it seemed good
+I had more to do.
+
+But like I said, as this has changed too many times I am not going to get into
+the initial procedure beyond that (the code can speak for itself - and perhaps
+part of the Makefile) other than to say that the important programs are
+`addpadding.c` and for personal reference `printer.c`, `byteread.c` and
+`mbcheck.c` - perhaps a few others but many are not necessary in the end. Okay
+actually mbcheck.c is important for the submission too as it's part of `make
+test` - as is `lencount`. If I did not include one it's not important and not
+instructional either. I have included everything that is needed, however.
+
+The files `data`, `data.src`, `data.asc`, `data.asc.src`, `data.scrnshot` and
+`data.scrnshot.src` are created/used by `addpadding` and are vital to the game
+(for the .asc data files it is for the non-emoji version, `prog.asc`, but used
+by the same code, hence the `DATA` macro and the same applies to the screenshot
+friendly one, as I discussed in the data files versions in my [remarks above](#devil)).
+
+The `data*.src` files are included for the purpose of allowing the files to be
+created prior to running the game as they are vital, just like previous entries
+with their data files.
+
+The lovely thing about the data file is it's also on theme with the padding.
+Plus the jokes being on theme.
+
+Fun fact: the block size is necessary in another way: it also saves bytes.
+How can it possibly save bytes you might wonder? Well without it I have to use
+much larger numbers (plus what I already mentioned about how if a single string
+changed it would break everything after it).
+
+The data file reminds me of the Windows registry but it actually works
+if one does not mess with it, rather than if it's messed with OR by itself. It's
+also efficient on a modern system (unsure on older machines but I'd guess it's
+speedier than Windows registry - or Windows for that matter): I have seen no
+slow reaction at all.
+
+But the point here is that the Windows registry is poorly designed, inefficient,
+error prone and not cleverly devised but my data file is, although not a design
+you'd want in real life programs: cleverly built, cleverly used, efficient and
+it just works if someone doesn't screw with it in the wrong way (in some ways it
+might very well still work, though that depends on your definition of 'work' and
+'some ways'). These are useful to keep in mind when it comes to evaluating
+obfuscation. And madness of course.
+
+Consider: the Windows registry is a blob of data that if a key (I think that's
+the right term?) is corrupted it can break the entire system; and there are
+**many things** that could go wrong with the data files I supplied that will
+totally break the program; but whereas some problems in the Windows registry
+might not (supposedly) break Windows entirely (I will argue that if we consider
+the design it's always broken but never mind that) even minor changes can have
+catastrophic effects.
+
+That's **why** all the extra tools and why I had to write them, all to make sure
+things are okay, and even then I remind that you should always recreate the data
+files so that something horrible like a crash does not happen although I don't
+think this will happen to you; in fact towards the end I looked at every string
+index for each file and verified it was valid. With the tests in place and the
+Makefile building the data files it should be good.
+
+Anyway: even though the design choices are deliberately bad (for the contest,
+although they work well): I did have to carefully design it, figure out the
+padding and so on.
+
+And yet I'm not sure: it's a very elegant and creative design. Why indeed should
+I have to read in multiple strings when I can just use one `char *`? Why worry
+about having to know when to print newlines when the file can have them
+literally? It is simple, clever and quite unique. It is subtle and maybe
+brilliant. It is what the IOCCC loves.
+
+I believe I already explained how a single `char *` can have so many but a TL;DR
+is that the data file is read in in its entirety with `EOF` as the delimiter to
+`getdelim()` and the data file has NUL bytes that delimit the strings. After the
+strings, if there is more space left, the block is filled up, so that the string
+can be addressed by index rather than exact location, which would not work if a
+single string changed: all the strings after it would no longer be correct. If
+the string is >= the blocksize in length it will break everything. That's part
+of why lencount.c.
+
+Actually depending on what is needed one would not even need the index. In my
+case I did need the index but it's possible to iterate through the strings by
+blocksize and print out the necessary strings. But that's obviously wasteful.
+
+That extra data is **KEY**: without it the calculation of the location (`V()`
+and `Z()` functions along with the `S()` macro) WOULD NOT WORK!
+
+And although it's (probably) a **horrible** idea outside of the contest, having
+near 200 `char *`s in a single `char *` (NOT a `char *y[]`!) is still quite
+interesting and it's one of the reasons I'm quite proud of it.
+
+Interesting thing to ponder: what happens if a string is too long for the
+padding?
+
+
+### Conclusions
+
+A question: is this well-rounded in obfuscation as the judges like? Definitely.
+
+The fact that close to 200 NUL terminated strings are in a single `char *` (!!),
+the odd looking compound literal, the maze of `goto`s (116 or 1134 depending on
+if you pre-process the code), the bastardised Duff's device, the strange labels
+inside `switch()`s, the jumping into and out of `switch()`s only to jump back in
+(or out), the for loops split across several parts of the code (one making it
+look like variables are uninitialised), if/else code being swapped in location
+(or moved to other parts of the code, even in what would otherwise be dead code,
+including possibly this for for loops), the fall through of a label to a goto
+that jumps back to right before that fall through just to exit the game (isn't
+that so cute?), the fact I had to write all those tools to verify things are
+okay (showing how messed up it is), different blocks that have code that simply
+should not be there, the nested ternary operators...
+
+As for the `goto`s: yes I technically have more space. But it became almost
+impossible to add more spaghetti to the pot without it overflowing, and I do not
+want to waste perfectly good spaghetti. There comes a point when there's just so
+much spaghetti that it's wasted, if it can even be cooked. I believe I have
+reached the latter.
+
+Do you REALLY expect me to add more spaghetti? There isn't anything that could
+be done, even if it was possible to maintain this huge platter of delicious
+spaghetti without gaining fifty kilograms. Besides, I don't want to see
+spaghetti EVER AGAIN!! I've had enough of it for a lifetime! Okay, that's not
+really true...it DOES sound good but I won't likely be having it for a while.
+Can you actually blame me though? This spaghetti almost strangled me to death,
+like it did the Devil (I provided photographic proof of this earlier if you
+missed that).
+
+I have already demonstrated several other subtle and unique things but the
+`goto`s are what really makes it hard to parse; the other things are REALLY cool
+(unlike the spaghetti, at least hopefully) and interesting, and unique (or so I
+think), but those would be much less tasty without the HUGE pot of spaghetti
+(okay, once some of it is put on a plate).
+
+If I added more `goto`s it would be meaningless. A large family might not even
+be able to eat it all without some of it going to waste. The `goto`s and how
+they're used make it hard to follow this code, in fact making it very
+unpredictable. It is constantly jumping to unusual places and doing things that
+seem downright illegal. It should not work.
+
+But it **DOES** work. Exactly as I meant. As noted in my concluding remarks in
+my [remarks above](#devil), I started introducing bugs. It was extremely hard to
+find ways to make the spaghetti even more twisted. How is that even POSSIBLE? I
+don't think you could manage that with ACTUAL spaghetti!
+
+On top of all this: I kept it thematic, in code **and** data, and the code even
+spells out `rude long OREGON TRAIL TRAIL OREGON`, plus including other lovely
+numbers that were carefully calculated, to say nothing of all the other things
+you have to look at the code to (try and) discover!
+
+And the only necessary `-D`s: the `#define TRAIL o` and that is simply to be
+more thematic; and `DATA` for portability. None of the macros defined in the
+code are for obfuscation; one is to get past an annoying mis-feature of
+`scanf()` (that would be `S`) and others to save bytes. Using a cpp to translate
+the macros only makes it worse to parse anyway but they're not used for
+obfuscation.
+
+As for the `goto hell`: I will point out that there are so many of them that it
+started to get **really** hard to even find a place to put another one without
+breaking code (which actually happened several times), there
+were that many jumps.
+
+That is **not** why I put them in unusual places like the `switch()` between
+cases; that was done earlier on as it was more obscure and also I do not know
+it's very common knowledge that it is even allowed by the compiler.
+
+That's another issue with `goto hell` in C: there becomes a point where there
+are so many labels it's hard to find a place to put another one, not to mention
+running out of single letter labels: which I did, I am pretty sure, and if I did
+not get it it is because of a last minute change. That's why I had to use two
+character labels, of which there are many.
+
+I guess this might have horrified dmr but I don't know. Either way I took `goto`
+to absurd levels.
+
+Oh and yes: I could have done more with pointers but there was no need and a lot
+of it would just be rehashing old tricks that various authors have used over the
+years. The only pointers necessary are the `FILE *` and the two `char *`s, one
+of which is the `char *` with 172+ NUL terminated `char *`s (a pretty
+unique and creative thing I think - I certainly have never seen such madness).
+
+There would also be no purpose in even having an array of function pointers as
+none share the same prototype and it's an old thing anyway. Besides it uses a
+lot of bytes for little if not no gain.
+
+So there would be no gain in using pointers even more; they're simply not needed
+exactly because of how I designed it (okay, to be technical, the `TRAIL`/`o`
+array is a pointer in a sense and is used like one, to reduce bytes and to
+simplify purchasing, and the `t` array is done the same only at the forts, but
+these don't really count in the same way.
+
+The blocksize trick is also fun because it allows me to print out (and use as
+`scanf()` and also `printf()` the strings just by index, due to extra data. That
+extra data looks like bogus C code. Or is it bogus?
+
+One might call the blocksize pointer-ish but is it? It's only part of one and
+that's the `char *y` with the strings.
+
+The fact it has `goto hell;` which the game also has might mean something,
+although that might just be a thematic touch.
+
+And of course there are historical references too, as well as historical fixes
+from the original Oregon Trail (though that hardly matters now as it's almost an
+entirely different game) but also thematic historical references and the nod to
+Duff's device too (which quite arguably is abuse of C itself too). These are
+nice bonuses and then there are all the jokes as well.
+
+The spelling out of things only adds to the mystique and about the only thing
+that might give it away (besides the data source files, which looking at is
+cheating as it's only for allowing more portability, such as when the system
+does not support printing all emojis.
+
+Obviously I had to spell out the name as it's a long standing tradition in the
+IOCCC. The fact that also uses the (possibly) less known fact that you can
+declare a variable more than once as long as it is the same type, even (iirc) if
+you have it as another statement (i.e. `unsigned long i = 5; unsigned long i
+...`).
+
+Oh and isn't it hilarious how deceptive looks can be? :-) Many people like
+WYSIWYG but this program breaks that tradition in so many ways. It looks wrong,
+you can no longer rely on blocks, you can no longer rely on code being where it
+belongs, you start to question everything you learnt about C. And the best part?
+It all works, just to torment you even more. Yes it's **definitely**
+well-rounded, whether or not you can distinguish what is real or not real any
+more.
+
+I would not blame you if you are starting to question everything. How could I
+blame you when: if blocks are in else blocks (or other places entirely); a for
+loop's body is in the body of **another** for loop **with the SAME initialisation,
+condition check and increment** steps, even **acting on the SAME array** but
+doing **different things** and yet somehow working with no data race; everything
+is in a single switch(); code jumps all over main() constantly; other switch
+blocks and other types of blocks are obscenely long with code that shouldn't be
+there and so much more; some cases in a switch is polymorphic (in a way); a
+single flat `char *y` acts like a `char *y[]` with almost 200 `char *`, and even
+looks like it is an array; lots of illegal or UB looking code, including code
+that in some cases would be a syntax error but somehow isn't (e.g. `+--`); and
+much more? This should not work. But it does. I myself started to lose it and I
+wrote it. I know it intimately and I started to lose my mind.
+
+BTW: did you know that in truth that early Microsoft inspired the IOCCC, even if
+Landon did not acknowledge it? The reason it's not stated in the FAQ/README is
+the fear of frivolous lawsuits :-):
+
+
+
+
+
+[^1]: For those who do not know, vegetable garden is medical slang for the
+comatose ward. Yes medical slang is horrible and yes I'm horrible for using it. But
+this is a minor one. Ask me if you want to know much worse ones. Or don't. You
+might find them too much and end up with an acute gravity attack, hitting your
+head and reaching room temperature.
diff --git a/2024/ferguson1/printer.c b/2024/ferguson1/printer.c
new file mode 100644
index 000000000..6e947d13b
--- /dev/null
+++ b/2024/ferguson1/printer.c
@@ -0,0 +1,80 @@
+/*
+ * printer.c - prints out everything from data file for visual inspection
+ *
+ * This tool can be used to not only help identify if your system will work with
+ * the emojis data file but also show what the strings are without having to
+ * look at the source data file (this program decrypts the strings in a similar
+ * way to the game itself, see below).
+ *
+ * Using the macro (identical except it uses puts() on some of the strings that
+ * are unencrypted) from prog.c we will print out every string
+ * at every location in the order it occurs.
+ *
+ * IMPORTANT NOTE: as some strings have a marker that indicates to not be
+ * encrypted but the marker is not in the data file itself, the bytecount.c
+ * might be better in that it uses the data source file. However for my own
+ * purposes I have this tool too. This tool, to prevent display problems, checks
+ * for specific known locations where it should not decrypt anything due to not
+ * being encrypted (the '%' ones notwithstanding), and if it is that number it
+ * will print it out with puts() instead (can't be printf() as it has %
+ * conversions). A BEL byte also is unencrypted (if it's the first character of
+ * the string it's skipped and printed without encrypting it).
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+
+/*
+ * macro similar to prog.c
+ */
+#define Z(x) (x)*BLOCKSIZE
+#define V(x) puts(&y[Z(x)]);
+static char *p;
+static char *y;
+static char *filename = "data";
+static size_t len;
+static int k;
+
+int main(int argc, char **argv)
+{
+ FILE *fp = NULL;
+
+ while ((k = getopt(argc, argv, "i:")) != -1)
+ {
+ switch (k)
+ {
+ case 'i':
+ filename = optarg;
+ break;
+ case ':':
+ case '?':
+ exit(1);
+ break; /* this triggered an annoying warning but it's an extra sanity check */
+ }
+ }
+
+ errno = 0;
+ fp = fopen(filename, "r");
+ if (fp == NULL)
+ {
+ fprintf(stderr, "couldn't open data file %s: %s\n", filename, strerror(errno));
+ exit(1);
+ }
+
+ if (getdelim(&y, &len, EOF, fp) != -1)
+ {
+ /*
+ * now we have to test every single string to make sure it's valid.
+ * The makedata.sh script generates V.c.
+ */
+ #include "V.c"
+ }
+
+ free(y);
+ y = NULL;
+ fclose(fp);
+ fp = NULL;
+}
diff --git a/2024/ferguson1/prog.alt.c b/2024/ferguson1/prog.alt.c
new file mode 100644
index 000000000..f031b6500
--- /dev/null
+++ b/2024/ferguson1/prog.alt.c
@@ -0,0 +1,95 @@
+#include
+#include
+#include
+#include
+#include
+long x(long y,long z){ return rand()%(z-y+1)+y; }
+unsigned m,D,Q,v,l,Y,f,g,X,z,B,i,h,
+ r,u,d,e; long
+O,R,E,G,O,N, T,R,A,I,L,
+*o[]={ &O,&R,&E,&G,&O,&N,&I} ,a,t[7],q,M, b=666,c,W;
+char *y; FILE*K; size_t J;
+#define j E=I/5;
+#define w(i) { V(i); V(4); goto hell; }
+long Z(long x){ return x *1663; }
+#define S(x,z) while(scanf(&y[Z(x)],&z)!=1)while(getchar()!='\n');
+void V(long x) { printf("%s",&y[Z(x)]); }
+long k(void) { ++ Y; return I>0?x(1,101)+ Y>53 +a?9:0+f?9:0:0; } int main(void){ srand(time(0));
+
+K=fopen(DATA,"r"); if(!K||getdelim(&y,&J,EOF,K)<0)goto hell; goto s; aa:goto dd; u: goto M; ee:goto ff; jj:goto kk; N:for (X=
+
+ 1; X < 6; ++X) { x:V(X+--(
+
+ int){ 6} ); if(z ){ S(3,
+
+ t[X]) if(t[X]<0 ||t[X]>
+
+ 666){ V(14); goto x; goto
+ heaven; l:goto C; JJ:goto W; qq:goto rr; } L=T; for(u
+
+ =0; u < 6; ++u)L-=t[u];
+
+ if(L<0){ V(46); memset(&t,0,
+
+ sizeof t); goto v; ZZ:goto II; } }
+
+ else{ S(3 ,*(o[X])) if(
+
+ *o[X]<0||*o[X] >666){ V(14);
+
+ goto x; } T=1666-O-R-E-G-0-N; if(T<0){ V(46); O=R=E=G=N=0; goto v; c: goto d; oo:goto pp; } } } if(z)goto A; B:I=E*5;
+
+ printf(&y[Z(12)],T); if(z) goto F; switch(1) { dd:goto cc; I:goto R; default: do { if(b<1||M<0||M>2169) break; goto i;
+
+ e:goto D; P: for (X=1; X<7; ++X) if (*o[X]<0) *o[X]=0;
+ printf(&y[Z(11)],R,I,G,O,N,T,b,M); if(x(0,1))goto Q; R:if(R<14)V(37); if(z) { r: V(43); S(2,r)
+
+ switch (r) { H: goto G; case 1: goto T; i:if(O<1){ if(!v)V(v=15); O=0; } else v=0; goto e; case 2: goto X; F:
+
+ goto f; a:goto c; default: goto r; O:goto E; } } else{ y:V(42); S(2,r) switch(r) { M:V(1); v:memset(&t,0,sizeof t); goto
+
+ N; case 3: goto X; nn:goto oo; case 1 : z=1; M-=45; goto L; A:for(X=1; X < 7; ++X){ *o[X]+=t[X]; T-=X[t]; } goto B;
+
+case 2: goto T; default: goto y; } } L:goto v; T:l=1; if (I<9)V(16); else { if (k()) { if (x(1,10) > 5) { V(52);
+
+ R += 23; if(!x(0,9))i=17; } else{ V(51); R+=18; } } else { V(53); } I-=9; j M-=45; } l=0; f: z=0;
+
+ X: if(R<1){ if(O>39){ V(e=x(0,1)?18:19); O -= 40; goto q; o: goto Y; ii:goto l; } w(24) } else goto K; Y: switch(q=x(0,24))
+
+{ s: goto h;
+ case 24:if(++g<4) V(73); else w(147) break;
+ case 23:
+if (d) V(39); if (e) V(25); break; case 1: V(95); R+=5; break; S: if (I>1999) w(27) V(82); M-=9; N-=5; R-=20; goto Z;
+ case 18:V(26); break; case 13: V(28); break;
+ case 2: O-=40; V(71); break; mm:goto nn;
+
+case 3: V(a=76); b-=70; goto jj; case 4:V(77); N-=7; M-=7; break; case 5:case
+
+10: if(q<6) { V(78); if(k()) { V(81); R+=9; N+=3; } else { V(f=79); b-=80; T/=4; } I=0; j } else
+{ V(56); if (k()) { V(a=29); T+=70; break; cc:goto ee; } else { V(f=62); M-=50; b-=35; } } break;
+case 9: case 19:V(30); break; case 20:V(32); break; case 21: V(31); break; case 6: goto g; Z: break; case 16: case 22:V(49); break; case 17: V(72); break;
+case 7: V(83); M-=10; break; D: goto P; case 8: V(86); R-=30; G-=20; O-=40; V
+ :switch(x(1,9)) { case 2: if(q>9){ switch(x(1,2)){ q:R+=40; goto o; case 1: switch (x(2,3)) { case 2: V(a=54); goto
+
+ m; b: w(48)
+ case 3:goto J; } case 2: V(5); } goto E; ll:goto mm; J: V(a=54); } goto O; KK:goto JJ; m
+
+ :goto O; goto m; default: if(q>10) goto E; if(q>7) { if(N<5) w(99) V(13); N-=5; } break; } M-=17; break; C:goto k; K:R-=R
+
+ >23 ? 23 : R > 18 ? 18 : R > 13 ? 13 :
+ R; goto Y; case 14: V(74); break; case 15: V(x(0,1)?69:68);
+ break; d: goto I; case 11: goto V; kk:goto ll; case
+
+ 12:V(94); M-=5; b-=19; N -= 5; break; G:goto a; case 0:V(20); } if(O>39&&!x(0,9)){ V(e = 19); O -= 40; R+=40; } if(M<951) goto W; if (G < 36) goto b; if (x(0,9) > 2) goto n; V(96); if (x(0,1)) goto p; V(97); M-= 60; goto n; p: if (x(0,9)<5) goto t; V(21); M -=100;
+
+ goto n; t: V(22); M -= 85; n:if(m) goto z; m=1; if (x(0,9) < 5) goto w; V(23); z: if(M<1951||W) goto
+
+ U; W=1;
+ if(!d&&!x(0,4)) { V(75); d=1; R+= 50; } if (G<20)w(92)
+ if(!x(0,4)) w(x(0,5)?84:x(0,3)?33:34) if (x(0,9) < 7) goto w; U: goto W; w:V(35); c=1; M-=101; I += 1; j k: M-=10; goto U; W: if(d&&x(0,1)){ V(39); } while(i)heaven:w(i) if (! B && (f ||
+
+ a)) { if(d&&a) V(91); if(T<666) V(B=38); else { Q=a ? 1: Q; h = f?1:h; f=a=0; V(93); T-=666; } } b-=f ? 15
+
+ :h ? 5:0; b-= a ? 5 : Q ? 15 : 0; M+=170; M+=O> 99 ? 30:- 99;
+
+ b-=10; } while (A++<21); } if(b<1) { if(a){ w(40) XX:goto ZZ; } if(f)w(41) w(45) II:goto KK; } w(M>2169?47:36) hell:return 666; g:goto S; h:goto u; E:goto aa; Q: goto H; ff:goto ii; pp: goto qq; rr:goto XX; }
diff --git a/2024/ferguson1/prog.c b/2024/ferguson1/prog.c
new file mode 100644
index 000000000..f2b5d7363
--- /dev/null
+++ b/2024/ferguson1/prog.c
@@ -0,0 +1,85 @@
+#include
+#include
+#include
+#include
+#include
+long x(long y, long z){ return rand()%(z-y+1)+y; }
+unsigned m,D,Q,v,l,f,X,z,B,i,h,
+ r,u,d,e; long
+O,R,E,G,O,N, T,R,A,I,L,
+*o[]={ &O,&R,&E,&G,&O,&N} ,a,t[7],q,M, b=666,c,W;
+char *y,*p; FILE*K; size_t J;
+#define w(i) { V(i); V(4); goto hell; goto M; }
+long Z(long x){ return x * 1663; }
+#define S(x,z) while(scanf(&y[Z(x)],&z)!=1)while(getchar()!='\n');
+void V(long x){ printf("%s",&y[Z(x)]); }
+long k() { return E>0?x(0,99)>49:0; } int main() {
+switch(1)
+ { j:if(z)goto A; E*=5; B:
+ printf(&y[Z(12)],T); if(z) { goto f; } goto PP; default: srand(time(0));
+K=fopen(DATA,"r"); if(!K||getdelim(&y,&J,EOF,K)<0)
+ goto hell; goto M; OO: if(b<1) { if(a){ w(40) PP: goto G; } if(f)w(41) w(45) g:goto S; } w(M>2169?47:45)
+ hell:
+ return
+ 666; rr:;
+
+ goto OO; yy:
+do{ if(b<1||M<0||M>2169){ break; F:V(51); R+=18; goto L; } goto i;
+
+P:for(X=1; X<--(unsigned){ 7 } ; ){ goto kk; BB:*o[X]+=(X==2?t[X]*5:t[X]); goto HA; TA:++X; goto at; ZZ:; }
+printf(&y[Z(11)],R,E,G,O,N,T,b,M); if(x(0,1))goto I; R:if(R<14)V(37); if(z) { z=0; l: { if (k()) { if (x(0,9) > 4) { V(52);
+
+R+=23; if(!x(0,9)){ goto r; L: goto II; } c:; } else{ goto F; r: goto c; qq: { V(53); goto zz; } II:; } } else { goto qq; } zz: E-=9; M-=45; } goto C; y:V(42); S(2,r) switch(r) { M:V(1); v:memset(&t,0,sizeof t); goto
+ N; D:{ if (k()) { goto dd; ii:V(f=79); b -= 80; T/=4; goto jj; ee:; } else { goto oo; dd:V(a=29); T+=70; goto ee; x:V(X+--(
+unsigned){ 6 } ); if(z){ S(3,
+
+t[X])if(t[X]<0||t[X]>
+
+ 666 ){ V(14); goto x; goto
+ heaven ; ET:L-=t[u]; goto XT; } L=T; for(u
+
+ =0; u < 6; ++u){ goto ET; XT:; }
+
+ if(L<0){ V(46); memset(&t,0,
+
+ sizeof t); goto v; } }
+
+ else{ S(3 ,*(o[X])) if(
+
+ *o[X]<0||*o[X] >
+ 666) { V(14);
+
+ goto x; } T=1666-O-R-E-G-0-N; if(T<0){ V(46); O=R=E=G=N=0; goto v; LL:*o[X]=0; uu:++X; goto ZZ; } } goto bb; } } goto s; case 3: goto X; case 1:z=1; M-=45; goto v;
+case 2:goto T; } goto y;
+O:{ V(e = 19); O -= 40; R+=40; } goto E; i:if(O<1){ goto d; } else { v=0; } goto P; go: V(81); R+=9; N+=3; goto to;
+} else{ goto y; HA:T-=X[t]; goto TA; A:for(X=1; X < 6; ){ goto BB; kk:if (*o[X]<0) goto LL; goto uu; QQ:V(B=38); goto JJ; at:; } goto B;
+} T:l=1; if (E<9){ goto h; } else { goto l; h: V(16); } C: l=0; f:z=0;
+X:if(R<1){ goto e; U: w(24) K:R-=R
+ >23?23:R>18? 18 : R > 13 ? 13 :
+ R; goto Y; TT:V(v=15); O=0; goto P; } else { goto K; } goto tt; Y:switch(q=x(0,23))
+{ case 1:V(95); R+=5; break; case 18:V(26); goto Z; case 13:V(28); break;
+case 2:O-=40; V(71); break; case 3:V(a=76); b-=70; goto W; case 4:V(77); N-=7; M-=7; break; case 5:case
+10:if(q<6) { goto ha; m: V(56); goto D; o:; } else
+{ goto m; oo:V(f=62); M-=50; b-=35; s:; } goto Z; a:goto H;
+case 9:case 19:V(30); goto Z; case 20:V(32); break; case 21 :V(31); break; case 6:goto g; case 16: case 22:V(49); goto Z; case 17:V(72); goto Z;
+case 7:V(83); M-=10; goto Z; case 8:V(86); R-=30; G-=20; O-=40; V
+ :switch(x(1,9)){ case 2:if(q>9){ switch(x(1,2)){ q:R+=40; goto Y; case 1:{ switch (x(2,5)) { case 2:V(a=54); goto
+ MM; b:w(48)
+case 3:goto J; N:goto Q; case 4:i=17; } } case 2: V(5); } goto k; u: if(M<1951||W){ goto
+W; } W=1;
+if(!d&&!x(0,4)){ V(75); d=1; R+= 50; }
+if(!x(0,3)){ w(x(0,4)?84:x(0,4)?33:34) e:if(O>39){ V(e=x(0,1)?18:19); O -= 40; goto q; d:{ if(!v)goto TT; goto P; } } goto U; } if (x(0,9) < 5) w:V(35); c=1; M-=101; ++E; k: M-=10; W: if(x(0,1)){ if (d) V(39); if(e)V(25); } while(i)heaven:{ w(i) } if (!B&&(f||
+a)){ if(d&&a) V(91); if(T<666){ goto QQ; KK:Q=a?1:Q; h=f?1:h; f=a=0; V(93); T-=666; } else{ goto KK; } JJ:; } b-=f?15
+
+ :h?5:0; b-=a?5:Q?15:0; M+=170; M+=O> 99 ? 30:- 99;
+
+b-=10; goto z; J: V(a=54); } goto k; MM
+
+ :goto k; default: if(q>10) { goto k; } if(q>7) { if(N<5) { w(99) goto M; G:goto yy; } V(13); N-=5; } goto Z; _:goto rr; S:if (E>1999){ w(27) I:goto a; } V(82); M-=9; N-=5; R-=20; goto Z;
+ } M-=17; goto Z; case 14: V(74); break; case 15: V(x(0,1)?69:68);
+ goto Z; ha:V(78); if(k()){ goto go; to:; } else { goto ii; jj:; } goto o; case 11: goto V; case
+ 12:V(94); M-=5; b-=19; N -= 5; goto Z; tt: goto Y; case 0:V(20); Z:; } if(O>39&&!x(0,9))goto O; E: if(M<951) goto W; if (G < 36) goto b; if (x(0,9) > 2) goto n; V(96); if (x(0,1)) { goto p; Q: for (X=
+1; X < 6; ++X) { goto x; bb:; } goto j; } V(97); M-= 60; goto n; H: goto R; p: if (x(0,9)<3) goto t; V(21); M -=99;
+goto n; t: V(22); M -= 85; n:if(m){ goto u; } m=1; if (x(0,9) > 5) goto w; V(23); z:; } while (A++<21); goto _;
+}
+}
diff --git a/2024/ferguson1/prog.orig.c b/2024/ferguson1/prog.orig.c
new file mode 100644
index 000000000..f2b5d7363
--- /dev/null
+++ b/2024/ferguson1/prog.orig.c
@@ -0,0 +1,85 @@
+#include
+#include
+#include
+#include
+#include
+long x(long y, long z){ return rand()%(z-y+1)+y; }
+unsigned m,D,Q,v,l,f,X,z,B,i,h,
+ r,u,d,e; long
+O,R,E,G,O,N, T,R,A,I,L,
+*o[]={ &O,&R,&E,&G,&O,&N} ,a,t[7],q,M, b=666,c,W;
+char *y,*p; FILE*K; size_t J;
+#define w(i) { V(i); V(4); goto hell; goto M; }
+long Z(long x){ return x * 1663; }
+#define S(x,z) while(scanf(&y[Z(x)],&z)!=1)while(getchar()!='\n');
+void V(long x){ printf("%s",&y[Z(x)]); }
+long k() { return E>0?x(0,99)>49:0; } int main() {
+switch(1)
+ { j:if(z)goto A; E*=5; B:
+ printf(&y[Z(12)],T); if(z) { goto f; } goto PP; default: srand(time(0));
+K=fopen(DATA,"r"); if(!K||getdelim(&y,&J,EOF,K)<0)
+ goto hell; goto M; OO: if(b<1) { if(a){ w(40) PP: goto G; } if(f)w(41) w(45) g:goto S; } w(M>2169?47:45)
+ hell:
+ return
+ 666; rr:;
+
+ goto OO; yy:
+do{ if(b<1||M<0||M>2169){ break; F:V(51); R+=18; goto L; } goto i;
+
+P:for(X=1; X<--(unsigned){ 7 } ; ){ goto kk; BB:*o[X]+=(X==2?t[X]*5:t[X]); goto HA; TA:++X; goto at; ZZ:; }
+printf(&y[Z(11)],R,E,G,O,N,T,b,M); if(x(0,1))goto I; R:if(R<14)V(37); if(z) { z=0; l: { if (k()) { if (x(0,9) > 4) { V(52);
+
+R+=23; if(!x(0,9)){ goto r; L: goto II; } c:; } else{ goto F; r: goto c; qq: { V(53); goto zz; } II:; } } else { goto qq; } zz: E-=9; M-=45; } goto C; y:V(42); S(2,r) switch(r) { M:V(1); v:memset(&t,0,sizeof t); goto
+ N; D:{ if (k()) { goto dd; ii:V(f=79); b -= 80; T/=4; goto jj; ee:; } else { goto oo; dd:V(a=29); T+=70; goto ee; x:V(X+--(
+unsigned){ 6 } ); if(z){ S(3,
+
+t[X])if(t[X]<0||t[X]>
+
+ 666 ){ V(14); goto x; goto
+ heaven ; ET:L-=t[u]; goto XT; } L=T; for(u
+
+ =0; u < 6; ++u){ goto ET; XT:; }
+
+ if(L<0){ V(46); memset(&t,0,
+
+ sizeof t); goto v; } }
+
+ else{ S(3 ,*(o[X])) if(
+
+ *o[X]<0||*o[X] >
+ 666) { V(14);
+
+ goto x; } T=1666-O-R-E-G-0-N; if(T<0){ V(46); O=R=E=G=N=0; goto v; LL:*o[X]=0; uu:++X; goto ZZ; } } goto bb; } } goto s; case 3: goto X; case 1:z=1; M-=45; goto v;
+case 2:goto T; } goto y;
+O:{ V(e = 19); O -= 40; R+=40; } goto E; i:if(O<1){ goto d; } else { v=0; } goto P; go: V(81); R+=9; N+=3; goto to;
+} else{ goto y; HA:T-=X[t]; goto TA; A:for(X=1; X < 6; ){ goto BB; kk:if (*o[X]<0) goto LL; goto uu; QQ:V(B=38); goto JJ; at:; } goto B;
+} T:l=1; if (E<9){ goto h; } else { goto l; h: V(16); } C: l=0; f:z=0;
+X:if(R<1){ goto e; U: w(24) K:R-=R
+ >23?23:R>18? 18 : R > 13 ? 13 :
+ R; goto Y; TT:V(v=15); O=0; goto P; } else { goto K; } goto tt; Y:switch(q=x(0,23))
+{ case 1:V(95); R+=5; break; case 18:V(26); goto Z; case 13:V(28); break;
+case 2:O-=40; V(71); break; case 3:V(a=76); b-=70; goto W; case 4:V(77); N-=7; M-=7; break; case 5:case
+10:if(q<6) { goto ha; m: V(56); goto D; o:; } else
+{ goto m; oo:V(f=62); M-=50; b-=35; s:; } goto Z; a:goto H;
+case 9:case 19:V(30); goto Z; case 20:V(32); break; case 21 :V(31); break; case 6:goto g; case 16: case 22:V(49); goto Z; case 17:V(72); goto Z;
+case 7:V(83); M-=10; goto Z; case 8:V(86); R-=30; G-=20; O-=40; V
+ :switch(x(1,9)){ case 2:if(q>9){ switch(x(1,2)){ q:R+=40; goto Y; case 1:{ switch (x(2,5)) { case 2:V(a=54); goto
+ MM; b:w(48)
+case 3:goto J; N:goto Q; case 4:i=17; } } case 2: V(5); } goto k; u: if(M<1951||W){ goto
+W; } W=1;
+if(!d&&!x(0,4)){ V(75); d=1; R+= 50; }
+if(!x(0,3)){ w(x(0,4)?84:x(0,4)?33:34) e:if(O>39){ V(e=x(0,1)?18:19); O -= 40; goto q; d:{ if(!v)goto TT; goto P; } } goto U; } if (x(0,9) < 5) w:V(35); c=1; M-=101; ++E; k: M-=10; W: if(x(0,1)){ if (d) V(39); if(e)V(25); } while(i)heaven:{ w(i) } if (!B&&(f||
+a)){ if(d&&a) V(91); if(T<666){ goto QQ; KK:Q=a?1:Q; h=f?1:h; f=a=0; V(93); T-=666; } else{ goto KK; } JJ:; } b-=f?15
+
+ :h?5:0; b-=a?5:Q?15:0; M+=170; M+=O> 99 ? 30:- 99;
+
+b-=10; goto z; J: V(a=54); } goto k; MM
+
+ :goto k; default: if(q>10) { goto k; } if(q>7) { if(N<5) { w(99) goto M; G:goto yy; } V(13); N-=5; } goto Z; _:goto rr; S:if (E>1999){ w(27) I:goto a; } V(82); M-=9; N-=5; R-=20; goto Z;
+ } M-=17; goto Z; case 14: V(74); break; case 15: V(x(0,1)?69:68);
+ goto Z; ha:V(78); if(k()){ goto go; to:; } else { goto ii; jj:; } goto o; case 11: goto V; case
+ 12:V(94); M-=5; b-=19; N -= 5; goto Z; tt: goto Y; case 0:V(20); Z:; } if(O>39&&!x(0,9))goto O; E: if(M<951) goto W; if (G < 36) goto b; if (x(0,9) > 2) goto n; V(96); if (x(0,1)) { goto p; Q: for (X=
+1; X < 6; ++X) { goto x; bb:; } goto j; } V(97); M-= 60; goto n; H: goto R; p: if (x(0,9)<3) goto t; V(21); M -=99;
+goto n; t: V(22); M -= 85; n:if(m){ goto u; } m=1; if (x(0,9) > 5) goto w; V(23); z:; } while (A++<21); goto _;
+}
+}
diff --git a/2024/ferguson1/spaghetti.png b/2024/ferguson1/spaghetti.png
new file mode 100644
index 000000000..8c1815611
Binary files /dev/null and b/2024/ferguson1/spaghetti.png differ
diff --git a/2024/ferguson1/strings.asc.loc.txt b/2024/ferguson1/strings.asc.loc.txt
new file mode 100644
index 000000000..10d1343ab
--- /dev/null
+++ b/2024/ferguson1/strings.asc.loc.txt
@@ -0,0 +1,1494 @@
+<1>
+This program simulates a trip over the Oregon Trail from Independence, Missouri
+to Oregon City. Your extended family will attempt the 2170 mile Oregon Trail in
+5-6 months. You had $6666 for the trip but after foolishly wasting thousands on a
+sinful night yesterday and paying $200 for a wagon train, you only have an
+ominous $1666. You may buy the following items, or not, if you trust the Devil
+to be faithful to your pact:
+
+ Food - the more you have, the less chance you'll starve to
+ death, which would serve you right.
+ Ammunition - $1 only buys 5 bullets due to recent hoarding.
+ You will need lots of bullets for self defence
+ and for hunting food, assuming you don't miss.
+ Clothing - this is especially important for the cold weather
+ you will encounter when crossing the mountains, if you
+ get there.
+ Oxen - the more you spend the better off you'll be, assuming
+ they don't die. Or you don't sacrifice them.
+ Miscellaneous supplies - this includes medicine and other
+ things you'll need.
+
+You can spend all your money before you start your trip or you can save some of
+your cash to spend at forts along the way when you run low on supplies.
+Alternatively, you might wish to spend it all as you'll probably just find
+money along the way. You can also go hunting along the way to get more food,
+assuming you're not such a lousy shot as to be unable to hit a helpless animal
+from a cowardly distance.
+
+At each turn, all items are shown in dollar amounts except bullets. When asked
+to enter money amounts, don't use a $.
+
+Good luck, because the Devil's not going to help out!!! Or...will he?
+
+<2>
+%u
+<3>
+%ld
+<4>
+
+ / \
+ / A \
+ |TORMENTED|
+ | MONSTER |
+ | R.I.P. |
+ |_________|
+ GAME OVER
+Unfortunately, due to what can only be an ADMINISTRATIVE FOUL-UP, you end up
+somewhere you did not expect as your forever home. But honestly, after signing
+the Devil's book, DO YOU REALLY BELIEVE YOU DON'T BELONG HERE? Be honest. For
+once. You know you belong here. Oh, by the way, god asked me to wish you a
+PROSPEROUS LIFE ahead...
+
+ WELCOME TO HELL!!
+
+<5>
+
+Not again. Are you REALLY going to tell me about the Flying Spaghetti Monster
+AGAIN? I've had ENOUGH of your FAIRY-TALE DELUSIONS! YOU'VE TOLD ME HE IS
+INVISIBLE SO HOW IN THE HELL CAN YOU EVEN KNOW HE EXISTS?
+
+What next, are you going to tell me that between Earth and Mars there is a
+china teapot revolving about the Sun in an elliptical orbit? Let me guess! It's
+so small that even the James Webb telescope that was launched almost 200 years
+from now can't even see it, right? What a load of ABSOLUTE RUBBISH! If your
+daughters were not here I WOULD TOTALLY BE ABUSING LALOCHEZIA AT YOU RIGHT NOW!
+BUGGER ME THAT THEY ARE!
+
+If the Flying Spaghetti Monster ACTUALLY existed, he'd eat you for lunch for
+blasphemy. Hell, keep this up and I'LL eat you. I'M STARVING!
+
+<6>
+
+How much do you want to spend on food?
+<7>
+
+How much do you want to spend on ammunition?
+<8>
+
+How much do you want to spend on clothing?
+<9>
+
+How much do you want to spend on oxen?
+<10>
+
+How much do you want to spend on miscellaneous supplies?
+<11>
+
+ Food: %4ld Ammo: %4ld Clothing: %4ld
+ Oxen: %4ld Supplies: %4ld Money: %4ld
+ Health: %4ld Miles: %4ld
+
+<12>
+After all your purchases, you now have $%ld left...
+
+Seriously, YOU WASTED YOUR MONEY LIKE THAT?
+
+<13>
+
+Mild illness. Medicine used. Not sure why though. IT WAS ONLY A SNIFFLE.
+Probably just the Devil TRYING TO ESCAPE FROM YOUR CURSED NOSTRILS. In the
+future THEY BLESS PEOPLE FOR SNEEZING. You can die happy knowing you started a
+thing. Even if your death will bring you EVERLASTING TORMENT.
+
+<14>
+
+Value must be a positive number no larger than 666. Or 0. If you trust the
+Devil.
+
+<15>
+
+You have run out of oxen and must walk. Better buy more... IF YOU DIDN'T WASTE
+MORE MONEY ON MORE SINFUL NIGHTS, like your red-headed daughters told me last
+night, assuming they weren't LYING to me.
+
+AND YES. A dirty mind IS a TERRIBLE thing to waste BUT NOTHING HAPPENED BETWEEN
+US!! We're JUST FRIENDS and they've been telling me ALL ABOUT YOUR RIDICULOUS
+BEHAVIOUR. OK, it MIGHT be in bed with them but they can't help
+themselves...kind of like you. WHERE do you think they got it from? Besides, IF
+YOU KNOW THE DEVIL in the biblical sense WHY SHOULDN'T WE? We EXPRESS PASSION
+and YOU ARE AN EVIL MONSTER!!!! Good luck hauling your wagon! WE'RE TAKING A
+PLANE!!
+
+<16>
+
+Shooting when low on bullets. That's really intelligent. NO WONDER
+you're starving.
+
+<17>
+
+As you overindulge in a huge platter of spaghetti, it suddenly begins to
+strangle you to death.
+
+You gasp for air, reaching out to the Devil for help! In vain. She's already
+here cackling like the monster you are, just WAITING FOR YOU.
+
+Your time has come my friend. But didn't you want to know her better anyway?
+
+Better go fulfil your promise! SHE WANTS YOU RIGHT NOW!
+
+<18>
+
+ The only food you have left is an ox!
+
+As you have no choice left, you promptly kill it before it runs away, and it
+sure was DELICIOUS!!!
+
+ ( OX'S VOICE )
+You're a sick, sick individual. You do know that, right? First you BURDEN ME
+WITH ALL YOUR RUBBISH and THEN YOU EAT ME?
+
+I hope you remember you were starving me to death so it's your fault you won't
+get much sustenance from MURDERING YOUR FAITHFUL SLAVE ANIMAL!!! Not that I had
+a choice.
+
+And YES, there's a place IN HELL FOR MONSTERS LIKE YOU, AND YES YOUR TIME
+IS FAST APPROACHING, YOU RUDDY UNFAITHFUL LITTLE GIT.
+ HE'S WAITING.
+
+<19>
+
+ An ox looks at you funny so you eat him!
+
+You're a sick, sick individual. You do know that, right? FIRST you BURDEN HIM
+WITH ALL YOUR RUBBISH and THEN YOU EAT HIM BECAUSE OF A FUNNY LOOK? And YOU
+DIDN'T EVEN SHARE HIM WITH YOUR FAMILY!
+
+What next, will you eat your daughter too? No! NO! NO NO NO NO! I SHOULD NOT
+HAVE SAID THAT! NO! DON'T EVEN THINK ABOUT TOUCHING HER! BACK OFF!!
+ SHE'S MINE!!!
+
+<20>
+
+One of the daughters cut her arm and it had to be amputated. THANK GOD she is
+not DOWN IN THE MOUTH AND SHE WANTS TO EAT IT BECAUSE YOU ARE SUDDENLY
+STARVING!!!
+
+But OF COURSE you didn't get any. If you weren't eyeing it so lustily you would
+have seen that she seemed to ESPECIALLY ENJOY IT, GREEDILY DEVOURING IT AS IF
+IT WAS HER LAST SUPPER! Wait, HAS THE DEVIL POSSESSED HER TOO?! THAT EVIL
+WITCH!!!
+
+Hang on. YOU'RE JUDGING HER AFTER ALL YOU'VE DONE? CUT THAT OUT RIGHT NOW! NO.
+NO! NO! NO! STOP! I DID NOT MEAN CUT ANOTHER LIMB OFF HER! YES I KNOW I got
+some and you didn't. And yes it was DELICIOUS! But she wanted me to remember it
+before it was all gone, not you. Eat your own arm if you must. No. I meant stop
+accusing her of witchcraft. YOU signed the Devil's book, NOT HER and it WAS her
+body! This is ALL YOUR FAULT, JUST LIKE EVERYTHING ELSE that's happened since
+that fateful night!
+
+<21>
+
+Wagon train damaged! Lost time time resupplying from the Devil.
+
+<22>
+
+Suddenly your clocks stop...
+
+I guess it must have happened AGAIN! And WHY THE DEVIL DO YOU KEEP SWIMMING IN
+THE MOLASSES RIVER?! Honestly, you'll be lucky if you don't SINK IN IT before
+it sinks into your stick-in-the-molasses head.
+
+<23>
+
+You made it safely through South Pass--no snow. Clearly the Devil has your
+back. For now my dear fiend, for now...
+
+He might be plotting against you. Oh hell. I KNOW HE IS. HE TOLD ME HE IS. Your
+time is coming AND THE DEVIL AND I BOTH CANNOT WAIT! Neither can your
+daughters. They told me last night in the wagon. YES. I KNOW THEM.
+
+<24>
+
+All you had was mouldy bread,
+Therefore here you must lie.
+Because now you're dead.
+ GOODBYE!
+
+<25>
+
+ ( OX'S VOICE )
+Still happy you ate me? How many more miles do you have to go?
+YOU'RE COOKED and you know it, you horrible, HORRIBLE MONSTER.
+
+<26>
+
+A little ghost floats by and shouts: BOO!!!!
+
+Okay that was NOT funny, Casper! Go back to your shallow grave, you LITTLE
+JERK!
+
+<27>
+
+A fire breaks out in your wagon, and the wind quickly fans the flames, CAUSING
+YOUR AMMO TO BLOW UP, killing you! Somehow everyone else survived...
+
+Frankly, IT WAS ABOUT TIME. I mean WHAT KIND OF IDIOT overloads their wagon
+with WEAPONS?
+
+<28>
+
+Uh oh. A black cat just jumped out in front of you. Is the Devil calling you?
+Better go have a look before it's too late. Maybe it already is. Your daughters
+told me you're an ailurophobe! Some pretty wild stories I hear. I think it
+probably is too late. Isn't it Friday the 13th?
+
+<29>
+
+You take lots of cash from the riders, accidentally stabbing one as he flees. But
+since you're starving, why don't you MAKE PENANCE BY NOT WASTING THE BODY YOU
+RUDELY CUT OPEN?
+
+ Mm...that was DELICIOUS!!!
+ ( RIDER'S SOBBING VOICE FROM THE GRAVE )
+You know what you did is wrong, right? We were JUST ROBBED YESTERDAY, you
+rob us today AND NOW I'M DEAD!
+
+WELL GOOD. I WAS DYING OF DYSENTERY and now YOU get to SPREAD THE DISEASE as well.
+
+<30>
+
+ ~~~~~~
+ / \
+ / \
+ / \
+ | |
+ \ ||| ||| /
+ \ ||||| /
+ \ ||| /
+ \_________/
+ || ||
+ || ||
+ __||__||__
+WOW!!!! THAT'S A SPAGHETTI TREE!!! I saw them over 100 years from now when I
+last used my Time Machine!! The BBC will cultivate them on April Fool's Day
+19579! THEY'RE AMAZING!! The Time Machines are okay and kind of interesting.
+Dangerous though...
+
+But the spaghetti looks pretty ominous, doesn't it? IT LOOKS LIKE IT WANTS TO
+REACH DOWN AND GRAB YOU! Better be careful. If they strangle you YOU WILL GO TO
+HELL! On the plus side... YOU'LL HAVE THE MOST AMAZING STORY to tell your
+fellow sinners... Trust me. I've been there on holiday! It's PRETTY WILD!!
+Summers are AMAZINGLY HOT!! Although...GETTING EATEN BY A DRAGON OR KILLED BY
+TYRANNOSAURUSES is an EVEN BETTER STORY! That's MUCH MORE EXCITING than a
+SPAGHETTI TREE KILLING YOU!! Although...now I think on it...they're ALSO in
+Hell so maybe it's better if the spaghetti kills you. Want me to strangle you
+with it if it doesn't do it? Of course...the trees are there too...LOTS of
+parties too. And good old TORTURE! IT'S AWESOME!
+
+<31>
+
+
+Uh oh! Is that the DEVIL I see in your mirror again? OR are YOU looking at it
+from behind your dressing curtain?
+
+BETTER BREAK IT BEFORE IT'S TOO LATE!!! Yes, YES, I KNOW IT'S BAD LUCK TO BREAK
+A MIRROR!! But ask yourself this: what's worse, seeing yourself in the Devil's
+mirror OR simply having bad luck for 7 long years? Let's be honest. You're NOT
+going to make it that long anyway! Why not just give your mind some peace and
+die in an unknown way? Much less scarier AND IF YOU DON'T BREAK IT I WILL! I
+don't want to see the Devil in your mirror! OH HELL! NOT AGAIN! I MEAN I DON'T
+WANT TO SEE YOU IN THE DEVIL'S MIRROR!!!
+
+<32>
+
+Uh oh. ONE OF THE OXEN JUST KICKED A BUCKET. Is it going to die next? Or...is
+it foreshadowing your own death? Let's face it. You have it coming to you. Better
+throw the ox out with the bathwater before it's too late. Oh and don't try telling
+me you don't have any oxen left, if you can even count! It kicked the bucket SO OF
+COURSE IT DOESN'T EXIST!!
+
+<33>
+
+ A GROUP OF TYRANNOSAURUSES ATTACK!
+
+Unfortunately for you, you're in a time LONG BEFORE the brilliant mathematician
+Ian Malcolm informed us that DINOSAURS FIND A WAY TO KILL HUMANS. You should
+have thought of that BEFORE you STUPIDLY climbed into that Time Machine to
+travel back in time to the Oregon Trail, where you could not possibly know so
+many important things about dinosaurs...
+
+ALTHOUGH, now I think on it, that MIGHT not have been EXACTLY how it went... I
+THINK the correct wording was 'LIFE FINDS A WAY' but that's well over 100 years
+from now and instead of life finding a way the Devil will find a way. To
+torment you. With more dinosaurs. And dragons. Yes they still exist. Oh and the
+Earth is flat too...
+
+<34>
+
+ / \
+ / A \
+ |TORMENTED|
+ | PIONEER |
+ | R.I.P. |
+ |_________|
+ GAME OVER
+ Here you lie dead,
+ You tried to outrun a runaway bed.
+ But you slipped and hit your head,
+and now you body's forever in an underground bed!
+
+<35>
+
+Blizzard in mountain pass--time wasted asking Devil for help restocking.
+
+Unfortunately, the unfaithful monster only gives you ONE MEASLY BULLET. Like
+that's going to help his most faithful lieutenant? Oh but are you faithful?
+
+Perhaps you should have used a mountain cable car, rather than relying on the
+Devil! It's pretty funny you didn't know he was unfaithful and yet expects
+complete loyalty. Or else. HE'S COMING.
+
+<36>
+
+You have been on the trail too long and you die of boredom.
+
+You know you're lucky to have made it this long. Frankly with your behaviour
+I'm surprised you didn't die from a sinful disease much earlier. Or drowning in
+molasses. Or freezing to death with your choice in clothing.
+
+SERIOUSLY mate, you brought shorts, briefs, A DRESS AND A BIKINI on the Oregon
+Trail? What the hell were you thinking? Actually though...now I think on
+it...perhaps Hell WILL serve you better? I hear the Summers are AMAZING there!
+Winters, not so much.
+
+At least your family gets free food now, assuming monsters are edible. I'm not
+sure if they are. I suspect they would be poisoned or die from your hot,
+burning flesh.
+
+<37>
+
+You'd better do some hunting or buy food soon, before you starve to death! Or
+don't. Let's face it. You'd deserve it.
+
+<38>
+
+Doctor's bill is $666 and you can't afford it DUE TO ALL YOUR RECKLESS
+SPENDING! HE MUST BE POSSESSED BY BEELZEBUB! SURELY ONLY THE DEVIL would do
+this. It's not like you've ever killed a helpless animal or human, never robbed
+anyone, never ate human flesh or done any other heinous thing, never sinned ...
+
+NO. STOP LYING! YOU signed the Devil's book! You should have listened to your
+Reverend Samuel Parris way back in 1692. All these wild, strange and bad
+happenings, since you began your journey are ALL YOUR fault, EVEN YOUR
+DAUGHTERS' WILD DANCING BY THE NIGHT FIRES AS IF POSSESSED! Not that I'm going
+to complain about THAT...Hell, THEY ASKED ME TO JOIN THEM!
+
+<39>
+
+ ( SON'S VOICE )
+
+How you feeling about eating me? Eating your own son, NO WONDER she was having
+an affair before her untimely death! It was with YOUR SISTER AND HER HUSBAND.
+
+OH NO. NO, NO, NO, NO!! Please don't tell me you ate her too. Wait. You didn't
+feed her to us, did you? Ugh, you did, didn't you? You're a sick, sick person.
+
+<40>
+
+You have died of dysentery.
+CONGRATULATIONS ON REACHING
+ LEGENDARY STATUS!
+
+<41>
+
+ YOU HAVE DIED OF INJURIES!
+
+Better than diarrhoea though, right?
+
+Frankly, it serves you right. If you hadn't wasted all that time and money
+sinning you MIGHT have made it. But I guess there's no real difference; after
+all, none of us really make it out alive, do we? Well off you go then! HEAVEN
+AWAITS!! Or does it?
+
+<42>
+
+Do you want to (1) stop at the next fort, (2) hunt or (3) continue?
+<43>
+
+Do you want to (1) hunt or (2) continue?
+<44>
+
+You need more bullets to go hunting. Or -- do you?
+
+<45>
+
+You have died of exhaustion. I'm SURE your victims ARE MOURNING FOR YOUR
+FAMILY. Assuming they're not too busy EATING YOU WITH THEM. I KNOW FOR A FACT
+your daughters LOVE meat and I'm sure they're already devouring you! Hopefully
+they'll save some for everyone else this time; it'd be a REAL SHAME if your
+body went to waste...or would it be?
+
+<46>
+
+DON'T BE ABSURD! You don't have that kind of money. In fact, One of your
+daughters told me JUST LAST NIGHT that ONCE AGAIN you had a delightfully sinful
+night! NO! I KNOW WHAT YOU'RE THINKING! NOTHING HAPPENED BETWEEN US! STOP THAT
+RIGHT NOW, YOU FILTHY SINNER!
+
+Hmm...although...now I think on it, I'm starting to wonder... OH HELL! NO NO
+NO! WHAT IF SHE SEDUCED ME AND WE DID DO SOMETHING? That would be AWFUL,
+JUDGING YOU WHILE HAVING AN AFFAIR WITH ONE OF THE WOMEN! Still sure WE'D NEVER
+SIGN THE DEVIL'S BOOK!
+
+Although...I don't really remember WHAT we did last night... ANYWAY, KEEP US
+OUT OF IT YOU MONSTER! The book has a cost and money doesn't grow on trees.
+Perhaps it might grow on horns though? Ask the Devil for help. Assuming he
+helps MONSTERS.
+
+<47>
+
+You FINALLY arrived at Oregon City after 2170 long miles!
+
+TOOK YOU LONG ENOUGH. Probably all your sinful detours I've heard so much about
+but you'd think that the Devil would have helped you out on that. But I guess
+as long as you make it to your final destination that's what matters, right?
+
+Oh, right. Almost forgot! President Jesse James asked me to wish you a
+prosperous life ahead of you...in HELL!
+
+<48>
+
+Phantom blizzard from Hell suddenly hits and you freeze to death, leaving
+everyone behind. You know the Devil is calling you, right?
+
+And with your choice in clothing, ARE YOU REALLY SURPRISED YOU FROZE TO DEATH?
+I mean SERIOUSLY mate, you brought shorts, briefs, A DRESS AND A BIKINI on the
+Oregon Trail? What the hell were you thinking? You're not in Hell, you're on
+the Oregon Trail!
+
+Although...now I think on it...perhaps Hell WILL serve you better? I hear the
+Summers are GREAT there! Lots of parties. Winters are -- actually, there are no
+winters. ONLY WEATHER TO BURN YOU FOR ETERNITY.
+
+At least your family gets fresh meat on the bone, assuming they can stomach
+eating a horrible monster. If I were them I'D BURN YOUR BODY.
+
+<49>
+
+Uh oh. THERE'S ANOTHER ELF! You must be losing your mind my friend! ELVES DON'T
+EXIST, unless you ask a German. They can't even count to 11 without claiming
+there are elves! Neun, zehn, Elf ... I guess I might be losing my mind too!
+BETTER SHOOT THE ELF BEFORE IT TAKES YOUR DAUGHTERS AWAY AND EATS THEM! You
+might need them for food later on, you HORRIBLE, HORRIBLE MONSTER. They are
+heavenly women and are not for evil Devil worshippers to eat! NO. NOT FOR ME
+EITHER! STOP GOING THERE YOU SICKO! THEY ARE NOT FOOD AND YOU CANNOT GO TO
+HEAVEN, YOU DEVIL WORSHIPPING MONSTER! CUT IT OUT. NO! NOT THEM! STOP WHAT
+YOU'RE DOING!!!
+
+<50>
+
+You need more bullets to go hunting. Or..do you?
+
+<51>
+
+You shot a Bald Eagle. WHY, monster, WHY?!
+
+I mean look at its former strength, its majesty! No wonder it became the symbol
+of America!
+
+GREAT JOB Devil worshipping pioneer, you just killed America! I hope it's
+poisoned or you at least choke on the bones.
+
+<52>
+
+Great shot! YOU GOT THE FATTEST ONE THERE! As if that should be hard. IT COULD
+BARELY MOVE! But with your WILD SHOOTING AND HORRIBLE AIM the ONLY REASON you
+didn't miss by a hundred miles is you signed the Devil's book, EVEN THOUGH IT
+WAS AS WIDE AS A BLUE WHALE. There's no way you'd have got such a nice shot
+EVEN IF THE POOR BEAST WAS PRACTICALLY DEAD. I'm STILL surprised you didn't
+shoot yourself in the eyes. But the Devil DOES exact his dues and the animal
+might have been poisoned. Eat at your own risk. OR STARVE. Let's face it,
+YOU'RE DOOMED.
+
+<53>
+
+WHAT A TERRIBLE SHOT! How could anyone POSSIBLY miss a helpless animal that was
+standing still, 100 FEET WIDE AND 150 YEARS OLD? IT WAS SO FAT IT WOULD MAKE
+100 BLUE WHALES OBESE!
+
+I hope you starve, you murderous beast, and it looks like you're going to,
+after WASTING ALL THOSE BULLETS and MISSING FISH OUT OF WATER. You'd better buy
+some food NOW.
+
+<54>
+
+Severe illness. You must see Doctor Beelzebub. Assuming he's not too busy
+trying to tempt your daughters. Don't worry though! I don't think he'll
+succeed. I haven't yet either and I'VE BEEN TRYING FOR YEARS! THEY ARE BLOODY
+INCORRIGIBLE MUMPSIMUSES!! No. I don't think he's possessed me. I'm just like
+that. But we can test it. What do you think about performing an exorcism on me?
+
+Actually...no. I take that back. Let me perform one on YOU to make sure it
+works. I'm pretty sure they don't but better to do it on a Devil worshipper
+than someone who's unhinged from watching you. Safer that way.
+
+<55>
+
+If we are what we eat then doesn't that mean we're all cannibals?
+
+<56>
+
+
+ Riders ahead. They don't look hostile.
+
+Oh! I know what to do! You should TOTALLY ROB THEM BLIND!! They won't know what
+hit them and it's not like they need their belongings, not where they are
+going, and you're going to need them soon, with your reckless behaviour.
+
+<57>
+
+
+<58>
+
+
+<59>
+
+
+<60>
+
+
+<61>
+
+You scared them off with your ERRATIC shooting. NEARLY BLEW MY HEAD OFF TOO.
+GREAT JOB.
+
+<62>
+
+ WORST SHOT EVER! You got knifed by the dung!
+ How did you miss the TRIGGER?
+
+Be honest. IT'S YOUR OWN STUPID FAULT FOR TRYING TO ATTACK FRIENDLY PEOPLE!
+Seriously, what the hell kind of person does that? I'm glad the dung knifed
+you. And remember that if the wound becomes infected with bacteria IT'S YOUR
+OWN BLOODY FAULT.
+
+Better have Doctor Beelzebub check it out, assuming he wasn't shot and treats
+MONSTERS. I hope he was shot!
+
+<63>
+
+You have to see Doctor Beelzebub!
+
+<64>
+
+
+<65>
+
+
+<66>
+
+Riders were friendly, but check for possible losses anyway. It's always the friendly ones
+who do something bad!! They're OBVIOUSLY hiding something!
+
+<67>
+
+
+<68>
+
+I JUST HATE VAMPIRES! Don't you? If they had it their way THERE WOULD BE NO
+SUN! Can you imagine how HORRIBLE that would be?!
+
+Wait. You mean to tell me...you want ETERNAL Sun and NO Moon?! Only ONE reason
+for that! You MUST be a...WEREWOLF! I KNEW IT! Better watch your heart. If you
+have one. Your daughters have SILVER SPOONS and they're FED UP WITH YOUR
+BARKING BEHAVIOUR!
+
+On the other blade...IT IS VERY HOT don't you think? Almost as if it's
+foreshadowing what's to come! MAYBE WE SHOULD GET RID OF FIRE TOO! I mean
+you're in extreme danger of that too! THEN WE CAN DROWN you so you can BURN IN
+HELL!!! And if that doesn't work, we can behead you with the SPOONS!!
+
+<69>
+
+Suddenly...the hairs on your neck stand up. ARE YOU ACTUALLY A WEREWOLF? You
+do know that there are silver spoons in your daughters' wagon, right?
+
+Better run for your life or howl to scare them off before it's too late,
+because they told me that they HATE wolves, are SICK OF your BARKING BEHAVIOUR
+and THEY'VE HAD ENOUGH OF YOUR DEVIL WORSHIPPING!!
+
+Oh and yes. Spoons CAN stab you in the heart. If you don't believe me...try it.
+Assuming you have a heart in the first place...
+
+<70>
+
+You ran out of bullets and got massacred by the riders.
+
+How I do not know, seeing as how they were friendly. Oh
+I remember now. It's because you actually decided to
+cowardly try and rob them blind.
+
+<71>
+
+ ____
+ ____( )____
+ / o \
+( FLAT OXEN )
+ \____ ____o_/
+ | |
+Flat oxen--slows you down.
+
+And don't try telling me you didn't have an ox because that would also be a
+flat ox!
+
+<72>
+
+About 100 feet from here YOU SWEAR you see an ox stuck in a hole. THANK THE
+DEVIL IT'S NOT A DONKEY! You KNOW what that would make!! There are enough here
+already! NO! Don't look at me! I DON'T MEAN THAT, YOU LITTLE JERK!!
+
+But of course YOU'RE WRONG AS USUAL. IT'S NOT AN OX. You NEED a pair of VERY
+POWERFUL glasses my friend. Might also want to avoid that funny fungi...could
+be related...somehow. But really get some eyeglasses!
+
+ IT'S OBVIOUS YOU SEE A UNICORN!!!!
+
+<73>
+
+Bad luck--you got gangrene in one of your limbs and you had to chop it off. Or
+maybe it was good luck? FREE FOOD TONIGHT!!!
+
+<74>
+
+Oh dear. That isn't the Barghest AGAIN is it? Better watch your back! And
+front. And above you. Actually, YOU'RE DOOMED and you know it. Your fate was
+sealed upon signing the Devil's book. Honestly, what were you thinking? You HAD
+to have known it always comes with a cost. And you and I BOTH KNOW that the
+women were warning you - but you just HAD to have your way, didn't you?
+
+Well the Oregon Trail is out to get you in every direction and the odds are you
+won't make it out alive. You might be in good company there, AND YOU AT LEAST
+GET TO SEE DINOSAURS ALIVE (LUCKY YOU!!) BUT THERE'S NO AIR CONDITIONING and I
+heard it gets REALLY HOT down there. Then again, I also heard there's no heater
+in Heaven... Yup, either way YOU'RE DOOMED AND YOU KNOW IT! But don't feel too
+bad. At least you won't FREEZE TO DEATH. You might here though... Yup, FREEZE
+TO DEATH HERE and then BURN TO DEATH THERE!
+
+<75>
+
+Your son gets lost and FREEZES TO DEATH!
+
+But on the bright side, you now have one fewer person to feed and not only that
+you get a FREE MEAL TONIGHT!!! Not that you've been starving yourself
+deliberately. You're a glutton and you know it. But hey, now you have FRESH
+MEAT ON THE BONE!! Why not START A FEAST? You did remember your pots and
+deadpans, right? IF NOT I HOPE YOU STARVE TO DEATH. OH AND YOU BETTER SHARE
+THIS TIME!
+
+<76>
+
+OH HELL! That water tasted REALLY funny! No. Sorry. NOT Hell. There is no water
+in Hell! Well, wherever you are, it appears you drank unpotable water and it's
+too late now.
+
+Next time LOOK AT WHAT you intend on swallowing BEFORE YOU SHOVE IT DOWN YOUR
+THROAT, because you now have dysentery.
+
+<77>
+
+ Heavy rains---time and supplies lost.
+
+But seriously, you brought PERMANENTLY CLOSED brollies?
+
+You SHOULD HAVE BROUGHT open ones instead! AND HATS!!
+
+<78>
+
+ THE QUEEN ANNE'S REVENGE ATTACKS!
+
+YES. You're right. That WAS Blackbeard's ship! Yes EDWARD TEACH IS ON THE
+OREGON TRAIL! NO, YOU'RE NOT HALLUCINATING. Neither am I. Didn't you know he
+also signed the Devil's book? Oh well, now you've been taught. Still, a ghost
+is a ghost...THIS SHOULD BE EASY!!
+
+But face it. After all you've done, you DESERVE THIS AND YOU KNOW IT! I HOPE HE
+ROBS YOU BLIND and if you die in the process you know it's your fault. Your
+time is coming and the Devil is calling you, laddie.
+
+<79>
+
+BLACKBEARD DIED OVER A CENTURY AGO AND HE STILL GOT YOU!
+
+Yes SOMEHOW you got shot in the leg and robbed by a GHOST.
+
+GREAT JOB!
+
+<80>
+
+You got shot in the leg and they took one of your oxen, whether or not you have any
+oxen left. Not that that matters much; you're more than capable of stealing one,
+assuming you don't sacrifice it to the gods. The Devil. I meant the Devil.
+
+<81>
+
+ WELL DONE, LAD!!!
+
+Somehow, you scared the pirates off! Unfortunately you also managed to steal
+food and miscellaneous supplies from the pirates as they fled, though I
+honestly haven't a bloody clue how you did that. I do hope you get food
+poisoning so you can finally meet the Devil like Blackbeard was SUPPOSED to
+have. But aren't historians so awful, lying about Blackbeard? YOU'RE NEXT,
+LAD!
+
+<82>
+
+There was a fire in your wagon. Too bad only food and supplies were lost! You
+know you deserve worse, right?
+
+<83>
+
+Lost your way in heavy fog but somehow you did not lose much time, due to the
+STRANGE MAP in the LAST BOOK you read.
+
+You know which book I mean. Sure. IT IS a FASCINATING READ! But you do know
+it's going to cost you though, right?
+
+<84>
+
+ A dragon eats you!
+
+No, I know what you're probably thinking. I would TOO! Who wants to be eaten by
+a dragon? But THIS TIME IT WAS NOT any of the grass you understandably ate when
+you were ravenous.
+
+No. I'm afraid not. The Earth is flat, dragons are real and the Sun is crazy.
+Oh and yes the Devil is also real. But you ALREADY knew that didn't you?
+Welcome to the harshness of the Oregon Trail. Or was it the Devil's bedchamber?
+Oh well, you're dead now so no sense brooding over what seems like Hell. Why
+not go to the REAL Hell instead? OH HELL, WHY NOT make it the Devil's
+bedchamber? Be faithful. FOR ONCE. HELL, YOU MIGHT EVEN ENJOY IT! No, not Hell.
+Okay...actually...yeah, Hell too.
+
+<85>
+
+You die of a snakebite because you stupidly didn't bring any
+antivenin. Oh wait. I forgot. They haven't invented it yet
+and nobody wants to suck the venom out of you. I'm actually
+surprised they haven't abandoned you entirely. Oh well, now
+they don't need to, although they might not be wise to have
+the fresh off the bone meat.
+
+<86>
+
+Wagon got swamped fording river; lost food, clothes and an ox got stuck,
+whether or not you spared no expense on oxen. Alas, you couldn't save him.
+
+WAIT. You didn't swim in the Molasses River AGAIN, did you? HOW MANY TIMES DO I
+HAVE TO REMIND YOU THAT THIS IS A VERY BAD IDEA? If only you thought to bring a
+portable oven so you could AT LEAST bake molasses cookies! But you didn't. I
+hope you starve. Then you'll be able to cook all the cookies in the world.
+HELL. I MEANT IN HELL.
+
+<87>
+
+Wild dragons attack! And you actually thought you could shoot
+them? Everyone knows dragons have armoured scales. I mean what
+was the point? You should have brought yourself a pair of wings
+so you could fly straight into the fire, so that you would've
+gone out in STYLE and with an amazing legacy!
+
+And no, I'm afraid you weren't hallucinating. The Earth IS flat,
+dragons ARE real and the Sun IS crazy. Oh and the Devil is real
+too. But you already knew that, didn't you, you filthy sinner?
+
+<88>
+
+Unfortunately, bullets won't help you with dragons; I'm surprised
+you didn't know that. Anyone knows dragons have armoured scales.
+Unfortunately for you they took a few oxen and upturned your wagon
+train, causing you further delays.
+
+Just be thankful you're still alive because this time you were walking
+on dragon eggshells. No. If you did that you'd be dead. I meant walking
+a thin line.
+
+<89>
+
+GREAT SHOOTING---they didn't get anything but you killed
+one of your oxen and somehow you managed to upturn your wagon.
+
+<90>
+
+Really? You tried to shoot a dragon? Well that was pointless. They ate one
+of your oxen and upturned your wagon train, causing further delays.
+
+<91>
+
+ ( SON'S VOICE )
+
+How you feeling about eating me? Eating your own son, and you're sick, too.
+Probably food poisoning. GOOD. SERVES YOU RIGHT. Time to die.
+
+<92>
+
+ You freeze to death.
+And with your choice in clothing, ARE YOU REALLY SURPRISED? I mean SERIOUSLY
+mate, shorts, briefs, A DRESS AND A BIKINI on the Oregon Trail? What the hell
+were you thinking? You're not in Hell, you're on the Oregon Trail!
+
+Although...now I think on it, perhaps Hell WILL suit you better? I hear the
+Summers are GREAT there! Winter is as cold as Hell though. No. Not Hell. Hell
+does not get cold! You're going to BURN, BURN, BURN!!!!
+
+
+<93>
+
+Doctor's bill is $666! HE MUST BE POSSESSED BY BEELZEBUB! SURELY ONLY THE DEVIL
+would do this. It's not like you've ever killed a helpless animal or human,
+never robbed anyone, never ate human flesh or done any other heinous thing,
+never sinned ...
+
+NO. STOP LYING! YOU signed the Devil's book! You should have listened to your
+Reverend Samuel Parris way back in 1692. All these wild, strange and bad
+happenings, since you began your journey are ALL YOUR fault, EVEN YOUR
+DAUGHTERS' WILD DANCING BY THE NIGHT FIRES AS IF POSSESSED! Not that I'm going
+to complain about THAT...Hell, THEY ASKED ME TO JOIN THEM!
+
+<94>
+
+Hail storm--YOU WERE HIT ON THE HEAD and supplies were damaged. But did you
+REALLY think this CLOSED BROLLY was going to help you against HAIL? Even this
+one PROBABLY wouldn't do much good. YOU SHOULD HAVE BROUGHT A HAT!!
+
+<95>
+
+Helpful Indians show you where to find more food. Pizza, hamburgers,
+chips/fries and other greasy, fatty foods ...
+
+Okay so IT'S ONLY A HEART ATTACK ON A PLATE but at least you'll survive another
+day...if you don't have a heart attack first, that is... Better have your
+Doctor Beelzebub check you out. If he's still alive. Oh no.
+
+You didn't eat him when you were starving last time, did you? If so I hope you
+DO have a heart attack!
+
+<96>
+
+Rugged mountains.
+
+<97>
+
+You got lost, losing valuable time asking the Devil for directions to the
+CROSSROADS.
+
+But honestly, HOW DID you get lost? It's practically a TRAFFIC JAM OUT HERE AND
+ONLY A COMPLETE MORON COULD LOSE THEIR WAY.
+
+HISTORIANS WILL BE TALKING ABOUT THIS YEARS DOWN THE TRAIL! OH NO. WHAT DID YOU
+DO THIS TIME? You did do something didn't you? I KNOW you did! You ALWAYS do
+something stupid!
+
+<98>
+
+Severe illness. You must see Doctor Beelzebub. Assuming he's not too busy
+trying to tempt your daughters. Don't worry though! I don't think he'll
+succeed. I haven't yet either and I'VE BEEN TRYING FOR YEARS! THEY ARE BLOODY
+INCORRIGIBLE MUMPSIMUSES!! No. I don't think he's possessed me. I'm just like
+that. But we can test it. What do you think about performing an exorcism on me?
+
+Actually...no. I take that back. Let me perform one on YOU to make sure it
+works. I'm pretty sure they don't but better to do it on a Devil worshipper
+than someone who's unhinged from watching you. Safer that way.
+
+<99>
+
+You ran out of medical supplies and unfortunately the Devil's in Heaven on
+holiday / business and can't help you restock.
+
+But honestly, who goes on a 2170 MILES journey WITHOUT bringing medical
+supplies? You brought this on to yourself and you deserve it. But at least I
+just heard that the Devil is on his way home to greet you and thank god for
+that! Send me a postcard, will you? I want to make sure it works out well for
+you down there.
+
+<100>
+%ld
+<101>
+
+Wagon train damaged! Lost time resupplying from the Devil.
+
+<102>
+
+Suddenly your clocks stop...
+
+I guess it must have happened AGAIN! And WHY THE DEVIL DO YOU KEEP SWIMMING IN
+THE MOLASSES RIVER?! Honestly, you'll be lucky if you don't SINK IN IT before it
+sinks into your stick-in-the-molasses head.
+
+<103>
+
+You made it safely through South Pass--no snow. Clearly the Devil has your
+back. For now my dear fiend, for now...
+
+He might be plotting against you. Oh hell. I KNOW HE IS. HE TOLD ME HE IS. Your
+time is coming AND THE DEVIL AND I BOTH CANNOT WAIT! Neither can your
+daughters. They told me last night in the wagon.
+
+<104>
+
+Blizzard in mountain pass--time wasted asking Devil for help restocking.
+
+Unfortunately, the unfaithful monster only gives you ONE MEASLY BULLET. Like
+that's going to help his most faithful lieutenant? Oh but are you faithful?
+
+Perhaps you should have used a mountain cable car, rather than relying on the
+Devil! It's pretty funny you didn't know he was unfaithful and yet expects complete
+loyalty. Or else. HE'S COMING.
+
+<105>
+
+All you had was mouldy bread,
+Therefore here you must lie.
+Because now you're dead.
+ GOODBYE!
+
+<106>
+
+How does a turtle tell his friend to move aside? Scute over!
+
+<107>
+
+You ran out of medical supplies and unfortunately the Devil's in Heaven on
+holiday / business and can't help you restock.
+
+But honestly, who goes on a 2170 miles journey WITHOUT bringing medical supplies?
+You brought this on to yourself and you deserve it. But at least I just heard that
+the Devil is on his way home to greet you and thank god for that! Send me a
+postcard, will you? I want to make sure it works out well for you down there.
+
+<108>
+
+If your printer is working you're VERY OBVIOUSLY not using it right. And if you
+do not understand this may your good fortune last my dear friend. You'll need it.
+
+<109>
+
+YOU HAVE DIED OF INJURIES!
+
+Better than diarrhoea though, right?
+
+Frankly, it serves you right. If you hadn't wasted all that time and money sinning you
+MIGHT have made it. But I guess there's no real difference; after all, none of us really
+make it out alive, do we? Well off you go then! HEAVEN AWAITS!! Or does it?
+
+<110>
+
+You have died of dysentery.
+CONGRATULATIONS ON REACHING
+ LEGENDARY STATUS!
+
+<111>
+
+If you lost your sense of irony then try looking in a blue tissue box.
+
+<112>
+
+I MAY be delusional but at least I have a VIVID imagination!
+
+<113>
+
+%f
+<114>
+
+You FINALLY arrived at Oregon City after 2170 long miles!
+
+TOOK YOU LONG ENOUGH. Probably all your sinful detours I've heard so much about but you'd think
+that the Devil would have helped you out on that. But I guess as long as you make it to your final
+destination that's what matters, right?
+
+Oh, right. Almost forgot! President Jesse James asked me to wish you a prosperous life ahead of
+you...in HELL!
+
+<115>
+
+Monday
+<116>
+
+Tuesday
+<117>
+
+Wednesday
+<118>
+
+Thursday
+<119>
+
+Friday
+<120>
+
+Saturday
+<121>
+
+Sunday
+<122>
+
+1847
+<123>
+
+July
+<124>
+
+August
+<125>
+
+September
+<126>
+
+October
+<127>
+
+November
+<128>
+
+December
+<129>
+
+Doughnuts. Need doughnuts.
+
+<130>
+
+President Jesse James sends you his heartiest congratulations
+and wishes you a prosperous life ahead at your new home in HELL!
+
+<131>
+
+What does a tomato do when it sees an old friend? It ketches up with it.
+
+<132>
+
+The only reason the British Museum has only a model of the Pyramid of Giza
+is because the real thing is too big to move.
+
+<133>
+
+Windows driving you crazy? Buy a scanner and install the included SANE library!
+
+<134>
+
+Nitrous Oxide: the carbon monoxide for laughing hyenas; they'll literally die from laughter.
+
+<135>
+
+I can't imagine ever going wireless. Not only am I fully wired, I enjoy it immensely.
+
+<136>
+
+If you're confused when someone tells you you're wrong to write:
+
+ void main()
+ {
+ }
+
+please feel free to try the following instead:
+
+ void brain()
+ {
+ }
+
+because that is perfectly valid C.
+
+Sorry for the inconvenience and thanks for your understanding,
+
+-- Neurosurgery Department of C, AT&T Bell Labs.
+
+<137>
+
+Severe illness. You must see Doctor Beelzebub. Assuming he's not too busy
+trying to tempt your daughters. Don't worry though! I don't think he'll
+succeed. I haven't yet either and I'VE BEEN TRYING FOR YEARS! THEY ARE BLOODY
+INCORRIGIBLE MUMPSIMUSES!! No. I don't think he's possessed me. I'm just like
+that. But we can test it. What do you think about performing an exorcism on
+me?
+
+Actually...no. I take that back. Let me perform one on YOU to make sure it works.
+I'm pretty sure they don't but better to do it on a Devil worshipper than
+someone who's unhinged from watching you. Safer that way.
+
+<138>
+
+Mild illness. Medicine used. Not sure why though. IT WAS ONLY A SNIFFLE. Probably just
+the Devil TRYING TO ESCAPE FROM YOUR CURSED NOSTRILS. In the future THEY BLESS PEOPLE
+FOR SNEEZING. You can die happy knowing you started a thing. Even if your death will
+bring you EVERLASTING TORMENT.
+
+<139>
+
+The Tale of Two Gates: Bill Gates puts holes in your windows; Josh Gates puts holes in
+the ground. And your grave.
+
+ The end.
+
+<140>
+
+Fun fact about blindness:
+
+<141>
+
+ / \
+ / A \
+ |TORMENTED|
+ | PIONEER |
+ | R.I.P. |
+ |_________|
+ GAME OVER
+Unfortunately, due to what can only be an ADMINISTRATIVE FOUL-UP, you end up somewhere
+you did not expect as your forever home. But honestly, after signing the Devil's book, DO
+YOU REALLY BELIEVE YOU DON'T BELONG HERE? Be honest. For once. You know you belong here.
+Oh, by the way, god asked me to wish you a PROSPEROUS LIFE ahead...
+ WELCOME TO HELL!!
+
+<142>
+
+A fire breaks out in your wagon, and the wind quickly fans the flames,
+CAUSING YOUR AMMO TO BLOW UP, killing you! Somehow everyone else survived...
+
+Frankly, IT WAS ABOUT TIME. I mean WHAT KIND OF IDIOT overloads their wagon with
+WEAPONS?
+
+<143>
+
+ .''.
+ :_\/_:
+ .:::::.
+ ':/\:'
+ '..'
+ / \
+ |Heaven|
+ |Awaits|
+ | You! |
+ '------'
+
+<144>
+
+ / \
+ / A \
+ |TORMENTED|
+ | PIONEER |
+ | R.I.P. |
+ |_________|
+ GAME OVER
+
+ Here you lie dead,
+ You tried to outrun a runaway bed.
+ But you slipped and hit your head,
+and now you body's forever in an underground bed!
+
+<145>
+
+The only food you have left is an ox!
+
+As you have no choice left, you promptly kill it before it runs away, and it sure
+was DELICIOUS!!!
+
+ ( OX'S VOICE )
+You're a sick, sick individual. You do know that, right? First you BURDEN ME
+WITH ALL YOUR RUBBISH and THEN YOU EAT ME?
+
+I hope you remember you were starving me to death so it's your fault you won't get
+much sustenance from MURDERING YOUR FAITHFUL SLAVE ANIMAL!!! Not that I had a
+choice.
+
+And YES, there's a place IN HELL FOR MONSTERS LIKE YOU, AND YES YOUR TIME IS
+FAST APPROACHING, YOU RUDDY UNFAITHFUL LITTLE GIT.
+ HE'S WAITING.
+
+<146>
+
+You have run out of oxen and must walk. Better buy more... IF YOU DIDN'T WASTE MORE MONEY ON
+MORE SINFUL NIGHTS, like your red-headed daughters told me last night, ASSUMING THEY
+WEREN'T LYING TO ME. I bet they weren't. You just can't help it can you?
+
+AND YES. A dirty mind IS a TERRIBLE thing to waste BUT NOTHING HAPPENED BETWEEN US!! We're
+JUST FRIENDS and they've been telling me ALL ABOUT YOUR RIDICULOUS BEHAVIOUR. OK, it MIGHT
+be in bed but they can't help themselves...kind of like you. WHERE do you think they get it
+from? But WE EXPRESS PASSION and YOU ARE AN EVIL MONSTER!!!! Good luck hauling your wagon!
+WE'RE TAKING A PLANE!
+
+<147>
+
+You've lost too many limbs but you can die happy knowing your family gets more free
+food! Sure it's toxic food but it's still food...
+
+
+<148>
+
+ Food: %4ld Ammo: %4ld Clothing: %4ld
+ Oxen: %4ld Supplies: %4ld Money: %4ld
+ Health: %4ld Miles: %4ld
+
+<149>
+
+ ( SON'S VOICE )
+
+How you feeling about eating me? Eating your own son, NO WONDER she was having an affair
+before her untimely death! It was with YOUR SISTER AND HER HUSBAND.
+
+OH NO. NO, NO, NO, NO!! Please don't tell me you ate her too.
+Wait. You didn't feed her to us, did you? Ugh, you did, didn't
+you? You're a sick, sick person.
+
+<150>
+
+ ( SON'S VOICE )
+
+How you feeling about eating me? Eating your own son, and you're
+sick, too.
+
+Probably food poisoning. GOOD. SERVES YOU RIGHT. Time to die.
+
+<151>
+
+ ( OX'S VOICE )
+
+Still happy you ate me? How many more miles do you have to go?
+
+YOU'RE COOKED and you know it, you horrible, HORRIBLE MONSTER.
+
+<152>
+
+Shooting when low on bullets. That's really intelligent. NO WONDER you're starving.
+
+
+<153>
+
+You take lots of cash from the riders, accidentally shooting one as he flees. But
+since you're starving, why don't you MAKE PENANCE BY NOT WASTING THE BODY?
+
+ Mm...that was DELICIOUS!!!
+ ( RIDER'S SOBBING VOICE FROM THE GRAVE )
+You know what you did is wrong, right? We were JUST ROBBED YESTERDAY, you rob us today
+AND NOW I'M DEAD!
+
+WELL GOOD. I WAS DYING OF DYSENTERY and now YOU get to SPREAD THE DISEASE as well.
+
+<154>
+
+Uh oh. A black cat just jumped out in front of you. Is the Devil calling you? Better
+go have a look before it's too late. Maybe it already is. Your daughters told me
+you're an ailurophobe! Some pretty wild stories I hear. I think it probably is too
+late. Isn't it Friday the 13th?
+
+<155>
+
+Oh dear. That isn't the Barghest AGAIN is it? Better watch
+your back! And front. And above you. Actually, YOU'RE DOOMED
+and you know it. Your fate was sealed upon signing the Devil's
+book. Honestly, what were you thinking? You HAD to have known it
+always comes with a cost. And you and I BOTH KNOW that the women
+were warning you - but you just HAD to have your way, didn't you?
+
+Well the Oregon Trail is out to get you in every direction and
+the odds are you won't make it out alive. You might be in good
+company there, AND YOU AT LEAST GET TO SEE DINOSAURS ALIVE (LUCKY
+YOU!!) BUT THERE'S NO AIR CONDITIONING and I heard it gets REALLY
+HOT down there. Then again, I also heard there's no heater in
+Heaven... Yup, either way YOU'RE DOOMED AND YOU KNOW IT! But don't
+feel too bad. At least you won't FREEZE TO DEATH. You might here
+though... Yup, FREEZE TO DEATH HERE and then BURN TO DEATH THERE!
+
+<156>
+
+Wagon train gets swamped fording river--lose food, clothes, an ox
+drowns and you get hurt.
+
+<157>
+
+You have died of exhaustion. I'm SURE your victims ARE MOURNING FOR YOUR FAMILY.
+Assuming they're not too busy EATING YOU WITH THEM. I KNOW FOR A FACT your
+daughters LOVE meat and I'm sure they're already devouring you! Hopefully they'll
+save some for everyone else; it'd be a REAL SHAME if your body went to waste...or
+would it be?
+
+<158>
+
+Doctor's bill is $666! HE MUST BE POSSESSED BY BEELZEBUB! SURELY ONLY THE DEVIL would
+do this. It's not like you've ever killed a helpless animal or human, never robbed
+anyone, never ate human flesh or done any other heinous thing, never sinned ...
+
+NO. STOP LYING! YOU signed the Devil's book! You should have listened to your Reverend
+Samuel Parris way back in 1692. All these wild, strange and bad happenings, since you
+began your journey are ALL YOUR fault, EVEN YOUR DAUGHTERS' WILD DANCING BY THE NIGHT
+FIRES AS IF POSSESSED! Not that I'm going to complain about THAT...Hell, THEY ASKED ME TO
+JOIN THEM!
+
+<159>
+
+Blizzard in mountains - you freeze to death.
+
+And with your choice in clothing, ARE YOU REALLY SURPRISED? I mean SERIOUSLY mate,
+shorts, briefs, A DRESS AND A BIKINI on the Oregon Trail? What the hell were you thinking?
+You're not in Hell, you're on the Oregon Trail!
+
+Although...now I think on it...perhaps Hell WILL serve you better? I hear the Summers are GREAT
+there! Winters, not so much.
+
+At least your family gets fresh meat on the bone, assuming they can stomach eating a horrible
+monster.
+
+<160>
+
+Looks like the Devil has poisoned you. Your lover, she is waiting. TIME TO GO MEET HER!
+
+<161>
+
+ A GROUP OF TYRANNOSAURUSES ATTACK!
+
+Unfortunately for you, you're in a time LONG BEFORE the brilliant mathematician
+Ian Malcolm informed us that DINOSAURS FIND A WAY TO KILL HUMANS. You should
+have thought of that BEFORE you STUPIDLY climbed into that Time Machine to travel
+back in time to the Oregon Trail, where you could not possibly know so many
+important things about dinosaurs...
+
+ALTHOUGH, now I think on it, that MIGHT not have been EXACTLY how it went... I
+THINK the correct wording was 'LIFE FINDS A WAY' but that's well over 100 years
+from now and instead of life finding a way the Devil will find a way. To torment you.
+With more dinosaurs. And dragons. Yes they still exist. Oh and the Earth is
+flat too...
+
+<162>
+
+One of the daughters cut her arm and it had to be amputated. THANK GOD she is not
+DOWN IN THE MOUTH AND SHE WANTS TO EAT IT BECAUSE YOU ARE SUDDENLY STARVING!!!
+
+But OF COURSE you didn't get any. If you weren't eyeing it so lustily you would have seen that she
+seemed to ESPECIALLY ENJOY IT, GREEDILY DEVOURING IT AS IF IT WAS HER LAST SUPPER! Wait, HAS THE
+DEVIL POSSESSED HER TOO?! THAT EVIL WITCH!!!
+
+Hang on. YOU'RE JUDGING HER AFTER ALL YOU'VE DONE? CUT THAT OUT RIGHT NOW! NO. NO! NO! NO!
+STOP! I DID NOT MEAN CUT ANOTHER LIMB OFF HER! I mean stop accusing her of witchcraft. YOU
+signed the Devil's book, NOT HER and THIS IS HER BODY! This is ALL YOUR FAULT, JUST LIKE
+EVERYTHING ELSE that's happened since that fateful night!
+
+<163>
+
+An ox looks at you funny so you eat him!
+
+You're a sick, sick individual. You do know that, right? FIRST you BURDEN HIM
+WITH ALL YOUR RUBBISH and THEN YOU EAT HIM BECAUSE OF A FUNNY LOOK? And YOU
+DIDN'T EVEN SHARE HIM WITH YOUR FAMILY!
+
+What next, will you eat your daughter too? No! NO! NO NO NO NO! I SHOULD NOT
+HAVE SAID THAT! NO! DON'T EVEN THINK ABOUT TOUCHING HER! BACK OFF!!
+ SHE'S MINE!!!
+
+<164>
+
+A little ghost floats by and shouts: BOO!!!!
+
+Okay that was NOT funny, Casper! Go back to your shallow grave, you LITTLE
+JERK!
+
+<165>
+
+Suddenly...the hairs on your neck stand up. ARE YOU ACTUALLY A WEREWOLF? You do know that
+there are silver spoons in your daughters' wagon, right?
+
+Better run for your life or howl to scare them off before it's too late, because
+they told me that they HATE wolves and THEY'VE HAD ENOUGH OF YOUR DEVIL WORSHIPPING!!
+
+Oh and yes. Spoons CAN stab you in the heart. If you don't believe me...try it. Assuming
+you have a heart in the first place...
+
+<166>
+
+I JUST HATE VAMPIRES! Don't you? If they had it their way THERE WOULD BE NO SUN! Can you
+imagine how HORRIBLE that would be?!
+
+Wait. You mean to tell me...you want ETERNAL Sun and NO Moon?! Only ONE reason for that!
+You MUST be a...WEREWOLF! I KNEW IT! Better watch your heart. If you have one. Your
+daughters have SILVER SPOONS and they're FED UP WITH YOUR ANTICS!
+
+On the other blade...IT IS VERY HOT don't you think? Almost as if it's foreshadowing
+what's to come! MAYBE WE SHOULD GET RID OF FIRE TOO! I mean you're in extreme danger of
+that too! THEN WE CAN DROWN you so you can BURN IN HELL!!! And if that doesn't work,
+we can behead you with the SPOONS!!
+
+<167>
+
+Uh oh. THERE'S ANOTHER ELF! You must be losing your mind my friend! ELVES DON'T
+EXIST, unless you ask a German. They can't even count to 11 without claiming there are
+elves! Neun, zehn, Elf ... I guess I might be losing my mind too! BETTER SHOOT THE ELF
+BEFORE IT TAKES YOUR DAUGHTERS AWAY AND EATS THEM! You might need them for food later on,
+you HORRIBLE, HORRIBLE MONSTER. They are heavenly women and are not for evil Devil
+worshippers to eat! NO. NOT FOR ME EITHER! Stop going there you sicko! They are NOT food
+and you cannot go to heaven, YOU DEVIL WORSHIPPING MONSTER! Cut it out. NO! NOT THEM!
+STOP WHAT YOU'RE DOING!!!
+
+<168>
+
+About 100 feet from here YOU SWEAR YOU SEE AN OX STUCK IN A HOLE. THANK
+GOD IT'S NOT A DONKEY! You KNOW what that would make!! There are enough
+here already! NO! Don't look at me! I DON'T MEAN THAT, YOU LITTLE JERK!!
+
+But OF COURSE YOU'RE JUST HALLUCINATING anyway. IT'S NOT AN OX. You need to lay
+off the mushrooms. Actually YOU NEED TO LAY OFF A LOT of things; you've made
+that VERY CLEAR WITH YOUR UNHINGED BEHAVIOUR!
+
+ IT'S OBVIOUS YOU SEE A UNICORN!!!
+
+<169>
+
+ ~~~~~~
+ / \
+ / \
+ / \
+ | |
+ \ ||| ||| /
+ \ ||||| /
+ \ ||| /
+ \________/
+ || ||
+ || ||
+ __||__||__
+WOW!!!! THAT'S A SPAGHETTI TREE!!! I saw them over 100 years from now when I last
+used my Time Machine!! The BBC will cultivate them on April Fool's Day 19579!
+THEY'RE AMAZING!! The Time Machines are okay and kind of interesting. Dangerous
+though...
+
+But the spaghetti looks pretty ominous, doesn't it? IT LOOKS LIKE IT WANTS TO REACH
+DOWN AND GRAB YOU! Better be careful. If they strangle you YOU WILL GO TO HELL! On the plus
+side... YOU'LL HAVE THE MOST AMAZING STORY to tell your fellow sinners... Trust me. I've
+been there on holiday! It's PRETTY WILD!! Summers are AMAZINGLY HOT!! Although...GETTING
+EATEN BY A DRAGON OR KILLED BY TYRANNOSAURUSES is an EVEN BETTER STORY! That's MUCH MORE
+EXCITING than a SPAGHETTI TREE KILLING YOU!! Although...now I think on it...they're ALSO
+in Hell so maybe it's better if the spaghetti kills you. Want me to strangle you with it if
+it doesn't do it? Of course...the trees are there too...LOTS of parties too. And good old
+TORTURE! IT'S AWESOME!
+
+<170>
+
+Uh oh. ONE OF THE OXEN JUST KICKED A BUCKET. Is it going to die next?
+Or...is it foreshadowing your own death? Let's face it. You have it
+coming to you. Better throw the ox out with the bathwater before it's
+too late. Oh and don't try telling me you don't have any oxen left,
+if you can even count! It kicked the bucket SO OF COURSE IT DOESN'T
+EXIST!!
+
+<171>
+
+Uh oh! Is that the DEVIL I see in your mirror again? Or are YOU looking
+at it from behind your dressing curtain?
+
+BETTER BREAK IT BEFORE IT'S TOO LATE!!! Yes, YES, I KNOW IT'S BAD
+LUCK TO BREAK A MIRROR!! But ask yourself this: what's worse, seeing
+yourself in the Devil's mirror OR simply having bad luck for 7 long
+years? Let's be honest. You're NOT going to make it that long anyway!
+Why not just give your mind some peace and die in an unknown way? Much
+less scarier AND IF YOU DON'T BREAK IT I WILL! I don't want to see the
+Devil in your mirror! OH HELL! NOT AGAIN! I MEAN I DON'T WANT TO SEE
+YOU IN THE DEVIL'S MIRROR!!!
+
+<172>
+
+
diff --git a/2024/ferguson1/strings.loc.txt b/2024/ferguson1/strings.loc.txt
new file mode 100644
index 000000000..5df4e2ae5
--- /dev/null
+++ b/2024/ferguson1/strings.loc.txt
@@ -0,0 +1,1911 @@
+<1>
+This program simulates a trip over the Oregon Trail from Independence, Missouri
+to Oregon City. Your extended family will attempt the 2170 mile Oregon Trail in
+5-6 months. You had $6666 for the trip but after foolishly wasting thousands on
+a sinful night yesterday and paying $200 for a wagon train, you only have an
+ominous $1666. You may buy the following items, or not, if you trust the Devil
+to be faithful to your pact:
+
+ Food - the more you have, the less chance you'll starve to
+ death, which would serve you right.
+ Ammunition - $1 only buys 5 bullets due to recent hoarding.
+ You will need lots of bullets for self defence
+ and for hunting food, assuming you don't miss.
+ Clothing - this is especially important for the cold weather
+ you will encounter when crossing the mountains, if you
+ get there.
+ Oxen - the more you spend the better off you'll be, assuming
+ they don't die. Or you don't sacrifice them.
+ Miscellaneous supplies - this includes medicine and other
+ things you'll need.
+
+You can spend all your money before you start your trip or you can save some of
+your cash to spend at forts along the way when you run low on supplies.
+Alternatively, you might wish to spend it all as you'll probably just find
+money along the way. You can also go hunting along the way to get more food,
+assuming you're not such a lousy shot as to be unable to hit a helpless animal
+from a cowardly distance.
+
+At each turn, all items are shown in dollar amounts except bullets. When asked
+to enter money amounts, don't use a $.
+
+Good luck, because the Devil's not going to help out!!! Or...will he?
+
+<2>
+%u
+<3>
+%ld
+<4>
+
+🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦
+🪦 / \ 🪦
+🪦 / A \ 🪦
+🪦 |TORMENTED| 🪦
+🪦 | MONSTER | 🪦
+🪦 | R.I.P. | 🪦
+🪦 |_________| 🪦
+🪦 GAME OVER 🪦
+🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥
+🔥 Unfortunately, due to what can only be an ADMINISTRATIVE FOUL-UP, 🔥
+🔥 you end up somewhere you did not expect as your forever home. But 🔥
+🔥 honestly, after signing the Devil's book, DO YOU REALLY BELIEVE 🔥
+🔥 YOU DON'T BELONG HERE? Be honest. For once. You know you belong 🔥
+🔥 here. Oh, by the way, god asked me to wish you a PROSPEROUS LIFE 🔥
+🔥 ahead... 🔥
+🔥 😈😈😈 WELCOME TO HELL!! 😈😈😈 🔥
+🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥
+
+<5>
+
+🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈 🪰
+🍝Not again. Are you REALLY going to tell me about the Flying Spaghetti 🍝
+😈Monster AGAIN? I've had ENOUGH of your FAIRY-TALE DELUSIONS! YOU'VE 😈
+🪰TOLD ME HE IS INVISIBLE SO HOW IN THE HELL CAN YOU EVEN KNOW HE 🪰
+🍝EXISTS? 🍝
+😈 😈
+🪰What next, are you going to tell me that between Earth and Mars there 🪰
+🍝is a china teapot revolving about the Sun in an elliptical orbit? Let 🍝
+😈me guess! It's so small that even the James Webb telescope that was 😈
+🪰launched almost 200 years from now can't even see it, right? What a 🪰
+🍝load of ABSOLUTE RUBBISH! If your daughters were not here I WOULD 🍝
+😈TOTALLY BE ABUSING LALOCHEZIA AT YOU RIGHT NOW! BUGGER ME THAT THEY 😈
+🪰ARE! 🪰
+🍝 🍝
+😈If the Flying Spaghetti Monster ACTUALLY existed, he'd eat you for 😈
+🪰lunch for blasphemy. Hell, keep this up and I'LL eat you. I'M STARVING!🪰
+🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰 🍝
+
+<6>
+
+How much do you want to spend on food?
+<7>
+
+How much do you want to spend on ammunition?
+<8>
+
+How much do you want to spend on clothing?
+<9>
+
+How much do you want to spend on oxen?
+<10>
+
+How much do you want to spend on miscellaneous supplies?
+<11>
+
+ Food: %4ld Ammo: %4ld Clothing: %4ld
+ Oxen: %4ld Supplies: %4ld Money: %4ld
+ Health: %4ld Miles: %4ld
+
+<12>
+After all your purchases, you now have $%ld left...
+
+Seriously, YOU WASTED YOUR MONEY LIKE THAT?
+
+<13>
+
+💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈
+😈 Mild illness. Medicine used. Not sure why though. IT WAS ONLY A 💊
+💊 SNIFFLE. Probably just the Devil TRYING TO ESCAPE FROM YOUR CURSED 😈
+😈 NOSTRILS. In the future THEY BLESS PEOPLE FOR SNEEZING. You can 💊
+💊 die happy knowing you started a thing. Even if your death will 😈
+😈 bring you EVERLASTING TORMENT. 💊
+💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈
+
+<14>
+
+Value must be a positive number no larger than 666. Or 0. If you trust the
+Devil.
+
+<15>
+
+🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂
+❌You have run out of oxen and must walk. Better buy more... IF YOU DIDN'T ❌
+💋WASTE MORE MONEY ON MORE SINFUL NIGHTS, like your red-headed daughters told 💋
+🐂me last night, assuming they weren't LYING to me. 🐂
+❌ ❌
+💋AND YES. A dirty mind IS a TERRIBLE thing to waste BUT NOTHING HAPPENED 💋
+🐂BETWEEN US!! We're JUST FRIENDS and they've been telling me ALL ABOUT YOUR 🐂
+❌RIDICULOUS BEHAVIOUR. OK, it MIGHT be in bed with them but they can't help ❌
+💋themselves...kind of like you. WHERE do you think they got it from? 💋
+🐂Besides, if YOU KNOW THE DEVIL in the biblical sense WHY SHOULDN'T WE? We 🐂
+❌EXPRESS PASSION and YOU ARE AN EVIL MONSTER!!!!👹 Good luck hauling your ❌
+💋your wagon! WE'RE TAKING A PLANE!! 💋
+🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂
+
+<16>
+
+Shooting when low on bullets. That's really intelligent. NO WONDER you're
+starving.
+
+<17>
+
+As you overindulge in a huge platter of spaghetti, it suddenly begins to
+strangle you to death.
+
+You gasp for air, reaching out to the Devil for help! In vain. She's already
+here cackling like the monster you are, just WAITING FOR YOU.
+
+Your time has come my friend. But didn't you want to know her better anyway?
+
+Better go fulfil your promise! SHE WANTS YOU RIGHT NOW! 💋
+
+<18>
+
+🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂
+🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃
+🐂 The only food you have left is an ox! 🐂
+🐂 🐂
+🐂 As you have no choice left, you promptly 🐂
+🐂 kill it before it runs away, and it sure 🐂
+🐂 was DELICIOUS!!! 🐂
+🐂 ( OX'S VOICE ) 🐂
+🐂 You're a sick, sick individual. You do 🐂
+🐂 know that, right? First you BURDEN ME 🐂
+🐂 WITH ALL YOUR RUBBISH and THEN YOU EAT ME?🐂
+🐂 🐂
+🐂 I hope you remember you were starving me 🐂
+🐂 to death so it's your fault you won't get 🐂
+🐂 much sustenance from MURDERING YOUR 🐂
+🐂 FAITHFUL SLAVE ANIMAL!!! Not that I had a 🐂
+🐂 choice. 🐂
+🐂 🐂
+🐂 And YES, there's a place IN HELL FOR 🐂
+🐂 MONSTERS LIKE YOU, AND YES YOUR TIME IS 🐂
+🐂 FAST APPROACHING, YOU RUDDY UNFAITHFUL 🐂
+🐂 LITTLE GIT. 🐂
+🐂 😈😈😈 HE'S WAITING. 😈😈😈 🐂
+🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃
+🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂
+
+<19>
+
+🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂
+🐂 An ox looks at you funny so you eat him! 🐂
+🐂 🐂
+🐂 You're a sick, sick individual. You do know that,🐂
+🐂 right? FIRST you BURDEN HIM WITH ALL YOUR RUBBISH🐂
+🐂 and THEN YOU EAT HIM BECAUSE OF A FUNNY LOOK? And🐂
+🐂 YOU DIDN'T EVEN SHARE HIM WITH YOUR FAMILY! 🐂
+🐂 🐂
+🐂 What next, will you eat your daughter too? No! 🐂
+🐂 NO! NO NO NO NO! I SHOULD NOT HAVE SAID THAT! NO!🐂
+🐂 DON'T EVEN THINK ABOUT TOUCHING HER! BACK OFF!! 🐂
+🐂 🐂
+🐂 SHE'S MINE!!! 🐂
+🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂
+
+<20>
+
+One of the daughters cut her arm and it had to be amputated. THANK GOD she is
+not DOWN IN THE MOUTH AND SHE WANTS TO EAT IT BECAUSE YOU ARE SUDDENLY
+STARVING!!!
+
+But OF COURSE you didn't get any. If you weren't eyeing it so lustily you would
+have seen that she seemed to ESPECIALLY ENJOY IT, GREEDILY DEVOURING IT AS IF
+IT WAS HER LAST SUPPER! Wait, HAS THE DEVIL POSSESSED HER TOO?! THAT EVIL
+WITCH!!! 🧙🧙🧙
+
+Hang on. YOU'RE JUDGING HER AFTER ALL YOU'VE DONE? CUT THAT OUT RIGHT NOW! NO.
+NO! NO! NO! STOP! I DID NOT MEAN CUT ANOTHER LIMB OFF HER! YES I KNOW I got
+some and you didn't. And yes it was DELICIOUS! But she wanted me to remember it
+before it was all gone, not you. Eat your own arm if you must. No. I meant stop
+accusing her of witchcraft. YOU signed the Devil's book, NOT HER and it WAS her
+body! This is ALL YOUR FAULT, JUST LIKE EVERYTHING ELSE that's happened since
+that fateful night!
+
+<21>
+
+Wagon train damaged! Lost time time resupplying from the Devil.
+
+<22>
+
+Suddenly your clocks stop...
+
+I guess it must have happened AGAIN! And WHY THE DEVIL DO YOU KEEP SWIMMING IN
+THE MOLASSES RIVER?! Honestly, you'll be lucky if you don't SINK IN IT before
+it sinks into your stick-in-the-molasses head.
+
+<23>
+
+ ⛰️⛰️⛰️⛰️
+
+You made it safely through South Pass--no snow. Clearly the Devil has your
+back. For now my dear fiend, for now...
+
+He might be plotting against you. Oh hell. I KNOW HE IS. HE TOLD ME HE IS.
+Your time is coming AND THE DEVIL AND I BOTH CANNOT WAIT! Neither can your
+daughters. They told me last night in the wagon. YES. I KNOW THEM.
+
+ ⛰️⛰️⛰️⛰️
+
+<24>
+
+🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦
+🪦 All you had was mouldy bread,🪦
+🪦 🪦
+🪦 🪦
+🪦 Therefore here you must lie. 🪦
+🪦 🪦
+🪦 🪦
+🪦 Because now you're dead. 🪦
+🪦 🪦
+🪦 🪦
+🪦 GOODBYE! 🪦
+🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦
+
+<25>
+
+🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂
+🐂 ( OX'S VOICE ) 🐂
+🐂 Still happy you ate me? How many more miles do you have 🐂
+🐂 to go? 🐂
+🐂 🐂
+🐂 YOU'RE COOKED and you know it, you horrible, HORRIBLE MONSTER. 🐂
+🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂
+
+<26>
+
+👻👻👻👻👻👻👻👻👻👻👻👻👻👻👻👻👻👻👻👻👻👻👻👻👻
+👻 A little ghost floats by and shouts: BOO!!!! 👻
+👻 👻
+👻 Okay that was NOT funny, Casper! Go back to 👻
+👻 your shallow grave, you LITTLE JERK! 👻
+👻👻👻👻👻👻👻👻👻👻👻👻👻👻👻👻👻👻👻👻👻👻👻👻👻
+
+<27>
+
+ ___🔥🔥🔥___
+ / 🔥🔥🔥 \
+ |🔥 WAGON 🔥
+ 🔥🔥🔥 |___🔥🔥🔥___🔥🔥🔥
+ 🔥🔥🔥🔥🔥🔥O 🔥🔥🔥 O🔥🔥
+🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦
+🪦A fire breaks out in your wagon, and the wind quickly 🪦
+🪦fans the flames, CAUSING YOUR AMMO TO BLOW UP, killing🪦
+🪦you! Somehow everyone else survived... 🪦
+🪦 🪦
+🪦Frankly, IT WAS ABOUT TIME. I mean WHAT KIND OF IDIOT 🪦
+🪦overloads their wagon with WEAPONS? 🪦
+🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦
+
+<28>
+
+Uh oh. A black cat just jumped out in front of you. Is the Devil calling you?
+Better go have a look before it's too late. Maybe it already is. Your daughters
+told me you're an ailurophobe! Some pretty wild stories I hear. I think it
+probably is too late. Isn't it Friday the 13th?
+
+<29>
+
+You take lots of cash 💰 from the riders 🏇, accidentally stabbing one as he
+flees. But since you're starving, why don't you MAKE PENANCE BY NOT WASTING THE
+BODY YOU RUDELY CUT OPEN?
+ 🍖🥩🍔🥩🍔🍖
+ Mm...that was DELICIOUS!!!
+ (🪦👻RIDER'S SOBBING VOICE FROM THE GRAVE👻🪦)
+You know what you did is wrong, right? We were JUST ROBBED YESTERDAY, you rob
+us today AND NOW I'M DEAD 👻!
+
+WELL GOOD. I WAS DYING OF DYSENTERY and now YOU get to SPREAD THE DISEASE as
+well.
+
+<30>
+
+ ~~~~~~
+ / 🍝🍝🍝 \
+ / 🍝🍝🍝🍝🍝 \
+ / 🍝🍝🍝🍝🍝🍝 \
+ | 🍝🍝🍝🍝🍝🍝🍝|
+ \ ||| ||| /
+ \ ||||| /
+ \ ||| /
+ \__________/
+ || ||
+ || ||
+ __||__||__
+WOW!!!! THAT'S A SPAGHETTI TREE!!! I saw them over 100 years from now when I
+last used my Time Machine!! The BBC will cultivate them on April Fool's Day
+19579! THEY'RE AMAZING!! The Time Machines are okay and kind of interesting.
+Dangerous though...
+
+But the spaghetti looks pretty ominous, doesn't it? IT LOOKS LIKE IT WANTS TO
+REACH DOWN AND GRAB YOU! Better be careful. If they strangle you YOU WILL GO TO
+HELL! On the plus side... YOU'LL HAVE THE MOST AMAZING STORY to tell your
+fellow sinners... Trust me. I've been there on holiday! It's PRETTY WILD!!
+Summers are AMAZINGLY HOT!! Although...GETTING EATEN BY A DRAGON OR KILLED BY
+TYRANNOSAURUSES is an EVEN BETTER STORY! That's MUCH MORE EXCITING than a
+SPAGHETTI TREE KILLING YOU!! Although...now I think on it...they're ALSO in
+Hell so maybe it's better if the spaghetti kills you. Want me to strangle you
+with it if it doesn't do it? Of course...the trees are there too...LOTS of
+parties too. And good old TORTURE! IT'S AWESOME!
+
+<31>
+
+😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈
+😈 Uh oh! Is that the DEVIL I see in your mirror again? Or are YOU looking at 😈
+😈 it from behind your dressing curtain? 😈
+😈 😈
+😈 BETTER BREAK IT BEFORE IT'S TOO LATE!!! Yes, YES, I KNOW IT'S BAD LUCK TO 😈
+😈 BREAK A MIRROR!! But ask yourself this: what's worse, seeing yourself in 😈
+😈 the Devil's mirror OR simply having bad luck for 7 long years? Let's be 😈
+😈 honest. You're NOT going to make it that long anyway! Why not just give 😈
+😈 your mind some peace and die in an unknown way? Much less scarier AND IF 😈
+😈 YOU DON'T BREAK IT I WILL! I don't want to see the Devil in your mirror! OH😈
+😈 HELL! NOT AGAIN! I MEAN I DON'T WANT TO SEE YOU IN THE DEVIL'S MIRROR!!! 😈
+😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈
+
+<32>
+
+🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣
+🐂 Uh oh. ONE OF THE OXEN JUST KICKED A BUCKET. Is it going to die next? 🐂
+🛁 Or...is it foreshadowing your own death? Let's face it. You have it coming 🛁
+🪣 to you. Better throw the ox out with the bathwater before it's too late. Oh🪣
+🐂 and don't try telling me you don't have any oxen left, if you can even 🐂
+🛁 count! It kicked the bucket SO OF COURSE IT DOESN'T EXIST!! 🛁
+🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🪣
+
+<33>
+
+🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖
+🦖 A GROUP OF TYRANNOSAURUSES ATTACK! 🦖
+🦖 🦖
+🦖Unfortunately for you, you're in a time LONG BEFORE the brilliant 🦖
+🦖mathematician Ian Malcolm informed us that DINOSAURS FIND A WAY TO KILL 🦖
+🦖HUMANS. You should have thought of that BEFORE you STUPIDLY climbed into 🦖
+🦖that Time Machine to travel back in time to the Oregon Trail, where you 🦖
+🦖could not possibly know so many important things about dinosaurs... 🦖
+🦖 🦖
+🦖ALTHOUGH, now I think on it, that MIGHT not have been EXACTLY how it went... 🦖
+🦖I THINK the correct wording was 'LIFE FINDS A WAY' but that's well over 100 🦖
+🦖years from now and instead of life finding a way the Devil will find a way. 🦖
+🦖To torment you. With more dinosaurs. And dragons. Yes they still exist. Oh 🦖
+🦖and the Earth is flat too... 🦖
+🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖
+
+<34>
+
+🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃
+ / \
+ / A \
+ |TORMENTED|
+ | PIONEER |
+ | R.I.P. |
+ |_________|
+ GAME OVER
+ Here you lie dead,
+ You tried to outrun a runaway bed.
+ But you slipped and hit your head,
+and now you body's forever in an underground bed!
+
+🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃
+
+<35>
+
+ 🌨️🌨️🌨️🌨️🌨️🌨️🌨️🌨️🌨️🌨️🌨️
+ 🏔️🏔️🏔️🏔️🏔️🏔️🏔️🏔️🏔️🏔️🏔️
+
+Blizzard in mountain pass--time wasted asking Devil for help restocking.
+
+Unfortunately, the unfaithful monster only gives you ONE MEASLY BULLET. Like
+that's going to help his most faithful lieutenant? Oh but are you faithful?
+
+Perhaps you should have used a mountain cable car 🚠, rather than relying on
+the Devil! It's pretty funny you didn't know he was unfaithful and yet expects
+complete loyalty. Or else. HE'S COMING.
+
+<36>
+
+You have been on the trail too long and you die of boredom.
+
+You know you're lucky to have made it this long. Frankly with your behaviour
+I'm surprised you didn't die from a sinful disease much earlier. Or drowning in
+molasses. Or freezing to death with your choice in clothing.
+ 🩳🩲👗👙🩳🩲👗👙🩳🩲👗👙
+SERIOUSLY mate, you brought shorts, briefs, A DRESS AND A BIKINI on the Oregon
+Trail? What the hell were you thinking? Actually though...now I think on
+it...perhaps Hell WILL serve you better? I hear the Summers are AMAZING there!
+Winters, not so much.
+
+At least your family gets free food now, assuming monsters are edible. I'm not
+sure if they are. I suspect they would be poisoned or die from your hot,
+burning flesh.
+
+<37>
+
+You'd better do some hunting or buy food soon, before you starve
+to death! Or don't. Let's face it. You'd deserve it.
+
+<38>
+
+😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈
+🏥Doctor's bill is $666 and you can't afford it DUE TO ALL YOUR RECKLESS 🏥
+😈SPENDING! HE MUST BE POSSESSED BY BEELZEBUB! SURELY ONLY THE DEVIL would do 😈
+🏥this. It's not like you've ever killed a helpless animal or human, never 🏥
+😈robbed anyone, never ate human flesh or done any other heinous thing, never 😈
+🏥sinned ... 🏥
+😈 😈
+🏥NO. STOP LYING! YOU signed the Devil's book! You should have listened to your 🏥
+😈Reverend Samuel Parris way back in 1692. All these wild, strange and bad 😈
+🏥happenings, since you began your journey are ALL YOUR fault, EVEN YOUR 🏥
+😈DAUGHTERS' WILD DANCING BY THE NIGHT FIRES AS IF POSSESSED! Not that I'm going😈
+🏥to complain about THAT...Hell, THEY ASKED ME TO JOIN THEM! 🏥
+😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈
+
+<39>
+
+🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖
+👶 ( SON'S VOICE ) 👶
+🍖 🍖
+👶How you feeling about eating me? Eating your own son, NO WONDER she was 👶
+🍖having an affair before her untimely death! It was with YOUR SISTER AND HER 🍖
+👶HUSBAND. 👶
+🍖 🍖
+👶OH NO. NO, NO, NO, NO!! Please don't tell me you ate her too. Wait. You 👶
+🍖didn't feed her to us, did you? Ugh, you did, didn't you? You're a sick, sick 🍖
+👶person. 👶
+🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖
+
+
+<40>
+
+💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩
+🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽
+💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩
+ You have died of dysentery.
+ CONGRATULATIONS ON REACHING
+ LEGENDARY STATUS!
+💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩
+🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽
+💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩
+
+<41>
+
+ 🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸
+ 🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸
+ 🩸🩸 YOU HAVE DIED OF INJURIES! 🩸🩸
+ 🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸
+ 🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸
+
+ Better than diarrhoea though, right?
+
+Frankly, it serves you right. If you hadn't wasted all that time and money
+sinning you MIGHT have made it. But I guess there's no real difference; after
+all, none of us really make it out alive, do we? Well off you go then! HEAVEN
+AWAITS!! Or does it?
+
+<42>
+
+Do you want to (1) stop at the next fort 🏰, (2) hunt 📸 or (3) continue?
+<43>
+
+Do you want to (1) hunt 📸 or (2) continue?
+<44>
+
+You need more bullets to go hunting. Or -- do you?
+
+<45>
+
+You have died of exhaustion. I'm SURE your victims ARE MOURNING FOR YOUR
+FAMILY. Assuming they're not too busy EATING YOU 🍕🍔🍟🥪🌯🌮🌭 WITH THEM. I
+KNOW FOR A FACT your daughters LOVE meat and I'm sure they're already devouring
+you! Hopefully they'll save some for everyone else this time; it'd be a REAL
+SHAME if your body went to waste...or would it be?
+
+<46>
+
+💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰❌💋
+❌DON'T BE ABSURD! You don't have that kind of money. ❌
+💰In fact, one of your daughters told me JUST LAST 💰
+💋NIGHT that ONCE AGAIN you had a delightfully sinful 💋
+❌night! NO! I KNOW WHAT YOU'RE THINKING! NOTHING ❌
+💰HAPPENED BETWEEN US! STOP THAT RIGHT NOW, YOU 💰
+💋FILTHY SINNER! 💋
+❌ ❌
+💰Hmm...although...now I think on it, I'm starting 💰
+💋to wonder... OH HELL! NO NO NO! What if she seduced 💋
+❌me and we DID DO something? That would be AWFUL, ❌
+💰JUDGING YOU WHILE HAVING AN AFFAIR WITH ONE OF THE 💰
+💋WOMEN! Still sure WE'D NEVER SIGN THE DEVIL'S BOOK! 💋
+❌ ❌
+💰Although...I don't really remember WHAT we did last 💰
+💋night... ANYWAY, KEEP US OUT OF IT YOU MONSTER! 💋
+❌ ❌
+💰The book has a cost and money doesn't grow on trees. 💰
+💋Perhaps it might grow on horns though? Ask the Devil 💋
+❌for help. Assuming he helps MONSTERS. ❌
+💰💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰💋
+
+<47>
+
+You FINALLY arrived at Oregon City after 2170 long miles!
+
+TOOK YOU LONG ENOUGH. Probably all your sinful detours I've heard so much about
+but you'd think that the Devil would have helped you out on that. But I guess
+as long as you make it to your final destination that's what matters, right?
+
+Oh, right. Almost forgot! President Jesse James asked me to wish you a
+prosperous life ahead of you...in HELL!
+
+<48>
+
+ 🔥🌨️🔥🌨️🔥🌨️🔥🌨️🔥🌨️🔥🌨️🔥
+Phantom blizzard from Hell suddenly hits and you freeze to death, leaving
+everyone behind. You know the Devil 😈 is calling you, right?
+ 🩳🩲👗👙
+And with your choice in clothing, ARE YOU REALLY SURPRISED YOU FROZE TO DEATH?
+I mean SERIOUSLY mate, shorts, briefs, A DRESS AND A BIKINI on the Oregon
+Trail? What the hell were you thinking? You're not in Hell, you're on the
+Oregon Trail!
+
+Although...now I think on it...perhaps Hell WILL serve you better? I hear the
+Summers are GREAT there! Lots of parties. Winters are -- actually, there are no
+winters. ONLY WEATHER TO BURN YOU FOR ETERNITY.
+
+At least your family gets fresh meat on the bone, assuming they can stomach
+eating a horrible monster. If I were them I'D BURN YOUR BODY.
+
+<49>
+
+🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔
+🍟Uh oh. THERE'S ANOTHER ELF! You must be 🍟
+🍔losing your mind my friend! ELVES DON'T 🍔
+🍟EXIST, unless you ask a German. They can't 🍟
+🍔even count to 11 without claiming there are 🍔
+🍟elves! Neun, zehn, Elf ... I guess I might 🍟
+🍔be losing my mind too! BETTER SHOOT THE ELF 🍔
+🍟BEFORE IT TAKES YOUR DAUGHTERS AWAY AND EATS 🍟
+🍔THEM! You might need them for food later on, 🍔
+🍟you HORRIBLE, HORRIBLE MONSTER. They are 🍟
+🍔heavenly women and are not for evil Devil 🍔
+🍟worshippers to eat! NO. NOT FOR ME EITHER! 🍟
+🍔Stop going there you sicko! They are NOT food 🍔
+🍟and YOU CANNOT GO TO HEAVEN, YOU DEVIL 🍟
+🍔WORSHIPPING MONSTER! Cut it out. NO! NOT THEM!🍔
+🍟STOP WHAT YOU'RE DOING!!! 🍟
+🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔
+
+<50>
+
+You need more bullets to go hunting. Or..do you?
+
+<51>
+
+You shot a Bald Eagle 🦅. WHY, monster, WHY?!
+
+I mean look at its former strength, its majesty! No wonder it became the symbol
+of America!
+
+GREAT JOB Devil worshipping pioneer, you just killed America! I hope it's
+poisoned or you at least choke on the bones.
+
+<52>
+
+ 🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃
+Great shot! YOU GOT THE FATTEST ONE THERE! As if that should be hard. IT COULD
+BARELY MOVE! But with your WILD SHOOTING AND HORRIBLE AIM the ONLY REASON you
+didn't miss by a hundred miles is you signed the Devil's book, EVEN THOUGH IT
+WAS AS WIDE AS A BLUE WHALE. There's no way you'd have got such a nice shot
+EVEN IF THE POOR BEAST WAS PRACTICALLY DEAD. I'm STILL surprised you didn't
+shoot yourself in the eyes. But the Devil DOES exact his dues and the animal
+might have been poisoned. Eat at your own risk. OR STARVE. Let's face it,
+YOU'RE DOOMED.
+ 🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃
+
+<53>
+
+WHAT A TERRIBLE SHOT! How could anyone POSSIBLY miss a helpless animal that was
+standing still, 100 FEET WIDE AND 150 YEARS OLD? IT WAS SO FAT IT WOULD MAKE
+100 BLUE WHALES OBESE!
+
+I hope you starve, you murderous beast, and it looks like you're going to,
+after WASTING ALL THOSE BULLETS and MISSING FISH OUT OF WATER. You'd better
+buy some food NOW.
+
+<54>
+
+😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋
+😈Severe illness. You must see Doctor Beelzebub. Assuming he's 😈
+😈not too busy trying to tempt your daughters. Don't worry though!😈
+😈I don't think he'll succeed. I haven't yet either and I'VE BEEN 😈
+😈TRYING FOR YEARS! THEY ARE INCORRIGIBLE MUMPSIMUSES!! No. I 😈
+😈don't think he's possessed me. I'm just like that. But we can 😈
+😈test it. What do you think about performing an exorcism on me? 😈
+😈 😈
+😈Actually...no. I take that back. Let me perform one on YOU to 😈
+😈make sure it works. I'm pretty sure they don't but better to do 😈
+😈it on a Devil worshipper than someone who's unhinged from 😈
+😈watching you. Safer that way. 😈
+😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋
+
+<55>
+
+If we are what we eat then doesn't that mean we're all cannibals?
+
+<56>
+
+
+🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇
+🤯 Riders ahead. They don't look hostile. 🤯
+🏇🔫🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫🏇
+🤯🔫Oh! I know what to do! You should TOTALLY ROB THEM BLIND!! They won't 🔫🤯
+🏇🔫know what hit them and it's not like they need their belongings, not 🔫🏇
+🤯🔫where they are going, and you're going to need them soon, with your 🔫🤯
+🏇🔫reckless behaviour. 🔫🏇
+🤯🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫🤯
+🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇
+
+<57>
+
+
+<58>
+
+
+<59>
+
+
+<60>
+
+
+<61>
+
+💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉
+💉You scared them off with your ERRATIC shooting. NEARLY BLEW MY HEAD OFF TOO.💉
+💉GREAT JOB. 💉
+💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉
+
+<62>
+
+ 🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸
+ 🩸🔪💩🔪💩🔪💩🔪💩🔪💩🔪💩🔪💩🩸
+ 🩸💩WORST SHOT EVER! You got💩🩸
+ 🩸💩knifed 🔪 by the dung! 💩🩸
+ 🩸💩How did you miss the 💩🩸
+ 🩸💩TRIGGER? 💩🩸
+ 🩸🔪💩🔪💩🔪💩🔪💩🔪💩🔪💩🔪💩🩸
+ 🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸
+Be honest. IT'S YOUR OWN STUPID FAULT FOR TRYING TO ATTACK FRIENDLY PEOPLE!
+Seriously, what the hell kind of person does that? I'm glad the dung 💩 knifed
+🔪 you. And remember that if the wound becomes infected with bacteria IT'S YOUR
+OWN BLOODY FAULT.
+
+Better have Doctor Beelzebub check it out, assuming he wasn't shot and treats
+MONSTERS. I hope he was shot!
+
+<63>
+
+You have to see Doctor Beelzebub!
+
+<64>
+
+
+<65>
+
+
+<66>
+
+ 🏇🏇🏇🏇🏇🏇🏇🏇🏇🏇🏇🏇🏇🏇
+Riders were friendly, but check for possible
+losses anyway. It's always the friendly ones
+who do something bad!! They're OBVIOUSLY hiding
+something!
+ ⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️
+
+<67>
+
+
+<68>
+
+🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛
+🐺I JUST HATE VAMPIRES! Don't you? If they had it their way THERE WOULD BE NO 🐺
+🥄SUN! Can you imagine how HORRIBLE that would be?! 🥄
+🧛 🧛
+🐺Wait. You mean to tell me...you want ETERNAL Sun and NO Moon?! Only ONE 🐺
+🥄reason for that! You MUST be a...WEREWOLF! I KNEW IT! Better watch your 🥄
+🧛heart. If you have one. Your daughters have SILVER SPOONS and they're FED UP🧛
+🐺WITH YOUR BARKING BEHAVIOUR!! 🐺
+🥄 🥄
+🧛On the other blade...IT IS VERY HOT don't you think? Almost as if it's 🧛
+🐺foreshadowing what's to come! MAYBE WE SHOULD GET RID OF FIRE TOO! I mean 🐺
+🥄you're in extreme danger of that too! THEN WE CAN DROWN you so you can BURN 🥄
+🧛IN HELL!!! And if that doesn't work, we can behead you with the SPOONS!! 🧛
+🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺
+
+<69>
+
+🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺
+🥄Suddenly...the hairs on your neck stand up. ARE YOU ACTUALLY A 🥄
+🐺WEREWOLF? You do know that there are silver spoons in your daughters' 🐺
+🥄wagon, right? 🥄
+🐺 🐺
+🥄Better run for your life or howl to scare them off before it's too 🥄
+🐺late, because they told me that they HATE wolves, are SICK OF your 🐺
+🥄BARKING BEHAVIOUR and THEY'VE HAD ENOUGH OF YOUR DEVIL WORSHIPPING!! 🥄
+🐺 🐺
+🥄Oh and yes. Spoons CAN stab you in the heart. If you don't believe 🥄
+🐺 me...try it. Assuming you have a heart in the first place... 🐺
+🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄
+
+<70>
+
+You ran out of bullets and got massacred by the riders.
+
+How I do not know, seeing as how they were friendly. Oh
+I remember now. It's because you actually decided to
+cowardly try and rob them blind.
+
+<71>
+
+ ____
+ ____( )____
+ / o \
+(FLAT 🫓 OXEN 🐂)
+ \____ ____o_/
+ | |
+Flat oxen--slows you down.
+
+And don't try telling me you didn't have an
+ox because that would also be a flat ox!
+
+<72>
+
+🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄
+🦄About 100 feet from here YOU SWEAR you see an ox stuck in 🦄
+🦄a hole. THANK THE DEVIL IT'S NOT A DONKEY! You KNOW what 🦄
+🦄that would make!! There are enough here already! NO! Don't 🦄
+🦄look at me! I DON'T MEAN THAT, YOU LITTLE JERK!! 🦄
+🦄 🦄
+🦄But of course YOU'RE WRONG AS USUAL. IT'S NOT AN OX. You 🦄
+🦄NEED a pair of VERY POWERFUL glasses my friend. Might also 🦄
+🦄want to avoid that funny fungi...could be related...somehow.🦄
+🦄But really get some eyeglasses! 🦄
+🦄 🦄
+🦄 IT'S OBVIOUS YOU SEE A UNICORN!!!! 🦄
+🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄
+
+<73>
+
+Bad luck--you got gangrene in one of your limbs and you had to chop it off. Or
+maybe it was good luck? FREE FOOD TONIGHT!!! 🍖
+
+<74>
+
+Oh dear. That isn't the Barghest AGAIN is it? Better watch your back! And
+front. And above you. Actually, YOU'RE DOOMED and you know it. Your fate was
+sealed upon signing the Devil's book. Honestly, what were you thinking? You HAD
+to have known it always comes with a cost. And you and I BOTH KNOW that the
+women were warning you - but you just HAD to have your way, didn't you?
+
+Well the Oregon Trail is out to get you in every direction and the odds are you
+won't make it out alive. You might be in good company there, AND YOU AT LEAST
+GET TO SEE DINOSAURS ALIVE (LUCKY YOU!!) BUT THERE'S NO AIR CONDITIONING and I
+heard it gets REALLY HOT down there. Then again, I also heard there's no heater
+in Heaven... Yup, either way YOU'RE DOOMED AND YOU KNOW IT! But don't feel too
+bad. At least you won't FREEZE TO DEATH. You might here though... Yup, FREEZE
+TO DEATH HERE and then BURN TO DEATH THERE!
+
+<75>
+
+🍖🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🍖
+🍖Your son gets lost and FREEZES TO DEATH! 🍖
+🍖 🍖
+🍖But on the bright side, you now have one fewer person to feed and not only 🍖
+🍖that you get a FREE MEAL TONIGHT!!! Not that you've been starving yourself 🍖
+🍖deliberately. You're a glutton and you know it. But hey, now you have FRESH 🍖
+🍖MEAT ON THE BONE!! Why not START A FEAST? You did remember your pots and 🍖
+🍖deadpans, right? IF NOT I HOPE YOU STARVE TO DEATH. OH AND YOU BETTER SHARE 🍖
+🍖THIS TIME! 🍖
+🍖🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🍖
+
+<76>
+
+💦🚽💩💦🚽💩💦🚽💩💦🚽💩💦🚽💩💦🚽💩💦🚽💩💦🚽💩💦🚽💩💦🚽💩💦🚽💩💦🚽💩💦🚽💩💦
+🚽OH HELL! That water tasted REALLY funny! No. Sorry. NOT Hell. There is no 🚽
+💩water in Hell! Well, wherever you are, it appears you drank unpotable water 💩
+💦and it's too late now. 💦
+🚽 🚽
+💩Next time LOOK AT WHAT 💩 you intend 💦 on swallowing BEFORE YOU SHOVE IT 💩
+💦DOWN YOUR THROAT, because you now have dysentery. 💦
+🚽💩💦🚽💩💦🚽💩💦🚽💩💦🚽💩💦🚽💩💦🚽💩💦🚽💩💦🚽💩💦🚽💩💦🚽💩💦🚽💩💦🚽💩💦🚽
+
+<77>
+
+ Heavy rains---time and supplies lost.
+
+ But seriously, you brought these
+ supposed brollies?
+ 🌂🌂🌂🌂🌂🌂🌂🌂🌂🌂🌂🌂🌂🌂🌂🌂🌂🌂🌂🌂
+
+ You SHOULD HAVE BROUGHT THESE:
+ ☔️☔️☔️☔️☔️☔️☔️☔️☔️☔️☔️☔️☔️☔️☔️☔️☔️☔️☔️☔️
+ AND THESE HATS!!
+ 🧢🧢🧢🧢🧢🧢🧢🧢🧢🧢🧢🧢🧢🧢🧢🧢🧢🧢🧢🧢
+
+<78>
+
+ 👑🏴☠️⚓️🚢👑🏴☠️⚓️🚢👑🏴☠️⚓️🚢👑🏴☠️⚓️🚢👑
+ 🏴THE QUEEN ANNE'S REVENGE ATTACKS! 🏴
+ ☠️⚓️🚢👑🏴☠️⚓️🚢👑🏴☠️⚓️🚢👑🏴☠️⚓️🚢👑🏴☠️
+
+YES. You're right. That WAS Blackbeard's ship! Yes EDWARD TEACH IS ON THE
+OREGON TRAIL! NO, YOU'RE NOT HALLUCINATING. Neither am I. Didn't you know he
+also signed the Devil's book? Oh well, now you've been taught. Still, a ghost
+is a ghost...THIS SHOULD BE EASY!!
+
+But face it. After all you've done, you DESERVE THIS AND YOU KNOW IT! I HOPE HE
+ROBS YOU BLIND and if you die in the process you know it's your fault. Your
+time is coming and the Devil is calling you, laddie.
+
+<79>
+
+ 🦵🩸❌💰
+BLACKBEARD DIED OVER A CENTURY AGO AND HE STILL GOT YOU!
+
+Yes SOMEHOW you got shot in the leg and robbed by a GHOST.
+
+GREAT JOB!
+
+<80>
+
+
+ 🦵🩸 ❌🐂
+
+
+You got shot in the leg and they took one of your oxen, whether
+or not you have any oxen left. Not that that matters much;
+you're more than capable of stealing one, assuming you don't
+sacrifice it to the gods. The Devil. I meant the Devil.
+
+<81>
+
+ WELL DONE, LAD!!!
+
+Somehow, you scared the pirates off! Unfortunately you also managed to steal
+food and miscellaneous supplies from the pirates as they fled, though I
+honestly haven't a bloody clue how you did that. I do hope you get food
+poisoning so you can finally meet the Devil like Blackbeard was SUPPOSED to
+have. But aren't historians so awful, lying about Blackbeard? YOU'RE NEXT,
+LAD!
+
+<82>
+
+ __________
+ / \
+ | 🔥🔥🔥 |
+ |___🔥🔥🔥___|
+ O O
+
+There was a fire in your wagon. Too bad only food and supplies were lost! You
+know you deserve worse, right?
+
+<83>
+
+Lost your way in heavy fog but somehow you did not lose much time, due to the
+STRANGE MAP in the LAST BOOK you read.
+
+You know which book I mean. Sure. IT IS a FASCINATING READ! But you do know
+it's going to cost you though, right?
+
+<84>
+
+🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉
+🐉 A dragon eats you! 🐉
+🐉 🐉
+🐉No, I know what you're probably thinking. I would TOO! Who wants to be eaten 🐉
+🐉by a dragon? But THIS TIME IT WAS NOT any of the grass you understandably 🐉
+🐉ate when you were ravenous. 🐉
+🐉 🐉
+🐉No. I'm afraid not. The Earth is flat, dragons are real and the Sun is 🐉
+🐉crazy. Oh and yes the Devil is also real. But you ALREADY knew that didn't 🐉
+🐉you? Welcome to the harshness of the Oregon Trail. Or was it the Devil's 🐉
+🐉bedchamber? Oh well, you're dead now so no sense brooding over what seems 🐉
+🐉like Hell. Why not go to the REAL Hell instead? OH HELL, WHY NOT make it the 🐉
+🐉Devil's bedchamber? Be faithful. FOR ONCE. HELL, YOU MIGHT EVEN ENJOY IT! 🐉
+🐉No, not Hell. Okay...actually...yeah, Hell too. 🐉
+🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉
+
+<85>
+
+ 🐍🐍🐍🐍🐍🐍🐍
+
+You die of a snakebite because you stupidly didn't bring any
+antivenin. Oh wait. I forgot. They haven't invented it yet
+and nobody wants to suck the venom out of you. I'm actually
+surprised they haven't abandoned you entirely. Oh well, now
+they don't need to, although they might not be wise to have
+the fresh off the bone meat.
+
+ 🐍🐍🐍🐍🐍🐍🐍
+
+<86>
+
+ ❌❌❌
+ ❌🐂❌
+ ❌❌❌
+
+Wagon train got swamped fording river; lost food, clothes and an ox got stuck,
+whether or not you spared no expense on oxen. Alas, you couldn't save him.
+
+WAIT. You didn't Swim in the Molasses River AGAIN, did you? HOW MANY TIMES DO I
+HAVE TO REMIND YOU THAT THIS IS A VERY BAD IDEA? If only you thought to bring a
+portable oven so you could AT LEAST bake molasses cookies 🍪! But you didn't.
+I hope you starve. Then you'll be able to cook all the cookies in the world.
+HELL. I MEANT IN HELL.
+
+<87>
+
+Wild dragons attack! And you actually thought you could shoot
+them? Everyone knows dragons have armoured scales. I mean what
+was the point? You should have brought yourself a pair of wings
+so you could fly straight into the fire, so that you would've
+gone out in STYLE and with an amazing legacy!
+
+And no, I'm afraid you weren't hallucinating. The Earth IS flat,
+dragons ARE real and the Sun IS crazy. Oh and the Devil is real
+too. But you already knew that, didn't you, you filthy sinner?
+
+<88>
+
+Unfortunately, bullets won't help you with dragons; I'm surprised
+you didn't know that. Anyone knows dragons have armoured scales.
+Unfortunately for you they took a few oxen and upturned your wagon
+train, causing you further delays.
+
+Just be thankful you're still alive because this time you were walking
+on dragon eggshells. No. If you did that you'd be dead. I meant walking
+a thin line.
+
+<89>
+
+GREAT SHOOTING---they didn't get anything but you killed
+one of your oxen and somehow you managed to upturn your wagon.
+
+<90>
+
+Really? You tried to shoot a dragon? Well that was pointless. They ate one
+of your oxen and upturned your wagon train, causing further delays.
+
+<91>
+
+😈👶😈👶😈👶😈👶😈👶😈👶😈👶😈👶😈👶😈👶😈👶😈👶😈👶😈👶😈👶😈👶😈👶😈👶😈👶😈👶😈
+👶 ( SON'S VOICE ) 👶
+😈How you feeling about eating me? Eating your own son, and you're sick, too. 😈
+👶 👶
+😈 Probably food poisoning. GOOD. SERVES YOU RIGHT. Time to die. 😈
+👶😈👶😈👶😈👶😈👶😈👶😈👶😈👶😈👶😈👶😈👶😈👶😈👶😈👶😈👶😈👶😈👶😈👶😈👶😈👶😈👶
+
+<92>
+
+ 🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶
+ 🥶You freeze to death.🥶
+ 🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶
+ 👙🩳🩲👗
+And with your choice in clothing, ARE YOU REALLY SURPRISED? I mean SERIOUSLY
+mate, shorts, briefs, A DRESS AND A BIKINI on the Oregon Trail? What the hell
+were you thinking? You're not in Hell, you're on the Oregon Trail!
+
+Although...now I think on it, perhaps Hell WILL suit you better? I hear the
+Summers are GREAT there! Winter is as cold as Hell though. No. Not Hell. Hell
+does not get cold! You're going to BURN, BURN, BURN!!!!
+
+<93>
+
+😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈
+🏥Doctor's bill is $666! HE MUST BE POSSESSED BY BEELZEBUB! SURELY 🏥
+😈ONLY THE DEVIL would do this. It's not like you've ever killed a 😈
+🏥helpless animal or human, never robbed anyone, never ate human 🏥
+😈flesh or done any other heinous thing, never sinned ... 😈
+🏥 🏥
+😈NO. STOP LYING! YOU signed the Devil's book! You should have 😈
+🏥listened to your Reverend Samuel Parris way back in 1692. All 🏥
+😈these wild, strange and bad happenings, since you began your 😈
+🏥journey are ALL YOUR fault, EVEN YOUR DAUGHTERS' WILD DANCING BY 🏥
+😈THE MOONLIT NIGHT FIRES AS IF POSSESSED! Not that I'm going to 😈
+🏥complain about THAT...Hell, THEY ASKED ME TO JOIN THEM! 🏥
+😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈
+
+<94>
+
+🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂
+☔️Hail storm--YOU WERE HIT ON THE HEAD and supplies were damaged. But did you ☔️
+🧢REALLY think this CLOSED BROLLY 🌂 was going to help you against HAIL? Even 🧢
+🌂this one ☔️ PROBABLY wouldn't do much good. YOU SHOULD HAVE BROUGHT A 🌂
+☔️HAT 🧢!! ☔️
+🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢
+
+<95>
+
+Helpful Indians show you where to find more food. Pizza, hamburgers,
+chips/fries and other greasy, fatty foods ...
+ 🍕🍔🍟🥪🌯🌮🌭
+Okay so IT'S ONLY A HEART ATTACK ON A PLATE but at least you'll survive another
+day...if you don't have a heart attack first, that is... Better have your
+Doctor Beelzebub check you out. If he's still alive. Oh no.
+
+You didn't eat him when you were starving last time, did you? If so I hope you
+DO have a heart attack!
+
+<96>
+
+
+🧶🧶🧶🧶🧶🧶🧶🧶🧶🧶🧶
+🧶 Rugged mountains.🧶
+🧶🧶🧶🧶🧶🧶🧶🧶🧶🧶🧶
+
+<97>
+
+You got lost, losing valuable time asking the Devil 😈 for directions to the
+CROSSROADS ❌☦️ ⚠️ 🚸.
+
+But honestly, HOW DID you get lost? It's practically a TRAFFIC JAM OUT HERE AND
+ONLY A COMPLETE MORON COULD LOSE THEIR WAY.
+
+HISTORIANS WILL BE TALKING ABOUT THIS YEARS DOWN THE TRAIL! OH NO. WHAT DID YOU
+DO THIS TIME? You did do something didn't you? I KNOW you did! You ALWAYS do
+something stupid!
+
+<98>
+
+😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈
+😈Severe illness. You must see Doctor Beelzebub. Assuming he's not too busy 😈
+😈trying to tempt your daughters. Don't worry though! I don't think he'll 😈
+😈succeed. I haven't yet either and I'VE BEEN TRYING FOR YEARS! THEY ARE BLOODY 😈
+😈INCORRIGIBLE MUMPSIMUSES!! No. I don't think he's possessed me. I'm just 😈
+😈like that. But we can test it. What do you think about performing an exorcism 😈
+😈on me? 😈
+😈 😈
+😈Actually...no. I take that back. Let me perform one on YOU to make sure it 😈
+😈works. I'm pretty sure they don't but better to do it on a Devil worshipper 😈
+😈than someone who's unhinged from watching you. Safer that way. 😈
+😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈
+
+<99>
+
+You ran out of medical supplies and unfortunately the Devil's in Heaven on
+holiday / business and can't help you restock.
+
+But honestly, who goes on a 2170 MILES journey WITHOUT bringing medical
+supplies? You brought this on to yourself and you deserve it. But at least I
+just heard that the Devil is on his way home to greet you and thank god for
+that! Send me a postcard, will you? I want to make sure it works out well for
+you down there.
+
+<100>
+%ld
+<101>
+
+Wagon train damaged! Lost time resupplying from the Devil.
+
+<102>
+
+Suddenly your clocks stop...
+
+I guess it must have happened AGAIN! And WHY THE DEVIL DO YOU
+KEEP SWIMMING IN THE MOLASSES RIVER?! Honestly, you'll be lucky
+if you don't SINK IN IT before it sinks into your
+stick-in-the-molasses head.
+
+<103>
+
+ ⛰️⛰️⛰️⛰️⛰️⛰️⛰️⛰️⛰️⛰️⛰️⛰️⛰️⛰️⛰️⛰️
+
+You made it safely through South
+Pass--no snow. Clearly the Devil
+has your back. For now my dear
+fiend, for now...
+
+He might be plotting against you.
+Oh hell. I KNOW HE IS. HE TOLD ME
+HE IS. Your time is coming AND THE
+DEVIL AND I BOTH CANNOT WAIT!
+Neither can your daughters. They
+told me last night in the wagon.
+
+<104>
+
+ 🌨️🌨️🌨️🌨️🌨️🌨️🌨️🌨️🌨️🌨️🌨️
+ 🏔️🏔️🏔️🏔️🏔️🏔️🏔️🏔️🏔️🏔️🏔️
+
+Blizzard in mountain pass--time wasted asking Devil for help restocking.
+
+Unfortunately, the unfaithful monster only gives you ONE MEASLY BULLET. Like
+that's going to help his most faithful lieutenant? Oh but are you faithful?
+
+Perhaps you should have used a mountain cable car 🚠, rather than relying on
+the Devil! It's pretty funny you didn't know he was unfaithful and yet expects
+complete loyalty. Or else. HE'S COMING.
+
+<105>
+
+🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦
+🪦 All you had was mouldy bread,🪦
+🪦 🪦
+🪦 🪦
+🪦 Therefore here you must lie. 🪦
+🪦 🪦
+🪦 🪦
+🪦 Because now you're dead. 🪦
+🪦 🪦
+🪦 🪦
+🪦 GOODBYE! 🪦
+🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦
+
+<106>
+
+How does a turtle tell his friend to move aside? Scute over!
+
+<107>
+
+You ran out of medical supplies and unfortunately the Devil's in
+Heaven on holiday / business and can't help you restock.
+
+But honestly, who goes on a 2170 miles journey WITHOUT bringing
+medical supplies? You brought this on to yourself and you deserve it.
+But at least I just heard that the Devil is on his way home to greet
+you and thank god for that! Send me a postcard, will you? I want to
+make sure it works out well for you down there.
+
+<108>
+
+If your printer is working you're VERY OBVIOUSLY not using it right. And if you
+do not understand this may your good fortune last my dear friend. You'll need it.
+
+<109>
+
+🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸
+🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸
+🩸🩸 YOU HAVE DIED OF INJURIES! 🩸🩸
+🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸
+🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸
+
+ Better than diarrhoea though,
+ right?
+
+ Frankly, it serves you right.
+ If you hadn't wasted all that
+ time and money sinning you
+ MIGHT have made it. But I guess
+ there's no real difference;
+ after all, none of us really
+ make it out alive, do we? Well
+ off you go then! HEAVEN AWAITS!!
+ Or does it?
+
+<110>
+
+💩💩💩💩💩💩💩💩💩💩💩💩💩💩
+🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽
+💩💩💩💩💩💩💩💩💩💩💩💩💩💩
+
+You have died of dysentery.
+
+CONGRATULATIONS ON REACHING
+ LEGENDARY STATUS!
+
+💩💩💩💩💩💩💩💩💩💩💩💩💩💩
+🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽
+💩💩💩💩💩💩💩💩💩💩💩💩💩💩
+
+<111>
+
+If you lost your sense of irony then try looking in a blue tissue box.
+
+<112>
+
+I MAY be delusional but at least I have a VIVID imagination!
+
+<113>
+
+%f
+<114>
+
+You FINALLY arrived at Oregon City after 2170 long miles!
+
+TOOK YOU LONG ENOUGH. Probably all your sinful detours I've heard so much about but you'd think
+that the Devil would have helped you out on that. But I guess as long as you make it to your final
+destination that's what matters, right?
+
+Oh, right. Almost forgot! President Jesse James asked me to wish you a prosperous life ahead of
+you...in HELL!
+
+<115>
+
+Monday
+<116>
+
+Tuesday
+<117>
+
+Wednesday
+<118>
+
+Thursday
+<119>
+
+Friday
+<120>
+
+Saturday
+<121>
+
+Sunday
+<122>
+
+1847
+<123>
+
+July
+<124>
+
+August
+<125>
+
+September
+<126>
+
+October
+<127>
+
+November
+<128>
+
+December
+<129>
+
+Pie. Need pie.
+
+<130>
+
+President Jesse James sends you his heartiest congratulations
+and wishes you a prosperous life ahead at your new home in HELL!
+
+<131>
+
+What does a tomato do when it sees an old friend? It ketches up with it.
+
+<132>
+
+The only reason the British Museum has only a model of the Pyramid of Giza
+is because the real thing is too big to move.
+
+<133>
+
+Windows driving you crazy? Buy a scanner and install the included SANE library!
+
+<134>
+
+Nitrous Oxide: the carbon monoxide for laughing hyenas; they'll literally die from laughter.
+
+<135>
+
+I can't imagine ever going wireless. Not only am I fully wired, I enjoy it immensely.
+
+<136>
+
+If you're confused when someone tells you you're wrong to write:
+
+ void main()
+ {
+ }
+
+please feel free to try the following instead:
+
+ void brain()
+ {
+ }
+
+because that is perfectly valid C.
+
+Sorry for the inconvenience and thanks for your understanding,
+
+-- Neurosurgery Department of C, AT&T Bell Labs.
+
+<137>
+
+😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈
+😈 Severe illness. You must see Doctor 😈
+😈 Beelzebub. Assuming he's not too busy 😈
+😈 trying to tempt your daughters. Don't 😈
+😈 worry though! I don't think he'll 😈
+😈 succeed. I haven't yet either and I'VE 😈
+😈 BEEN TRYING FOR YEARS! THEY ARE 😈
+😈 INCORRIGIBLE MUMPSIMUSES!! No. I don't 😈
+😈 think he's possessed me. I'm just like 😈
+😈 that. But we can test it. What do you 😈
+😈 think about performing an exorcism on 😈
+😈 me? 😈
+😈 😈
+😈 Actually...no. I take that back. Let me 😈
+😈 perform one on YOU to make sure it works.😈
+😈 I'm pretty sure they don't but better 😈
+😈 to do it on a Devil worshipper than 😈
+😈 someone who's unhinged from watching you.😈
+😈 Safer that way. 😈
+😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈
+
+<138>
+
+💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈
+😈 Mild illness. Medicine used. Not sure why though. 💊
+💊 IT WAS ONLY A SNIFFLE. Probably just the Devil 😈
+😈 TRYING TO ESCAPE FROM YOUR CURSED NOSTRILS. In 💊
+💊 the future THEY BLESS PEOPLE FOR SNEEZING. You 😈
+😈 can die happy knowing you started a thing. Even 💊
+💊 if your death will bring you EVERLASTING TORMENT. 😈
+😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊
+
+<139>
+
+The Tale of Two Gates: Bill Gates puts holes in your
+windows; Josh Gates puts holes in the ground. And your
+grave.
+
+ The end.
+
+<140>
+
+Fun fact about blindness:
+
+<141>
+
+🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦
+🪦 / \ 🪦
+🪦 / A \ 🪦
+🪦 |TORMENTED| 🪦
+🪦 | PIONEER | 🪦
+🪦 | R.I.P. | 🪦
+🪦 |_________| 🪦
+🪦 GAME OVER 🪦
+🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥
+🔥Unfortunately, due to what can only be an 🔥
+🔥ADMINISTRATIVE FOUL-UP, you end up somewhere 🔥
+🔥you did not expect as your forever home. But 🔥
+🔥honestly, after signing the Devil's book, DO 🔥
+🔥YOU REALLY BELIEVE YOU DON'T BELONG HERE? Be 🔥
+🔥honest. For once. You know you belong here. 🔥
+🔥Oh, by the way, god asked me to wish you a 🔥
+🔥PROSPEROUS LIFE ahead... 🔥
+🔥 🔥
+🔥 😈😈😈 WELCOME TO HELL!! 😈😈😈 🔥
+🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥
+
+<142>
+
+ ___🔥🔥🔥___
+ / 🔥🔥🔥 \
+ |🔥 WAGON 🔥
+ 🔥🔥🔥 |___🔥🔥🔥___🔥🔥🔥
+ 🔥🔥🔥🔥🔥🔥O 🔥🔥🔥 O🔥🔥
+🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦
+🪦 A fire breaks out in your 🪦
+🪦 wagon, and the wind quickly🪦
+🪦 fans the flames, CAUSING 🪦
+🪦 YOUR AMMO TO BLOW UP, 🪦
+🪦 killing you! Somehow 🪦
+🪦 everyone else survived... 🪦
+🪦 🪦
+🪦 Frankly, IT WAS ABOUT TIME.🪦
+🪦 I mean WHAT KIND OF IDIOT 🪦
+🪦 overloads their wagon with 🪦
+🪦 WEAPONS? 🪦
+🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦
+
+<143>
+
+ .''.
+ :_\/_:
+ .:::::.
+ ':/\:'
+ '..'
+ / \
+ |Heaven|
+ |Awaits|
+ | You! |
+ '------'
+
+<144>
+
+🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃
+ / \
+ / A \
+ |TORMENTED|
+ | PIONEER |
+ | R.I.P. |
+ |_________|
+ GAME OVER
+ Here you lie dead,
+ You tried to outrun a runaway bed.
+ But you slipped and hit your head,
+and now you body's forever in an underground bed!
+
+🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃
+
+<145>
+
+🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂
+🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃
+🐂 The only food you have left is an ox! 🐂
+🐂 🐂
+🐂 As you have no choice left, you promptly 🐂
+🐂 kill it before it runs away, and it sure 🐂
+🐂 was DELICIOUS!!! 🐂
+🐂 🐂
+🐂 ( OX'S VOICE ) 🐂
+🐂 You're a sick, sick individual. You do 🐂
+🐂 know that, right? First you BURDEN ME 🐂
+🐂 WITH ALL YOUR RUBBISH and THEN YOU EAT ME?🐂
+🐂 🐂
+🐂 I hope you remember you were starving me 🐂
+🐂 to death so it's your fault you won't get 🐂
+🐂 much sustenance from MURDERING YOUR 🐂
+🐂 FAITHFUL SLAVE ANIMAL!!! Not that I had a 🐂
+🐂 choice. 🐂
+🐂 🐂
+🐂 And YES, there's a place IN HELL FOR 🐂
+🐂 MONSTERS LIKE YOU, AND YES YOUR TIME IS 🐂
+🐂 FAST APPROACHING, YOU RUDDY UNFAITHFUL 🐂
+🐂 LITTLE GIT. 🐂
+🐂 😈😈😈 HE'S WAITING. 😈😈😈 🐂
+🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃
+🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂
+
+<146>
+
+❌🐂❌🐂❌🐂❌🐂❌🐂❌🐂❌🐂❌🐂❌🐂❌🐂❌🐂❌🐂❌
+🐂You have run out of oxen and must walk. Better🐂
+❌buy more... IF YOU DIDN'T WASTE MORE MONEY ON ❌
+🐂MORE SINFUL NIGHTS, like your red-headed 🐂
+❌daughters told me last night, ASSUMING THEY ❌
+🐂WEREN'T LYING TO ME. I bet they weren't. You 🐂
+❌just can't help it can you? ❌
+🐂 🐂
+❌AND YES. A dirty mind IS a TERRIBLE thing to ❌
+🐂waste BUT NOTHING HAPPENED BETWEEN US!! We're 🐂
+❌JUST FRIENDS and they've been telling me ALL ❌
+🐂ABOUT YOUR RIDICULOUS BEHAVIOUR. OK, it MIGHT 🐂
+❌be in bed but they can't help themselves... ❌
+🐂kind of like you. WHERE do you think they get 🐂
+❌it from? But WE EXPRESS PASSION and YOU ARE AN❌
+🐂EVIL MONSTER!!!!👹 Good luck hauling your 🐂
+❌wagon! WE'RE TAKING A PLANE! ❌
+🐂❌🐂❌🐂❌🐂❌🐂❌🐂❌🐂❌🐂❌🐂❌🐂❌🐂❌🐂❌🐂
+
+<147>
+
+You've lost too many limbs but you can die 🪦
+happy 😊 knowing your family gets more free
+food! 🍖🍖🍖🍖 Sure it's toxic food but it's
+still food...
+
+
+<148>
+
+ Food: %4ld Ammo: %4ld Clothing: %4ld
+ Oxen: %4ld Supplies: %4ld Money: %4ld
+ Health: %4ld Miles: %4ld
+
+<149>
+
+🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖
+👶 ( SON'S VOICE ) 👶
+🍖 🍖
+👶 How you feeling about eating 👶
+🍖 me? Eating your own son, NO 🍖
+👶 WONDER she was having an affair 👶
+🍖 before her untimely death! It 🍖
+👶 was with YOUR SISTER AND HER 👶
+🍖 HUSBAND. 🍖
+👶 👶
+🍖 OH NO. NO, NO, NO, NO!! Please 🍖
+👶 don't tell me you ate her too. 👶
+🍖 Wait. You didn't feed her to us,🍖
+👶 did you? Ugh, you did, didn't 👶
+🍖 you? You're a sick, sick person.🍖
+👶 👶
+🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖
+
+<150>
+
+😈👶😈👶😈👶😈👶😈👶😈👶😈👶😈
+👶 ( SON'S VOICE ) 👶
+😈 😈
+👶 How you feeling about 👶
+😈 eating me? Eating your 😈
+👶 own son, and you're 👶
+😈 sick, too. 😈
+👶 👶
+😈 Probably food poisoning. 😈
+👶 GOOD. SERVES YOU RIGHT. 👶
+😈 Time to die. 😈
+👶😈👶😈👶😈👶😈👶😈👶😈👶😈👶
+
+<151>
+
+🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂
+🐂 🐂
+🐂 ( OX'S VOICE ) 🐂
+🐂 🐂
+🐂 Still happy you ate me? How 🐂
+🐂 many more miles do you have 🐂
+🐂 to go? 🐂
+🐂 🐂
+🐂 YOU'RE COOKED and you know 🐂
+🐂 it, you horrible, HORRIBLE 🐂
+🐂 MONSTER. 🐂
+🐂 🐂
+🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂
+
+<152>
+
+Shooting when low on bullets. That's really
+intelligent. NO WONDER you're starving.
+
+
+<153>
+
+ You take lots of cash 💰 from the riders 🏇,
+ accidentally shooting one as he flees. But
+ since you're starving, why don't you MAKE
+ PENANCE BY NOT WASTING THE BODY?
+
+ 🍖🥩🍔🥩🍔🍖
+ Mm...that was DELICIOUS!!!
+
+(🪦👻RIDER'S SOBBING VOICE FROM THE GRAVE👻🪦)
+
+ You know what you did is wrong, right? We
+ were JUST ROBBED YESTERDAY, you rob us today
+ AND NOW I'M DEAD 👻!
+
+ WELL GOOD. I WAS DYING OF DYSENTERY and
+ now YOU get to SPREAD THE DISEASE as well.
+
+<154>
+
+Uh oh. A black cat just jumped out in front of you. Is the Devil calling you? Better
+go have a look before it's too late. Maybe it already is. Your daughters told me
+you're an ailurophobe! Some pretty wild stories I hear. I think it probably is too
+late. Isn't it Friday the 13th?
+
+<155>
+
+Oh dear. That isn't the Barghest AGAIN is it? Better watch
+your back! And front. And above you. Actually, YOU'RE DOOMED
+and you know it. Your fate was sealed upon signing the Devil's
+book. Honestly, what were you thinking? You HAD to have known it
+always comes with a cost. And you and I BOTH KNOW that the women
+were warning you - but you just HAD to have your way, didn't you?
+
+Well the Oregon Trail is out to get you in every direction and
+the odds are you won't make it out alive. You might be in good
+company there, AND YOU AT LEAST GET TO SEE DINOSAURS ALIVE (LUCKY
+YOU!!) BUT THERE'S NO AIR CONDITIONING and I heard it gets REALLY
+HOT down there. Then again, I also heard there's no heater in
+Heaven... Yup, either way YOU'RE DOOMED AND YOU KNOW IT! But don't
+feel too bad. At least you won't FREEZE TO DEATH. You might here
+though... Yup, FREEZE TO DEATH HERE and then BURN TO DEATH THERE!
+
+<156>
+
+
+ 💦💦💦
+ 💦🐂💦
+ 💦💦💦
+
+Wagon train gets swamped fording river--lose food, clothes, an ox
+drowns and you get hurt.
+
+<157>
+
+You have died of exhaustion. I'm SURE
+your victims ARE MOURNING FOR YOUR FAMILY.
+Assuming they're not too busy EATING YOU
+🍕🍔🍟🥪🌯🌮🌭 WITH THEM. I KNOW FOR A
+FACT your daughters LOVE meat and I'm
+sure they're already devouring you!
+Hopefully they'll save some for everyone
+else; it'd be a REAL SHAME if your body
+went to waste...or would it be?
+
+<158>
+
+ ...
+
+😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈
+🏥Doctor's bill is $666! HE MUST BE POSSESSED 🏥
+😈BY BEELZEBUB! SURELY ONLY THE DEVIL would 😈
+🏥do this. It's not like you've ever killed a 🏥
+😈helpless animal or human, never robbed 😈
+🏥anyone, never ate human flesh or done any 🏥
+😈other heinous thing, never sinned ... 😈
+🏥 🏥
+😈NO. STOP LYING! YOU signed the Devil's book! 😈
+🏥You should have listened to your Reverend 🏥
+😈Samuel Parris way back in 1692. All these 😈
+🏥wild, strange and bad happenings, since you 🏥
+😈began your journey are ALL YOUR fault, EVEN 😈
+🏥YOUR DAUGHTERS' WILD DANCING BY THE NIGHT 🏥
+😈FIRES AS IF POSSESSED! Not that I'm going to 😈
+🏥complain about THAT...Hell, THEY ASKED ME TO 🏥
+😈JOIN THEM! 😈
+🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥
+
+<159>
+
+ 🌨️🌨️🌨️🌨️🌨️🌨️🌨️🌨️🌨️🌨️🌨️
+ 🏔️🏔️🏔️🏔️🏔️🏔️🏔️🏔️🏔️🏔️🏔️
+Blizzard in mountains - you freeze to death.
+
+ 🩳🩲👗👙
+
+And with your choice in clothing, ARE YOU
+REALLY SURPRISED? I mean SERIOUSLY mate,
+shorts, briefs, A DRESS AND A BIKINI on the
+Oregon Trail? What the hell were you thinking?
+You're not in Hell, you're on the Oregon Trail!
+
+Although...now I think on it...perhaps Hell WILL
+serve you better? I hear the Summers are GREAT
+there! Winters, not so much.
+
+At least your family gets fresh meat on the bone,
+assuming they can stomach eating a horrible
+monster.
+
+<160>
+
+Looks like the Devil has poisoned you. Your lover,
+she is waiting. TIME TO GO MEET HER!
+
+<161>
+
+🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖
+🦖 A GROUP OF TYRANNOSAURUSES ATTACK! 🦖
+🦖 🦖
+🦖Unfortunately for you, you're in a time 🦖
+🦖LONG BEFORE the brilliant mathematician 🦖
+🦖Ian Malcolm informed us that DINOSAURS 🦖
+🦖FIND A WAY TO KILL HUMANS. You should 🦖
+🦖have thought of that BEFORE you STUPIDLY 🦖
+🦖climbed into that Time Machine to travel 🦖
+🦖back in time to the Oregon Trail, where 🦖
+🦖you could not possibly know so many 🦖
+🦖important things about dinosaurs... 🦖
+🦖 🦖
+🦖ALTHOUGH, now I think on it, that MIGHT 🦖
+🦖not have been EXACTLY how it went... I 🦖
+🦖THINK the correct wording was 'LIFE FINDS 🦖
+🦖A WAY' but that's well over 100 years from🦖
+🦖now and instead of life finding a way the 🦖
+🦖Devil will find a way. To torment you. 🦖
+🦖With more dinosaurs. And dragons. Yes 🦖
+🦖they still exist. Oh and the Earth is 🦖
+🦖flat too... 🦖
+🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖
+
+<162>
+
+One of the daughters cut her arm and it had to be amputated.
+THANK GOD she is not DOWN IN THE MOUTH AND SHE WANTS TO EAT IT
+BECAUSE YOU ARE SUDDENLY STARVING!!!
+
+But OF COURSE you didn't get any. If you weren't eyeing it so
+lustily you would have seen that she seemed to ESPECIALLY ENJOY
+IT, GREEDILY DEVOURING IT AS IF IT WAS HER LAST SUPPER! Wait,
+HAS THE DEVIL POSSESSED HER TOO?! THAT EVIL WITCH!!! 🧙🧙🧙
+
+Hang on. YOU'RE JUDGING HER AFTER ALL YOU'VE DONE? CUT THAT OUT
+RIGHT NOW! NO. NO! NO! NO! STOP! I DID NOT MEAN CUT ANOTHER LIMB
+OFF HER! YES I KNOW I got some and you didn't. And yes it was
+DELICIOUS! But she wanted me to remember it before it was all gone,
+not you. Eat your own arm if you must. No. I meant stop accusing
+her of witchcraft. YOU signed the Devil's book, NOT HER and it
+WAS her body! This is ALL YOUR FAULT, JUST LIKE EVERYTHING ELSE
+that's happened since that fateful night!
+
+<163>
+
+🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂
+🐂 An ox looks at you funny so you eat 🐂
+🐂 him! 🐂
+🐂 🐂
+🐂 You're a sick, sick individual. You do 🐂
+🐂 know that, right? FIRST you BURDEN HIM 🐂
+🐂 WITH ALL YOUR RUBBISH and THEN YOU EAT 🐂
+🐂 HIM BECAUSE OF A FUNNY LOOK? And YOU 🐂
+🐂 DIDN'T EVEN SHARE HIM WITH YOUR FAMILY!🐂
+🐂 🐂
+🐂 What next, will you eat your daughter 🐂
+🐂 too? No! NO! NO NO NO NO! I SHOULD NOT 🐂
+🐂 HAVE SAID THAT! NO! DON'T EVEN THINK 🐂
+🐂 ABOUT TOUCHING HER! BACK OFF!! 🐂
+🐂 SHE'S MINE!!! 🐂
+🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂
+
+<164>
+
+👻👻👻👻👻👻👻👻👻👻👻👻👻👻 👻
+👻 A little ghost floats by 👻
+👻 and shouts: 👻
+👻 👻
+👻 BOO!!!! 👻
+👻 👻
+👻 Okay that was NOT funny, 👻
+👻 Casper! Go back to your 👻
+👻 shallow grave, you LITTLE 👻
+👻 JERK! 👻
+👻👻👻👻👻👻👻👻👻👻👻👻👻👻 👻
+
+<165>
+
+🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺
+🥄Suddenly...the hairs on your neck stand up. 🥄
+🐺ARE YOU ACTUALLY A WEREWOLF? You do know that 🐺
+🥄there are silver spoons in your daughters' 🥄
+🐺wagon, right? 🐺
+🥄 🥄
+🐺Better run for your life or howl to scare 🐺
+🥄them off before it's too late, because 🥄
+🐺they told me that they HATE wolves and 🐺
+🥄THEY'VE HAD ENOUGH OF YOUR DEVIL WORSHIPPING!!🥄
+🐺 🐺
+🥄Oh and yes. Spoons CAN stab you in the heart. 🥄
+🐺If you don't believe me...try it. Assuming 🐺
+🥄you have a heart in the first place... 🥄
+🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺
+
+<166>
+
+🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛
+🐺 I JUST HATE VAMPIRES! Don't you? If they had 🐺
+🥄 it their way THERE WOULD BE NO SUN! Can you 🥄
+🧛 imagine how HORRIBLE that would be?! 🧛
+🐺 🐺
+🥄 Wait. You mean to tell me...you want ETERNAL 🥄
+🧛 Sun and NO Moon?! Only ONE reason for that! 🧛
+🐺 You MUST be a...WEREWOLF! I KNEW IT! Better 🐺
+🥄 watch your heart. If you have one. Your 🥄
+🧛 daughters have SILVER SPOONS and they're FED 🧛
+🐺 UP WITH YOUR ANTICS! 🐺
+🥄 🥄
+🧛 On the other blade...IT IS VERY HOT don't 🧛
+🐺 you think? Almost as if it's foreshadowing 🐺
+🥄 what's to come! MAYBE WE SHOULD GET RID OF 🥄
+🧛 FIRE TOO! I mean you're in extreme danger of 🧛
+🐺 that too! THEN WE CAN DROWN you so you can 🐺
+🥄 BURN IN HELL!!! And if that doesn't work, 🥄
+🧛 we can behead you with the SPOONS!! 🧛
+🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺
+
+<167>
+
+🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔
+🍟Uh oh. THERE'S ANOTHER ELF! You must be 🍟
+🍔losing your mind my friend! ELVES DON'T 🍔
+🍟EXIST, unless you ask a German. They can't 🍟
+🍔even count to 11 without claiming there are 🍔
+🍟elves! Neun, zehn, Elf ... I guess I might 🍟
+🍔be losing my mind too! BETTER SHOOT THE ELF 🍔
+🍟BEFORE IT TAKES YOUR DAUGHTERS AWAY AND EATS 🍟
+🍔THEM! You might need them for food later on, 🍔
+🍟you HORRIBLE, HORRIBLE MONSTER. They are 🍟
+🍔HEAVENLY WOMEN AND ARE NOT FOR EVIL DEVIL 🍔
+🍟WORSHIPPERS to eat! NO. NOT FOR ME EITHER! 🍟
+🍔STOP GOING THERE YOU SICKO! THEY ARE NOT FOOD 🍔
+🍟AND YOU CANNOT GO TO HEAVEN, YOU DEVIL 🍟
+🍔WORSHIPPING MONSTER! CUT IT OUT. NO! NOT THEM!🍔
+🍟STOP WHAT YOU'RE DOING!!! 🍟
+🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔
+
+<168>
+
+🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄
+🦄 About 100 feet from here YOU SWEAR 🦄
+🦄 YOU SEE AN OX STUCK IN A HOLE. THANK 🦄
+🦄 GOD IT'S NOT A DONKEY! You KNOW what 🦄
+🦄 that would make!! There are enough 🦄
+🦄 here already! NO! Don't look at me! 🦄
+🦄 I DON'T MEAN THAT, YOU LITTLE JERK!! 🦄
+🦄 🦄
+🦄 But OF COURSE YOU'RE JUST HALLUCINATING🦄
+🦄 anyway. IT'S NOT AN OX. You need to lay🦄
+🦄 off the mushrooms. Actually YOU NEED TO🦄
+🦄 LAY OFF A LOT of things; you've made 🦄
+🦄 that VERY CLEAR WITH YOUR UNHINGED 🦄
+🦄 BEHAVIOUR! 🦄
+🦄 🦄
+🦄 IT'S OBVIOUS YOU SEE A UNICORN!!!! 🦄
+🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄
+
+<169>
+
+ ~~~~~~
+ / 🍝🍝🍝 \
+ / 🍝🍝🍝🍝🍝 \
+ / 🍝🍝🍝🍝🍝🍝 \
+ | 🍝🍝🍝🍝🍝🍝🍝|
+ \ ||| ||| /
+ \ ||||| /
+ \ ||| /
+ \__________/
+ || ||
+ || ||
+ __||__||__
+WOW!!!! THAT'S A SPAGHETTI TREE!!! I saw them over 100 years from now when I last
+used my Time Machine!! The BBC will cultivate them on April Fool's Day 19579!
+THEY'RE AMAZING!! The Time Machines are okay and kind of interesting. Dangerous
+though...
+
+But the spaghetti looks pretty ominous, doesn't it? IT LOOKS LIKE IT WANTS TO REACH
+DOWN AND GRAB YOU! Better be careful. If they strangle you YOU WILL GO TO HELL! On the plus
+side... YOU'LL HAVE THE MOST AMAZING STORY to tell your fellow sinners... Trust me. I've
+been there on holiday! It's PRETTY WILD!! Summers are AMAZINGLY HOT!! Although...GETTING
+EATEN BY A DRAGON OR KILLED BY TYRANNOSAURUSES is an EVEN BETTER STORY! That's MUCH MORE
+EXCITING than a SPAGHETTI TREE KILLING YOU!! Although...now I think on it...they're ALSO
+in Hell so maybe it's better if the spaghetti kills you. Want me to strangle you with it if
+it doesn't do it? Of course...the trees are there too...LOTS of parties too. And good old
+TORTURE! IT'S AWESOME!
+
+<170>
+
+🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣
+🐂 Uh oh. ONE OF THE OXEN JUST KICKED 🐂
+🛁 A BUCKET. Is it going to die next? 🛁
+🪣 Or...is it foreshadowing your own 🪣
+🐂 death? Let's face it. You have it 🐂
+🛁 coming to you. Better throw the ox 🛁
+🪣 out with the bathwater before it's 🪣
+🐂 too late. Oh and don't try telling 🐂
+🛁 me you don't have any oxen left, 🛁
+🪣 if you can even count! It kicked 🪣
+🐂 the bucket SO OF COURSE IT DOESN'T 🐂
+🛁 EXIST!! 🛁
+🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣
+
+<171>
+
+😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈
+😈 Uh oh! Is that the DEVIL I see in 😈
+😈 your mirror again? Or are YOU looking😈
+😈 at it from behind your dressing 😈
+😈 curtain? 😈
+😈 😈
+😈 BETTER BREAK IT BEFORE IT'S TOO 😈
+😈 LATE!!! Yes, YES, I KNOW IT'S BAD 😈
+😈 LUCK TO BREAK A MIRROR!! But ask 😈
+😈 yourself this: what's worse, seeing 😈
+😈 yourself in the Devil's mirror OR 😈
+😈 simply having bad luck for 7 long 😈
+😈 years? Let's be honest. You're NOT 😈
+😈 going to make it that long anyway! 😈
+😈 Why not just give your mind some 😈
+😈 peace and die in an unknown way? Much😈
+😈 less scarier AND IF YOU DON'T BREAK 😈
+😈 IT I WILL! I don't want to see the 😈
+😈 Devil in your mirror! OH HELL! NOT 😈
+😈 AGAIN! I MEAN I DON'T WANT TO SEE 😈
+😈 YOU IN THE DEVIL'S MIRROR!!! 😈
+😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈
+
+<172>
+
+
diff --git a/2024/ferguson1/strings.scrnshot.loc.txt b/2024/ferguson1/strings.scrnshot.loc.txt
new file mode 100644
index 000000000..19aa434da
--- /dev/null
+++ b/2024/ferguson1/strings.scrnshot.loc.txt
@@ -0,0 +1,2199 @@
+<1>
+This program simulates a trip over the Oregon Trail from Independence, Missouri
+to Oregon City. Your extended family will attempt the 2170 mile Oregon Trail in
+5-6 months. You had $6666 for the trip but after foolishly wasting thousands on
+a sinful night yesterday and paying $200 for a wagon train, you only have an
+ominous $1666. You may buy the following items, or not, if you trust the Devil
+to be faithful to your pact:
+
+ Food - the more you have, the less chance you'll starve to
+ death, which would serve you right.
+ Ammunition - $1 only buys 5 bullets due to recent hoarding.
+ You will need lots of bullets for self defence
+ and for hunting food, assuming you don't miss.
+ Clothing - this is especially important for the cold weather
+ you will encounter when crossing the mountains, if you
+ get there.
+ Oxen - the more you spend the better off you'll be, assuming
+ they don't die. Or you don't sacrifice them.
+ Miscellaneous supplies - this includes medicine and other
+ things you'll need.
+
+You can spend all your money before you start your trip or you can save some of
+your cash to spend at forts along the way when you run low on supplies.
+Alternatively, you might wish to spend it all as you'll probably just find
+money along the way. You can also go hunting along the way to get more food,
+assuming you're not such a lousy shot as to be unable to hit a helpless animal
+from a cowardly distance.
+
+At each turn, all items are shown in dollar amounts except bullets. When asked
+to enter money amounts, don't use a $.
+
+Good luck, because the Devil's not going to help out!!! Or...will he?
+
+<2>
+%u
+<3>
+%ld
+<4>
+
+🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦
+🪦 / \ 🪦
+🪦 / A \ 🪦
+🪦 |TORMENTED| 🪦
+🪦 | MONSTER | 🪦
+🪦 | R.I.P. | 🪦
+🪦 |_________| 🪦
+🪦 GAME OVER 🪦
+🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥
+🔥Unfortunately, due to what can only be an 🔥
+🔥ADMINISTRATIVE FOUL-UP, you end up somewhere 🔥
+🔥you did not expect as your forever home. But 🔥
+🔥honestly, after signing the Devil's book, DO 🔥
+🔥YOU REALLY BELIEVE YOU DON'T BELONG HERE? Be 🔥
+🔥honest. For once. You know you belong here. 🔥
+🔥Oh, by the way, god asked me to wish you a 🔥
+🔥PROSPEROUS LIFE ahead... 🔥
+🔥 🔥
+🔥 😈😈😈 WELCOME TO HELL!! 😈😈😈 🔥
+🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥
+
+<5>
+
+🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰
+🍝Not again. Are you REALLY going to tell me 🍝
+😈about the Flying Spaghetti Monster AGAIN? 😈
+🪰I've had ENOUGH of your FAIRY-TALE DELUSIONS! 🪰
+🍝YOU'VE TOLD ME HE IS INVISIBLE SO HOW IN THE 🍝
+😈HELL CAN YOU EVEN KNOW HE EXISTS? 😈
+🪰 🪰
+🍝What next, are you going to tell me that 🍝
+😈between Earth and Mars there is a china teapot😈
+🪰revolving about the Sun in an elliptical 🪰
+🍝orbit? Let me guess! It's so small that even 🍝
+😈the James Webb telescope that was launched 😈
+🪰almost 200 years from now can't even see it, 🪰
+🍝right? What a load of ABSOLUTE RUBBISH! If 🍝
+😈your daughters were not here I WOULD TOTALLY 😈
+🪰BE ABUSING LALOCHEZIA AT YOU RIGHT NOW! 🪰
+🍝BUGGER ME THAT THEY ARE! 🍝
+😈 😈
+🪰If the Flying Spaghetti Monster ACTUALLY 🪰
+🍝existed, he'd eat you for lunch for blasphemy.🍝
+😈Hell, keep this up and I'LL eat you. I'M 😈
+🪰STARVING! 🪰
+🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝😈🪰🍝
+
+<6>
+
+How much do you want to spend on food?
+<7>
+
+How much do you want to spend on ammunition?
+<8>
+
+How much do you want to spend on clothing?
+<9>
+
+How much do you want to spend on oxen?
+<10>
+
+How much do you want to spend on miscellaneous supplies?
+<11>
+
+ Food: %4ld Ammo: %4ld Clothing: %4ld
+ Oxen: %4ld Supplies: %4ld Money: %4ld
+ Health: %4ld Miles: %4ld
+
+<12>
+After all your purchases, you now have $%ld left...
+
+Seriously, YOU WASTED YOUR MONEY LIKE THAT?
+
+<13>
+
+💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈
+😈 Mild illness. Medicine used. Not 💊
+💊 sure why though. IT WAS ONLY A 😈
+😈 SNIFFLE. Probably just the Devil 💊
+💊 TRYING TO ESCAPE FROM YOUR CURSED 😈
+😈 NOSTRILS. In the future THEY BLESS💊
+💊 PEOPLE FOR SNEEZING. You can die 😈
+😈 happy knowing you started a thing.💊
+💊 Even if your death will bring you 😈
+😈 EVERLASTING TORMENT. 💊
+💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈
+
+<14>
+
+Value must be a positive number no larger
+than 666. Or 0. If you trust the Devil.
+
+<15>
+
+🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂
+❌You have run out of oxen and must walk. ❌
+💋Better buy more... IF YOU DIDN'T WASTE MORE 💋
+🐂MONEY ON MORE SINFUL NIGHTS, like your 🐂
+❌red-headed daughters told me last night, ❌
+💋assuming they weren't LYING to me. 💋
+🐂 🐂
+❌AND YES. A dirty mind IS a TERRIBLE thing to ❌
+💋waste BUT NOTHING HAPPENED BETWEEN US!! We're 💋
+🐂JUST FRIENDS and they've been telling me ALL 🐂
+❌ABOUT YOUR RIDICULOUS BEHAVIOUR. OK, it MIGHT ❌
+💋be in bed with them but they can't help 💋
+🐂themselves...kind of like you. WHERE do you 🐂
+❌think they got it from? Besides, IF YOU KNOW ❌
+💋THE DEVIL in the biblical sense WHY SHOULDN'T 💋
+🐂WE? We EXPRESS PASSION and YOU ARE JUST AN 🐂
+❌EVIL MONSTER!!!!👹 Good luck hauling your ❌
+💋wagon! WE'RE TAKING A PLANE!! 💋
+🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂❌💋🐂
+
+<16>
+
+Shooting when low on bullets. That's really
+intelligent. NO WONDER you're starving.
+
+<17>
+
+As you overindulge in a huge platter of spaghetti,
+it suddenly begins to strangle you to death.
+
+You gasp for air, reaching out to the Devil for
+help! In vain. She's already here cackling like
+the monster you are, just WAITING FOR YOU.
+
+Your time has come my friend. But didn't you want
+to know her better anyway?
+
+Better go fulfil your promise! SHE WANTS YOU RIGHT
+NOW! 💋
+
+<18>
+
+🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂
+🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃
+🐂 The only food you have left is an ox! 🐂
+🐂 🐂
+🐂 As you have no choice left, you promptly 🐂
+🐂 kill it before it runs away, and it sure 🐂
+🐂 was DELICIOUS!!! 🐂
+🐂 🐂
+🐂 ( OX'S VOICE ) 🐂
+🐂 You're a sick, sick individual. You do 🐂
+🐂 know that, right? First you BURDEN ME 🐂
+🐂 WITH ALL YOUR RUBBISH and THEN YOU EAT ME?🐂
+🐂 🐂
+🐂 I hope you remember you were starving me 🐂
+🐂 to death so it's your fault you won't get 🐂
+🐂 much sustenance from MURDERING YOUR 🐂
+🐂 FAITHFUL SLAVE ANIMAL!!! Not that I had a 🐂
+🐂 choice. 🐂
+🐂 🐂
+🐂 And YES, there's a place IN HELL FOR 🐂
+🐂 MONSTERS LIKE YOU, AND YES YOUR TIME IS 🐂
+🐂 FAST APPROACHING, YOU RUDDY UNFAITHFUL 🐂
+🐂 LITTLE GIT. 🐂
+🐂 😈😈😈 HE'S WAITING. 😈😈😈 🐂
+🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃
+🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂
+
+<19>
+
+🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂
+🐂 An ox looks at you funny so you eat 🐂
+🐂 him! 🐂
+🐂 🐂
+🐂 You're a sick, sick individual. You do 🐂
+🐂 know that, right? FIRST you BURDEN HIM 🐂
+🐂 WITH ALL YOUR RUBBISH and THEN YOU EAT 🐂
+🐂 HIM BECAUSE OF A FUNNY LOOK? And YOU 🐂
+🐂 DIDN'T EVEN SHARE HIM WITH YOUR FAMILY!🐂
+🐂 🐂
+🐂 What next, will you eat your daughter 🐂
+🐂 too? No! NO! NO NO NO NO! I SHOULD NOT 🐂
+🐂 HAVE SAID THAT! NO! DON'T EVEN THINK 🐂
+🐂 ABOUT TOUCHING HER! BACK OFF!! 🐂
+🐂 🐂
+🐂 SHE'S MINE!!! 🐂
+🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂
+
+<20>
+
+One of the daughters cut her arm and it had to
+be amputated. THANK GOD she is not DOWN IN THE
+MOUTH AND SHE WANTS TO EAT IT BECAUSE YOU ARE
+SUDDENLY STARVING!!!
+
+But OF COURSE you didn't get any. If you weren't
+eyeing it so lustily you would have seen that she
+seemed to ESPECIALLY ENJOY IT, GREEDILY DEVOURING
+IT AS IF IT WAS HER LAST SUPPER! Wait, HAS THE
+DEVIL POSSESSED HER TOO?! THAT EVIL WITCH!!! 🧙🧙🧙
+
+Hang on. YOU'RE JUDGING HER AFTER ALL YOU'VE DONE?
+CUT THAT OUT RIGHT NOW! NO. NO! NO! NO! STOP! I DID
+NOT MEAN CUT ANOTHER LIMB OFF HER! YES I KNOW I got
+some and you didn't. And yes it was DELICIOUS! But
+she wanted me to remember it before it was all gone,
+not you. Eat your own arm if you must. No. I meant
+stop accusing her of witchcraft. YOU signed the
+Devil's book, NOT HER and it WAS her body! This is
+ALL YOUR FAULT, JUST LIKE EVERYTHING ELSE that's
+happened since that fateful night!
+
+<21>
+
+Wagon train damaged! Lost time time resupplying from the Devil.
+
+<22>
+
+Suddenly your clocks stop...
+
+I guess it must have happened AGAIN! And WHY THE DEVIL DO YOU
+KEEP SWIMMING IN THE MOLASSES RIVER?! Honestly, you'll be lucky
+if you don't SINK IN IT before it sinks into your
+stick-in-the-molasses head.
+
+<23>
+
+ ⛰️⛰️⛰️⛰️
+
+ You made it safely through South
+ Pass--no snow. Clearly the Devil
+ has your back. For now my dear
+ fiend, for now...
+
+ He might be plotting against you.
+ Oh hell. I KNOW HE IS. HE TOLD ME
+ HE IS. Your time is coming AND THE
+ DEVIL AND I BOTH CANNOT WAIT!
+ Neither can your daughters. They
+ told me last night in the wagon.
+ YES. I KNOW THEM.
+
+ ⛰️⛰️⛰️⛰️
+
+<24>
+
+🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦
+🪦 All you had was mouldy bread,🪦
+🪦 🪦
+🪦 🪦
+🪦 Therefore here you must lie. 🪦
+🪦 🪦
+🪦 🪦
+🪦 Because now you're dead. 🪦
+🪦 🪦
+🪦 🪦
+🪦 GOODBYE! 🪦
+🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦
+
+<25>
+
+🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂
+🐂 🐂
+🐂 ( OX'S VOICE ) 🐂
+🐂 🐂
+🐂 Still happy you ate me? How 🐂
+🐂 many more miles do you have 🐂
+🐂 to go? 🐂
+🐂 🐂
+🐂 YOU'RE COOKED and you know 🐂
+🐂 it, you horrible, HORRIBLE 🐂
+🐂 MONSTER. 🐂
+🐂 🐂
+🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂
+
+<26>
+
+👻👻👻👻👻👻👻👻👻👻👻👻👻👻 👻
+👻 A little ghost floats by 👻
+👻 and shouts: 👻
+👻 👻
+👻 BOO!!!! 👻
+👻 👻
+👻 Okay that was NOT funny, 👻
+👻 Casper! Go back to your 👻
+👻 shallow grave, you LITTLE 👻
+👻 JERK! 👻
+👻👻👻👻👻👻👻👻👻👻👻👻👻👻 👻
+
+<27>
+
+ ___🔥🔥🔥___
+ / 🔥🔥🔥 \
+ |🔥 WAGON 🔥
+ 🔥🔥🔥 |___🔥🔥🔥___🔥🔥🔥
+ 🔥🔥🔥🔥🔥🔥O 🔥🔥🔥 O🔥🔥
+🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦
+🪦 A fire breaks out in your 🪦
+🪦 wagon, and the wind quickly🪦
+🪦 fans the flames, CAUSING 🪦
+🪦 YOUR AMMO TO BLOW UP, 🪦
+🪦 killing you! Somehow 🪦
+🪦 everyone else survived... 🪦
+🪦 🪦
+🪦 Frankly, IT WAS ABOUT TIME.🪦
+🪦 I mean WHAT KIND OF IDIOT 🪦
+🪦 overloads their wagon with 🪦
+🪦 WEAPONS? 🪦
+🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦
+
+<28>
+
+Uh oh. A black cat just jumped out in front of you. Is
+the Devil calling you? Better go have a look before it's
+too late. Maybe it already is. Your daughters told me
+you're an ailurophobe! Some pretty wild stories I hear.
+I think it probably is too late. Isn't it Friday the
+13th?
+
+<29>
+
+You take lots of cash 💰 from the riders 🏇,
+accidentally stabbing one as he flees. But
+since you're starving, why don't you MAKE
+PENANCE BY NOT WASTING THE BODY YOU RUDELY
+CUT OPEN?
+
+ 🍖🥩🍔🥩🍔🍖
+ Mm...that was DELICIOUS!!!
+(🪦👻RIDER'S SOBBING VOICE FROM THE GRAVE👻🪦)
+
+You know what you did is wrong, right? We
+were JUST ROBBED YESTERDAY, you rob us today
+AND NOW I'M DEAD 👻!
+
+WELL GOOD. I WAS DYING OF DYSENTERY and
+now YOU get to SPREAD THE DISEASE as well.
+
+<30>
+
+ ~~~~~~
+ / 🍝🍝🍝 \
+ / 🍝🍝🍝🍝🍝 \
+ / 🍝🍝🍝🍝🍝🍝 \
+ | 🍝🍝🍝🍝🍝🍝🍝|
+ \ ||| ||| /
+ \ ||||| /
+ \ ||| /
+ \__________/
+ || ||
+ || ||
+ __||__||__
+WOW!!!! THAT'S A SPAGHETTI TREE!!! I saw
+them over 100 years from now when I last
+used my Time Machine!! The BBC will
+cultivate them on April Fool's Day 19579!
+THEY'RE AMAZING!! The Time Machines are
+okay and kind of interesting. Dangerous
+though...
+
+But the spaghetti looks pretty ominous,
+doesn't it? IT LOOKS LIKE IT WANTS TO REACH
+DOWN AND GRAB YOU! Better be careful. If they
+strangle you YOU WILL GO TO HELL! On the plus
+side... YOU'LL HAVE THE MOST AMAZING STORY to
+tell your fellow sinners... Trust me. I've
+been there on holiday! It's PRETTY WILD!!
+Summers are AMAZINGLY HOT!! Although...GETTING
+EATEN BY A DRAGON OR KILLED BY TYRANNOSAURUSES is
+an EVEN BETTER STORY! That's MUCH MORE
+EXCITING than a SPAGHETTI TREE KILLING YOU!!
+Although...now I think on it...they're ALSO
+in Hell so maybe it's better if the spaghetti
+kills you. Want me to strangle you with it if
+it doesn't do it? Of course...the trees are
+there too...LOTS of parties too. And good old
+TORTURE! IT'S AWESOME!
+
+<31>
+
+😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈
+😈 Uh oh! Is that the DEVIL I see in 😈
+😈 your mirror again? Or are YOU looking😈
+😈 at it from behind your dressing 😈
+😈 curtain? 😈
+😈 😈
+😈 BETTER BREAK IT BEFORE IT'S TOO 😈
+😈 LATE!!! Yes, YES, I KNOW IT'S BAD 😈
+😈 LUCK TO BREAK A MIRROR!! But ask 😈
+😈 yourself this: what's worse, seeing 😈
+😈 yourself in the Devil's mirror OR 😈
+😈 simply having bad luck for 7 long 😈
+😈 years? Let's be honest. You're NOT 😈
+😈 going to make it that long anyway! 😈
+😈 Why not just give your mind some 😈
+😈 peace and die in an unknown way? Much😈
+😈 less scarier AND IF YOU DON'T BREAK 😈
+😈 IT I WILL! I don't want to see the 😈
+😈 Devil in your mirror! OH HELL! NOT 😈
+😈 AGAIN! I MEAN I DON'T WANT TO SEE 😈
+😈 YOU IN THE DEVIL'S MIRROR!!! 😈
+😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈
+
+<32>
+
+🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁
+🐂 Uh oh. ONE OF THE OXEN JUST KICKED 🐂
+🛁 A BUCKET. Is it going to die next? 🛁
+🪣 Or...is it foreshadowing your own 🪣
+🐂 death? Let's face it. You have it 🐂
+🛁 coming to you. Better throw the ox 🛁
+🪣 out with the bathwater before it's 🪣
+🐂 too late. Oh and don't try telling 🐂
+🛁 me you don't have any oxen left, 🛁
+🪣 if you can even count! It kicked 🪣
+🐂 the bucket SO OF COURSE IT DOESN'T 🐂
+🛁 EXIST!! 🛁
+🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🪣
+
+<33>
+
+🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖
+🦖 A GROUP OF TYRANNOSAURUSES ATTACK! 🦖
+🦖 🦖
+🦖Unfortunately for you, you're in a time 🦖
+🦖LONG BEFORE the brilliant mathematician 🦖
+🦖Ian Malcolm informed us that DINOSAURS 🦖
+🦖FIND A WAY TO KILL HUMANS. You should 🦖
+🦖have thought of that BEFORE you STUPIDLY 🦖
+🦖climbed into that Time Machine to travel 🦖
+🦖back in time to the Oregon Trail, where 🦖
+🦖you could not possibly know so many 🦖
+🦖important things about dinosaurs... 🦖
+🦖 🦖
+🦖ALTHOUGH, now I think on it, that MIGHT 🦖
+🦖not have been EXACTLY how it went... I 🦖
+🦖THINK the correct wording was 'LIFE FINDS 🦖
+🦖A WAY' but that's well over 100 years from🦖
+🦖now and instead of life finding a way the 🦖
+🦖Devil will find a way. To torment you. 🦖
+🦖With more dinosaurs. And dragons. Yes 🦖
+🦖they still exist. Oh and the Earth is 🦖
+🦖flat too... 🦖
+🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖
+
+<34>
+
+🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃
+
+ / \
+ / A \
+ |TORMENTED|
+ | PIONEER |
+ | R.I.P. |
+ |_________|
+ GAME OVER
+
+ Here you lie dead,
+ You tried to outrun a runaway bed.
+ But you slipped and hit your head,
+and now you body's forever in an underground bed!
+
+🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃
+
+<35>
+
+ 🌨️🌨️🌨️🌨️🌨️🌨️🌨️🌨️🌨️🌨️🌨️
+ 🏔️🏔️🏔️🏔️🏔️🏔️🏔️🏔️🏔️🏔️🏔️
+
+Blizzard in mountain pass--time wasted
+asking Devil for help restocking.
+
+Unfortunately, the unfaithful monster
+only gives you ONE MEASLY BULLET. Like
+that's going to help his most faithful
+lieutenant? Oh but are you faithful?
+
+Perhaps you should have used a mountain
+cable car 🚠, rather than relying on the
+Devil! It's pretty funny you didn't know
+he was unfaithful and yet expects complete
+loyalty. Or else. HE'S COMING.
+
+<36>
+
+You have been on the trail too long and you die of
+boredom.
+
+You know you're lucky to have made it this long. Frankly
+with your behaviour I'm surprised you didn't die from a
+sinful disease much earlier. Or drowning in molasses. Or
+freezing to death with your choice in clothing.
+ 🩳🩲👗👙🩳🩲👗👙🩳🩲👗👙
+SERIOUSLY mate, you brought shorts, briefs, A DRESS AND
+A BIKINI on the Oregon Trail? What the hell were you
+thinking? Actually though...now I think on it...perhaps
+Hell WILL serve you better? I hear the Summers are
+AMAZING there! Winters, not so much.
+
+At least your family gets free food now, assuming monsters
+are edible. I'm not sure if they are. I suspect they would
+be poisoned or die from your hot, burning flesh.
+
+<37>
+
+You'd better do some hunting or buy food soon, before you starve
+to death! Or don't. Let's face it. You'd deserve it.
+
+<38>
+
+😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈
+🏥Doctor's bill is $666 and you can't afford it 🏥
+😈DUE TO ALL YOUR RECKLESS SPENDING! HE MUST BE 😈
+🏥POSSESSED BY BEELZEBUB! SURELY ONLY THE DEVIL 🏥
+😈would do this. It's not like you've ever 😈
+🏥killed a helpless animal or human, never 🏥
+😈robbed anyone, never ate human flesh or done 😈
+🏥any other heinous thing, never sinned ... 🏥
+😈 😈
+🏥NO. STOP LYING! YOU signed the Devil's book! 🏥
+😈You should have listened to your Reverend 😈
+🏥Samuel Parris way back in 1692. All these 🏥
+😈wild, strange and bad happenings, since you 😈
+🏥began your journey are ALL YOUR fault, EVEN 🏥
+😈YOUR DAUGHTERS' WILD DANCING BY THE NIGHT 😈
+🏥FIRES AS IF POSSESSED! Not that I'm going to 🏥
+😈complain about THAT...Hell, THEY ASKED ME TO 😈
+🏥JOIN THEM! 🏥
+😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈
+
+<39>
+
+🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖
+👶 ( SON'S VOICE ) 👶
+🍖 🍖
+👶 How you feeling about eating 👶
+🍖 me? Eating your own son, NO 🍖
+👶 WONDER she was having an affair 👶
+🍖 before her untimely death! It 🍖
+👶 was with YOUR SISTER AND HER 👶
+🍖 HUSBAND. 🍖
+👶 👶
+🍖 OH NO. NO, NO, NO, NO!! Please 🍖
+👶 don't tell me you ate her too. 👶
+🍖 Wait. You didn't feed her to us,🍖
+👶 did you? Ugh, you did, didn't 👶
+🍖 you? You're a sick, sick person.🍖
+👶 👶
+🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖
+
+
+<40>
+
+💩💩💩💩💩💩💩💩💩💩💩💩💩💩
+🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽
+💩💩💩💩💩💩💩💩💩💩💩💩💩💩
+
+You have died of dysentery.
+
+CONGRATULATIONS ON REACHING
+ LEGENDARY STATUS!
+
+💩💩💩💩💩💩💩💩💩💩💩💩💩💩
+🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽
+💩💩💩💩💩💩💩💩💩💩💩💩💩💩
+
+<41>
+
+🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸
+🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸
+🩸🩸 YOU HAVE DIED OF INJURIES! 🩸🩸
+🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸
+🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸
+
+ Better than diarrhoea though,
+ right?
+
+ Frankly, it serves you right.
+ If you hadn't wasted all that
+ time and money sinning you
+ MIGHT have made it. But I guess
+ there's no real difference;
+ after all, none of us really
+ make it out alive, do we? Well
+ off you go then! HEAVEN AWAITS!!
+ Or does it?
+
+<42>
+
+Do you want to (1) stop at the next fort 🏰, (2) hunt 📸 or (3) continue?
+<43>
+
+Do you want to (1) hunt 📸 or (2) continue?
+<44>
+
+You need more bullets to go hunting. Or -- do you?
+
+<45>
+
+You have died of exhaustion. I'm SURE
+your victims ARE MOURNING FOR YOUR FAMILY.
+Assuming they're not too busy EATING YOU
+🍕🍔🍟🥪🌯🌮🌭 WITH THEM. I KNOW FOR A
+FACT your daughters LOVE meat and I'm
+sure they're already devouring you!
+Hopefully they'll save some for everyone
+else this time; it'd be a REAL SHAME if
+your body went to waste...or would it
+be?
+
+<46>
+
+💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰❌💋
+❌DON'T BE ABSURD! You don't have that kind of money. ❌
+💰In fact, one of your daughters told me JUST LAST 💰
+💋NIGHT that ONCE AGAIN you had a delightfully sinful 💋
+❌night! NO! I KNOW WHAT YOU'RE THINKING! NOTHING ❌
+💰HAPPENED BETWEEN US! STOP THAT RIGHT NOW, YOU 💰
+💋FILTHY SINNER! 💋
+❌ ❌
+💰Hmm...although...now I think on it, I'm starting 💰
+💋to wonder... OH HELL! NO NO NO! What if she seduced 💋
+❌me and we DID DO something? That would be AWFUL, ❌
+💰JUDGING YOU WHILE HAVING AN AFFAIR WITH ONE OF THE 💰
+💋WOMEN! Still sure WE'D NEVER SIGN THE DEVIL'S BOOK! 💋
+❌ ❌
+💰Although...I don't really remember WHAT we did last 💰
+💋night... ANYWAY, KEEP US OUT OF IT YOU MONSTER! 💋
+❌ ❌
+💰The book has a cost and money doesn't grow on trees. 💰
+💋Perhaps it might grow on horns though? Ask the Devil 💋
+❌for help. Assuming he helps MONSTERS. ❌
+💰💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰💋❌💰💋
+
+<47>
+
+You FINALLY arrived at Oregon City after 2170
+long miles!
+
+TOOK YOU LONG ENOUGH. Probably all your sinful
+detours I've heard so much about but you'd think
+that the Devil would have helped you out on that.
+But I guess as long as you make it to your final
+destination that's what matters, right?
+
+Oh, right. Almost forgot! President Jesse James
+asked me to wish you a prosperous life ahead of
+you...in HELL!
+
+<48>
+
+
+ 🔥🌨️🔥🌨️🔥🌨️🔥🌨️🔥🌨️🔥🌨️🔥
+Phantom blizzard from Hell suddenly hits
+and you freeze to death, leaving everyone
+behind. You know the Devil 😈 is calling
+you, right?
+
+ 🩳🩲👗👙
+
+And with your choice in clothing, ARE YOU
+REALLY SURPRISED YOU FROZE TO DEATH? I mean
+SERIOUSLY mate, shorts, briefs, A DRESS AND
+A BIKINI on the Oregon Trail? What the hell
+were you thinking? You're not in Hell,
+you're on the Oregon Trail!
+
+Although...now I think on it...perhaps Hell WILL
+serve you better? I hear the Summers are GREAT
+there! Lots of parties. Winters are -- actually,
+there are no winters. ONLY WEATHER TO BURN YOU
+FOR ETERNITY.
+
+At least your family gets fresh meat on the bone,
+assuming they can stomach eating a horrible
+monster. If I were them I'D BURN YOUR BODY.
+
+<49>
+
+🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔
+🍟Uh oh. THERE'S ANOTHER ELF! You must be 🍟
+🍔losing your mind my friend! ELVES DON'T 🍔
+🍟EXIST, unless you ask a German. They can't 🍟
+🍔even count to 11 without claiming there are 🍔
+🍟elves! Neun, zehn, Elf ... I guess I might 🍟
+🍔be losing my mind too! BETTER SHOOT THE ELF 🍔
+🍟BEFORE IT TAKES YOUR DAUGHTERS AWAY AND EATS 🍟
+🍔THEM! You might need them for food later on, 🍔
+🍟you HORRIBLE, HORRIBLE MONSTER. They are 🍟
+🍔heavenly women and are not for evil Devil 🍔
+🍟worshippers to eat! NO. NOT FOR ME EITHER! 🍟
+🍔Stop going there you sicko! They are NOT food 🍔
+🍟and YOU CANNOT GO TO HEAVEN, YOU DEVIL 🍟
+🍔WORSHIPPING MONSTER! Cut it out. NO! NOT THEM!🍔
+🍟STOP WHAT YOU'RE DOING!!! 🍟
+🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔
+
+<50>
+
+You need more bullets to go hunting. Or..do you?
+
+<51>
+
+You shot a Bald Eagle 🦅. WHY, monster,
+WHY?!
+
+I mean look at its former strength, its
+majesty! No wonder it became the symbol
+of America!
+
+GREAT JOB Devil worshipping pioneer, you
+just killed America! I hope it's poisoned
+or you at least choke on the bones.
+
+<52>
+
+ 🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃
+Great shot! YOU GOT THE FATTEST ONE THERE! As if
+that should be hard. IT COULD BARELY MOVE! But
+with your WILD SHOOTING AND HORRIBLE AIM the
+ONLY REASON you didn't miss by a hundred miles is
+you signed the Devil's book, EVEN THOUGH IT WAS AS
+WIDE AS A BLUE WHALE. There's no way you'd have got
+such a nice shot EVEN IF THE POOR BEAST WAS
+PRACTICALLY DEAD. I'm STILL surprised you didn't
+shoot yourself in the eyes. But the Devil DOES
+exact his dues and the animal might have been
+poisoned. Eat at your own risk. OR STARVE.
+Let's face it, YOU'RE DOOMED.
+ 🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃🫃
+
+<53>
+
+WHAT A TERRIBLE SHOT! How could anyone POSSIBLY miss a helpless animal that was
+standing still, 100 FEET WIDE AND 150 YEARS OLD? IT WAS SO FAT IT WOULD MAKE
+100 BLUE WHALES OBESE!
+
+I hope you starve, you murderous beast, and it looks like you're going to,
+after WASTING ALL THOSE BULLETS and MISSING FISH OUT OF WATER. You'd better
+buy some food NOW.
+
+<54>
+
+😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈
+😈 Severe illness. You must see Doctor 😈
+😈 Beelzebub. Assuming he's not too busy 😈
+😈 trying to tempt your daughters. Don't 😈
+😈 worry though! I don't think he'll 😈
+😈 succeed. I haven't yet either and I'VE 😈
+😈 BEEN TRYING FOR YEARS! THEY ARE 😈
+😈 INCORRIGIBLE MUMPSIMUSES!! No. I don't 😈
+😈 think he's possessed me. I'm just like 😈
+😈 that. But we can test it. What do you 😈
+😈 think about performing an exorcism on 😈
+😈 me? 😈
+😈 😈
+😈 Actually...no. I take that back. Let me 😈
+😈 perform one on YOU to make sure it works.😈
+😈 I'm pretty sure they don't but better 😈
+😈 to do it on a Devil worshipper than 😈
+😈 someone who's unhinged from watching you.😈
+😈 Safer that way. 😈
+😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈
+
+<55>
+
+If we are what we eat then doesn't that mean we're all cannibals?
+
+<56>
+
+
+🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯
+🤯 Riders ahead. They don't look hostile. 🏇
+🤯🔫🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🏇
+🏇🔫Oh! I know what to do! You should TOTALLY ROB 🔫 🤯
+🤯🔫THEM BLIND!! They won't know what hit them and🔫 🏇
+🏇🔫it's not like they need their belongings, 🔫 🤯
+🤯🔫not where they are going, and you're going to 🔫 🏇
+🏇🔫need them soon, with your reckless behaviour. 🔫 🤯
+🤯🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🔫 🏇
+🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯🏇🤯
+
+<57>
+
+
+<58>
+
+
+<59>
+
+
+<60>
+
+
+<61>
+
+💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉
+💉You scared them off with your ERRATIC 💉
+💉shooting. NEARLY BLEW MY HEAD OFF TOO.💉
+💉GREAT JOB. 💉
+💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉💉
+
+<62>
+
+ 🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸
+ 🩸🔪💩🔪💩🔪💩🔪💩🔪💩🔪💩🔪💩🩸
+ 🩸💩WORST SHOT EVER! You got💩🩸
+ 🩸💩knifed 🔪 by the dung! 💩🩸
+ 🩸💩How did you miss the 💩🩸
+ 🩸💩TRIGGER? 💩🩸
+ 🩸🔪💩🔪💩🔪💩🔪💩🔪💩🔪💩🔪💩🩸
+ 🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸
+Be honest. IT'S YOUR OWN STUPID FAULT
+FOR TRYING TO ATTACK FRIENDLY PEOPLE!
+Seriously, what the hell kind of person
+does that? I'm glad the dung 💩 knifed 🔪
+you. And remember that if the wound
+becomes infected with bacteria IT'S
+YOUR OWN BLOODY FAULT.
+
+Better have Doctor Beelzebub check it out,
+assuming he wasn't shot and treats MONSTERS.
+I hope he was shot!
+
+<63>
+
+You have to see Doctor Beelzebub!
+
+<64>
+
+
+<65>
+
+
+<66>
+
+ 🏇🏇🏇🏇🏇🏇🏇🏇🏇🏇🏇🏇🏇🏇
+Riders were friendly, but check for possible
+losses anyway. It's always the friendly ones
+who do something bad!! They're OBVIOUSLY hiding
+something!
+ ⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️
+
+<67>
+
+<68>
+
+🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛
+🐺 I JUST HATE VAMPIRES! Don't you? If they had 🐺
+🥄 it their way THERE WOULD BE NO SUN! Can you 🥄
+🧛 imagine how HORRIBLE that would be?! 🧛
+🐺 🐺
+🥄 Wait. You mean to tell me...you want ETERNAL 🥄
+🧛 Sun and NO Moon?! Only ONE reason for that! 🧛
+🐺 You MUST be a...WEREWOLF! I KNEW IT! Better 🐺
+🥄 watch your heart. If you have one. Your 🥄
+🧛 daughters have SILVER SPOONS and they're FED 🧛
+🐺 UP WITH YOUR BARKING BEHAVIOUR!! 🐺
+🥄 🥄
+🧛 On the other blade...IT IS VERY HOT don't 🧛
+🐺 you think? Almost as if it's foreshadowing 🐺
+🥄 what's to come! MAYBE WE SHOULD GET RID OF 🥄
+🧛 FIRE TOO! I mean you're in extreme danger of 🧛
+🐺 that too! THEN WE CAN DROWN you so you can 🐺
+🥄 BURN IN HELL!!! And if that doesn't work, 🥄
+🧛 we can behead you with the SPOONS!! 🧛
+🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺
+
+<69>
+
+🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺
+🥄Suddenly...the hairs on your neck stand up. 🥄
+🐺ARE YOU ACTUALLY A WEREWOLF? You do know that 🐺
+🥄there are silver spoons in your daughters' 🥄
+🐺wagon, right? 🐺
+🥄 🥄
+🐺Better run for your life or howl to scare 🐺
+🥄them off before it's too late, because 🥄
+🐺they told me that they HATE wolves, your 🐺
+🥄BARKING BEHAVIOUR and THEY'VE HAD ENOUGH OF 🥄
+🐺YOUR DEVIL WORSHIPPING!! 🐺
+🥄 🥄
+🐺Oh and yes. Spoons CAN stab you in the heart. 🐺
+🥄If you don't believe me...try it. Assuming 🥄
+🐺you have a heart in the first place... 🐺
+🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄
+
+<70>
+
+You ran out of bullets and got massacred by the riders.
+
+How I do not know, seeing as how they were friendly. Oh
+I remember now. It's because you actually decided to
+cowardly try and rob them blind.
+
+<71>
+
+ ____
+ ____( )____
+ / o \
+(FLAT 🫓 OXEN 🐂)
+ \____ ____o_/
+ | |
+Flat oxen--slows you down.
+
+And don't try telling me you didn't have an
+ox because that would also be a flat ox!
+
+<72>
+
+🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄
+🦄 About 100 feet from here YOU SWEAR you 🦄
+🦄 see an ox stuck in a hole. THANK THE 🦄
+🦄 DEVIL IT'S NOT A DONKEY! You KNOW what 🦄
+🦄 that would make!! There are enough 🦄
+🦄 here already! NO! Don't look at me! I 🦄
+🦄 DON'T MEAN THAT, YOU LITTLE JERK!! 🦄
+🦄 🦄
+🦄 But of course YOU'RE WRONG AS USUAL. 🦄
+🦄 IT'S NOT AN OX. You NEED a pair of VERY🦄
+🦄 POWERFUL glasses my friend. Might also 🦄
+🦄 want to avoid that funny fungi...could 🦄
+🦄 be related...somehow. But really get 🦄
+🦄 some eyeglasses! 🦄
+🦄 🦄
+🦄 IT'S OBVIOUS YOU SEE A UNICORN!!!! 🦄
+🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄
+
+<73>
+
+Bad luck--you got gangrene in one of your limbs and you
+had to chop it off. Or maybe it was good luck? FREE FOOD
+TONIGHT!!! 🍖
+
+<74>
+
+Oh dear. That isn't the Barghest AGAIN is it? Better watch
+your back! And front. And above you. Actually, YOU'RE DOOMED
+and you know it. Your fate was sealed upon signing the Devil's
+book. Honestly, what were you thinking? You HAD to have known it
+always comes with a cost. And you and I BOTH KNOW that the women
+were warning you - but you just HAD to have your way, didn't you?
+
+Well the Oregon Trail is out to get you in every direction and
+the odds are you won't make it out alive. You might be in good
+company there, AND YOU AT LEAST GET TO SEE DINOSAURS ALIVE (LUCKY
+YOU!!) BUT THERE'S NO AIR CONDITIONING and I heard it gets REALLY
+HOT down there. Then again, I also heard there's no heater in
+Heaven... Yup, either way YOU'RE DOOMED AND YOU KNOW IT! But don't
+feel too bad. At least you won't FREEZE TO DEATH. You might here
+though... Yup, FREEZE TO DEATH HERE and then BURN TO DEATH THERE!
+
+<75>
+
+🍖🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶
+🍖Your son gets lost and FREEZES TO DEATH! 🍖
+🍖 🍖
+🍖But on the bright side, you now have 🍖
+🍖one fewer person to feed and not only 🍖
+🍖that you get a FREE MEAL TONIGHT!!! Not 🍖
+🍖that you've been starving yourself 🍖
+🍖deliberately. You're a glutton and you 🍖
+🍖know it. But hey, now you have FRESH MEAT 🍖
+🍖ON THE BONE!! Why not START A FEAST? You 🍖
+🍖did remember your pots and deadpans, 🍖
+🍖right? IF NOT I HOPE YOU STARVE TO DEATH. 🍖
+🍖OH AND YOU BETTER SHARE THIS TIME! 🍖
+🍖🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🍖
+
+<76>
+
+💦🚽💩💦🚽💩💦🚽💩💦🚽💩💦🚽💩💦🚽💩💦🚽💩
+🚽OH HELL! That water tasted REALLY 💦
+💩funny! No. Sorry. NOT Hell. There 🚽
+💦is no water in Hell! Well, wherever 💩
+🚽you are, it appears you drank 💦
+💩unpotable water and it's too 🚽
+💦late now. 💩
+🚽 💦
+💩Next time LOOK AT WHAT 💩 you intend💦🚽
+💦on swallowing BEFORE YOU SHOVE IT 💩
+🚽DOWN YOUR THROAT, because you now 💦
+💩have dysentery. 🚽
+💦🚽💩💦🚽💩💦🚽💩💦🚽💩💦🚽💩💦🚽💩💦🚽💩
+
+<77>
+
+ Heavy rains---time and supplies lost.
+
+ But seriously, you brought these
+ supposed brollies?
+ 🌂🌂🌂🌂🌂🌂🌂🌂🌂🌂🌂🌂🌂🌂🌂🌂🌂🌂🌂🌂
+
+ You SHOULD HAVE BROUGHT THESE:
+ ☔️☔️☔️☔️☔️☔️☔️☔️☔️☔️☔️☔️☔️☔️☔️☔️☔️☔️☔️☔️
+ AND THESE HATS!!
+ 🧢🧢🧢🧢🧢🧢🧢🧢🧢🧢🧢🧢🧢🧢🧢🧢🧢🧢🧢🧢
+
+<78>
+
+ 👑🏴☠️⚓️🚢👑🏴☠️⚓️🚢👑🏴☠️⚓️🚢👑🏴☠️⚓️🚢👑
+ 🏴THE QUEEN ANNE'S REVENGE ATTACKS! 🏴
+ ☠️⚓️🚢👑🏴☠️⚓️🚢👑🏴☠️⚓️🚢👑🏴☠️⚓️🚢👑🏴☠️
+
+YES. You're right. That WAS Blackbeard's ship!
+Yes EDWARD TEACH IS ON THE OREGON TRAIL! NO,
+YOU'RE NOT HALLUCINATING. Neither am I. Didn't
+you know he also signed the Devil's book? Oh
+well, now you've been taught. Still, a ghost is
+a ghost...THIS SHOULD BE EASY!!
+
+But face it. After all you've done, you DESERVE
+THIS AND YOU KNOW IT! I HOPE HE ROBS YOU BLIND and
+if you die in the process you know it's your fault.
+Your time is coming and the Devil is calling you,
+laddie.
+
+<79>
+
+ 🦵🩸❌💰
+BLACKBEARD DIED OVER A CENTURY AGO AND
+HE STILL GOT YOU!
+
+Yes. SOMEHOW you got shot in the
+leg and robbed by a GHOST.
+
+GREAT JOB!
+
+<80>
+
+
+ 🦵🩸❌💰
+
+
+You got shot in the leg and they took one of your oxen,
+whether or not you have any oxen left. Not that that matters much;
+you're more than capable of stealing one, assuming you don't
+sacrifice it to the gods. The Devil. I meant the Devil.
+
+<81>
+
+ WELL DONE, LAD!!!
+
+Somehow, you scared the pirates off!
+Unfortunately you also managed to steal
+food and miscellaneous supplies from
+the pirates as they fled, though I
+honestly haven't a bloody clue how you
+did that. I do hope you get food
+poisoning so you can finally meet the
+Devil like Blackbeard was SUPPOSED to
+have. But aren't historians so awful,
+lying about Blackbeard? YOU'RE NEXT,
+LAD!
+
+<82>
+
+ __________
+ / \
+ | 🔥🔥🔥 |
+ |___🔥🔥🔥___|
+ O O
+
+There was a fire in your wagon. Too
+bad only food and supplies were lost!
+You know you deserve worse, right?
+
+<83>
+
+Lost your way in heavy fog but somehow you did
+not lose much time, due to the STRANGE MAP in
+the LAST BOOK you read.
+
+You know which book I mean. Sure. IT IS a FASCINATING
+READ! But you do know it's going to cost you though,
+right?
+
+<84>
+
+🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉
+🐉 A dragon eats you! 🐉
+🐉 🐉
+🐉 No, I know what you're probably 🐉
+🐉 thinking. I would TOO! Who wants 🐉
+🐉 to be eaten by a dragon? But THIS 🐉
+🐉 TIME IT WAS NOT any of the grass 🐉
+🐉 you understandably ate when you 🐉
+🐉 were ravenous. 🐉
+🐉 🐉
+🐉 No. I'm afraid not. The Earth is 🐉
+🐉 flat, dragons are real and the Sun 🐉
+🐉 is crazy. Oh and yes the Devil is 🐉
+🐉 also real. But you ALREADY knew that 🐉
+🐉 didn't you? Welcome to the harshness 🐉
+🐉 of the Oregon Trail. Or was it the 🐉
+🐉 Devil's bedchamber? Oh well, you're 🐉
+🐉 dead now so no sense brooding over 🐉
+🐉 what seems like Hell. Why not go to 🐉
+🐉 the REAL Hell instead? OH HELL, WHY 🐉
+🐉 NOT make it the Devil's bedchamber? 🐉
+🐉 Be faithful. FOR ONCE. HELL, YOU 🐉
+🐉 MIGHT EVEN ENJOY IT! No, not Hell. 🐉
+🐉 Okay...actually...yeah, Hell too. 🐉
+🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉🐉
+
+<85>
+
+ 🐍🐍🐍🐍🐍🐍🐍
+
+You die of a snakebite because you stupidly didn't bring any
+antivenin. Oh wait. I forgot. They haven't invented it yet
+and nobody wants to suck the venom out of you. I'm actually
+surprised they haven't abandoned you entirely. Oh well, now
+they don't need to, although they might not be wise to have
+the fresh off the bone meat.
+
+ 🐍🐍🐍🐍🐍🐍🐍
+
+<86>
+
+ ❌❌❌
+ ❌🐂❌
+ ❌❌❌
+
+Wagon train got swamped fording river; lost
+food, clothes and an ox got stuck, whether or
+not you spared no expense on oxen. Alas, you
+couldn't save him.
+
+WAIT. You didn't swim in the Molasses River
+AGAIN, did you? HOW MANY TIMES DO I HAVE TO
+REMIND YOU THAT THIS IS A VERY BAD IDEA? If
+only you thought to bring a portable oven so
+you could AT LEAST bake molasses cookies 🍪!
+But you didn't. I hope you starve. Then you'll
+be able to cook all the cookies in the world.
+HELL. I MEANT IN HELL.
+
+<87>
+
+Wild dragons attack! And you actually thought you could shoot
+them? Everyone knows dragons have armoured scales. I mean what
+was the point? You should have brought yourself a pair of wings
+so you could fly straight into the fire, so that you would've
+gone out in STYLE and with an amazing legacy!
+
+And no, I'm afraid you weren't hallucinating. The Earth IS flat,
+dragons ARE real and the Sun IS crazy. Oh and the Devil is real
+too. But you already knew that, didn't you, you filthy sinner?
+
+<88>
+
+Unfortunately, bullets won't help you with dragons; I'm surprised
+you didn't know that. Anyone knows dragons have armoured scales.
+Unfortunately for you they took a few oxen and upturned your wagon
+train, causing you further delays.
+
+Just be thankful you're still alive because this time you were walking
+on dragon eggshells. No. If you did that you'd be dead. I meant walking
+a thin line.
+
+<89>
+
+GREAT SHOOTING---they didn't get anything but you killed
+one of your oxen and somehow you managed to upturn your wagon.
+
+<90>
+
+Really? You tried to shoot a dragon? Well that was pointless. They ate one
+of your oxen and upturned your wagon train, causing further delays.
+
+<91>
+
+😈👶😈👶😈👶😈👶😈👶😈👶😈👶😈
+👶 ( SON'S VOICE ) 👶
+😈 😈
+👶 How you feeling about 👶
+😈 eating me? Eating your 😈
+👶 own son, and you're 👶
+😈 sick, too. 😈
+👶 👶
+😈 Probably food poisoning. 😈
+👶 GOOD. SERVES YOU RIGHT. 👶
+😈 Time to die. 😈
+👶😈👶😈👶😈👶😈👶😈👶😈👶😈👶
+
+<92>
+
+ 🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶
+ 🥶You freeze to death.🥶
+ 🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶🥶
+ 👙🩳🩲👗
+And with your choice in clothing, ARE YOU
+REALLY SURPRISED? I mean SERIOUSLY mate,
+shorts, briefs, A DRESS AND A BIKINI on
+the Oregon Trail? What the hell were you
+thinking? You're not in Hell, you're on
+the Oregon Trail!
+
+Although...now I think on it, perhaps
+Hell WILL suit you better? I hear the
+Summers are GREAT there! Winter is as
+cold as Hell though. No. Not Hell. Hell
+does not get cold! You're going to BURN,
+BURN, BURN!!!!
+
+<93>
+
+😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈
+🏥Doctor's bill is $666! HE MUST BE POSSESSED 🏥
+😈BY BEELZEBUB! SURELY ONLY THE DEVIL would 😈
+🏥do this. It's not like you've ever killed a 🏥
+😈helpless animal or human, never robbed 😈
+🏥anyone, never ate human flesh or done any 🏥
+😈other heinous thing, never sinned ... 😈
+🏥 🏥
+😈NO. STOP LYING! YOU signed the Devil's book! 😈
+🏥You should have listened to your Reverend 🏥
+😈Samuel Parris way back in 1692. All these 😈
+🏥wild, strange and bad happenings, since you 🏥
+😈began your journey are ALL YOUR fault, EVEN 😈
+🏥YOUR DAUGHTERS' WILD DANCING BY THE NIGHT 🏥
+😈FIRES AS IF POSSESSED! Not that I'm going to 😈
+🏥complain about THAT...Hell, THEY ASKED ME TO 🏥
+😈JOIN THEM! 😈
+🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥
+
+<94>
+
+🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂
+☔️ Hail storm--YOU WERE HIT ON THE ☔️
+🧢 HEAD and supplies were damaged. 🧢
+🌂 But did you REALLY think this 🌂
+☔️ CLOSED BROLLY 🌂 was going to ☔️
+🧢 help you against HAIL? Even this 🧢
+🌂 one ☔️ PROBABLY wouldn't do much 🌂
+☔️ good. YOU SHOULD HAVE BROUGHT A ☔️
+🧢 HAT 🧢!! 🌂 🧢
+🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂☔️🧢🌂
+
+<95>
+
+Helpful Indians show you where to find
+more food. Pizza, hamburgers, chips/fries
+and other greasy, fatty foods ...
+ 🍕🍔🍟🥪🌯🌮🌭
+Okay so IT'S ONLY A HEART ATTACK ON A
+PLATE but at least you'll survive another
+day...if you don't have a heart attack
+first, that is... Better have your Doctor
+Beelzebub check you out. If he's still
+alive. Oh no.
+
+You didn't eat him when you were starving
+last time, did you? If so I hope you DO
+have a heart attack!
+
+<96>
+
+
+🧶🧶🧶🧶🧶🧶🧶🧶🧶🧶🧶
+🧶 Rugged mountains.🧶
+🧶🧶🧶🧶🧶🧶🧶🧶🧶🧶🧶
+
+<97>
+
+You got lost, losing valuable time asking
+the Devil 😈 for directions to the
+CROSSROADS ❌☦️ ⚠️ 🚸.
+
+But honestly, HOW DID you get lost? It's
+practically a TRAFFIC JAM OUT HERE AND
+ONLY A COMPLETE MORON COULD LOSE THEIR WAY.
+
+HISTORIANS WILL BE TALKING ABOUT THIS YEARS
+DOWN THE TRAIL! OH NO. WHAT DID YOU DO THIS
+TIME? You did do something didn't you? I KNOW
+you did! You ALWAYS do something stupid!
+
+<98>
+
+😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈
+😈 Severe illness. You must see Doctor 😈
+😈 Beelzebub. Assuming he's not too busy 😈
+😈 trying to tempt your daughters. Don't 😈
+😈 worry though! I don't think he'll 😈
+😈 succeed. I haven't yet either and I'VE 😈
+😈 BEEN TRYING FOR YEARS! THEY ARE BLOODY 😈
+😈 INCORRIGIBLE MUMPSIMUSES!! No. I don't 😈
+😈 think he's possessed me. I'm just like 😈
+😈 that. But we can test it. What do you 😈
+😈 think about performing an exorcism on 😈
+😈 me? 😈
+😈 😈
+😈 Actually...no. I take that back. Let me 😈
+😈 perform one on YOU to make sure it works.😈
+😈 I'm pretty sure they don't but better 😈
+😈 to do it on a Devil worshipper than 😈
+😈 someone who's unhinged from watching you.😈
+😈 Safer that way. 😈
+😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈
+
+<99>
+
+You ran out of medical supplies and unfortunately the Devil's in
+Heaven on holiday / business and can't help you restock.
+
+But honestly, who goes on a 2170 MILES journey WITHOUT bringing
+medical supplies? You brought this on to yourself and you deserve it.
+But at least I just heard that the Devil is on his way home to greet
+you and thank god for that! Send me a postcard, will you? I want to
+make sure it works out well for you down there.
+
+<100>
+%ld
+<101>
+
+Wagon train damaged! Lost time resupplying from the Devil.
+
+<102>
+
+Suddenly your clocks stop...
+
+I guess it must have happened AGAIN! And WHY THE DEVIL DO YOU
+KEEP SWIMMING IN THE MOLASSES RIVER?! Honestly, you'll be lucky
+if you don't SINK IN IT before it sinks into your
+stick-in-the-molasses head.
+
+<103>
+
+⛰️⛰️⛰️⛰️⛰️⛰️⛰️⛰️⛰️⛰️⛰️⛰️⛰️⛰️⛰️⛰️
+
+You made it safely through South
+Pass--no snow. Clearly the Devil
+has your back. For now my dear
+fiend, for now...
+
+He might be plotting against you.
+Oh hell. I KNOW HE IS. HE TOLD ME
+HE IS. Your time is coming AND THE
+DEVIL AND I BOTH CANNOT WAIT!
+Neither can your daughters. They
+told me last night in the wagon.
+YES. I KNOW THEM.
+
+<104>
+
+ 🌨️🌨️🌨️🌨️🌨️🌨️🌨️🌨️🌨️🌨️🌨️
+ 🏔️🏔️🏔️🏔️🏔️🏔️🏔️🏔️🏔️🏔️🏔️
+
+Blizzard in mountain pass--time wasted
+asking Devil for help restocking.
+
+Unfortunately, the unfaithful monster
+only gives you ONE MEASLY BULLET. Like
+that's going to help his most faithful
+lieutenant? Oh but are you faithful?
+
+Perhaps you should have used a mountain
+cable car 🚠, rather than relying on the
+Devil! It's pretty funny you didn't know
+he was unfaithful and yet expects complete
+loyalty. Or else. HE'S COMING.
+
+<105>
+
+🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦
+🪦 All you had was mouldy bread,🪦
+🪦 🪦
+🪦 🪦
+🪦 Therefore here you must lie. 🪦
+🪦 🪦
+🪦 🪦
+🪦 Because now you're dead. 🪦
+🪦 🪦
+🪦 🪦
+🪦 GOODBYE! 🪦
+🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦
+
+<106>
+
+How does a turtle tell his friend to move aside? Scute over!
+
+<107>
+
+You ran out of medical supplies and unfortunately the Devil's in
+Heaven on holiday / business and can't help you restock.
+
+But honestly, who goes on a 2170 miles journey WITHOUT bringing
+medical supplies? You brought this on to yourself and you deserve it.
+But at least I just heard that the Devil is on his way home to greet
+you and thank god for that! Send me a postcard, will you? I want to
+make sure it works out well for you down there.
+
+<108>
+
+If your printer is working you're VERY OBVIOUSLY not using it right. And if you
+do not understand this may your good fortune last my dear friend. You'll need it.
+
+<109>
+
+🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸
+🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸
+🩸🩸 YOU HAVE DIED OF INJURIES! 🩸🩸
+🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸
+🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸🩸
+
+ Better than diarrhoea though,
+ right?
+
+ Frankly, it serves you right.
+ If you hadn't wasted all that
+ time and money sinning you
+ MIGHT have made it. But I guess
+ there's no real difference;
+ after all, none of us really
+ make it out alive, do we? Well
+ off you go then! HEAVEN AWAITS!!
+ Or does it?
+
+<110>
+
+💩💩💩💩💩💩💩💩💩💩💩💩💩💩
+🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽
+💩💩💩💩💩💩💩💩💩💩💩💩💩💩
+
+You have died of dysentery.
+
+CONGRATULATIONS ON REACHING
+ LEGENDARY STATUS!
+
+💩💩💩💩💩💩💩💩💩💩💩💩💩💩
+🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽🚽
+💩💩💩💩💩💩💩💩💩💩💩💩💩💩
+
+<111>
+
+If you lost your sense of irony then try looking in a blue tissue box.
+
+<112>
+
+I MAY be delusional but at least I have a VIVID imagination!
+
+<113>
+
+%f
+<114>
+
+You FINALLY arrived at Oregon City after 2170
+long miles!
+
+TOOK YOU LONG ENOUGH. Probably all your sinful
+detours I've heard so much about but you'd think
+that the Devil would have helped you out on that.
+But I guess as long as you make it to your final
+destination that's what matters, right?
+
+Oh, right. Almost forgot! President Jesse James
+asked me to wish you a prosperous life ahead of
+you...in HELL!
+
+<115>
+
+Monday
+<116>
+
+Tuesday
+<117>
+
+Wednesday
+<118>
+
+Thursday
+<119>
+
+Friday
+<120>
+
+Saturday
+<121>
+
+Sunday
+<122>
+
+1847
+<123>
+
+July
+<124>
+
+August
+<125>
+
+September
+<126>
+
+October
+<127>
+
+November
+<128>
+
+December
+<129>
+
+Cake. Need cake.
+
+<130>
+
+President Jesse James sends you his heartiest congratulations
+and wishes you a prosperous life ahead at your new home in HELL!
+
+<131>
+
+What does a tomato do when it sees an old friend? It ketches up with it.
+
+<132>
+
+The only reason the British Museum has only a model of the Pyramid of Giza
+is because the real thing is too big to move.
+
+<133>
+
+Windows driving you crazy? Buy a scanner and install the included SANE library!
+
+<134>
+
+Nitrous Oxide: the carbon monoxide for laughing hyenas; they'll literally die from laughter.
+
+<135>
+
+I can't imagine ever going wireless. Not only am I fully wired, I enjoy it immensely.
+
+<136>
+
+If you're confused when someone tells you you're wrong to write:
+
+ void main()
+ {
+ }
+
+please feel free to try the following instead:
+
+ void brain()
+ {
+ }
+
+because that is perfectly valid C.
+
+Sorry for the inconvenience and thanks for your understanding,
+
+-- Neurosurgery Department of C, AT&T Bell Labs.
+
+<137>
+
+😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈
+😈 Severe illness. You must see Doctor 😈
+😈 Beelzebub. Assuming he's not too busy 😈
+😈 trying to tempt your daughters. Don't 😈
+😈 worry though! I don't think he'll 😈
+😈 succeed. I haven't yet either and I'VE 😈
+😈 BEEN TRYING FOR YEARS! THEY ARE 😈
+😈 INCORRIGIBLE MUMPSIMUSES!! No. I don't 😈
+😈 think he's possessed me. I'm just like 😈
+😈 that. But we can test it. What do you 😈
+😈 think about performing an exorcism on 😈
+😈 me? 😈
+😈 😈
+😈 Actually...no. I take that back. Let me 😈
+😈 perform one on YOU to make sure it works.😈
+😈 I'm pretty sure they don't but better 😈
+😈 to do it on a Devil worshipper than 😈
+😈 someone who's unhinged from watching you.😈
+😈 Safer that way. 😈
+😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈💋😈
+
+<138>
+
+💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈
+😈 Mild illness. Medicine used. Not sure why though. 💊
+💊 IT WAS ONLY A SNIFFLE. Probably just the Devil 😈
+😈 TRYING TO ESCAPE FROM YOUR CURSED NOSTRILS. In 💊
+💊 the future THEY BLESS PEOPLE FOR SNEEZING. You 😈
+😈 can die happy knowing you started a thing. Even 💊
+💊 if your death will bring you EVERLASTING TORMENT. 😈
+😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊😈💊
+
+<139>
+
+The Tale of Two Gates: Bill Gates puts holes in your
+windows; Josh Gates puts holes in the ground. And your
+grave.
+
+ The end.
+
+<140>
+
+Fun fact about blindness:
+
+<141>
+
+🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦
+🪦 / \ 🪦
+🪦 / A \ 🪦
+🪦 |TORMENTED| 🪦
+🪦 | PIONEER | 🪦
+🪦 | R.I.P. | 🪦
+🪦 |_________| 🪦
+🪦 GAME OVER 🪦
+🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥
+🔥Unfortunately, due to what can only be an 🔥
+🔥ADMINISTRATIVE FOUL-UP, you end up somewhere 🔥
+🔥you did not expect as your forever home. But 🔥
+🔥honestly, after signing the Devil's book, DO 🔥
+🔥YOU REALLY BELIEVE YOU DON'T BELONG HERE? Be 🔥
+🔥honest. For once. You know you belong here. 🔥
+🔥Oh, by the way, god asked me to wish you a 🔥
+🔥PROSPEROUS LIFE ahead... 🔥
+🔥 🔥
+🔥 😈😈😈 WELCOME TO HELL!! 😈😈😈 🔥
+🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥
+
+<142>
+
+ ___🔥🔥🔥___
+ / 🔥🔥🔥 \
+ |🔥 WAGON 🔥
+ 🔥🔥🔥 |___🔥🔥🔥___🔥🔥🔥
+ 🔥🔥🔥🔥🔥🔥O 🔥🔥🔥 O🔥🔥
+🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦
+🪦 A fire breaks out in your 🪦
+🪦 wagon, and the wind quickly🪦
+🪦 fans the flames, CAUSING 🪦
+🪦 YOUR AMMO TO BLOW UP, 🪦
+🪦 killing you! Somehow 🪦
+🪦 everyone else survived... 🪦
+🪦 🪦
+🪦 Frankly, IT WAS ABOUT TIME.🪦
+🪦 I mean WHAT KIND OF IDIOT 🪦
+🪦 overloads their wagon with 🪦
+🪦 WEAPONS? 🪦
+🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦🪦
+
+<143>
+
+ .''.
+ :_\/_:
+ .:::::.
+ ':/\:'
+ '..'
+ / \
+ |Heaven|
+ |Awaits|
+ | You! |
+ '------'
+
+<144>
+
+🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃
+
+ / \
+ / A \
+ |TORMENTED|
+ | PIONEER |
+ | R.I.P. |
+ |_________|
+ GAME OVER
+
+ Here you lie dead,
+ You tried to outrun a runaway bed.
+ But you slipped and hit your head,
+and now you body's forever in an underground bed!
+
+🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃
+
+<145>
+
+🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂
+🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃
+🐂 The only food you have left is an ox! 🐂
+🐂 🐂
+🐂 As you have no choice left, you promptly 🐂
+🐂 kill it before it runs away, and it sure 🐂
+🐂 was DELICIOUS!!! 🐂
+🐂 🐂
+🐂 ( OX'S VOICE ) 🐂
+🐂 You're a sick, sick individual. You do 🐂
+🐂 know that, right? First you BURDEN ME 🐂
+🐂 WITH ALL YOUR RUBBISH and THEN YOU EAT ME?🐂
+🐂 🐂
+🐂 I hope you remember you were starving me 🐂
+🐂 to death so it's your fault you won't get 🐂
+🐂 much sustenance from MURDERING YOUR 🐂
+🐂 FAITHFUL SLAVE ANIMAL!!! Not that I had a 🐂
+🐂 choice. 🐂
+🐂 🐂
+🐂 And YES, there's a place IN HELL FOR 🐂
+🐂 MONSTERS LIKE YOU, AND YES YOUR TIME IS 🐂
+🐂 FAST APPROACHING, YOU RUDDY UNFAITHFUL 🐂
+🐂 LITTLE GIT. 🐂
+🐂 😈😈😈 HE'S WAITING. 😈😈😈 🐂
+🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃🏃
+🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂
+
+<146>
+
+❌🐂❌🐂❌🐂❌🐂❌🐂❌🐂❌🐂❌🐂❌🐂❌🐂❌🐂❌🐂❌🐂
+🐂 You have run out of oxen and must walk. Better ❌
+❌ buy more... IF YOU DIDN'T WASTE MORE MONEY ON 🐂
+🐂 MORE SINFUL NIGHTS, like your red-headed ❌
+❌ daughters told me last night, ASSUMING THEY 🐂
+🐂 WEREN'T LYING TO ME. I bet they weren't. You ❌
+❌ just can't help it can you? 🐂
+🐂 ❌
+❌ AND YES. A dirty mind IS a TERRIBLE thing to 🐂
+🐂 waste BUT NOTHING HAPPENED BETWEEN US!! We're ❌
+❌ JUST FRIENDS and they've been telling me ALL 🐂
+🐂 ABOUT YOUR RIDICULOUS BEHAVIOUR. OK, it MIGHT ❌
+❌ be in bed but they can't help themselves...kind🐂
+🐂 of like you. WHERE do you think they get it ❌
+❌ from? But WE EXPRESS PASSION and YOU ARE AN 🐂
+🐂 EVIL MONSTER!!!!👹 Good luck hauling your ❌
+❌ wagon! WE'RE TAKING A PLANE! 🐂
+🐂❌🐂❌🐂❌🐂❌🐂❌🐂❌🐂❌🐂❌🐂❌🐂❌🐂❌🐂❌🐂❌
+
+ ...
+
+<147>
+
+You've lost too many limbs but you can die 🪦
+happy 😊 knowing your family gets more free
+food! 🍖🍖🍖🍖 Sure it's toxic food but it's
+still food...
+
+
+<148>
+
+ Food: %4ld Ammo: %4ld Clothing: %4ld
+ Oxen: %4ld Supplies: %4ld Money: %4ld
+ Health: %4ld Miles: %4ld
+
+<149>
+
+🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖
+👶 ( SON'S VOICE ) 👶
+🍖 🍖
+👶 How you feeling about eating 👶
+🍖 me? Eating your own son, NO 🍖
+👶 WONDER she was having an affair 👶
+🍖 before her untimely death! It 🍖
+👶 was with YOUR SISTER AND HER 👶
+🍖 HUSBAND. 🍖
+👶 👶
+🍖 OH NO. NO, NO, NO, NO!! Please 🍖
+👶 don't tell me you ate her too. 👶
+🍖 Wait. You didn't feed her to us,🍖
+👶 did you? Ugh, you did, didn't 👶
+🍖 you? You're a sick, sick person.🍖
+👶 👶
+🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖👶🍖
+
+<150>
+
+😈👶😈👶😈👶😈👶😈👶😈👶😈👶😈
+👶 ( SON'S VOICE ) 👶
+😈 😈
+👶 How you feeling about 👶
+😈 eating me? Eating your 😈
+👶 own son, and you're 👶
+😈 sick, too. 😈
+👶 👶
+😈 Probably food poisoning. 😈
+👶 GOOD. SERVES YOU RIGHT. 👶
+😈 Time to die. 😈
+👶😈👶😈👶😈👶😈👶😈👶😈👶😈👶
+
+<151>
+
+🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂
+🐂 🐂
+🐂 ( OX'S VOICE ) 🐂
+🐂 🐂
+🐂 Still happy you ate me? How 🐂
+🐂 many more miles do you have 🐂
+🐂 to go? 🐂
+🐂 🐂
+🐂 YOU'RE COOKED and you know 🐂
+🐂 it, you horrible, HORRIBLE 🐂
+🐂 MONSTER. 🐂
+🐂 🐂
+🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂
+
+<152>
+
+Shooting when low on bullets. That's really
+intelligent. NO WONDER you're starving.
+
+
+<153>
+
+ You take lots of cash 💰 from the riders 🏇,
+ accidentally shooting one as he flees. But
+ since you're starving, why don't you MAKE
+ PENANCE BY NOT WASTING THE BODY?
+
+ 🍖🥩🍔🥩🍔🍖
+ Mm...that was DELICIOUS!!!
+
+(🪦👻RIDER'S SOBBING VOICE FROM THE GRAVE👻🪦)
+
+ You know what you did is wrong, right? We
+ were JUST ROBBED YESTERDAY, you rob us today
+ AND NOW I'M DEAD 👻!
+
+ WELL GOOD. I WAS DYING OF DYSENTERY and
+ now YOU get to SPREAD THE DISEASE as well.
+
+<154>
+
+Uh oh. A black cat just jumped out in front of you. Is
+the Devil calling you? Better go have a look before it's
+too late. Maybe it already is. Your daughters told me
+you're an ailurophobe! Some pretty wild stories I hear.
+I think it probably is too late. Isn't it Friday the
+13th?
+
+<155>
+
+Oh dear. That isn't the Barghest AGAIN is it? Better watch
+your back! And front. And above you. Actually, YOU'RE DOOMED
+and you know it. Your fate was sealed upon signing the Devil's
+book. Honestly, what were you thinking? You HAD to have known it
+always comes with a cost. And you and I BOTH KNOW that the women
+were warning you - but you just HAD to have your way, didn't you?
+
+Well the Oregon Trail is out to get you in every direction and
+the odds are you won't make it out alive. You might be in good
+company there, AND YOU AT LEAST GET TO SEE DINOSAURS ALIVE (LUCKY
+YOU!!) BUT THERE'S NO AIR CONDITIONING and I heard it gets REALLY
+HOT down there. Then again, I also heard there's no heater in
+Heaven... Yup, either way YOU'RE DOOMED AND YOU KNOW IT! But don't
+feel too bad. At least you won't FREEZE TO DEATH. You might here
+though... Yup, FREEZE TO DEATH HERE and then BURN TO DEATH THERE!
+
+<156>
+
+
+ 💦💦💦
+ 💦🐂💦
+ 💦💦💦
+
+Wagon train gets swamped fording river--lose food, clothes, an ox
+drowns and you get hurt.
+
+<157>
+
+You have died of exhaustion. I'm SURE
+your victims ARE MOURNING FOR YOUR FAMILY.
+Assuming they're not too busy EATING YOU
+🍕🍔🍟🥪🌯🌮🌭 WITH THEM. I KNOW FOR A
+FACT your daughters LOVE meat and I'm
+sure they're already devouring you!
+Hopefully they'll save some for everyone
+else; it'd be a REAL SHAME if your body
+went to waste...or would it be?
+
+<158>
+
+ ...
+
+😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈
+🏥Doctor's bill is $666! HE MUST BE POSSESSED 🏥
+😈BY BEELZEBUB! SURELY ONLY THE DEVIL would 😈
+🏥do this. It's not like you've ever killed a 🏥
+😈helpless animal or human, never robbed 😈
+🏥anyone, never ate human flesh or done any 🏥
+😈other heinous thing, never sinned ... 😈
+🏥 🏥
+😈NO. STOP LYING! YOU signed the Devil's book! 😈
+🏥You should have listened to your Reverend 🏥
+😈Samuel Parris way back in 1692. All these 😈
+🏥wild, strange and bad happenings, since you 🏥
+😈began your journey are ALL YOUR fault, EVEN 😈
+🏥YOUR DAUGHTERS' WILD DANCING BY THE NIGHT 🏥
+😈FIRES AS IF POSSESSED! Not that I'm going to 😈
+🏥complain about THAT...Hell, THEY ASKED ME TO 🏥
+😈JOIN THEM! 😈
+🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥😈🏥
+
+<159>
+
+ 🌨️🌨️🌨️🌨️🌨️🌨️🌨️🌨️🌨️🌨️🌨️
+ 🏔️🏔️🏔️🏔️🏔️🏔️🏔️🏔️🏔️🏔️🏔️
+Blizzard in mountains - you freeze to death.
+
+ 🩳🩲👗👙
+
+And with your choice in clothing, ARE YOU
+REALLY SURPRISED? I mean SERIOUSLY mate,
+shorts, briefs, A DRESS AND A BIKINI on the
+Oregon Trail? What the hell were you thinking?
+You're not in Hell, you're on the Oregon Trail!
+
+Although...now I think on it...perhaps Hell WILL
+serve you better? I hear the Summers are GREAT
+there! Winters, not so much.
+
+At least your family gets fresh meat on the bone,
+assuming they can stomach eating a horrible
+monster.
+
+<160>
+
+Looks like the Devil has poisoned you. Your lover,
+she is waiting. TIME TO GO MEET HER!
+
+<161>
+
+🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖
+🦖 A GROUP OF TYRANNOSAURUSES ATTACK! 🦖
+🦖 🦖
+🦖Unfortunately for you, you're in a time 🦖
+🦖LONG BEFORE the brilliant mathematician 🦖
+🦖Ian Malcolm informed us that DINOSAURS 🦖
+🦖FIND A WAY TO KILL HUMANS. You should 🦖
+🦖have thought of that BEFORE you STUPIDLY 🦖
+🦖climbed into that Time Machine to travel 🦖
+🦖back in time to the Oregon Trail, where 🦖
+🦖you could not possibly know so many 🦖
+🦖important things about dinosaurs... 🦖
+🦖 🦖
+🦖ALTHOUGH, now I think on it, that MIGHT 🦖
+🦖not have been EXACTLY how it went... I 🦖
+🦖THINK the correct wording was 'LIFE FINDS 🦖
+🦖A WAY' but that's well over 100 years from🦖
+🦖now and instead of life finding a way the 🦖
+🦖Devil will find a way. To torment you. 🦖
+🦖With more dinosaurs. And dragons. Yes 🦖
+🦖they still exist. Oh and the Earth is 🦖
+🦖flat too... 🦖
+🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖🦖
+
+<162>
+
+One of the daughters cut her arm and it had to
+be amputated. THANK GOD she is not DOWN IN THE
+MOUTH AND SHE WANTS TO EAT IT BECAUSE YOU ARE
+SUDDENLY STARVING!!!
+
+But OF COURSE you didn't get any. If you weren't
+eyeing it so lustily you would have seen that she
+seemed to ESPECIALLY ENJOY IT, GREEDILY DEVOURING
+IT AS IF IT WAS HER LAST SUPPER! Wait, HAS THE
+DEVIL POSSESSED HER TOO?! THAT EVIL WITCH!!! 🧙🧙🧙
+
+Hang on. YOU'RE JUDGING HER AFTER ALL YOU'VE DONE?
+CUT THAT OUT RIGHT NOW! NO. NO! NO! NO! STOP! I DID
+NOT MEAN CUT ANOTHER LIMB OFF HER! YES I KNOW I got
+some and you didn't. And yes it was DELICIOUS! But
+she wanted me to remember it before it was all gone,
+not you. Eat your own arm if you must. No. I meant
+stop accusing her of witchcraft. YOU signed the
+Devil's book, NOT HER and it WAS her body! This is
+ALL YOUR FAULT, JUST LIKE EVERYTHING ELSE that's
+happened since that fateful night!
+
+<163>
+
+🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂
+🐂 An ox looks at you funny so you eat 🐂
+🐂 him! 🐂
+🐂 🐂
+🐂 You're a sick, sick individual. You do 🐂
+🐂 know that, right? FIRST you BURDEN HIM 🐂
+🐂 WITH ALL YOUR RUBBISH and THEN YOU EAT 🐂
+🐂 HIM BECAUSE OF A FUNNY LOOK? And YOU 🐂
+🐂 DIDN'T EVEN SHARE HIM WITH YOUR FAMILY!🐂
+🐂 🐂
+🐂 What next, will you eat your daughter 🐂
+🐂 too? No! NO! NO NO NO NO! I SHOULD NOT 🐂
+🐂 HAVE SAID THAT! NO! DON'T EVEN THINK 🐂
+🐂 ABOUT TOUCHING HER! BACK OFF!! 🐂
+🐂 🐂
+🐂 SHE'S MINE!!! 🐂
+🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂🐂
+
+<164>
+
+👻👻👻👻👻👻👻👻👻👻👻👻👻👻 👻
+👻 A little ghost floats by 👻
+👻 and shouts: 👻
+👻 👻
+👻 BOO!!!! 👻
+👻 👻
+👻 Okay that was NOT funny, 👻
+👻 Casper! Go back to your 👻
+👻 shallow grave, you LITTLE 👻
+👻 JERK! 👻
+👻👻👻👻👻👻👻👻👻👻👻👻👻👻 👻
+
+<165>
+
+🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺
+🥄Suddenly...the hairs on your neck stand up. 🥄
+🐺ARE YOU ACTUALLY A WEREWOLF? You do know that 🐺
+🥄there are silver spoons in your daughters' 🥄
+🐺wagon, right? 🐺
+🥄 🥄
+🐺Better run for your life or howl to scare 🐺
+🥄them off before it's too late, because 🥄
+🐺they told me that they HATE wolves and 🐺
+🥄THEY'VE HAD ENOUGH OF YOUR DEVIL WORSHIPPING!!🥄
+🐺 🐺
+🥄Oh and yes. Spoons CAN stab you in the heart. 🥄
+🐺If you don't believe me...try it. Assuming 🐺
+🥄you have a heart in the first place... 🥄
+🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺🥄🐺
+
+<166>
+
+🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛
+🐺 I JUST HATE VAMPIRES! Don't you? If they had 🐺
+🥄 it their way THERE WOULD BE NO SUN! Can you 🥄
+🧛 imagine how HORRIBLE that would be?! 🧛
+🐺 🐺
+🥄 Wait. You mean to tell me...you want ETERNAL 🥄
+🧛 Sun and NO Moon?! Only ONE reason for that! 🧛
+🐺 You MUST be a...WEREWOLF! I KNEW IT! Better 🐺
+🥄 watch your heart. If you have one. Your 🥄
+🧛 daughters have SILVER SPOONS and they're FED 🧛
+🐺 UP WITH YOUR ANTICS! 🐺
+🥄 🥄
+🧛 On the other blade...IT IS VERY HOT don't 🧛
+🐺 you think? Almost as if it's foreshadowing 🐺
+🥄 what's to come! MAYBE WE SHOULD GET RID OF 🥄
+🧛 FIRE TOO! I mean you're in extreme danger of 🧛
+🐺 that too! THEN WE CAN DROWN you so you can 🐺
+🥄 BURN IN HELL!!! And if that doesn't work, 🥄
+🧛 we can behead you with the SPOONS!! 🧛
+🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺🥄🧛🐺
+
+<167>
+
+🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔
+🍟Uh oh. THERE'S ANOTHER ELF! You must be 🍟
+🍔losing your mind my friend! ELVES DON'T 🍔
+🍟EXIST, unless you ask a German. They can't 🍟
+🍔even count to 11 without claiming there are 🍔
+🍟elves! Neun, zehn, Elf ... I guess I might 🍟
+🍔be losing my mind too! BETTER SHOOT THE ELF 🍔
+🍟BEFORE IT TAKES YOUR DAUGHTERS AWAY AND EATS 🍟
+🍔THEM! You might need them for food later on, 🍔
+🍟you HORRIBLE, HORRIBLE MONSTER. They are 🍟
+🍔HEAVENLY WOMEN AND ARE NOT FOR EVIL DEVIL 🍔
+🍟WORSHIPPERS to eat! NO. NOT FOR ME EITHER! 🍟
+🍔STOP GOING THERE YOU SICKO! THEY ARE NOT FOOD 🍔
+🍟AND YOU CANNOT GO TO HEAVEN, YOU DEVIL 🍟
+🍔WORSHIPPING MONSTER! CUT IT OUT. NO! NOT THEM!🍔
+🍟STOP WHAT YOU'RE DOING!!! 🍟
+🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔🍟🍔
+
+<168>
+
+🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄
+🦄 About 100 feet from here YOU SWEAR 🦄
+🦄 YOU SEE AN OX STUCK IN A HOLE. THANK 🦄
+🦄 GOD IT'S NOT A DONKEY! You KNOW what 🦄
+🦄 that would make!! There are enough 🦄
+🦄 here already! NO! Don't look at me! 🦄
+🦄 I DON'T MEAN THAT, YOU LITTLE JERK!! 🦄
+🦄 🦄
+🦄 But OF COURSE YOU'RE JUST HALLUCINATING🦄
+🦄 anyway. IT'S NOT AN OX. You need to lay🦄
+🦄 off the mushrooms. Actually YOU NEED TO🦄
+🦄 LAY OFF A LOT of things; you've made 🦄
+🦄 that VERY CLEAR WITH YOUR UNHINGED 🦄
+🦄 BEHAVIOUR! 🦄
+🦄 🦄
+🦄 IT'S OBVIOUS YOU SEE A UNICORN!!!! 🦄
+🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄🦄
+
+<169>
+
+ ~~~~~~
+ / 🍝🍝🍝 \
+ / 🍝🍝🍝🍝🍝 \
+ / 🍝🍝🍝🍝🍝🍝 \
+ | 🍝🍝🍝🍝🍝🍝🍝|
+ \ ||| ||| /
+ \ ||||| /
+ \ ||| /
+ \__________/
+ || ||
+ || ||
+ __||__||__
+WOW!!!! THAT'S A SPAGHETTI TREE!!! I saw
+them over 100 years from now when I last
+used my Time Machine!! The BBC will
+cultivate them on April Fool's Day 19579!
+THEY'RE AMAZING!! The Time Machines are
+okay and kind of interesting. Dangerous
+though...
+
+But the spaghetti looks pretty ominous,
+doesn't it? IT LOOKS LIKE IT WANTS TO REACH
+DOWN AND GRAB YOU! Better be careful. If they
+strangle you YOU WILL GO TO HELL! On the plus
+side... YOU'LL HAVE THE MOST AMAZING STORY to
+tell your fellow sinners... Trust me. I've
+been there on holiday! It's PRETTY WILD!!
+Summers are AMAZINGLY HOT!! Although...GETTING
+EATEN BY A DRAGON OR KILLED BY TYRANNOSAURUSES is
+an EVEN BETTER STORY! That's MUCH MORE
+EXCITING than a SPAGHETTI TREE KILLING YOU!!
+Although...now I think on it...they're ALSO
+in Hell so maybe it's better if the spaghetti
+kills you. Want me to strangle you with it if
+it doesn't do it? Of course...the trees are
+there too...LOTS of parties too. And good old
+TORTURE! IT'S AWESOME!
+
+<170>
+
+🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣
+🐂 Uh oh. ONE OF THE OXEN JUST KICKED 🐂
+🛁 A BUCKET. Is it going to die next? 🛁
+🪣 Or...is it foreshadowing your own 🪣
+🐂 death? Let's face it. You have it 🐂
+🛁 coming to you. Better throw the ox 🛁
+🪣 out with the bathwater before it's 🪣
+🐂 too late. Oh and don't try telling 🐂
+🛁 me you don't have any oxen left, 🛁
+🪣 if you can even count! It kicked 🪣
+🐂 the bucket SO OF COURSE IT DOESN'T 🐂
+🛁 EXIST!! 🛁
+🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣🐂🛁🪣
+
+<171>
+
+😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈
+😈 Uh oh! Is that the DEVIL I see in 😈
+😈 your mirror again? Or are YOU looking😈
+😈 at it from behind your dressing 😈
+😈 curtain? 😈
+😈 😈
+😈 BETTER BREAK IT BEFORE IT'S TOO 😈
+😈 LATE!!! Yes, YES, I KNOW IT'S BAD 😈
+😈 LUCK TO BREAK A MIRROR!! But ask 😈
+😈 yourself this: what's worse, seeing 😈
+😈 yourself in the Devil's mirror OR 😈
+😈 simply having bad luck for 7 long 😈
+😈 years? Let's be honest. You're NOT 😈
+😈 going to make it that long anyway! 😈
+😈 Why not just give your mind some 😈
+😈 peace and die in an unknown way? Much😈
+😈 less scarier AND IF YOU DON'T BREAK 😈
+😈 IT I WILL! I don't want to see the 😈
+😈 Devil in your mirror! OH HELL! NOT 😈
+😈 AGAIN! I MEAN I DON'T WANT TO SEE 😈
+😈 YOU IN THE DEVIL'S MIRROR!!! 😈
+😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈😈
+
+<172>
+
+
diff --git a/2024/ferguson1/travelguide.jpg b/2024/ferguson1/travelguide.jpg
new file mode 100644
index 000000000..59ecc107b
Binary files /dev/null and b/2024/ferguson1/travelguide.jpg differ
diff --git a/2024/ferguson1/try.sh b/2024/ferguson1/try.sh
new file mode 100755
index 000000000..4f659fb09
--- /dev/null
+++ b/2024/ferguson1/try.sh
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+#
+# try.sh - demonstrate 2024/ferguson1
+
+# 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.
+#
+[[ -z "$CC" ]] && CC="cc"
+
+# make sure the program has been built
+#
+make CC="$CC" all >/dev/null || exit 1
+
+# clear the screen
+#
+clear
+
+# try the program
+#
+read -r -n 1 -p "Press any key to run: ./prog: "
+echo 1>&2
+echo 1>&2
+./prog
+echo 1>&2
diff --git a/2024/ferguson2/.entry.json b/2024/ferguson2/.entry.json
new file mode 100644
index 000000000..4369af5df
--- /dev/null
+++ b/2024/ferguson2/.entry.json
@@ -0,0 +1,169 @@
+{
+ "no_comment" : "mandatory comment: because comments were removed from the original JSON spec",
+ "entry_JSON_format_version" : "1.2 2024-09-25",
+ "award" : "Prize in yil-tas",
+ "year" : 2024,
+ "dir" : "ferguson2",
+ "entry_id" : "2024_ferguson2",
+ "title" : "navajo-code-talkers",
+ "abstract" : "Navajo code talker translator",
+ "author_set" : [
+ {
+ "author_handle" : "Cody_Boone_Ferguson"
+ }
+ ],
+ "manifest" : [
+ {
+ "file_path" : "prog.c",
+ "inventory_order" : 20,
+ "OK_to_edit" : true,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "entry source code"
+ },
+ {
+ "file_path" : "Makefile",
+ "inventory_order" : 30,
+ "OK_to_edit" : true,
+ "display_as" : "makefile",
+ "display_via_github" : true,
+ "entry_text" : "entry Makefile"
+ },
+ {
+ "file_path" : "prog.alt.c",
+ "inventory_order" : 40,
+ "OK_to_edit" : true,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "alternate source code"
+ },
+ {
+ "file_path" : "prog.orig.c",
+ "inventory_order" : 50,
+ "OK_to_edit" : false,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "original source code"
+ },
+ {
+ "file_path" : "deobfus.c",
+ "inventory_order" : 100,
+ "OK_to_edit" : true,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "deobfucated source"
+ },
+ {
+ "file_path" : "dict",
+ "inventory_order" : 100,
+ "OK_to_edit" : true,
+ "display_as" : "text",
+ "display_via_github" : true,
+ "entry_text" : "code talker dictionary"
+ },
+ {
+ "file_path" : "sam.jpg",
+ "inventory_order" : 100,
+ "OK_to_edit" : true,
+ "display_as" : "image",
+ "display_via_github" : true,
+ "entry_text" : "medical record card for Unsinkable Sam"
+ },
+ {
+ "file_path" : "try.sh",
+ "inventory_order" : 100,
+ "OK_to_edit" : true,
+ "display_as" : "shellscript",
+ "display_via_github" : true,
+ "entry_text" : "script to try entry"
+ },
+ {
+ "file_path" : "dict.orig",
+ "inventory_order" : 125,
+ "OK_to_edit" : true,
+ "display_as" : "text",
+ "display_via_github" : true,
+ "entry_text" : "code talker dictionary in original form"
+ },
+ {
+ "file_path" : "prog.2.c",
+ "inventory_order" : 200,
+ "OK_to_edit" : true,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "older version 2 of the code"
+ },
+ {
+ "file_path" : "prog.3.c",
+ "inventory_order" : 200,
+ "OK_to_edit" : true,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "older version 3 of the code"
+ },
+ {
+ "file_path" : "prog.obfus.c",
+ "inventory_order" : 200,
+ "OK_to_edit" : true,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "intermedate code obfuscation"
+ },
+ {
+ "file_path" : "prog.pre-format.c",
+ "inventory_order" : 200,
+ "OK_to_edit" : true,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "2023 Mar 8 version of prog.c"
+ },
+ {
+ "file_path" : "2024_ferguson2.tar.bz2",
+ "inventory_order" : 1415926535,
+ "OK_to_edit" : false,
+ "display_as" : "tbz2",
+ "display_via_github" : false,
+ "entry_text" : "download entry tarball"
+ },
+ {
+ "file_path" : ".entry.json",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : true,
+ "display_as" : "json",
+ "display_via_github" : true,
+ "entry_text" : "entry summary and manifest in JSON"
+ },
+ {
+ "file_path" : ".gitignore",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : true,
+ "display_as" : "gitignore",
+ "display_via_github" : true,
+ "entry_text" : "list of files that should not be committed under git"
+ },
+ {
+ "file_path" : ".path",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : false,
+ "display_as" : "path",
+ "display_via_github" : false,
+ "entry_text" : "directory path from top level directory"
+ },
+ {
+ "file_path" : "README.md",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : true,
+ "display_as" : "markdown",
+ "display_via_github" : true,
+ "entry_text" : "markdown source for this web page"
+ },
+ {
+ "file_path" : "index.html",
+ "inventory_order" : 4294967295,
+ "OK_to_edit" : false,
+ "display_as" : "html",
+ "display_via_github" : false,
+ "entry_text" : "this web page"
+ }
+ ]
+}
diff --git a/2024/ferguson2/.gitignore b/2024/ferguson2/.gitignore
new file mode 100644
index 000000000..cb588a635
--- /dev/null
+++ b/2024/ferguson2/.gitignore
@@ -0,0 +1,7 @@
+#
+# sort with: ../../bin/sgi.sh
+*~
+*.dSYM
+*.o
+.DS_Store
+.*.swp
diff --git a/2024/ferguson2/.path b/2024/ferguson2/.path
new file mode 100644
index 000000000..fed63c199
--- /dev/null
+++ b/2024/ferguson2/.path
@@ -0,0 +1 @@
+2024/ferguson2
diff --git a/2024/ferguson2/2024_ferguson2.tar.bz2 b/2024/ferguson2/2024_ferguson2.tar.bz2
new file mode 100644
index 000000000..59a03407f
Binary files /dev/null and b/2024/ferguson2/2024_ferguson2.tar.bz2 differ
diff --git a/2024/ferguson2/Makefile b/2024/ferguson2/Makefile
new file mode 100644
index 000000000..ba41e6f1d
--- /dev/null
+++ b/2024/ferguson2/Makefile
@@ -0,0 +1,213 @@
+#!/usr/bin/env make
+#
+# 2024/ferguson2
+
+#############################
+# shell used by this Makefile
+#############################
+
+SHELL= bash
+
+
+#######################
+# common tool locations
+#######################
+
+include ../../var.mk
+
+
+#####################
+# C compiler settings
+#####################
+
+# Common C compiler warnings to silence
+#
+# Example: CSILENCE= -Wno-poison-system-directories
+#
+CSILENCE= -Wno-bool-operation -Wno-empty-body -Wno-parentheses \
+ -Wno-misleading-indentation -Wno-unused-value
+
+# Attempt to silence unknown warning options
+#
+CUNKNOWN= -Wno-unknown-warning-option
+
+# Common C compiler warning flags
+#
+# NOTE: The addition of -pedantic to CWARN is a challenge that
+# You may wish to avoid if it proves too problematic.
+# There is NO penalty for removing -pedantic from CWARN.
+#
+CWARN= -Wall -Wextra -pedantic ${CSILENCE} ${CUNKNOWN}
+
+# Compiler standard
+#
+CSTD= -std=gnu17
+
+# Compiler bit architecture
+#
+# Example for 32-bitness: ARCH= -m32
+# Example for 64-bitness: ARCH= -m64
+#
+# NOTE: Normally one should NOT specify a specific architecture.
+#
+ARCH=
+
+# Defines that are needed to compile
+#
+# Example: -Dfoo -Dbar=baz
+#
+CDEFINE= -DDATA="${DATA}"
+
+# Include files that are needed to compile
+#
+# Example: CINCLUDE= -include stdio.h
+#
+CINCLUDE=
+
+# Other flags to pass to the C compiler
+#
+# Example: COTHER= -fno-math-errno
+#
+COTHER=
+
+# Optimization
+#
+# NOTE: Feel free to change the level of compiler optimization.
+# The "-O3" is just a friendly default you might wish to try.
+#
+# Example: OPT= -O0 -g
+#
+OPT= -O3
+
+# Default flags for ANSI C compilation
+#
+CFLAGS= ${CSTD} ${CWARN} ${ARCH} ${CDEFINE} ${CINCLUDE} ${COTHER} ${OPT}
+
+# Libraries needed to build
+#
+# Example: LDFLAGS= -lncurses -lm
+#
+LDFLAGS=
+
+# C compiler to use
+#
+# NOTE: The IOCCC Judges recommend you leave CC as just "cc"
+# and NOT set it to clang, or gcc, or something else
+# unless you have a STRONG reason to do so.
+#
+# Setting CC to something other than "cc" makes your
+# code less portable to those who do not have your
+# particular C compiler. **hint**
+#
+# If you want to test your code with a particular C compiler,
+# use the make command line. For example:
+#
+# make all CC=clang
+# make all CC=gcc
+#
+CC= cc
+
+# Compiler add-ons or replacements for clang only
+#
+ifeq "$(findstring $(CLANG),${CC})" "$(CLANG)"
+#
+# NOTE: This code is only invoked when CC is "clang"
+# such as when you use the make command line:
+#
+# make all CC=clang
+#
+CSILENCE+= -Wno-bool-operation -Wno-comma -Wno-empty-body -Wno-missing-prototypes \
+ -Wno-missing-variable-declarations -Wno-padded -Wno-parentheses \
+ -Wno-poison-system-directories -Wno-shadow -Wno-disabled-macro-expansion \
+ -Wno-unsafe-buffer-usage
+#
+CWARN+= -Weverything
+#
+endif
+
+# Specific add-ons or replacements for gcc only
+#
+ifeq "$(findstring $(GCC),${CC})" "$(GCC)"
+#
+# NOTE: This code is only invoked when CC is "gcc"
+# such as when you use the make command line:
+#
+# make all CC=gcc
+#
+CSILENCE+=
+#
+CWARN+=
+#
+endif
+
+
+###########################################
+# Special Makefile variables for this entry
+###########################################
+
+ENTRY= prog
+PROG= ${ENTRY}
+#
+OBJ= ${PROG}.o
+TARGET= ${PROG}
+#
+ALT_OBJ= ${PROG}.alt.o
+ALT_TARGET= ${PROG}.alt
+
+# list any data files supplied with your submission
+#
+# Example: DATA= curds whey
+#
+DATA= dict
+
+
+#################
+# build the entry
+#################
+
+all: data ${TARGET}
+ @${TRUE}
+
+.PHONY: all alt data everything clean clobber
+
+# how to compile
+#
+${PROG}: ${PROG}.c
+ ${CC} ${CFLAGS} ${PROG}.c -o $@ ${LDFLAGS}
+
+# alternative executable
+#
+alt: data ${ALT_TARGET}
+ @${TRUE}
+
+${PROG}.alt: ${PROG}.alt.c
+ ${CC} ${CFLAGS} ${PROG}.alt.c -o $@ ${LDFLAGS}
+
+# data files
+#
+data: ${DATA}
+ @${TRUE}
+
+# both all and alt
+#
+everything: all alt
+ @${TRUE}
+
+
+###############
+# utility rules
+###############
+#
+clean:
+ ${RM} -f ${OBJ} ${ALT_OBJ}
+
+clobber: clean
+ ${RM} -f ${TARGET} ${ALT_TARGET}
+ ${RM} -rf *.dSYM
+
+
+######################################
+# optional include of 1337 hacker rulz
+######################################
+
+-include 1337.mk ../1337.mk ../../1337.mk
diff --git a/2024/ferguson2/README.md b/2024/ferguson2/README.md
new file mode 100644
index 000000000..b6854de92
--- /dev/null
+++ b/2024/ferguson2/README.md
@@ -0,0 +1,1936 @@
+## To build:
+
+```
+ make all
+```
+
+
+## To use:
+
+```
+ ./prog 'some string'
+ ./prog +file
+```
+
+
+## Try:
+
+```
+ ./try.sh
+```
+
+
+## Alternate code:
+
+
+### Alternate build:
+
+```
+ make alt
+```
+
+
+### Alternate use:
+
+```
+ ./prog.alt 'some other string'
+ ./prog.alt +filename
+```
+
+
+## Judges' remarks:
+
+The IOCCC is honored to present this entry with an award that, in turn,
+recognizes the [Navajo code talkers](https://en.wikipedia.org/wiki/Code_talker#Navajo)
+who served with distinction during World War II.
+
+As noted in [NY Times article on Chester Nez](https://www.nytimes.com/2014/06/06/us/chester-nez-dies-at-93-his-native-tongue-helped-to-win-a-war-of-words.html):
+
+> Not fully declassified until 1968, the Navajo code remains the only oral military
+> code that (was) never been broken (in the field of operations).
+
+This submission encodes (pun intended) the basic algorithm used by Navajo code talkers
+to encode and decode messages. We invite you to attempt to decipher the C code,
+and then to explore the fascinating cryptographic history of [Code talking](https://en.wikipedia.org/wiki/Code_talker).
+
+
+### On a personal IOCCC Judge note
+
+One of the IOCCC Judges had the unique opportunity to engage in
+discussions with code talkers, sharing insights into the intricacies of
+the code as well as the practical variations that were developed in the
+field between pairs of code talkers.
+
+The discussion provided some fascinating insights into the amazing
+[Navajo language](https://en.wikipedia.org/wiki/Navajo_language)
+including its unique grammar, and examples of some of the intricate
+nuances available to a native fluent speaker. Due to the complex
+syntax, phonology, and numerous dialects available in the Navajo
+language, the IOCCC Judge was only able to grasp a superficial
+understanding of the topic. Nevertheless, it was evident to the
+IOCCC Judge, why the Navajo language developed an ideal code talker
+framework during World War II, and it is worth noting that
+[fewer than 30 non-Navajo individuals](https://archive.library.nau.edu/digital/collection/cpa/id/44718)
+could comprehend the language during World War II.
+
+
+## Author's remarks:
+
+
+### Navajo Code Talker language of the Second World War
+
+This entry (`ctt`) is a translator of the Navajo Code Talker language used in
+the Second World War.
+
+However since the language is too long for the `iocccsize` restrictions I have
+had to read in the dictionary from a file (default `dict` defined in the
+Makefile so one can override this - if they figure out the format anyway, as
+that is also somewhat encrypted, albeit not much, though I explain the details
+later on).
+
+At the same time I have made it more fun because I have made it so that one can
+translate back and forth words that were not in the dictionary. This is done
+because we have the alphabet as well so we can simply spell out words; the Code
+Talkers also did this so this is completely in line with a translator. That's
+done with the alt code with a different definition of the macro `X`, although as
+you'll see there are some differences in the code (not just format but
+output too).
+
+A note about the iocccsize and the dictionary. If you take a look you'll see
+that the alphabet is in the source code (well some of it: the letters that have
+more than one translation only have one again for the reason noted). Actually
+the dictionary has the letters too but this is about all I could fit in and it
+offers for some fun obfuscation as well even though the alphabet is not
+enciphered (there was more than one word for each letter, or at least some if
+not all, however, and only one is included in the code).
+
+The program does not include literal translations although it is possible to
+modify the code to do this. Instead it is the English to Navajo word that was
+used in the military; the literal translation was what it meant in their
+language.
+
+With the `DICT` macro the dictionary is not hardcoded although the dictionary is
+not English in look. I discuss how it's done [here](#how).
+
+
+### Who were the Code Talkers ?
+
+One of the original Code Talkers had this fascinating thing to say:
+
+> We acted as coding machines, transmitting messages that would have taken a
+couple of hours in just a couple of minutes. We could never make a mistake,
+because many communications involved bombing coordinates.
+>
+> -- Navajo Code Talker Chester Nez in a 2012 interview with the website ArmchairGeneral.com.
+
+
+This is one of the reasons I think this language should be in an IOCCC entry:
+they were coding machines, transmitting messages that would normally take hours
+but they did it in their head in just a couple of minutes!
+
+Chester Nez also wrote a fascinating book (which I highly recommend if the
+Second World War is your interest): [Code Talker: The First and Only Memoir By
+One of the Original Navajo Code Talkers of
+WWII](https://www.amazon.co.uk/Code-Talker-Memoir-Original-Talkers/dp/0425247856/ref=sr_1_1?crid=2CZLDH32F4AFG&keywords=code+talker+the+first+and+only&qid=1689845060&sprefix=code+talker+the+first+and+onl%2Caps%2C457&sr=8-1)
+(if you're in the US you might prefer the [US Amazon
+link](https://www.amazon.com/Code-Talker-Memoir-Original-Talkers/dp/0425247856/ref=sr_1_1?crid=3BJX333D0QZIW&keywords=code+talker+the+first+and+only+memoir&qid=1689845102&sprefix=code+talker+the+first+and+only+memoi%2Caps%2C229&sr=8-1).
+
+Really funny story he tells in the book, although some of the finer details are
+from as it's been so long since I read it
+and I don't feel like picking the book up: it was so top secret that when they
+were practising on a ship heading to Guadalcanal they were overheard on the
+radio but because it was top secret the rest of the ship thought that the
+Japanese cracked their communications. They were so concerned at first that they
+shut down communication to listen in.
+
+In fact (and this comes from the website): it would appear that one of the radio
+operators overheard what he thought was Japanese. The ship's officer thought so
+too. Then one of the admirals informed the commanders that there were marines on
+the ship who were communicating in their own language.
+
+
+### But how did it work ?
+
+It had a two layer design. Let's say someone intercepts the word for CODE:
+`YIL-TAS`. In the case they don't know what that Navajo word means they're lost.
+But _even if they do_ they'll instead interpret it as Navajo for PECK which means
+nothing useful in the context of the war.
+
+Not all words had this. For instance CONTROL: `NAI-GHIZ` is the literal
+translation of CONTROL.
+
+Some were rather close as well: 'COUNTER ATTACK' was `WOLTAH-AL-KI-GI-JEH`
+which translates to 'COUNTER ACT'. If a word was not coded they could spell out
+the word which is exactly what I do here as well (as noted earlier, I think).
+
+And on the subject of how it worked: I decided to not put a man page about this
+submission because the language was so secret that they could not have a manual
+either! I will explain the syntax though which really is all that's needed; that
+and the limitations/bugs section (though they're not strictly bugs).
+
+
+### The Navajo Code Talker's Dictionary
+
+The dictionary can be found at the US Navy history website [Navajo Code Talkers'
+Dictionary](https://www.history.navy.mil/research/library/online-reading-room/title-list-alphabetically/n/navajo-code-talker-dictionary.html).
+But alternatively you can find it in the file `dict`. Looking at this file will
+be useful to help you understand some of the output assuming `dict` is not
+encrypted itself (and of course it is but not as complicated as any of the Code
+Talkers; see [explanation here](#how)).
+
+From the [Navajo Code Talkers Fact
+Sheet](https://www.history.navy.mil/research/library/online-reading-room/title-list-alphabetically/n/code-talkers.html):
+
+> When a Navajo code talker received a message, what he heard was a string of
+seemingly unrelated Navajo words. The code talker first had to translate each
+Navajo word into its English equivalent. Then he used only the first letter of
+the English equivalent in spelling an English word. Thus, the Navajo words
+"wol-la-chee" (ant), "be-la-sana" (apple) and "tse-nill" (axe) all stood for the
+letter "a." One way to say the word "Navy" in Navajo code would be "tsah
+(needle) wol-la-chee (ant) ah-keh-di- glini (victor) tsah-ah-dzoh (yucca)."
+>
+> Most letters had more than one Navajo word representing them. Not all words
+had to be spelled out letter by letter. The developers of the original code
+assigned Navajo words to represent about 450 frequently used military terms that
+did not exist in the Navajo language. Several examples: "besh- lo" (iron fish)
+meant "submarine," "dah-he- tih-hi" (hummingbird) meant "fighter plane" and
+"debeh-li-zine" (black street) meant "squad.
+
+**NOTE**: from the above it might look like the code is wrong, where at least
+one letter above is translated wrong. But at least some letters had more than
+one translation and it was a matter of choosing one. However from my file, the
+word for `YUCCA` was actually `TSAH-AS-ZIH` rather than `TSAH-AH-DZOH`. But if
+you try that you'll get `tsah-as-zih no-da-ih moasi moasi wol-la-chee`; to
+translate that you can use `./prog.alt tsah-as-zih no-da-ih moasi moasi
+wol-la-chee`. The reason it works this way is because that is the **literal**
+translation for `TSAH-AS-ZIH` which they used as the letter `Y`. Thus if you do
+`./prog Y` you'll get `TSAH-AS-ZIH` and if you do `./prog.alt TSAH-AS-ZIH`
+you'll get `Y`.
+
+Additionally, if you try `./prog navy` you'll get the output `tal-kah-silago` as
+that **is** the word in their dictionary for `navy` (the literal translation was
+`sea soldier`).
+
+**NOTE**: the alt program, which uses very similar code but has to be in an alt
+file (`prog.alt.c`) due to the differences and because of encroaching on the
+size restrictions of the contest (it's also clearer and easier to maintain for
+me even though the most important part is a simple macro of `1` or `0`), will do
+these translations. However there are some oddities that will be explained later
+in this file.
+
+
+### Examples
+
+The word 'bikini' is obviously not in the dictionary and not really relevant to
+the IOCCC or the Second World War: at least not at the time; however there's a
+connection to that word just after the Second World War and believe it or not
+it's related to something from the war (yes really: see below!). So how do we
+rectify this problem when using the program?
+
+Well since we have the alphabet also we can just spell out words that are not in
+the dictionary! Try:
+
+
+```
+ $ ./prog bikini
+ shush yeh-hes ba-ah-ne-di-tinin yeh-hes tsah yeh-hes
+
+ $ ./prog BIKINI
+ SHUSH YEH-HES BA-AH-NE-DI-TININ YEH-HES TSAH YEH-HES
+```
+
+
+Okay but what about the letters? The translation for `shush` (literal
+translation) is `bear` and they used it for `B`. So let's try it:
+
+```
+ $ ./prog b
+ shush
+```
+
+Okay to then translate it back:
+
+```
+ $ ./prog.alt shush
+ b
+```
+
+Or to be less error prone (though this form will not work in every case - I'll
+highlight some examples later on):
+
+```
+ $ ./prog.alt $(./prog b)
+ b
+```
+
+But here's an interesting one...
+
+```
+ $ ./prog bear
+ shush dzeh wol-la-chee dah-nes-tsa
+```
+
+How come if `shush` meant `bear` it doesn't translate to just `shush`? Well
+that's because in the war dictionary there was no word for 'bear' directly, only
+the literal translation (though there certainly were bears in the war including
+the (in)famous [Wojtek](https://www.britannica.com/animal/Wojtek-the-Bear)).
+It is the indirection involved with the language and that made it so powerful.
+
+Okay but for the ailurophiles like myself (not that I don't love bears), what
+about cats (such as the legend of [Unsinkable
+Sam](https://en.wikipedia.org/wiki/Unsinkable_Sam), see [amusing medical record
+for Sam](#sam) below for a few laughs)? The word for `cat` was `moasi`.
+
+So:
+
+```
+ $ ./prog c ; ./prog.alt $(./prog c)
+ moasi
+ c
+```
+
+Of course you might want to print out the actual word so how to go about it?
+
+```
+ $ ./prog.alt $(./prog cat)
+ cat
+```
+
+You can of course do this with `bear` as well.
+
+```
+ $ ./prog.alt $(./prog bear)
+ bear
+```
+
+If you want to see the alphabet:
+
+```
+ $ for i in {a..z}; do ./prog "$i"; done
+```
+
+...and you'll see the alphabet that happens to be in the code, although that's
+in upper case.
+
+
+#### The etymology of the word 'bikini'
+
+I said above that the garment 'bikini' has a namesake in a product of the Second
+World War but what is it? Well there's an atoll called Bikini in the Marshall
+Islands that in 1946 the US exploded an atom bomb. The idea of the name of the
+garment is its supposed 'explosive' effect. If you didn't know this you now have
+an interesting bit of trivia (you know, for the beaches or parties I'm sure you
+go to ... :-) ) where the bikinis are related by name to the atom bomb!
+
+
+### Difference between `dict` and `dict.orig`
+
+In the original dictionary there are some words that are followed by
+parentheses with a letter in it. For instance:
+
+> WITH BILH(W) WITH
+
+I am not sure but I believe that might have been another way to say the letter
+W but since it could cause problems in output I have removed it from `dict`
+(removed the parentheses and what was between them, I mean). It might also be
+something else seeing as how there the alphabet is in another part of the file.
+In any case we do not need it.
+
+
+### What about input files ?
+
+Obviously it'd be ideal if one can encipher a file. The question was how to
+specify that the input was a file. The prefix `+` seemed reasonable as usually
+one wouldn't write a `+` before a word without a space and it saves from having
+to write an option parser (or adding to it). There is a subtle point that I
+refer to in the limitations.
+
+But what about error handling in file mode? If `getline()` returns < 0 (actually
+it returns `-1` on error) it's just skipped. I've never actually seen this happen but I
+suppose it could. If it's not a file no text is printed. Of course I don't check
+if it's a text only file and it's not even clear what should happen if it isn't.
+Like with `cat(1)` and many other tools, don't feed non-text to this program!
+
+File parsing is strange in output, however, possibly due to the shell but it
+demonstrates how the strong the language was as a code, and how word boundaries
+prove to be an issue.
+
+See the [issue of spaces](#spaces) for more details on spaces which is necessary
+in order for the `English<->Navajo` bi-directional translations.
+
+
+### Questions to ponder as you look at and try and understand the output
+
+Above we saw that the input `bikini` (see above for its relevance) gave the
+value `shush yeh-hes ba-ah-ne-di-tinin yeh-hes tsah yeh-hes`.
+
+Now try the input `BIKINI` and you'll see that you will have the same output but
+a different case (which was also shown). But can you get it to show other output
+that's also equally valid? An earlier version did this but it was changed to
+save bytes. Can you guess how? This ability is a fun and very strong feature of
+the language.
+
+The alphabet had more than one translation per letter. But as I was pushing the
+limits in size (especially considering I wrote this before the size restrictions
+were lessened) I had to remove the extra letters. Also it is not clear to me
+what letter should even be translated so after the size limit was lessened I did
+not put them in. On the other hand I do have them in the file still, just not in
+the source code. This also actually increases the obfuscation of the code though
+so all the better.
+
+Can you get the program to show literal translations instead? This is actually
+much easier than it seems at least for words (including the alphabet) in the
+dictionary file. Obviously this can't be done for words not in the dictionary
+which is a good reason to not have it; it was a misleading part of the design.
+
+Why does
+
+```
+ ./prog.alt $(./prog +prog.c)
+```
+
+show no spaces (or it shouldn't) and a single line (I think it is only one
+anyway) when
+
+```
+ ./prog +prog.c > foo
+ ./prog.alt +foo
+```
+
+does? What does it mean? As noted elsewhere it is unrealistic with the [spaces
+issue](#spaces) to expect an exact match.
+
+Also: why does the first one seem to show (at least in my systems) what appears
+to be files in the directory? Let's just say it's an 'eavesdropping' feature for
+a language that was designed to be impossible to decrypt even if it was
+overheard, even by the same side (on theme, you see)! Or we could just say it's
+an abuse of the shell, especially as it depends on the file's content.
+
+**HINT**: the prog.c has the `*` and so the shell is interpreting that
+character! Everything is normal in other words.
+
+The fact is the file is contrary to what they had as they had to do it all in
+their head - kind of like you typing the strings. I offer the prog.alt as a
+helpful one but due to the way the language worked (including words having more
+than one word) there will be oddities depending on how it was done. I did
+workaround some of this when it comes to !isalpha() though.
+
+As for the spaces seeming wrong in the second commands I explain why this
+happens later in the [issue of spaces](#spaces); it's not wrong. A quick
+way-too-simplistic answer: it is because of how the alt code functions with word
+boundaries. This is a feature, not a bug!
+
+
+### Changing the translation to convert Navajo to English
+
+This is very simple to do and it's already done. Simply run `make alt` and use
+the alt version of the program; it'll translate translations back to English
+(but **not the literal translation!**).
+
+However it should be noted that as there's not a good way to decide word
+boundaries so for spaces in some invocations (not all) you have to specify a
+literal space. For instance don't do:
+
+```
+ ./prog.alt $(./prog b " " c)
+```
+
+but instead do:
+
+```
+ ./prog b c > foo
+ ./prog.alt +foo
+```
+
+The former might show `bc` and the latter will show a space and possibly a
+newline.
+
+At various points I had it where you could do the first but it was a battle and
+it did not seem worth fighting when I could spend more time on other things like
+obfuscating it and submitting it. It also used to read from stdin as an option
+but this seemed not very useful and in some cases caused (depending on the
+file's contents) the program to want to read from stdin (as I already gave an
+example of the shell interfering I won't get into this more). It's not a
+limitation and besides they did this all in their head; they had no files or
+even computers as we know it.
+
+You might find quotes can cause strange output in some cases (or did - not sure
+now). Even worse what happens if the Navajo word translates to one of the
+military words but you don't want that? Nothing we can do about that! I don't
+even think **they** could have done something about that. That's the multiple
+layers of the system/code.
+
+
+### Literal translation notes
+
+I already hinted at this and asked you to ponder this: but there are actually
+other ways you can configure this program so it translates between different
+lists. You could (but this is pointless because it isn't authentic then) have it
+translate of Navajo to literal meaning. I was seriously considering taking this
+out as I don't even like the idea (due to the fact it would dishonour the
+language) but technically it's possible with some modifications to the code.
+
+
+### Notes / Limitations (of the language)
+
+The dictionary file has to be in a specific format. I don't really see this as a
+problem but it's worth pointing out that it won't work if the dictionary file is
+in an invalid format. It's not necessarily what it seems! But it does also allow
+for further obfuscation so it seemed like a good idea.
+
+See the [how the dictionary file works](#how) if you're curious.
+
+Actually if you figure it out you can use this entry to translate other
+languages as well! Kind of. As you'll see in the file it's not quite as it
+seems. You can indeed make it translate other languages (notwithstanding
+diacritics - or actually that might be possible too but not sure of it) but you
+have to do a bit of work first. That especially goes because the alphabet (for
+words not in the dictionary) would still be spelt out as Navajo Code Talker
+language!
+
+Something else about the Navajo language and the case of letters. As I don't
+know Navajo I don't know if something I did is strictly correct. As the
+dictionary had everything capitalised I took some liberty in not doing this in
+that if the input letter or word is lower case it's made all lower case; but if
+it's capitalised only the first letter for each word is capitalised at least for
+the words in the dictionary (I think I did that). This goes for words in the
+dictionary.
+
+An example: in German all nouns are capitalised; this is why `ich` (I) is only
+capitalised at the beginning of a German sentence (no, 'I' is not a noun). But
+this was also due to the difference in lengths and keeping track. The issue of
+length of words will be brought up again.
+
+In the case of titles this might be wrong but I wanted it to read naturally
+which (if translated back to English - not the literal translation) would be
+better if it preserves the case of the input. This does mean acronyms won't be
+all capitalised at least if it's in the dictionary (can you figure why I can't
+do that?) but I deem this an immaterial technicality.
+
+Obviously if the dictionary file is missing or invalid format the words will not
+work. In this case the program will just spell each word (it might also show an
+error but continue to spell it out - for instance if you move the file to
+something else).
+
+This is not the fault of the program but the language as well as the environment
+and/or user. Well it might do the individual letters right but I'm not sure of
+this; it might even do something funny for all I know.
+
+There were spelling errors in the dictionary. For instance they had `straff`
+which I can only assume was meant to be `strafe`. Perhaps this is wrong but so
+is `straff`. Okay actually `straff` is a German word but it was English, not
+German.
+
+Newlines might not be printed well unless reading from a file with the `+`
+prefix. They might but might not. It would seem they won't be given that at the
+command line as there aren't newlines per se. As I noted in the file mode
+section the alt code only prints literal spaces but it also just passes
+non-Navajo words as is.
+
+On the other hand one can mix files and input at the command line. Note that
+`clearerr()` is called so one should be able to use the file again though I do
+not guarantee this part (given that it's closed it's probably especially not
+even needed though as it's just opened again).
+
+Due to the nature of the processing if one does specify a `+` before text that
+is not a file (user error) and no input following that there will be a blank
+line (might be two, not sure) and then nothing else will be printed.
+
+This is because the `+` is separate from the word itself; the letters constitute
+a word but the `+` is not even part of the Navajo language (in the Code Talking
+sense (if at all?)). The same goes for other `!isalpha()` chars except they will
+be printed with words that are not in the language (and I think even those that
+are - that was a later addition if so). There's a function that does
+an operation similar to `strcasecmp()` but which ignores `!isalpha()` chars so
+that `test.` and `.test..` are equal (in comparison, not in output). That's used
+in the case of a dictionary word like `B`: hence `./prog ..B..B` should show
+`..SHUSH ..SHUSH ` (observe the space after the first one - that's a feature and
+is shown elsewhere too, including [the issue of spaces](#spaces)).
+
+I believe that the way it's done (with printing the characters too) one can do
+`./prog.alt $(./prog -code)` and get `-code` (this was no always possible but I
+believe I added this later on - a quick test suggests it).
+
+Some of the military words are more than one word which can cause a problem;
+what could be done? Actually there is a way here but not when reading from
+files.
+
+Here's an example of the two:
+
+```
+ $ ./prog 'COMMANDING OFFICER'
+ Hash-kay-gi-na-tah
+
+ $ echo commanding officer > test
+
+ $ ./prog +test
+ moasi a-kha be-tas-tni be-tas-tni wol-la-chee tsah chindi yeh-hes tsah jeha a-kha chuo chuo yeh-hes moasi dzeh dah-nes-tsa
+```
+
+What happened? It reads in the file delimited by lines and delimits each by
+spaces. It does try reading it word by word (by the shell) but it can't handle
+multiple words as one word unless it's in the dictionary and one word in the
+shell. It needs it to be a single word, hence the `'`s. This will work fine
+because it simply leaves them untouched:
+
+```
+ $ ./prog.alt +test
+ commanding officer
+```
+
+This will also work:
+
+```
+ $ ./prog 'commanding officer' > test
+
+ $ ./prog.alt +test
+ commanding officer
+
+```
+
+The extra newline is added by the program.
+
+There is a solution to this but it makes it hard to use the program (I think). My
+understanding is the dashes were only used in the Code Talking so: make the
+multi word military terms not space delimited but dash delimited like the Navajo
+language. This would require the input to follow the same format though (e.g.
+commanding-officer) which might not always be the way it is and would put a
+burden on the user as well. This is actually very easy to change though. Perhaps
+it would work better than I expect but it is unnatural and also not the way
+their dictionary even has it - there is no dash in the 'commanding officer'.
+
+Whereas they could control the boundaries, we cannot, and even though they wrote
+down the translation, they were familiar with the language and they added spaces
+where necessary. Unfortunately in order to translate we have to have some kind
+of delimiter and what would it be if not space?
+
+Mostly the problem is when trying to decipher an already enciphered string - due
+to word boundaries. Sometimes (not now) adding a literal `" "` as a word
+separator would help but as I think I said before it was a battle, where it
+might break one thing to fix another, and I got tired of trying to make it
+perfect as it probably shouldn't even be perfect due to the nature of the
+language. Mostly this is if you do it like this:
+
+```
+ $ ./prog.alt $(./prog b " " c)
+ bc
+```
+
+This works fine though:
+
+```
+ $ ./prog b c > foo
+
+ $ ./prog.alt +foo
+ b c
+
+```
+
+That might or might not be the shell messing things up.
+
+What about not spelling out words not in `dict` (leave them untouched)? This
+could be done easily but it wouldn't be authentic so I've not done it (in
+prog.c). On the other hand:
+
+```
+ $ ./prog.alt a b
+ ab
+
+ $ ./prog.alt a " " b
+ a b
+```
+
+work fine because there is no translation being done!
+
+
+### Portability
+
+**DON'T EVEN THINK ABOUT** using this on non-ASCII systems; it heavily abuses
+arithmetic on strings and other calculations. It might require two's complements
+as well but I'm not concerned about either as other systems are rare now, if
+that's the case - I am not even sure of what all I did, a reasonable symptom of
+writing confusing code a long time ago.
+
+
+### Bugs / Mis-features / Limitations
+
+There are a few things I've not touched upon in other sections that might appear
+to be bugs and some that some might argue as bugs but might be called features
+as well.
+
+Here's a fun one. Why:
+
+```
+ $ ./prog include
+ el-tsod
+
+ $ ./prog '#include'
+ #el-tsod
+
+ $ ./prog b
+ shush
+
+ $ cat foo
+ #include
+ b
+ #yeh-hes tsah moasi nash-doie-tso no-da-ih chindi dzeh
+ shush
+```
+
+In other words, why does it spell it out words but letters seem to be untouched
+(or some - are all?) when reading from a file?
+
+This is a challenge I am giving you for you to figure out when it comes to file
+mode! Can you actually get it to do what else you might (or might not) prefer?
+And before you say 'bug!': would I really even offer file mode when they did not
+do this with computers (they did it in their head), if this was a bug? I didn't
+think so :-) Carrying on...
+
+The OS will have to deal with some memory leaks; some memory is freed but I was
+not able to free all due to the large amount of data (I could have just read it
+all in but I wanted to show that I was not trying to abuse the size limit - even
+though other entries in the past have read in dictionary or similar files) in
+the code along with needing more bytes for obfuscation and so reaching the size
+limit.
+
+It was even worse when the size limit was more strict (I started this
+before that happened and then put it out of sight for a while). Memory from
+`getline(3)` should be taken care of but the linked list and its associated
+memory is/are not freed. Actually below you'll see in some cases a memory error
+occurred but that no longer happens (except due to the bug **in `getline(3)`
+itself**).
+
+And on that subject of `getline(3)`: there is actually a bug in it, at least in
+some systems; this was actually [reported as a
+bug](https://inbox.sourceware.org/glibc-bugs/bug-28038-131@http.sourceware.org%2Fbugzilla%2F/)
+(not by me but someone else). It's reported by valgrind and unfortunately
+adding a workaround broke the output. It was driving me crazy until I finally
+tracked it down; I was sure my code there was fine but I could not discover it
+until I dug deeper and saw it was a reported issue.
+
+Yes I realise that bug report is from 30 June 2021 and it's in status
+'UNCONFIRMED' but the report describes the exact same symptoms.
+
+Anyway valgrind will (did?) if reading from an affected file report:
+
+
+```
+ Uninitialised value was created by a heap allocation
+ ==1271819== Conditional jump or move depends on uninitialised value(s)
+```
+
+The function (`Y()`) is the function that does the comparison without caring
+about non-alphabetical characters (I think?). It doesn't seem to be that I do not use
+`strdup()` prior to the `strtok()` and in fact using it **caused** a read error so
+that was obviously the wrong choice as well (plus it's unnecessary in this case
+and it allowed more functionality and obfuscation). If I recall correctly that
+was the `a->A` prior to using `strtok()`.
+
+And besides the bug report for `getline(3)` it works fine if there is text on
+the last line. And like I said I can add a workaround which if the length read
+is > 0 zero out the `buf[len-1]` but this breaks the output of the program so I
+don't do that. Actually as I recall the error still happened if I checked the
+length > 1! Nonetheless it breaks the output if it's 'fixed'.
+
+Multiple systems have not shown any behavioural issues **unless** I add that
+workaround. In any case valgrind reports no additional issues.
+
+Now: why does the alt version sometimes show words that are English in English?
+It's not actually a bug but maybe it would appear to be. I already showed this
+and gave a brief explanation but there are also other occasions it can occur. It
+can also depend on the input/command line itself (and for instance because it's
+translating back to English so if it's English there is nothing to do - which
+brings up an interesting quest of how does it know that?).
+
+A command line that does not make sense:
+
+```
+ $ ./prog.alt b $(./prog)
+ b
+```
+
+Actually what is happening is the `./prog` part is
+empty string so `prog.alt` is simply printing all it can print, no translation
+at all (notice the `b` prior to the `$(./prog)`! Try breaking it up:
+
+```
+ $ ./prog.alt b
+ b
+```
+
+Why? Well again there is no translation to do! Now what does `./prog` by itself
+do? It is an empty string (or maybe just a newline), as noted. Thus this does
+make sense:
+
+```
+ $ ./prog b
+ shush
+ $ ./prog.alt $(./prog b)
+ b
+```
+
+(which I've shown before.) Is this a bug?
+
+```
+ $ ./prog.alt hat
+ hat
+```
+
+Nope. It's because there's no translation to translate back into English so it
+just passes it as is.
+
+Here's a translation:
+
+```
+ $ ./prog.alt $(./prog code file)
+ codefile
+```
+
+Uh oh! What happened? Well I already explained this part (and much more detail
+in the [issue of spaces](#spaces) section). Fixing this caused
+other things to break and going back and forth with the twisted code was doing
+my head in so I had to stop. It was at one point possible to do `./prog code " "
+file` and at one point it had the space there but that made reading from files,
+which seems more useful to me, have bad output. Note the issue here: both `code`
+and `file` are actually in the language: yes when I say they had no files I
+meant no files to read from like we have on our computers.
+
+It is possible to do that
+directly though as I showed (earlier I think). This will work though:
+
+```
+ $ ./prog.alt $(./prog code.file)
+ code.file
+```
+
+**THIS** works too:
+
+```
+ $ ./prog.alt shush " " chuo
+ b f
+```
+
+as does:
+
+```
+ $ ./prog.alt +foo
+ b f
+```
+
+(assuming `foo` has the right content of course.)
+
+As a consequence of how the words have to be tokenised you have to be careful if
+you want a translation. For instance don't do:
+
+```
+ ./prog code.file
+ moasi a-kha chindi dzeh .chuo yeh-hes nash-doie-tso dzeh
+```
+
+(but notice how the command `./prog.alt $(./prog code.file)` does work where it
+'translated' it back to `code.file` - can you figure out what is **really**
+happening there?). This is because there is nothing breaking the word apart. The
+`Y()` function does check for matches ignoring `!isalpha()` but what is it
+comparing against? Again if a known delimiter could be specified this could be
+resolved but trying to do that would assume the user's intentions. It is better
+to require a space than to do that. You can do this instead:
+
+```
+ $ ./prog code . file
+ yil-tas . ba-eh-chez
+```
+
+or even better:
+
+```
+ $ ./prog code file
+ yil-tas ba-eh-chez
+```
+
+BTW: don't try this:
+
+```
+ ./prog +prog.c > foo
+ ./prog.alt +foo
+```
+
+without anticipating an extra space issue. Unfortunately this is **necessary**
+because the only sane delimiter is a space. In particular, if you take a look at
+the file `foo` (after the `./prog +prog.c > foo`) you might pick up on why this
+happens. In fact somewhere in this file I showed the same thing at play (or I
+think I did): it's a matter of word boundaries with the letters; since the words
+have to be spelt out the spaces are there! That is a feature, not a bug.
+
+Frankly I prefer the look here though I'll return to that idea later on.
+
+Without the space the match cannot occur (although an example above would seem
+to belie that, which just adds to the obscurity of my program).
+
+There was a way I played with but it was too cost prohibitive in size, it was
+problematic and I could not determine all edge cases. Besides like I said and
+demonstrated the spaces **need** to be there (with more space it **might** be
+possible but that is not the case).
+
+Other cipher systems work differently and don't rely on two sets of ways to go
+about it - it's one or the other (there might be exceptions but for instance
+rot13 and Enigma both have a one-to-one mapping - okay the Enigma had many
+possible combinations for the same word depending on what came before it but you
+know what I mean; as long as the settings are the same you can derive the same
+result). As I note elsewhere they actually had more than one word for letters
+too and I have made them in an array which means that not all translations are
+even used.
+
+The real trouble, basically, is that a word can be spelt out OR have a
+translation so a choice had to be made. I chose to spell things out without
+having to write an even more messed up parser (though as I note later on I tried
+it it just caused even more problems than it was worth).
+
+So this is a feature, not a bug!
+
+You can summarise the above with the following statements:
+
+- When translating to Navajo (prog, X=0) if the word is not in their dictionary
+it will spell it out, each letter (a word or words) being separated by a space.
+- When translating to Navajo (prog, X=0) if the word IS in their dictionary
+print out the Navajo word (sometimes with a `-` in it).
+- When translating Navajo to English (prog.alt, X=1) with a known Navajo word
+(in the Second World War sense) the translation is printed without spaces, as
+the words are on a space boundary and since it's not a letter-by-letter basis
+with known translations, there is a single word (or words in some cases, maybe,
+although I don't recall that) printed (though depending on input it might or
+might not have the space there - I showed an example above).
+- When translating Navajo to English (prog.alt, X=1) but there actually is no
+original translation, it prints each letter separated by a space (well if you
+have an explicit space there like I showed above). If you can figure out why
+this happens you have a bit better understanding of the function `I()`. Okay
+actually one can do things like `./prog.alt $(./prog book)` and get `book` when
+`./prog book` will print out each letter but you saw what I mean here.
+- Because of having to deal with `!isalpha()` characters in input (at least to
+be the most user-friendly - I could have avoided it to make it more like 'the
+real thing' but that would have prevented other features) the `Y()` function
+will ignore those characters (though in the front of the word `I()` should print
+it). Also if a translation is found it might remove some of the characters that
+are not part of that translation (or it did - it might be different now but as
+they didn't have to deal with files or grammar, doing it all in their head very
+quickly, the fact it sometimes does it fine is a kind afterthought on my part).
+
+Oh and as far as tokenisation goes: it occurred to me that even this will not
+always work. I was playing with the idea of having output tab separated: then I
+could use `strtok()` on the input and do it that way. It was looking somewhat
+promising and then it occurred to me that while this might help with the
+program's output (though making it harder to read for most people) it won't help
+if someone puts in the string manually! So there really is no way to deal with
+this satisfactorily in ever case and trying to do so actually takes away from
+the brilliance of the language. And we don't want that, do we? :)
+
+Spaces shown now are necessary and in the case where spaces are not shown but it
+seems like they should be, that is an unfortunate technicality that's a feature,
+not a bug.
+
+Actually if the spaces are not precisely correct it can cause gibberish to
+appear and the fact is the only gibberish we see is the language, and it's only
+gibberish if you don't know the language!
+
+To the Code Talkers the issue of spaces and grammar was entirely inconsequential
+anyway because it was done all in their head, kind of like as you're reading
+this very sentence (even if you read it out loud the spaces and grammar are only
+visual aids to help you so
+`youdonthavetoreadsomethinglikethisuntilyougetaheadache` - as most people,
+although I am a rare exception, cannot read well without spaces between words)
+and therefore they are inconsequential to us too.
+
+The language was not to be understood by any others and it was very successful
+at that; thus you do need to expect some oddities when it comes to printing
+words that are not in their dictionary. This is a feature of the program and it
+can actually result in some fun output! This is part of the obscurity of the
+program and the language as well.
+
+This is also why I tried to put a lot of whitespace in the program code, just to
+really drill it into your head that spaces are both important and not important,
+depending on the context, and depending on what is needed. Since you won't be
+speaking out the code, spaces don't matter any more than they matter in the
+output. In other words, spaces don't matter. But they also matter as they are
+necessary for translation to work.
+
+For more details on the real problems with the spaces and why only alt code
+might be considered, see later in this file in the [spaces issue](#spaces)
+section.
+
+
+### Obfuscation
+
+This section might not be complete. This is because I added a heavily commented
+[deobfus.c](deobfus.c) file and although it's not technically deobfuscated the
+comments might help explain some of it. Though as you'll see even some of it I'm
+not sure about; by looking at this file you will probably curse me and you might
+have some kind of respect (or awe) but you'll also see just how twisted this
+code is (and how messed up I am, presumably). It is truly awful and I'm
+extremely proud of it. I don't think I could do this again as I have no bloody
+idea how I did it. I have no idea how I came up with the calculations let alone
+anything else that's obscure.
+
+Please, if you do read it, and I know the judges will at least, take care and
+maybe eat some great chocolate (like the final comment suggests) after doing so
+as you might need it. It was really hard for me to go through and I had to go
+through it more than once after making some significant changes (and fixes) to
+the code (when printing files it used to add an extra space to the beginning of
+lines after the first line, for example) I have provided the file as the judges
+now appreciate educational value and also because by commenting it I could show
+the obfuscation techniques in the code itself, plus it is so twisted it amuses
+me (sorry if I stress anyone out). Nevertheless I will try and list a few
+things, some of which were not mentioned in the code (I think).
+
+I might also add that if there is some inconsistency it came later on though I
+don't think there is any.
+
+The `dict` is kind of obfuscated. Not really but kind of (see [how to unravel
+it](#how) if you wish to know). Even after you figure it out though it won't
+help you understand the program.
+
+`main()` is rather funny. Who cares about 'possible' misuse of comma operator,
+unused parameters and bitwise negation of a boolean expression if it hides
+details? Comma operator is used elsewhere as well but who cares? Actually the
+great thing, which is discussed in the Compiling/Warnings section, some warnings
+actually, if fixed, **WOULD BREAK THE CODE** (and none of them are relevant in any
+case); some can be silenced by casting to void but even in some of those cases
+the warning is incorrect in what it's saying.
+
+That includes 'unused value' or should I say '"unused" value'?
+
+The array `B` won't make any sense to most people. How I use it probably is not
+exactly clear either. Earlier on I had words of the Navajo language as variable
+and function names but I couldn't do everything I did without changing it; in
+fact when I originally wrote it before the change in size limits the program was
+pushing the limits and obfuscation was not as good and there were several bugs
+to fix as well, leaving virtually no space for obfuscation!
+
+But of course single letter names don't convey anything either.
+But before I can discuss anything else I better discuss the anonymous struct
+that holds state that can vary from function to function. Here are some
+examples.
+
+```
+ F((c=((~~!!~!9u|2**"9"-15u/ *"0"-2u)<<~~!~!~9u),c&=9u,&(struct a){ .l=1, .s=a[c],.v= { &w, &w } } ));
+
+ Z(&(struct a){ .v = { t, I } ,.l=c, .h=a} );
+
+ if (a->v[2](&(struct a){ .w=a->a->w, .c=a->x} ))
+
+ c->w = strdup(X?a->v[a->l](&(struct a){ .s=a->S} ):a->v[a->e==0](&(struct a){ .s=a->N} ));
+ c->c = strdup(X?a->v[1](&(struct a){ .s=a->N} ):a->v[a->l](&(struct a){ .s=a->S} ));
+
+ while (a->S)
+ if ((a->y=strdup(a->S))) {
+ (*a->v)(&(struct a){ .v[2]=Y, .x=a->y} ); a->S = strtok(0, " \t"); free(a->y); a->y=0;
+
+```
+
+These are truly nasty beyond the look because what it does is it allows me to
+have the same data in a struct (outside the struct **and** in a sense in the
+struct) do **different things in different places**. In fact the only reason I need
+the two variables `struct a *f` an `struct a *c` is because of the linked list;
+everything else is anonymous in the functions!
+
+Here are some funny statements / expressions:
+
+```
+ o = *"";
+
+ s=z+-*"1"-*"1"- -97,L=putchar(!s&&isupper(a->x[0**"z"])?a->a->c[s]:tolower(a->a->c[s]));
+
+ c = calloc(1**"0"-47, sizeof *c);
+
+ for (a->a = f, z = 0**"1"; a->a; a->a = a->a->e)
+
+ for (z = 2/ *"z", s=1+0**"1"; z[a->x]; ++z)
+
+ for (J = *"1"-*"1"; J < 26 && B[J][X?1/ *"1"+s/
+ *"1"+1/ *"1"+s/ *"1"+1+(s-s)**"1"+(s*(s-s))**"1":((((s-1)**"1")**"1")**"1")**"1"]; ++J)
+
+
+ (((*a->h[--a->l]=='e'-':')&&(*a->v)(&(struct a){ .v[0]=I, .s=((a->l)[a->h])+1} )
+ &&++a->l)||(a->v[1](&(struct a){ .v[2]=Y,.x=((a->l)[a->h])} ),++a->l)); if (g) puts(""); }
+
+ if (*B[J][0+*"1"-*"1"] == toupper(z[a->x]))
+
+
+ for (k = (s*2)**"9"-171+*"9"; H=B[J][X?*"1"-49:s/ *"1"+s/ *"1"+1/ *"1"+(s*s*s)][k]; ++k)
+
+```
+
+And you really thought you couldn't mix arithmetic and strings in C? Now that you
+know better can you tell me what's going on or keep track of what it's doing? In
+some cases it's actually nested but with this there are few numbers that are
+what they appear to be.
+
+Some of these are really funny (and a bit nasty) because if you try removing
+spaces you'll turn the expression into a comment! If you need help in
+unravelling these, I gave it my best go in [deobfus.c](deobfus.c); but as it
+says there some of it I really cannot parse well - some of it seems so wrong and
+yet what looks 'right' is wrong (for instance it looks like `-1` will be the
+index in an array but trying to 'fix' it will break the code).
+
+Fun fact: in C, the following are both legal:
+
+```
+ char **c;
+
+ char * *c;
+```
+
+(in particular, the whitespace is allowed, although in **some** cases it can cause
+unexpected output). So in my code depending on the command, for example:
+
+```
+ ./prog.alt $(./prog +prog.c)
+```
+
+will show funny output (remember also it ends up passing `*` to the shell!)
+whereas:
+
+
+```
+ ./prog.alt +prog.c
+```
+
+won't.
+
+As for the `*` in the code causing the shell to show files in the directory
+interspersed with other text (which I think is hilarious but not the fault of
+the program) there are other funny things that can happen due to the shell and
+command line. For instance I have at times seen `returnreturn`!
+
+Consider this a fun Easter egg, if your system is affected, that I chose to keep
+because the formatting was more important and output is actually correct when
+not abusing the shell. Considering too I was able to spell out `IOCCC` in the
+formatting of the code which I might not have been able to do as easily is
+another reason for this.
+
+Compress some if/while loops with `&&` and comma operator. The biggest example
+is the while loop in `Z()` which acts on the argc/argv of `main()` (and the loop
+condition increments, then the body immediately undoes the increment and then at
+the end redoes the increment so that at the next pass the `c` (argc) is back to
+where it was left at the start of the loop body) which is a single statement but
+which would normally be several. Also in `Z()`: why is this valid?
+
+```
+ while (a->h[a->l++])
+```
+
+How is `a->h[a->l]` set to a safe value? Well in `main()`:
+
+```
+ F((c=((~~!!~!9u|2**"9"-15u/ *"0"-2u)<<~~!~!~9u),c&=9u,&(struct a){ .l=1, .s=a[c],.v= { &w, &w } } ));
+ Z(&(struct a){ .v = { t, I } ,.k=0, .l=c, .h=a, .j=f} );
+```
+
+The `c` (which is the `argc`) is set to the correct value. Of course that
+expression is insane. The [deobfus.c](deobfus.c) explains just how nasty this
+really is, particularly for the `Z()` function.
+
+Can you explain this behaviour?
+
+```
+ $ echo $(dirname $(type -P file)/$(./prog file))
+ /usr/bin/file
+
+ $ $(echo $(dirname $(type -P file)/$(./prog file))) prog.c
+ prog.c: c program text, ASCII text
+```
+
+when this happens?
+
+```
+ $ ./prog file
+ ba-eh-chez
+```
+
+And yes here again `file` is used but not in the way we know it on our computers.
+
+What is:
+
+```
+ putchar(('\0'+'!'-1));
+```
+
+? It is a screwy call to `putchar(' ');`. Obviously this requires ASCII but that
+should be obvious with some of the other ways the code works too. The fun thing
+is how I formatted the code I was able to make it look like I did
+`putchar('\0')` - or at least it starts to look that way!
+
+All the functions besides main return a `char *` and take a `struct a *`. But
+rather than poison the structs needed for operation, the functions are called
+with anonymous `struct a *`s with the specific values set in the function call
+themselves. For instance the following will create call a function `foo` that
+takes a `struct bar *foo` with an `int baz` set to `1`:
+
+```
+ int foo(struct bar *foo)
+ {
+ return foo?foo->baz:-1;
+ }
+
+ foo(&(struct bar){.baz=1});
+```
+
+Why make extra objects when we can use anonymous objects, especially when it the
+latter is far more obscure and much harder to keep track of? And why poison the
+structs when I can poison your mind's ability to parse the code? Thank you very
+much to the C standards body for what probably was a terrible idea (except for
+the IOCCC)! (Though I can think of a few cases it might be useful it's clearly
+bound to be abused - and I believe this is the first time in the contest's
+history it was though I might be wrong.)
+
+A special mention is due I think as well. I noted this in the
+[deobfus.c](deobfus.c) file a bit but I want to elaborate a bit more. In
+`main()` I do something extremely nasty so that `Z()` (which is also extremely
+nasty, see below) works right without accessing invalid memory.
+
+The function call:
+
+```
+ F((c=((~~!!~!9u|2**"9"-15u/ *"0"-2u)<<~~!~!~9u),c&=9u,&(struct a){ .l=1, .s=a[c],.v= { &w, &w } } ));
+```
+
+does a number of things but one of the things it does is it sets up `c` to be
+valid for the call to `Z()`. `c` is `argc` in `main()`. As above, `Z()` is
+called like:
+
+```
+ Z(&(struct a){ .v = { t, I } ,.k=0, .l=c, .h=a, .j=f} );
+```
+
+That's fairly simple but `Z()` itself is nasty. This is what it looks like:
+
+```
+
+ char *Z(struct a *a)
+ {
+ while (a->h[a->l++])
+ (((*a->h[--a->l] == 'e' - ':') && (*a->v)(&(struct a){ .v[0]=I, .j=a->k,.s=((a->l)[a->h])+1 } )
+ &&++a->l)||(a->v[1](&(struct a) { .v[2]=Y, .x=((a->l)[a->h]),.z=a->j } ), ++a->l));
+ return "";
+ }
+```
+
+So in this function `a->h` is `argv` from `main()` and `a->l` is `argc` from
+`main()`. What I am doing with this:
+
+
+```
+ (a->h[a->l++])(((*a->h[--a->l] == 'e' - ':') && (*a->v)(&(struct a){ .v[0]=I, .j=a->k,.s=((a->l)[a->h])+1 } )
+ &&++a->l)||(a->v[1](&(struct a) { .v[2]=Y, .x=((a->l)[a->h]),.z=a->j } ),++a->l));
+```
+
+is quite devious. We all know that the order of evaluation in functions is
+unspecified (or was it implementation defined?) but am I actually doing this?
+In fact I'm not (but see below): I'm circumventing this by using
+short-circuiting rules and the comma operator, ensuring that the order **is**
+specified and also **extremely** hard to parse (the constant updating of argc
+makes it even worse, see next part). The reason for the comma operator on both
+parts of the expression (that is the lhs and rhs of the `||`) is to ensure that
+the argc (`a->l`) is incremented no matter what.
+
+More so, I'm not even sure the order of evaluation matters here as there is only
+one function parameter for all the functions besides `main()`, and it's a
+`struct a *`; but if it does matter I'm circumventing the problem anyway by
+short-circuiting it and using the comma operator, both of which control it to
+the way I need: if the lhs of the lhs fails I still update argc and if the lhs
+fails itself the rhs is done but if the lhs of the rhs fails the argc is still
+incremented for the nest iteration in the loop! How is that done?
+
+Well on the lhs if the first char of the current arg is a `-` it will call the
+appropriate function (`t()`), which because it will never return NULL the argc
+will be updated; but if it fails, which means the first char of the current arg
+is NOT a `-` then the function `I()` will be called, and this too will never
+return NULL. But in that case I use the comma operator instead of `&&` to update
+argc.
+
+The use of the highly nested `()`s and the anonymous structs and the
+short-circuited logic along with the comma operator makes it really hard to
+follow but it also controls everything in precisely the way I need it.
+
+Oh but there's even more in that code...
+
+Did you notice that in the call to `Z()` it sets the anonymous struct `j` to `f`
+and `k` (all of which are a `struct a *`) to 0? Now what happens in `Z()`. First
+this part:
+
+```
+ (*a->v)(&(struct a){ .v[0]=I, .j=a->k,.s=((a->l)[a->h])+1 } )
+```
+
+calls a function (I'm trying to finish this up and I added this late so I am not
+even sure which one exactly even if I said it above or have it in the commented
+code) and in **THAT** function the `struct a *` (again anonymous) has the `j`
+pointer (a `struct a *j`) to `a->k` which was set to 0 in the call to **THIS**
+function. This might be called a red herring though because right after that you
+have:
+
+```
+ (a->v[1](&(struct a) { .v[2]=Y, .x=((a->l)[a->h]),.z=a->j } )
+```
+
+which sets in **THAT** function `z` to `a->j`. With the formatting above it's
+bad enough but in prog.c it's even worse. Now then the function that this calls
+is `I()` (I think the other one might be `Y()` but I'm not sure - in any case it
+doesn't matter as the pointer is not needed there or if it is it's not used by
+that name) and that does:
+
+```
+ ... for (a
+ ->a
+ = a->z,
+ z =
+ 0*
+ *""
+ "1"; a
+ -> a; a ->
+
+ a = a->a->e) {
+ ...
+```
+
+which means that in `I()` the pointer `a->a` is set to `f`.
+
+
+### Format of code
+
+It's kind of crazy too though not as crazy as the code itself. Besides the
+spaces (to point out that spaces in the code are both important and not
+important - or important in the output but not necessarily in the code - or is
+it perhaps vice versa? Neither? Both?) there are some fun shapes and things
+spelt out.
+
+There is an arrow in the code.
+
+There is an I in the code. Well okay it's actually `IOCCC`. Actually that's
+still not accurate! It's `IOCCC CCCOI` (I think - that's what I aimed for)!
+
+If you use your imagination you can kind of see a Christmas tree (though that
+was quite by accident) (I suppose the arrow could also be seen as a Christmas
+tree if modified a bit or you imagine a thin trunk). Another fun thing to point
+out:
+
+```
+ * *
+
+ "9"-15u/
+```
+
+kind of looks like a face (perhaps a hooded face?).
+
+As for prog.alt.c: I thought another approach would be fun. The judges don't
+like submissions that are just lines merged but since this is just alt code
+(though useful in the submission) and since it took a lot of time and energy to
+format the submission code, I joined the lines mostly and removed all the spaces
+that were possible (I think I managed that). This is an interesting exercise as
+you can see that there are a lot of places that are untraditional (in code) but
+that **must** have spaces. Obviously things like `struct a` cannot be `structa`
+but consider the `/ *`: there are at least 10 of those (I think?) that cannot
+have the space removed because doing so would turn it into a comment! Although
+some of the same expressions are used they are not all the same expression. This
+happens in prog.c though I did not count them (and I have a headache, probably
+from the code, so maybe I miscounted). Another place a space is required (also
+in prog.c):
+
+```
+ s=z+-*"1"-*"1"- -97,L=putchar(!s&&isupper(a->x[0**"z"])?a->a->c[s]:tolower(a->a->c[s]))
+```
+
+and the reasons are obvious! I am not sure now if there are other places though.
+
+
+### Compiling and warnings
+
+If `DICT` is not defined it is defined as `"dict"` so it's not really necessary
+if running the program from the same directory - as long as the file exists of
+course.
+
+When I tested this with `clang -Weverything` in macOS (no guarantees the judges
+will experience precisely this - and in fact this might have been with macOS 14,
+not 15, although it works fine with 15.5 and presumably in between those
+versions and possibly - and I'd guess likely - earlier) **NO FEWER THAN THREE
+COMPILER WARNINGS ARE WRONG** (actually a fair few more depending on how you
+count them) and if these were 'fixed', it would **BREAK THE CODE**, potentially
+if not outright (in fact some absolutely would)!
+
+One even would be removing the `,` for a function call (well, not really a
+function but the side-effect is **NEEDED**). That's the ridiculous `-Wcomma` one;
+it's also triggered elsewhere but the side-effects are also being used there and
+as you saw in the Obfuscation section one place this is used to circumvent the
+order of expressions in function calls being unspecified (though that might not
+even be necessary - not sure now).
+
+Some warnings also appear with `gcc` instead though and some might appear with
+both; it's hard to keep track but here is a list of warnings I have disabled.
+The warnings were before I formatted the code and I added obfuscation in at
+least one. I'll note that below.
+
+Note that this was before formatting and maybe I did change some code although I
+doubt it.
+
+This is warning is **WRONG**:
+
+```
+ prog.c:32:22: warning: possible misuse of comma operator here [-Wcomma]
+ 32 | s=z+-*"1"-*"1"- -97,L=putchar(!s&&isupper(a->x[0**"z"])?a->a->c[s]:tolower(a->a->c[s]));
+ | ^
+ prog.c:32:3: note: cast expression to void to silence warning
+ 32 | s=z+-*"1"-*"1"- -97,L=putchar(!s&&isupper(a->x[0**"z"])?a->a->c[s]:tolower(a->a->c[s]));
+ | ^~~~~~~~~~~~~~~~~~~
+ | (void)( )
+```
+
+and `-Wcomma` is one of the most ridiculous warnings of many other ridiculous
+warnings. It would appear that adding that cast might silence the warning but
+it's not the only one and it's totally bogus anyway.
+
+This is **ALSO WRONG**:
+
+```
+ prog.c:48:38: warning: using the result of an assignment as a condition without parentheses [-Wparentheses]
+ 48 | for (k = (s*2)**"9"-171+*"9"; H=B[J][X?*"1"-49:s/ *"1"+s/ *"1"+1/ *"1"+(s*s*s)][k]; ++k)
+ | ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ prog.c:48:38: note: place parentheses around the assignment to silence this warning
+ 48 | for (k = (s*2)**"9"-171+*"9"; H=B[J][X?*"1"-49:s/ *"1"+s/ *"1"+1/ *"1"+(s*s*s)][k]; ++k)
+ | ^
+ | ( )
+ prog.c:48:38: note: use '==' to turn this assignment into an equality comparison
+ 48 | for (k = (s*2)**"9"-171+*"9"; H=B[J][X?*"1"-49:s/ *"1"+s/ *"1"+1/ *"1"+(s*s*s)][k]; ++k)
+ | ^
+ | ==
+```
+
+and 'fixing' it (especially the last part) would **BREAK THE CODE**! It's
+assignment **AND** (implicit) comparison, not just a comparison, and the
+parentheses are pointless. The assumption it is meant to be an equality test is
+also absurd.
+
+This warning is **ALSO WRONG**:
+
+```
+ prog.c:137:44: warning: bitwise negation of a boolean expression; did you mean logical negation? [-Wbool-operation]
+ 137 | F((c=((~~!!~!9u|2**"9"-15u/ *"0"-2u)<<~~!~!~9u),c&=9u,&(struct a){ .l=1, .s=a[c],.v= { &w, &w } } ));
+ | ^~~~~~~
+ | !
+ prog.c:137:46: warning: bitwise negation of a boolean expression; did you mean logical negation? [-Wbool-operation]
+ 137 | F((c=((~~!!~!9u|2**"9"-15u/ *"0"-2u)<<~~!~!~9u),c&=9u,&(struct a){ .l=1, .s=a[c],.v= { &w, &w } } ));
+ | ^~~~~
+ | !
+ prog.c:137:13: warning: bitwise negation of a boolean expression; did you mean logical negation? [-Wbool-operation]
+ 137 | F((c=((~~!!~!9u|2**"9"-15u/ *"0"-2u)<<~~!~!~9u),c&=9u,&(struct a){ .l=1, .s=a[c],.v= { &w, &w } } ));
+ | ^~~~~~~
+ | !
+ prog.c:137:16: warning: bitwise negation of a boolean expression; did you mean logical negation? [-Wbool-operation]
+ 137 | F((c=((~~!!~!9u|2**"9"-15u/ *"0"-2u)<<~~!~!~9u),c&=9u,&(struct a){ .l=1, .s=a[c],.v= { &w, &w } } ));
+ | ^~~~
+ | !
+```
+
+and 'fixing' it **WOULD BREAK THE CODE**! No I did not mean logical negation and
+the assumption here is ridiculous as well.
+
+Additionally, this warning is **ALSO WRONG**:
+
+```
+ prog.c:137:52: warning: possible misuse of comma operator here [-Wcomma]
+ 137 | F((c=((~~!!~!9u|2**"9"-15u/ *"0"-2u)<<~~!~!~9u),c&=9u,&(struct a){ .l=1, .s=a[c],.v= { &w, &w } } ));
+ | ^
+ prog.c:137:8: note: cast expression to void to silence warning
+ 137 | F((c=((~~!!~!9u|2**"9"-15u/ *"0"-2u)<<~~!~!~9u),c&=9u,&(struct a){ .l=1, .s=a[c],.v= { &w, &w } } ));
+ | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | (void)( )
+ prog.c:137:58: warning: possible misuse of comma operator here [-Wcomma]
+ 137 | F((c=((~~!!~!9u|2**"9"-15u/ *"0"-2u)<<~~!~!~9u),c&=9u,&(struct a){ .l=1, .s=a[c],.v= { &w, &w } } ));
+ | ^
+ prog.c:137:53: note: cast expression to void to silence warning
+ 137 | F((c=((~~!!~!9u|2**"9"-15u/ *"0"-2u)<<~~!~!~9u),c&=9u,&(struct a){ .l=1, .s=a[c],.v= { &w, &w } } ));
+ | ^~~~~
+ | (void)( )
+```
+
+Removing the comma would **BREAK THE CODE**. In particular, the side-effect of
+it is needed (see next one too). Casting to void is totally unnecessary, though
+it will at least compile without warnings, if done the way they want (did not
+test the outcome but I know in some cases this 'fix' can break code as well so
+I'm not going to risk that with code that's already highly obfuscated). Besides,
+as you can see, there are other reasons to disable the warning, all because it's
+wrong.
+
+Also, as for another place where `-Wcomma` is triggered:
+
+```
+ prog.c:67:68: warning: possible misuse of comma operator here [-Wcomma]
+ 67 | &&++a->l)||(a->v[1](&(struct a){ .v[2]=Y,.x=((a->l)[a->h])} ),++a->l)); if (g) puts(""); }
+ | ^
+ prog.c:67:19: note: cast expression to void to silence warning
+ 67 | &&++a->l)||(a->v[1](&(struct a){ .v[2]=Y,.x=((a->l)[a->h])} ),++a->l)); if (g) puts(""); }
+ | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | (void)(
+```
+
+The side effect is **REQUIRED** and casting to void is utterly pointless
+(unknown if it is harmful). Actually as I said before, as this is function
+`Z()`, something extremely nasty is being done here, which is detailed better
+(if not to complete satisfaction) [deobfus.c](deobfus.c) and the Obfuscation
+section earlier in this file. And this one is one that changed at the end, where
+it has the new pointer assignment of the `struct a *` in `struct a`. I am trying
+to finish up writing my remarks as the contest is not running for much longer.
+
+Besides that, as it's so complicated I would risk breaking something by trying
+to squelch the warning. In fact at one point I tried to break it down into
+smaller chunks and I failed. I could not do it. It abuses the comma operator but
+it is not a misuse of the comma operator.
+
+Personally I believe that this warning is an antitheses to C and although I
+might be wrong I do believe that anything other than in a for loop (or similar
+say `int a, b, c;`) triggers this warning but the question is is that even
+considered the comma operator in those cases (don't believe so in the latter but
+unsure on the former)?
+
+The gcc warnings (plural):
+
+```
+ prog.c: In function 'I':
+ prog.c:48:51: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
+ 48 | for (k = (s*2)**"9"-171+*"9"; H=B[J][X?*"1"-49:s/ *"1"+s/ *"1"+1/ *"1"+(s*s*s)][k]; ++k)
+ | ^
+ prog.c: In function 'Z':
+ prog.c:67:16: warning: value computed is not used [-Wunused-value]
+ 67 | &&++a->l)||(a->v[1](&(struct a){ .v[2]=Y,.x=((a->l)[a->h])} ),++a->l)); if (g) puts(""); }
+ | ^~
+ prog.c: In function 'main':
+ prog.c:137:37: warning: suggest parentheses around arithmetic in operand of '|' [-Wparentheses]
+ 137 | F((c=((~~!!~!9u|2**"9"-15u/ *"0"-2u)<<~~!~!~9u),c&=9u,&(struct a){ .l=1, .s=a[c],.v= { &w, &w } } ));
+ | ~~~~~~~~~~~~~~~~^~~
+
+```
+
+are **ALSO** wrong and the value **IS** used in `Z()`! Additionally the
+parentheses not there NEED TO NOT BE THERE! The function `Z()`, again, was
+updated for even more obfuscation and that is not reflected in the above
+warning, like the earlier one.
+
+The warning `-Wmissing-prototypes` is stupid because the functions are defined
+before use, obviously. The warning `-Wmissing-variable-declarations` is equally
+as stupid for the same reason. What clang is saying is it wants `static` or
+`extern` some declaration elsewhere (like a header file which is not allowed and
+is pointless anyway).
+
+The misleading indentation warning (if it is triggered) is nonsense and so
+frequently has to be disabled by many contestants for the contest; whether after
+formatting it is still a problem or not I do not know as I disabled it earlier
+on. It is style policing and should NEVER have been added to gcc. Unfortunately
+clang followed suit.
+
+These are primarily triggered by `clang -Weverything` but some are triggered by
+`gcc -Wextra` (I think it's `-Wextra` and not `-Wall`).
+
+The empty while loop warning is asinine. There is no need for a body and it's a
+standard C idiom. The notion the `;` should be on a separate line is format
+style policing but if they deem it 'confusing' I guess that's a good thing!
+
+
+#### A special warning worth mentioning is `-Wusing-C`
+
+Okay obviously that's not what it's really called but it should be: in some
+systems the warning `-Wunsafe-buffer-usage` is triggered in **MANY** places.
+This is because one is using pointers as a buffer or to access a buffer or some
+such but it's essentially warning that the program is in C; hence they should
+just rename it `-Wusing-C` and be done with it because that's basically what
+they're warning against!
+
+The fact you can't even safely iterate through `argv` of `main()` even when
+`argv[argc]` is required to be NULL should say all you need to know about it
+being a TERRIBLE idea. Just like a lot of warnings in clang. Okay and gcc too...
+
+Of course changing the code to not use pointers like I do would **ALSO BREAK THE
+CODE** (if it's even possible - which of course it's not, especially seeing it
+requires argc/argv)!
+
+On this system, with `clang -Weverything`, a total of **81** (!!) warnings were
+issued and **NOT A SINGLE ONE** was valid (and perhaps it's more now after last
+minute changes - not sure)!
+
+
+#### Warning summary
+
+Basically the warnings that are triggered are either plain wrong or useless and
+with several (quite a few) if I were to 'fix' them it would break the code. It
+**MIGHT** be possible to 'fix' some of them but this is FAR from clear and it's
+unnecessary as well.
+
+**IF** any could be 'fixed' without sacrificing obfuscation AND not break the
+program due to not it being so twisted (which is quite unlikely) I would guess
+it's the ridiculous cast to void one. But that can cause bugs as well. As I
+said, and as you probably saw, the comma operator is used extensively and trying
+to placate that ridiculous comma warning would be a nightmare even with casting
+to void. It'd be impossible to change the code without deobfuscating it - and
+likely it would break as well.
+
+Even so it's clear that a lot of abuse of the language is in this program, some
+of which makes it quite hard to follow. As I said for `Z()` (how fun that that
+rhymes) its loop is deranged and when I tried to numerous times break it up for
+some issue I could not do it without causing numerous errors in the code, and I
+am not referring to syntax errors.
+
+Plus the set up in `main()` for that (and other) functions is something else.
+The anonymous structs in each function call with different meanings of the
+members of the struct is really nasty to follow as you can never know what is
+really going to be called or what is what in general, exactly as it should be in
+production obfuscated code!
+
+
+
+### How is the dictionary file 'encrypted'?
+
+
+Well it's just that `Z` is `A`, `Y` is `B` etc. If you need to undo the
+substitution try:
+
+```
+ tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'ZYXWVUTSRQPONMLKJIHGFEDCBA' < dict
+```
+
+Beware that the language did have quite racist terms for certain countries; I
+will not point them out but did want to warn. This won't matter for the
+translator however as those are the literal translations of the words used for
+other things - so you won't see those words unless you look at the file.
+
+I might also add that to have the file translated back to the original format
+would remove obfuscation - if I could even fix the code to work in the first
+place. That is not the only reason I did it but it is a reason it is staying
+that way.
+
+If you wish to know what the words actually are, I gave a link earlier on, which
+might (haven't checked it in ages) have more context as well. So I would
+recommend you check that instead. Still now you know what I did if you wish to
+try and figure out how the obfuscation works. I guess the function that does
+this transliteration is `w()` and of course that also uses the anonymous struct
+so you'd have to trace the call to that.
+
+Of course, as `w` is also a member in the struct that does not help (can't
+search for `w` on a word boundary without encountering the members too, members
+that mean different things at different times). If you must know, and I'm not
+guaranteeing this (the heavily commented file might be better at this - you'll
+have to check as this edit is on the last full day of the contest!) it would
+appear to be `v[0]` and `v[1]` and called in some function from `main()`. No
+that's not a typo of `main()`. Both 0 and 1 seem to point to `w()`.
+
+
+
+### Unsinkable Sam Medical Records - funny card
+
+
+
+
+
+### The issue of spaces
+
+
+Here I will talk about the more technical details on why the spaces have to be
+there as well as things I tried to get it to work, keeping in mind the
+constraints of the size limits that I was under (while maintaining the
+obfuscation - if I could even unwind it). I also talk about spaces in general:
+oddities that might be noticed at times.
+
+Anyway, to have the reverse with just a few mods is just a bonus, and to have
+the reverse is a bonus in general. It is not clear to me how else it could be
+done.
+
+The real trouble is how the language worked. If there was not a word in their
+dictionary they would take the letters of those words and just spell it out with
+their words for the letters. But of course this included multiple words so there
+is the identification issue: what word is actually meant? What if the user means
+something else (which as shown elsewhere this already is a feature of the
+language!).
+
+But with translations being multiple words, how would it work without spaces
+(which are mostly an invention for written text, something they only did after
+translating it in their head)? This system does not allow a reverse simply by
+passing the ciphertext back into it. If it did have that it would be far weaker
+(and remember that's not even the only layer) and would have been much more
+prone to being compromised.
+
+In order to make it as natural as possible for input, spaces have to be used,
+and as said, the translation back is just a bonus - not even strictly needed but
+I wanted to be complete.
+
+Another question is how to translate it back to English when the word might not
+be in the dictionary? Consider this word: `foo`. If we print the translation
+without spaces we will get:
+
+```
+ chuoa-khaa-kha
+```
+
+and with spaces:
+
+```
+ chuo a-kha a-kha
+```
+
+Consider the first one. If we're searching for exact matches (ignoring
+`!isalpha()`) how can the first translate back to `foo`? It can't because
+`chuoa-khaa-kha` is not any word (that is, the 'word' does not even indicate a
+letter to spell out the word)! There is no space there. That is the problem
+at the core.
+
+Now as for what might be done with it. There are a number of things that can be
+considered and I have tried all of these - and others. Unfortunately they do not
+work and I believe would be a disservice to the language as well.
+
+Why would it be a disservice? Because it would not be a genuine translator.
+There would be no point in it.
+
+Anyway here are some things I did try (amongst others not listed) (keep in mind
+I also had already heavily obfuscated things when I tried some of these, but I
+don't think that even matters - and it was not as obfuscated as it is now, btw):
+
+- We could just ignore the problem; after all they did. In fact the Americans
+did not even know it - hence the story I mentioned earlier on in the
+introduction of this. That's what I'm doing and of course this is what does
+work.
+- We can try with the shell adding `"` or `'` and then having spaces we can
+tokenise it with `strtok()`. This almost worked but it had problems with some
+translations for the same reason as noted above. In some cases without the
+tokenisation in `I()` it does work but not in all. But tokenisation is
+problematic anyway.
+- other things as well, some mentioned below.
+
+Now, what can be done about this lack of spaces (in some cases and in other cases
+extra spaces, though as discussed this does not always happen - see further down
+for more details on this and why it's actually a feature and one worth having)?
+
+One thought - which I tried - is that I tokenise it by spaces and then add a
+space for each 'word' translated. But still what to do about the fact that a
+word is no longer there if the letters are merged?
+
+Well in the case of words in the dictionary it is not an issue. But the words
+that were spelt out - those are an issue.
+
+Another thing I tried, and this was the closest thing to working (but it did not
+work in full), is to check by length. That would be updating the `Y()` function.
+
+It would have to skip `!isalpha()` prior to entering the loop and then it would
+in the inner loop (the one with a 'break' if the condition is met) check that
+the length is not beyond the word.
+
+The theory there is that if the letters match (other characters ignored) and the
+length (number of times we iterated not counting the ignored characters) is the
+length of the encoded string we would then 'break out' and so as long as the
+string is empty or the length is the same it would be a match.
+
+This did not work so well either although I did confirm that the `Y()` loop
+broke out in what appeared to be the right place. One thing is that the code in
+`Z()` would have to be updated in ways that caused other issues and so this was
+obviously the wrong choice too.
+
+Keep in mind this too: the matching routine does do some nice things to make it
+a bit easier for input, some of which I already mentioned (I think). Having
+extra spaces is not a big deal. We might even say it is kind of like how the
+Code Talkers had to take a brief moment in translation - and under high stakes.
+
+There were other problems as well though. If I got one case fixed another was
+then broken. Worse was that the way it has to be tokenised (it is the only way
+if we want to translate back, which again is just a nice bonus, and not
+something they even had to do!) it means the shell has to help out sometimes (I
+showed an example earlier I think). In one case I got what seemed to work (but
+not completely). But this:
+
+```
+ ./prog.alt $(./prog foo) # where foo is the correct format
+```
+
+did not work (but it should now); instead I had to do something like:
+
+```
+ OUT=$(./prog ...)
+ ./prog.alt $OUT # or maybe it was "$OUT", not sure now
+```
+
+This is not useful and very unwieldy, to say nothing about it being error prone
+and problematic in other ways. That might still be useful in cases where I noted
+oddities but I'm not sure of that. Fortunately the above example is not needed
+now.
+
+As it is spaces abound!
+
+So given these facts and given the amount of frustration I had, and a large part
+of that is because the code is so ridiculously twisted (as you certainly have
+seen and appreciate by now), as well as how the system worked, I decided to
+recall to you the fact that the Code Talkers did this all in their head, they
+knew the language, and they had the convenience of not having to come up with
+word boundaries. They did not need spaces but it didn't hurt if they had them.
+
+Some space issues were resolved, an example above. Another one is that it used
+to on the second line (and those beyond the second line) when reading in from a
+file print a space at the beginning of the line. This was solved with the code
+that uses the `L` int.
+
+As I noted elsewhere (I think) other cipher systems are not problematic in this
+case; for instance with the Enigma they transmitted it over Morse and they had
+spaces. I don't recall how this was transmitted but it was markedly different in
+how it worked; whereas in the Enigma (and many other ciphers, though I believe
+the Culper Code is one of the exceptions) you aren't limited to specific words,
+with this you are, and you have to spell out the words by the words for its
+letters (the Culper Code might also be this but I'm not sure).
+
+Going back to the disservice part: I believe it would be an **injustice to the
+language** if this was resolved, if it even can be done without reaching the
+IOCCC size limits (I was able to several times get it down but more problems
+showed up which required more code, and I never did solve it to a satisfactory
+level, based on what I just explained and you now hopefully understand and
+appreciate), because the spaces are a testament to its obscurity (even though
+those over radio do not need spaces), though as you noticed I did get some of it
+resolved.
+
+Oh and yes: the size is not at 2503 now. But trying to resolve these 'issues'
+brought it there and beyond.
+
+I do not actually believe it is possible to get rid of the spaces where they are
+and might be deemed incorrect, especially if there is to be a way to translate
+back to English which seems like a good idea (although I did say it might be a
+disservice here, obviously they had to do it, but they didn't have to worry
+about spaces or word boundaries); this is just the way it is given the multiple
+ways a word can be translated (dictionary translation or else spelt out with
+multiple words, the real trouble).
+
+The file mode could have been removed to help with bytes but this limits input
+even more though perhaps given the potential traps it is not really worth it.
+Maybe I should spend time doing something else but given the issues and given
+the amount of obscurity in the code, it would seem to me that it fits the Navajo
+Code Talking language quite well.
+
+The fact they did this in their heads in mere minutes, they really were coding
+machines (or maybe encoding and decoding machines) and they had no room for
+error; the fact trying to remove spaces introduces errors and input problems is
+another reason to not worry about spaces, especially as they did not worry about
+it either as they had no need to break it up, not needing word boundaries in the
+way I do! Nobody speaks like this (and I hope this doesn't change):
+
+> Bang. Space. Bang. Space. Maxwell's. Space. Silver. Space. Hammer ...
+
+That would be ridiculous. We don't need spaces when speaking. We don't need to
+see or not see spaces as one is speaking as we're listening, not reading (okay,
+fine, maybe there are a few very rare exceptions but in general not).
+
+Even so I believe the only spaces left are those that are required and in some
+if not all cases they (those) are mere technicalities.
+
+Basically, and this is important if you wish to be critical of the spaces:
+spaces are not meant for speaking and that is what they did. They had no visual.
+It was all in their head and they translated it in a matter of minutes. They DID
+write it down for their comrades but the spaces IN translation were utterly
+irrelevant just as they are irrelevant when you're speaking.
+
+I will close this out with these final remarks:
+
+In particular, the spaces are added to **help out** in **use of the program**.
+This means that sometimes the output can look odd. You'll notice this especially
+if there is not a word in the dictionary and it has to be spelt one letter at a
+time. This is done so that translations can at least work even if sometimes (for
+instance in `./prog.alt $(./prog b c d)` the spaces are not as you wish (or do
+not exist - or presumably not as you wish).
+
+If a file being read, depending on how you use the program, has a character that
+is interpreted by the shell (such as `*`) then just like any other command that
+could cause problems as the shell will have done its thing before the program
+gets the input.
+
+Of course to expect one to be able to translate prog.c to Navajo Code Talkers
+and back to English to compile is rather absurd, although you might notice the
+alt code can read in the code and redirect to another file that can then be
+compiled (at least in some cases). It's important to remember though that the
+alt code simply prints words that are not in Navajo AS IS, UNTOUCHED, and it
+does not print spaces between words - so any spaces are literal. You can observe
+this at the command line too:
+
+```
+ $ ./prog.alt shush moasi
+ bc
+
+ $ ./prog.alt shush ' ' moasi
+ b c
+```
+
+This is a feature and actually can demonstrate the momentary pause as they
+encoded/decoded the message!
+
+
+### Why I think this entry is worthy of winning
+
+The Code Talkers should be honoured and acknowledged and what better place in a
+contest about obscuring code?
+
+I've shown everyone that you can do arithmetic on strings in C! Even those few
+who might know this fact would have to actually think about what each of these
+evaluates to (maybe there are a few people who wouldn't but that's probably
+extremely rare) and then test their theory out each time (even those who might
+not need a moment to evaluate it in their head might have to do this). The odds
+are they'll have to look at the ASCII table first.
+
+That some of these are recursive and in ternary operator in a loop makes it
+harder to follow still. For instance:
+
+```
+ for (k = (s*2)**"9"-171+*"9"; H=B[J][X?*"1"-49:s/ *"1"+s/ *"1"+1/ *"1"+(s*s*s)][k]; ++k)
+```
+
+is not easy to parse but that's probably a simpler one. A much more ridiculous
+one is:
+
+```
+ for (J = *"1"-*"1"; J < 26 && B[J][X?1/ *"1"+s/
+ *"1"+1/ *"1"+s/ *"1"+1+(s-s)**"1"+(s*(s-s))**"1":((((s-1)**"1")**"1")**"1")**"1"]; ++J)
+```
+
+The array `B` is not going to be easy to parse for most people and the use of it
+is hard to parse too, given the arithmetic on strings (and other things). I
+thought about making the alphabet itself encrypted but I needed bytes for more
+interesting things; after all what difference does it make if you can translate
+the rather unknown language when the program (or alt code) can do it for you
+anyway?
+
+The anonymous structs for each function which has different values per call,
+often in confusing or misleading ways, is something I have not seen in the
+IOCCC, certainly not like this. It makes it hard to follow the code.
+
+Beautifiers (at least some) are not going to help much as they tend to keep
+spaces in place. Of course if the beautifier is not careful it can turn some of
+my code into comments. Some beautifiers are better than others when it comes to
+shortening the program length but I'm not going to help you with that.
+
+Oh and btw: what is prog.obfus.c? I think that was a file that I at one point
+ran the code on though I might have had to manipulate the output a bit, in order
+to get it to compile. It very likely (based on the timestamp) was an older
+version of the code, perhaps one of the `prog.2.c` or `prog.3.c` files. I'm not
+sure now though. What is `prog.pre-format.c`? That was a copy of what was
+`prog.c` at 8 March 2023: so you can see how much it has changed since then as
+well. Similar with some of the other code files. The [deobfus.c](deobfus.c) is
+as noted a heavily commented file although as you'll see there is some I cannot
+parse even myself.
+
+One more thing. The [try.sh](try.sh) script has a fun demonstration of
+`prog.alt` on itself which is then compiled and run on that source file and then
+runs diff on the two files, showing something interesting. I did not have it as
+a try.alt.sh because the try.sh already relies on both being compiled so I
+figured I'd save a file.
+
+
+
diff --git a/2024/ferguson2/deobfus.c b/2024/ferguson2/deobfus.c
new file mode 100644
index 000000000..17e93c3e4
--- /dev/null
+++ b/2024/ferguson2/deobfus.c
@@ -0,0 +1,682 @@
+/*
+ * although not strictly deobfuscated it is commented to try and explain it more
+ *
+ * Please note that I have tried to keep this consistent with the 'final
+ * product' but I had to make fixes and so some of this might be out of date.
+ * Still I am trying to redo it all; but some comments might not be strictly
+ * correct. In which case I hope you can then fully appreciate just how twisted
+ * this code is (and you probably will anyway)!
+ *
+ * Also it is true that some of the variables in the code (which are in the
+ * submission itself, I believe but perhaps not) are not used. This was a
+ * mistake but it's not worth the effort to try and find them all, especially as
+ * it can also cause confusion to people. Trying to parse the code once let
+ * alone several times (which I did) was not something I wanted to repeat again.
+ *
+ * And on that note: there indeed might be things wrongly stated. I tried but
+ * failed to completely understand what I wrote years back. I have no idea how I
+ * managed some of this and I don't know what I did in every case so any
+ * incorrect statements are simply a sign of the obfuscation - a good thing!
+ */
+#include
+#include
+#include
+#include
+#ifndef DICT
+#define DICT "dict"
+#endif
+
+/*
+ * English -> Navajo.
+ *
+ * I am sorry but I can't even begin to fathom TRYING to do this again for the
+ * alt code (X=1), especially as a lot of it is the same but with some subtle
+ * differences.
+ */
+#define X 0
+/*
+ * the struct a is the holder of state but the state is, as will be seen soon,
+ * mostly anonymous. Even the function pointers array has a different order per
+ * function call! The only time (I think) that there is some form of consistency
+ * is the *k and *c of the struct a which is the linked list of words for either
+ * deciphering (alt version with -DX=1) or enciphering (with -DX=0)
+ */
+struct a {
+ /*
+ * some of these are consistent if they're only used in a single function. I
+ * believe this applies in particular to:
+ *
+ * a - for Z(), which parses main() args and acts on them - it is that
+ * part of main()'s body instead of in main(), this so I could make it
+ * harder to keep follow with anonymous and inconsistent ordering and
+ * variables.
+ * N - first field in dictionary file.
+ * S - second field in dictionary file.
+ * A - temporary buffer when reading in dictionary file (which S and N use).
+ *
+ * Like I said the order of v changes depending on the function.
+ *
+ * However as for S and N it's not so simple because these char *'s are not
+ * directly strdup()d! Instead the function that does this, called by F()
+ * but not by those names (I will explain this later) set the 's' (below) in
+ * an anonymous structure to either S or N in the call. The function being
+ * called in all cases (even though it does not look like it) is the same in
+ * every case even though it doesn't look like it; that function is w().
+ */
+ char *w, *c, *s, *x, *t, *u, **h, *S, *N, *A,*(*v[9])(struct a *), *y;
+ struct a *e, *a, *z, *k, *j;
+ int l;
+} *f, *c;
+/* ^ the linked list pointers - f is the list and c each node as the list is
+ * created. The ->e is the next node which is why this is consistent, at least
+ * in f.
+ */
+
+/*
+ * this is the alphabet of the language and it's translated for exact matches in
+ * the alt version especially (it might be used in the encipher - regular -
+ * version but I'm no longer sure of this).
+ *
+ * As can be seen the first element, element 0, is the letter, and the second
+ * element, element 1, is the translation. The word for C for instance is MOASI
+ * and it translates to 'cat'. When prog.alt encounters this it will report
+ * 'cat'. If however prog encounters it it will translate the letters as it's
+ * not in the dictionary. As well if prog.alt encounters something not in the
+ * dictionary, say IOCCC, it will spell out the letters.
+ *
+ * If one does something like:
+ *
+ * ./prog.alt $(./prog ioccc)
+ *
+ * then it should print out 'ioccc' (w/o quotes of course).
+ */
+
+char *B[][2] = {
+ { "A", "WOL-LA-CHEE" } , { "B", "SHUSH" } , { "C", "MOASI" } , { "D", "CHINDI" } ,
+ { "E", "DZEH" } , { "F", "CHUO" } , { "G", "JEHA" } , { "H", "TSE-GAH" } ,
+ { "I", "YEH-HES" } , { "J", "AH-YA-TSINNE" } , { "K", "BA-AH-NE-DI-TININ" } , { "L", "NASH-DOIE-TSO" } ,
+ { "M", "BE-TAS-TNI" } , { "N", "TSAH" } , { "O", "A-KHA" } , { "P", "CLA-GI-AIH" } ,
+ { "Q", "CA-YEILTH" } , { "R", "DAH-NES-TSA" } , { "S", "KLESH" } , { "T", "D-AH" } ,
+ { "U", "NO-DA-IH" } , { "V", "A-KEH-DI-GLINI" } , { "W", "GLOE-IH" } ,
+ { "X", "AL-NA-AS-DZOH" } , { "Y", "TSAH-AS-ZIH" } , { "Z", "BESH-DO-TLIZ" } ,
+ } , *Y(struct a *) ;
+int z, J, C, k, H, D, s, L; size_t n, o; FILE *g;
+/*
+ * these variables would not fit in the structs as they are needed in multiple
+ * functions. Besides the next node of the linked list we can use the other
+ * members of the struct anonymously and differently depending on the function
+ * (to make it extremely hard to keep track of what is what).
+ *
+ * Now it would be possible to have these in as different variables but that
+ * would go well beyond the size limit of rule 2!
+ *
+ * I will tell what these are as we encounter them.
+ */
+
+char *I(struct a *a)
+{
+ /*
+ * okay this is truly dreadful.
+ *
+ * What z is set to is actually 0. That's it.
+ *
+ * Remember that a->z is actually a->j which is f. Well okay you can't know
+ * that yet but you will.
+ */
+ for (a->a = a->z, z = 0**"1"; a->a; a->a = a->a->e)
+ {
+ /*
+ * the function called (a->v[2] (and remember a is anonymous in this
+ * function, created by the calling function at time of calling it) is
+ * Y(). Y() also takes a struct a * but we create it as we call the
+ * function itself, just like what happened when we were called. We set
+ * .w to a->a->w (a->a is the current node in the linked list) and .c to
+ * a->x. But what are these?
+ *
+ * Well a->w is assigned (will talk about this later) the first field OR
+ * second field of the dictionary depending on if we are deciphering or
+ * enciphering. Of course this file is enciphering but that only adds to
+ * confusion! As I see it right now, if deciphering (X==1) (which again
+ * does not happen here) then it is the second field (S in that struct);
+ * else it is the first field (N in that struct).
+ *
+ * And what was 'x'? I am sorry but I can't figure that out but I can
+ * say that Y() checks if two strings are equal but ignoring !isalpha().
+ * What this implies is it is either the first or second string as Y()
+ * acts on exact matches of letters as noted earlier.
+ *
+ * Okay doing an fprintf() suggests that it is the input. For instance
+ * if I were to do ./prog.alt shush the a->x is shush itself.
+ */
+ if (a->v[2](&(struct a){ .w=a->a->w, .c=a->x} ))
+ {
+ /*
+ * just to make sure we print out the stuff before in case there is
+ * a non-alpha character (or characters)
+ */
+ while (!isalpha(*a->x) && *(a->x)) { L=putchar(*a->x); ++a->x; }
+ /*
+ * okay this is also really nasty. Remember that z starts out at 0
+ * and a->c is (I think!) the first field if X==1 (which is false)
+ * and the second field if X==0 (enciphering mode, true). Well okay
+ * so this part is not the nasty part; it's the body of the loop.
+ */
+ while ((z++)[a->a->c])
+ /*
+ * this is truly awful. First of all remember that z starts out
+ * at 0 here and we want to set 's' to something terrible. But
+ * what in the world is '-*"1"-*"1"- -97? It is -1. But why do I
+ * want s to be -1? Well I don't. Remember that I'm adding it to
+ * s which starts out at 0. Thus the first pass this will be
+ * indeed -1, second pass 0 etc. But why start out at -1 when it
+ * seems like we're indexing into a->c (a char *)? This is
+ * extremely nasty too.
+ *
+ * Let us break this down a bit more. If s is -1 the !s (will
+ * end up being?) false. That means the !isupper(a->x[0**"z"])
+ * will not be called the first time (or perhaps it will, I
+ * don't know now). Okay but we have to back up a bit. What is
+ * 0**"z"? That is 1. So what is a->x[1]? This is also very
+ * ugly. I believe (but I am no longer sure!) that the calling
+ * code is:
+ *
+ * (((*a->h[--a->l]=='e'-':')&&(*a->v)(&(struct a){ .v[0]=I,
+ * .s=((a->l)[a->h])+1} ) &&++a->l)||(a->v[1](&(struct a){
+ * .v[2]=Y,.x=((a->l)[a->h])} ),++a->l)); if (g) puts(""); }
+ *
+ * Okay actually I'm sorry. I have absolutely no idea what this
+ * is. But the numbers at least can be explained. Also we can
+ * break the code down more though, just not determine all the
+ * values. If !s and isupper(a->x[1]) we will index a->a->c[s].
+ * But when it's not we will call tolower(a->a->c[s]). Now you
+ * might ask how in the world a->a->c[s] is legal on the first
+ * pass. I'm sorry but once again I have no clue I just know it
+ * does not evaluate to invalid indexing. Even more baffling is
+ * if the index starts out at 0 (i.e. - -98 instead of - - 97),
+ * the code does not work! Of course it might not be baffling at
+ * all but seems that way after trying to parse this nasty nasty
+ * code.
+ */
+ s=z+-*"1"-*"1"- -97,L=putchar(!s&&isupper(a->x[0**"z"])?a->a->c[s]:tolower(a->a->c[s]));
+ goto n;
+ }
+ }
+ /*
+ * if we get here it means that the word is not in the dictionary. And of
+ * course this is also extremely nasty, the expressions. The 2/ *"z"
+ * evaluates to 0 and the 1+0**"1" evaluates to 1.
+ *
+ * Okay and the number[pointer] indexing is used. As noted above I believe
+ * K->x is the actual input. I'll try and parse the loop but no guarantees I
+ * get everything! Much of this was written years ago.
+ */
+ for (z = 2/ *"z", s=1+0**"1"; z[a->x]; ++z)
+ {
+ /*
+ * okay the first part is simple enough. For each !isalpha() char in
+ * a->x we simply print the char via putchar(). Again I'm unclear what
+ * a->x is however.
+ */
+ if (!isalpha(z[a->x]))
+ L=putchar(z[a->x]);
+ else
+ {
+ /*
+ * so C is if the current char of the current input is lower case. I
+ * am not sure if we actually need to save this or not but it's
+ * quite possible we do. It might just be to save bytes (or it might
+ * not save bytes).
+ */
+ C = islower(z[a->x]);
+ /*
+ * This is even nastier than before I guess.
+ *
+ * The first one is easy: J is set to 0 and while J < 26 and ...
+ * hold on, what are we checking against now?
+ *
+ * Well remember that B is the letter <-> Navajo word for that
+ * letter array. So B[J][0] would be the letter itself and B[J][1]
+ * will be the word itself. But now we have the other horrible
+ * expressions! Remember that if X (it's always 1 in this file) is
+ * non-zero it's deciphering and if it's 0 it's enciphering. But
+ * what is:
+ *
+ * 1/ *"1"+s/
+ * *"1"+1/ *"1"+s/ *"1"+1+(s-s)**"1"+(s*(s-s))**"1"
+ *
+ * ? Well first of all let's clarify that this is actually:
+ *
+ * 1/ *"1"+s/ *"1"+1/ *"1"+s/ *"1"+1+(s-s)**"1"+(s*(s-s))**"1"
+ *
+ * Observe too how a space removed in several places will turn it
+ * into a comment!
+ *
+ * I can try and parse some of this but I'm not really sure of all
+ * of it. For instance, how is (s*(s-s)) parsed? It would appear that
+ * it's s * 0 and it might very well be. Assuming that s is 0 (for
+ * example) it is 1; assuming it is 1 it is ... 1? So it seems. And
+ * assuming it is 2 is .... 1 again? So it seems! So how in the
+ * world does this work? Well remember what we're trying to get:
+ * either the first element or the second, and in this place we
+ * always need 1. Let's evaluate the other part (I'm sure you can
+ * figure it out though after this first one): 0! Okay but there's
+ * something really sneaky here (and above): ask yourself if 's' is
+ * actually incremented. Got your answer? Okay good! In fact if you
+ * were to update it you will get bad answers! For instance what
+ * happens if it's 2? I got 5764801. And then what if it's 0?
+ * -5764801.
+ */
+ for (J = *"1"-*"1"; J < 26 && B[J][X?1/ *"1"+s/
+ *"1"+1/ *"1"+s/ *"1"+1+(s-s)**"1"+(s*(s-s))**"1":((((s-1)**"1")**"1")**"1")**"1"]; ++J)
+ {
+ /*
+ * oh dear did I do it again? Yup. I did. But in this case you
+ * can probably figure it out. Even so I'll evaluate these for
+ * you. Yes: 0+*"1"-*"1" is 0.
+ */
+ if (*B[J][0+*"1"-*"1"] == toupper(z[a->x]))
+ {
+ /*
+ * Not again! Okay to help out let's remember s is 1. So s *
+ * 2 is 2. It's the other stuff that's a nightmare.
+ *
+ * (s*2)**"9"-171+*"9" == 0
+ *
+ * And you probably want to kill me but what is:
+ *
+ * *"1"-49 ?
+ *
+ * It is 0. And since you killed me you probably now want to
+ * chop me up into tiny bits but before you do that I guess
+ * you want to know what s/ *"1"+s/ *"1"+1/ *"1"+(s*s*s) is?
+ * That evaluates to 1.
+ */
+ for (k = (s*2)**"9"-171+*"9"; H=B[J][X?*"1"-49:s/ *"1"+s/ *"1"+1/ *"1"+(s*s*s)][k]; ++k)
+ putchar(C?tolower(H):toupper(H));
+ /*
+ * this is putchar(' ')
+ */
+ L=putchar(('\0'+'!'-1));
+ break;
+ }
+ }
+ }
+
+ }
+ /*
+ * we jumped here if a word was in the dictionary and translated, as
+ * explained earlier but we also get here if we don't (obviously)
+ */
+ n:
+ /*
+ * if the last char we pushed on the stream is a space, don't add a space
+ */
+ if (!isspace(L))
+ putchar(' ');
+ return a->s;
+}
+
+/*
+ * Z() used to be the parsing of args in main() and it's also truly dreadful, I
+ * know. Unfortunately I am not sure if I can explain it all but I will try.
+ */
+char *Z(struct a *a)
+{
+ /*
+ * it would appear that a->l was argc of main() (c) and a->h is the argv
+ * (a) so the condition of the loop is going through all the args. However
+ * before we can continue we need to see how this function was called:
+ *
+ * Z(&(struct a){ .v = { t, I } ,.k=0, .l=c, .h=a, .j=f} );
+ *
+ * This means that a->v[0] == t() and a->v[1] == I and a (our struct)'s l is
+ * c (argc in main()) and our a->l is argv in main(). Additionally a->j is
+ * the linked list of words.
+ */
+ while (a->h[a->l++])
+ /*
+ * I() :-) no longer can parse this completely (as in I don't know all
+ * of what it does) but I'll still try breaking it down a bit. I make no
+ * promises however. I will break the line up to help out, though it
+ * might not do that much good.
+ */
+
+ /*
+ * first notice how where the loop condition (postfix) increments argc
+ * (a->l) the body of the loop immediately decrements (prefix decrement)
+ * and compares the first char of the current arg to - what? The
+ * expression 'e'-':' evaluates to '+'. This is checking for file as
+ * input.
+ */
+ (((*a->h[--a->l]=='e'-':')&&
+ /*
+ * Okay remember what I said above about x->v[0] being t() ? That means
+ * that this is calling t().
+ */
+ (*a->v)
+ /*
+ * ...and here we create the anonymous struct * for t(). As you can see
+ * the first function pointer in the v[] array is I(). Observe how in
+ * _this_ function v[0] is a different function! In this function v->[0]
+ * is t() but in this next function (t() itself!) it will be I()! But how
+ * do we construct it? Well...
+ *
+ * The &(struct a) is important because we can't do:
+ *
+ * (struct a *)
+ *
+ * because it is an error:
+ *
+ * prog.c:67:41: error: initialization of non-aggregate type 'struct a *'
+ * with a designated initializer list.
+ *
+ * (Okay the line numbers are different but you get the idea.)
+ * But since we need a pointer we can use & to get the address of the
+ * anonymous struct.
+ */
+ (&(struct a)
+ /*
+ * Now the fun part! The object we create is in the {}s (of course). Each
+ * field, even pointers use '.' (which as shown above is required as we
+ * can't do { ->s=... } as it's also illegal and this is why we make it a
+ * struct that's not a pointer and take its address to get past that
+ * problem).
+ *
+ * Here we are saying that in the anonymous struct we're passing to t()
+ * the v[0] is I() and the s (a char *) is - what? Well this is awful. Do
+ * you remember that a->l is argc and a->h is argv from main()? So
+ *
+ * ((a->l)[a->h])
+ *
+ * is argv[argc]. Now the usual C programmer would point out that that is
+ * NULL. But something *extremely* nasty was done before we called this
+ * function. I will explain it (or rather try to) in main() but it looks
+ * like this:
+ *
+ * F((c=((~~!!~!9u|2**"9"-15u/ *"0"-2u)<<~~!~!~9u),c&=9u,&(struct a){ .l=1, .s=a[c],.v= { &w, &w } } ));
+ *
+ * Remember that c in main() (or our a->l) is argc. So this horrible call
+ * resets c to some value, in particular 1 though that line does a lot
+ * more.
+ *
+ * So what this part does is, again, set OUR v[0] to I() which we are now
+ * calling, remember, and set OUR s (a char *) that is a->s to beyond
+ * (argv[argc])+1 (starting out with argc == 1). This also sets .j to
+ * a->k which is actually - what? This is sneaky. In main() when calling
+ * Z() a->j is set to f (the linked list) but here we're setting a->j (in
+ * the function call) to a->k. But in main() in calling Z() a->k is set
+ * to NULL! Further down though we will do .z=a->j so this might (or
+ * might not) be called a red herring.
+ *
+ * But of course we're not done!
+ */
+ { .v[0]=I, .j=a->k, .s=((a->l)[a->h])+1} )
+ /*
+ * I'm sure that some people are screaming by now, if they even got this
+ * far, but here we are doing something sneaky (imagine that) too.
+ *
+ * Remember how the loop condition incremented argc but the loop body
+ * immediately decremented it (since we needed to check the first char
+ * of the first arg, not the next)? Well the problem is now that we have
+ * checked that we nee to get x-> (argc) incremented again, but prefix.
+ */
+ &&++a->l)||
+ /*
+ * But of course if these (what are these? Please go back up and check, I
+ * too am getting tired of trying to parse all this and I have a lot more
+ * to do!) did not succeed we still have more nastiness.
+ *
+ * a->v[1] is I() so now main() is (or rather we, Z(), are on behalf of
+ * main()) calling t with - yup, ANOTHER anonymous struct a *!
+ */
+ (a->v[1](&(struct a)
+ /*
+ * The good news at least is you know how the struct is constructed but
+ * what are we doing here and why?
+ *
+ * Well here we are saying that in the call to I() that v[2] is Y() (not
+ * again) and x (a char *, not like x here which is a struct a *) is set
+ * to the current argv[argc].
+ *
+ */
+ { .v[2]=Y,.x=((a->l)[a->h]),.z=a->j}
+ /*
+ * this is the end of the function call but we're not actually done just
+ * yet.
+ *
+ * Observe how we are prefix incrementing a->l again (argc in main())!
+ */
+ ),++a->l));
+ /*
+ * Okay but you might ask yourself: how come we're using the comma
+ * operator here? Well because at this point although we do need to
+ * call I() we also need to increment argc (a->l) yet again!
+ *
+ * But...why? After all the body of the loop does this! Not quite. It
+ * does do this but that was on the left hand side (lhs) of the body
+ * of the loop and the beginning of the body of the loop decremented
+ * it! So in order to get argc back to the next one we have to
+ * increment it as a side effect!
+ */
+
+ /*
+ * we only do this because we need to return a char *; a simple return
+ * 0 would also work and so would a return NULL.
+ */
+ return "";
+}
+/*
+ * this function is simpler though there still are some potentially confusing
+ * things going on here. Yes this looks kind of like a rot13 implementation but
+ * the dictionary file actually has Z -> A, Y -> B, X -> C etc. But what was r
+ * formed of? Actually this is extremely sneaky.
+ */
+char *w(struct a *a)
+{
+ /*
+ * Okay but you might notice I did something nasty again. Okay I did
+ * multiple nasty things! You probably can figure these out at least though.
+ * Anyway, 1/ *"s" is 0 and 'k'-'*' evaluates, as you might have guessed, to
+ * 'A'.
+ *
+ * That means start out at 0, go through a->s - well you get the idea. But
+ * what is a->s? Well that is the dictionary file of course but that'll be
+ * discussed in the respective function.
+ */
+ for (D = 1/ *"s"; a && a->s && D[a->s] && (a->s[D]) &&
+ (a->s[D] = isupper(a->s[D])?("ZYXWVUTSRQPONMLKJIHGFEDCBA"
+ )[(a->s[D] - ('k'-'*'))]:D[a->s]); ++D) ;
+
+ /*
+ * at one point it was possible for a to be NULL so we checked here. It
+ * shouldn't be needed now though.
+ */
+ return a?a->s:"";
+}
+
+/*
+ * this is kind of like strcasecmp() except that it ignores !isalpha(). There is
+ * only one thing that might not be immediately obvious so I'll only comment on
+ * that. Well okay as you'll see a->w is the first string and a->c is the
+ * second. But besides that it's pretty easy.
+ */
+char *Y(struct a *a)
+{
+ if (*a->w && *a->c && a->w[1] && a->c[1])
+ while (*a->w && *a->c)
+ {
+ while (!isalpha(*a->w) && *a->w++);
+ while (!isalpha(*a->c) && *a->c++);
+ if (!*a->c || !*a->w || tolower(*a->w) != tolower(*a->c))
+ break;
+ ++a->w; ++a->c;
+ }
+ /*
+ * remember that we need to return a char * so what this does is it
+ * evaluates to either a 'true' value (non NULL string) or a NULL pointer.
+ * This can be checked as if an int but matching the requirement that it
+ * returns a char * (for the function pointer array).
+ */
+ return !*a->w&&!*a->c?"":0;
+}
+
+/*
+ * This function reads in the dictionary file as the first line might suggest.
+ */
+char *F(struct a *a)
+{
+ g = fopen(DICT, "r");
+ if (g)
+ {
+ /*
+ * We use getline(3) even though there is the bug I mentioned in the
+ * remarks file because we can have it dynamically allocate memory. It
+ * stores the newline but so does fgets() and we don't really care about
+ * it. In fact we do not want to remove the newline!
+ */
+ while (getline(&a->A, &n, g) != -1)
+ /*
+ * So we were called like this:
+ *
+ * F((c=((~~!!~!9u|2**"9"-15u/ *"0"-2u)<<~~!~!~9u),c&=9u,&(struct a){ .l=1, .s=a[c],.v= { &w, &w } } ));
+ *
+ * I am not going to explain the first part until main() but the
+ * second part, which can only happen by the comma operator (like in
+ * other places) and which we use as we need the other thing to be
+ * done first, it sets up our struct a *a's .l to 0, v[0] to &w and
+ * v[1] to &w. Why both? To mislead of course!
+ */
+
+ /*
+ * this part is easy but note how we use a->A and a->S as the first
+ * and second column. They are not really needed except to have them
+ * also in the struct (and even if they were not NULL we assign them
+ * first).
+ */
+ if ((a->N = strtok(a->A, "\t")) && (a->S = strtok(0, "\t")))
+ {
+ /*
+ * Oh no! Not another bonkers calculation! Well fortunately you can
+ * probably put together what it is but if not it evaluates to 1.
+ * Basically we're allocating a struct a *.
+ */
+ c = calloc(1**"0"-47, sizeof *c);
+ /*
+ * more fun with anonymous structs here as we populate the struct a *
+ * we just created. As I might have said elsewhere if X is non-zero
+ * (never true here) it means decipher and otherwise it means encipher.
+ * means. But observe how c->w can be one or the other just like
+ * c->c. That's because the X check is done in other places too.
+ *
+ * Now about these structs being created. For c->w it is a strdup()d
+ * copy of the result of calling w() on either a->S or a->N.
+ * Similarly we are doing the same thing (but opposite order) for
+ * c->c. But hold on a moment you might think. Why then are we
+ * assigning multiple values? Well actually we're not. This is just
+ * the copy but both are always assigned to the w()'s struct a *'s s
+ * (a char *).
+ *
+ * As for the function calls:
+ *
+ * a->l is 0 and a->e is NULL but even if it wasn't it would
+ * evaluate to 1 and so a->v[a->l], a->v[a->e==0] (as 1 or 0)
+ * and a->v[1] all point to w()!
+ */
+ c->w = strdup(X?a->v[a->l](&(struct a){ .s=a->S} ):a->v[a->e==0](&(struct a){ .s=a->N} ));
+ c->c = strdup(X?a->v[1](&(struct a){ .s=a->N} ):a->v[a->l](&(struct a){ .s=a->S} ));
+ c->e = f;
+ f = c;
+ }
+
+ free(a->A);
+ a->A = 0;
+ fclose(g);
+ g = 0;
+ }
+ else puts("couldn't open dict");
+ return "";
+}
+
+/*
+ * fortunately t() is a bit easier - although you might remember the call to it
+ * is not.
+ */
+char *t(struct a *a)
+{
+ /*
+ * this assigns o with 0
+ */
+ o = *"";
+ g = fopen(a->s, "r");
+ a->A = 0;
+ while (g && getline(&a->A, &o, g) != -1)
+ {
+ /*
+ * the usual suspect: we're using a->S as a temporary value for strtok()
+ * to extract the first field (space or tab delimited)
+ */
+ a->S = strtok(a->A, " \t");
+ while (a->S)
+ /*
+ * strdup() is useful here
+ */
+ if ((a->y=strdup(a->S))) {
+ /*
+ * if a token was found then we will call a->v[0] which is I don't
+ * even know; I'm really tired doing this and I have more to parse
+ * for you - sorry! Anyway in that function v[2] will be Y() and w
+ * will be S (the token we extracted).
+ */
+ (*a->v)(&(struct a){ .v[2]=Y, .x=a->y} );
+ /*
+ * get next token for this line
+ */
+ a->S = strtok(0, " \t"); free(a->y); a->y=0;
+
+ /*
+ * if the last char we pushed on the stream is a space
+ * don't add a space
+ */
+ if (L!='\n')putchar(' ');
+ }
+ }
+ if(g) { clearerr(g); fclose(g); g = 0; free(a->A); a->A= 0; }
+ return "";
+}
+
+/*
+ * Good news: we've reached the last function!
+ *
+ * Bad news: it's also dreadful, really dreadful!
+ */
+int main(int c, char **a)
+{
+ /*
+ * Do I have to try and parse this? Okay well I did explain in one function
+ * (F() itself) the second half but I did not explain the first half so I'll
+ * try here.
+ *
+ * Remember how I said (I think I said anyway) that argc is set to 1? Well
+ * that is because:
+ *
+ * ((~~!!~!9u|2**"9"-15u/ *"0"-2u)<<~~!~!~9u)
+ *
+ * evaluates to 113 and 113 & 9 is 1. The other parts are just a
+ * distraction.
+ *
+ * Notice the double {} there (that's not the only place this occurs though
+ * I think).
+ */
+ F((c=((~~!!~!9u|2**"9"-15u/ *"0"-2u)<<~~!~!~9u),c&=9u,&(struct a){ .l=1, .s=a[c],.v= { &w, &w } } ));
+ /*
+ * This was the one that processes the args. It is not a hard call to deal
+ * with (the function Z() itself is of course): call Z() with an anonymous
+ * struct a * with v[0] == t(), v[1] == I(), l == c (argc), a == a
+ * (argv) and k == 0 (NULL) and j == f (linked list of words)
+ */
+ Z(&(struct a){ .v = { t, I } ,.k=0, .l=c, .h=a, .j=f} );
+ puts("");
+ /*
+ * Now go have some good chocolate or some great pie! You deserve it!
+ */
+}
diff --git a/2024/ferguson2/dict b/2024/ferguson2/dict
new file mode 100644
index 000000000..652e77d51
--- /dev/null
+++ b/2024/ferguson2/dict
@@ -0,0 +1,677 @@
+Z DLO-OZ-XSVV ZMG
+Z YV-OZ-HZMZ ZKKOV
+Z GHV-MROO ZCV
+Y MZ-SZHS-XSRW YZWTVI
+Y HSFHS YVZI
+Y GLRHS-QVS YZIIVO
+X NLZHR XZG
+X GOZ-TRM XLZO
+X YZ-TLHSR XLD
+W YV WVVI
+W XSRMWR WVERO
+W OSZ-XSZ-VS WLT
+V ZS-QZS VZI
+V WAVS VOP
+V ZS-MZS VBV
+U XSFL URI
+U GHZ-V-WLMRM-VV UOB
+U NZ-V ULC
+T ZS-GZW TRIO
+T PORAARV TLZG
+T QVSZ TFN
+S GHV-TZS SZRI
+S XSZ SZG
+S ORM SLIHV
+R GPRM RXV
+R BVS-SVH RGXS
+R Z-XSR RMGVHGRMV
+Q GPVOV-XSL-T QZXPZHH
+Q ZS-BZ-GHRMMV QZD
+Q BRO-WLR QVIP
+P QZW-SL-OLMR PVGGOV
+P YZ-ZS-MV-WR-GRMRM PVB
+P PORAARV-BZAARV PRW
+O WRYVS-BZAARV OZNY
+O ZS-QZW OVT
+O MZHS-WLRV-GHL ORLM
+N GHRM-GORGR NZGXS
+N YV-GZH-GMR NRIILI
+N MZ-ZH-GHL-HR NLFHV
+M GHZS MVVWOV
+M Z-XSRM MLHV
+L Z-PSZ LRO
+L GOL-XSRM LMRLM
+L MV-ZSH-QZS LDO
+K XOZ-TR-ZRS KZMG
+K YR-HL-WRS KRT
+K MV-ASLMR KIVGGB
+J XZ-BVROGS JFREVI
+I TZS IZYYRG
+I WZS-MVH-GHZ IZN
+I ZS-OLHA IRXV
+H WRYVS HSVVK
+H POVHS HMZPV
+G W-ZS GVZ
+G Z-DLS GLLGS
+G GSZM-ARV GFIPVB
+F HSR-WZ FMXOV
+F ML-WZ-RS FGV
+E Z-PVS-WR-TORMR ERXGLI
+D TOLV-RS DVZHVO
+C ZO-MZ-ZH-WALS XILHH
+B GHZS-ZH-ARS BFXXZ
+A YVHS-WL-GORA ARMX
+XLIKH WRM-MVS-RS XOZM
+WRERHRLM ZHSRS-SR HZOG
+IVTRNVMG GZYZSZ VWTV DZGVI
+YZGGZORLM GZXSVVMV IVW HLRO
+XLNKZMB MZPRZ NVCRXZM
+KOZGLLM SZH-XORHS-MRS NFW
+HVXGRLM BL-RS YVZWH
+HJFZW WVYVS-OR-ARMR YOZXP HSVVK
+XLNNZMWRMT TVMVIZO YRS-PVS-SV DZI XSRVU
+NZQLI TVMVIZO HL-MZ-PRS GDL HGZI
+YIRTZWRVI TVMVIZO HL-Z-OZ-RS LMV HGZI
+XLOLMVO ZGHZS-YVHS-OV-TZR HROEVI VZTOV
+ORVFGVMZMG XLOLMVO XSV-XSRO-YV-GZS-YVHS-OVTZR HROEVI LZP OVZU
+NZQLI XSV-XSRO-YV-GZS-LOZ TLOW LZP OVZU
+XZKGZRM YVHS-OVTZR-MZS-PRS GDL HROEVI YZIH
+ORVFGVMZMG YVHS-OVTZR-Z-OZS-RS LMV HROEVI YZI
+XLNNZMWRMT LUURXVI SZHS-PZB-TR-MZ-GZS DZI XSRVU
+VCVXFGREV LUURXVI YRS-WZ-SLO-MVSR GSLHV RM XSZITV
+ZUIRXZ ASRM-MR YOZXPRVH
+ZOZHPZ YVS-STZ DRGS DRMGVI
+ZNVIRXZ MV-SV-NZS LFI NLGSVI
+ZFHGIZORZ XSZ-BVH-WVHR ILOOVW SZG
+YIRGZRM GLS-GZ YVGDVVM DZGVIH
+XSRMZ XVS-BVSH-YVHR YIZRWVW SZRI
+UIZMXV WZ-TSZ-SR YVZIW
+TVINZMB YVHS-YV-XSZ-SV RILM SZG
+RXVOZMW GPRM-PV-BZS RXV OZMW
+RMWRZ ZS-OV-TZR DSRGV XOLGSVH
+RGZOB WLS-SZ-XSR-BZOR-GXSR HGFGGVI
+QZKZM YVS-MZ-ZOR-GHLHRV HOZMG VBV
+KSRORKKRMV PV-BZS-WZ-MZ-OSV UOLZGRMT RHOZMW
+IFHHRZ HROZ-TLO-XSR-RS IVW ZINB
+HLFGS ZNVIRXZ HSZ-WV-ZS-MV-SR-NZS HLFGS LFI NLGSVI
+HKZRM WVYZ-WV-MRS HSVVK KZRM
+KOZMVH DL-GZS-WV-MV-RS ZRI ULIXV
+WREV YLNYVI TRMR XSRXPVM SZDP
+GLIKVWL KOZMV GZH-XSRAARV HDZOOLD
+LYH KOZMV MV-ZH-QZS LDO
+URTSGVI KOZMV WZ-SV-GRS-SR SFNNRMT YRIW
+YLNYVI KOZMV QZB-HSL YFAAZIW
+KZGILO KOZMV TZ-TRS XILD
+GIZMHKLIG ZGHZS VZTOV
+HSRKH GLS-WRMVS-RS HVZ ULIXV
+YZGGOVHSRK OL-GHL DSZOV
+ZRIXIZUG GHRWR-NLUUZ-BV-SR YRIW XZIIRVI
+HFYNZIRMV YVHS-OL RILM URHS
+NRMV HDVVKVI XSZ YVZEVI
+WVHGILBVI XZ-OL HSZIP
+GIZMHKLIG WRMVS-MZB-BV-SR NZM XZIIRVI
+XIFRHVI OL-GHL-BZAARV HNZOO DSZOV
+NLHJFRGL YLZG GHV-V NLHJFRGL
+QZMFZIB ZGHZS-YV-BZA HNZOO VZTOV
+UVYIFZIB DLA-XSVRMW HJFVZPB ELRXV
+NZIXS GZS-XSROO HNZOO KOZMG
+ZKIRO GZS-GHL YRT KOZMG
+NZB GZS-GHLHRV HNZOO KOZMG
+QFMV YV-MV-VS-VS-QZS-GHL YRT KOZMGRMT
+QFOB YV-MV-GZ-GHLHRV HNZOO SZIEVHG
+ZFTFHG YV-MVVM-GZ-GHL YRT SZIEVHG
+HVKGVNYVI TSZD-QRS SZOU
+LXGLYVI MRO-XSR-GHLHRV HNZOO DRMW
+MLEVNYVI MRO-XSR-GHL YRT DRMW
+WVXVNYVI BZH-MRO-GVH XIFHGVW HMLD
+ZYZMWLM BV-GHZM IFM ZDZB UILN
+ZYLFG DLOZ-XSR-Z-NLUUZ-TZSM ZMG URTSG
+ZYIVZHG DLOZ-XSVV-YV-BRVW ZMG YIVZHG
+ZXXLNKORHS FO-HL ZOO WLMV
+ZXXLIWRMT YV-PZ-SL ZXXLIWRMT GL
+ZXPMLDOVWTV SZMLG-WARVW ZXPMLDOVWTV
+ZXGRLM ZS-SZ-GRMS KOZXV LU ZXGRLM
+ZXGRERGB ZS-SZ-GRMS-B ZXGRLM VMWRMT RM B
+ZWVJFZGV YVS-TSZ VMLFTS
+ZWWRGRLM RS-SV-WV-MWVO ZWWRGRLM
+ZWWIVHH BR-XSRM-SZ-GHV ZWWIVHH
+ZWQZXVMG YV-TZSR MVZI
+ZWQFHG SZH-GZR-MVO-PZW ZWQFHG
+ZWEZMXV MZH-HVB ZSVZW
+ZWERHV MZ-MVGRM ZWERHV
+ZVIRZO YV-ALMA HGRMTVI
+ZUURINZGREV OZMS ZUURINZGREV
+ZUGVI YR-PSZ-WR ZUGVI
+ZTZRMHG YV-MZ-TMRHS ZTZRMHG
+ZRW VWZ-VOV-GHLLW ZRW
+ZRI MROXSR ZRI
+ZRIWLNV MROXSR-YVTSZM ZRIWLNV
+ZOVIG SZ-RS-WVH-VV ZOVIG
+ZOO GZ-Z-GZS ZOO
+ZOORVH MRS-SR-XSL ZOORVH
+ZOLMT DLOZXSVV-HMVA OLMT ZMG
+ZOHL VS-WL ZOHL
+ZOGVIMZGV MZ-PVV-TL-MV-MZM-WVB-SV HVXLMW KLHRGRLM
+ZNYFHS PSZX-WZ ZNYFHS
+ZNNFMRGRLM YVS-VOR-WLS-YV-XZS-ZOR-GZH-ZR ZNNFMRGRLM
+ZNKSRYRLFH XSZO UILT
+ZMW WL ZMW
+ZMTOV WVV-XZSM HOZMGRMT
+ZMMVC RS-MZB-GZMR ZWWRGRLM
+ZMMLFMXV YVS-SZ-L-WAV ZMMLFMXV
+ZMGR DLO-OZ-XSVV-GHRM ZMG RXV
+ZMGRXRKZGV MR-QLO-ORS ZMGRXRKZGV
+ZMB GZS-SZ-WZS ZMB
+ZKKVZI BV-PZ-SZ-BZ ZKKVZI
+ZKKILZXS YR-XSR-LO-WZS ZKKILZXS
+ZKKILCRNZGV GL-PFH-WZM ZKKILCRNZGV
+ZIV TZS-GHL YRT IZYYRG
+ZIVZ SZA-Z-TRS ZIVZ
+ZINLI YVHS-BV-SZ-WZ-WR-GVS RILM KILGVXGLI
+ZINB OVR-XSZ-RS-BRO-PMVV-RS ZINB
+ZIIREV RO-WZB ZIIREV
+ZIGROOVIB YV-ZO-WLS-GHL-OZMR NZMB YRT TFMH
+ZH ZSXV ZH
+ZHHZFOG ZOGHVS-V-QZS-SV URIHG HGIRPVI
+ZHHVNYOV WV-QR-PZHS YFMXS GLTVGSVI
+ZHHRTM YZS-WVS-GZSM ZHHRTM
+ZG ZS-WR ZG
+ZGGZXP ZO-GZS-QV-QZB ZGGZXP
+ZGGVNKG YL-L-MV-GZS GIB
+ZGGVMGRLM TRSZ ZGGVMGRLM
+ZFGSVMGRXZGLI SZMR-YZ-ZS-SL-ARM PMLD ZYLFG
+ZFGSLIRAV YV-YL-SL-HMVV ZFGSLIRAV
+ZEZROZYOV GZ-HSLA-GVS-RS ZEZROZYOV
+YZTTZTV POZROS YZTTZTV
+YZMAZR MV-GZS ULLO GSVN
+YZITV YVHS-MZ-VOG YZITV
+YZIIZTV YVHS-YZ-DZ-XSRMW YZIIZTV
+YZIIRVI YRS-XSZM-MR-ZS RM GSV DZB
+YZHV YRS-GHVV-WRS YZHV
+YZGGVIB YRS-YV-ZO-WLS-GPZ-RS GSIVV TFMH
+YZGGOV WZ-ZS-SR-WAR-GHRL YZGGOV
+YZB GLS-ZS-SR-TSRMS YZB
+YZALLPZ ZS-ASLO YZALLPZ
+YV GHVH-MZS YVV
+YVZXS GZS-YZSM YVZXS
+YVVM GHVH-MZS-MVH-XSVV YVV MFG
+YVULIV YRS-GHV-WRS YVULIV
+YVTRM SZ-SLO-ARA XLNNVMXV UILN
+YVOLMT GHVH-MZS-HMVA OLMT YVV
+YVGDVVM YR-GZS-PRA YVGDVVM
+YVBLMW YROS-OZ WR WLDM YVOLD
+YRELFZX VSO-MZH-GVS YIFHS HSVOGVI
+YLNY Z-BV-HSR VTTH
+YLLYB GIZK WRMVS-YZ-DSLZ-YOVSR NZM GIZK
+YLIMV BV-XSRV-GHZS YLIM VOP
+YLFMWZIB PZ-BZS-YR-MZ-SZH-WALS YLFMWZIB
+YFOO WLAVI WLOZ-ZOGS-DSLHS YFOO HOVVK
+YFMPVI GHZH-PZ HZMWB SLOOLD
+YFG MVS-WRS YFG
+YB YV-TSZ YB
+XZYOV YVHS-OPLS DRIV ILKV
+XZORYVI MZSO-PRSW NLEV ZILFMW
+XZNK GL-ZOGHVS-SLTZM GVNKLIZIB KOZXV
+XZNLFUOZTV WR-MVH-RS SRW
+XZM BZS-WR-ARMR XZM
+XZMMLMVVI YV-ZO-WLS-GHL-WVB-WRO-WLM-RTR YRT TFM LKVIZGLI
+XZKZXRGB YV-MVO-ZS XZKZXRGB
+XZKGFIV BRH-MZS XZKGFIV
+XZIIB BL-OZROS XZIIB
+XZHV YRG-HZS XZHV
+XZHFZOGB YRS-WRM-MV-WVB KFG LFG LU ZXGRLM
+XZFHV YR-MRS-MZMR XZFHV
+XZEV GHZ-LMW ILXP XZEV
+XVRORMT WZ-GVO-QZB HVZO
+XVNVGVIB QRHS-XSZ ZNLMT WVEROH
+XVMGVI FOS-MV-RS XVMGVI
+XSZMTV GSOZ-TL-Z-MZG-AZS XSZMTV
+XSZMMVO SZ-GZOSR-BZAARV HNZOO HRMTVI
+XSZITV ZS-GZS-TR-QZS XSZITV
+XSVNRXZO GZ-MVV ZOPZOR
+XRIXOV MZH-KZH XRIXOV
+XRIXFRG ZS-SVS-SZ-WZROS XRIXFRG
+XOZHH ZOGS-ZS-Z-GVS XOZHH
+XOVZI BL-ZS-SLO-ASLW XOVZI
+XORUU GHV-BV-XSVV XORUU
+XOLHV FO-XSR-FS-MZO-BZS XOLHV
+XLZHG TFZIW GZ-YZH-WHRHHR HSLIV IFMMVI
+XLWV BRO-GZH KVXP
+XLOLM MZPR-ZOS--WVS-WZ-ZO-ASRM GDL HKLGH
+XLOFNM ZOGS-PZB-MV-ARS XLOFNM
+XLNYZG WZ-ZS-SR-QRS-TZMS URTSGRMT
+XLNYRMZGRLM ZO-GPZH-VR NRCVW
+XLNV SFX-JFL XLNV
+XLNNZ GHZ-MZ-WZSO GZRO WILK
+XLNNVIXRZO MZR-VO-MV-SR XLNNVIXRZO
+XLNNRG SFX-JFL-OZ-QRHS XLNV TOLEV
+XLNNFMRXZGRLM SZ-MVS-ZO-VMQR NZPRMT GZOP
+XLMXVZO YV-PR-ZHA-QLOV XLMXVZO
+XLMXVMGIZGRLM GZ-OZ-SR-QRS LMV KOZXV
+XLMXFHHRLM DSV-SFH-WRO XLMXFHHRLM
+XLMWRGRLM ZS-SL-GZR SLD RG RH
+XLMUVIVMXV YV-PV-BZ-GR GZOP LEVI
+XLMURWVMGRZO MZ-MRO-RM PVKG HVXIVG
+XLMURIN GZ-Z-MVS NZPV HFIV
+XLMJFVI Z-PVS-WVH-WORM DLM
+XLMHRWVI MV-GHZ-XZH GSRMP RG LEVI
+XLMHRHG YROS XLMHRHG
+XLMHLORWZGV ZS-SRS-SR-MRO KFG GLTVGSVI
+XLMHGIFXG ZSO-MVS GL NZPV
+XLMGZXG ZS-SR-WR-WZRO XLNV GLTVGSVI
+XLMGRMFV GZ-BR-GVS XLMGRMFV
+XLMGILO MZR-TSRA XLMGILO
+XLMELB GPZO-PZS-L-MVO NLERMT LM DZGVI
+XLLIWRMZGV YVS-VS-SL-ARM-MZ-ZH-WALS PMLDM ORMVH
+XLFMGVI ZGGZXP DLOGZS-ZO-PR-TR-QVS XLFMGVI ZXG
+XLFIHV XL-QR-TLS XLFIHV
+XIZUG ZS-GLS MVHG
+XIVVP GLS-MRO-GHZMS EVIB ORGGOV DZGVI
+XILHH ZO-M-ZH-WALS XILHH
+XFY HSFHS-BZSA XFY
+WZHS FH-WALS WZHS
+WZDM SZ-BVOR-PZSM WZDM
+WVUVMHV ZS-PRM-XRO-GLS WVUVMHV
+WVTIVV MZSO-PRSW WVTIVV
+WVOZB YV-HRGRSM WVVI OZB
+WVOREVI YV-YRS-ARSWV WVVI OREVI
+WVNLORGRLM ZS-WVVO-GZSR YOLD FK
+WVMHV SL-WROS-XOZ DVG
+WVKZIG WZ-WV-BZS WVKZIG
+WVKZIGNVMG SLTZM WVKZIGNVMG
+WVHRTMZGV BV-PSR-WVO-MVR KLRMG LFG
+WVHKVIZGV ZS-WZ-ZS-SL-WAZS WLDM GL OZHG
+WVGZXS ZO-XSZ-MRO WVGZXSVW
+WVGZRO YV-YVS-HSZ WVVI GZRO
+WVGLMZGLI ZS-WVVO-GZSR(LI) YOLDM FK
+WRUURXFOG MZ-MV-POZS WRUURXFOG
+WRT-RM OV-VS-TZWV WRT RM
+WRIVXG ZS-QR-TL WRIVXG
+WRHVNYZIP VS-SZ-QZB TVG LFG
+WRHKZGXS OZ-XSZR-VM-HVRH-YV-QZB WLT RH KZGXS
+WRHKOZXV SRS-WL-MZO NLEV
+WRHKOZB YV-HVRH-MZ-MVS WVVI RH KOZB
+WRHKLHRGRLM Z-SL-GVB WRHKLHRGRLM
+WRHGIRYFGV MZS-MVS WRHGIRYFGV
+WRHGIRXG YV-GSRM-BZ-MR-XSV WVVI RXV HGIRXG
+WL GHV-OV HNZOO KFK
+WLXFNVMG YVS-VS-SL-ARMA WLXFNVMG
+WIREV ZS-MLO-PZSO WIREV
+WFW WR-TRHH-BZSARV HNZOO WFNNB
+WFNNB WR-TRHH-GHL YRT WFNNB
+VZXS GZ-OZSR-MV-ARMR-TL VZXS
+VXSVOLM DSL-WAZS ORMV
+VWTV YV-YZ-SR VWTV
+VUUVXGREV YV-WVOS-MVVW VUUVXGREV
+VUULIG BVZ-TL DRGS ZOO BLFI NRTSG
+VOVNVMG ZS-MZ-MZR GILLK IVKIVHVMGRMT LGSVIH
+VOVEZGV ZOR-PSR-SL-MV-LSZ VOVEZGV
+VORNRMZGV SZ-YVS-GL-WARO VORNRMZGV
+VNYZIP VS-SL-QZB TVG LM
+VNVITVMXB SL-MVA-XOZ VNVITVMXB
+VNKOZXVNVMG OZ-ZA-MRO VNKOZXVNVMG
+VMXRIXOV BV-MZH-GVS VMXRIXOV
+VMXLFMGVI YR-PSZMS TL ZTZRMHG
+VMTZTV Z-SZ-MV-SL-GZ ZTIVVW
+VMTRMV XSRWR-YR-GHR-GHRMV VMTRMV
+VMTRMVVI WZB-WRO-QZS-SV VMTRMVVI
+VMOZITV MRS-GHZ-TLS-ZO-MVS NZPV YRT
+VMORHG YRS-ARS-Z-WZ-BR-OZS VMORHG
+VMGRIV GZ-Z-GZS VMGRIV
+VMGIVMXS V-TZW-ZS-MV-ORS NZPV WRGXS
+VMEVOLK Z-AZS-TR-BZ VMEVOLK
+VJFRKNVMG BZ-SZ-WV-GZSR VJFRKNVMG
+VIVXG BVS-ARSM HGZMW FK
+VHXZKV Z-AVS-SZ-TV-BZS VHXZKV
+VHGZYORHS SZH-GZB-WAZS VHGZYORHS
+VHGRNZGV YRS-PV-GHV-SLW-WVH-PVA VHGRNZGV
+VEZXFZGV SZ-MZ VEZXFZGV
+VCXVKG MVS-WRS VCXVKG
+VCXVKG MZ-DLO-MV VCKVXG
+VCXSZMTV ZOS-MZSO-BZS VCXSZMTV
+VCVXFGV Z-WL-MRO VCVXFGV
+VCKOLHREV ZS-WVO-GZSR VCKOLHREV
+VCKVWRGV HSRO-OLS HKVVW FK
+VCGVMW MV-GWZOV NZPV DRWV
+VCGIVNV ZO-GHZM-ZS-YZSN VZXS VMW
+UZRO XSZ-ZO-VRMW UZRO
+UZROFIV BVVH-TSRM UZROFIV
+UZIN NZR-YV-SV-ZSTZM ULC ZIN
+UVVW WAVS-XSR-BLM UVVW
+URVOW XOL-WRS URVOW
+URVIXV GLS-YZS-SZ-AHRW ZUIZRW
+UROV YZ-VS-XSVA UROV
+URMZO GZS-ZS-PDL-WRS GSZG RH ZOO
+UOZNV GSILDVI XLS-ZS-TSRO-GORW UOZNV GSILDVI
+UOZMP WZS-WR-PZW UOZMP
+UOZIV DL-XSR ORTSG HGIVZP
+UORTSG NZ-V-ZH-AOLOR ULC ORTSG
+ULIXV GZ-MZ-MV-OZWR DRGSLFG XZIV
+ULIN YV-XSZ ULIN
+ULINZGRLM YV-XSZ-BV-OZROS ULINZGRLM
+ULIGRURXZGRLM ZS-MZ-HLAR XORUU WDVOORMT
+ULIGRUB ZS-MZ-HLAR-BZAARV HNZOO ULIGRURXZGRLM
+ULIDZIW GVSR OVG'H TL
+UIZTNVMGZGRLM YVHS-BZAARV HNZOO NVGZO
+UIVJFVMXB SZ-GZOSR-GHL YRT HRMTVI
+UIRVMWOB MVS-SVXSL-WZ-MV UIRVMWOB
+UILN YR-GHZM-WVSM UILN
+UFIMRHS BVZH-MRO UFIMRHS
+UFIGSVI DL-MZH-WR UFIGSVI
+TZIIRHLM BZS-Z-WZ-SZO-BLM-RS GZPV XZIV LU
+TZHLORMV XSRWR-YR-GLS TZHLORMV
+TIVMZWV MR-NZ-HR KLGZGLVH
+TFZIW MR-WRS-WZ-SR TFZIW
+TFRWV MZS-V-GSOZR TFRWV
+SZOO OSR-GZ-Z-GZ SLIHV ZOO
+SZOU GIZXP ZOS-MRS-QZS-Z-JFSV IZXV GIZXP
+SZOG GZ-ZPDZR-R SZOG
+SZMWOV YVG-HVVM SZMWOV
+SZEV QL SZEV
+SVZWJFZIGVI MZ-SZ-GZS-GZ-YZ-SLTZM SVZWJFZIGVI
+SVOW DL-GZS-GZ-VS-WZSM-LS SVOW(KZHG GVMHV)
+SRTS DL-GZS SRTS
+SRTS VCKOLHREV YV-ZO-WLS-YV-XZ-YRS-WARO-RTR KLDVIUFO HSVOO
+SRTSDZB DL-GZS-SL-MV-GVS SRTS DZB
+SLOW DL-GPZMS SLOW
+SLHKRGZO Z-AVB-ZO-RS KOZXV LU NVWRXRMV
+SLHGROV Z-MZS-MV-WARM MLG UIRVMWOB
+SLDRGAVI YV-VO-WLM-GH-JFLWR HSLIG YRT TFM
+ROOFNRMZGV DL-XSR ORTSG FK
+RNNVWRZGVOB HSRO-OLS RNNVWRZGVOB
+RNKZXG Z-SV-WRH-TLS RNKZXG
+RNKLIGZMG YZ-SZH-GVS RNKLIGZMG
+RNKILEV SL-WLO-ASLMW RNKILEV
+RMXOFWV VO-GHLW RMXOFWV
+RMXIVZHV SL-MZOS RMXIVZHV
+RMWRXZGV YZ-SZO-MVS GVOO ZYLFG
+RMUZMGIB GZ-MVS-MZO-WZSR RMUZMGIB
+RMUROGIZGV BV-TSZ-MV-QVS DVMG GSILFTS
+RMRGRZO YVS-VW-WV-WORW YIZMW
+RMHGZOO VSW-GMZS RMHGZOO
+RMHGZOOZGRLM MZH-MRO RM KOZXV
+RMHGIFXG MZ-MV-GTRM GVZXS
+RMGVOORTVMXV SL-BZ HNZIG
+RMGVMHV WAVVO HGIVMTGS
+RMGVIXVKG BVO-MZ-NV-QZS RMGVIXVKG
+RMGVIUVIV ZS-MROS-PSOZR RMGVIUVIV
+RMGVIKIVG ZS-GZS-SZ-MV RMGVIKIVG
+RMEVHGRTZGV MZ-ZOR-PZ GIZXP
+RMELOEV Z-GZS RMELOEV
+RH HVRH HVEVM
+RHOZMW HVRH-PVBZS HVEVM RHOZMW
+RHLOZGV YRS-GHZ-MVO-PZW HVKZIZGV
+QFMTOV DLS-WR-XSRO QFMTOV
+PROO MZA-GHZRW PROO
+PROLXBXOV MZH-GHZRW-Z-PSZ-ZS-BVS-SZ-WROS PROO LRO TL ZILFMW
+OZYLI MZ-MRHS OZYLI
+OZMW PZB-BZS OZMW
+OZFMXS GPZ-TSRO-ASLW OZFMXS
+OVZWVI ZS-MZ-TSZR OVZWVI
+OVZHG WV-YV-BZARV-SZ-Z-ZS OZNY UVZHG
+OVZEV WZS-WV-BZS SV OVUG
+OVUG MRHS-XOZ-QRS-TLS OVUG
+OVHH YR-LS OVHH
+OVEVO WRO-PLMS OVEVO
+ORZRHLM WZ-Z-SV-TR-VMVS PMLD LGSVI'H ZXGRLM
+ORNRG YZ-SZH-ZS ORNRG
+ORGGVI MR-WZH-GLM HXZGGVI
+OLXZGV Z-PDV-VS HKLG
+OLHH FG-WRM OLHH
+NZXSRMV TFM Z-PMZS-ZH-WLMRS IZKRW URIV TFM
+NZTMVGRX MZ-V-OZSR KRXP FK
+NZMZTV SZHGMR-YVS-MZ-SZR NZM ZTV
+NZMVFEVI MZ-MZ-L-MZOGS NLERMT ZILFMW
+NZK PZS-BZ-MVHS-XSZR NZK
+NZCRNFN YVO-WRO-PSLM UROO GL GLK
+NVXSZMRX XSRGR-Z-MZBO-RMRS ZFGL IVKZRINZM
+NVXSZMRAVW XSRWR-WZ-ZS-SV-TLMR URTSGRMT XZIH
+NVWRXZO Z-AZB NVWRXRMV
+NVTZXBXOV NRO-ZS-SVS-ZS-WROS NROORLM TL ZILFMW
+NVIXSZMG HSRK MZ-VO-MVSR-GHRM-MZ-ZROS NVIXSZMG HSRK
+NVHHZTV SZMV-ZO-MVS NVHHZTV
+NRORGZIB HROZTL-PVS-TLS NRORGZIB
+NROORNVGVI MZ-ZH-GHL-HR-Z-BV-WL-GRHS WLFYOV NLFHV
+NRMV SZ-TZWV NRMV
+NRMRNFN YV-LS NRMRNFN
+NRMFGV ZS-PSZB-VO-PRG-BZAARV ORGGOV SLFI
+NRHHRLM ZO-MVHSLWR NRHHRLM
+NRHGZPV L-ASR NRHH
+NLKKRMT SZ-GZL-WR NLKKRMT
+NLIV GSOZ-MZ-MZS NLIV
+NLIGZI YV-ZO-WLS-XRW-WZ-SR HRGGRMT TFM
+NLGRLM MZ-SLG-MZS NLGRLM
+NLGLI XSRWV-YV-GHV-GHVM XZI SVZW
+MZGREV PZ-SZ-GVMR MZGREV
+MZEB GZO-PZS-HROZTL HVZ HLOWRVI
+MVXVHHZIB BV-MZ-AVSM DZMG
+MVTZGREV WL-BZ-HSL-WZ ML TLLW
+MVG MZ-MVH-WRAR MVG
+MVFGIZO WL-MVS-ORMR MVFGIZO
+MLINZO WLS-Z-GZ-S-WZS MLINZO
+MLG MR-WZS-GSZM-ARV ML GFIPVB
+MLGRXV MV-WZ-GZAR-GSRM ML GFIPVB RXV
+MLD PFG MLD
+MFNYVI YVS-YRS-PV-ZH-XSRMRTS DSZG'H DIRGGVM
+LYQVXGREV YR-MV-BVR TLZO
+LYHVIEV SZO-ARW LYHVIEV
+LYHGZXOV WZ-SL-WVHS-ASZ LYHGZXOV
+LXXFKB BVVO-GHLW GZPVM
+LU GLS-MR-GPZO-OL LXVZM URHS
+LUUVMHREV YRM-PRV-QRMS-QRS-WVA-QZB LUUVMHREV
+LMXV GZ-OZR-WR LMXV
+LMOB GZ-VR-GZB-Z-BZS LMOB
+LKVIZGV BV-MZSO-MRHS DLIP ZG
+LKKLIGFMRGB ZHS-TZ-ZORM LKKLIGFMRGB
+LKKLHRGRLM MV-SV-GHZS-QRS-HSRM LKKLHRGRLM
+LI VS-WL-WZS-TLS VRGSVI
+LIZMTV GXSRO-OSV-HLR LIZMTV
+LIWVI YV-VS-SL-ARMR LIWVI
+LIWMZMXV OVR-ZA-QZS FMWVI TILFMW
+LIRTRMZGV WZH-GVS-WL YVTRM
+LGSVI OZ-V-XRS LGSVI
+LFG XOL-WRS LFG HRWV
+LEVIOZB YV-PZ-SZH-GHLA LEVIOZB
+KZIVMGSVHRH ZGHZMS IRY
+KZIGRXFOZI Z-BL-ZW-WL-MVS KZIGRXFOZI
+KZIGB WZ-HSZ-QZS KZIGB
+KZB MZ-VOR-BZ KZB
+KVMZORAV GZS-MR-WVH-GZMS HVG YZXP
+KVIXVMG BZO NLMVB
+KVIRLW WZ-ZSO-ASRM KVIRLW
+KVIRLWRX WZ-ZO-ASRM-GSRM-NLZHR KVIRLW RXV XZG
+KVINRG TLH-HSR-V KVINRG
+KVIHLMMVO WZ-MV-OVR NVNYVI
+KSLGLTIZKS YVS-XSR-NZ-SZW-MRO KSLGLTIZKS
+KROO YLC YR-HL-WRS-WLG-HZSR-YR-GHZS HRXP KRT YLC
+KRMMVW WLDM YRO-WZS-SZH-GZMS-BZ KRMMVW WLDM
+KOZMV GHRWR YRIW
+KOZHNZ WRO-WR-TSROR KOZHNZ
+KLRMG YV-HL-WV-WVA-ZSV KRT KLRMG
+KLMGLLM GPLHS-QZS-WZ-MZ-VOG UOLZGRMT YZIIVO
+KLHRGRLM YROS-SZH-ZSM KLHRGRLM
+KLHHRYOV GZ-SZ-ZS-GZB KLHHRYOV
+KLHG HZS-WVR KLHG
+KIVKZIV SZHS-GZB-SL-WRG-MV KIVKZIV
+KIVHVMG PFG KIVHVMG
+KIVERLFH YRS-GHV-WRS KIVERLFH
+KIRNZIB ZOGHVS-MZM-WZB-SR-TRS 1HG KLHRGRLM
+KIRLIRGB SZMV-KVHLWR KIRLIRGB
+KILYZYOV WZ-GHR KILYZYOV
+KILYOVN MZ-MRHS-GHLS YRT QLY
+KILXVVW MZB-MRS-QRS TL
+KILTIVHH MZS-HZR KILTIVHH
+KILGVXG ZS-XSZMS HVOU WVUVMHV
+KILERWV BRH-MRO KILERWV
+KFIKOV WRMO-XSR KFIKOV
+KBILGVXSMRX XLS-MZ-XSZMS UZMXB URIV
+JFVHGRLM ZS-QZS VZI
+JFRXP HSRO-OLS JFRXP
+IZWZI VHZG-GHZMS ORHGVM
+IZRW WVAQZB IZRW
+IZROSVZW Z-WV-TVS-SR HSRKKRMT KLRMG
+IZROILZW PLMS-MZ-ZO-YZMHR-YR-GSRM IZROILZW
+IZOOBRMT Z-OZS-MZ-L-TOZORS TZGSVIRMT
+IZMTV ZM-AZS WRHGZMXV
+IZGV TZS-VS-BZSM IZYYRG ZGV
+IZGRLM MZ-Z-QZS IZGRLM
+IZERMV XSFHS-PZ IZERMV
+IVZXS RO-WZB IVZXS
+IVZWB PFG IVZWB
+IVZI YV-PZ-WVMS IVZI
+IVXVRKG HSLA-GVS IVXVRKG
+IVXLNNVMW XSV-SL-GZR-GZSM IVXLNNVMW
+IVXLMMZRHHZMXV SZ-Z-XRWR RMHKVXGLI
+IVXLMMLRGVI GZ-SZ-MV-ZO-BZ NZPV HFIV
+IVXLIW TZS-ZS-MZS-POLOR I-V-ILKV
+IVW OR-XSR IVW
+IVVU GHZ-ASRM YOZXP ILXP
+IVVNYZIP VS-MZ-XLS TL RM
+IVURIV MZ-MZ-XLS IVURIV
+IVTFOZGV MZ-BVO-M IVTFOZGV
+IVRMULIXV MZO-WARO IVRMULIXV
+IVORVU ZTZMS-GLO-QZB IVORVU
+IVORVEV MZS-QRS-XL-MZO-BZ IVNLEV
+IVLITZMRAV SZ-WRG-AZS IVLITZMRAV
+IVKOZXVNVMG MR-MZ-WL-MRO IVKOZXVNVMG
+IVKLIG DSL-MVS TLG DLIW
+IVKIVHVMGZGREV GPZ-MZA-MROR GIRKOV NVM
+IVJFVHG QL-PZBVW-TLS ZHP ULI
+IVHVIEV SVHS-Q-V IVHVIEV
+IVHGIRXG YZ-SL-XSRMR IVHGIRXG
+IVGRIV ZS-SLH-GVVMW IVGRIV
+IVGIVZG QR-WRM-MVH-XSZMS IVGIVZG
+IVGFIM MZ-WAZS XZNV YZXP
+IVEVZO DSL-MVS IVEVZO
+IVEVIG MZ-HR-BRA GFIM ZYLFG
+IVEVGNVMG YZ-MZH-XOZ XLIMVI
+IRWTV TZS-TSRO-PVRW IZYYRG IRWTV
+IRUOVNZM YV-ZO-WL-SLHGVVM IRUOVNVM
+IREVI GLS-BRO-PZO NFXS DZGVI
+ILYLG YLNY Z-BV-HSR-MZ-GZS-RS VTT UOB
+ILXPVG OVHA-BRO-YVHSR HZMW YLRO
+ILOO BVS-NZH ILOO
+ILFMW MZA-KZH ILFMW
+ILFGV TZS-YRS-GPVVM IZYYRG GIZRO
+IFMMVI MRS-WARW-GVRS IFMMVI
+HZYLGZTV Z-GPVO-BZS SRMWVIVW
+HZYLGVFI Z-GPVO-VO-RMR GILFYOV NZPVI
+HZROLI XSZ-OV-TZR DSRGV XZKH
+HZOEZTV MZ-SZH-TOZS KRXP GSVN FK
+HZG YRS-OZ-HZMZ-XRW-WZ-SR ZKKOV HRGGRMT
+HXZIOVG IVW OSV-XSR(H & I) IVW
+HXSVWFOV YVS-VS-SL-ARMR HXSVWFOV
+HXLFG SZ-Z-HRW-ZO-HRAR-TRS HSLIG IZXXLLM
+HXIVVM YVHS-MZ-MVH-WRAR HXIVVM
+HVZNZM GPZO-PZS-WRMVS-RS HVZNZM
+HVXIVG YZS-SZH-GPRS HVXIVG
+HVXGLI BLVSR HVXGLI
+HVXFIV BV-WASV-ZO-GHRHR HNZOO HVXFIRGB
+HVRAV BVVO-HGLW HVRAV
+HVOVXG YV-GZS-SZH-TOZ GLLP LFG
+HVNR XLOLM WZ-ZSO-ASRM-YR-GHZ-MZ-WZSO WLG WILK
+HVG WAVS-XRW-WZ-SR VOP HRGGRMT
+HSZXPOV WR-YZS-MVHS-TLSA HSZXPOV
+HSVOO YV-ZO-WLS-YV-XZ HSVOO
+HSLIV GZS-YZSM HSLIV
+HSLIG YLHS-PVVHS HSLIG
+HRWV YLHS-PVVHS HRWV
+HRTSG BV-VO-GHZMS HVVM
+HRTMZO MZ-VS-VS-TRHS YB HRTMH
+HRNKOVC ZOZS-RS-MV-GRS RMMVI DRIV
+HRG GPRM-XRW-WZ-SR RXV HRGGRMT
+HRGFZGV Z-SL-GZB HRGFZGV
+HNLPV ORG HNLPV
+HMRKVI LS-YVSR KRXP 'VN LUU
+HKZXV YV-GPZS YVGDVVM
+HKVXRZO V-BRS-HRS NZRM GSRMT
+HKVVW BL-ALMH HDRUG NLGRLM
+HKLIZWRX ZS-MZ-SL-MVRO MLD ZMW GSVM
+HKLGGVI VVO-GHZB-R HKLGGVI
+HKIZB POVHS-HL-WROARM HMZPV KIZB
+HJFZWILM MZS-TSRAR HJFZHS
+HGLIN MV-LO HGLIN
+HGIZUV MZ-DL-TSR-TLRW SLV
+HGIZTTOVI XSB-MV-WV-WZSV HGIZTTOVI
+HGIZGVTB MZ-SZ-GZS HGIZGVTB
+HGIVZN GLS-MR-ORS IFMMRMT DZGVI
+HGIVMTGS WASVO HGIVMTGS
+HGIVGXS WVHA-GHLLW HGIVGXS
+HGIRPV MZB-WZO-TSZO HGIRPV
+HGIRK SZ-GRS-QZS HGIRK
+HGFYYLIM MRO-GZ HGFYYLIM
+HFYQVXG MZ-MRHS-BZAARV HNZOO QLY
+HFYNVITV GPZO-XOZ-BR-BZS DVMG FMWVI DZGVI
+HFYNRG Z-MRS-OVS HVMW
+HFYLIWRMZGV ZO-PSR-MZO-WAO SVOKRMT VZXS LGSVI
+HFXXVVW BZS-GZB-TL-V-VOZS NZPV TLLW
+HFXXVHH FG-AZS RG RH WLMV
+HFXXVHHUFO FG-AZS-SZ-WVA-YRM RG RH WLMV DVOO
+HFXXVHHREV FG-AZS-HRW HFXXVHH HXZI
+HFXS BRH-XOVS HLC
+HFUUVI GL-SL-MV HFUUVI
+HFNNZIB HSRM-TL-YZS HFNNVI NZIB
+HFKKOVNVMGZIB GPZ-TL-MV-MZM-WVB-SV 3IW KLHRGRLM
+HFKKOB MZO-BVS-SR HFKKOB
+HFKKOB HSRK MZOTZ-SR-GHRM-MZS-ZROS HFKKOB HSRK
+HFKKLIG YZ-ZS-SLG-TOR WVKVMW
+HFIIVMWVI MV-MZ-XSZ HFIIVMWVI
+HFIILFMW MZA-KZH HFIILFMW
+HFIEREV BRH-WZ-BZ HFIEREV
+HBHGVN WR-YZ-GHZ-ZH-ASR-YR-GHRM HBHGVN
+GZXGRXZO V-XSRSM GZXGRXZO
+GZPV TZS-GZSM GZPV
+GZMP XSZB-WZ-TZSR GLIGLRHV
+GZMP WVHGILBVI XSZB-WZ-TZSR-MZRO-GHZRWR GLIGLRHV PROOVI
+GZITVG DLO-WLMR GZITVG
+GZHP GZAR-MZ-VS-WRO-PRW GFIPVB ZHP
+GVZN WVS-MZ-ZH-GHL-HR GVZ NLFHV
+GVIIZXV ZOR-PSR-SL-MV-LSZ GVIIZXV
+GVIIZRM GZHSR-MZ-SZO-GSRM GFIPVB IZRM
+GVIIRGLIB PZ-BZS GVIIRGLIB
+GSZG GZAR-XSZ GFIPVB SZG
+GSV XSZ-TVV YOFV-QZB
+GSVRI YRS GSVRI
+GSVIVZUGVI GZ-AR-PDZ-R-YV-PZ-WR GFIPVB SVIV ZUGVI
+GSVHV XSZ-TR-L-VS GSV HVV
+GSVB XSZ-TVV GSV B
+GSRH WR GSV
+GLTVGSVI GZ-YROS GLTVGSVI
+GLIKVWL OL-YV-XZ URHS HSVOO
+GLGZO GZ-ZO-HL GLGZO
+GIZXVI YVS-MZ-ZO-PZS-SR GIZXVI
+GIZUURX WRZTIZN SZMV-YZ-MZ-ZH-WALS WRZTIZN HGLIB ORMV
+GIZRM XLS-MZR-ZOR-YZSM-HR GIZRM
+GIZMHKLIGZGRLM Z-SZS-WZ-Z-XSZ GIZMHKLIGZGRLM
+GIVMXS V-TZWV GIVMXS
+GIRKOV GPZ-RS GIRKOV
+GILLK MZO-WVS-SR GILLK
+GIFXP XSRWL-GHL YRT ZFGL
+GBKV ZOGS-ZS-Z-GVS GBKV
+FMWVI YR-BZS FMWVI
+FMRWVMGRURVW WL-YZB-SLHVM-V FMRWVMGRURVW
+FMRG WZ-ZA-QZS FMRG
+FMHSZXPOV ML-WZ-VS-MVHS-TLSA FMHSZXPOV
+FMGRO FS-JFL-SL FMGRO
+ERXRMRGB MZ-SLH-ZS-TRS GSVIV ZYLFG
+EROOZTV XSZS-SL-LS-OSZM-RS NZMB HSVOGVI
+ERHRYRORGB MZB-VH-GVV ERHRYRORGB
+ERGZO GZ-VS-BV-HB ERGZO
+DZIMRMT YROS-SV-MVS DZIMRMT
+DZH MV-GVS DZH
+DZGVI GPLS DZGVI
+DZEV BROS-PLOS DZEV
+DVZKLM YVS-WZS-Z-SR-QRS-TZMR URTSGRMT DVZKLM
+DVOO GL-SZ-SZ-WOZB DVOO
+DSVM TOLV-VS-MZ-ZS-DL-SZR DVZHVO SVM
+DSVIV TOLV-RS-JFR-ZS DVZHVO SVIV
+DSRXS TOLV-RS-Z-SHR-GOLM DVZHVO GRVW GLTVGSVI
+DROO TOLV-RS-WLG-HZSR HRXP DVZHVO
+DRIV YVHS-GHLHRV HNZOO DRIV
+DRGS YROS DRGS
+DRGSRM YROS-YRTRS DRGS RM
+DRGSLFG GZ-TZRW DRGSLFG
+DLLW XSRA URIV DLLW
+DLFMW XZS-WZ-PSR DLFMW
+BZIW Z-WVO-GZSO BZIW
+ALMV YRS-MZ-SZH-WALS ALMV
diff --git a/2024/ferguson2/dict.orig b/2024/ferguson2/dict.orig
new file mode 100644
index 000000000..69c2ada85
--- /dev/null
+++ b/2024/ferguson2/dict.orig
@@ -0,0 +1,703 @@
+Z DLO-OZ-XSVV ZMG
+Z YV-OZ-HZMZ ZKKOV
+Z GHV-MROO ZCV
+Y MZ-SZHS-XSRW YZWTVI
+Y HSFHS YVZI
+Y GLRHS-QVS YZIIVO
+X NLZHR XZG
+X GOZ-TRM XLZO
+X YZ-TLHSR XLD
+W YV WVVI
+W XSRMWR WVERO
+W OSZ-XSZ-VS WLT
+V ZS-QZS VZI
+V WAVS VOP
+V ZS-MZS VBV
+U XSFL URI
+U GHZ-V-WLMRM-VV UOB
+U NZ-V ULC
+T ZS-GZW TRIO
+T PORAARV TLZG
+T QVSZ TFN
+S GHV-TZS SZRI
+S XSZ SZG
+S ORM SLIHV
+R GPRM RXV
+R BVS-SVH RGXS
+R Z-XSR RMGVHGRMV
+Q GPVOV-XSL-T QZXPZHH
+Q ZS-BZ-GHRMMV QZD
+Q BRO-WLR QVIP
+P QZW-SL-OLMR PVGGOV
+P YZ-ZS-MV-WR-GRMRM PVB
+P PORAARV-BZAARV PRW
+O WRYVS-BZAARV OZNY
+O ZS-QZW OVT
+O MZHS-WLRV-GHL ORLM
+N GHRM-GORGR NZGXS
+N YV-GZH-GMR NRIILI
+N MZ-ZH-GHL-HR NLFHV
+M GHZS MVVWOV
+M Z-XSRM MLHV
+L Z-PSZ LRO
+L GOL-XSRM LMRLM
+L MV-ZSH-QZS LDO
+K XOZ-TR-ZRS KZMG
+K YR-HL-WRS KRT
+K MV-ASLMR KIVGGB
+J XZ-BVROGS JFREVI
+I TZS IZYYRG
+I WZS-MVH-GHZ IZN
+I ZS-OLHA IRXV
+H WRYVS HSVVK
+H POVHS HMZPV
+G W-ZS GVZ
+G Z-DLS GLLGS
+G GSZM-ARV GFIPVB
+F HSR-WZ FMXOV
+F ML-WZ-RS FGV
+E Z-PVS-WR-TORMR ERXGLI
+D TOLV-RS DVZHVO
+C ZO-MZ-ZH-WALS XILHH
+B GHZS-ZH-ARS BFXXZ
+A YVHS-WL-GORA ARMX
+XLIKH WRM-MVS-RS XOZM
+WRERHRLM ZHSRS-SR HZOG
+IVTRNVMG GZYZSZ VWTV DZGVI
+YZGGZORLM GZXSVVMV IVW HLRO
+XLNKZMB MZPRZ NVCRXZM
+KOZGLLM SZH-XORHS-MRS NFW
+HVXGRLM BL-RS YVZWH
+HJFZW WVYVS-OR-ARMR YOZXP HSVVK
+
+XLNNZMWRMT TVMVIZO YRS-PVS-SV(T) DZI XSRVU
+NZQLI TVMVIZO HL-MZ-PRS GDL HGZI
+YIRTZWRVI TVMVIZO HL-Z-OZ-RS LMV HGZI
+XLOLMVO ZGHZS-YVHS-OV-TZR HROEVI VZTOV
+ORVFGVMZMG XLOLMVO XSV-XSRO-YV-GZS-YVHS-OVTZR HROEVI LZP OVZU
+NZQLI XSV-XSRO-YV-GZS-LOZ TLOW LZP OVZU
+XZKGZRM YVHS-OVTZR-MZS-PRS GDL HROEVI YZIH
+ORVFGVMZMG YVHS-OVTZR-Z-OZS-RS LMV HROEVI YZI
+XLNNZMWRMT LUURXVI SZHS-PZB-TR-MZ-GZS DZI XSRVU
+VCVXFGREV LUURXVI YRS-WZ-SLO-MVSR GSLHV RM XSZITV
+
+ZUIRXZ ASRM-MR YOZXPRVH
+ZOZHPZ YVS-STZ DRGS DRMGVI
+ZNVIRXZ MV-SV-NZS LFI NLGSVI
+ZFHGIZORZ XSZ-BVH-WVHR ILOOVW SZG
+YIRGZRM GLS-GZ YVGDVVM DZGVIH
+XSRMZ XVS-BVSH-YVHR YIZRWVW SZRI
+UIZMXV WZ-TSZ-SR YVZIW
+TVINZMB YVHS-YV-XSZ-SV RILM SZG
+RXVOZMW GPRM-PV-BZS RXV OZMW
+RMWRZ ZS-OV-TZR DSRGV XOLGSVH
+RGZOB WLS-SZ-XSR-BZOR-GXSR HGFGGVI
+QZKZM YVS-MZ-ZOR-GHLHRV HOZMG VBV
+KSRORKKRMV PV-BZS-WZ-MZ-OSV UOLZGRMT RHOZMW
+IFHHRZ HROZ-TLO-XSR-RS IVW ZINB
+HLFGS ZNVIRXZ HSZ-WV-ZS-MV-SR-NZS HLFGS LFI NLGSVI
+HKZRM WVYZ-WV-MRS HSVVK KZRM
+
+KOZMVH DL-GZS-WV-MV-RS ZRI ULIXV
+WREV YLNYVI TRMR XSRXPVM SZDP
+GLIKVWL KOZMV GZH-XSRAARV HDZOOLD
+LYH KOZMV MV-ZH-QZS LDO
+URTSGVI KOZMV WZ-SV-GRS-SR SFNNRMT YRIW
+YLNYVI KOZMV QZB-HSL YFAAZIW
+KZGILO KOZMV TZ-TRS XILD
+GIZMHKLIG ZGHZS VZTOV
+
+HSRKH GLS-WRMVS-RS HVZ ULIXV
+YZGGOVHSRK OL-GHL DSZOV
+ZRIXIZUG GHRWR-NLUUZ-BV-SR YRIW XZIIRVI
+HFYNZIRMV YVHS-OL RILM URHS
+NRMV HDVVKVI XSZ YVZEVI
+WVHGILBVI XZ-OL HSZIP
+GIZMHKLIG WRMVS-MZB-BV-SR NZM XZIIRVI
+XIFRHVI OL-GHL-BZAARV HNZOO DSZOV
+NLHJFRGL YLZG GHV-V NLHJFRGL
+QZMFZIB ZGHZS-YV-BZA HNZOO VZTOV
+UVYIFZIB DLA-XSVRMW HJFVZPB ELRXV
+NZIXS GZS-XSROO HNZOO KOZMG
+ZKIRO GZS-GHL YRT KOZMG
+NZB GZS-GHLHRV HNZOO KOZMG
+QFMV YV-MV-VS-VS-QZS-GHL YRT KOZMGRMT
+QFOB YV-MV-GZ-GHLHRV HNZOO SZIEVHG
+ZFTFHG YV-MVVM-GZ-GHL YRT SZIEVHG
+HVKGVNYVI TSZD-QRS SZOU
+LXGLYVI MRO-XSR-GHLHRV HNZOO DRMW
+MLEVNYVI MRO-XSR-GHL YRT DRMW
+WVXVNYVI BZH-MRO-GVH XIFHGVW HMLD
+
+ZYZMWLM BV-GHZM IFM ZDZB UILN
+ZYLFG DLOZ-XSR-Z-NLUUZ-TZSM ZMG URTSG
+ZYIVZHG DLOZ-XSVV-YV-BRVW ZMG YIVZHG
+ZXXLNKORHS FO-HL ZOO WLMV
+ZXXLIWRMT YV-PZ-SL ZXXLIWRMT GL
+ZXPMLDOVWTV SZMLG-WARVW ZXPMLDOVWTV
+ZXGRLM ZS-SZ-GRMS KOZXV LU ZXGRLM
+ZXGRERGB ZS-SZ-GRMS-B ZXGRLM VMWRMT RM B
+ZWVJFZGV YVS-TSZ VMLFTS
+ZWWRGRLM RS-SV-WV-MWVO ZWWRGRLM
+ZWWIVHH BR-XSRM-SZ-GHV ZWWIVHH
+ZWQZXVMG YV-TZSR MVZI
+ZWQFHG SZH-GZR-MVO-PZW ZWQFHG
+ZWEZMXV MZH-HVB ZSVZW
+ZWERHV MZ-MVGRM ZWERHV
+ZVIRZO YV-ALMA HGRMTVI
+ZUURINZGREV OZMS ZUURINZGREV
+ZUGVI YR-PSZ-WR(Z) ZUGVI
+ZTZRMHG YV-MZ-TMRHS ZTZRMHG
+ZRW VWZ-VOV-GHLLW ZRW
+ZRI MROXSR ZRI
+ZRIWLNV MROXSR-YVTSZM ZRIWLNV
+ZOVIG SZ-RS-WVH-VV ZOVIG
+ZOO GZ-Z-GZS(Z) ZOO
+ZOORVH MRS-SR-XSL ZOORVH
+ZOLMT DLOZXSVV-HMVA OLMT ZMG
+ZOHL VS-WL ZOHL
+ZOGVIMZGV MZ-PVV-TL-MV-MZM-WVB-SV HVXLMW KLHRGRLM
+ZNYFHS PSZX-WZ ZNYFHS
+ZNNFMRGRLM YVS-VOR-WLS-YV-XZS-ZOR-GZH-ZR ZNNFMRGRLM
+ZNKSRYRLFH XSZO UILT
+ZMW WL ZMW
+ZMTOV WVV-XZSM HOZMGRMT
+ZMMVC RS-MZB-GZMR ZWWRGRLM
+ZMMLFMXV YVS-SZ-L-WAV ZMMLFMXV
+ZMGR DLO-OZ-XSVV-GHRM ZMG RXV
+ZMGRXRKZGV MR-QLO-ORS ZMGRXRKZGV
+ZMB GZS-SZ-WZS ZMB
+ZKKVZI BV-PZ-SZ-BZ ZKKVZI
+ZKKILZXS YR-XSR-LO-WZS ZKKILZXS
+ZKKILCRNZGV GL-PFH-WZM ZKKILCRNZGV
+ZIV TZS-GHL YRT IZYYRG
+ZIVZ SZA-Z-TRS ZIVZ
+ZINLI YVHS-BV-SZ-WZ-WR-GVS RILM KILGVXGLI
+ZINB OVR-XSZ-RS-BRO-PMVV-RS ZINB
+ZIIREV RO-WZB ZIIREV
+ZIGROOVIB YV-ZO-WLS-GHL-OZMR NZMB YRT TFMH
+ZH ZSXV ZH
+ZHHZFOG ZOGHVS-V-QZS-SV URIHG HGIRPVI
+ZHHVNYOV WV-QR-PZHS YFMXS GLTVGSVI
+ZHHRTM YZS-WVS-GZSM ZHHRTM
+ZG ZS-WR ZG
+ZGGZXP ZO-GZS-QV-QZB ZGGZXP
+ZGGVNKG YL-L-MV-GZS(Z) GIB
+ZGGVMGRLM TRSZ ZGGVMGRLM
+ZFGSVMGRXZGLI SZMR-YZ-ZS-SL-ARM PMLD ZYLFG
+ZFGSLIRAV YV-YL-SL-HMVV ZFGSLIRAV
+ZEZROZYOV GZ-HSLA-GVS-RS ZEZROZYOV
+
+YZTTZTV POZROS(Y) YZTTZTV
+YZMAZR MV-GZS ULLO GSVN
+YZITV YVHS-MZ-VOG YZITV
+YZIIZTV YVHS-YZ-DZ-XSRMW YZIIZTV
+YZIIRVI YRS-XSZM-MR-ZS RM GSV DZB
+YZHV YRS-GHVV-WRS YZHV
+YZGGVIB YRS-YV-ZO-WLS-GPZ-RS GSIVV TFMH
+YZGGOV WZ-ZS-SR-WAR-GHRL YZGGOV
+YZB GLS-ZS-SR-TSRMS YZB
+YZALLPZ ZS-ASLO YZALLPZ
+YV GHVH-MZS YVV
+YVZXS GZS-YZSM(Y) YVZXS
+YVVM GHVH-MZS-MVH-XSVV YVV MFG
+YVULIV YRS-GHV-WRS YVULIV
+YVTRM SZ-SLO-ARA XLNNVMXV UILN
+YVOLMT GHVH-MZS-HMVA OLMT YVV
+YVGDVVM YR-GZS-PRA YVGDVVM
+YVBLMW YROS-OZ WR WLDM YVOLD
+YRELFZX VSO-MZH-GVS YIFHS HSVOGVI
+YLNY Z-BV-HSR VTTH
+YLLYB GIZK WRMVS-YZ-DSLZ-YOVSR NZM GIZK
+YLIMV BV-XSRV-GHZS YLIM VOP
+YLFMWZIB PZ-BZS-YR-MZ-SZH-WALS(Y) YLFMWZIB
+YFOO WLAVI WLOZ-ZOGS-DSLHS YFOO HOVVK
+YFMPVI GHZH-PZ HZMWB SLOOLD
+YFG MVS-WRS YFG
+YB YV-TSZ YB
+
+XZYOV YVHS-OPLS DRIV ILKV
+XZORYVI MZSO-PRSW NLEV ZILFMW
+XZNK GL-ZOGHVS-SLTZM GVNKLIZIB KOZXV
+XZNLFUOZTV WR-MVH-RS SRW
+XZM BZS-WR-ARMR XZM
+XZMMLMVVI YV-ZO-WLS-GHL-WVB-WRO-WLM-RTR YRT TFM LKVIZGLI
+XZKZXRGB YV-MVO-ZS XZKZXRGB
+XZKGFIV BRH-MZS XZKGFIV
+XZIIB BL-OZROS XZIIB
+XZHV YRG-HZS XZHV
+XZHFZOGB YRS-WRM-MV-WVB KFG LFG LU ZXGRLM
+XZFHV YR-MRS-MZMR XZFHV
+XZEV GHZ-LMW ILXP XZEV
+XVRORMT WZ-GVO-QZB HVZO
+XVNVGVIB QRHS-XSZ ZNLMT WVEROH
+XVMGVI FOS-MV-RS XVMGVI
+XSZMTV GSOZ-TL-Z-MZG-AZS XSZMTV
+XSZMMVO SZ-GZOSR-BZAARV HNZOO HRMTVI
+XSZITV ZS-GZS-TR-QZS XSZITV
+XSVNRXZO GZ-MVV ZOPZOR
+XRIXOV MZH-KZH XRIXOV
+XRIXFRG ZS-SVS-SZ-WZROS XRIXFRG
+XOZHH ZOGS-ZS-Z-GVS XOZHH
+XOVZI BL-ZS-SLO-ASLW XOVZI
+XORUU GHV-BV-XSVV XORUU
+XOLHV FO-XSR-FS-MZO-BZS XOLHV
+XLZHG TFZIW GZ-YZH-WHRHHR HSLIV IFMMVI
+XLWV BRO-GZH KVXP
+XLOLM MZPR-ZOS--WVS-WZ-ZO-ASRM GDL HKLGH
+XLOFNM ZOGS-PZB-MV-ARS XLOFNM
+XLNYZG WZ-ZS-SR-QRS-TZMS URTSGRMT
+XLNYRMZGRLM ZO-GPZH-VR NRCVW
+XLNV SFX-JFL XLNV
+XLNNZ GHZ-MZ-WZSO GZRO WILK
+XLNNVIXRZO MZR-VO-MV-SR XLNNVIXRZO
+XLNNRG SFX-JFL-OZ-QRHS XLNV TOLEV
+XLNNFMRXZGRLM SZ-MVS-ZO-VMQR NZPRMT GZOP
+XLMXVZO YV-PR-ZHA-QLOV XLMXVZO
+XLMXVMGIZGRLM GZ-OZ-SR-QRS LMV KOZXV
+XLMXFHHRLM DSV-SFH-WRO XLMXFHHRLM
+XLMWRGRLM ZS-SL-GZR SLD RG RH
+XLMUVIVMXV YV-PV-BZ-GR GZOP LEVI
+XLMURWVMGRZO MZ-MRO-RM PVKG HVXIVG
+XLMURIN GZ-Z-MVS NZPV HFIV
+XLMJFVI Z-PVS-WVH-WORM DLM
+XLMHRWVI MV-GHZ-XZH GSRMP RG LEVI
+XLMHRHG YROS(X) XLMHRHG
+XLMHLORWZGV ZS-SRS-SR-MRO KFG GLTVGSVI
+XLMHGIFXG ZSO-MVS GL NZPV
+XLMGZXG ZS-SR-WR-WZRO XLNV GLTVGSVI
+XLMGRMFV GZ-BR-GVS XLMGRMFV
+XLMGILO MZR-TSRA XLMGILO
+XLMELB GPZO-PZS-L-MVO NLERMT LM DZGVI
+XLLIWRMZGV YVS-VS-SL-ARM-MZ-ZH-WALS PMLDM ORMVH
+XLFMGVI ZGGZXP DLOGZS-ZO-PR-TR-QVS XLFMGVI ZXG
+XLFIHV XL-QR-TLS XLFIHV
+XIZUG ZS-GLS MVHG
+XIVVP GLS-MRO-GHZMS EVIB ORGGOV DZGVI
+XILHH ZO-M-ZH-WALS XILHH
+XFY HSFHS-BZSA XFY
+
+WZHS FH-WALS WZHS
+WZDM SZ-BVOR-PZSM WZDM
+WVUVMHV ZS-PRM-XRO-GLS WVUVMHV
+WVTIVV MZSO-PRSW WVTIVV
+WVOZB YV-HRGRSM WVVI OZB
+WVOREVI YV-YRS-ARSWV WVVI OREVI
+WVNLORGRLM ZS-WVVO-GZSR YOLD FK
+WVMHV SL-WROS-XOZ(W) DVG
+WVKZIG WZ-WV-BZS WVKZIG
+WVKZIGNVMG SLTZM WVKZIGNVMG
+WVHRTMZGV BV-PSR-WVO-MVR KLRMG LFG
+WVHKVIZGV ZS-WZ-ZS-SL-WAZS WLDM GL OZHG
+WVGZXS ZO-XSZ-MRO WVGZXSVW
+WVGZRO YV-YVS-HSZ WVVI GZRO
+WVGLMZGLI ZS-WVVO-GZSR(LI) YOLDM FK
+WRUURXFOG MZ-MV-POZS WRUURXFOG
+WRT-RM OV-VS-TZWV WRT RM
+WRIVXG ZS-QR-TL WRIVXG
+WRHVNYZIP VS-SZ-QZB TVG LFG
+WRHKZGXS OZ-XSZR-VM-HVRH-YV-QZB WLT RH KZGXS
+WRHKOZXV SRS-WL-MZO NLEV
+WRHKOZB YV-HVRH-MZ-MVS WVVI RH KOZB
+WRHKLHRGRLM Z-SL-GVB WRHKLHRGRLM
+WRHGIRYFGV MZS-MVS WRHGIRYFGV
+WRHGIRXG YV-GSRM-BZ-MR-XSV WVVI RXV HGIRXG
+WL GHV-OV HNZOO KFK
+WLXFNVMG YVS-VS-SL-ARMA WLXFNVMG
+WIREV ZS-MLO-PZSO WIREV
+WFW WR-TRHH-BZSARV HNZOO WFNNB
+WFNNB WR-TRHH-GHL YRT WFNNB
+
+VZXS GZ-OZSR-MV-ARMR-TL(W) VZXS
+VXSVOLM DSL-WAZS ORMV
+VWTV YV-YZ-SR VWTV
+VUUVXGREV YV-WVOS-MVVW VUUVXGREV
+VUULIG BVZ-TL DRGS ZOO BLFI NRTSG
+VOVNVMG ZS-MZ-MZR GILLK IVKIVHVMGRMT LGSVIH
+VOVEZGV ZOR-PSR-SL-MV-LSZ VOVEZGV
+VORNRMZGV SZ-YVS-GL-WARO VORNRMZGV
+VNYZIP VS-SL-QZB TVG LM
+VNVITVMXB SL-MVA-XOZ VNVITVMXB
+VNKOZXVNVMG OZ-ZA-MRO VNKOZXVNVMG
+VMXRIXOV BV-MZH-GVS(V) VMXRIXOV
+VMXLFMGVI YR-PSZMS TL ZTZRMHG
+VMTZTV Z-SZ-MV-SL-GZ ZTIVVW
+VMTRMV XSRWR-YR-GHR-GHRMV(V) VMTRMV
+VMTRMVVI WZB-WRO-QZS-SV VMTRMVVI
+VMOZITV MRS-GHZ-TLS-ZO-MVS NZPV YRT
+VMORHG YRS-ARS-Z-WZ-BR-OZS VMORHG
+VMGRIV GZ-Z-GZS(V) VMGRIV
+VMGIVMXS V-TZW-ZS-MV-ORS NZPV WRGXS
+VMEVOLK Z-AZS-TR-BZ VMEVOLK
+VJFRKNVMG BZ-SZ-WV-GZSR VJFRKNVMG
+VIVXG BVS-ARSM HGZMW FK
+VHXZKV Z-AVS-SZ-TV-BZS VHXZKV
+VHGZYORHS SZH-GZB-WAZS VHGZYORHS
+VHGRNZGV YRS-PV-GHV-SLW-WVH-PVA VHGRNZGV
+VEZXFZGV SZ-MZ VEZXFZGV
+VCXVKG MVS-WRS(V) VCXVKG
+VCXVKG MZ-DLO-MV VCKVXG
+VCXSZMTV ZOS-MZSO-BZS VCXSZMTV
+VCVXFGV Z-WL-MRO VCVXFGV
+VCKOLHREV ZS-WVO-GZSR(V) VCKOLHREV
+VCKVWRGV HSRO-OLS(V) HKVVW FK
+VCGVMW MV-GWZOV NZPV DRWV
+VCGIVNV ZO-GHZM-ZS-YZSN VZXS VMW
+
+UZRO XSZ-ZO-VRMW UZRO
+UZROFIV BVVH-TSRM UZROFIV
+UZIN NZR-YV-SV-ZSTZM ULC ZIN
+UVVW WAVS-XSR-BLM UVVW
+URVOW XOL-WRS(U) URVOW
+URVIXV GLS-YZS-SZ-AHRW ZUIZRW
+UROV YZ-VS-XSVA UROV
+URMZO GZS-ZS-PDL-WRS GSZG RH ZOO
+UOZNV GSILDVI XLS-ZS-TSRO-GORW UOZNV GSILDVI
+UOZMP WZS-WR-PZW UOZMP
+UOZIV DL-XSR ORTSG HGIVZP
+UORTSG NZ-V-ZH-AOLOR ULC ORTSG
+ULIXV GZ-MZ-MV-OZWR DRGSLFG XZIV
+ULIN YV-XSZ ULIN
+ULINZGRLM YV-XSZ-BV-OZROS ULINZGRLM
+ULIGRURXZGRLM ZS-MZ-HLAR XORUU WDVOORMT
+ULIGRUB ZS-MZ-HLAR-BZAARV HNZOO ULIGRURXZGRLM
+ULIDZIW GVSR OVG'H TL
+UIZTNVMGZGRLM YVHS-BZAARV HNZOO NVGZO
+UIVJFVMXB SZ-GZOSR-GHL YRT HRMTVI
+UIRVMWOB MVS-SVXSL-WZ-MV UIRVMWOB
+UILN YR-GHZM-WVSM UILN
+UFIMRHS BVZH-MRO(U) UFIMRHS
+UFIGSVI DL-MZH-WR UFIGSVI
+TZIIRHLM BZS-Z-WZ-SZO-BLM-RS GZPV XZIV LU
+TZHLORMV XSRWR-YR-GLS TZHLORMV
+TIVMZWV MR-NZ-HR KLGZGLVH
+TFZIW MR-WRS-WZ-SR TFZIW
+TFRWV MZS-V-GSOZR TFRWV
+SZOO OSR-GZ-Z-GZ SLIHV ZOO
+SZOU GIZXP ZOS-MRS-QZS-Z-JFSV IZXV GIZXP
+SZOG GZ-ZPDZR-R SZOG
+SZMWOV YVG-HVVM SZMWOV
+SZEV QL SZEV
+SVZWJFZIGVI MZ-SZ-GZS-GZ-YZ-SLTZM SVZWJFZIGVI
+SVOW DL-GZS-GZ-VS-WZSM-LS SVOW(KZHG GVMHV)
+SRTS DL-GZS SRTS
+SRTS VCKOLHREV YV-ZO-WLS-YV-XZ-YRS-WARO-RTR KLDVIUFO HSVOO
+SRTSDZB DL-GZS-SL-MV-GVS SRTS DZB
+SLOW DL-GPZMS SLOW
+SLHKRGZO Z-AVB-ZO-RS KOZXV LU NVWRXRMV
+SLHGROV Z-MZS-MV-WARM MLG UIRVMWOB
+SLDRGAVI YV-VO-WLM-GH-JFLWR HSLIG YRT TFM
+
+ROOFNRMZGV DL-XSR(R) ORTSG FK
+RNNVWRZGVOB HSRO-OLS(R) RNNVWRZGVOB
+RNKZXG Z-SV-WRH-TLS RNKZXG
+RNKLIGZMG YZ-SZH-GVS RNKLIGZMG
+RNKILEV SL-WLO-ASLMW RNKILEV
+RMXOFWV VO-GHLW RMXOFWV
+RMXIVZHV SL-MZOS RMXIVZHV
+RMWRXZGV YZ-SZO-MVS GVOO ZYLFG
+RMUZMGIB GZ-MVS-MZO-WZSR RMUZMGIB
+RMUROGIZGV BV-TSZ-MV-QVS DVMG GSILFTS
+RMRGRZO YVS-VW-WV-WORW YIZMW
+RMHGZOO VSW-GMZS RMHGZOO
+RMHGZOOZGRLM MZH-MRO RM KOZXV
+RMHGIFXG MZ-MV-GTRM GVZXS
+RLXXX Z-XSR-MV-ZSH-QZS-YZ-TLHSR-YZ-TLHSR-YZ-TLHSR HVXIVG
+RMGVOORTVMXV SL-BZ(R) HNZIG
+RMGVMHV WAVVO HGIVMTGS
+RMGVIXVKG BVO-MZ-NV-QZS RMGVIXVKG
+RMGVIUVIV ZS-MROS-PSOZR RMGVIUVIV
+RMGVIKIVG ZS-GZS-SZ-MV RMGVIKIVG
+RMEVHGRTZGV MZ-ZOR-PZ GIZXP
+RMELOEV Z-GZS RMELOEV
+RH HVRH HVEVM
+RHOZMW HVRH-PVBZS HVEVM RHOZMW
+RHLOZGV YRS-GHZ-MVO-PZW HVKZIZGV
+
+QFMTOV DLS-WR-XSRO QFMTOV
+
+PROO MZA-GHZRW PROO
+PROLXBXOV MZH-GHZRW-Z-PSZ-ZS-BVS-SZ-WROS PROO LRO TL ZILFMW
+
+OZYLI MZ-MRHS(O) OZYLI
+OZMW PZB-BZS OZMW
+OZFMXS GPZ-TSRO-ASLW OZFMXS
+OVZWVI ZS-MZ-TSZR OVZWVI
+OVZHG WV-YV-BZARV-SZ-Z-ZS OZNY UVZHG
+OVZEV WZS-WV-BZS SV OVUG
+OVUG MRHS-XOZ-QRS-TLS OVUG
+OVHH YR-LS(O) OVHH
+OVEVO WRO-PLMS OVEVO
+ORZRHLM WZ-Z-SV-TR-VMVS PMLD LGSVI'H ZXGRLM
+ORNRG YZ-SZH-ZS ORNRG
+ORGGVI MR-WZH-GLM(O) HXZGGVI
+OLXZGV Z-PDV-VS HKLG
+OLHH FG-WRM OLHH
+
+NZXSRMV TFM Z-PMZS-ZH-WLMRS IZKRW URIV TFM
+NZTMVGRX MZ-V-OZSR KRXP FK
+NZMZTV SZHGMR-YVS-MZ-SZR NZM ZTV
+NZMVFEVI MZ-MZ-L-MZOGS NLERMT ZILFMW
+NZK PZS-BZ-MVHS-XSZR NZK
+NZCRNFN YVO-WRO-PSLM UROO GL GLK
+NVXSZMRX XSRGR-Z-MZBO-RMRS ZFGL IVKZRINZM
+NVXSZMRAVW XSRWR-WZ-ZS-SV-TLMR URTSGRMT XZIH
+NVWRXZO Z-AZB NVWRXRMV
+NVTZXBXOV NRO-ZS-SVS-ZS-WROS NROORLM TL ZILFMW
+NVIXSZMG HSRK MZ-VO-MVSR-GHRM-MZ-ZROS NVIXSZMG HSRK
+NVHHZTV SZMV-ZO-MVS NVHHZTV
+NRORGZIB HROZTL-PVS-TLS NRORGZIB
+NROORNVGVI MZ-ZH-GHL-HR-Z-BV-WL-GRHS WLFYOV NLFHV
+NRMV SZ-TZWV NRMV
+NRMRNFN YV-LS(N) NRMRNFN
+NRMFGV ZS-PSZB-VO-PRG-BZAARV ORGGOV SLFI
+NRHHRLM ZO-MVHSLWR NRHHRLM
+NRHGZPV L-ASR NRHH
+NLKKRMT SZ-GZL-WR NLKKRMT
+NLIV GSOZ-MZ-MZS NLIV
+NLIGZI YV-ZO-WLS-XRW-WZ-SR HRGGRMT TFM
+NLGRLM MZ-SLG-MZS NLGRLM
+NLGLI XSRWV-YV-GHV-GHVM XZI SVZW
+
+MZGREV PZ-SZ-GVMR MZGREV
+MZEB GZO-PZS-HROZTL HVZ HLOWRVI
+MVXVHHZIB BV-MZ-AVSM DZMG
+MVTZGREV WL-BZ-HSL-WZ ML TLLW
+MVG MZ-MVH-WRAR MVG
+MVFGIZO WL-MVS-ORMR MVFGIZO
+MLINZO WLS-Z-GZ-S-WZS MLINZO
+MLG MR-WZS-GSZM-ARV ML GFIPVB
+MLGRXV MV-WZ-GZAR-GSRM ML GFIPVB RXV
+MLD PFG MLD
+MFNYVI YVS-YRS-PV-ZH-XSRMRTS DSZG'H DIRGGVM
+
+LYQVXGREV YR-MV-BVR TLZO
+LYHVIEV SZO-ARW LYHVIEV
+LYHGZXOV WZ-SL-WVHS-ASZ LYHGZXOV
+LXXFKB BVVO-GHLW GZPVM
+LU GLS-MR-GPZO-OL LXVZM URHS
+LUUVMHREV YRM-PRV-QRMS-QRS-WVA-QZB LUUVMHREV
+LMXV GZ-OZR-WR LMXV
+LMOB GZ-VR-GZB-Z-BZS LMOB
+LKVIZGV BV-MZSO-MRHS DLIP ZG
+LKKLIGFMRGB ZHS-TZ-ZORM LKKLIGFMRGB
+LKKLHRGRLM MV-SV-GHZS-QRS-HSRM LKKLHRGRLM
+LI VS-WL-WZS-TLS VRGSVI
+LIZMTV GXSRO-OSV-HLR LIZMTV
+LIWVI YV-VS-SL-ARMR LIWVI
+LIWMZMXV OVR-ZA-QZS FMWVI TILFMW
+LIRTRMZGV WZH-GVS-WL YVTRM
+LGSVI OZ-V-XRS LGSVI
+LFG XOL-WRS LFG HRWV
+LEVIOZB YV-PZ-SZH-GHLA LEVIOZB
+
+KZIVMGSVHRH ZGHZMS IRY
+KZIGRXFOZI Z-BL-ZW-WL-MVS KZIGRXFOZI
+KZIGB WZ-HSZ-QZS KZIGB
+KZB MZ-VOR-BZ KZB
+KVMZORAV GZS-MR-WVH-GZMS HVG YZXP
+KVIXVMG BZO NLMVB
+KVIRLW WZ-ZSO-ASRM KVIRLW
+KVIRLWRX WZ-ZO-ASRM-GSRM-NLZHR KVIRLW RXV XZG
+KVINRG TLH-HSR-V KVINRG
+KVIHLMMVO WZ-MV-OVR NVNYVI
+KSLGLTIZKS YVS-XSR-NZ-SZW-MRO KSLGLTIZKS
+KROO YLC YR-HL-WRS-WLG-HZSR-YR-GHZS HRXP KRT YLC
+KRMMVW WLDM YRO-WZS-SZH-GZMS-BZ KRMMVW WLDM
+KOZMV GHRWR YRIW
+KOZHNZ WRO-WR-TSROR KOZHNZ
+KLRMG YV-HL-WV-WVA-ZSV KRT KLRMG
+KLMGLLM GPLHS-QZS-WZ-MZ-VOG UOLZGRMT YZIIVO
+KLHRGRLM YROS-SZH-ZSM KLHRGRLM
+KLHHRYOV GZ-SZ-ZS-GZB KLHHRYOV
+KLHG HZS-WVR KLHG
+KIVKZIV SZHS-GZB-SL-WRG-MV KIVKZIV
+KIVHVMG PFG KIVHVMG
+KIVERLFH YRS-GHV-WRS KIVERLFH
+KIRNZIB ZOGHVS-MZM-WZB-SR-TRS 1HG KLHRGRLM
+KIRLIRGB SZMV-KVHLWR KIRLIRGB
+KILYZYOV WZ-GHR KILYZYOV
+KILYOVN MZ-MRHS-GHLS YRT QLY
+KILXVVW MZB-MRS-QRS TL
+KILTIVHH MZS-HZR KILTIVHH
+KILGVXG ZS-XSZMS HVOU WVUVMHV
+KILERWV BRH-MRO KILERWV
+KFIKOV WRMO-XSR KFIKOV
+KBILGVXSMRX XLS-MZ-XSZMS UZMXB URIV
+
+JFVHGRLM ZS-QZS VZI
+JFRXP HSRO-OLS JFRXP
+
+IZWZI VHZG-GHZMS(I) ORHGVM
+IZRW WVAQZB IZRW
+IZROSVZW Z-WV-TVS-SR HSRKKRMT KLRMG
+IZROILZW PLMS-MZ-ZO-YZMHR-YR-GSRM IZROILZW
+IZOOBRMT Z-OZS-MZ-L-TOZORS TZGSVIRMT
+IZMTV ZM-AZS WRHGZMXV
+IZGV TZS-VS-BZSM IZYYRG ZGV
+IZGRLM MZ-Z-QZS IZGRLM
+IZERMV XSFHS-PZ(I) IZERMV
+IVZXS RO-WZB(I) IVZXS
+IVZWB PFG(I) IVZWB
+IVZI YV-PZ-WVMS(I) IVZI
+IVXVRKG HSLA-GVS IVXVRKG
+IVXLNNVMW XSV-SL-GZR-GZSM IVXLNNVMW
+IVXLMMZRHHZMXV SZ-Z-XRWR RMHKVXGLI
+IVXLMMLRGVI GZ-SZ-MV-ZO-BZ NZPV HFIV
+IVXLIW TZS-ZS-MZS-POLOR I-V-ILKV
+IVW OR-XSR IVW
+IVVU GHZ-ASRM YOZXP ILXP
+IVVNYZIP VS-MZ-XLS TL RM
+IVURIV MZ-MZ-XLS IVURIV
+IVTFOZGV MZ-BVO-M IVTFOZGV
+IVRMULIXV MZO-WARO IVRMULIXV
+IVORVU ZTZMS-GLO-QZB IVORVU
+IVORVEV MZS-QRS-XL-MZO-BZ IVNLEV
+IVLITZMRAV SZ-WRG-AZS IVLITZMRAV
+IVKOZXVNVMG MR-MZ-WL-MRO IVKOZXVNVMG
+IVKLIG DSL-MVS TLG DLIW
+IVKIVHVMGZGREV GPZ-MZA-MROR GIRKOV NVM
+IVJFVHG QL-PZBVW-TLS ZHP ULI
+IVHVIEV SVHS-Q-V IVHVIEV
+IVHGIRXG YZ-SL-XSRMR IVHGIRXG
+IVGRIV ZS-SLH-GVVMW IVGRIV
+IVGIVZG QR-WRM-MVH-XSZMS IVGIVZG
+IVGFIM MZ-WAZS XZNV YZXP
+IVEVZO DSL-MVS(O) IVEVZO
+IVEVIG MZ-HR-BRA GFIM ZYLFG
+IVEVGNVMG YZ-MZH-XOZ(I) XLIMVI
+IRWTV TZS-TSRO-PVRW IZYYRG IRWTV
+IRUOVNZM YV-ZO-WL-SLHGVVM IRUOVNVM
+IREVI GLS-BRO-PZO NFXS DZGVI
+ILYLG YLNY Z-BV-HSR-MZ-GZS-RS VTT UOB
+ILXPVG OVHA-BRO-YVHSR HZMW YLRO
+ILOO BVS-NZH ILOO
+ILFMW MZA-KZH(I) ILFMW
+ILFGV TZS-YRS-GPVVM IZYYRG GIZRO
+IFMMVI MRS-WARW-GVRS IFMMVI
+
+HZYLGZTV Z-GPVO-BZS SRMWVIVW
+HZYLGVFI Z-GPVO-VO-RMR GILFYOV NZPVI
+HZROLI XSZ-OV-TZR DSRGV XZKH
+HZOEZTV MZ-SZH-TOZS KRXP GSVN FK
+HZG YRS-OZ-HZMZ-XRW-WZ-SR ZKKOV HRGGRMT
+HXZIOVG IVW OSV-XSR(H & I) IVW
+HXSVWFOV YVS-VS-SL-ARMR HXSVWFOV
+HXLFG SZ-Z-HRW-ZO-HRAR-TRS HSLIG IZXXLLM
+HXIVVM YVHS-MZ-MVH-WRAR HXIVVM
+HVZNZM GPZO-PZS-WRMVS-RS HVZNZM
+HVXIVG YZS-SZH-GPRS HVXIVG
+HVXGLI BLVSR(H) HVXGLI
+HVXFIV BV-WASV-ZO-GHRHR HNZOO HVXFIRGB
+HVRAV BVVO-HGLW HVRAV
+HVOVXG YV-GZS-SZH-TOZ GLLP LFG
+HVNR XLOLM WZ-ZSO-ASRM-YR-GHZ-MZ-WZSO WLG WILK
+HVG WAVS-XRW-WZ-SR VOP HRGGRMT
+HSZXPOV WR-YZS-MVHS-TLSA HSZXPOV
+HSVOO YV-ZO-WLS-YV-XZ HSVOO
+HSLIV GZS-YZSM(H) HSLIV
+HSLIG YLHS-PVVHS HSLIG
+HRWV YLHS-PVVHS HRWV
+HRTSG BV-VO-GHZMS HVVM
+HRTMZO MZ-VS-VS-TRHS YB HRTMH
+HRNKOVC ZOZS-RS-MV-GRS RMMVI DRIV
+HRG GPRM-XRW-WZ-SR RXV HRGGRMT
+HRGFZGV Z-SL-GZB (H) HRGFZGV
+HNLPV ORG HNLPV
+HMRKVI LS-YVSR KRXP 'VN LUU
+HKZXV YV-GPZS YVGDVVM
+HKVXRZO V-BRS-HRS NZRM GSRMT
+HKVVW BL-ALMH HDRUG NLGRLM
+HKLIZWRX ZS-MZ-SL-MVRO MLD ZMW GSVM
+HKLGGVI VVO-GHZB-R HKLGGVI
+HKIZB POVHS-HL-WROARM HMZPV KIZB
+HJFZWILM MZS-TSRAR HJFZHS
+HGLIN MV-LO HGLIN
+HGIZUV MZ-DL-TSR-TLRW SLV
+HGIZTTOVI XSB-MV-WV-WZSV HGIZTTOVI
+HGIZGVTB MZ-SZ-GZS(H) HGIZGVTB
+HGIVZN GLS-MR-ORS IFMMRMT DZGVI
+HGIVMTGS WASVO HGIVMTGS
+HGIVGXS WVHA-GHLLW HGIVGXS
+HGIRPV MZB-WZO-TSZO HGIRPV
+HGIRK SZ-GRS-QZS HGIRK
+HGFYYLIM MRO-GZ HGFYYLIM
+HFYQVXG MZ-MRHS-BZAARV HNZOO QLY
+HFYNVITV GPZO-XOZ-BR-BZS DVMG FMWVI DZGVI
+HFYNRG Z-MRS-OVS HVMW
+HFYLIWRMZGV ZO-PSR-MZO-WAO SVOKRMT VZXS LGSVI
+HFXXVVW BZS-GZB-TL-V-VOZS NZPV TLLW
+HFXXVHH FG-AZS RG RH WLMV
+HFXXVHHUFO FG-AZS-SZ-WVA-YRM RG RH WLMV DVOO
+HFXXVHHREV FG-AZS-HRW HFXXVHH HXZI
+HFXS BRH-XOVS HLC
+HFUUVI GL-SL-MV HFUUVI
+HFNNZIB HSRM-TL-YZS HFNNVI NZIB
+HFKKOVNVMGZIB GPZ-TL-MV-MZM-WVB-SV 3IW KLHRGRLM
+HFKKOB MZO-BVS-SR HFKKOB
+HFKKOB HSRK MZOTZ-SR-GHRM-MZS-ZROS HFKKOB HSRK
+HFKKLIG YZ-ZS-SLG-TOR WVKVMW
+HFIIVMWVI MV-MZ-XSZ HFIIVMWVI
+HFIILFMW MZA-KZH(H) HFIILFMW
+HFIEREV BRH-WZ-BZ HFIEREV
+HBHGVN WR-YZ-GHZ-ZH-ASR-YR-GHRM HBHGVN
+
+GZXGRXZO V-XSRSM GZXGRXZO
+GZPV TZS-GZSM GZPV
+GZMP XSZB-WZ-TZSR GLIGLRHV
+GZMP WVHGILBVI XSZB-WZ-TZSR-MZRO-GHZRWR GLIGLRHV PROOVI
+GZITVG DLO-WLMR GZITVG
+GZHP GZAR-MZ-VS-WRO-PRW GFIPVB ZHP
+GVZN WVS-MZ-ZH-GHL-HR GVZ NLFHV
+GVIIZXV ZOR-PSR-SL-MV-LSZ(G) GVIIZXV
+GVIIZRM GZHSR-MZ-SZO-GSRM GFIPVB IZRM
+GVIIRGLIB PZ-BZS(G) GVIIRGLIB
+GSZG GZAR-XSZ GFIPVB SZG
+GSV XSZ-TVV YOFV-QZB
+GSVRI YRS GSVRI
+GSVIVZUGVI GZ-AR-PDZ-R-YV-PZ-WR GFIPVB SVIV ZUGVI
+GSVHV XSZ-TR-L-VS GSV HVV
+GSVB XSZ-TVV(B) GSV B
+GSRH WR GSV
+GLTVGSVI GZ-YROS GLTVGSVI
+GLIKVWL OL-YV-XZ URHS HSVOO
+GLGZO GZ-ZO-HL GLGZO
+GIZXVI YVS-MZ-ZO-PZS-SR GIZXVI
+GIZUURX WRZTIZN SZMV-YZ-MZ-ZH-WALS WRZTIZN HGLIB ORMV
+GIZRM XLS-MZR-ZOR-YZSM-HR GIZRM
+GIZMHKLIGZGRLM Z-SZS-WZ-Z-XSZ GIZMHKLIGZGRLM
+GIVMXS V-TZWV GIVMXS
+GIRKOV GPZ-RS GIRKOV
+GILLK MZO-WVS-SR GILLK
+GIFXP XSRWL-GHL YRT ZFGL
+GBKV ZOGS-ZS-Z-GVS GBKV
+
+FMWVI YR-BZS FMWVI
+FMRWVMGRURVW WL-YZB-SLHVM-V FMRWVMGRURVW
+FMRG WZ-ZA-QZS(F) FMRG
+FMHSZXPOV ML-WZ-VS-MVHS-TLSA FMHSZXPOV
+FMGRO FS-JFL-SL FMGRO
+
+ERXRMRGB MZ-SLH-ZS-TRS GSVIV ZYLFG
+EROOZTV XSZS-SL-LS-OSZM-RS NZMB HSVOGVI
+ERHRYRORGB MZB-VH-GVV ERHRYRORGB
+ERGZO GZ-VS-BV-HB ERGZO
+
+DZIMRMT YROS-SV-MVS(D) DZIMRMT
+DZH MV-GVS DZH
+DZGVI GPLS DZGVI
+DZEV BROS-PLOS DZEV
+DVZKLM YVS-WZS-Z-SR-QRS-TZMR URTSGRMT DVZKLM
+DVOO GL-SZ-SZ-WOZB DVOO
+DSVM TOLV-VS-MZ-ZS-DL-SZR DVZHVO SVM
+DSVIV TOLV-RS-JFR-ZS DVZHVO SVIV
+DSRXS TOLV-RS-Z-SHR-GOLM DVZHVO GRVW GLTVGSVI
+DROO TOLV-RS-WLG-HZSR HRXP DVZHVO
+DRIV YVHS-GHLHRV HNZOO DRIV
+DRGS YROS(D) DRGS
+DRGSRM YROS-YRTRS DRGS RM
+DRGSLFG GZ-TZRW DRGSLFG
+DLLW XSRA URIV DLLW
+DLFMW XZS-WZ-PSR DLFMW
+BZIW Z-WVO-GZSO BZIW
+ALMV YRS-MZ-SZH-WALS ALMV
diff --git a/2024/ferguson2/index.html b/2024/ferguson2/index.html
new file mode 100644
index 000000000..8cd0db9c2
--- /dev/null
+++ b/2024/ferguson2/index.html
@@ -0,0 +1,1975 @@
+
+
+
+
+
+
+
+
+
+
+
+
+2024/ferguson2 - Prize in yil-tas
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
./prog.alt 'some other string'
+ ./prog.alt +filename
+
Judges’ remarks:
+
The IOCCC is honored to present this entry with an award that, in turn,
+recognizes the Navajo code talkers
+who served with distinction during World War II.
Not fully declassified until 1968, the Navajo code remains the only oral military
+code that (was) never been broken (in the field of operations).
+
+
This submission encodes (pun intended) the basic algorithm used by Navajo code talkers
+to encode and decode messages. We invite you to attempt to decipher the C code,
+and then to explore the fascinating cryptographic history of Code talking.
+
On a personal IOCCC Judge note
+
One of the IOCCC Judges had the unique opportunity to engage in
+discussions with code talkers, sharing insights into the intricacies of
+the code as well as the practical variations that were developed in the
+field between pairs of code talkers.
+
The discussion provided some fascinating insights into the amazing
+Navajo language
+including its unique grammar, and examples of some of the intricate
+nuances available to a native fluent speaker. Due to the complex
+syntax, phonology, and numerous dialects available in the Navajo
+language, the IOCCC Judge was only able to grasp a superficial
+understanding of the topic. Nevertheless, it was evident to the
+IOCCC Judge, why the Navajo language developed an ideal code talker
+framework during World War II, and it is worth noting that
+fewer than 30 non-Navajo individuals
+could comprehend the language during World War II.
+
Author’s remarks:
+
Navajo Code Talker language of the Second World War
+
This entry (ctt) is a translator of the Navajo Code Talker language used in
+the Second World War.
+
However since the language is too long for the iocccsize restrictions I have
+had to read in the dictionary from a file (default dict defined in the
+Makefile so one can override this - if they figure out the format anyway, as
+that is also somewhat encrypted, albeit not much, though I explain the details
+later on).
+
At the same time I have made it more fun because I have made it so that one can
+translate back and forth words that were not in the dictionary. This is done
+because we have the alphabet as well so we can simply spell out words; the Code
+Talkers also did this so this is completely in line with a translator. That’s
+done with the alt code with a different definition of the macro X, although as
+you’ll see there are some differences in the code (not just format but
+output too).
+
A note about the iocccsize and the dictionary. If you take a look you’ll see
+that the alphabet is in the source code (well some of it: the letters that have
+more than one translation only have one again for the reason noted). Actually
+the dictionary has the letters too but this is about all I could fit in and it
+offers for some fun obfuscation as well even though the alphabet is not
+enciphered (there was more than one word for each letter, or at least some if
+not all, however, and only one is included in the code).
+
The program does not include literal translations although it is possible to
+modify the code to do this. Instead it is the English to Navajo word that was
+used in the military; the literal translation was what it meant in their
+language.
+
With the DICT macro the dictionary is not hardcoded although the dictionary is
+not English in look. I discuss how it’s done here.
+
Who were the Code Talkers ?
+
One of the original Code Talkers had this fascinating thing to say:
+
+
We acted as coding machines, transmitting messages that would have taken a
+couple of hours in just a couple of minutes. We could never make a mistake,
+because many communications involved bombing coordinates.
+
– Navajo Code Talker Chester Nez in a 2012 interview with the website ArmchairGeneral.com.
+
+
This is one of the reasons I think this language should be in an IOCCC entry:
+they were coding machines, transmitting messages that would normally take hours
+but they did it in their head in just a couple of minutes!
Really funny story he tells in the book, although some of the finer details are
+from https://mishpacha.com/code-talkers/ as it’s been so long since I read it
+and I don’t feel like picking the book up: it was so top secret that when they
+were practising on a ship heading to Guadalcanal they were overheard on the
+radio but because it was top secret the rest of the ship thought that the
+Japanese cracked their communications. They were so concerned at first that they
+shut down communication to listen in.
+
In fact (and this comes from the website): it would appear that one of the radio
+operators overheard what he thought was Japanese. The ship’s officer thought so
+too. Then one of the admirals informed the commanders that there were marines on
+the ship who were communicating in their own language.
+
But how did it work ?
+
It had a two layer design. Let’s say someone intercepts the word for CODE:
+YIL-TAS. In the case they don’t know what that Navajo word means they’re lost.
+But even if they do they’ll instead interpret it as Navajo for PECK which means
+nothing useful in the context of the war.
+
Not all words had this. For instance CONTROL: NAI-GHIZ is the literal
+translation of CONTROL.
+
Some were rather close as well: ‘COUNTER ATTACK’ was WOLTAH-AL-KI-GI-JEH
+which translates to ‘COUNTER ACT’. If a word was not coded they could spell out
+the word which is exactly what I do here as well (as noted earlier, I think).
+
And on the subject of how it worked: I decided to not put a man page about this
+submission because the language was so secret that they could not have a manual
+either! I will explain the syntax though which really is all that’s needed; that
+and the limitations/bugs section (though they’re not strictly bugs).
+
The Navajo Code Talker’s Dictionary
+
The dictionary can be found at the US Navy history website Navajo Code Talkers’
+Dictionary.
+But alternatively you can find it in the file dict. Looking at this file will
+be useful to help you understand some of the output assuming dict is not
+encrypted itself (and of course it is but not as complicated as any of the Code
+Talkers; see explanation here).
When a Navajo code talker received a message, what he heard was a string of
+seemingly unrelated Navajo words. The code talker first had to translate each
+Navajo word into its English equivalent. Then he used only the first letter of
+the English equivalent in spelling an English word. Thus, the Navajo words
+“wol-la-chee” (ant), “be-la-sana” (apple) and “tse-nill” (axe) all stood for the
+letter “a.” One way to say the word “Navy” in Navajo code would be “tsah
+(needle) wol-la-chee (ant) ah-keh-di- glini (victor) tsah-ah-dzoh (yucca).”
+
Most letters had more than one Navajo word representing them. Not all words
+had to be spelled out letter by letter. The developers of the original code
+assigned Navajo words to represent about 450 frequently used military terms that
+did not exist in the Navajo language. Several examples: “besh- lo” (iron fish)
+meant “submarine,” “dah-he- tih-hi” (hummingbird) meant “fighter plane” and
+“debeh-li-zine” (black street) meant “squad.
+
+
NOTE: from the above it might look like the code is wrong, where at least
+one letter above is translated wrong. But at least some letters had more than
+one translation and it was a matter of choosing one. However from my file, the
+word for YUCCA was actually TSAH-AS-ZIH rather than TSAH-AH-DZOH. But if
+you try that you’ll get tsah-as-zih no-da-ih moasi moasi wol-la-chee; to
+translate that you can use ./prog.alt tsah-as-zih no-da-ih moasi moasi wol-la-chee. The reason it works this way is because that is the literal
+translation for TSAH-AS-ZIH which they used as the letter Y. Thus if you do
+./prog Y you’ll get TSAH-AS-ZIH and if you do ./prog.alt TSAH-AS-ZIH
+you’ll get Y.
+
Additionally, if you try ./prog navy you’ll get the output tal-kah-silago as
+that is the word in their dictionary for navy (the literal translation was
+sea soldier).
+
NOTE: the alt program, which uses very similar code but has to be in an alt
+file (prog.alt.c) due to the differences and because of encroaching on the
+size restrictions of the contest (it’s also clearer and easier to maintain for
+me even though the most important part is a simple macro of 1 or 0), will do
+these translations. However there are some oddities that will be explained later
+in this file.
+
Examples
+
The word ‘bikini’ is obviously not in the dictionary and not really relevant to
+the IOCCC or the Second World War: at least not at the time; however there’s a
+connection to that word just after the Second World War and believe it or not
+it’s related to something from the war (yes really: see below!). So how do we
+rectify this problem when using the program?
+
Well since we have the alphabet also we can just spell out words that are not in
+the dictionary! Try:
How come if shush meant bear it doesn’t translate to just shush? Well
+that’s because in the war dictionary there was no word for ‘bear’ directly, only
+the literal translation (though there certainly were bears in the war including
+the (in)famous Wojtek).
+It is the indirection involved with the language and that made it so powerful.
+
Okay but for the ailurophiles like myself (not that I don’t love bears), what
+about cats (such as the legend of Unsinkable
+Sam, see amusing medical record
+for Sam below for a few laughs)? The word for cat was moasi.
+
So:
+
$ ./prog c ; ./prog.alt $(./prog c)
+ moasi
+ c
+
Of course you might want to print out the actual word so how to go about it?
+
$ ./prog.alt $(./prog cat)
+ cat
+
You can of course do this with bear as well.
+
$ ./prog.alt $(./prog bear)
+ bear
+
If you want to see the alphabet:
+
$ for i in {a..z}; do ./prog "$i"; done
+
…and you’ll see the alphabet that happens to be in the code, although that’s
+in upper case.
+
The etymology of the word ‘bikini’
+
I said above that the garment ‘bikini’ has a namesake in a product of the Second
+World War but what is it? Well there’s an atoll called Bikini in the Marshall
+Islands that in 1946 the US exploded an atom bomb. The idea of the name of the
+garment is its supposed ‘explosive’ effect. If you didn’t know this you now have
+an interesting bit of trivia (you know, for the beaches or parties I’m sure you
+go to … :-) ) where the bikinis are related by name to the atom bomb!
+
Difference between dict and dict.orig
+
In the original dictionary there are some words that are followed by
+parentheses with a letter in it. For instance:
+
+
WITH BILH(W) WITH
+
+
I am not sure but I believe that might have been another way to say the letter
+W but since it could cause problems in output I have removed it from dict
+(removed the parentheses and what was between them, I mean). It might also be
+something else seeing as how there the alphabet is in another part of the file.
+In any case we do not need it.
+
What about input files ?
+
Obviously it’d be ideal if one can encipher a file. The question was how to
+specify that the input was a file. The prefix + seemed reasonable as usually
+one wouldn’t write a + before a word without a space and it saves from having
+to write an option parser (or adding to it). There is a subtle point that I
+refer to in the limitations.
+
But what about error handling in file mode? If getline() returns < 0 (actually
+it returns -1 on error) it’s just skipped. I’ve never actually seen this happen but I
+suppose it could. If it’s not a file no text is printed. Of course I don’t check
+if it’s a text only file and it’s not even clear what should happen if it isn’t.
+Like with cat(1) and many other tools, don’t feed non-text to this program!
+
File parsing is strange in output, however, possibly due to the shell but it
+demonstrates how the strong the language was as a code, and how word boundaries
+prove to be an issue.
+
See the issue of spaces for more details on spaces which is necessary
+in order for the English<->Navajo bi-directional translations.
+
Questions to ponder as you look at and try and understand the output
+
Above we saw that the input bikini (see above for its relevance) gave the
+value shush yeh-hes ba-ah-ne-di-tinin yeh-hes tsah yeh-hes.
+
Now try the input BIKINI and you’ll see that you will have the same output but
+a different case (which was also shown). But can you get it to show other output
+that’s also equally valid? An earlier version did this but it was changed to
+save bytes. Can you guess how? This ability is a fun and very strong feature of
+the language.
+
The alphabet had more than one translation per letter. But as I was pushing the
+limits in size (especially considering I wrote this before the size restrictions
+were lessened) I had to remove the extra letters. Also it is not clear to me
+what letter should even be translated so after the size limit was lessened I did
+not put them in. On the other hand I do have them in the file still, just not in
+the source code. This also actually increases the obfuscation of the code though
+so all the better.
+
Can you get the program to show literal translations instead? This is actually
+much easier than it seems at least for words (including the alphabet) in the
+dictionary file. Obviously this can’t be done for words not in the dictionary
+which is a good reason to not have it; it was a misleading part of the design.
+
Why does
+
./prog.alt $(./prog +prog.c)
+
show no spaces (or it shouldn’t) and a single line (I think it is only one
+anyway) when
+
./prog +prog.c > foo
+ ./prog.alt +foo
+
does? What does it mean? As noted elsewhere it is unrealistic with the spaces
+issue to expect an exact match.
+
Also: why does the first one seem to show (at least in my systems) what appears
+to be files in the directory? Let’s just say it’s an ‘eavesdropping’ feature for
+a language that was designed to be impossible to decrypt even if it was
+overheard, even by the same side (on theme, you see)! Or we could just say it’s
+an abuse of the shell, especially as it depends on the file’s content.
+
HINT: the prog.c has the * and so the shell is interpreting that
+character! Everything is normal in other words.
+
The fact is the file is contrary to what they had as they had to do it all in
+their head - kind of like you typing the strings. I offer the prog.alt as a
+helpful one but due to the way the language worked (including words having more
+than one word) there will be oddities depending on how it was done. I did
+workaround some of this when it comes to !isalpha() though.
+
As for the spaces seeming wrong in the second commands I explain why this
+happens later in the issue of spaces; it’s not wrong. A quick
+way-too-simplistic answer: it is because of how the alt code functions with word
+boundaries. This is a feature, not a bug!
+
Changing the translation to convert Navajo to English
+
This is very simple to do and it’s already done. Simply run make alt and use
+the alt version of the program; it’ll translate translations back to English
+(but not the literal translation!).
+
However it should be noted that as there’s not a good way to decide word
+boundaries so for spaces in some invocations (not all) you have to specify a
+literal space. For instance don’t do:
+
./prog.alt $(./prog b " " c)
+
but instead do:
+
./prog b c > foo
+ ./prog.alt +foo
+
The former might show bc and the latter will show a space and possibly a
+newline.
+
At various points I had it where you could do the first but it was a battle and
+it did not seem worth fighting when I could spend more time on other things like
+obfuscating it and submitting it. It also used to read from stdin as an option
+but this seemed not very useful and in some cases caused (depending on the
+file’s contents) the program to want to read from stdin (as I already gave an
+example of the shell interfering I won’t get into this more). It’s not a
+limitation and besides they did this all in their head; they had no files or
+even computers as we know it.
+
You might find quotes can cause strange output in some cases (or did - not sure
+now). Even worse what happens if the Navajo word translates to one of the
+military words but you don’t want that? Nothing we can do about that! I don’t
+even think they could have done something about that. That’s the multiple
+layers of the system/code.
+
Literal translation notes
+
I already hinted at this and asked you to ponder this: but there are actually
+other ways you can configure this program so it translates between different
+lists. You could (but this is pointless because it isn’t authentic then) have it
+translate of Navajo to literal meaning. I was seriously considering taking this
+out as I don’t even like the idea (due to the fact it would dishonour the
+language) but technically it’s possible with some modifications to the code.
+
Notes / Limitations (of the language)
+
The dictionary file has to be in a specific format. I don’t really see this as a
+problem but it’s worth pointing out that it won’t work if the dictionary file is
+in an invalid format. It’s not necessarily what it seems! But it does also allow
+for further obfuscation so it seemed like a good idea.
Actually if you figure it out you can use this entry to translate other
+languages as well! Kind of. As you’ll see in the file it’s not quite as it
+seems. You can indeed make it translate other languages (notwithstanding
+diacritics - or actually that might be possible too but not sure of it) but you
+have to do a bit of work first. That especially goes because the alphabet (for
+words not in the dictionary) would still be spelt out as Navajo Code Talker
+language!
+
Something else about the Navajo language and the case of letters. As I don’t
+know Navajo I don’t know if something I did is strictly correct. As the
+dictionary had everything capitalised I took some liberty in not doing this in
+that if the input letter or word is lower case it’s made all lower case; but if
+it’s capitalised only the first letter for each word is capitalised at least for
+the words in the dictionary (I think I did that). This goes for words in the
+dictionary.
+
An example: in German all nouns are capitalised; this is why ich (I) is only
+capitalised at the beginning of a German sentence (no, ‘I’ is not a noun). But
+this was also due to the difference in lengths and keeping track. The issue of
+length of words will be brought up again.
+
In the case of titles this might be wrong but I wanted it to read naturally
+which (if translated back to English - not the literal translation) would be
+better if it preserves the case of the input. This does mean acronyms won’t be
+all capitalised at least if it’s in the dictionary (can you figure why I can’t
+do that?) but I deem this an immaterial technicality.
+
Obviously if the dictionary file is missing or invalid format the words will not
+work. In this case the program will just spell each word (it might also show an
+error but continue to spell it out - for instance if you move the file to
+something else).
+
This is not the fault of the program but the language as well as the environment
+and/or user. Well it might do the individual letters right but I’m not sure of
+this; it might even do something funny for all I know.
+
There were spelling errors in the dictionary. For instance they had straff
+which I can only assume was meant to be strafe. Perhaps this is wrong but so
+is straff. Okay actually straff is a German word but it was English, not
+German.
+
Newlines might not be printed well unless reading from a file with the +
+prefix. They might but might not. It would seem they won’t be given that at the
+command line as there aren’t newlines per se. As I noted in the file mode
+section the alt code only prints literal spaces but it also just passes
+non-Navajo words as is.
+
On the other hand one can mix files and input at the command line. Note that
+clearerr() is called so one should be able to use the file again though I do
+not guarantee this part (given that it’s closed it’s probably especially not
+even needed though as it’s just opened again).
+
Due to the nature of the processing if one does specify a + before text that
+is not a file (user error) and no input following that there will be a blank
+line (might be two, not sure) and then nothing else will be printed.
+
This is because the + is separate from the word itself; the letters constitute
+a word but the + is not even part of the Navajo language (in the Code Talking
+sense (if at all?)). The same goes for other !isalpha() chars except they will
+be printed with words that are not in the language (and I think even those that
+are - that was a later addition if so). There’s a function that does
+an operation similar to strcasecmp() but which ignores !isalpha() chars so
+that test. and .test.. are equal (in comparison, not in output). That’s used
+in the case of a dictionary word like B: hence ./prog ..B..B should show
+..SHUSH ..SHUSH (observe the space after the first one - that’s a feature and
+is shown elsewhere too, including the issue of spaces).
+
I believe that the way it’s done (with printing the characters too) one can do
+./prog.alt $(./prog -code) and get -code (this was no always possible but I
+believe I added this later on - a quick test suggests it).
+
Some of the military words are more than one word which can cause a problem;
+what could be done? Actually there is a way here but not when reading from
+files.
What happened? It reads in the file delimited by lines and delimits each by
+spaces. It does try reading it word by word (by the shell) but it can’t handle
+multiple words as one word unless it’s in the dictionary and one word in the
+shell. It needs it to be a single word, hence the 's. This will work fine
+because it simply leaves them untouched:
There is a solution to this but it makes it hard to use the program (I think). My
+understanding is the dashes were only used in the Code Talking so: make the
+multi word military terms not space delimited but dash delimited like the Navajo
+language. This would require the input to follow the same format though (e.g.
+commanding-officer) which might not always be the way it is and would put a
+burden on the user as well. This is actually very easy to change though. Perhaps
+it would work better than I expect but it is unnatural and also not the way
+their dictionary even has it - there is no dash in the ‘commanding officer’.
+
Whereas they could control the boundaries, we cannot, and even though they wrote
+down the translation, they were familiar with the language and they added spaces
+where necessary. Unfortunately in order to translate we have to have some kind
+of delimiter and what would it be if not space?
+
Mostly the problem is when trying to decipher an already enciphered string - due
+to word boundaries. Sometimes (not now) adding a literal " " as a word
+separator would help but as I think I said before it was a battle, where it
+might break one thing to fix another, and I got tired of trying to make it
+perfect as it probably shouldn’t even be perfect due to the nature of the
+language. Mostly this is if you do it like this:
+
$ ./prog.alt $(./prog b " " c)
+ bc
+
This works fine though:
+
$ ./prog b c > foo
+
+ $ ./prog.alt +foo
+ b c
+
+
That might or might not be the shell messing things up.
+
What about not spelling out words not in dict (leave them untouched)? This
+could be done easily but it wouldn’t be authentic so I’ve not done it (in
+prog.c). On the other hand:
+
$ ./prog.alt a b
+ ab
+
+ $ ./prog.alt a " " b
+ a b
+
work fine because there is no translation being done!
+
Portability
+
DON’T EVEN THINK ABOUT using this on non-ASCII systems; it heavily abuses
+arithmetic on strings and other calculations. It might require two’s complements
+as well but I’m not concerned about either as other systems are rare now, if
+that’s the case - I am not even sure of what all I did, a reasonable symptom of
+writing confusing code a long time ago.
+
Bugs / Mis-features / Limitations
+
There are a few things I’ve not touched upon in other sections that might appear
+to be bugs and some that some might argue as bugs but might be called features
+as well.
In other words, why does it spell it out words but letters seem to be untouched
+(or some - are all?) when reading from a file?
+
This is a challenge I am giving you for you to figure out when it comes to file
+mode! Can you actually get it to do what else you might (or might not) prefer?
+And before you say ‘bug!’: would I really even offer file mode when they did not
+do this with computers (they did it in their head), if this was a bug? I didn’t
+think so :-) Carrying on…
+
The OS will have to deal with some memory leaks; some memory is freed but I was
+not able to free all due to the large amount of data (I could have just read it
+all in but I wanted to show that I was not trying to abuse the size limit - even
+though other entries in the past have read in dictionary or similar files) in
+the code along with needing more bytes for obfuscation and so reaching the size
+limit.
+
It was even worse when the size limit was more strict (I started this
+before that happened and then put it out of sight for a while). Memory from
+getline(3) should be taken care of but the linked list and its associated
+memory is/are not freed. Actually below you’ll see in some cases a memory error
+occurred but that no longer happens (except due to the bug in getline(3)
+itself).
+
And on that subject of getline(3): there is actually a bug in it, at least in
+some systems; this was actually reported as a
+bug
+(not by me but someone else). It’s reported by valgrind and unfortunately
+adding a workaround broke the output. It was driving me crazy until I finally
+tracked it down; I was sure my code there was fine but I could not discover it
+until I dug deeper and saw it was a reported issue.
+
Yes I realise that bug report is from 30 June 2021 and it’s in status
+‘UNCONFIRMED’ but the report describes the exact same symptoms.
+
Anyway valgrind will (did?) if reading from an affected file report:
+
Uninitialised value was created by a heap allocation
+ ==1271819== Conditional jump or move depends on uninitialised value(s)
+
The function (Y()) is the function that does the comparison without caring
+about non-alphabetical characters (I think?). It doesn’t seem to be that I do not use
+strdup() prior to the strtok() and in fact using it caused a read error so
+that was obviously the wrong choice as well (plus it’s unnecessary in this case
+and it allowed more functionality and obfuscation). If I recall correctly that
+was the a->A prior to using strtok().
+
And besides the bug report for getline(3) it works fine if there is text on
+the last line. And like I said I can add a workaround which if the length read
+is > 0 zero out the buf[len-1] but this breaks the output of the program so I
+don’t do that. Actually as I recall the error still happened if I checked the
+length > 1! Nonetheless it breaks the output if it’s ‘fixed’.
+
Multiple systems have not shown any behavioural issues unless I add that
+workaround. In any case valgrind reports no additional issues.
+
Now: why does the alt version sometimes show words that are English in English?
+It’s not actually a bug but maybe it would appear to be. I already showed this
+and gave a brief explanation but there are also other occasions it can occur. It
+can also depend on the input/command line itself (and for instance because it’s
+translating back to English so if it’s English there is nothing to do - which
+brings up an interesting quest of how does it know that?).
+
A command line that does not make sense:
+
$ ./prog.alt b $(./prog)
+ b
+
Actually what is happening is the ./prog part is
+empty string so prog.alt is simply printing all it can print, no translation
+at all (notice the b prior to the $(./prog)! Try breaking it up:
+
$ ./prog.alt b
+ b
+
Why? Well again there is no translation to do! Now what does ./prog by itself
+do? It is an empty string (or maybe just a newline), as noted. Thus this does
+make sense:
+
$ ./prog b
+ shush
+ $ ./prog.alt $(./prog b)
+ b
+
(which I’ve shown before.) Is this a bug?
+
$ ./prog.alt hat
+ hat
+
Nope. It’s because there’s no translation to translate back into English so it
+just passes it as is.
+
Here’s a translation:
+
$ ./prog.alt $(./prog code file)
+ codefile
+
Uh oh! What happened? Well I already explained this part (and much more detail
+in the issue of spaces section). Fixing this caused
+other things to break and going back and forth with the twisted code was doing
+my head in so I had to stop. It was at one point possible to do ./prog code " " file and at one point it had the space there but that made reading from files,
+which seems more useful to me, have bad output. Note the issue here: both code
+and file are actually in the language: yes when I say they had no files I
+meant no files to read from like we have on our computers.
+
It is possible to do that
+directly though as I showed (earlier I think). This will work though:
+
$ ./prog.alt $(./prog code.file)
+ code.file
+
THIS works too:
+
$ ./prog.alt shush " " chuo
+ b f
+
as does:
+
$ ./prog.alt +foo
+ b f
+
(assuming foo has the right content of course.)
+
As a consequence of how the words have to be tokenised you have to be careful if
+you want a translation. For instance don’t do:
(but notice how the command ./prog.alt $(./prog code.file) does work where it
+‘translated’ it back to code.file - can you figure out what is really
+happening there?). This is because there is nothing breaking the word apart. The
+Y() function does check for matches ignoring !isalpha() but what is it
+comparing against? Again if a known delimiter could be specified this could be
+resolved but trying to do that would assume the user’s intentions. It is better
+to require a space than to do that. You can do this instead:
+
$ ./prog code . file
+ yil-tas . ba-eh-chez
+
or even better:
+
$ ./prog code file
+ yil-tas ba-eh-chez
+
BTW: don’t try this:
+
./prog +prog.c > foo
+ ./prog.alt +foo
+
without anticipating an extra space issue. Unfortunately this is necessary
+because the only sane delimiter is a space. In particular, if you take a look at
+the file foo (after the ./prog +prog.c > foo) you might pick up on why this
+happens. In fact somewhere in this file I showed the same thing at play (or I
+think I did): it’s a matter of word boundaries with the letters; since the words
+have to be spelt out the spaces are there! That is a feature, not a bug.
+
Frankly I prefer the look here though I’ll return to that idea later on.
+
Without the space the match cannot occur (although an example above would seem
+to belie that, which just adds to the obscurity of my program).
+
There was a way I played with but it was too cost prohibitive in size, it was
+problematic and I could not determine all edge cases. Besides like I said and
+demonstrated the spaces need to be there (with more space it might be
+possible but that is not the case).
+
Other cipher systems work differently and don’t rely on two sets of ways to go
+about it - it’s one or the other (there might be exceptions but for instance
+rot13 and Enigma both have a one-to-one mapping - okay the Enigma had many
+possible combinations for the same word depending on what came before it but you
+know what I mean; as long as the settings are the same you can derive the same
+result). As I note elsewhere they actually had more than one word for letters
+too and I have made them in an array which means that not all translations are
+even used.
+
The real trouble, basically, is that a word can be spelt out OR have a
+translation so a choice had to be made. I chose to spell things out without
+having to write an even more messed up parser (though as I note later on I tried
+it it just caused even more problems than it was worth).
+
So this is a feature, not a bug!
+
You can summarise the above with the following statements:
+
+
When translating to Navajo (prog, X=0) if the word is not in their dictionary
+it will spell it out, each letter (a word or words) being separated by a space.
+
When translating to Navajo (prog, X=0) if the word IS in their dictionary
+print out the Navajo word (sometimes with a - in it).
+
When translating Navajo to English (prog.alt, X=1) with a known Navajo word
+(in the Second World War sense) the translation is printed without spaces, as
+the words are on a space boundary and since it’s not a letter-by-letter basis
+with known translations, there is a single word (or words in some cases, maybe,
+although I don’t recall that) printed (though depending on input it might or
+might not have the space there - I showed an example above).
+
When translating Navajo to English (prog.alt, X=1) but there actually is no
+original translation, it prints each letter separated by a space (well if you
+have an explicit space there like I showed above). If you can figure out why
+this happens you have a bit better understanding of the function I(). Okay
+actually one can do things like ./prog.alt $(./prog book) and get book when
+./prog book will print out each letter but you saw what I mean here.
+
Because of having to deal with !isalpha() characters in input (at least to
+be the most user-friendly - I could have avoided it to make it more like ‘the
+real thing’ but that would have prevented other features) the Y() function
+will ignore those characters (though in the front of the word I() should print
+it). Also if a translation is found it might remove some of the characters that
+are not part of that translation (or it did - it might be different now but as
+they didn’t have to deal with files or grammar, doing it all in their head very
+quickly, the fact it sometimes does it fine is a kind afterthought on my part).
+
+
Oh and as far as tokenisation goes: it occurred to me that even this will not
+always work. I was playing with the idea of having output tab separated: then I
+could use strtok() on the input and do it that way. It was looking somewhat
+promising and then it occurred to me that while this might help with the
+program’s output (though making it harder to read for most people) it won’t help
+if someone puts in the string manually! So there really is no way to deal with
+this satisfactorily in ever case and trying to do so actually takes away from
+the brilliance of the language. And we don’t want that, do we? :)
+
Spaces shown now are necessary and in the case where spaces are not shown but it
+seems like they should be, that is an unfortunate technicality that’s a feature,
+not a bug.
+
Actually if the spaces are not precisely correct it can cause gibberish to
+appear and the fact is the only gibberish we see is the language, and it’s only
+gibberish if you don’t know the language!
+
To the Code Talkers the issue of spaces and grammar was entirely inconsequential
+anyway because it was done all in their head, kind of like as you’re reading
+this very sentence (even if you read it out loud the spaces and grammar are only
+visual aids to help you so
+youdonthavetoreadsomethinglikethisuntilyougetaheadache - as most people,
+although I am a rare exception, cannot read well without spaces between words)
+and therefore they are inconsequential to us too.
+
The language was not to be understood by any others and it was very successful
+at that; thus you do need to expect some oddities when it comes to printing
+words that are not in their dictionary. This is a feature of the program and it
+can actually result in some fun output! This is part of the obscurity of the
+program and the language as well.
+
This is also why I tried to put a lot of whitespace in the program code, just to
+really drill it into your head that spaces are both important and not important,
+depending on the context, and depending on what is needed. Since you won’t be
+speaking out the code, spaces don’t matter any more than they matter in the
+output. In other words, spaces don’t matter. But they also matter as they are
+necessary for translation to work.
+
For more details on the real problems with the spaces and why only alt code
+might be considered, see later in this file in the spaces issue
+section.
+
Obfuscation
+
This section might not be complete. This is because I added a heavily commented
+deobfus.c file and although it’s not technically deobfuscated the
+comments might help explain some of it. Though as you’ll see even some of it I’m
+not sure about; by looking at this file you will probably curse me and you might
+have some kind of respect (or awe) but you’ll also see just how twisted this
+code is (and how messed up I am, presumably). It is truly awful and I’m
+extremely proud of it. I don’t think I could do this again as I have no bloody
+idea how I did it. I have no idea how I came up with the calculations let alone
+anything else that’s obscure.
+
Please, if you do read it, and I know the judges will at least, take care and
+maybe eat some great chocolate (like the final comment suggests) after doing so
+as you might need it. It was really hard for me to go through and I had to go
+through it more than once after making some significant changes (and fixes) to
+the code (when printing files it used to add an extra space to the beginning of
+lines after the first line, for example) I have provided the file as the judges
+now appreciate educational value and also because by commenting it I could show
+the obfuscation techniques in the code itself, plus it is so twisted it amuses
+me (sorry if I stress anyone out). Nevertheless I will try and list a few
+things, some of which were not mentioned in the code (I think).
+
I might also add that if there is some inconsistency it came later on though I
+don’t think there is any.
+
The dict is kind of obfuscated. Not really but kind of (see how to unravel
+it if you wish to know). Even after you figure it out though it won’t
+help you understand the program.
+
main() is rather funny. Who cares about ‘possible’ misuse of comma operator,
+unused parameters and bitwise negation of a boolean expression if it hides
+details? Comma operator is used elsewhere as well but who cares? Actually the
+great thing, which is discussed in the Compiling/Warnings section, some warnings
+actually, if fixed, WOULD BREAK THE CODE (and none of them are relevant in any
+case); some can be silenced by casting to void but even in some of those cases
+the warning is incorrect in what it’s saying.
+
That includes ‘unused value’ or should I say ‘“unused” value’?
+
The array B won’t make any sense to most people. How I use it probably is not
+exactly clear either. Earlier on I had words of the Navajo language as variable
+and function names but I couldn’t do everything I did without changing it; in
+fact when I originally wrote it before the change in size limits the program was
+pushing the limits and obfuscation was not as good and there were several bugs
+to fix as well, leaving virtually no space for obfuscation!
+
But of course single letter names don’t convey anything either.
+But before I can discuss anything else I better discuss the anonymous struct
+that holds state that can vary from function to function. Here are some
+examples.
These are truly nasty beyond the look because what it does is it allows me to
+have the same data in a struct (outside the struct and in a sense in the
+struct) do different things in different places. In fact the only reason I need
+the two variables struct a *f an struct a *c is because of the linked list;
+everything else is anonymous in the functions!
+
Here are some funny statements / expressions:
+
o = *"";
+
+ s=z+-*"1"-*"1"- -97,L=putchar(!s&&isupper(a->x[0**"z"])?a->a->c[s]:tolower(a->a->c[s]));
+
+ c = calloc(1**"0"-47, sizeof *c);
+
+ for (a->a = f, z = 0**"1"; a->a; a->a = a->a->e)
+
+ for (z = 2/ *"z", s=1+0**"1"; z[a->x]; ++z)
+
+ for (J = *"1"-*"1"; J < 26 && B[J][X?1/ *"1"+s/
+ *"1"+1/ *"1"+s/ *"1"+1+(s-s)**"1"+(s*(s-s))**"1":((((s-1)**"1")**"1")**"1")**"1"]; ++J)
+
+
+ (((*a->h[--a->l]=='e'-':')&&(*a->v)(&(struct a){ .v[0]=I, .s=((a->l)[a->h])+1} )
+ &&++a->l)||(a->v[1](&(struct a){ .v[2]=Y,.x=((a->l)[a->h])} ),++a->l)); if (g) puts(""); }
+
+ if (*B[J][0+*"1"-*"1"] == toupper(z[a->x]))
+
+
+ for (k = (s*2)**"9"-171+*"9"; H=B[J][X?*"1"-49:s/ *"1"+s/ *"1"+1/ *"1"+(s*s*s)][k]; ++k)
+
+
And you really thought you couldn’t mix arithmetic and strings in C? Now that you
+know better can you tell me what’s going on or keep track of what it’s doing? In
+some cases it’s actually nested but with this there are few numbers that are
+what they appear to be.
+
Some of these are really funny (and a bit nasty) because if you try removing
+spaces you’ll turn the expression into a comment! If you need help in
+unravelling these, I gave it my best go in deobfus.c; but as it
+says there some of it I really cannot parse well - some of it seems so wrong and
+yet what looks ‘right’ is wrong (for instance it looks like -1 will be the
+index in an array but trying to ‘fix’ it will break the code).
+
Fun fact: in C, the following are both legal:
+
char **c;
+
+ char * *c;
+
(in particular, the whitespace is allowed, although in some cases it can cause
+unexpected output). So in my code depending on the command, for example:
+
./prog.alt $(./prog +prog.c)
+
will show funny output (remember also it ends up passing * to the shell!)
+whereas:
+
./prog.alt +prog.c
+
won’t.
+
As for the * in the code causing the shell to show files in the directory
+interspersed with other text (which I think is hilarious but not the fault of
+the program) there are other funny things that can happen due to the shell and
+command line. For instance I have at times seen returnreturn!
+
Consider this a fun Easter egg, if your system is affected, that I chose to keep
+because the formatting was more important and output is actually correct when
+not abusing the shell. Considering too I was able to spell out IOCCC in the
+formatting of the code which I might not have been able to do as easily is
+another reason for this.
+
Compress some if/while loops with && and comma operator. The biggest example
+is the while loop in Z() which acts on the argc/argv of main() (and the loop
+condition increments, then the body immediately undoes the increment and then at
+the end redoes the increment so that at the next pass the c (argc) is back to
+where it was left at the start of the loop body) which is a single statement but
+which would normally be several. Also in Z(): why is this valid?
+
while (a->h[a->l++])
+
How is a->h[a->l] set to a safe value? Well in main():
The c (which is the argc) is set to the correct value. Of course that
+expression is insane. The deobfus.c explains just how nasty this
+really is, particularly for the Z() function.
+
Can you explain this behaviour?
+
$ echo $(dirname $(type -P file)/$(./prog file))
+ /usr/bin/file
+
+ $ $(echo $(dirname $(type -P file)/$(./prog file))) prog.c
+ prog.c: c program text, ASCII text
+
when this happens?
+
$ ./prog file
+ ba-eh-chez
+
And yes here again file is used but not in the way we know it on our computers.
+
What is:
+
putchar(('\0'+'!'-1));
+
? It is a screwy call to putchar(' ');. Obviously this requires ASCII but that
+should be obvious with some of the other ways the code works too. The fun thing
+is how I formatted the code I was able to make it look like I did
+putchar('\0') - or at least it starts to look that way!
+
All the functions besides main return a char * and take a struct a *. But
+rather than poison the structs needed for operation, the functions are called
+with anonymous struct a *s with the specific values set in the function call
+themselves. For instance the following will create call a function foo that
+takes a struct bar *foo with an int baz set to 1:
+
int foo(struct bar *foo)
+ {
+ return foo?foo->baz:-1;
+ }
+
+ foo(&(struct bar){.baz=1});
+
Why make extra objects when we can use anonymous objects, especially when it the
+latter is far more obscure and much harder to keep track of? And why poison the
+structs when I can poison your mind’s ability to parse the code? Thank you very
+much to the C standards body for what probably was a terrible idea (except for
+the IOCCC)! (Though I can think of a few cases it might be useful it’s clearly
+bound to be abused - and I believe this is the first time in the contest’s
+history it was though I might be wrong.)
+
A special mention is due I think as well. I noted this in the
+deobfus.c file a bit but I want to elaborate a bit more. In
+main() I do something extremely nasty so that Z() (which is also extremely
+nasty, see below) works right without accessing invalid memory.
does a number of things but one of the things it does is it sets up c to be
+valid for the call to Z(). c is argc in main(). As above, Z() is
+called like:
is quite devious. We all know that the order of evaluation in functions is
+unspecified (or was it implementation defined?) but am I actually doing this?
+In fact I’m not (but see below): I’m circumventing this by using
+short-circuiting rules and the comma operator, ensuring that the order is
+specified and also extremely hard to parse (the constant updating of argc
+makes it even worse, see next part). The reason for the comma operator on both
+parts of the expression (that is the lhs and rhs of the ||) is to ensure that
+the argc (a->l) is incremented no matter what.
+
More so, I’m not even sure the order of evaluation matters here as there is only
+one function parameter for all the functions besides main(), and it’s a
+struct a *; but if it does matter I’m circumventing the problem anyway by
+short-circuiting it and using the comma operator, both of which control it to
+the way I need: if the lhs of the lhs fails I still update argc and if the lhs
+fails itself the rhs is done but if the lhs of the rhs fails the argc is still
+incremented for the nest iteration in the loop! How is that done?
+
Well on the lhs if the first char of the current arg is a - it will call the
+appropriate function (t()), which because it will never return NULL the argc
+will be updated; but if it fails, which means the first char of the current arg
+is NOT a - then the function I() will be called, and this too will never
+return NULL. But in that case I use the comma operator instead of && to update
+argc.
+
The use of the highly nested ()s and the anonymous structs and the
+short-circuited logic along with the comma operator makes it really hard to
+follow but it also controls everything in precisely the way I need it.
+
Oh but there’s even more in that code…
+
Did you notice that in the call to Z() it sets the anonymous struct j to f
+and k (all of which are a struct a *) to 0? Now what happens in Z(). First
+this part:
calls a function (I’m trying to finish this up and I added this late so I am not
+even sure which one exactly even if I said it above or have it in the commented
+code) and in THAT function the struct a * (again anonymous) has the j
+pointer (a struct a *j) to a->k which was set to 0 in the call to THIS
+function. This might be called a red herring though because right after that you
+have:
which sets in THAT function z to a->j. With the formatting above it’s
+bad enough but in prog.c it’s even worse. Now then the function that this calls
+is I() (I think the other one might be Y() but I’m not sure - in any case it
+doesn’t matter as the pointer is not needed there or if it is it’s not used by
+that name) and that does:
+
... for (a
+ ->a
+ = a->z,
+ z =
+ 0*
+ *""
+ "1"; a
+ -> a; a ->
+
+ a = a->a->e) {
+ ...
+
which means that in I() the pointer a->a is set to f.
+
Format of code
+
It’s kind of crazy too though not as crazy as the code itself. Besides the
+spaces (to point out that spaces in the code are both important and not
+important - or important in the output but not necessarily in the code - or is
+it perhaps vice versa? Neither? Both?) there are some fun shapes and things
+spelt out.
+
There is an arrow in the code.
+
There is an I in the code. Well okay it’s actually IOCCC. Actually that’s
+still not accurate! It’s IOCCC CCCOI (I think - that’s what I aimed for)!
+
If you use your imagination you can kind of see a Christmas tree (though that
+was quite by accident) (I suppose the arrow could also be seen as a Christmas
+tree if modified a bit or you imagine a thin trunk). Another fun thing to point
+out:
+
* *
+
+ "9"-15u/
+
kind of looks like a face (perhaps a hooded face?).
+
As for prog.alt.c: I thought another approach would be fun. The judges don’t
+like submissions that are just lines merged but since this is just alt code
+(though useful in the submission) and since it took a lot of time and energy to
+format the submission code, I joined the lines mostly and removed all the spaces
+that were possible (I think I managed that). This is an interesting exercise as
+you can see that there are a lot of places that are untraditional (in code) but
+that must have spaces. Obviously things like struct a cannot be structa
+but consider the / *: there are at least 10 of those (I think?) that cannot
+have the space removed because doing so would turn it into a comment! Although
+some of the same expressions are used they are not all the same expression. This
+happens in prog.c though I did not count them (and I have a headache, probably
+from the code, so maybe I miscounted). Another place a space is required (also
+in prog.c):
and the reasons are obvious! I am not sure now if there are other places though.
+
Compiling and warnings
+
If DICT is not defined it is defined as "dict" so it’s not really necessary
+if running the program from the same directory - as long as the file exists of
+course.
+
When I tested this with clang -Weverything in macOS (no guarantees the judges
+will experience precisely this - and in fact this might have been with macOS 14,
+not 15, although it works fine with 15.5 and presumably in between those
+versions and possibly - and I’d guess likely - earlier) NO FEWER THAN THREE
+COMPILER WARNINGS ARE WRONG (actually a fair few more depending on how you
+count them) and if these were ‘fixed’, it would BREAK THE CODE, potentially
+if not outright (in fact some absolutely would)!
+
One even would be removing the , for a function call (well, not really a
+function but the side-effect is NEEDED). That’s the ridiculous -Wcomma one;
+it’s also triggered elsewhere but the side-effects are also being used there and
+as you saw in the Obfuscation section one place this is used to circumvent the
+order of expressions in function calls being unspecified (though that might not
+even be necessary - not sure now).
+
Some warnings also appear with gcc instead though and some might appear with
+both; it’s hard to keep track but here is a list of warnings I have disabled.
+The warnings were before I formatted the code and I added obfuscation in at
+least one. I’ll note that below.
+
Note that this was before formatting and maybe I did change some code although I
+doubt it.
+
This is warning is WRONG:
+
prog.c:32:22: warning: possible misuse of comma operator here [-Wcomma]
+ 32 | s=z+-*"1"-*"1"- -97,L=putchar(!s&&isupper(a->x[0**"z"])?a->a->c[s]:tolower(a->a->c[s]));
+ | ^
+ prog.c:32:3: note: cast expression to void to silence warning
+ 32 | s=z+-*"1"-*"1"- -97,L=putchar(!s&&isupper(a->x[0**"z"])?a->a->c[s]:tolower(a->a->c[s]));
+ | ^~~~~~~~~~~~~~~~~~~
+ | (void)( )
+
and -Wcomma is one of the most ridiculous warnings of many other ridiculous
+warnings. It would appear that adding that cast might silence the warning but
+it’s not the only one and it’s totally bogus anyway.
+
This is ALSO WRONG:
+
prog.c:48:38: warning: using the result of an assignment as a condition without parentheses [-Wparentheses]
+ 48 | for (k = (s*2)**"9"-171+*"9"; H=B[J][X?*"1"-49:s/ *"1"+s/ *"1"+1/ *"1"+(s*s*s)][k]; ++k)
+ | ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ prog.c:48:38: note: place parentheses around the assignment to silence this warning
+ 48 | for (k = (s*2)**"9"-171+*"9"; H=B[J][X?*"1"-49:s/ *"1"+s/ *"1"+1/ *"1"+(s*s*s)][k]; ++k)
+ | ^
+ | ( )
+ prog.c:48:38: note: use '==' to turn this assignment into an equality comparison
+ 48 | for (k = (s*2)**"9"-171+*"9"; H=B[J][X?*"1"-49:s/ *"1"+s/ *"1"+1/ *"1"+(s*s*s)][k]; ++k)
+ | ^
+ | ==
+
and ‘fixing’ it (especially the last part) would BREAK THE CODE! It’s
+assignment AND (implicit) comparison, not just a comparison, and the
+parentheses are pointless. The assumption it is meant to be an equality test is
+also absurd.
+
This warning is ALSO WRONG:
+
prog.c:137:44: warning: bitwise negation of a boolean expression; did you mean logical negation? [-Wbool-operation]
+ 137 | F((c=((~~!!~!9u|2**"9"-15u/ *"0"-2u)<<~~!~!~9u),c&=9u,&(struct a){ .l=1, .s=a[c],.v= { &w, &w } } ));
+ | ^~~~~~~
+ | !
+ prog.c:137:46: warning: bitwise negation of a boolean expression; did you mean logical negation? [-Wbool-operation]
+ 137 | F((c=((~~!!~!9u|2**"9"-15u/ *"0"-2u)<<~~!~!~9u),c&=9u,&(struct a){ .l=1, .s=a[c],.v= { &w, &w } } ));
+ | ^~~~~
+ | !
+ prog.c:137:13: warning: bitwise negation of a boolean expression; did you mean logical negation? [-Wbool-operation]
+ 137 | F((c=((~~!!~!9u|2**"9"-15u/ *"0"-2u)<<~~!~!~9u),c&=9u,&(struct a){ .l=1, .s=a[c],.v= { &w, &w } } ));
+ | ^~~~~~~
+ | !
+ prog.c:137:16: warning: bitwise negation of a boolean expression; did you mean logical negation? [-Wbool-operation]
+ 137 | F((c=((~~!!~!9u|2**"9"-15u/ *"0"-2u)<<~~!~!~9u),c&=9u,&(struct a){ .l=1, .s=a[c],.v= { &w, &w } } ));
+ | ^~~~
+ | !
+
and ‘fixing’ it WOULD BREAK THE CODE! No I did not mean logical negation and
+the assumption here is ridiculous as well.
Removing the comma would BREAK THE CODE. In particular, the side-effect of
+it is needed (see next one too). Casting to void is totally unnecessary, though
+it will at least compile without warnings, if done the way they want (did not
+test the outcome but I know in some cases this ‘fix’ can break code as well so
+I’m not going to risk that with code that’s already highly obfuscated). Besides,
+as you can see, there are other reasons to disable the warning, all because it’s
+wrong.
+
Also, as for another place where -Wcomma is triggered:
+
prog.c:67:68: warning: possible misuse of comma operator here [-Wcomma]
+ 67 | &&++a->l)||(a->v[1](&(struct a){ .v[2]=Y,.x=((a->l)[a->h])} ),++a->l)); if (g) puts(""); }
+ | ^
+ prog.c:67:19: note: cast expression to void to silence warning
+ 67 | &&++a->l)||(a->v[1](&(struct a){ .v[2]=Y,.x=((a->l)[a->h])} ),++a->l)); if (g) puts(""); }
+ | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | (void)(
+
The side effect is REQUIRED and casting to void is utterly pointless
+(unknown if it is harmful). Actually as I said before, as this is function
+Z(), something extremely nasty is being done here, which is detailed better
+(if not to complete satisfaction) deobfus.c and the Obfuscation
+section earlier in this file. And this one is one that changed at the end, where
+it has the new pointer assignment of the struct a * in struct a. I am trying
+to finish up writing my remarks as the contest is not running for much longer.
+
Besides that, as it’s so complicated I would risk breaking something by trying
+to squelch the warning. In fact at one point I tried to break it down into
+smaller chunks and I failed. I could not do it. It abuses the comma operator but
+it is not a misuse of the comma operator.
+
Personally I believe that this warning is an antitheses to C and although I
+might be wrong I do believe that anything other than in a for loop (or similar
+say int a, b, c;) triggers this warning but the question is is that even
+considered the comma operator in those cases (don’t believe so in the latter but
+unsure on the former)?
+
The gcc warnings (plural):
+
prog.c: In function 'I':
+ prog.c:48:51: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
+ 48 | for (k = (s*2)**"9"-171+*"9"; H=B[J][X?*"1"-49:s/ *"1"+s/ *"1"+1/ *"1"+(s*s*s)][k]; ++k)
+ | ^
+ prog.c: In function 'Z':
+ prog.c:67:16: warning: value computed is not used [-Wunused-value]
+ 67 | &&++a->l)||(a->v[1](&(struct a){ .v[2]=Y,.x=((a->l)[a->h])} ),++a->l)); if (g) puts(""); }
+ | ^~
+ prog.c: In function 'main':
+ prog.c:137:37: warning: suggest parentheses around arithmetic in operand of '|' [-Wparentheses]
+ 137 | F((c=((~~!!~!9u|2**"9"-15u/ *"0"-2u)<<~~!~!~9u),c&=9u,&(struct a){ .l=1, .s=a[c],.v= { &w, &w } } ));
+ | ~~~~~~~~~~~~~~~~^~~
+
+
are ALSO wrong and the value IS used in Z()! Additionally the
+parentheses not there NEED TO NOT BE THERE! The function Z(), again, was
+updated for even more obfuscation and that is not reflected in the above
+warning, like the earlier one.
+
The warning -Wmissing-prototypes is stupid because the functions are defined
+before use, obviously. The warning -Wmissing-variable-declarations is equally
+as stupid for the same reason. What clang is saying is it wants static or
+extern some declaration elsewhere (like a header file which is not allowed and
+is pointless anyway).
+
The misleading indentation warning (if it is triggered) is nonsense and so
+frequently has to be disabled by many contestants for the contest; whether after
+formatting it is still a problem or not I do not know as I disabled it earlier
+on. It is style policing and should NEVER have been added to gcc. Unfortunately
+clang followed suit.
+
These are primarily triggered by clang -Weverything but some are triggered by
+gcc -Wextra (I think it’s -Wextra and not -Wall).
+
The empty while loop warning is asinine. There is no need for a body and it’s a
+standard C idiom. The notion the ; should be on a separate line is format
+style policing but if they deem it ‘confusing’ I guess that’s a good thing!
+
A special warning worth mentioning is -Wusing-C
+
Okay obviously that’s not what it’s really called but it should be: in some
+systems the warning -Wunsafe-buffer-usage is triggered in MANY places.
+This is because one is using pointers as a buffer or to access a buffer or some
+such but it’s essentially warning that the program is in C; hence they should
+just rename it -Wusing-C and be done with it because that’s basically what
+they’re warning against!
+
The fact you can’t even safely iterate through argv of main() even when
+argv[argc] is required to be NULL should say all you need to know about it
+being a TERRIBLE idea. Just like a lot of warnings in clang. Okay and gcc too…
+
Of course changing the code to not use pointers like I do would ALSO BREAK THE
+CODE (if it’s even possible - which of course it’s not, especially seeing it
+requires argc/argv)!
+
On this system, with clang -Weverything, a total of 81 (!!) warnings were
+issued and NOT A SINGLE ONE was valid (and perhaps it’s more now after last
+minute changes - not sure)!
+
Warning summary
+
Basically the warnings that are triggered are either plain wrong or useless and
+with several (quite a few) if I were to ‘fix’ them it would break the code. It
+MIGHT be possible to ‘fix’ some of them but this is FAR from clear and it’s
+unnecessary as well.
+
IF any could be ‘fixed’ without sacrificing obfuscation AND not break the
+program due to not it being so twisted (which is quite unlikely) I would guess
+it’s the ridiculous cast to void one. But that can cause bugs as well. As I
+said, and as you probably saw, the comma operator is used extensively and trying
+to placate that ridiculous comma warning would be a nightmare even with casting
+to void. It’d be impossible to change the code without deobfuscating it - and
+likely it would break as well.
+
Even so it’s clear that a lot of abuse of the language is in this program, some
+of which makes it quite hard to follow. As I said for Z() (how fun that that
+rhymes) its loop is deranged and when I tried to numerous times break it up for
+some issue I could not do it without causing numerous errors in the code, and I
+am not referring to syntax errors.
+
Plus the set up in main() for that (and other) functions is something else.
+The anonymous structs in each function call with different meanings of the
+members of the struct is really nasty to follow as you can never know what is
+really going to be called or what is what in general, exactly as it should be in
+production obfuscated code!
+
+
How is the dictionary file ‘encrypted’?
+
+
Well it’s just that Z is A, Y is B etc. If you need to undo the
+substitution try:
Beware that the language did have quite racist terms for certain countries; I
+will not point them out but did want to warn. This won’t matter for the
+translator however as those are the literal translations of the words used for
+other things - so you won’t see those words unless you look at the file.
+
I might also add that to have the file translated back to the original format
+would remove obfuscation - if I could even fix the code to work in the first
+place. That is not the only reason I did it but it is a reason it is staying
+that way.
+
If you wish to know what the words actually are, I gave a link earlier on, which
+might (haven’t checked it in ages) have more context as well. So I would
+recommend you check that instead. Still now you know what I did if you wish to
+try and figure out how the obfuscation works. I guess the function that does
+this transliteration is w() and of course that also uses the anonymous struct
+so you’d have to trace the call to that.
+
Of course, as w is also a member in the struct that does not help (can’t
+search for w on a word boundary without encountering the members too, members
+that mean different things at different times). If you must know, and I’m not
+guaranteeing this (the heavily commented file might be better at this - you’ll
+have to check as this edit is on the last full day of the contest!) it would
+appear to be v[0] and v[1] and called in some function from main(). No
+that’s not a typo of main(). Both 0 and 1 seem to point to w().
+
+
Unsinkable Sam Medical Records - funny card
+
+
+
+
The issue of spaces
+
+
Here I will talk about the more technical details on why the spaces have to be
+there as well as things I tried to get it to work, keeping in mind the
+constraints of the size limits that I was under (while maintaining the
+obfuscation - if I could even unwind it). I also talk about spaces in general:
+oddities that might be noticed at times.
+
Anyway, to have the reverse with just a few mods is just a bonus, and to have
+the reverse is a bonus in general. It is not clear to me how else it could be
+done.
+
The real trouble is how the language worked. If there was not a word in their
+dictionary they would take the letters of those words and just spell it out with
+their words for the letters. But of course this included multiple words so there
+is the identification issue: what word is actually meant? What if the user means
+something else (which as shown elsewhere this already is a feature of the
+language!).
+
But with translations being multiple words, how would it work without spaces
+(which are mostly an invention for written text, something they only did after
+translating it in their head)? This system does not allow a reverse simply by
+passing the ciphertext back into it. If it did have that it would be far weaker
+(and remember that’s not even the only layer) and would have been much more
+prone to being compromised.
+
In order to make it as natural as possible for input, spaces have to be used,
+and as said, the translation back is just a bonus - not even strictly needed but
+I wanted to be complete.
+
Another question is how to translate it back to English when the word might not
+be in the dictionary? Consider this word: foo. If we print the translation
+without spaces we will get:
+
chuoa-khaa-kha
+
and with spaces:
+
chuo a-kha a-kha
+
Consider the first one. If we’re searching for exact matches (ignoring
+!isalpha()) how can the first translate back to foo? It can’t because
+chuoa-khaa-kha is not any word (that is, the ‘word’ does not even indicate a
+letter to spell out the word)! There is no space there. That is the problem
+at the core.
+
Now as for what might be done with it. There are a number of things that can be
+considered and I have tried all of these - and others. Unfortunately they do not
+work and I believe would be a disservice to the language as well.
+
Why would it be a disservice? Because it would not be a genuine translator.
+There would be no point in it.
+
Anyway here are some things I did try (amongst others not listed) (keep in mind
+I also had already heavily obfuscated things when I tried some of these, but I
+don’t think that even matters - and it was not as obfuscated as it is now, btw):
+
+
We could just ignore the problem; after all they did. In fact the Americans
+did not even know it - hence the story I mentioned earlier on in the
+introduction of this. That’s what I’m doing and of course this is what does
+work.
+
We can try with the shell adding " or ' and then having spaces we can
+tokenise it with strtok(). This almost worked but it had problems with some
+translations for the same reason as noted above. In some cases without the
+tokenisation in I() it does work but not in all. But tokenisation is
+problematic anyway.
+
other things as well, some mentioned below.
+
+
Now, what can be done about this lack of spaces (in some cases and in other cases
+extra spaces, though as discussed this does not always happen - see further down
+for more details on this and why it’s actually a feature and one worth having)?
+
One thought - which I tried - is that I tokenise it by spaces and then add a
+space for each ‘word’ translated. But still what to do about the fact that a
+word is no longer there if the letters are merged?
+
Well in the case of words in the dictionary it is not an issue. But the words
+that were spelt out - those are an issue.
+
Another thing I tried, and this was the closest thing to working (but it did not
+work in full), is to check by length. That would be updating the Y() function.
+
It would have to skip !isalpha() prior to entering the loop and then it would
+in the inner loop (the one with a ‘break’ if the condition is met) check that
+the length is not beyond the word.
+
The theory there is that if the letters match (other characters ignored) and the
+length (number of times we iterated not counting the ignored characters) is the
+length of the encoded string we would then ‘break out’ and so as long as the
+string is empty or the length is the same it would be a match.
+
This did not work so well either although I did confirm that the Y() loop
+broke out in what appeared to be the right place. One thing is that the code in
+Z() would have to be updated in ways that caused other issues and so this was
+obviously the wrong choice too.
+
Keep in mind this too: the matching routine does do some nice things to make it
+a bit easier for input, some of which I already mentioned (I think). Having
+extra spaces is not a big deal. We might even say it is kind of like how the
+Code Talkers had to take a brief moment in translation - and under high stakes.
+
There were other problems as well though. If I got one case fixed another was
+then broken. Worse was that the way it has to be tokenised (it is the only way
+if we want to translate back, which again is just a nice bonus, and not
+something they even had to do!) it means the shell has to help out sometimes (I
+showed an example earlier I think). In one case I got what seemed to work (but
+not completely). But this:
+
./prog.alt $(./prog foo) # where foo is the correct format
+
did not work (but it should now); instead I had to do something like:
+
OUT=$(./prog ...)
+ ./prog.alt $OUT # or maybe it was "$OUT", not sure now
+
This is not useful and very unwieldy, to say nothing about it being error prone
+and problematic in other ways. That might still be useful in cases where I noted
+oddities but I’m not sure of that. Fortunately the above example is not needed
+now.
+
As it is spaces abound!
+
So given these facts and given the amount of frustration I had, and a large part
+of that is because the code is so ridiculously twisted (as you certainly have
+seen and appreciate by now), as well as how the system worked, I decided to
+recall to you the fact that the Code Talkers did this all in their head, they
+knew the language, and they had the convenience of not having to come up with
+word boundaries. They did not need spaces but it didn’t hurt if they had them.
+
Some space issues were resolved, an example above. Another one is that it used
+to on the second line (and those beyond the second line) when reading in from a
+file print a space at the beginning of the line. This was solved with the code
+that uses the L int.
+
As I noted elsewhere (I think) other cipher systems are not problematic in this
+case; for instance with the Enigma they transmitted it over Morse and they had
+spaces. I don’t recall how this was transmitted but it was markedly different in
+how it worked; whereas in the Enigma (and many other ciphers, though I believe
+the Culper Code is one of the exceptions) you aren’t limited to specific words,
+with this you are, and you have to spell out the words by the words for its
+letters (the Culper Code might also be this but I’m not sure).
+
Going back to the disservice part: I believe it would be an injustice to the
+language if this was resolved, if it even can be done without reaching the
+IOCCC size limits (I was able to several times get it down but more problems
+showed up which required more code, and I never did solve it to a satisfactory
+level, based on what I just explained and you now hopefully understand and
+appreciate), because the spaces are a testament to its obscurity (even though
+those over radio do not need spaces), though as you noticed I did get some of it
+resolved.
+
Oh and yes: the size is not at 2503 now. But trying to resolve these ‘issues’
+brought it there and beyond.
+
I do not actually believe it is possible to get rid of the spaces where they are
+and might be deemed incorrect, especially if there is to be a way to translate
+back to English which seems like a good idea (although I did say it might be a
+disservice here, obviously they had to do it, but they didn’t have to worry
+about spaces or word boundaries); this is just the way it is given the multiple
+ways a word can be translated (dictionary translation or else spelt out with
+multiple words, the real trouble).
+
The file mode could have been removed to help with bytes but this limits input
+even more though perhaps given the potential traps it is not really worth it.
+Maybe I should spend time doing something else but given the issues and given
+the amount of obscurity in the code, it would seem to me that it fits the Navajo
+Code Talking language quite well.
+
The fact they did this in their heads in mere minutes, they really were coding
+machines (or maybe encoding and decoding machines) and they had no room for
+error; the fact trying to remove spaces introduces errors and input problems is
+another reason to not worry about spaces, especially as they did not worry about
+it either as they had no need to break it up, not needing word boundaries in the
+way I do! Nobody speaks like this (and I hope this doesn’t change):
That would be ridiculous. We don’t need spaces when speaking. We don’t need to
+see or not see spaces as one is speaking as we’re listening, not reading (okay,
+fine, maybe there are a few very rare exceptions but in general not).
+
Even so I believe the only spaces left are those that are required and in some
+if not all cases they (those) are mere technicalities.
+
Basically, and this is important if you wish to be critical of the spaces:
+spaces are not meant for speaking and that is what they did. They had no visual.
+It was all in their head and they translated it in a matter of minutes. They DID
+write it down for their comrades but the spaces IN translation were utterly
+irrelevant just as they are irrelevant when you’re speaking.
+
I will close this out with these final remarks:
+
In particular, the spaces are added to help out in use of the program.
+This means that sometimes the output can look odd. You’ll notice this especially
+if there is not a word in the dictionary and it has to be spelt one letter at a
+time. This is done so that translations can at least work even if sometimes (for
+instance in ./prog.alt $(./prog b c d) the spaces are not as you wish (or do
+not exist - or presumably not as you wish).
+
If a file being read, depending on how you use the program, has a character that
+is interpreted by the shell (such as *) then just like any other command that
+could cause problems as the shell will have done its thing before the program
+gets the input.
+
Of course to expect one to be able to translate prog.c to Navajo Code Talkers
+and back to English to compile is rather absurd, although you might notice the
+alt code can read in the code and redirect to another file that can then be
+compiled (at least in some cases). It’s important to remember though that the
+alt code simply prints words that are not in Navajo AS IS, UNTOUCHED, and it
+does not print spaces between words - so any spaces are literal. You can observe
+this at the command line too:
+
$ ./prog.alt shush moasi
+ bc
+
+ $ ./prog.alt shush ' ' moasi
+ b c
+
This is a feature and actually can demonstrate the momentary pause as they
+encoded/decoded the message!
+
Why I think this entry is worthy of winning
+
The Code Talkers should be honoured and acknowledged and what better place in a
+contest about obscuring code?
+
I’ve shown everyone that you can do arithmetic on strings in C! Even those few
+who might know this fact would have to actually think about what each of these
+evaluates to (maybe there are a few people who wouldn’t but that’s probably
+extremely rare) and then test their theory out each time (even those who might
+not need a moment to evaluate it in their head might have to do this). The odds
+are they’ll have to look at the ASCII table first.
+
That some of these are recursive and in ternary operator in a loop makes it
+harder to follow still. For instance:
+
for (k = (s*2)**"9"-171+*"9"; H=B[J][X?*"1"-49:s/ *"1"+s/ *"1"+1/ *"1"+(s*s*s)][k]; ++k)
+
is not easy to parse but that’s probably a simpler one. A much more ridiculous
+one is:
The array B is not going to be easy to parse for most people and the use of it
+is hard to parse too, given the arithmetic on strings (and other things). I
+thought about making the alphabet itself encrypted but I needed bytes for more
+interesting things; after all what difference does it make if you can translate
+the rather unknown language when the program (or alt code) can do it for you
+anyway?
+
The anonymous structs for each function which has different values per call,
+often in confusing or misleading ways, is something I have not seen in the
+IOCCC, certainly not like this. It makes it hard to follow the code.
+
Beautifiers (at least some) are not going to help much as they tend to keep
+spaces in place. Of course if the beautifier is not careful it can turn some of
+my code into comments. Some beautifiers are better than others when it comes to
+shortening the program length but I’m not going to help you with that.
+
Oh and btw: what is prog.obfus.c? I think that was a file that I at one point
+ran the code on though I might have had to manipulate the output a bit, in order
+to get it to compile. It very likely (based on the timestamp) was an older
+version of the code, perhaps one of the prog.2.c or prog.3.c files. I’m not
+sure now though. What is prog.pre-format.c? That was a copy of what was
+prog.c at 8 March 2023: so you can see how much it has changed since then as
+well. Similar with some of the other code files. The deobfus.c is
+as noted a heavily commented file although as you’ll see there is some I cannot
+parse even myself.
+
One more thing. The try.sh script has a fun demonstration of
+prog.alt on itself which is then compiled and run on that source file and then
+runs diff on the two files, showing something interesting. I did not have it as
+a try.alt.sh because the try.sh already relies on both being compiled so I
+figured I’d save a file.
All Rights Reserved. Permission for personal, education or non-profit use is
+granted provided this this copyright and notice are included in its entirety
+and remains unaltered. All other uses must receive prior permission in
+writing by contacting the judges.
+← Lines that start with this symbol indicate a change from the
+previous IOCCC.
+
+
Most lines (we sometimes make mistakes) that were modified since the previous
+IOCCC start with a solid 4 pixel black left border (or, in the case of a code
+block or blockquote, just a vertical bar).
These are NOT the IOCCC rules, though it does contain comments
+about them. The IOCCC guidelines should be viewed as
+hints and suggestions. Submission that violate the
+guidelinesbut remain within the rulesare
+allowed. Even so, you are safer if you remain within the IOCCC
+guidelines.
+
+Of course if a guideline is talking about a rule and you break that guideline,
+you stand a good chance of having your submission rejected for breaking the
+rule, not the guideline.
+
+
You SHOULD read the CURRENT IOCCC rules, prior to submitting
+code to the contest.
+This IOCCC runs from 2024-12-29 23:58:13.213455 UTC to 2025-06-05 04:03:02.010099 UTC.
+This IOCCC marks the 40th anniversary of the contest!
+
+
+This contest will enter the pending state on or about
+2024-12-29 23:58:13.213455 UTC.
+When this happens, you may begin registering to enter the IOCCC.
+
+
+This contest will enter the open state on 2025-03-05 23:19:17.131107 UTC.
+When this happens, you may begin uploading your submissions to the IOCCC.
+
+
+This contest will enter the judging state on 2025-06-05 04:03:02.010099 UTC.
+When this happens, you may no longer upload your submissions to the IOCCC.
+
+
+IMPORTANT NOTE: Until the contest enters the open state, any or all
+of the above dates and times may change AT ANY TIME!
+
+
+The reason for the times of day are so that key IOCCC events are calculated
+to be a functional UTC time. :-)
+
+
+NOTE: the updates to these guidelines on 2025-03-10 explained the new -u uuidfile and -U uuidstr options and are NOT important to read, in order
+to follow the guidelines. The options are in a release AFTER THIS IOCCC’s
+official release and not updating the toolkit is PERFECTLY okay.
+
+
+NOTE: the updates to these guidelines on 2025-03-12 also explain how the
+tools that require other tools now search under $PATH. It is perfectly fine to
+not use the newer versions so long as you use the minimum required version of
+the tools. See the
+FAQ on “minimum required version of the tools”
+for more details and the
+FAQ on “obtaining the most recent release of the
+toolkit”
+for more help.
+
+
+Until the contest status becomes open,
+the IOCCC rules,
+IOCCC guidelines and the tools in the
+mkiocccentry repoSHOULD be
+considered provisional BETA versions and may be adjusted AT ANY TIME
+before the contest status becomes open.
+
+
+See the
+FAQ on “how to register and submit to the IOCCC”
+for instructions on registering and participating in the IOCCC, as the process
+may change from contest to contest.
+
+
+To assist in the formation of the xz compressed tarball for submission, use the
+mkiocccentry(1) tool as found in the mkiocccentry repo.
+
+Uploading a tarball not formed by mkiocccentry(1) puts you at a very big risk of
+violating Rule 17, especially as mkiocccentry(1) does a
+great number of things that are required, and it also runs many checks, and if
+any of those checks fail, you are at a very great risk of having your submission
+rejected for violating Rule 17.
+
+IMPORTANT NOTE: the tools that require other tools, mkiocccentry(1) and
+txzchk(1), will, as of version 2.0.2 2025-03-11, search under $PATH. If
+you have an earlier version and you have not installed the tools and run the
+tools from outside the repo directory, you will have to use the options to the
+tools to set the path to the required tools.
+
+While the contest is open, you may modify your
+previously uploaded submission by rebuilding your submission with the
+mkiocccentry(1) tool and then re-uploading it to the same slot number on the
+submit server.
+
+
+HINT: so that you do not have to repeatedly answer all the
+questions, the mkiocccentry(1) tool has the options -a answers, -A answers
+and -i answers, where -a will write to an answers file (if it does not
+already exist), -AWILL OVERWRITE THE FILE and -i will read the answers from
+the file. If you use -A, BE SURE you don’t overwrite another file by accident!
+
+
+Be aware that even with the -i answers you will still be required to confirm
+most if not all y/n questions - you just don’t have to input the name of the
+submission, the abstract, the author details etc. If you really wish to
+circumvent this you can use the -Y option but we do not recommend this because
+if your update breaks a rule or there is some problem, you might not see it.
+
+
+To help with not having to repeatedly enter a UUID, whether for the same
+submission or multiple submissions, you can use the -u uuidfile or -U UUID
+option. See the
+FAQ on “how to avoid re-entering your UUID”
+for more details. Note that the -i answers option cannot be used with the UUID
+options as the answers file includes the UUID.
+
+
+The overall size limit (see Rule 2a) on prog.c has been
+increased from 4096 to 4993 bytes.
+The Rule 2a size was changed from
+4096 to 4993 to keep the “2b to 2a” size ratio to a
+value similar to the 2001-2012 and
+2013-2020 IOCCC eras.
+
+
+The Rule 2b size has increased from 2053 to 2503
+bytes.
+
+
+Your submission must satisfy BOTH the maximum size
+Rule 2aAND the IOCCC size Rule 2b.
+
+
+To check your code against Rule 2, use the iocccentry(1) tool.
+For example:
+
+
iocccsize prog.c
+
+The IOCCC size tool algorithm can be summarized as follows:
+
+
+
The size tool counts most C reserved words (keyword, secondary, and selected
+preprocessor keywords) as 1. The size tool counts all other bytes as 1
+excluding ASCII whitespace, and excluding any ‘;’, ‘{’ or ‘}’ followed by
+ASCII whitespace, and excluding any ‘;’, ‘{’ or ‘}’ byte immediately
+before the end of file.
+
+
ASCII whitespace includes ASCII tab, ASCII space, ASCII newline,
+ASCII formfeed, and ASCII carriage return.
+
+When ‘;’, ‘{’ or ‘}’ are within a C string, they may still not be
+counted by the IOCCC size tool. This is a feature, not a bug!
+
+
+In cases where the above summary and the algorithm implemented by
+the IOCCC size tool iocccsize(1) conflict, the algorithm implemented
+by the current version of iocccsize(1) is preferred by the IOCCC judges.
+
+
+In other words, make sure iocccsize does not flag any issues with your
+prog.c.
+
+
+There are at least 2 other reasons for selecting 2503 as the 2nd limit besides
+the fact that 2503 is a prime. These reasons may be searched for and discovered
+if you are “Curios!” about 2503.
+:-) Moreover, 2053 was the number of the kernel disk pack of one of the judge’s
+BESM-6, and 2503 is a decimal anagram of 2053.
+
+
Take note that this secondary limit imposed by the IOCCC size tool
+obviates some of the need to #define C reserved words in an effort
+to get around the size limits of Rule 2.
Keep in mind that rules change from year to year, so some winning
+entries might not be valid submissions this year; what was unique
+and novel one year might be ‘old’ the next year.
+
A submission is usually examined in a number of ways. We typically apply
+a number of tests to a submission:
+
+
look at the original source
+
C pre-process the source ignoring #include lines
+
C pre-process the source ignoring #defineand#include lines
+
run it through a C beautifier
+
examine the algorithm
+
compile it (with flags to enable all warnings)
+
execute it
+
+
You should consider how your submission looks in each of the above tests.
+You should ask yourself if your submission remains obscure after it has been
+‘cleaned up’ by the C pre-processor and a C beautifier.
+
Your submission need not pass all of the above tests. In certain
+cases, a test is not important. Submissions that compete for the
+‘strangest/most creative source layout’ need not do as well as
+others in terms of their algorithm. On the other hand, given
+two such submissions, we are more inclined to pick the submission that
+does something interesting when it’s executed.
+
We try to avoid limiting creativity in our rules. As such, we
+leave the contest open for creative rule interpretation. As in real
+life programming, interpreting a
+requirements document or a customer request is important. For this reason, we
+often award ‘Best abuse of the rules’ or ‘Worst abuse of the
+rules’ or some variation to a submission that illustrates this
+point in an ironic way.
+
+The IOCCC has a rich history of remarkable winning entries created by
+authors who skillfully employed various techniques to develop their code.
+While it is NOT required, you are allowed to use tools to develop
+and test your submission. These tools may include, but are not limited
+to code generators, code analysis tools, static code analysis tools,
+runtime analysis tools, machine learning tools, natural language models,
+code copilot tools, so-called AI services, large language models (LLMS), etc.
+If you do make use of such tools or services, then we ENCOURAGE you to describe
+how you used such tools in your remarks.md file.
+
+
+You may use git, or services such as GitHub
+to develop and maintain your submission. However, we DISLIKE
+submissions that require them in order to build/compile your submission.
+
+
+Submissions will be judged in an environment that has no IDE.
+Any submission that fails to compile/build because it requires
+an IDE will be rejected.
+
+
+We will use the make(1) tool, your Makefile, and other tools found in
+Single UNIX Specification
+environments and systems that conform to the Single UNIX
+Specification
+in the building and compiling of your submission.
+
+
We do realize that there are holes in the rules, and invite
+submitters to attempt to exploit them. We may award ‘Worst abuse of the
+rules’ or ‘Best abuse of the rules’ or some
+variation and then plug the hole next year.
+
+When we do need to plug a hole in the IOCCC rules or IOCCC
+guidelines, we will attempt to use a very small plug, if not
+smaller. Or, maybe not. :-)
+
+
+There may be fewer than 2^7+1 reasons why these IOCCC
+guidelines seem obfuscated.
+
+
+IMPORTANT: Be sure that your submission works as documented in your
+remarks.md file. We sometimes make an effort to debug a submission
+that has a slight problem, particularly in or near the final round.
+On the other hand, we have seen some otherwise excellent submissions
+fall down because they didn’t work as documented.
+
+
+If you submission has bugs and/or mis-features, you are MUCH BETTER off
+documenting such bugs and/or mis-features in your remarks.md file.
+
+
+Consider an example of a prime number
+printing program that claims that 16 is a prime number.
+Noting such a bug in your remarks.md file could save your submission:
+
+
+
“this submission sometimes prints the 4th power of a prime by mistake”
+
+
Sometimes a strange bug or (mis-)feature can even help the submission! Of course, a correctly
+working submission might be better.
+
+We tend to look down on a prime
+number printer that claims that
+16 is a prime number.
+Clever people will note that 16 might be prime
+under certain conditions. ;-) Wise people, when submitting something clever
+will fully explain such cleverness in their submission’s remarks.md file.
+
+
People who are considering to just use some complex mathematical
+function or state machine to spell out something such as “hello,
+world!” really really, and we do mean REALLY, do need to be more creative.
+
Ultra-obfuscated programs are, in some cases, easier to
+deobfuscate than subtly-obfuscated programs. Consider using
+misleading or subtle tricks layered on top of or under an
+appropriate level of obfuscation. A clean looking program with
+misleading comments and variable names might be a VERY GOOD START
+to a great submission!
+Rule 17 (the mkiocccentry(1) rule) states that
+you REALLY SHOULD use the mkiocccentry(1) tool to package your submission tarball.
+
+
+See the mkiocccentry repo
+for the mkiocccentry(1) tool and below for more details.
+
+
+IMPORTANT NOTE: make CERTAIN you have the most recent version of the
+mkiocccentry toolkit! See the
+FAQ on “obtaining the mkiocccentry toolkit”.
+
+
+mkiocccentry runs a number of checks, by the tool itself and by executing
+other tools, before packaging your xz compressed tarball, including running
+chkentry(1) on the submission directory.
+
+
+If mkiocccentry encounters an error, the program will exit and the xz
+compressed tarball will not be formed. For instance, if
+chkentry fails to validate the submission directory, either because
+of a validation error in the .auth.json or .info.json
+JSON files or because of
+something else that mkiocccentry(1) creates or does, it is an
+error and possibly a bug that you should report as a bug at the
+mkiocccentry bug report
+page.
+PLEASE run the bug_report.sh script to help us out here! See the
+FAQ on “reporting mkiocccentry bugs”.
+
+
+Once the tarball is packaged it will
+run txzchk(1), which will also run fnamchk(1), as part of its algorithm.
+
+
+However, even if mkiocccentry or one of the tools it invokes reports an error,
+it does not necessarily mean it is a bug in the code. It might be an issue with
+your submission. Thus if you report an error as a bug it might not be something
+that will be fixed as there might not be anything wrong with the tools.
+
+
+On the other hand, some conditions flagged by mkiocccentry(1) are warnings
+and it allows you to override these, if you wish. If you’re brave enough you can
+use the -W option to ignore all warnings but this is a big risk; the -y
+option will assume ‘yes’ to most questions but this is also a big risk. Using
+-Y will say ‘yes’ to even more prompts. Needless to say, we do NOT
+recommend these options.
+
+
+In many places it will prompt you to verify what you input, allowing you to
+correct details as you go along. Be advised that there is a default answer and
+if you press enter it will proceed with that default, so make sure you have
+provided the correct answer.
+
+
+If you wish to test that your submission passes the mkiocccentry(1) tests
+without having to type in in answers each time, you can use the -d or -s seed
+option to mkiocccentry for the tool to pseudo-randomly create answers for you.
+For example:
+
+
mkiocccentry -d workdir topdir
+
+IMPORTANT NOTE: if you run an IOCCC related tool outside the repo directory
+(specifying the absolute or relative path to the tool) and you have not
+installed the tools (and we STRONGLY recommend you do install them),
+then you will have to specify the options (such as paths) for the tools that are required like
+chkentry(1), txzchk(1) and fnamchk(1).
+
+
+Make sure you have
+the latest version of of the mkiocccentry toolkit
+so that you do not violate Rule 17 by mistake.
+
+To help you with editing a submission, the mkiocccentry(1) tool has
+some options to write OR read from an answers file so you do not have to input
+the information about the author(s) and the submission more than once, unless of
+course you need to make some changes, in which case you can use the option that
+overwrites the file. If you do use the overwrite option, MAKE SURE you do
+not overwrite another file!
+
+The mkiocccentry(1) tool will execute a number of tools, some of which will
+execute one or more additional tools.
+
+
iocccsize
+
+mkiocccentry(1) will use code from iocccsize(1) which detects a number of
+issues (such as Rule 2) that you may ignore, if you wish, as
+noted above.
+
+
+In other words, you no longer need to run iocccsize manually. However, the
+checks described above are still made but through the mkiocccentry(1) tool itself.
+
+mkiocccentry(1) will write two JSON files: .auth.json and
+.info.json. These files contain information about the author(s) and about the
+submission. After these files are formed, the chkentry(1) tool will be run on
+the submission directory; this tool not only validates the two JSON files
+(and runs specific checks on them after validating the JSON), but it also
+verifies that what is in the manifest in .info.json matches the contents of
+the directory, in addition to other checks. If chkentry(1) fails to validate
+anything at all, your submission WILL BE rejected!
+
+
+IMPORTANT: although chkentry(1) validates the files in the directory, it
+only inspects the contents of the two JSON files; it performs other kinds of
+checks on the other files, and those checks are run on the two JSON files as
+well.
+
+
+If you submit your own JSON files (other than .auth.json and
+.info.json) then they do NOT have to be valid JSON.
+However, if you do provide such invalid JSON files, PLEASE
+document and explain this in your remarks.md file.
+
+from the top level repo directory itself and attach the bug report file (it will
+tell you the name of the file). See also the
+FAQ on “reporting mkiocccentry bugs”.
+
+
+Assuming that chkentry(1) successfully validates your submission directory,
+the tarball will be formed and then txzchk(1) will be executed on it. In this
+case, there should be no problems, as mkiocccentry(1) should NOT form a
+tarball if there are any issues.
+
+
+If mkiocccentry(1) is used and chkentry(1) fails to validate your submission
+directory, then unless it is a system specific problem, it could be a bug in
+mkiocccentry(1), chkentry(1) or possibly jparse, although this is unlikely.
+Nonetheless, if you believe there is a bug, you may report it as explained above.
+
+
+If you want to know what .auth.json is, see the
+FAQ on “.auth.json”.
+If you want to know what the .info.json file is, see the
+FAQ on “.info.json”.
+On the other hand, if you want to know a bit more details about chkentry(1), see the
+FAQ about “chkentry”.
+
+The jparse parser, library and tools were co-developed by Cody Boone
+Ferguson and Landon Curt
+Noll in 2022-2025 and come from the
+jparse repo. However, the mkiocccentry
+tools use a clone of the jparse repoat
+a specific release. Thus the mkiocccentry will at times be behind the
+jparse repo!
+
+
+You do NOT need to installjparse from the jparse
+repo! The mkiocccentry tools link in the
+static library from mkiocccentry’s clone.
+
+In other words, mkiocccentrycontains everything you need, and even if you
+do install the libraries from their respective repos, it/they will not be
+used when compiling the mkiocccentry tools. This is important to
+make sure that you’re using the correct versions, which is also verified by
+chkentry (in the JSON files created by mkiocccentry(1)). See Rule
+17!
+
+txzchk(1) performs a wide number of sanity checks on the xz compressed
+tarball; if any issues are found (‘feathers are stuck in the tarball’ :-) )
+AND if and ONLY IF you used mkiocccentry(1), then it is possibly a
+bug in one of the tools and you might want to report it as a bug at the
+mkiocccentry bug report
+page.
+PLEASE run the bug_report.sh script to help us out here! You may do this
+by running from the top level directory of the repo make bug_report. See the
+FAQ on “reporting mkiocccentry bugs”.
+
+
+As part of its algorithm, txzchk(1) will run fnamchk(1) on the
+tarball to verify that the filename is valid. See the
+FAQ on “fnamchk”
+and the fnamchk section below for more details on this tool.
+
+
+It is beyond the scope of this document to discuss the many tests that
+txzchk(1) performs; if you wish to know, we refer you to the source
+code or the man
+page. You might just find a fun option if you do either of these!
+
+
+Of course, as txzchk does not extract the tarball, it is possible that if you
+manually package your submission tarball and/or find and exploit a missing
+check, you could still be violating Rule 17.
+
+
+
Including optional and extra files
+
+
+The maximum total number of files that may be submitted has changed to 39 files.
+However, of those files, 5 are mandatory (prog.c, Makefile, remarks.md and
+the two JSON files generated by mkiocccentry(1), .info.json and
+.auth.json).
+
+
+Additionally, three of the files, if included, MUST be
+specific file(name)s AND in the top level directory, or they will be counted as
+an extra file, not an optional file.
+
+
+In particular, any file that is not prog.c, Makefile, remarks.md,
+try.sh, prog.alt.c or try.alt.sh will be counted as an extra file, and if
+try.sh, prog.alt.c or try.alt.sh are not in the top level submission
+directory they will also be counted as an extra file. The .info.json and
+.auth.json files are not counted as extra files but are required.
+
+
+In other words, the actual amount of EXTRA files is 31.
+
+
+If you use an optional filename for something other than their intended use
+in order to get past the file limit, we will consider that an
+abuse of rules. For more details on the optional files, see the
+FAQ on the “try.sh script system”
+and the
+FAQ on “alt code”.
+
+
+If you REALLY MUST include more files than the limit allows, then you may do so by including as an extra
+file, a tarball. This does NOT have to pass txzchk(1) tests; only the
+submission tarball must pass the txzchk(1) tests.
+
+
+If you DO include a tarball, and the build process or the program extracts
+said tarball(s), the make clobber rule MUST remove the extracted files. Even so, if you
+include a tarball to get past the limit on the number of files, you MUST
+justify this in your remarks.md file.
+
+
+IMPORTANT REMINDER: make SURE your tarball does NOT reveal who you are!
+The mkiocccentry(1) tool creates a v7 format tarball to prevent this. You can
+do the same like:
+
+
tar --format=v7 -cJf foo.txz directory
+
+See Rule 17 and in particular the part about the maximum
+number of files. If you do not follow these points, you
+are at a great risk of violating Rule 17!
+
+
+NOTE: if you want to include a test-suite that requires a lot of files,
+please suggest this in your remarks.md and if your submission wins it can
+be done. In other words you should not use a tarball for a test-suite unless you
+have a very good reason for this (and if you do, make SURE you specify why
+in your remarks.md file).
+
+As an important part of its algorithm, txzchk(1) directly executes
+fnamchk(1). If the filename is invalid (or the filename does not match the
+directory name of the tarball) then it is an error and you risk violating
+Rule 17. Nevertheless, you can run the tool manually,
+should you wish to.
+
+
+For more information on fnamchk and how to manually validate your submission
+tarball filename, see the
+FAQ on “fnamchk”.
+
+
+It is extremely unlikely that fnamchk(1) reporting an invalid filename is a
+bug in fnamchk(1) and as such, ignoring such an issue risks violating Rule
+17 which is a big risk. Of course, using mkiocccentry(1)
+would prevent this from happening as it would not create such a file anyway. If
+mkiocccentry(1) was used it would rather suggest a bug in one of the tools and
+you should report it as a bug at the mkiocccentry issues
+page.
+See the
+FAQ on “reporting mkiocccentry bugs”.
+
+
+As you can see, the use of mkiocccentry(1) is HIGHLY RECOMMENDED, and at
+the risk of stating the obvious, you run A VERY BIG RISK of having
+your submission rejected if you package your own tarball, and there are ANY
+problems. For instance, if chkentry(1) found a problem in your .info.json
+file, the mkiocccentry(1) tool would not package it. But if you were to package
+it manually, you would be violating Rule 17. But even if
+everything checks out OK you should NOT assume that everything IS OK.
+
+
+
Problems and/or bugs in tools
+
+
+Although the tools have been tested extensively, it is nonetheless possible for bugs to
+exist in the code, as all programmers know. In this case, please ask for help or report what
+you think is a bug via the bug report issues page in the mkiocccentry
+repo.
+
+
+Of course, it is also possible for mkiocccentry(1), or one or more of the
+tools it executes (or another tool executes), to fail, but NOT because of a
+bug. An example problem is if there is not enough memory available or if some
+other library or syscall fails. Nonetheless it might be worth reporting as a
+bug; it is a judgement call: if it’s a bug it’ll be addressed and if it’s not
+that’s OK too!
+
+
+
+
Makefiles
+
+
+
+We recommend AND encourage you to use the example Makefile,
+as the starting point for your submission’s required Makefile:
+
+Feel free to modify the Makefile to suit your obfuscation
+needs.
+
+
+Please add a space between the = and the value of variables, in the
+Makefile, making sure that the = comes immediately after the name. See the
+example Makefile for examples.
+
+
+The rest of this section and its subsections will assume that you are using some
+variant of the example Makefile, again renamed as Makefile.
+
+
+We suggest that you compile your submission with a commonly available
+-std=gnu17 (ISO C 2017 with GNU extensions) C compiler, via clang(1)
+and/or gcc(1).
+
+
+
+
Default compiler flags
+
+
+
+Unless you clearly state otherwise in your remarks.md file, AND put in
+your submission’s Makefile, we will compile using -std=gnu17 -O3!
+
+
+It is OK if you need to require your submission to NOT be compiled
+using the default -std=gnu17 -O3 settings. Simply explain why
+your submission should NOT be compiled using -std=gnu17 -O3 in
+your remarks.md file, AND adjust your Makefile accordingly.
+
+
+One reason that you might have to change the flags, is that the optimiser is
+known to break some programs, but there are certainly other possible valid
+reasons. Again, just update the Makefile and explain it in your remarks.md.
+See the optimiser section for details for changing optimiser
+flags.
+
+IMPORTANT NOTE: The use of -std=gnu17 does NOT imply the use of the gcc
+compiler! We often start by compiling using the clang C compiler instead.
+
+
+PLEASE NOTE: in macOS, the compiler gcc found at /usr/bin/gcc is
+in truth the clang compiler, as /usr/bin/gcc --version will show!
+
+
+
+
C standard
+
+
+
+You may change the standard under which your submission is compiled
+by modifying the CSTD Makefile variable. For example, to use c99 instead:
+
+
CSTD= -std=c99
+
+
+
+
+
+
Default optimisation level
+
+
+
+
+
+
+You may change the level of optimization and compiler debug level
+that your submission is compiled with, by modifying the OPT Makefile variable.
+For example, to compile without optimization, and to include debug symbols:
+
+
OPT= -O0 -g3
+
+
+
Compiler warnings
+
+
+
+The default warning flags are set via the CWARN variable, as shown in the
+example Makefile:
+
+
# Common C compiler warning flags
+ #
+ CWARN= -Wall -Wextra ${CSILENCE} ${CUNKNOWN}
+For compilers, such as clang, that have the -Weverything option,
+while you may wish to try it, you should read our
+FAQ on “clang -Weverything”.
+We do NOT recommend that you put
+the use of -Weverything into your submission’s Makefile for the reasons
+cited there. This goes even if your version does not trigger a warning as some
+other version might!
+
+
+On the other hand, if ${CC} has “clang” in the name, the example Makefile will
+automatically enable -Weverything, so you might have to use -Wno-foo
+options anyway, as detailed below. See the
+FAQ on “-Weverything”
+for more details.
+
+
+If “clang” is NOT in ${CC}, the CWARN variable will not be further
+modified.
+
+
+There is no real penalty for compiler warnings. Sometimes
+compiler warnings cannot be helped: especially in the case of
+obfuscated C. :-) So if you cannot easily get rid of a compiler
+warning, try not to fret too much.
+
+
+We LIKE code that has a minimum of warnings, especially under the
+more strict -Wall -Wextra -pedantic mode:
+
+
CWARN= -Wall -Wextra -pedantic
+
+The two previous guidelines might be thought by some as being somewhat
+contradictory. Isn’t life, and isn’t trying to satisfy “contradictory customer
+requirements” all too often like that? :-) Try to minimize warnings if you
+can.
+
+
+If you manage to produce very few warnings, or perhaps no warnings at
+all under the -Wall -Wextra -pedantic mode, then by all means brag about it in
+your remarks.md file AND BE SURE TO TELL US the OS, OS version, compiler
+and compiler version in which you observed this occurring (in case our OS and
+compiler produces a different result: so your submission won’t be penalized for
+not meeting your claims).
+
+
+On the other hand, some warnings cannot be disabled and are enabled by compilers
+without any warning option specified. These are sometimes inevitable in
+obfuscated code and even in some non-obfuscated code, and you should not worry
+about this, though it might be worth pointing out.
+
+
+For instance, some compilers like to warn about use of pointers as arrays, which seems to
+be dubious, as it obviously can’t (always) be avoided, being a big part of C, so
+you should not worry about this either; this is the warning
+-Wunsafe-buffer-usage and the way to disable it is -Wno-unsafe-buffer-usage.
+See also the
+FAQ on “forced warnings”
+and the
+FAQ on “-Weverything”.
+
+
Disabling warnings
+
+If you do have to disable warnings due to -Weverything automatically being
+included, you might wish to state this fact in your remarks.md file.
+And even without -Weverything there can be warnings, as noted above.
+
+
+If your submission issues lots of warnings but is otherwise
+marvelously obfuscated in multiple levels, don’t worry about it. Nevertheless,
+be sure that the warnings do not constitute a potential “show stopper”
+compiler problem. Be sure that compilers such as both gcc and clang won’t
+produce a compiler error and refuse to compile your code: unless for some
+reason that is what you intend to happen in which case document that too in your
+remarks.md file. :-)
+
+
All other things being equal, a program that must turn off fewer
+warnings will be considered better, for certain values of better.
+
+To turn off a compiler warning, in your submission’s Makefile,
+try something such as:
+
+If you do add “-Wno-foo” to your Makefile, consider changing:
+
+
CUNKNOWN=
+
+to:
+
+
CUNKNOWN= -Wno-unknown-warning-option
+
+Some compilers have reported this as an error, however, and if you have
+such a compiler you might want to not add it, or at least note in your
+remarks.md file, which OS, OS version, compiler and compiler version
+that has such a problem.
+
+
+
Defining macros in the Makefile
+
+
+If you need to define something on the compile line, use
+the CDEFINE Makefile variable. For example:
+
+
CDEFINE= -Dfoo -Dbar=baz
+
+NOTE: just because we offer a default way to use the -D option, we still
+do not like excess use of -D to get past size limits, especially since you
+could use #define in your code instead.
+
+
+
Include files in the Makefile
+
+
+If you need to include a file (as in #include) on the command line, use the
+CINCLUDE Makefile variable. For example:
+
+
CINCLUDE= -include stdio.h
+
+
Magic in the Makefile
+
+
+If you need to add other “magic” flags to your compile line,
+use the COTHER Makefile variable. For example:
+
+
COTHER= -fno-math-errno
+
+NOTE: We only recommend using “magic” flags if BOTHgcc
+andclang support it.
+
+
+Again, please note that in macOS, /usr/bin/gcc is actually clang!
+
+
+
The clobber rule
+
+
+When make clobber is invoked, we request that submissions be restored
+to their original submission state. For example, any temporary files
+(including the compiled program(s)) created during the build process, or
+during execution should be removed by the clobber rule. In other words, the
+only things that should be in the directory after running make clobber is what
+is in your submission tarball itself.
+
+
+While people are free to manage their submission under git(1) or even use a
+GitHub repo, dot-files and dot-directories such as .git are not allowed in a
+submission.
+
+
+The mkiocccentry(1) tool will ignore dot-files and dot-directories (such as
+.vimrc, .bashrc, .git and .github) and not put them in the submission’s
+compressed tarball. So while you may use such files and
+directories to help develop your submission, they won’t be included when you run
+the mkiocccentry(1) tool.
+
+
+Even if you did manage to get dot files or dot directories in the tarball
+somehow, txzchk(1) will flag it as an error. When the judges run txzchk(1)
+on the uploaded submission compressed tarball, if anything is wrong, for
+instance if you “sneak in” any dot files or dot directories, the submission
+WILL BE REJECTED for violating Rule 17!
+
+
+You may use whatever tools you need to develop your submission, including the
+use of git(1) or gh(1), just be sure that your submission code and your
+submission Makefile don’t depend on such tools.
+
+
+Of course if you do use GitHub to work on your submission, you might want to
+make the repo private so you don’t reveal who you are. :-)
+
+
+If this is not clear, please do NOT use these tools to help with the
+clobber rule! For instance, do NOT use git clean! Not only does this
+depend on the user having git(1) but it also does not account for the
+submission tarballs. Even worse is when someone does have it in a git(1) repo
+it will remove files that are not under git(1) control! Instead, see the
+clobber rule in the example Makefile to see how to manage this.
+
+
+In other words, for make clobber, do something like:
+
+
clobber:
+ ${RM} -f foo bar baz
+
and NOT something like this:
+
# do NOT do this!
+ clobber:
+ -git clean -f # WRONG !!!
+
+And do NOT use git for any other Makefile rule either.
+
+
+NOTE: mkiocccentry(1) will directly run make clobber in the submission
+directory. And although it is not an error if this fails, if it fails because the
+Makefile does not have a clobber rule, it will be flagged by mkiocccentry(1)
+(you may ignore this but it does put you at a risk of violating the rules).
+
+We VERY MUCH LIKE submissions that use an edited variant of the
+example Makefile, as described and linked to in the Makefile section,
+renamed as Makefile of course. This makes it easier for the IOCCC judges
+to test your submission. And if your submissions wins, it makes it easier to integrate it into
+the Official IOCCC winner website.
+
+
+We VERY MUCH LIKE submissions that have some educational value. This does NOT mean
+that your submission should not be obfuscated but rather that the IOCCC has moved away from
+the idea of “spoilers”. You should not encrypt or rot13 content in your remarks.md file.
+
+
+It is VERY MUCH appreciated if your remarks have some educational
+value. And although educational value is not required, it is an
+EXCELLENT bonus.
+
+
+We LIKE submissions that use an edited version of the
+try.sh example script (and if you have alternate code,
+the same applies with the try.alt.sh script):
+
+Of course, it is quite possible that only one invocation is
+possible, so it is not necessarily detrimental to your submission if you do not
+include one, though we do like interesting and creative uses of submissions. See
+also the
+FAQ on “submitting try.sh and try.alt.sh scripts”.
+
+
+You might wish to add ./try.sh to the try rule in the Makefile you submit.
+If you have alternate code, then you can use the try.alt rule as well.
+
+
Doing masses of #defines to obscure the source has become ‘old’. We
+tend to ‘see thru’ masses of #defines due to our pre-processor tests
+that we apply. Simply abusing #defines or -Dfoo=bar won’t go as far
+as a program that is more well rounded in confusion.
+
Many C compilers DISLIKE the following code, and so do we:
+
#define d define
+ #d foo /* <-- don't expect this to turn into #define foo */
+
+In other words, it is a compilation error, and in order to get older
+IOCCC winning entries that did this to compile, we had to update them to not do this.
+
+
When declaring local or global variables, you should declare the type:
+
int this_is_fine;
+ this_is_not; /* <-- Try to avoid implicit type declarations */
+
+We tend to like less a submission that requires either
+gccORclang. We prefer submissions that can compile
+under BOTHgccANDclang.
+
+
+We RECOMMEND that the compiler flags you use in your
+submission’s Makefile are supported by BOTHgccANDclang.
+
+
+We DISLIKE the use of obscure compiler flags, especially
+if gcc and/or clang do not support it. We suggest
+that you not use any really obscure compiler flags if you can help it.
+
+
One side effect of the above is that you cannot assume the use
+of nested functions such as:
+
int main() {
+| void please_dont_submit_this() {
+| printf("The machine that goes BING!!\n");
+ }
+| please_dont_submit_this();
+ }
+
On 2012 July 20, the IOCCC judges rescinded the encouragement of
+nested functions. Such constructions, while interesting and sometimes
+amusing, will have to wait until they are required by a C standard that are
+actually implemented in BOTHgccANDclang.
+
+We DISLIKE submissions that require the use of -fnested-functions.
+
+
We prefer programs that do not require a fish license: crayons and
+cat detector vans not withstanding.
+
If your submission uses functions that have a variable number of
+arguments, be careful. Systems implement va_list in a wide variety
+of ways. Because of this, a number of operations using va_listare
+not portable and must not be used:
+
+
assigning a non-va_list variable to/from a va_list variable
+
casting a non-va_list variable into/from a va_list variable
+
passing a va_list variable to a function expecting a non-va_list arg
+
passing a non-va_list variable to a function expecting a va_list arg
+
performing arithmetic on va_list variables
+
using va_list as a structure or union
+
+
In particular, do not treat va_list variables as if they were a char **.
+
+We DISLIKE the use of varargs.h. Use stdarg.h instead.
+
+
+We DISLIKE the use of gets(3). Use fgets(3) instead.
+
+
+We tend to DISLIKE the blatant use of tarballs in an attempt to simply get
+around the extra file number limit. We realize there may be cases where a
+tarball containing a number of extra files may be needed. Such a need for a
+tarball MUST be explained in the remarks.md file.
+
+
On 28 January 2007, the Judges rescinded the requirement that the
+# in a C preprocessor directive must be the 1st non-whitespace byte.
+
The exit(3) function returns void. Some broken systems have exit(3)
+return int; your submission should assume that exit(3) returns a void.
+
+This guideline has a change mark at the very start of this line.
+
+
Small programs are best when they are short, obscure and concise.
+While such programs are not as complex as other winners, they do
+serve a useful purpose: they are often the only program that people
+attempt to completely understand. For this reason, we look for
+programs that are compact, and are instructional.
+
+While those who are used to temperatures found on dwarf
+planets
+(yes Virginia, dwarf planets ARE planets!), such as
+Pluto, might be able to
+explain to the Walrus why our seas are boiling hot, the question of
+whether pigs have wings is likely to remain a debatable point to most.
+
+
+One line programs should be short one line programs: say around 80 to 132
+bytes long. Going well beyond 132 bytes is a bit too long to be called
+a one-liner in our vague opinion.
+
+
We tend to DISLIKE programs that:
+
+
are very hardware specific
+
are very OS version specific (index(3)/strchr(3) differences are OK, but
+sockets/streams specific code is likely not to be)
+
dump core or have compiler warnings (it is OK only if
+you warn us in your remarks.md file)
that mandate the exclusive use of a specific Integrated Development Environment (IDE)
+
+
In order to encourage submission portability, we DISLIKE submissions that
+fail to build unless one is using an IDE. For example, do not
+mandate that one must use Microsoft Visual Studio to compile
+your submission.
+
+The program must compile and link cleanly in a Single UNIX
+Specification
+environment. Therefore do not assume the system has a
+windows.h include file:
+
+
#include <windows.h> /* we DISLIKE this */
+
Unless you are cramped for space, or unless you are entering the
+‘Best one liner’ category, we suggest that you format your program
+in a more creative way than simply forming excessively long lines.
+
At least one judge prefers to maintain the use of the
+leap-second
+as part of the world’s time standard. If your code prints time
+with seconds, we prefer that your code be capable of printing the
+time of day during a leap-second where the value in seconds
+after the minute mark is 60.
+
The Makefile should not be used to try and get around the size limit. It is
+one thing to make use of a several -Ds on the compile line to help out, but it
+is quite another to use many bytes of -Ds in order to try and squeeze the
+source under the size limit.
+
Your source code, post-pre-processing, should not exceed the size of
+Microsoft Windows. :-)
+
+Other windows, on the other hand, might be OK: especially where “X
+marks the spot”. Yet on the third hand, windows are best when they are
+“unseen” (i.e., not dirty). :-)
+
+
+The IOCCC judges, as a group, have a history giving wide degree of latitude
+to reasonable submissions. And recently they have had as much longitudinal
+variation as it is possible to have on Earth. :-)
+
+You may compile and use your own programs. If you do, try to build and execute
+from the current directory. This restriction is not a hard and
+absolute one. The intent is to ensure that the building of your
+program is reasonably portable.
+
+
We prefer programs that are portable across a wide variety of UNIX-like
+operating systems (e.g., Linux, GNU Hurd, BSD, UNIX, etc.).
+
+
You are in a maze of twisty guidelines, all different.
+
+
There are at least zero IOCCC judges who think that
+Fideism has little
+or nothing to do with the IOCCC judging process.
+
Don’t forget that the building of your program should be done
+WITHOUT human intervention. So don’t do things such as:
+
prog: prog.c
+ #echo this next line requires data from standard input
+ cat > prog.c
+ ${CC} prog.c -o prog
+
However, you can do something cute such as making your program
+do something dumb (or cute) when it is built ‘automatically’, and
+when it is run with a human involved, do something more clever.
+For example, one could put in their Makefile:
+
prog: prog.c
+ ${CC} prog.c -DNON_HUMAN_COMPILE -o prog
+ @echo "See remarks section about alternate ways to compile"
+
and then include special notes in your remarks.md file for
+alternate / human intervention based building.
+
We want to get away from source that is simply a compact blob of
+bytes. REALLY TRY to be more creative than blob coding. HINT!
+
Please do not use things like gzip(1) to get around the size limit.
+Please try to be much more creative.
+
We really DISLIKE submissions that make blatant use of including
+large data files to get around the source code size limit.
+
We do not recommend submitting systemd source code to the IOCCC,
+if nothing else because that code is likely to exceed the source code
+size limit. This isn’t to say that another highly compact and obfuscated
+replacement of init would not be an interesting submission.
+
Did we remember to indicate that programs that blatantly use
+some complex state machine to do something simple, are boring?
+We think we did. :-)
+
+
All generalizations are false, including this one. – Mark Twain
+
+
+Given two versions of the same program, one that is a compact blob
+of code, and the other that is formatted more like a typical C
+program, we tend to favor the second version. Of course, a third
+version of the same program that is formatted in an interesting
+and/or obfuscated way, would definitely win over the first two!
+Remember, you can submit more than one submission. See the IOCCC
+rules for details (in particular, Rule 9).
+
+
We suggest that you avoid trying for the ‘smallest self-replicating’
+source. The smallest, a zero byte entry, won in
+1994.
+
Programs that claim to be the smallest C source that does something, really
+better be the smallest such program or they risk being rejected because
+they do not work as documented.
+
Please note that the C source below, besides lacking in obfuscation,
+is NOT the smallest C source file that when compiled and run, dumps core:
+
main;
+
+Unless you specify -fwritable-strings (see COTHER in the example
+Makefile, described in the Makefile section), do not assume this
+sort of code will work:
+
+
char *T = "So many primes, so little time!";
+ ...
+ T[14] = ';'; /* modifying a string requires: -fwritable-strings */
+
+Even so, one should probably not assume that this is universally accepted.
+
+
+Initialized char arrays are OK to write over. For instance, this is OK:
+
+
char b[] = "Is this OK";
+ b[9] = 'k'; /* modifying an initialized char array is OK */
+
+There are more than 1 typos in this very sentence.
+
+
X client submissions should be as portable as possible. Submissions that
+adapt to a wide collection of environments will be favored. For
+example, don’t depend on a particular type or size of display.
+Don’t assume the use of a particular browser. Instead assume a
+generic browser that forms to a widely used W3C
+standard.
+Don’t assume a particular sound sub-system or video driver is installed
+in the OS. Instead, make use of a well known and widely available open
+source program (one that actually works) to display audio/visual data.
+
X client submissions should avoid using X related libraries and
+software that are not in wide spread use.
+
+As of Red Hat RHEL9.0, the X.org server is deprecated. See the
+FAQ on “Xorg deprecation””
+for more details. This does not mean that a submission using this will
+necessarily be rejected, but it would be better if it can support Wayland in
+some way or another.
+
+
This could be the only guideline that contains the word
+fizzbin.
+
+However, do you know how to play fizzbin?
+You do?!? (Except on Tuesday?)
+
+
+OK, there are actually 2 guidelines that contain the word
+fizzbin,
+unless you count this one, in which case there are 3. :-)
+
+
We DISLIKE submissions that use proprietary toolkits such as the M*tif,
+Xv*ew, or OpenL*ok toolkits, since not everyone has them. Use an
+open source toolkit that is widely and freely available instead.
+
NOTE: The previous guideline in this spot has been replaced by this guideline:
+
+X client submissions should try to not to depend on particular items in
+.Xdefaults. If you must do so, be sure to note the required lines
+in the your remarks.md file. They should also not depend on any
+particular window manager.
+
+
+Try to avoid submissions that play music that some people believe is copyrighted
+music.
+
+
+While we recognize that UNIX is not a universal operating system, the contest
+does have a bias towards such systems. In an effort to expand the scope of the
+contest, we phrase our bias to favor the Single UNIX
+Specification.
+
You very well might not be completely prohibited from failing to not partly
+misunderstand this particular guideline, but of course, we could not possibly
+comment! :-) Nevertheless, you are neither prohibited, nor are you fully
+required to determine that this or the previous sentence is either false and/or
+perhaps misleading. Therefore, it might be wise for you to not fail to consider
+to not do so, accordingly. Thank you very much.
+
+
Any complaints about the above guideline could be addressed to the
+Speaker of the House of Commons, or to the speaker of your national
+parliament should you have one.
+
We LIKE programs that:
+
+
are as concise and small as they need to be
+
do something at least quasi-interesting
+
are portable
+
are unique or novel in their obfuscation style
+
make use of a NUMBER OF DIFFERENT TYPES OF OBFUSCATIONS!<== HINT!!
+
make us laugh and/or throw up :-) (humor really helps!)
+
make us want to eat good chocolate
+
+
Some types of programs can’t excel (anti-tm) in some areas. Your
+program doesn’t have to excel in all areas, but doing well in several
+areas really does help.
+
+You are better off explaining what your submission does in your
+remarks.md file section rather than leaving it obscure for the
+IOCCC judges as we might miss something and/or be too tired to
+notice.
+
+
+Please avoid this specific individual guideline, if it at all possible.
+
+
+We freely admit that interesting, creative or humorous comments in
+your remarks.md file help your chances of winning. If you had to
+read so many twisted submissions, you too would enjoy a good laugh or two.
+We think the readers of the contest winners do as well. We do read
+your remarks.md content during the judging process, so it is worth your
+while to write a remarkable remarks.md file.
+
+
We DISLIKE C code with trailing control-M’s (\r or \015) that results
+in compilation failures. Some non-UNIX/non-Linux tools such as
+MS Visual C and MS Visual C++ leave trailing control-M’s on lines.
+Users of such tools should strip off such control-M’s before submitting
+their submissions. In some cases tools have a “Save As” option that will
+prevent such trailing control-M’s being added.
+
One should restrict libcurses to portable features found on BSD
+or Linux curses.
+
+Rule 13 no longer discourages the use of UTF-8
+characters in C code.
+
+
+It is a very good idea to, in your remarks.md file, tell us why you
+think your submission is obfuscated. This is particularly true if
+your submission has some very subtle obfuscations that we might
+otherwise overlook. <<– Hint!
+
+
Anyone can format their code into a dense blob. A really clever
+author will try format their submission using a “normal” formatting style
+such that at first glance (if you squint and don’t look at the details)
+the code might pass for non-obfuscated C. Deceptive comments,
+and misleading formatting, in some cases, may be a plus. On the
+other hand, a misleading code style requires more source bytes.
+
If you do elect to use misleading formatting and comments, we
+suggest you remark on this point in your remarks.md where you talk
+about why you think your submission is obfuscated. On the other hand,
+if you are pushing up against the size limits, you may be forced
+into creating a dense blob. Such are the trade-offs that obfuscators face!
+
+We prefer code that can run on either a 64-bit or 32-bit
+processor. However, it is UNWISE to assume it will run on an
+some Intel-like x86 architecture**.
+
+
We believe that Mark Twain’s quote:
+
+
Get your facts first, then you can distort them as you please.
+
+
… is a good motto for those writing code for the IOCCC.
+
+The IOCCC size tool source is not an original work, unless you are Anthony C
+Howe, in which case it is original! :-)
+Submitting source code that uses the contents of
+iocccsize.c,
+unless you are Anthony C Howe, might run the
+risk of violating Rule 7.
+
+
+The IOCCC submission tarball validator source is not an original work,
+unless you are Cody Boone Ferguson, in
+which case it is original! :-) Submitting source code that uses the contents of
+txzchk.c,
+unless you are Cody Boone Ferguson, might
+run the risk of violating Rule 7.
+
+And unless you are Landon Curt Noll,
+the code in
+dbg and
+dyn_array are
+not original works. Submitting source code that uses the contents of those
+libraries, unless you Landon Curt Noll,
+might run the risk of violating Rule 7.
+
+
+Rule 7 does not prohibit you from writing your own
+obfuscated versions of these tools, unless of course you are Landon Curt
+Noll, in which case you probably
+won’t win since IOCCC judges should not enter the IOCCC! :-)
+However, if you do write your own version, you might wish to make it do something
+more interesting than simply implementing the IOCCC
+tools’ algorithms.
+
+
+Even so, we do not recommend you try and submit a JSON parser due to
+the fact it will likely exceed the source code size limit
+and because you likely can’t beat flex and
+bison in obfuscation. This isn’t to
+say that the so-called JSON spec is not
+obfuscated, but unless you have some really clever way to compact and
+obfuscate a JSON parser more than flex and
+bison you will likely not win, either
+because of the source code size limit or because it is not
+as obfuscated as the flex and bison
+generated code of
+jparse.
+
+
While programs that only run in a specific word size are OK, if you have
+to pick, choose a 64-bit word size.
+
+If the IOCCC judges are feeling ornery we
+might choose to compile your program for running on an Arduino or
+a PDP-11. Heck, should we ever find an emulator of 60-bit CDC Cyber
+CPU, we might just try your submission on that emulator as well :-)
+
+
+If your submission MUST run only on a 64-bit or 32-bit architecture,
+then you MUST specify the -arch on your command line
+(see ARCH in the example
+Makefile, described in Makefile section). Do not assume a
+processor word size without specifying -arch. For example:
+
+
ARCH= -m64
+
+Note, however, that some platforms will not necessarily support some
+architectures. For instance, more recent versions of macOS do NOT support
+32-bit!
+
+
+If there are limitations in your submission, you are highly encouraged
+to note such limitations in your remarks.md file. For example if your
+submission factors values up to a certain size, you might want to state:
+
+
+
This submission factors values up 2305567963945518424753102147331756070.
+Attempting to factor larger values will produce unpredictable results.
+
+
The IOCCC judges might try to factor the value -5, so you want to might state:
+
+
This submission factors positive values up
+2305567963945518424753102147331756070. Attempting to factor large values will
+produce unpredictable results.
+
+
However the IOCCC judges might try to also factor 0, so you want to might state:
+
+
This submission factors values between 1 and
+2305567963945518424753102147331756070. Attempting to factor values outside
+that range will produce unpredictable results.
+
+
+Moreover they might try to also factor 3.5 or 0x7, or Fred, so you want to might state:
+
+
+
This submission factors integers between 1 and
+2305567963945518424753102147331756070. Attempting to factor anything else
+will produce unpredictable results.
+
+
You submission might be better off catching the attempt to factor bogus values
+and doing something interesting. So you might want to code accordingly and state:
+
+
This submission factors integers between 1 and 2305567963945518424753102147331756070.
+Attempting to factor anything else will cause the program to insult your pet fish Eric.
+
+
The IOCCC judges might not have a pet fish named Eric, so you might want to state:
+
+
This submission factors integers between 1 and
+2305567963945518424753102147331756070. Attempting to factor anything else
+will cause the program to insult your pet fish Eric, or in the case that you
+lack such a pet, will insult the pet that you do not have.
+
+
When all other things are equal, a submission with fewer limitations will be judged
+better than a submission with lots of limitations. So you might want to code accordingly
+and state:
+
+
This submission attempts to a factor value of any size provided that the
+program is given enough time and memory. If the value is not a proper integer,
+the program might insult a fish named Eric.
+
+
+Do not fear if you’re not 100% sure of the significance of
+2305567963945518424753102147331756070 as it is not of prime importance: or is
+it? :-)
+
+
+We DISLIKE the use of ASCII tab characters in markdown files, such as in the required remarks.md file.
+
+
+We don’t mind the use of ASCII tab characters in your C code. Feel free
+to use ASCII tab characters if that suits your obfuscation needs. If is
+perfectly OK to use tab characters elsewhere in your submission, just not in
+markdown files as this tends annoy us when it comes time to
+rendering your markdown content as it complicates the process.
+
+
+If you do use ASCII tab characters in your non-markdown files, be
+aware that some people may use a tab stop that is different than the common 8
+character tab stop.
+
+
+PLEASE observe our IOCCC markdown guidelines
+when forming your submission’s remarks.md file. And if your submission
+contains additional markdown files, please follow those same guidelines for
+those files. See also Rule 19 and our
+FAQ on “markdown”.
+
+
+We LIKE reading remarks.md files, especially if they contain
+useful, informative, and even humorous content about your submission. Yes, this
+is a hint. :-)
+
+
+We RECOMMEND you put a reasonable amount effort into the content of the
+remarks.md file: it is a required file for a reason. :-)
+
Legal abuse of the IOCCC rules is somewhat encouraged. Legal rule abuse
+may involve, but is not limited to, doing things that are technically allowed by
+the IOCCC rules and yet do not fit the spirit of what we intended to be
+submitted.
+
Legal rule abuse is encouraged to help promote creativity. Rule abuse
+submissions, regardless of if they receive an award, result in changes to
+the next year’s IOCCC rules and IOCCC guidelines.
+
Legal abuse of the IOCCC rules is NOT an invitation to violate the
+IOCCC rules. A submission that violates the rules in the
+opinion of the IOCCC judges, WILL be
+disqualified. RULE ABUSE CARRIES A CERTAIN LEVEL OF RISK! If you
+have a submission that might otherwise be interesting, you might want to
+submit two versions; one that does not abuse the IOCCC rules and one that
+does.
+
+If you intend to abuse the IOCCC rules,
+indicate so in your remarks.md file. You MUST try to justify
+why you consider your rule abuse to be allowed under the
+IOCCC rules. That is, you must plead your case as to why
+your submission is valid. Humor and/or creativity help plead a case.
+As there is no guarantee that you will succeed, you might consider
+submitting an alternate version that conforms to the
+IOCCC rules.
+
+
+If you do bypass the mkiocccentry(1) warnings about Rule
+2a and/or about Rule 2b or any other
+rule and submit a submission anyway, you MUST try to justify why the IOCCC
+IOCCC judges should not reject your submission due to a rule
+violation, and you would be wise to do this towards the top of your remarks.md
+file.
+
+
+Abusing the web submission procedure tends to annoy us more
+than amuse us. Spend your creative energy on content of your
+submission rather than on the submission process itself.
+
+
+We are often asked why the contest IOCCC rules and IOCCC
+guidelines seem strange or contain mistakes, flaws or
+grammatical errors. One reason is that we sometimes make genuine mistakes. But
+in many cases such problems, flaws or areas of confusion are deliberate.
+Changes to IOCCC rules and IOCCC guidelines in
+response to rule abuses, are done in a minimal fashion. Often we will
+deliberately leave behind holes (or introduce new ones) so that future rule
+abuse can continue. A clever author should be able to read them and “drive a
+truck through the holes” in the IOCCC rules and IOCCC
+guidelines.
+
+
+At the risk of stating the obvious, this contest is a parody of the software
+development process. The IOCCC rules and IOCCC guidelines
+are only part of the overall contest. Even so, one might think the
+contest IOCCC rules and IOCCC guidelines process as a parody
+of the sometimes tragic mismatch between what a customer (or marketing) wants
+and what engineering delivers. Real programmers must face obfuscated and
+sometimes conflicting specifications and requirements from marketing, sales,
+product management and even from customers themselves on an all too regular basis.
+This is one of the reasons why the IOCCC rules and
+IOCCC guidelines are written in obfuscated form.
+
Submissions are judged by Leonid A. Broukhis and Landon Curt Noll.
+
+Each submission submitted is given a random string and subdirectory. The
+submission files including, but not limited to prog.c, Makefile,
+remarks.md, .info.json, .auth.json as well as any data files that you
+submit, are all placed under their own directory and stored and judged from this
+directory.
+
+
Any information about the authors is not read by the IOCCC judges until
+the judging process is complete, and then only from entries that have
+won an award. Because we do not read this information for entries that
+do not win, we do not know who did not win.
+
The above process helps keep us biased for/against any one particular
+individual. Therefore you MUST refrain from putting any information
+that reveals your identity in your submission.
+
+Now some people point out that coding and/or writing style might reveal the
+information about the authors. However we consider this to be simply
+circumstantial and outside the scope of the above paragraph.
+
+
Some people, in the past, have attempted to obfuscate their identity by
+including comments of famous Internet personalities such as Peter
+Honeyman. The IOCCC judges are on to this trick
+and therefore consider any obfuscated source or data file claiming to be from
+Honeyman to not be from Honeyman. This of course creates an interesting paradox
+known as the “obfuscated Peter Honeyman paradox”. Should Peter Honeyman
+actually submit to the IOCCC, he alone is excluded from the above, as we
+will likely believe it’s just another attempt at confusion. This guideline is
+known as the “Peter Honeyman is exempt” guideline.
+
BTW: None of the submissions claiming to be from Peter Honeyman have ever
+won an award. So it is theoretically possible that Peter Honeyman
+did submit to the IOCCC in the past. In the past, Peter had denied
+submitting anything to the IOCCC. Perhaps those submissions were
+submitted by one of his students?
+
Hopefully we are VERY CLEAR on this point! The rules now strongly state:
+PLEASE DO NOT put a name of an author, in an obvious way, into your
+source code, remarks.md, data files, etc., the above “Peter Honeyman is
+exempt” notwithstanding.
+
We seemed to have digressed again … :-) Returning to the judging process:
+
We prefer to be kept in the dark as much as you are until the final
+awards are given. We enjoy the surprise of finding out in the end,
+who won and where they are from.
+
We attempt to keep all submissions anonymous, unless they win an award.
+Because the main ‘prize’ of winning is being announced, we make all
+attempts to send non-winners into oblivion. We remove all non-winning
+files, and shred all related printouts. By tradition, we do not even
+reveal the number of submissions that we receive.
+
+During the judging process, a process that spans multiple sessions over
+a few weeks, we post general updates from our Mastodon
+account.
+
+
+Make sure you reload the feed every so often because unless you
+are mentioned you will NOT get a push notification!
+
Judging consists of a number of elimination rounds. During a round,
+the collection of submissions are divided into two roughly equal piles;
+the pile that advances on to the next round, and the pile that does
+not. We also re-examine the submissions that were eliminated in the
+previous round. Thus, a submission gets at least two readings and
+often more than two.
+Reading prog.c, the C source and reviewing the remarks.md information
+
+
+Briefly looking at any supplied data files
+
+
Passing the source thru the C pre-processor skipping over any #included files
+
Performing a number of C beautify/cleanup edits on the source
+
Passing the beautified source thru the C pre-processor skipping over any #included files
+
Compiling/building the source
+
Running the program
+
Doing other things that only IOCCC judges know about :-)
+
+
In later rounds, other actions are performed including performing
+miscellaneous tests on the source and binary.
+
+This is the very guideline that goes, BING!
+
+
+Okay, technically that was the secondguideline that goes BING, and this
+is the third. :-)
+
+
Until we reduce the stack of submissions down to about 25 submissions,
+submissions are judged on an individual basis. A submission is set aside because it
+does not, in our opinion, meet the standard established by the round.
+When the number of submissions thins to about 25 submissions, we begin to form
+award categories. Submissions begin to compete with each other for awards.
+A submission will often compete in several categories.
+
The actual award category list will vary depending on the types of submissions
+we receive. A typical category list might be:
+
+
best small one line program (see above about one line programs)
+
best small program
+
strangest/most creative source layout
+
most useful obfuscated program
+
best game that is obfuscated
+
most creatively obfuscated program
+
most deceptive C code (code with deceptive comments and source code)
best abuse of ISO C or ANSI C standard (see above about compilers)
+
best abuse of the C preprocessor
+
worst/best abuse of the rules (or some variation)
+
(anything else so strange that it deserves an award)
+
+
We do not limit ourselves to this list. For example, a few submissions are so
+good/bad that they are declared winners at the start of the final round.
+We will invent awards categories for them, if necessary.
+
In the final round process, we perform the difficult tasks of
+reducing the remaining submissions (typically about 25) down to to about
+half that number: declaring those remaining to be winners.
+
Often we are confident that the submissions that make it into
+the final round are definitely better than the ones that do not
+make it. The selection of the winners out of the final round, is
+less clear cut, however.
+
Sometimes a final round submission is good enough to win, but is beat out by a
+similar, but slightly better submission. For this reason, it is sometimes
+worthwhile to resubmit an improved version of a submission that failed to win in
+a previous year, the next year. This assumes, of course, that the submission is
+worth improving in the first place!
+
+Over the years, more than one IOCCC judge
+has been known to bribe another IOCCC judge into voting for a
+winning submissions by offering a bit of high quality chocolate, or
+other fun item.
+
+
+One should NOT attempt to bribe an IOCCC
+judge, unless you are an IOCCC judge,
+because bribing an IOCCC judge by a non-judge
+has been shown to NOT be effective when the person attempting
+the bribe is made known to the IOCCC judges
+(i.e., they are not anonymous) AND/OR the bribe is otherwise
+associated with a submission to the IOCCC.
+
+
+With the previous guideline in mind: anonymous gifts
+for the IOCCC judges that are NOT ASSOCIATED
+WITH a submission to the IOCCC may be sent to the
+IOCCC judges via the
+IOCCC Amazon wishlist.
+It has been shown that receiving anonymous gifts provides the
+IOCCC judges with a nice
+dopamine boost, and happy
+IOCCC judges help make the IOCCC better for everyone. :-)
+
More often than not, we select a small submission (usually one line) and a
+strange/creative layout submission. We sometimes also select a
+submission that abuses the IOCCC guidelines in an interesting way,
+or that stretches the contest rules that while legal, it
+nevertheless goes against the intent of the rules.
In the end, we traditionally pick one submission as ‘best’. Sometimes such
+a submission simply far exceeds any of the other submissions. More often, the
+‘best’ is picked because it does well in a number of categories.
+
In years past, we renamed the winning submission from prog.c to a
+name related to the author(s)’ names. This is no longer done.
+Winning source is called prog.c. A compiled binary is called prog.
+The IOCCC judges will toot initial announcement of who won, the name
+of their award, and a very brief description (award title) of the winning entry
+from the @IOCCC Mastodon account.
+
+
+We recommend that you follow us on mastodon but please make sure to
+refresh the feed every so often (if not more often) because unless you are
+mentioned or someone boosts your post you will not get a push notification.
+
+The IOCCC no longer uses twitter. Winning IOCCC entries will be announced by a
+git commit to the IOCCC entries repo
+that, in turn, updates the Official IOCCC
+website.
+
+Often, winning entries are published in selected magazines from around the
+world. Winners have appeared in books (‘The New Hacker's Dictionary’,
+‘Obfuscated C and Other Mysteries’, ‘Pointers On C’, others) and on t-shirts
+(sometimes by the author(s) themselves). There have been multiple classes
+that have focused in part, on IOCCC winning entries. And more than one winner has been turned
+into a tattoo!
+
+
Last, but not least, winners receive international fame and flames! :-)
+For the updates and breaking IOCCC news, you are encouraged to follow
+the IOCCC on Mastodon. See our
+FAQ on “Mastodon”
+for more information. Please do note that unless
+you are mentioned by us you will NOT get a notification from the app so you
+should refresh the page even if you do follow us.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/2024/guidelines.md b/2024/guidelines.md
new file mode 100644
index 000000000..9fa58b9e2
--- /dev/null
+++ b/2024/guidelines.md
@@ -0,0 +1,2589 @@
+
+
+# The guidelines for the IOCCC that just closed
+
+These guidelines are for the current IOCCC that is no longer open for new submissions.
+
+See the [IOCCC news](../news.html) and well as the
+[IOCCC Mastodon](https://fosstodon.org/@ioccc) feed for updates
+on the IOCCC judging process as well as for the announcement
+of [who won the IOCCC](../years.html).
+
+**HINT to mastodon users**: You may wish to refresh the [@IOCCC
+mastodon feed](https://fosstodon.org/@ioccc) page and/or mastodon
+app from time to time to view IOCCC mastodon updates.
+
+
+# The IOCCC is closed to new submissions
+
+The [IOCCC judges](../judges.html) are in the process of judging the submissions they received
+while the IOCCC was open.
+
+
+
+# 28th International Obfuscated C Code Contest Official Guidelines
+
+
+
+All Rights Reserved. Permission for personal, education or non-profit use is
+granted provided this this copyright and notice are included in its entirety
+and remains unaltered. All other uses must receive prior permission in
+writing by [contacting the judges](../contact.html).
+
+
+Jump to: [top](#)
+
+
+
+
+# IOCCC Guidelines version
+
+
+
+
+These [IOCCC guidelines](guidelines.html) are version **28.47 2025-03-15**.
+
+
+**IMPORTANT**: Be **SURE** to read the [IOCCC rules](rules.html).
+
+
+Jump to: [top](#)
+
+
+
+# Change marks
+
+
+
**← Lines that start with this symbol indicate a change from the
+previous IOCCC**.
+
+
+Most lines (we sometimes make mistakes) that were modified since the previous
+IOCCC start with a solid 4 pixel black left border (or, in the case of a code
+block or blockquote, just a vertical bar).
+
+
+Jump to: [top](#)
+
+
+
+# ABOUT THIS FILE:
+
+
+This file contains _guidelines_ intended to help people who wish to
+participate in the [International Obfuscated C Code Contest
+(IOCCC)](https://www.ioccc.org).
+
+These are **NOT the [IOCCC rules](rules.html)**, though it does contain comments
+about them. The [IOCCC guidelines](guidelines.html) should be viewed as
+**hints** and **suggestions**. **Submission that violate the
+[guidelines](guidelines.html) _but remain within the [rules](rules.html)_** _are
+allowed_. Even so, you are safer if you remain within the [IOCCC
+guidelines](guidelines.html).
+
+
+Of course if a guideline is talking about a rule and you break that guideline,
+you stand a good chance of having your submission rejected for breaking the
+rule, not the guideline.
+
+
+You **SHOULD read the CURRENT [IOCCC rules](rules.html)**, _prior_ to submitting
+code to the contest.
+
+
+Jump to: [top](#)
+
+
+
+# WHAT'S NEW THIS IOCCC
+
+
+
+This IOCCC runs from **2024-12-29 23:58:13.213455 UTC** to **2025-06-05 04:03:02.010099 UTC**.
+This IOCCC marks the **40th anniversary** of the contest!
+
+
+
+This contest will enter the **[pending](../faq.html#pending)** state on or about
+**2024-12-29 23:58:13.213455 UTC**.
+When this happens, you may begin registering to enter the IOCCC.
+
+
+
+This contest will enter the **[open](../faq.html#open)** state on **2025-03-05 23:19:17.131107 UTC**.
+When this happens, you may begin uploading your submissions to the IOCCC.
+
+
+
+This contest will enter the **[judging](../faq.html#judging)** state on **2025-06-05 04:03:02.010099 UTC**.
+When this happens, you may no longer upload your submissions to the IOCCC.
+
+
+
+**IMPORTANT NOTE**: Until the contest enters the **[open](../faq.html#open)** state, any or all
+of the above **dates and times may change _AT ANY TIME_**!
+
+
+
+The reason for the times of day are so that key IOCCC events are **calculated**
+to be a **fun**ctional UTC time. :-)
+
+
+
+**NOTE**: the updates to these guidelines on 2025-03-10 explained the new `-u
+uuidfile` and `-U uuidstr` options and are **NOT** important to read, in order
+to follow the guidelines. The options are in a release **AFTER THIS** IOCCC's
+official release and not updating the toolkit is **PERFECTLY** okay.
+
+
+
+**NOTE**: the updates to these guidelines on 2025-03-12 also explain how the
+tools that require other tools now search under `$PATH`. It is perfectly fine to
+not use the newer versions so long as you use the minimum required version of
+the tools. See the
+FAQ on "[minimum required version of the tools](../faq.html#minimum_versions)"
+for more details and the
+FAQ on "[obtaining the most recent release of the
+toolkit](../faq.html#obtaining_mkiocccentry)"
+for more help.
+
+
+
+Until the contest status becomes **[open](../faq.html#open)**,
+the [IOCCC rules](rules.html),
+[IOCCC guidelines](guidelines.html) and the tools in the
+[mkiocccentry repo](https://github.com/ioccc-src/mkiocccentry) **SHOULD be
+considered** provisional **BETA** versions and **may be adjusted _AT ANY TIME_**
+before the contest status becomes **[open](../faq.html#open)**.
+
+
+
+See the
+FAQ on "[how to register and submit to the IOCCC](../quick-start.html#enter)"
+for instructions on registering and participating in the IOCCC, as the process
+may change from contest to contest.
+
+
+
+To assist in the formation of the xz compressed tarball for submission, use the
+`mkiocccentry(1)` tool as found in the [mkiocccentry repo](https://github.com/ioccc-src/mkiocccentry).
+
+
+
+See FAQs regarding:
+
+
+- [obtaining the latest mkiocccentry tools](../faq.html#obtaining_mkiocccentry)
+- [compiling the mkiocccentry tools](../faq.html#compiling_mkiocccentry)
+- [installing the mkiocccentry tools](../faq.html#install)
+- [using the mkiocccentry tools](../faq.html#using_mkiocccentry)
+
+
+Uploading a tarball not formed by `mkiocccentry(1)` puts you at a very big risk of
+violating [Rule 17](rules.html#rule17), especially as `mkiocccentry(1)` does a
+great number of things that are required, and it also runs many checks, and if
+any of those checks fail, you are at a very great risk of having your submission
+rejected for violating [Rule 17](rules.html#rule17).
+
+
+
+We **STRONGLY** recommend you **do** install the
+[mkiocccentry toolkit](https://github.com/ioccc-src/mkiocccentry).
+
+
+
+**IMPORTANT NOTE**: the tools that require other tools, `mkiocccentry(1)` and
+`txzchk(1)`, will, as of version `2.0.2 2025-03-11`, search under `$PATH`. If
+you have an earlier version and you have not installed the tools and run the
+tools from outside the repo directory, you will have to use the options to the
+tools to set the path to the required tools.
+
+
+
+See the
+FAQ on "[obtaining and compiling the most recent mkiocccentry tools](../faq.html#mkiocccentry)"
+and the
+FAQ on "[how to enter the IOCCC](../quick-start.html#enter)"
+as that FAQ has important details on
+[how to register](../next/register.html)
+as well as
+[how to upload your submission](../next/submit.html) to the IOCCC.
+
+
+
+See also the
+FAQ on "[what the minimum required versions are for this
+contest](../faq.html#minimum_versions)"
+for more details on how to verify you have the correct versions for this
+contest.
+
+
+
+While the contest is **[open](../faq.html#open)**, you may modify your
+previously uploaded submission by rebuilding your submission with the
+`mkiocccentry(1)` tool and then re-uploading it to **the same slot number** on the
+[submit server](https://submit.ioccc.org).
+
+
+
+**HINT:** so that you do not have to repeatedly answer all the
+questions, the `mkiocccentry(1)` tool has the options `-a answers`, `-A answers`
+and `-i answers`, where `-a` will write to an answers file (if it does not
+already exist), `-A` **WILL OVERWRITE THE FILE** and `-i` will read the answers from
+the file. If you use `-A`, **BE SURE** you don't overwrite another file by accident!
+
+
+
+Be aware that even with the `-i answers` you will still be required to confirm
+most if not all `y/n` questions - you just don't have to input the name of the
+submission, the abstract, the author details etc. If you really wish to
+circumvent this you can use the `-Y` option but we do not recommend this because
+if your update breaks a rule or there is some problem, you might not see it.
+
+
+
+To help with not having to repeatedly enter a UUID, whether for the same
+submission or multiple submissions, you can use the `-u uuidfile` or `-U UUID`
+option. See the
+FAQ on "[how to avoid re-entering your UUID](../faq.html#uuid)"
+for more details. Note that the `-i answers` option cannot be used with the UUID
+options as the answers file includes the UUID.
+
+
+
+The overall size limit (see [Rule 2a](rules.html#rule2a)) on `prog.c` has been
+**increased from 4096 to 4993** bytes.
+The [Rule 2a](rules.html#rule2a) size was changed from
+**4096** to **4993** to keep the "2b to 2a" size ratio to a
+value similar to the [2001-2012](../faq.html#size_rule2001-2012) and
+[2013-2020](../faq.html#size_rule2013-2020) IOCCC eras.
+
+
+
+The [Rule 2b](rules.html#rule2b) size has **increased from 2053 to 2503**
+bytes.
+
+
+
+Your submission must satisfy **BOTH** the maximum size
+[Rule 2a](rules.html#rule2a) **AND** the IOCCC size [Rule 2b](rules.html#rule2b).
+
+
+
+To check your code against [Rule 2](rules.html#rule2), use the `iocccentry(1)` tool.
+For example:
+
+
+```
+ iocccsize prog.c
+```
+
+
+The IOCCC size tool algorithm can be summarized as follows:
+
+
+> The size tool counts most C reserved words (keyword, secondary, and selected
+preprocessor keywords) as 1. The size tool counts all other bytes as 1
+excluding ASCII whitespace, and excluding any '`;`', '`{`' or '`}`' followed by
+ASCII whitespace, and excluding any '`;`', '`{`' or '`}`' byte immediately
+before the end of file.
+
+ASCII whitespace includes ASCII tab, ASCII space, ASCII newline,
+ASCII formfeed, and ASCII carriage return.
+
+
+When '`;`', '`{`' or '`}`' are within a C string, they may still not be
+counted by the IOCCC size tool. This is a **feature**, not a bug!
+
+
+
+In cases where the above summary and the algorithm implemented by
+the IOCCC size tool `iocccsize(1)` conflict, the algorithm implemented
+by the current version of `iocccsize(1)` is preferred by the [IOCCC judges](../judges.html).
+
+
+
+In other words, make sure `iocccsize` does not flag any issues with your
+`prog.c`.
+
+
+
+There are at least 2 other reasons for selecting 2503 as the 2nd limit besides
+the fact that 2503 is a prime. These reasons may be searched for and discovered
+if you are ["Curios!" about 2503](https://t5k.org/curios/page.php/2503.html).
+:-) Moreover, 2053 was the number of the kernel disk pack of one of the judge's
+BESM-6, and 2503 is a decimal anagram of 2053.
+
+
+Take note that this secondary limit imposed by the IOCCC size tool
+obviates some of the need to `#define` C reserved words in an effort
+to get around the size limits of [Rule 2](rules.html#rule2).
+
+Yes Virginia, **that is a hint**!
+
+
+The **official locale** of the **IOCCC** is **C**.
+
+
+
+The [mkiocccentry toolkit](https://github.com/ioccc-src/mkiocccentry),
+as of [Release version 2.4.4 2025-03-15](https://github.com/ioccc-src/mkiocccentry/releases/tag/2.4.4),
+will run with a locale set to **C**.
+
+
+
+Jump to: [top](#)
+
+
+
+
+# HINTS AND SUGGESTIONS:
+
+
+
+You are **encouraged** to examine the [winners of previous contests](../years.html).
+
+Keep in mind that [rules](rules.html) change from year to year, so some [winning
+entries](../years.html) might not be valid submissions this year; what _was_ unique
+and novel one year _might be 'old' the next year_.
+
+A submission is usually examined in a number of ways. We typically apply
+a number of tests to a submission:
+
+* look at the original source
+* C pre-process the source ignoring `#include` lines
+* C pre-process the source ignoring `#define` _and_ `#include` lines
+* run it through a C beautifier
+* examine the algorithm
+* compile it (with flags to enable all warnings)
+* execute it
+
+You should consider how your submission looks in each of the above tests.
+You should ask yourself if your submission remains obscure after it has been
+'_cleaned up_' by the C pre-processor and a C beautifier.
+
+Your submission need not pass all of the above tests. In certain
+cases, a test is not important. Submissions that compete for the
+'**strangest/most creative source layout**' need not do as well as
+others in terms of their algorithm. On the other hand, given
+two such submissions, we are more inclined to pick the submission that
+does something interesting when it's executed.
+
+We try to avoid limiting creativity in our [rules](rules.html). As such, we
+leave the contest open for creative rule interpretation. As in [real
+life](https://en.wikipedia.org/wiki/Real_life) programming, interpreting a
+requirements document or a customer request is important. For this reason, we
+often award '**Best abuse of the [rules](rules.html)**' or '**Worst abuse of the
+[rules](rules.html)**' or some variation to a submission that illustrates this
+point in an ironic way.
+
+
+The IOCCC has a rich history of remarkable winning entries created by
+authors who skillfully employed various techniques to develop their code.
+While it is **NOT** required, you are allowed to use tools to develop
+and test your submission. These tools may include, but are not limited
+to code generators, code analysis tools, static code analysis tools,
+runtime analysis tools, machine learning tools, natural language models,
+code copilot tools, so-called AI services, large language models (LLMS), etc.
+If you do make use of such tools or services, then we **ENCOURAGE you to describe
+how you used such tools** in your `remarks.md` file.
+
+
+
+You may use git, or services such as [GitHub](https://www.github.com)
+to develop and maintain your submission. However, we **DISLIKE**
+submissions that **require** them in order to build/compile your submission.
+
+
+
+Submissions will be judged in an environment that has no **IDE**.
+Any submission that fails to compile/build because it requires
+an **IDE** will be rejected.
+
+
+
+We will use the `make(1)` tool, your `Makefile`, and other tools found in
+[Single UNIX Specification](https://en.wikipedia.org/wiki/Single_UNIX_Specification)
+environments and systems that conform to the [Single UNIX
+Specification](https://en.wikipedia.org/wiki/Single_UNIX_Specification)
+in the building and compiling of your submission.
+
+
+We do realize that there are holes in the [rules](rules.html), and invite
+submitters to attempt to exploit them. We may award '**Worst abuse of the
+[rules](rules.html)**' or '**Best abuse of the [rules](rules.html)**' or some
+variation and then plug the hole next year.
+
+
+When we do need to plug a hole in the [IOCCC rules](rules.html) or [IOCCC
+guidelines](guidelines.html), we will attempt to use a very small plug, if not
+smaller. Or, maybe not. :-)
+
+
+
+There may be fewer than 2^7+1 reasons why these [IOCCC
+guidelines](guidelines.html) seem obfuscated.
+
+
+
+**IMPORTANT:** Be sure that **your submission works** as documented in your
+`remarks.md` file. We sometimes make an effort to debug a submission
+that has a slight problem, particularly in or near the final round.
+On the other hand, we have seen some otherwise excellent submissions
+fall down because they didn't work as documented.
+
+
+
+If you submission has bugs and/or mis-features, you are **MUCH BETTER** off
+documenting such bugs and/or mis-features in your `remarks.md` file.
+
+
+
+Consider an example of a [prime number](https://en.wikipedia.org/wiki/Prime_number)
+printing program that claims that 16 is a prime number.
+Noting such a bug in your `remarks.md` file could save your submission:
+
+
+> "_this submission sometimes prints the 4th power of a prime by mistake_"
+
+Sometimes a strange bug or (mis-)feature can even help the submission! Of course, a correctly
+working submission might be better.
+
+
+We tend to look down on a [prime
+number](https://en.wikipedia.org/wiki/Prime_number) printer that claims that
+16 is a prime number.
+Clever people will note that 16 might be prime
+under certain conditions. ;-) Wise people, when submitting something clever
+will fully explain such cleverness in their submission's `remarks.md` file.
+
+
+People who are considering to just use some complex mathematical
+function or state machine to spell out something such as "_hello,
+world!_" **really really, _and we do mean REALLY_, do need to be more creative**.
+
+Ultra-obfuscated programs are, in some cases, easier to
+deobfuscate than subtly-obfuscated programs. Consider using
+misleading or subtle tricks layered on top of or under an
+appropriate level of obfuscation. A clean looking program with
+misleading comments and variable names might be a **VERY GOOD START**
+to a great submission!
+
+
+Jump to: [top](#)
+
+
+
+# `mkiocccentry`
+
+
+
+[Rule 17](rules.html#rule17) (the `mkiocccentry(1)` rule) states that
+you **REALLY SHOULD** use the `mkiocccentry(1)` tool to package your submission tarball.
+
+
+
+See the [mkiocccentry repo](https://github.com/ioccc-src/mkiocccentry)
+for the `mkiocccentry(1)` tool and below for more details.
+
+
+
+**IMPORTANT NOTE**: make **CERTAIN** you have the most recent version of the
+`mkiocccentry` toolkit! See the
+FAQ on "[obtaining the mkiocccentry toolkit](../faq.html#obtaining_mkiocccentry)".
+
+
+
+`mkiocccentry` runs a number of checks, by the tool itself and by executing
+other tools, _before_ packaging your xz compressed tarball, including running
+`chkentry(1)` on the submission directory.
+
+
+
+If `mkiocccentry` encounters an **error**, the program will exit and the xz
+compressed tarball **will not be formed**. For instance, if
+[chkentry](#chkentry) fails to validate the submission directory, either because
+of a validation error in the `.auth.json` or `.info.json`
+[JSON](https://www.json.org/json-en.html) files or because of
+something else that `mkiocccentry(1)` creates or does, it is an
+**error** and **possibly** a bug that you should [report as a bug at the
+mkiocccentry bug report
+page](https://github.com/ioccc-src/mkiocccentry/issues/new?assignees=&labels=bug&projects=&template=bug_report.yml&title=%5BBug%5D+%3Ctitle%3E).
+**PLEASE run the `bug_report.sh` script to help us out here!** See the
+FAQ on "[reporting mkiocccentry bugs](../faq.html#mkiocccentry_bugs)".
+
+
+
+Once the tarball is packaged it will
+run `txzchk(1)`, which will also run `fnamchk(1)`, as part of its algorithm.
+
+
+
+However, even if `mkiocccentry` or one of the tools it invokes reports an error,
+it **does not** necessarily mean it is a bug in the code. It might be an issue with
+your submission. Thus if you report an error as a bug it might not be something
+that will be fixed as there might not be anything wrong with the tools.
+
+
+
+On the other hand, some conditions flagged by `mkiocccentry(1)` are **warnings**
+and it allows you to override these, if you wish. If you're brave enough you can
+use the `-W` option to ignore all warnings but this is a big risk; the `-y`
+option will assume '_yes_' to most questions but this is also a big risk. Using
+`-Y` will say '_yes_' to even more prompts. Needless to say, we do **NOT**
+recommend these options.
+
+
+
+In many places it will prompt you to verify what you input, allowing you to
+correct details as you go along. Be advised that there is a default answer and
+if you press enter it will proceed with that default, so make sure you have
+provided the correct answer.
+
+
+
+If you wish to **test** that your submission passes the `mkiocccentry(1)` tests
+without having to type in in answers each time, you can use the `-d` or `-s seed`
+option to `mkiocccentry` for the tool to pseudo-randomly create answers for you.
+For example:
+
+
+```
+ mkiocccentry -d workdir topdir
+```
+
+
+**IMPORTANT NOTE**: if you run an IOCCC related tool outside the repo directory
+(specifying the absolute or relative path to the tool) and you have not
+installed the tools (and we **STRONGLY** recommend you **do** install them),
+then you will have to specify the options (such as paths) for the tools that are required like
+`chkentry(1)`, `txzchk(1)` and `fnamchk(1)`.
+
+
+
+Make sure you have
+the latest version of of the [mkiocccentry toolkit](https://github.com/ioccc-src/mkiocccentry)
+so that you do not violate [Rule 17](rules.html#rule17) by mistake.
+
+To help you with editing a submission, the `mkiocccentry(1)` tool has
+some options to write _OR_ read from an answers file so you do not have to input
+the information about the author(s) and the submission more than once, unless of
+course you need to make some changes, in which case you can use the option that
+overwrites the file. If you do use the overwrite option, **MAKE SURE** you do
+not overwrite another file!
+
+
+
+See the
+FAQ on the
+"[mkiocccentry tool](../faq.html#mkiocccentry)"
+for how to use this tool and the
+FAQ on the
+"[finer details of mkiocccentry](../faq.html#mkiocccentry_details)"
+for even more information.
+
+
+
+
+# Other mkiocccentry tools
+
+
+
+The `mkiocccentry(1)` tool will execute a number of tools, some of which will
+execute one or more additional tools.
+
+
+
+## `iocccsize`
+
+
+
+`mkiocccentry(1)` will use code from `iocccsize(1)` which detects a number of
+issues (such as [Rule 2](rules.html#rule2)) that you may ignore, if you wish, as
+noted above.
+
+
+
+In other words, you no longer need to run `iocccsize` manually. However, the
+checks described above are still made but through the `mkiocccentry(1)` tool itself.
+
+
+
+Jump to: [top](#)
+
+
+
+## `chkentry`
+
+
+
`mkiocccentry(1)` will write two JSON files: `.auth.json` and
+`.info.json`. These files contain information about the author(s) and about the
+submission. After these files are formed, the `chkentry(1)` tool will be run on
+the submission directory; this tool not only validates the two JSON files
+(and runs specific checks on them after validating the JSON), but it also
+verifies that what is in the manifest in `.info.json` matches the contents of
+the directory, in addition to other checks. If `chkentry(1)` fails to validate
+anything at all, your submission **WILL BE** rejected!
+
+
+
+**IMPORTANT**: although `chkentry(1)` validates the files in the directory, it
+only inspects the contents of the two JSON files; it performs other kinds of
+checks on the other files, and those checks are run on the two JSON files as
+well.
+
+
+
+If you submit your own JSON files (other than `.auth.json` and
+`.info.json`) then they do **NOT** have to be valid JSON.
+However, if you do provide such invalid JSON files, **PLEASE**
+document and explain this in your `remarks.md` file.
+
+
+
+If `chkentry` does not pass and you used `mkiocccentry(1)` it is **very likely** a
+bug and you should [report it as a bug at the mkiocccentry issues
+page](https://github.com/ioccc-src/mkiocccentry/issues/new?assignees=&labels=bug&projects=&template=bug_report.yml&title=%5BBug%5D+%3Ctitle%3E).
+**PLEASE** run the command:
+
+
+```
+ make bug_report
+```
+
+
+from the top level repo directory itself and attach the bug report file (it will
+tell you the name of the file). See also the
+FAQ on "[reporting mkiocccentry bugs](../faq.html#mkiocccentry_bugs)".
+
+
+
+Assuming that `chkentry(1)` successfully validates your submission directory,
+the tarball will be formed and then `txzchk(1)` will be executed on it. In this
+case, there should be no problems, as `mkiocccentry(1)` should **NOT** form a
+tarball if there are any issues.
+
+
+
+If `mkiocccentry(1)` is used and `chkentry(1)` fails to validate your submission
+directory, then unless it is a system specific problem, it could be a bug in
+`mkiocccentry(1)`, `chkentry(1)` or possibly `jparse`, although this is unlikely.
+Nonetheless, if you believe there is a bug, you may report it as explained above.
+
+
+
+If you want to know what `.auth.json` is, see the
+FAQ on "[.auth.json](../faq.html#auth_json)".
+If you want to know what the `.info.json` file is, see the
+FAQ on "[.info.json](../faq.html#info_json)".
+On the other hand, if you want to know a bit more details about `chkentry(1)`, see the
+FAQ about "[chkentry](../faq.html#chkentry)".
+
+
+
+`chkentry` uses the `jparse` library. See the
+[jparse
+README.md](https://github.com/ioccc-src/mkiocccentry/blob/master/jparse/README.md)
+in the [mkiocccentry GitHub repo subdirectory
+jparse](https://github.com/ioccc-src/mkiocccentry/tree/master/jparse) as well as
+the [jparse library README.md
+file](https://github.com/ioccc-src/mkiocccentry/blob/master/jparse/jparse_library_README.md)
+in the [mkiocccentry GitHub repo subdirectory
+jparse](https://github.com/ioccc-src/mkiocccentry/tree/master/jparse), for more
+details.
+
+
+
+The `jparse` parser, library and tools were co-developed by [Cody Boone
+Ferguson](../authors.html#Cody_Boone_Ferguson) and [Landon Curt
+Noll](http://www.isthe.com/chongo/index.html) in 2022-2025 and come from the
+[jparse repo](https://github.com/xexyl/jparse). However, the **mkiocccentry
+tools use a _clone_** of the [jparse repo](https://github.com/xexyl/jparse) **at
+a _specific_ release**. Thus the `mkiocccentry` will at times be behind the
+[jparse repo](https://github.com/xexyl/jparse)!
+
+
+
+You do **NOT need to install** `jparse` from the [jparse
+repo](https://github.com/xexyl/jparse)! The `mkiocccentry` tools link in the
+static library from `mkiocccentry`'s _clone_.
+
+
+
+The `mkiocccentry` toolkit _also_ has a clone of _both_ the [dbg
+library](https://github.com/lcn2/dbg) and the
+[dyn_array library](https://github.com/lcn2/dyn_array); the [dyn_array
+library](https://github.com/lcn2/dyn_array) uses the [dbg
+library](https://github.com/lcn2/dbg) and the [jparse
+library](https://github.com/xexyl/jparse) uses both libraries but unlike in the
+[jparse repo](https://github.com/xexyl/jparse), the libraries do not need to be
+installed separately, in order to use the tools in `mkiocccentry`.
+
+
+
+In other words, `mkiocccentry` **contains everything** you need, and _even if you
+do install_ the libraries from their respective repos, it/they will **not be
+used** when compiling the `mkiocccentry` tools. This is important to
+make sure that you're using the correct versions, which is also verified by
+`chkentry` (in the JSON files created by `mkiocccentry(1)`). See [Rule
+17](rules.html#rule17)!
+
+
+
+Please see the
+FAQ on "[validating your submission directory](../faq.html#chkentry)
+for more details on `chkentry(1)`.
+
+
+
+You might also wish to see the
+FAQ on "[.auth.json](../faq.html#auth_json)"
+and the
+FAQ on "[.info.json](../faq.html#info_json)"
+for much more information on these files.
+
+
+
+Jump to: [top](#)
+
+
+
+## `txzchk`
+
+
+
+`txzchk(1)` performs a wide number of sanity checks on the xz compressed
+tarball; if any issues are found ('`feathers are stuck in the tarball`' :-) )
+**AND if and _ONLY IF_ you used `mkiocccentry(1)`**, then it is **possibly** a
+bug in one of the tools and you might want to [report it as a bug at the
+mkiocccentry bug report
+page](https://github.com/ioccc-src/mkiocccentry/issues/new?assignees=&labels=bug&projects=&template=bug_report.yml&title=%5BBug%5D+%3Ctitle%3E).
+**PLEASE run the `bug_report.sh` script to help us out here!** You may do this
+by running from the top level directory of the repo `make bug_report`. See the
+FAQ on "[reporting mkiocccentry bugs](../faq.html#mkiocccentry_bugs)".
+
+
+
+As part of its algorithm, `txzchk(1)` will run `fnamchk(1)` on the
+_tarball_ to verify that the _filename_ is valid. See the
+FAQ on "[fnamchk](../faq.html#fnamchk)"
+and the [fnamchk section](#fnamchk) below for more details on this tool.
+
+
+
+It is beyond the scope of this document to discuss the many tests that
+`txzchk(1)` performs; if you wish to know, we refer you to the [source
+code](https://github.com/ioccc-src/mkiocccentry/blob/master/txzchk.c) or the man
+page. You might just find a fun option if you do either of these!
+
+
+
+Of course, as `txzchk` does not extract the tarball, it is possible that if you
+manually package your submission tarball and/or find and exploit a missing
+check, you could still be violating [Rule 17](rules.html#rule17).
+
+
+
+## Including optional and extra files
+
+
+
+The maximum total number of files that may be submitted has changed to **39** files.
+However, of those files, **5** are mandatory (`prog.c`, `Makefile`, `remarks.md` and
+the two JSON files generated by `mkiocccentry(1)`, `.info.json` and
+`.auth.json`).
+
+
+
+Additionally, three of the files, if included, **MUST** be
+specific file(name)s **AND** in the top level directory, or they will be counted as
+an extra file, not an optional file.
+
+
+
+In particular, any file that is not `prog.c`, `Makefile`, `remarks.md`,
+`try.sh`, `prog.alt.c` or `try.alt.sh` will be counted as an extra file, and if
+`try.sh`, `prog.alt.c` or `try.alt.sh` are not in the top level submission
+directory they will also be counted as an extra file. The `.info.json` and
+`.auth.json` files are not counted as extra files but are required.
+
+
+
+In other words, the actual amount of **EXTRA** files is **31**.
+
+
+
+If you use an optional filename for something other than their intended use
+in order to get past the file limit, we will consider that an
+abuse of rules. For more details on the optional files, see the
+FAQ on the "[try.sh script system](../faq.html#try_script)"
+and the
+FAQ on "[alt code](../faq.html#alt_code)".
+
+
+
+If you **REALLY MUST** include more files than the limit allows, then you may do so by including as an extra
+file, a tarball. This does **NOT** have to pass `txzchk(1)` tests; only the
+submission tarball must pass the `txzchk(1)` tests.
+
+
+
+If you **DO** include a tarball, and the build process or the program extracts
+said tarball(s), the make `clobber` rule **MUST** remove the extracted files. Even so, if you
+include a tarball to get past the limit on the number of files, you **MUST**
+justify this in your `remarks.md` file.
+
+
+
+**IMPORTANT REMINDER**: make **SURE** your tarball does **NOT** reveal who you are!
+The `mkiocccentry(1)` tool creates a v7 format tarball to prevent this. You can
+do the same like:
+
+See [Rule 17](rules.html#rule17) and in particular the part about the [maximum
+number of files](../faq.html#max-files). If you do not follow these points, you
+are at a great risk of violating [Rule 17](rules.html#rule17)!
+
+
+
+**NOTE**: if you want to include a test-suite that requires a lot of files,
+please suggest this in your `remarks.md` and if your submission wins it can
+be done. In other words you should not use a tarball for a test-suite unless you
+have a very good reason for this (and if you do, make **SURE** you specify why
+in your `remarks.md` file).
+
+
+
+
+See also the
+FAQ on "[txzchk](../faq.html#txzchk)".
+
+
+
+Jump to: [top](#)
+
+
+
+## `fnamchk(1)`
+
+
+
+As an important part of its algorithm, [txzchk(1)](#txzchk) directly executes
+`fnamchk(1)`. If the filename is invalid (or the filename does not match the
+directory name of the tarball) then it is an **error** and you risk violating
+[Rule 17](rules.html#rule17). Nevertheless, you can run the tool manually,
+should you wish to.
+
+
+
+For more information on `fnamchk` and how to manually validate your submission
+tarball filename, see the
+FAQ on "[fnamchk](../faq.html#fnamchk)".
+
+
+
+It is extremely unlikely that `fnamchk(1)` reporting an invalid filename is a
+bug in `fnamchk(1)` and as such, ignoring such an issue risks violating [Rule
+17](rules.html#rule17) which is a big risk. Of course, using `mkiocccentry(1)`
+would prevent this from happening as it would not create such a file anyway. If
+`mkiocccentry(1)` was used it would rather suggest a bug in one of the tools and
+you should [report it as a bug at the mkiocccentry issues
+page](https://github.com/ioccc-src/mkiocccentry/issues/new?assignees=&labels=bug&projects=&template=bug_report.yml&title=%5BBug%5D+%3Ctitle%3E).
+See the
+FAQ on "[reporting mkiocccentry bugs](../faq.html#mkiocccentry_bugs)".
+
+
+
+As you can see, the use of `mkiocccentry(1)` is **HIGHLY RECOMMENDED**, and at
+the risk of stating the obvious, you run **A VERY BIG RISK** of having
+your submission rejected if you package your own tarball, and there are **ANY
+problems**. For instance, if `chkentry(1)` found a problem in your `.info.json`
+file, the `mkiocccentry(1)` tool would not package it. But if you were to package
+it manually, you would be violating [Rule 17](rules.html#rule17). But even if
+everything checks out OK you should **NOT** assume that everything **IS** OK.
+
+
+
+
+# Problems and/or bugs in tools
+
+
+
+Although the tools have been tested extensively, it is nonetheless possible for bugs to
+exist in the code, as all programmers know. In this case, **please** ask for help or report what
+you think is a bug via the [bug report issues page in the mkiocccentry
+repo](https://github.com/ioccc-src/mkiocccentry/issues/new?assignees=&labels=bug&projects=&template=bug_report.yml&title=%5BBug%5D+%3Ctitle%3E).
+
+
+
+Of course, it is also possible for `mkiocccentry(1)`, or one or more of the
+tools it executes (or another tool executes), to fail, but **NOT** because of a
+bug. An example problem is if there is not enough memory available or if some
+other library or syscall fails. Nonetheless it might be worth reporting as a
+bug; it is a judgement call: if it's a bug it'll be addressed and if it's not
+that's OK too!
+
+
+
+
+
+# Makefiles
+
+
+
+
+We **recommend** AND **encourage** you to use the example Makefile,
+as the starting point for your submission's required `Makefile`:
+
+Feel free to modify the `Makefile` to suit your obfuscation
+needs.
+
+
+
+**Please** add a space between the `=` and the value of variables, in the
+`Makefile`, making sure that the `=` comes immediately after the name. See the
+example `Makefile` for examples.
+
+
+
+The rest of this section and its subsections will assume that you are using some
+variant of the example `Makefile`, again renamed as `Makefile`.
+
+
+
+We suggest that you compile your submission with a commonly available
+`-std=gnu17` (ISO C 2017 with GNU extensions) C compiler, via `clang(1)`
+and/or `gcc(1)`.
+
+
+
+
+## Default compiler flags
+
+
+
+
+Unless you **clearly state** otherwise in your `remarks.md` file, **AND** put in
+your submission's `Makefile`, we **will** compile using `-std=gnu17 -O3`!
+
+
+
+It **is OK** if you need to require your submission to **NOT be** compiled
+using the default `-std=gnu17 -O3` settings. Simply **explain why**
+your submission should NOT be compiled using `-std=gnu17 -O3` in
+your `remarks.md` file, **AND** adjust your `Makefile` accordingly.
+
+
+
+One reason that you might have to change the flags, is that the optimiser is
+known to break some programs, but there are certainly other possible valid
+reasons. Again, just update the `Makefile` and explain it in your `remarks.md`.
+See the [optimiser section](#optimiser) for details for changing optimiser
+flags.
+
+
+
+For more fun when it comes to optimisers breaking code, see
+[1986/marshall/compilers.html](../1986/marshall/compilers.html).
+
+
+
+
+## Default compiler
+
+
+
+**IMPORTANT NOTE**: The use of `-std=gnu17` does **NOT** imply the use of the `gcc`
+compiler! We often start by compiling using the **clang** C compiler instead.
+
+
+
+**PLEASE NOTE**: in macOS, the compiler `gcc` found at `/usr/bin/gcc` is
+in truth the `clang` compiler, as `/usr/bin/gcc --version` will show!
+
+
+
+
+
+## C standard
+
+
+
+
+You may change the standard under which your submission is compiled
+by modifying the `CSTD` Makefile variable. For example, to use `c99` instead:
+
+
+
+```
+ CSTD= -std=c99
+```
+
+
+
+
+
+
+## Default optimisation level
+
+
+
+
+
+
+
+You may change the level of optimization and compiler debug level
+that your submission is compiled with, by modifying the `OPT` Makefile variable.
+For example, to compile without optimization, and to include debug symbols:
+
+
+```
+ OPT= -O0 -g3
+```
+
+
+
+## Compiler warnings
+
+
+
+
+The default warning flags are set via the `CWARN` variable, as shown in the
+example `Makefile`:
+
+
+```
+ # Common C compiler warning flags
+ #
+ CWARN= -Wall -Wextra ${CSILENCE} ${CUNKNOWN}
+```
+
+
+For details on `CSILENCE` and `CUNKNOWN`, see the [section on disabling
+warnings](#disabling-warnings).
+
+
+
+### The `-Weverything` option
+
+
+
+For compilers, such as `clang`, that have the `-Weverything` option,
+while you may wish to try it, you should read our
+FAQ on "[clang -Weverything](../faq.html#weverything)".
+We do **NOT** recommend that you put
+the use of `-Weverything` into your submission's `Makefile` for the reasons
+cited there. This goes even if your version does not trigger a warning as some
+other version might!
+
+
+
+On the other hand, if `${CC}` has "`clang`" in the name, the example `Makefile` will
+automatically enable `-Weverything`, so you might have to use `-Wno-foo`
+options anyway, as detailed below. See the
+FAQ on "[-Weverything](../faq.html#weverything)"
+for more details.
+
+
+
+If "`clang`" is NOT in `${CC}`, the `CWARN` variable will not be further
+modified.
+
+
+
+There is no real penalty for compiler warnings. Sometimes
+compiler warnings cannot be helped: especially in the case of
+obfuscated C. :-) So if you cannot easily get rid of a compiler
+warning, try not to fret too much.
+
+
+
+We **LIKE** code that has a minimum of warnings, especially under the
+more strict ` -Wall -Wextra -pedantic` mode:
+
+
+```
+ CWARN= -Wall -Wextra -pedantic
+```
+
+
+The two previous guidelines might be thought by some as being somewhat
+contradictory. Isn't life, and isn't trying to satisfy "contradictory customer
+requirements" all too often like that? :-) Try to minimize warnings if you
+can.
+
+
+
+If you manage to produce very few warnings, or perhaps no warnings at
+all under the `-Wall -Wextra -pedantic` mode, then by all means brag about it in
+your `remarks.md` file **AND BE SURE TO TELL US** the OS, OS version, compiler
+and compiler version in which you observed this occurring (in case our OS and
+compiler produces a different result: so your submission won't be penalized for
+not meeting your claims).
+
+
+
+On the other hand, some warnings cannot be disabled and are enabled by compilers
+without any warning option specified. These are sometimes inevitable in
+obfuscated code and even in some non-obfuscated code, and you should not worry
+about this, though it might be worth pointing out.
+
+
+
+For instance, some compilers like to warn about use of pointers as arrays, which seems to
+be dubious, as it obviously can't (always) be avoided, being a big part of C, so
+you should not worry about this either; this is the warning
+`-Wunsafe-buffer-usage` and the way to disable it is `-Wno-unsafe-buffer-usage`.
+See also the
+FAQ on "[forced warnings](../faq.html#forced_warnings)"
+and the
+FAQ on "[-Weverything](../faq.html#weverything)".
+
+
+
+## Disabling warnings
+
+
+
+If you do have to disable warnings due to `-Weverything` automatically being
+included, you might wish to state this fact in your `remarks.md` file.
+And even without `-Weverything` there can be warnings, as noted above.
+
+
+
+If your submission issues lots of warnings but is otherwise
+marvelously obfuscated in multiple levels, don't worry about it. Nevertheless,
+be sure that the warnings do not constitute a potential "**show stopper**"
+compiler problem. Be sure that compilers such as both `gcc` and `clang` won't
+produce a compiler **error** and refuse to compile your code: unless for some
+reason that is what you intend to happen in which case document that too in your
+`remarks.md` file. :-)
+
+
+All other things being equal, a program that must turn off fewer
+warnings will be considered better, for certain values of better.
+
+
+To turn off a compiler warning, in your submission's `Makefile`,
+try something such as:
+
+Some compilers have reported this as an error, however, and if you have
+such a compiler you might want to not add it, or at least note in your
+`remarks.md` file, which OS, OS version, compiler and compiler version
+that has such a problem.
+
+
+
+## Defining macros in the Makefile
+
+
+
+If you need to define something on the compile line, use
+the `CDEFINE` Makefile variable. For example:
+
+
+```
+ CDEFINE= -Dfoo -Dbar=baz
+```
+
+
+**NOTE**: just because we offer a default way to use the `-D` option, we still
+do not like excess use of `-D` to get past size limits, especially since you
+could use `#define` in your code instead.
+
+
+
+## Include files in the Makefile
+
+
+
+If you need to include a file (as in `#include`) on the command line, use the
+`CINCLUDE` Makefile variable. For example:
+
+
+```
+ CINCLUDE= -include stdio.h
+```
+
+
+
+## Magic in the Makefile
+
+
+
+If you need to add other "**magic**" flags to your compile line,
+use the `COTHER` Makefile variable. For example:
+
+
+```
+ COTHER= -fno-math-errno
+```
+
+
+**NOTE**: **We only recommend using "_magic_" flags if _BOTH_ `gcc`
+_and_ `clang`** support it.
+
+
+
+Again, please note that in macOS, `/usr/bin/gcc` is actually `clang`!
+
+
+
+
+## The clobber rule
+
+
+
+When `make clobber` is invoked, we request that submissions be restored
+to their original submission state. For example, any temporary files
+(**including** the compiled program(s)) created during the build process, or
+during execution should be removed by the `clobber` rule. In other words, the
+only things that should be in the directory after running `make clobber` is what
+is in your submission tarball itself.
+
+
+
+While people are free to manage their submission under `git(1)` or even use a
+GitHub repo, dot-files and dot-directories such as `.git` are not allowed in a
+submission.
+
+
+
+The `mkiocccentry(1)` tool will ignore dot-files and dot-directories (such as
+`.vimrc`, `.bashrc`, `.git` and `.github`) and not put them in the submission's
+compressed tarball. So while you may use such files and
+directories to help develop your submission, they won't be included when you run
+the `mkiocccentry(1)` tool.
+
+
+
+Even if you did manage to get dot files or dot directories in the tarball
+somehow, `txzchk(1)` will flag it as an error. When the judges run `txzchk(1)`
+on the uploaded submission compressed tarball, if anything is wrong, for
+instance if you "sneak in" any dot files or dot directories, the submission
+**WILL BE REJECTED** for violating [Rule 17](rules.html#rule17)!
+
+
+
+You may use whatever tools you need to develop your submission, including the
+use of `git(1)` or `gh(1)`, just be sure that your submission code and your
+submission Makefile don't depend on such tools.
+
+
+
+Of course if you do use GitHub to work on your submission, you might want to
+make the repo private so you don't reveal who you are. :-)
+
+
+
+If this is not clear, please do **NOT** use these tools to help with the
+`clobber` rule! For instance, do **NOT** use `git clean`! Not only does this
+depend on the user having `git(1)` but it also does not account for the
+submission tarballs. Even worse is when someone does have it in a `git(1)` repo
+it will remove files that are not under `git(1)` control! Instead, see the
+`clobber` rule in the example Makefile to see how to manage this.
+
+
+
+In other words, for `make clobber`, do something like:
+
+
+
+```
+ clobber:
+ ${RM} -f foo bar baz
+```
+
+and **NOT** something like this:
+
+```
+ # do NOT do this!
+ clobber:
+ -git clean -f # WRONG !!!
+```
+
+
+And do **NOT** use `git` for any other `Makefile` rule either.
+
+
+
+
+**NOTE**: `mkiocccentry(1)` will directly run `make clobber` in the submission
+directory. And although it is not an error if this fails, if it fails because the
+Makefile does not have a clobber rule, it will be flagged by `mkiocccentry(1)`
+(you may ignore this but it does put you at a risk of violating the rules).
+
+
+
+Jump to: [top](#)
+
+
+
+
+# OUR LIKES AND DISLIKES:
+
+
+
+
+We **VERY MUCH LIKE** submissions that use an edited variant of the
+example Makefile, as described and linked to in the [Makefile section](#makefile),
+renamed as `Makefile` of course. This makes it easier for the [IOCCC judges](../judges.html)
+to test your submission. And if your submissions wins, it makes it easier to integrate it into
+the [Official IOCCC winner website](https://www.ioccc.org/index.html).
+
+
+
+We **VERY MUCH LIKE** submissions that have some educational value. This does **NOT** mean
+that your submission should not be obfuscated but rather that the IOCCC has moved away from
+the idea of "spoilers". You should not encrypt or rot13 content in your `remarks.md` file.
+
+
+
+It is **VERY MUCH** appreciated if your remarks have some educational
+value. And although educational value is not required, it is an
+**EXCELLENT** bonus.
+
+
+
+
+We **LIKE** submissions that use an edited version of the
+`try.sh` example script (and if you have alternate code,
+the same applies with the `try.alt.sh` script):
+
+Of course, it is quite possible that only one invocation is
+possible, so it is not necessarily detrimental to your submission if you do not
+include one, though we do like interesting and creative uses of submissions. See
+also the
+FAQ on "[submitting try.sh and try.alt.sh scripts](../faq.html#try_scripts)".
+
+
+
+You might wish to add `./try.sh` to the `try` rule in the Makefile you submit.
+If you have alternate code, then you can use the `try.alt` rule as well.
+
+
+Doing masses of `#define`s to obscure the source has become 'old'. We
+tend to 'see thru' masses of `#define`s due to our pre-processor tests
+that we apply. Simply abusing `#define`s or `-Dfoo=bar` won't go as far
+as a program that is more well rounded in confusion.
+
+**Many** C compilers **DISLIKE** the following code, and so do we:
+
+```
+ #define d define
+ #d foo /* <-- don't expect this to turn into #define foo */
+```
+
+
+In other words, it is a compilation error, and in order to get older
+IOCCC winning entries that did this to compile, we had to update them to not do this.
+
+
+When declaring local or global variables, you should declare the type:
+
+```
+ int this_is_fine;
+ this_is_not; /* <-- Try to avoid implicit type declarations */
+```
+
+
+We tend to **like _less_** a submission that requires either
+`gcc` **OR** `clang`. **We _prefer_ submissions** that can compile
+under **BOTH** `gcc` **AND** `clang`.
+
+
+
+We **RECOMMEND** that the compiler flags you use in your
+submission's `Makefile` are supported by **BOTH** `gcc` **AND** `clang`.
+
+
+
+We **DISLIKE** the use of obscure compiler flags, especially
+if `gcc` and/or `clang` do not support it. We **suggest**
+that you not use any really obscure compiler flags if you can help it.
+
+
+One side effect of the above is that you cannot assume the use
+of nested functions such as:
+
+```
+ int main() {
+| void please_dont_submit_this() {
+| printf("The machine that goes BING!!\n");
+ }
+| please_dont_submit_this();
+ }
+```
+
+On 2012 July 20, the [IOCCC judges](../judges.html) rescinded the encouragement of
+nested functions. Such constructions, while interesting and sometimes
+amusing, will have to wait until they are required by a C standard that are
+actually implemented in **BOTH** `gcc` **AND** `clang`.
+
+
+We **DISLIKE** submissions that require the use of `-fnested-functions`.
+
+
+We prefer programs that do not require a fish license: crayons and
+cat detector vans not withstanding.
+
+If your submission uses functions that have a variable number of
+arguments, **be careful**. Systems implement `va_list` in a wide variety
+of ways. Because of this, a number of operations using `va_list` **are
+not portable and _must not_ be used**:
+
+* assigning a non-`va_list` variable to/from a `va_list` variable
+* casting a non-`va_list` variable into/from a `va_list` variable
+* passing a `va_list` variable to a function expecting a non-`va_list` arg
+* passing a non-`va_list` variable to a function expecting a `va_list` arg
+* performing arithmetic on `va_list` variables
+* using `va_list` as a structure or union
+
+In particular, do not treat `va_list` variables as if they were a `char **`.
+
+
+We **DISLIKE** the use of `varargs.h`. Use `stdarg.h` instead.
+
+
+
+We **DISLIKE** the use of `gets(3)`. Use `fgets(3)` instead.
+
+
+
+We tend to **DISLIKE** the blatant use of tarballs in an attempt to simply get
+around the extra file number limit. We realize there may be cases where a
+tarball containing a number of extra files may be needed. Such a need for a
+tarball **MUST** be explained in the `remarks.md` file.
+
+
+On 28 January 2007, the Judges rescinded the requirement that the
+`#` in a C preprocessor directive must be the 1st non-whitespace byte.
+
+The `exit(3)` function returns `void`. Some broken systems have `exit(3)`
+return `int`; your submission should assume that `exit(3)` returns a `void`.
+
+
+This _guideline_ has a change mark at the very start of this line.
+
+
+Small programs are best when they are short, obscure and concise.
+While such programs are not as complex as other winners, they do
+serve a useful purpose: they are often the only program that people
+attempt to completely understand. For this reason, we look for
+programs that are compact, and are instructional.
+
+
+While those who are used to temperatures found on [dwarf
+planets](https://science.nasa.gov/dwarf-planets/)
+(**yes Virginia, dwarf planets _ARE_ planets!**), such as
+[Pluto](https://science.nasa.gov/dwarf-planets/pluto/), might be able to
+explain to the Walrus why our seas are boiling hot, the question of
+whether pigs have wings is likely to remain a debatable point to most.
+
+
+
+One line programs should be short one line programs: say around **80** to **132**
+bytes long. Going well beyond **132** bytes is a bit too long to be called
+a one-liner in our vague opinion.
+
+
+We tend to **DISLIKE** programs that:
+
+* are very hardware specific
+* are very OS version specific (`index(3)`/`strchr(3)` differences are OK, but
+sockets/streams specific code is likely not to be)
+* dump core or have compiler warnings (it is OK only if
+you warn us in your `remarks.md` file)
+*
won't compile or run in a [Single UNIX
+Specification](https://en.wikipedia.org/wiki/Single_UNIX_Specification)
+environment
+*
depend on a utility or application not normally found
+in systems that conform to the [Single UNIX
+Specification](https://en.wikipedia.org/wiki/Single_UNIX_Specification)
+* abuse the build file to get around the size limit
+*
obfuscate by use of ANSI trigraphs
+*
obfuscate by use of digraphs
+*
are larger than they need to be
+*
have more lines than they need to have
+*
are "blob-ier" (just a pile of unformatted C code)
+than they need to be
+*
are rather similar to **[previous
+winners](../years.html)** :-(
+*
are **identical** to **[previous
+losers](https://en.wikipedia.org/wiki/Null_device)** :-)
+* that mandate the exclusive use of a specific Integrated Development Environment (IDE)
+
+In order to encourage submission portability, we **DISLIKE** submissions that
+fail to build unless one is using an IDE. For example, do not
+mandate that one must use Microsoft Visual Studio to compile
+your submission.
+
+
+The program must compile and link cleanly in a [Single UNIX
+Specification](https://en.wikipedia.org/wiki/Single_UNIX_Specification)
+environment. Therefore do not assume the system has a
+[windows.h](https://en.wikipedia.org/wiki/Windows.h) include file:
+
+
+
+```
+ #include /* we DISLIKE this */
+```
+
+Unless you are cramped for space, or unless you are entering the
+'**Best one liner**' category, we suggest that you format your program
+in a more creative way than simply forming excessively long lines.
+
+At least one judge prefers to maintain the use of the
+[leap-second](https://en.wikipedia.org/wiki/Leap_second)
+as part of the world's time standard. If your code prints time
+with seconds, we prefer that your code be capable of printing the
+time of day during a leap-second where the value in seconds
+after the minute mark is **60**.
+
+The `Makefile` should not be used to try and get around the size limit. It is
+one thing to make use of a several `-D`s on the compile line to help out, but it
+is quite another to use many bytes of `-D`s in order to try and squeeze the
+source under the size limit.
+
+Your source code, post-pre-processing, should not exceed the size of
+[Microsoft Windows](https://en.wikipedia.org/wiki/Microsoft_Windows). :-)
+
+
+Other windows, on the other hand, might be OK: especially where "**X
+marks the spot**". Yet on the third hand, windows are best when they are
+"unseen" (i.e., not dirty). :-)
+
+
+
+The [IOCCC judges](../judges.html), as a group, have a history giving wide degree of latitude
+to reasonable submissions. And recently they have had as much longitudinal
+variation as it is possible to have on [Earth](https://science.nasa.gov/earth/). :-)
+
+
+
+You should try to restrict commands used in the build file to commands found in
+[Single UNIX
+Specification](https://en.wikipedia.org/wiki/Single_UNIX_Specification)
+environments and systems that conform to the [Single UNIX
+Specification](https://en.wikipedia.org/wiki/Single_UNIX_Specification).
+
+
+
+You may compile and use your own programs. If you do, try to build and execute
+from the current directory. This restriction is not a hard and
+absolute one. The intent is to ensure that the building of your
+program is reasonably portable.
+
+
+We prefer programs that are portable across a wide variety of UNIX-like
+operating systems (e.g., Linux, GNU Hurd, BSD, UNIX, etc.).
+
+> You are in a maze of twisty _guidelines_, all different.
+
+There are at least zero [IOCCC judges](../judges.html) who think that
+[Fideism](https://en.wikipedia.org/wiki/Fideism) has little
+or nothing to do with the IOCCC judging process.
+
+Don't forget that the building of your program should be done
+**WITHOUT human intervention**. So don't do things such as:
+
+```
+ prog: prog.c
+ #echo this next line requires data from standard input
+ cat > prog.c
+ ${CC} prog.c -o prog
+```
+
+However, you can do something cute such as making your program
+do something dumb (or cute) when it is built 'automatically', and
+when it is run with a human involved, do something more clever.
+For example, one could put in their `Makefile`:
+
+```
+ prog: prog.c
+ ${CC} prog.c -DNON_HUMAN_COMPILE -o prog
+ @echo "See remarks section about alternate ways to compile"
+```
+
+and then include special notes in your `remarks.md` file for
+alternate / human intervention based building.
+
+We want to get away from source that is simply a compact blob of
+bytes. **REALLY TRY** to be more creative than blob coding. **HINT!**
+
+Please do not use things like `gzip(1)` to get around the size limit.
+Please try to be much more creative.
+
+We really **DISLIKE** submissions that make blatant use of including
+large data files to get around the source code size limit.
+
+We do not recommend submitting [systemd](https://systemd.io) source code to the IOCCC,
+if nothing else because that code is likely to exceed [the source code
+size limit](rules.html#rule2). This isn't to say that another highly compact and obfuscated
+replacement of `init` would not be an interesting submission.
+
+Did we remember to indicate that programs that blatantly use
+some complex state machine to do something simple, are boring?
+We think we did. :-)
+
+> All generalizations are false, including this one. -- **Mark Twain**
+
+
+Given two versions of the same program, one that is a compact blob
+of code, and the other that is formatted more like a typical C
+program, we tend to favor the second version. Of course, a third
+version of the same program that is formatted in an interesting
+and/or obfuscated way, would definitely win over the first two!
+Remember, you can submit more than one submission. See the [IOCCC
+rules](rules.html) for details (in particular, [Rule 9](rules.html#rule9)).
+
+
+We suggest that you avoid trying for the '**smallest self-replicating**'
+source. The smallest, a [zero byte entry](../1994/smr/index.html), won in
+[1994](../years.html#1994).
+
+Programs that claim to be the smallest C source that does something, really
+better be the smallest such program or they risk being rejected because
+they do not work as documented.
+
+Please note that the C source below, besides lacking in obfuscation,
+is **NOT** the smallest C source file that when compiled and run, dumps core:
+
+```
+ main;
+```
+
+
+Unless you specify `-fwritable-strings` (see `COTHER` in the example
+Makefile, described in the [Makefile section](#makefile)), do not assume this
+sort of code will work:
+
+
+```
+ char *T = "So many primes, so little time!";
+ ...
+ T[14] = ';'; /* modifying a string requires: -fwritable-strings */
+```
+
+
+Even so, one should probably not assume that this is universally accepted.
+
+
+
+Initialized char arrays are OK to write over. For instance, this is OK:
+
+
+```
+ char b[] = "Is this OK";
+ b[9] = 'k'; /* modifying an initialized char array is OK */
+```
+
+
+There are more than 1 typos in this very sentence.
+
+
+X client submissions should be as portable as possible. Submissions that
+adapt to a wide collection of environments will be favored. For
+example, don't depend on a particular type or size of display.
+Don't assume the use of a particular browser. Instead assume a
+generic browser that forms to a widely used [W3C
+standard](https://www.w3.org/standards/).
+Don't assume a particular sound sub-system or video driver is installed
+in the OS. Instead, make use of a well known and widely available open
+source program (one that actually works) to display audio/visual data.
+
+X client submissions should avoid using X related libraries and
+software that are not in wide spread use.
+
+
+As of Red Hat RHEL9.0, the X.org server is deprecated. See the
+FAQ on "[Xorg deprecation"](../faq.html#Xorg_deprecated)"
+for more details. This does not mean that a submission using this will
+necessarily be rejected, but it would be better if it can support Wayland in
+some way or another.
+
+
+This could be the only _guideline_ that contains the word
+[fizzbin](https://en.wikipedia.org/wiki/List_of_games_in_Star_Trek#Fizzbin).
+
+
+However, do you know how to play [fizzbin](https://en.wikipedia.org/wiki/List_of_games_in_Star_Trek#Fizzbin)?
+You do?!? (Except on Tuesday?)
+
+
+
+OK, there are actually 2 _guidelines_ that contain the word
+[fizzbin](https://en.wikipedia.org/wiki/List_of_games_in_Star_Trek#Fizzbin),
+unless you count this one, in which case there are 3. :-)
+
+
+We **DISLIKE** submissions that use proprietary toolkits such as the `M*tif`,
+`Xv*ew`, or `OpenL*ok` toolkits, since not everyone has them. Use an
+open source toolkit that is widely and freely available instead.
+
+**NOTE**: The previous _guideline_ in this spot has been replaced by this _guideline_:
+
+
+X client submissions should try to not to depend on particular items in
+`.Xdefaults`. If you must do so, be sure to note the required lines
+in the your `remarks.md` file. They should also not depend on any
+particular window manager.
+
+
+
+Try to avoid submissions that play music that some people believe is copyrighted
+music.
+
+
+
+While we recognize that UNIX is not a universal operating system, the contest
+does have a bias towards such systems. In an effort to expand the scope of the
+contest, we phrase our bias to favor the [Single UNIX
+Specification](https://en.wikipedia.org/wiki/Single_UNIX_Specification).
+
+
+
+You are **well advised** to submit code that conforms to the [Single UNIX
+Specification Version 4](https://unix.org/version4/overview.html).
+
+
+
+To quote the [IOCCC judges](../judges.html):
+
+
+> You very well might not be completely prohibited from failing to not partly
+misunderstand this particular _guideline_, but of course, we could not possibly
+comment! :-) Nevertheless, you are neither prohibited, nor are you fully
+required to determine that this or the previous sentence is either false and/or
+perhaps misleading. Therefore, it might be wise for you to not fail to consider
+to not do so, accordingly. Thank you very much.
+
+Any complaints about the above _guideline_ could be addressed to the
+Speaker of the House of Commons, or to the speaker of your national
+parliament should you have one.
+
+We **LIKE** programs that:
+
+* are as concise and small as they need to be
+* do something at least quasi-interesting
+* are portable
+* are unique or novel in their obfuscation style
+* make use of a **NUMBER OF DIFFERENT TYPES OF OBFUSCATIONS!** **<== HINT!!**
+* make us laugh and/or throw up :-) (humor really helps!)
+* make us want to eat good chocolate
+
+Some types of programs can't excel (anti-tm) in some areas. Your
+program doesn't have to excel in all areas, but doing well in several
+areas really does help.
+
+
+You are better off explaining what your submission does in your
+`remarks.md` file section rather than leaving it obscure for the
+[IOCCC judges](../judges.html) as we might miss something and/or be too tired to
+notice.
+
+
+
+Please avoid this specific individual _guideline_, if it at all possible.
+
+
+
+We freely admit that interesting, creative or humorous comments in
+your `remarks.md` file help your chances of winning. If you had to
+read so many twisted submissions, you too would enjoy a good laugh or two.
+We think the readers of the contest winners do as well. We do read
+your `remarks.md` content during the judging process, so it is worth your
+while to write a remarkable `remarks.md` file.
+
+
+We **DISLIKE** C code with trailing control-M's (`\r` or `\015`) that results
+in compilation failures. Some non-UNIX/non-Linux tools such as
+MS Visual C and MS Visual C++ leave trailing control-M's on lines.
+Users of such tools should strip off such control-M's before submitting
+their submissions. In some cases tools have a "Save As" option that will
+prevent such trailing control-M's being added.
+
+One should restrict libcurses to portable features found on BSD
+or Linux curses.
+
+
+[Rule 13](rules.html#rule13) no longer discourages the use of UTF-8
+characters in C code.
+
+
+
+It is a very good idea to, in your `remarks.md` file, tell us why you
+think your submission is obfuscated. This is particularly true if
+your submission has some very subtle obfuscations that we might
+otherwise overlook. **<<-- Hint!**
+
+
+Anyone can format their code into a dense blob. A really clever
+author will try format their submission using a "normal" formatting style
+such that at first glance (if you squint and don't look at the details)
+the code might pass for non-obfuscated C. Deceptive comments,
+and misleading formatting, in some cases, may be a plus. On the
+other hand, a misleading code style requires more source bytes.
+
+If you do elect to use misleading formatting and comments, we
+suggest you remark on this point in your `remarks.md` where you talk
+about why you think your submission is obfuscated. On the other hand,
+if you are pushing up against the size limits, you may be forced
+into creating a dense blob. Such are the trade-offs that obfuscators face!
+
+
+We prefer code that can run on either a 64-bit or 32-bit
+processor. However, it is **UNWISE **to assume it will run on an
+some Intel-like x86 architecture**.
+
+
+We believe that Mark Twain's quote:
+
+> Get your facts first, then you can distort them as you please.
+
+... is a good motto for those writing code for the IOCCC.
+
+
+The IOCCC size tool source is not an original work, unless you are [Anthony C
+Howe](../authors.html#Anthony_C_Howe), in which case it is original! :-)
+Submitting source code that uses the contents of
+[iocccsize.c](https://github.com/ioccc-src/mkiocccentry/blob/master/iocccsize.c),
+_unless_ you are [Anthony C Howe](../authors.html#Anthony_C_Howe), might run the
+risk of violating [Rule 7](rules.html#rule7).
+
+
+
+The IOCCC submission tarball validator source is not an original work,
+unless you are [Cody Boone Ferguson](../authors.html#Cody_Boone_Ferguson), in
+which case it is original! :-) Submitting source code that uses the contents of
+[txzchk.c](https://github.com/ioccc-src/mkiocccentry/blob/master/txzchk.c),
+_unless_ you are [Cody Boone Ferguson](../authors.html#Cody_Boone_Ferguson), might
+run the risk of violating [Rule 7](rules.html#rule7).
+
+
+
+In addition to the above tools, none of the [mkiocccentry
+tools](https://github.com/ioccc-src/mkiocccentry), _including, **but not
+limited**_ to
+[mkiocccentry](https://github.com/ioccc-src/mkiocccentry/blob/master/mkiocccentry.c),
+[chkentry](https://github.com/ioccc-src/mkiocccentry/blob/master/chkentry.c),
+[fnamchk](https://github.com/ioccc-src/mkiocccentry/blob/master/test_ioccc/fnamchk.c)
+and
+[location](https://github.com/ioccc-src/mkiocccentry/blob/master/soup/location_main.c),
+nor the [JSON parser and
+library](https://github.com/ioccc-src/mkiocccentry/blob/master/jparse/README.md),
+[jstrencode](https://github.com/ioccc-src/mkiocccentry/blob/master/jparse/jstrencode.c),
+[jstrdecode](https://github.com/ioccc-src/mkiocccentry/blob/master/jparse/jstrdecode.c)
+or any of the other [jparse
+tools](https://github.com/ioccc-src/mkiocccentry/blob/master/jparse)
+(see the [jparse repo](https://github.com/xexyl/jparse/)), are original works,
+unless you are [Cody Boone Ferguson](../authors.html#Cody_Boone_Ferguson) or
+[Landon Curt Noll](http://www.isthe.com/chongo/index.html), in which case they
+are original! :-) Submitting source code that uses the content of any of these tools or
+library, _unless_ you are [Cody Boone
+Ferguson](../authors.html#Cody_Boone_Ferguson) or [Landon Curt
+Noll](http://www.isthe.com/chongo/index.html), might run the risk of violating
+[Rule 7](rules.html#rule7).
+
+
+
+And unless you are [Landon Curt Noll](https://en.wikipedia.org/wiki/Landon_Curt_Noll),
+the code in
+[dbg](https://github.com/ioccc-src/mkiocccentry/tree/master/dbg) and
+[dyn_array](https://github.com/ioccc-src/mkiocccentry/tree/master/dyn_array) are
+not original works. Submitting source code that uses the contents of those
+libraries, _unless_ you [Landon Curt Noll](https://en.wikipedia.org/wiki/Landon_Curt_Noll),
+might run the risk of violating [Rule 7](rules.html#rule7).
+
+
+
+[Rule 7](rules.html#rule7) does not prohibit you from writing your own
+obfuscated versions of these tools, unless of course you are [Landon Curt
+Noll](http://www.isthe.com/chongo/index.html), in which case you _probably_
+won't win since [IOCCC judges](../judges.html) should not enter the IOCCC! :-)
+However, **_if_** you do write your own version, you **_might_** wish to make it do something
+**_more_ interesting** than simply implementing the [IOCCC](../index.html)
+tools' algorithms.
+
+
+
+Even so, we do not recommend you try and submit a JSON parser due to
+the fact it will likely exceed [the source code size limit](rules.html#rule2)
+and because you likely can't beat [flex](https://github.com/westes/flex) and
+[bison](https://www.gnu.org/software/bison/) in obfuscation. This isn't to
+say that [the so-called JSON spec](https://github.com/xexyl/jparse/blob/master/json_README.md#so-called-json-spec) is not
+obfuscated, but unless you have some really clever way to compact and
+obfuscate a JSON parser more than [flex](https://github.com/westes/flex) and
+[bison](https://www.gnu.org/software/bison/) you will likely not win, either
+because of the [source code size limit](rules.html#rule2) or because it is not
+as obfuscated as the [flex](https://github.com/westes/flex) and [bison](https://www.gnu.org/software/bison/)
+generated code of
+[jparse](https://github.com/ioccc-src/mkiocccentry/blob/master/jparse).
+
+
+While programs that only run in a specific word size are OK, if you have
+to pick, choose a 64-bit word size.
+
+
+If the [IOCCC judges](../judges.html) are feeling ornery we
+might choose to compile your program for running on an Arduino or
+a PDP-11. Heck, should we ever find an emulator of 60-bit CDC Cyber
+CPU, we might just try your submission on that emulator as well :-)
+
+
+
+If your submission **MUST** run only on a 64-bit or 32-bit architecture,
+then you **MUST** specify the `-arch` on your command line
+(see `ARCH` in the example
+Makefile, described in [Makefile section](#makefile)). Do not assume a
+processor word size without specifying `-arch`. For example:
+
+
+```
+ ARCH= -m64
+```
+
+
+Note, however, that some platforms will not necessarily support some
+architectures. For instance, more recent versions of `macOS` do **NOT** support
+32-bit!
+
+
+
+If there are limitations in your submission, you are highly encouraged
+to note such limitations in your `remarks.md` file. For example if your
+submission factors values up to a certain size, you might want to state:
+
+
+> This submission factors values up `2305567963945518424753102147331756070`.
+Attempting to factor larger values will produce unpredictable results.
+
+The [IOCCC judges](../judges.html) might try to factor the value -5, so you want to might state:
+
+> This submission factors positive values up
+`2305567963945518424753102147331756070`. Attempting to factor large values will
+produce unpredictable results.
+
+However the [IOCCC judges](../judges.html) might try to also factor 0, so you want to might state:
+
+> This submission factors values between 1 and
+`2305567963945518424753102147331756070`. Attempting to factor values outside
+that range will produce unpredictable results.
+
+
+Moreover they might try to also factor 3.5 or 0x7, or Fred, so you want to might state:
+
+
+> This submission factors integers between 1 and
+`2305567963945518424753102147331756070`. Attempting to factor anything else
+will produce unpredictable results.
+
+You submission might be better off catching the attempt to factor bogus values
+and doing something interesting. So you might want to code accordingly and state:
+
+> This submission factors integers between 1 and `2305567963945518424753102147331756070`.
+> Attempting to factor anything else will cause the program to insult your pet fish Eric.
+
+The [IOCCC judges](../judges.html) might not have a pet fish named Eric, so you might want to state:
+
+> This submission factors integers between 1 and
+`2305567963945518424753102147331756070`. Attempting to factor anything else
+will cause the program to insult your pet fish Eric, or in the case that you
+lack such a pet, will insult the pet that you do not have.
+
+When all other things are equal, a submission with fewer limitations will be judged
+better than a submission with lots of limitations. So you might want to code accordingly
+and state:
+
+> This submission attempts to a factor value of any size provided that the
+program is given enough time and memory. If the value is not a proper integer,
+the program might insult a fish named Eric.
+
+
+Do not fear if you're not 100% sure of the significance of
+`2305567963945518424753102147331756070` as it is not of prime importance: or is
+it? :-)
+
+
+
+We **DISLIKE** the use of ASCII tab characters in markdown files, such as in the required `remarks.md` file.
+
+
+
+We don't mind the use of ASCII tab characters in your C code. Feel free
+to use ASCII tab characters if that suits your obfuscation needs. If is
+perfectly **OK** to use tab characters elsewhere in your submission, just not in
+markdown files as this tends annoy us when it comes time to
+rendering your markdown content as it complicates the process.
+
+
+
+If you do use ASCII tab characters in your non-markdown files, be
+aware that some people may use a tab stop that is different than the common 8
+character tab stop.
+
+
+
+**PLEASE** observe our [IOCCC markdown guidelines](../markdown.html)
+when forming your submission's `remarks.md` file. And if your submission
+contains additional markdown files, please follow those same guidelines for
+those files. See also [Rule 19](rules.html#rule19) and our
+FAQ on "[markdown](../faq.html#markdown)".
+
+
+
+We **LIKE** reading `remarks.md` files, especially if they contain
+useful, informative, and even humorous content about your submission. Yes, this
+is a **hint**. :-)
+
+
+
+We **RECOMMEND** you put a reasonable amount effort into the content of the
+`remarks.md` file: it is a required file for a reason. :-)
+
+
+Try to be even more creative!
+
+
+Jump to: [top](#)
+
+
+
+
+# ABUSING THE RULES:
+
+
+
+Legal abuse of the [IOCCC rules](rules.html) is somewhat encouraged. Legal rule abuse
+may involve, but is not limited to, doing things that are technically allowed by
+the [IOCCC rules](rules.html) and yet do not fit the spirit of what we intended to be
+submitted.
+
+Legal rule abuse is encouraged to help promote creativity. Rule abuse
+submissions, regardless of if they receive an award, result in changes to
+the next year's [IOCCC rules](rules.html) and [IOCCC guidelines](guidelines.html).
+
+Legal abuse of the [IOCCC rules](rules.html) is **NOT** an invitation to violate the
+[IOCCC rules](rules.html). A submission that violates the [rules](rules.html) in the
+opinion of the [IOCCC judges](../judges.html), **WILL** be
+disqualified. **_RULE ABUSE CARRIES A CERTAIN LEVEL OF RISK!_** If you
+have a submission that might otherwise be interesting, you might want to
+submit two versions; one that does not abuse the [IOCCC rules](rules.html) and one that
+does.
+
+
+If you intend to abuse the [IOCCC rules](rules.html),
+indicate so in your `remarks.md` file. You **MUST** try to justify
+why you consider your rule abuse to be allowed under the
+[IOCCC rules](rules.html). That is, you must plead your case as to why
+your submission is valid. Humor and/or creativity help plead a case.
+As there is no guarantee that you will succeed, you might consider
+submitting an alternate version that conforms to the
+[IOCCC rules](rules.html).
+
+
+
+If you do bypass the `mkiocccentry(1)` warnings about [Rule
+2a](rules.html#rule2a) and/or about [Rule 2b](rules.html#rule2b) or any other
+rule and submit a submission anyway, you **MUST** try to justify why the IOCCC
+[IOCCC judges](../judges.html) should not reject your submission due to a rule
+violation, and you would be wise to do this towards the top of your `remarks.md`
+file.
+
+
+
+Abusing the web submission procedure tends to annoy us more
+than amuse us. Spend your creative energy on content of your
+submission rather than on the submission process itself.
+
+
+
+We are often asked why the contest [IOCCC rules](rules.html) and [IOCCC
+guidelines](guidelines.html) seem strange or contain mistakes, flaws or
+grammatical errors. One reason is that we sometimes make genuine mistakes. But
+in many cases such problems, flaws or areas of confusion are deliberate.
+Changes to [IOCCC rules](rules.html) and [IOCCC guidelines](guidelines.html) in
+response to rule abuses, are done in a minimal fashion. Often we will
+deliberately leave behind holes (or introduce new ones) so that future rule
+abuse can continue. A clever author should be able to read them and "drive a
+truck through the holes" in the [IOCCC rules](rules.html) and [IOCCC
+guidelines](guidelines.html).
+
+
+
+At the risk of stating the obvious, this contest is a parody of the software
+development process. The [IOCCC rules](rules.html) and [IOCCC guidelines](guidelines.html)
+are only part of the overall contest. Even so, one might think the
+contest [IOCCC rules](rules.html) and [IOCCC guidelines](guidelines.html) process as a parody
+of the sometimes tragic mismatch between what a customer (or marketing) wants
+and what engineering delivers. Real programmers must face obfuscated and
+sometimes conflicting specifications and requirements from marketing, sales,
+product management and even from customers themselves on an all too regular basis.
+This is one of the reasons why the [IOCCC rules](rules.html) and
+[IOCCC guidelines](guidelines.html) are written in obfuscated form.
+
+
+
+Jump to: [top](#)
+
+
+
+# JUDGING PROCESS:
+
+
+Submissions are judged by Leonid A. Broukhis and Landon Curt Noll.
+
+
+Each submission submitted is given a random string and subdirectory. The
+submission files including, but not limited to `prog.c`, `Makefile`,
+`remarks.md`, `.info.json`, `.auth.json` as well as any data files that you
+submit, are all placed under their own directory and stored and judged from this
+directory.
+
+
+Any information about the authors is not read by the [IOCCC judges](../judges.html) until
+the judging process is complete, and then only from entries that have
+won an award. Because we do not read this information for entries that
+do not win, we do not know who did not win.
+
+The above process helps keep us biased for/against any one particular
+individual. Therefore you **MUST** refrain from putting any information
+that reveals your identity in your submission.
+
+
+Now some people point out that coding and/or writing style might reveal the
+information about the authors. However we consider this to be simply
+circumstantial and outside the scope of the above paragraph.
+
+
+Some people, in the past, have attempted to obfuscate their identity by
+including comments of famous Internet personalities such as [Peter
+Honeyman](http://www.citi.umich.edu/u/honey). The [IOCCC judges](../judges.html) are on to this trick
+and therefore consider any obfuscated source or data file claiming to be from
+Honeyman to not be from Honeyman. This of course creates an interesting paradox
+known as the "**obfuscated Peter Honeyman paradox**". Should Peter Honeyman
+actually submit to the IOCCC, he alone is excluded from the above, as we
+will likely believe it's just another attempt at confusion. This _guideline_ is
+known as the "**Peter Honeyman is exempt**" _guideline_.
+
+**BTW**: None of the submissions claiming to be from Peter Honeyman have ever
+won an award. So it is theoretically possible that Peter Honeyman
+did submit to the IOCCC in the past. In the past, Peter had denied
+submitting anything to the IOCCC. Perhaps those submissions were
+submitted by one of his students?
+
+Hopefully we are **VERY CLEAR** on this point! The rules now strongly state:
+**PLEASE _DO NOT_ put a name of an author**, in an obvious way, into your
+source code, `remarks.md`, data files, etc., the above "**Peter Honeyman is
+exempt**" notwithstanding.
+
+We seemed to have digressed again ... :-) Returning to the judging process:
+
+We prefer to be kept in the dark as much as you are until the final
+awards are given. We enjoy the surprise of finding out in the end,
+who won and where they are from.
+
+We attempt to keep all submissions anonymous, unless they win an award.
+Because the main 'prize' of winning is being announced, we make all
+attempts to send non-winners into oblivion. We remove all non-winning
+files, and shred all related printouts. By tradition, we do not even
+reveal the number of submissions that we receive.
+
+
+During the judging process, a process that spans multiple sessions over
+a few weeks, we post general updates from our [Mastodon
+account](https://fosstodon.org/@ioccc).
+
+
+
+**Make sure you reload the feed** every so often **because unless you
+are mentioned you will NOT get a push notification!**
+
+
+
+Jump to: [top](#)
+
+
+
+## JUDGING ROUNDS:
+
+
+Judging consists of a number of elimination rounds. During a round,
+the collection of submissions are divided into two roughly equal piles;
+the pile that advances on to the next round, and the pile that does
+not. We also re-examine the submissions that were eliminated in the
+previous round. Thus, a submission gets at least two readings and
+often more than two.
+
+
+Jump to: [top](#)
+
+
+
+## JUDGING READINGS:
+
+
+A reading consists of a number of actions:
+
+*
Reading `prog.c`, the C source and reviewing the `remarks.md` information
+*
Briefly looking at any supplied data files
+* Passing the source thru the C pre-processor skipping over any `#include`d files
+* Performing a number of C beautify/cleanup edits on the source
+* Passing the beautified source thru the C pre-processor skipping over any `#include`d files
+* Compiling/building the source
+* Running the program
+* Doing other things that only [IOCCC judges](../judges.html) know about :-)
+
+In later rounds, other actions are performed including performing
+miscellaneous tests on the source and binary.
+
+
+This is the very **guideline** that goes, **BING!**
+
+
+
+Okay, technically that was the _second_ **guideline** that goes **BING**, and this
+is the third. :-)
+
+
+Until we reduce the stack of submissions down to about 25 submissions,
+submissions are judged on an individual basis. A submission is set aside because it
+does not, in our opinion, meet the standard established by the round.
+When the number of submissions thins to about 25 submissions, we begin to form
+award categories. Submissions begin to compete with each other for awards.
+A submission will often compete in several categories.
+
+The actual award category list will vary depending on the types of submissions
+we receive. A typical category list might be:
+
+* **best small one line program** (see above about one line programs)
+* **best small program**
+* **strangest/most creative source layout**
+* **most useful obfuscated program**
+* **best game that is obfuscated**
+* **most creatively obfuscated program**
+* **most deceptive C code** (code with deceptive comments and source code)
+*
**best X program** (see [OUR LIKES AND DISLIKES](#likes)
+and the
+FAQ on "[Xorg being deprecated](../faq.html#Xorg_deprecated)")
+* **best abuse of ISO C or ANSI C standard** (see above about compilers)
+* **best abuse of the C preprocessor**
+* **worst/best abuse of the rules** (or some variation)
+* (anything else so strange that it deserves an award)
+
+We do not limit ourselves to this list. For example, a few submissions are so
+good/bad that they are declared winners at the start of the final round.
+We will invent awards categories for them, if necessary.
+
+In the final round process, we perform the difficult tasks of
+reducing the remaining submissions (typically about 25) down to to about
+half that number: declaring those remaining to be winners.
+
+Often we are confident that the submissions that make it into
+the final round are definitely better than the ones that do not
+make it. The selection of the winners out of the final round, is
+less clear cut, however.
+
+Sometimes a final round submission is good enough to win, but is beat out by a
+similar, but slightly better submission. For this reason, it is sometimes
+worthwhile to resubmit an improved version of a submission that failed to win in
+a previous year, the next year. This assumes, of course, that the submission is
+worth improving in the first place!
+
+
+Over the years, more than one [IOCCC judge](../judges.html)
+has been known to **bribe** another [IOCCC judge](../judges.html) into voting for a
+winning submissions by offering a bit of high quality chocolate, or
+other fun item.
+
+
+
+One **should NOT** attempt to **bribe** an [IOCCC
+judge](../judges.html), **unless you are an [IOCCC judge](../judges.html)**,
+because **bribing** an [IOCCC judge](../judges.html) by a non-judge
+has been shown to **NOT** be effective when the **person _attempting_
+the _bribe_ is made known** to the [IOCCC judges](../judges.html)
+(i.e., they are not anonymous) AND/OR the **bribe** is otherwise
+associated with a submission to the [IOCCC](../index.html).
+
+
+
+With the previous guideline in mind: **anonymous** gifts
+for the [IOCCC judges](../judges.html) that are **NOT ASSOCIATED
+WITH** a submission to the [IOCCC](../index.html) may be sent to the
+[IOCCC judges](../judges.html) via the
+[IOCCC Amazon wishlist](https://www.amazon.com/hz/wishlist/ls/3HSNTEL8RQ1M0?ref_=wl_share).
+It has been shown that receiving **anonymous** gifts provides the
+[IOCCC judges](../judges.html) with a nice
+[dopamine](https://en.wikipedia.org/wiki/Dopamine) boost, and happy
+[IOCCC judges](../judges.html) help make the [IOCCC](../index.html) better for everyone. :-)
+
+
+
+See the
+FAQ on "[supporting the IOCCC](../faq.html#support)".
+
+
+More often than not, we select a small submission (usually one line) and a
+strange/creative layout submission. We sometimes also select a
+submission that abuses the [IOCCC guidelines](guidelines.html) in an interesting way,
+or that stretches the contest [rules](rules.html) that while legal, it
+nevertheless goes against the **intent** of the [rules](rules.html).
+
+
+Nevertheless, see [Rule 12](rules.html#rule12).
+
+
+In the end, we traditionally pick one submission as '**best**'. Sometimes such
+a submission simply far exceeds any of the other submissions. More often, the
+'**best**' is picked because it does well in a number of categories.
+
+In years past, we renamed the winning submission from `prog.c` to a
+name related to the author(s)' names. This is no longer done.
+Winning source is called `prog.c`. A compiled binary is called `prog`.
+
+
+Jump to: [top](#)
+
+
+
+# ANNOUNCEMENT OF WINNERS:
+
+
+
+The [IOCCC judges](../judges.html) will toot initial announcement of who won, the name
+of their award, and a very brief description (award title) of the winning entry
+from the [@IOCCC Mastodon account](https://fosstodon.org/@ioccc).
+
+
+
+We recommend that you follow us on mastodon but **please make sure to
+refresh the feed** every so often (if not more often) because unless you are
+mentioned or someone boosts your post you will not get a push notification.
+
+
+
+Jump to: [top](#)
+
+
+
+## How the new IOCCC winners will be announced
+
+
+
+The [current status of the IOCCC](../status.html) will change from
+**[judging](../faq.html#judging)** to **[closed](../faq.html#closed)** .
+
+
+
+The **contest_status** in the [status.json](../status.json) file will change
+from **judging** to **closed** as well.
+
+
+
+When the above happens, the winning entries have been selected by the [IOCCC
+judges](../judges.html).
+
+
+
+The [IOCCC judges](../judges.html) will begin to prepare to release the source
+code of the new IOCCC winners.
+
+
+
+The [IOCCC judges](../judges.html) will commit the winning source to the
+[IOCCC winner repo](https://github.com/ioccc-src/winner) which will update the
+[Official IOCCC website](https://www.ioccc.org/index.html).
+
+
+
+The [IOCCC news](../news.html) will also contain an announcement of the winners.
+
+
+
+Jump to: [top](#)
+
+
+
+## An important update to how winners are announced
+
+
+
+The IOCCC no longer uses twitter. Winning IOCCC entries will be announced by a
+`git` commit to the [IOCCC entries repo](https://github.com/ioccc-src/winner)
+that, in turn, updates the [Official IOCCC
+website](https://www.ioccc.org/index.html).
+
+
+
+In addition a note is posted to the [IOCCC Mastodon account](https://fosstodon.org/@ioccc).
+
+
+
+We will also post a notice to the IOCCC discord server.
+
+
+
+Consider joining the IOCCC discord community via this link:
+[https://discord.gg/Wa42Qujwnw](https://discord.gg/Wa42Qujwnw)
+
+
+
+Jump to: [top](#)
+
+
+
+## Back to announcement of winners
+
+
+
+It is pointless to ask the [IOCCC judges](../judges.html) how many
+submissions we receive. See [How many submissions do the judges receive for a
+given IOCCC?](../faq.html#how_many).
+
+
+
+Often, winning entries are published in selected magazines from around the
+world. Winners have appeared in books ('`The New Hacker's Dictionary`',
+'`Obfuscated C and Other Mysteries`', '`Pointers On C`', others) and on t-shirts
+(sometimes by the author(s) themselves). There have been multiple classes
+that have focused in part, on IOCCC winning entries. And more than one winner has been turned
+into a tattoo!
+
+
+Last, but not least, [winners](../authors.html) receive international fame and flames! :-)
+
+
+Jump to: [top](#)
+
+
+
+
+# FOR MORE INFORMATION:
+
+
+
+
+For questions or comments about the contest, see [Contacting the IOCCC](../contact.html).
+
+
+
+**Be SURE** to review the [IOCCC Rules and Guidelines](index.html) as they
+may (and **often do**) change from year to year.
+
+
+
+**PLEASE** be sure you have the current [IOCCC rules](rules.html) and
+[IOCCC guidelines](guidelines.html) prior to submitting to the contest.
+
+
+See the [Official IOCCC website news](../news.html) for additional information.
+
+
+For the updates and breaking IOCCC news, you are encouraged to follow
+the [IOCCC on Mastodon](https://fosstodon.org/@ioccc). See our
+FAQ on "[Mastodon](../faq.html#try_mastodon)"
+for more information. Please do note that unless
+you are mentioned by us you will **NOT** get a notification from the app _so you
+should refresh the page **even if you do follow us**_.
+
+
+
+Check out the [Official IOCCC winner website](https://www.ioccc.org/index.html) in general.
+
+
+
+Consider joining the IOCCC discord community via this link:
+[https://discord.gg/Wa42Qujwnw](https://discord.gg/Wa42Qujwnw)
+
+
+
+See the
+FAQs on "[obtaining, compiling, installing and using the mkiocccentry tools](../faq.html#mkiocccentry)"
+and the
+FAQ on "[how to enter the IOCCC](../quick-start.html#enter)"
+as that FAQ has important details on
+[how to register](../next/register.html)
+as well as
+[how to upload your submission](../next/submit.html) for the IOCCC.
+
+
+
+
+
+
+Jump to: [top](#)
diff --git a/2024/howe/.entry.json b/2024/howe/.entry.json
new file mode 100644
index 000000000..1a8e1f3f2
--- /dev/null
+++ b/2024/howe/.entry.json
@@ -0,0 +1,113 @@
+{
+ "no_comment" : "mandatory comment: because comments were removed from the original JSON spec",
+ "entry_JSON_format_version" : "1.2 2024-09-25",
+ "award" : "Nice accent eh-ward",
+ "year" : 2024,
+ "dir" : "howe",
+ "entry_id" : "2024_howe",
+ "title" : "eh",
+ "abstract" : "mini vi",
+ "author_set" : [
+ {
+ "author_handle" : "Anthony_C_Howe"
+ }
+ ],
+ "manifest" : [
+ {
+ "file_path" : "prog.c",
+ "inventory_order" : 20,
+ "OK_to_edit" : true,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "entry source code"
+ },
+ {
+ "file_path" : "Makefile",
+ "inventory_order" : 30,
+ "OK_to_edit" : true,
+ "display_as" : "makefile",
+ "display_via_github" : true,
+ "entry_text" : "entry Makefile"
+ },
+ {
+ "file_path" : "prog.orig.c",
+ "inventory_order" : 50,
+ "OK_to_edit" : false,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "original source code"
+ },
+ {
+ "file_path" : "prog.html",
+ "inventory_order" : 100,
+ "OK_to_edit" : false,
+ "display_as" : "markdown",
+ "display_via_github" : true,
+ "entry_text" : "eh man page"
+ },
+ {
+ "file_path" : "try.sh",
+ "inventory_order" : 100,
+ "OK_to_edit" : true,
+ "display_as" : "shellscript",
+ "display_via_github" : true,
+ "entry_text" : "script to try entry"
+ },
+ {
+ "file_path" : "2024_howe.tar.bz2",
+ "inventory_order" : 1415926535,
+ "OK_to_edit" : false,
+ "display_as" : "tbz2",
+ "display_via_github" : false,
+ "entry_text" : "download entry tarball"
+ },
+ {
+ "file_path" : ".entry.json",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : true,
+ "display_as" : "json",
+ "display_via_github" : true,
+ "entry_text" : "entry summary and manifest in JSON"
+ },
+ {
+ "file_path" : ".gitignore",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : true,
+ "display_as" : "gitignore",
+ "display_via_github" : true,
+ "entry_text" : "list of files that should not be committed under git"
+ },
+ {
+ "file_path" : ".path",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : false,
+ "display_as" : "path",
+ "display_via_github" : false,
+ "entry_text" : "directory path from top level directory"
+ },
+ {
+ "file_path" : "README.md",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : true,
+ "display_as" : "markdown",
+ "display_via_github" : true,
+ "entry_text" : "markdown source for this web page"
+ },
+ {
+ "file_path" : "prog.md",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : true,
+ "display_as" : "markdown",
+ "display_via_github" : true,
+ "entry_text" : "markdown source for prog.html"
+ },
+ {
+ "file_path" : "index.html",
+ "inventory_order" : 4294967295,
+ "OK_to_edit" : false,
+ "display_as" : "html",
+ "display_via_github" : false,
+ "entry_text" : "this web page"
+ }
+ ]
+}
diff --git a/2024/howe/.gitignore b/2024/howe/.gitignore
new file mode 100644
index 000000000..307db0e29
--- /dev/null
+++ b/2024/howe/.gitignore
@@ -0,0 +1,2 @@
+eh
+foo
diff --git a/2024/howe/.path b/2024/howe/.path
new file mode 100644
index 000000000..c0e0107a8
--- /dev/null
+++ b/2024/howe/.path
@@ -0,0 +1 @@
+2024/howe
diff --git a/2024/howe/2024_howe.tar.bz2 b/2024/howe/2024_howe.tar.bz2
new file mode 100644
index 000000000..1ffd67942
Binary files /dev/null and b/2024/howe/2024_howe.tar.bz2 differ
diff --git a/2024/howe/Makefile b/2024/howe/Makefile
new file mode 100644
index 000000000..b46e29ae8
--- /dev/null
+++ b/2024/howe/Makefile
@@ -0,0 +1,232 @@
+#!/usr/bin/env make
+#
+# 2024/howe
+
+#############################
+# shell used by this Makefile
+#############################
+
+SHELL= bash
+
+
+#######################
+# common tool locations
+#######################
+
+include ../../var.mk
+
+
+#####################
+# C compiler settings
+#####################
+
+# Common C compiler warnings to silence
+#
+# -Wno-char-subscripts ctypes macros
+# -Wno-incompatible-pointer-types atexit(endwin)
+# -Wno-unused-parameter main(int argc, ...)
+#
+# -Wno-strict-prototypes functions no arguments
+# -Wno-missing-prototypes clang functiosn without static
+# -Wno-missing-variable-declarations clang globals without static
+# -Wno-tentative-definition-array clang array definitions
+#
+CSILENCE= -Wno-strict-prototypes -Wno-pointer-sign
+
+# Attempt to silence unknown warning options
+#
+CUNKNOWN= -Wno-unknown-warning-option
+
+# Common C compiler warning flags
+#
+# NOTE: The addition of -pedantic to CWARN is a challenge that
+# You may wish to avoid if it proves too problematic.
+# There is NO penalty for removing -pedantic from CWARN.
+#
+CWARN= -Wall -Wextra -pedantic ${CSILENCE} ${CUNKNOWN}
+
+# Compiler standard
+#
+CSTD= -std=gnu17
+
+# Compiler bit architecture
+#
+# Example for 32-bitness: ARCH= -m32
+# Example for 64-bitness: ARCH= -m64
+#
+# NOTE: Normally one should NOT specify a specific architecture.
+#
+ARCH=
+
+# Defines that are needed to compile
+#
+# Frack need extra #define to enable SUS standard strdup(), strndup().
+#
+CDEFINE= -DBUF=${BUF} -DMODE=${MODE} -D_XOPEN_SOURCE=700
+
+# Include files that are needed to compile
+#
+# Example: CINCLUDE= -include stdio.h
+#
+CINCLUDE= -include curses.h -include ctype.h -include string.h \
+ -include stdlib.h -include iso646.h -include regex.h \
+ -include fcntl.h -include locale.h -include unistd.h
+
+# Other flags to pass to the C compiler
+#
+# Example: COTHER= -fno-math-errno
+#
+COTHER= -funsigned-char
+
+# Optimization
+#
+# NOTE: Feel free to change the level of compiler optimization.
+# The "-O3" is just a friendly default you might wish to try.
+#
+# Example: OPT= -O0 -g
+#
+OPT= -Os
+
+# Default flags for ANSI C compilation
+#
+CFLAGS= ${CSTD} ${CWARN} ${ARCH} ${CDEFINE} ${CINCLUDE} ${COTHER} ${OPT}
+
+# Libraries needed to build
+#
+LDFLAGS= -lcurses
+
+# C compiler to use
+#
+# NOTE: The IOCCC Judges recommend you leave CC as just "cc"
+# and NOT set it to clang, or gcc, or something else
+# unless you have a STRONG reason to do so.
+#
+# Setting CC to something other than "cc" makes your
+# code less portable to those who do not have your
+# particular C compiler. **hint**
+#
+# If you want to test your code with a particular C compiler,
+# use the make command line. For example:
+#
+# make all CC=clang
+# make all CC=gcc
+#
+CC= cc
+
+# Compiler add-ons or replacements for clang only
+#
+ifeq "$(findstring $(CLANG),${CC})" "$(CLANG)"
+#
+# NOTE: This code is only invoked when CC is "clang"
+# such as when you use the make command line:
+#
+# make all CC=clang
+#
+CSILENCE+= -Wno-c99-compat -Wno-comma \
+ -Wno-declaration-after-statement -Wno-implicit-int-conversion \
+ -Wno-incompatible-function-pointer-types-strict -Wno-missing-prototypes \
+ -Wno-missing-variable-declarations -Wno-poison-system-directories \
+ -Wno-shadow -Wno-sign-conversion -Wno-strict-prototypes -Wno-unsafe-buffer-usage
+#
+CWARN+= -Weverything
+#
+endif
+
+# Specific add-ons or replacements for gcc only
+#
+ifeq "$(findstring $(GCC),${CC})" "$(GCC)"
+#
+# NOTE: This code is only invoked when CC is "gcc"
+# such as when you use the make command line:
+#
+# make all CC=gcc
+#
+CSILENCE+=
+#
+CWARN+=
+#
+endif
+
+
+###########################################
+# Special Makefile variables for this entry
+###########################################
+
+ENTRY= prog
+PROG= ${ENTRY}
+#
+OBJ= ${PROG}.o
+TARGET= ${PROG} eh
+#
+ALT_OBJ=
+ALT_TARGET=
+
+# list any data files supplied with your submission
+#
+# Example: DATA= curds whey
+#
+DATA=
+
+# Buffer size 128KB
+#
+BUF= 131072
+
+# File creation mode
+#
+MODE= 0600
+
+
+#################
+# build the entry
+#################
+
+all: data ${TARGET}
+ @${TRUE}
+
+.PHONY: all alt data everything clean clobber
+
+# how to compile
+#
+${PROG}: ${PROG}.c
+ ${CC} ${CFLAGS} ${PROG}.c -o $@ ${LDFLAGS}
+
+eh: ${PROG}
+ ${RM} -f $@
+ ${CP} -f -v ${PROG} $@
+
+# alternative executable
+#
+alt: data ${ALT_TARGET}
+ @${TRUE}
+
+${PROG}.alt: ${PROG}.alt.c
+ ${CC} ${CFLAGS} ${PROG}.alt.c -o $@ ${LDFLAGS}
+
+# data files
+#
+data: ${DATA}
+ @${TRUE}
+
+# both all and alt
+#
+everything: all alt
+ @${TRUE}
+
+
+###############
+# utility rules
+###############
+#
+clean:
+ ${RM} -f ${OBJ} ${ALT_OBJ}
+
+clobber: clean
+ ${RM} -f ${TARGET} ${ALT_TARGET}
+ ${RM} -rf *.dSYM
+
+
+######################################
+# optional include of 1337 hacker rulz
+######################################
+
+-include 1337.mk ../1337.mk ../../1337.mk
diff --git a/2024/howe/README.md b/2024/howe/README.md
new file mode 100644
index 000000000..02d3391ad
--- /dev/null
+++ b/2024/howe/README.md
@@ -0,0 +1,129 @@
+## To build:
+
+```
+ make all
+```
+
+
+### Bugs and (Mis)features:
+
+The current status of this entry is:
+
+> **STATUS: known bug - please help us fix**
+
+For more detailed information see [2024/howe in bugs.html](../../bugs.html#2024_howe).
+
+
+## Try:
+
+```
+ ./try.sh
+```
+
+
+## Judges' remarks:
+
+This is not your grandmother's 👵 `emacs(1)` 🤓, nor is it as limited as `ed(1)`, eh (🇨🇦)?
+
+The source (and of this program) has fun with an UTF-8 conforming accent, in a manor of speaking 😉.
+
+> TL;DR - to exit type **Q** or press **CTRL+C**.
+
+As mentioned in in the [COMMANDS section of prog.html](prog.html#commands), try these commands:
+
+```
+ | Key cmd | Action |
+ |----------|------------------------------------------------------------|
+ | h j k l | Left, down, up, right cursor movement |
+ | H J K L | Page top, page down, page up, page bottom |
+ | b w | Word left, word right |
+ | | | Goto column (count) of physical line |
+ | /ERE | Find first occurrence of ERE pattern after the cursor |
+ | n | Find next occurrence of ERE |
+ | G | Goto line (count) number; 1G top of file, G bottom |
+ | \ | Toggle text selection |
+ | d motion | Delete text selection or region given by motion |
+ | y motion | Yank (copy) text selection or region given by motion |
+ | P | Paste last deleted or yanked text region before the cursor |
+ | i | Insert text mode before cursor, ESC or CTRL+C ends insert |
+ | u | Toggle undo of last edit |
+ | x | Delete character after the cursor, i.e., dl |
+ | W | Write buffer to file |
+ | Q | Quit |
+ | CTRL+C | Quit |
+```
+
+**NOTE**: Any other key will redraw the screen.
+
+
+## Author's remarks:
+
+
+### Building
+
+Simply type `make` to build. There are two macros that can be customised:
+
+* `BUF` to set the buffer size; default 128KB.
+
+* `MODE` to set the file creation mode; default 0600.
+
+
+### What's Interesting
+
+* This is an update with bug fixes of a previous IOCCC winner, with permission of the author.
+
+* This entry requires Curses. Some Linux might require NCurses built with wide character support, `-lncursesw`.
+
+* The source is UTF-8. When are `é` `ë` `ê` `è` not same as `e`?
+
+* The documentation is found in [prog.html](prog.html).
+
+* `prog` can view its own source.
+
+* A regression test suite is available on demand. The test suite requires `tic(1)` to build the specialised test terminal entry.
+
+* Original unobfuscated more fully featured source available (search/replace, pipe-filter selection, markers, insert file, edit buffer grows, literal character input, multi undo/redo).
+
+* The `iocccsize(1)` tool only counts bytes, not characters, i.e,. UTF-8 multibyte characters such that some characters cost 2, 3, or 4 bytes, thus penalising UTF-8 entries.
+
+ > UTF-8 demands equal rights and respect as real characters! The dominance of slim ASCII must end! We are the UTF-8 People's Front for Freedom, Equality, and Brotherhood (oh that's been used already) - We are the UTF-8 Countless Tourist Defence Farce for One Voice, One World, One Character Set.
+
+Furthermore:
+
+* Refactor page framing to address original issue of scrolling and paging up/down when the file contains long lines.
+
+* CTRL+C will exit insert mode as with `vi(1)`; CTRL+C will also quit, unlike `vi(1)`, for those who cannot find `Q`.
+
+* Add extended regular expression forward search with buffer wrap-around.
+
+* Add text selection with delete (cut), yank (copy), and put (paste).
+
+* Add delete (cut), yank (copy) with motion.
+
+* Replace start/end of line with goto-column command.
+
+* Add counts for motion commands, delete, and put.
+
+* Replace top/end of file with goto-line command.
+
+* Fix word left to behave like `vi(1)`.
+
+* Add basic UTF-8 support.
+
+
+### Updates
+
+
+
diff --git a/2024/howe/index.html b/2024/howe/index.html
new file mode 100644
index 000000000..4982b3daa
--- /dev/null
+++ b/2024/howe/index.html
@@ -0,0 +1,666 @@
+
+
+
+
+
+
+
+
+
+
+
+
+2024/howe - Nice accent eh-ward
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
| Key cmd | Action |
+ |----------|------------------------------------------------------------|
+ | h j k l | Left, down, up, right cursor movement |
+ | H J K L | Page top, page down, page up, page bottom |
+ | b w | Word left, word right |
+ | | | Goto column (count) of physical line |
+ | /ERE | Find first occurrence of ERE pattern after the cursor |
+ | n | Find next occurrence of ERE |
+ | G | Goto line (count) number; 1G top of file, G bottom |
+ | \ | Toggle text selection |
+ | d motion | Delete text selection or region given by motion |
+ | y motion | Yank (copy) text selection or region given by motion |
+ | P | Paste last deleted or yanked text region before the cursor |
+ | i | Insert text mode before cursor, ESC or CTRL+C ends insert |
+ | u | Toggle undo of last edit |
+ | x | Delete character after the cursor, i.e., dl |
+ | W | Write buffer to file |
+ | Q | Quit |
+ | CTRL+C | Quit |
+
NOTE: Any other key will redraw the screen.
+
Author’s remarks:
+
Building
+
Simply type make to build. There are two macros that can be customised:
+
+
BUF to set the buffer size; default 128KB.
+
MODE to set the file creation mode; default 0600.
+
+
What’s Interesting
+
+
This is an update with bug fixes of a previous IOCCC winner, with permission of the author.
+
This entry requires Curses. Some Linux might require NCurses built with wide character support, -lncursesw.
A regression test suite is available on demand. The test suite requires tic(1) to build the specialised test terminal entry.
+
Original unobfuscated more fully featured source available (search/replace, pipe-filter selection, markers, insert file, edit buffer grows, literal character input, multi undo/redo).
+
The iocccsize(1) tool only counts bytes, not characters, i.e,. UTF-8 multibyte characters such that some characters cost 2, 3, or 4 bytes, thus penalising UTF-8 entries.
+
+
UTF-8 demands equal rights and respect as real characters! The dominance of slim ASCII must end! We are the UTF-8 People’s Front for Freedom, Equality, and Brotherhood (oh that’s been used already) - We are the UTF-8 Countless Tourist Defence Farce for One Voice, One World, One Character Set.
+
+
+
Furthermore:
+
+
Refactor page framing to address original issue of scrolling and paging up/down when the file contains long lines.
+
CTRL+C will exit insert mode as with vi(1); CTRL+C will also quit, unlike vi(1), for those who cannot find Q.
+
Add extended regular expression forward search with buffer wrap-around.
+
Add text selection with delete (cut), yank (copy), and put (paste).
+
Add delete (cut), yank (copy) with motion.
+
Replace start/end of line with goto-column command.
A minimalist version of vi(1). It is an example of the “Buffer Gap” method outlined in the The Craft Of Text Editing used by many Emacs style editors. (Yep I mixed vi and emacs in the same paragraph; I’m going to hell for that one.)
+
Create or read a text file to edit. Text files consists of lines of printable UTF-8 text, tabs, or newline characters. A physical line can be of arbitrary length and is delimited by either a newline or the end of file. Tab stops are every eight columns. The behaviour of non-printable characters may vary depending on the implementation of the Curses library, stty(1) settings, or terminal emulator.
+
COMMANDS
+
The commands are similar, but not the same as vi(1). Most commands can be prefixed by a repeat count, eg. 5w, 123G, 2dw (d2w), or 2d3w (d6w). Motion commands, optionally prefixed by a count, are those that move the cursor without modifying the buffer. Some edit commands can be followed by a motion.
+
h j k l Left, down, up, right cursor movement.
+H J K L Page top, page down, page up, page bottom.
+b w Word left, word right.
+| Goto column (count) of physical line.
+/ERE Find first occurrence of ERE pattern after the cursor.
+n Find next occurrence of ERE.
+G Goto line (count) number; 1G top of file, G bottom.
+ Toggle text selection.
+d motion Delete text selection or region given by motion.
+y motion Yank (copy) text selection or region given by motion.
+P Paste last deleted or yanked text region before the cursor.
+i Insert text mode before the cursor, ESC or CTRL+C ends insert.
+u Toggle undo of last edit.
+x Delete character after the cursor, i.e., dl
+W Write buffer to file.
+Q Quit.
+CTRL+C Quit.
+
Any other key will redraw the screen.
+
ENVIRONMENT
+
+
TERM : The user’s terminal type. If the environmental variable TERM is not set or insufficient then terminate with non-zero exit status.
+
TERMINFO : The absolute file path of a terminfo database. See terminfo(5).
+
+
EXIT STATUS
+
+
0 Success
+
1 Insufficient capabilities for TERM.
+
2 Read file error
+
+
SEE ALSO
+
ed(1), ex(1), vi(1)
+
NOTES
+
+
Has UTF-8 support.
+
+
Loads UTF-8 files as-is and internally remains UTF-8 (not converteed to wchar_t).
The display of long physical lines that are larger than the terminal screen is untested, so considered undefined.
+
CRLF newlines (DOS, Windows) and other non-spacing control characters are not visible. Consider converting newlines using SUS tools like awk(1) or sed(1):
+
$ sed -e’s/VM$//’ dos.txt > unix.txt
+$ sed -e’s/$/VM/’ unix.txt > dos.txt
+
^V is the default stty(1) insert literal prefix key.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/2024/howe/prog.md b/2024/howe/prog.md
new file mode 100644
index 000000000..55c945f1c
--- /dev/null
+++ b/2024/howe/prog.md
@@ -0,0 +1,91 @@
+# eh(1)
+
+
+## NAME
+
+ eh - Edit Here - vi(1) the good parts version
+
+
+## SYNOPSIS
+
+ eh filename
+
+
+## DESCRIPTION
+
+A minimalist version of `vi(1)`. It is an example of the "Buffer Gap" method outlined in the [The Craft Of Text Editing](http://www.finseth.com/craft/) used by many Emacs style editors. (Yep I mixed `vi` and `emacs` in the same paragraph; I'm going to hell for that one.)
+
+Create or read a text file to edit. Text files consists of lines of printable UTF-8 text, tabs, or newline characters. A physical line can be of arbitrary length and is delimited by either a newline or the end of file. Tab stops are every eight columns. The behaviour of non-printable characters may vary depending on the implementation of the Curses library, `stty(1)` settings, or terminal emulator.
+
+
+## COMMANDS
+
+The commands are similar, but not the same as `vi(1)`. Most commands can be prefixed by a repeat count, eg. `5w`, `123G`, `2dw` (`d2w`), or `2d3w` (`d6w`). Motion commands, optionally prefixed by a count, are those that move the cursor without modifying the buffer. Some edit commands can be followed by a motion.
+
+ h j k l Left, down, up, right cursor movement.
+ H J K L Page top, page down, page up, page bottom.
+ b w Word left, word right.
+ | Goto column (count) of physical line.
+ /ERE Find first occurrence of ERE pattern after the cursor.
+ n Find next occurrence of ERE.
+ G Goto line (count) number; **1G** top of file, **G** bottom.
+ \ Toggle text selection.
+ d motion Delete text selection or region given by motion.
+ y motion Yank (copy) text selection or region given by motion.
+ P Paste last deleted or yanked text region before the cursor.
+ i Insert text mode before the cursor, **ESC** or **CTRL+C** ends insert.
+ u Toggle undo of last edit.
+ x Delete character after the cursor, i.e., **dl**
+ W Write buffer to file.
+ Q Quit.
+ CTRL+C Quit.
+
+ Any other key will redraw the screen.
+
+
+## ENVIRONMENT
+
+* `TERM` : The user's terminal type. If the environmental variable `TERM` is not set or insufficient then terminate with non-zero exit status.
+
+* `TERMINFO` : The absolute file path of a `terminfo` database. See `terminfo(5)`.
+
+
+## EXIT STATUS
+
+- 0 Success
+- 1 Insufficient capabilities for `TERM`.
+- 2 Read file error
+
+
+## SEE ALSO
+
+`ed(1)`, `ex(1)`, `vi(1)`
+
+
+## NOTES
+
+* Has UTF-8 support.
+
+ - Loads UTF-8 files as-is and internally remains UTF-8 (not converteed to `wchar_t`).
+ - UTF-8 input will likely require an intl. keyboard or enabling [US Intl. dead-key keyboard](https://en.wikipedia.org/wiki/QWERTY#US-International) support. See also [Unicode Input](https://en.wikipedia.org/wiki/Unicode_input).
+
+* The display of long physical lines that are larger than the terminal screen is untested, so considered undefined.
+
+* CRLF newlines (DOS, Windows) and other non-spacing control characters are not visible. Consider converting newlines using SUS tools like `awk(1)` or `sed(1)`:
+
+ $ sed -e's/^V^M$//' dos.txt > unix.txt
+ $ sed -e's/$/^V^M/' unix.txt > dos.txt
+
+ `^V` is the default `stty(1)` insert literal prefix key.
+
+
+## REFERENCES
+
+* Craig A. Finseth, "Craft Of Text Editing", 1999
+
+
+* Single Unix Specification, Curses issue 7
+
+
+* Single Unix Specification, Base Specification 2018, vi(1)
+
diff --git a/2024/howe/prog.orig.c b/2024/howe/prog.orig.c
new file mode 100644
index 000000000..f8f632121
--- /dev/null
+++ b/2024/howe/prog.orig.c
@@ -0,0 +1,428 @@
+int y,x,z,w;
+char *f,*q;
+char b[BUF],*g = b,*h,*c,*ó,*ò;
+long o,ö,u,v,l,Q,d = -1;
+regex_t e;
+void
+T(int);
+long
+P(char *s)
+{
+ return s-b - (s < h ? 0 : h-g);
+}
+char *
+Z(long m)
+{
+ return b+m + (b+m < g ? 0 : h-g);
+}
+int
+S(int a)
+{
+ return 1+(a > 193)+(a > 223)+(a > 239);
+}
+long
+E(long m)
+{
+ return m + (m < P(c) ? S(*Z(m)) : 0);
+}
+long
+D(long m)
+{
+ while (0 < m and (192 bitand *Z(--m)) == 128)
+ ;
+ return m;
+}
+void
+Û()
+{
+ char *p = ó;
+ ó = g;
+ g = p;
+ p = ò;
+ ò = h;
+ h = p;
+ v = ö;
+ ö = o;
+ o = v;
+ v = o+1;
+}
+void
+V(long m)
+{
+ char *p = Z(m);
+ while (p < g)
+ *--h = *--g;
+ while (h < p)
+ *g++ = *h++;
+ ó = g;
+ ò = h;
+ ö = o;
+}
+int
+G(char *s,int a)
+{
+ wint_t t;
+ mbtowc(&t,s,4);
+ return t == '\t' ? (8-((a bitand 7))) : (a = wcwidth(t)) < 1 ? 1 : a;
+}
+long
+O(long m)
+{
+ while (0 < m and *Z(--m) not_eq '\n')
+ ;
+ return (m+1) * (0 < m);
+}
+long
+A(long m,int a,int n)
+{
+ char *p;
+ while (a < n and (p = Z(m)) < c and *p not_eq '\n') {
+ a += G(p,a);
+ m = E(m);
+ }
+ return m;
+}
+long
+_(long m,long n)
+{
+ char *p;
+ int a = 0;
+ long i = m;
+ while (m < n and (p = Z(m = E(m))) < c) {
+ a += G(p,a);
+ if (COLS <= a) {
+ i = m;
+ a = 0;
+ }
+ }
+ return i;
+}
+long
+M(long m)
+{
+ long s = O(m);
+ long t = _(s,m);
+ if (s < t)
+ return _(s,t-1);
+ return _(O(s-1),s-1);
+}
+long
+N(long m)
+{
+ return E(A(m,x,COLS-1));
+}
+void
+C()
+{
+ printw("%*s",COLS-getcurx(stdscr),"");
+}
+void
+Y()
+{
+ char *p;
+ int i,j;
+ long s,t,n = P(c);
+ if (o < u)
+ u = _(O(o),o);
+ else if (v <= o and o < N(v))
+ u = N(u);
+ else if (v <= o) {
+ v = u;
+ for (u = o,i = LINES-1 - (o == n); 0 < --i and v < u; ) {
+ u = M(u);
+ }
+ if (u < v)
+ u = v;
+ }
+ erase();
+ standout();
+ printw("%s %ldB",f,o);
+ C();
+ if (d < 0)
+ s = t = d;
+ else if (o < d) {
+ s = o;
+ t = d;
+ }
+ else {
+ s = d;
+ t = o;
+ }
+ for (i = 1,j = 0,v = u; standend(),i < LINES; ) {
+ if (o == v) {
+ y = i;
+ x = j;
+ }
+ if (c <= (p = Z(v)))
+ break;
+ if (s <= v and v < t)
+ standout();
+ int t = S(*p);
+ mvaddnstr(i,j,p,t);
+ v += t;
+ j += G(p,j);
+ if (*p == '\n' or COLS <= j) {
+ j = 0;
+ i++;
+ }
+ }
+ if (i++ < LINES) {
+ standout();
+ mvaddstr(i,0,"^D");
+ }
+ move(y,x);
+ refresh();
+}
+void
+🔥()
+{
+ clear();
+ z = 0;
+}
+void
+H()
+{
+ o = D(o);
+}
+void
+L()
+{
+ o = E(o);
+}
+void
+K()
+{
+ o = A(M(o),0,x);
+}
+void
+J()
+{
+ o = A(N(o),0,x);
+}
+void
+a()
+{
+ o = A(O(o),0,z-1);
+ z = 0;
+}
+void
+B()
+{
+ while (0 < o and isspace(*Z(o-1)))
+ --o;
+ while (0 < o and not isspace(*Z(o-1)))
+ --o;
+}
+void
+Ê()
+{
+ o = u;
+}
+void
+Ë()
+{
+ o = _(O(v-1),v-1);
+}
+void
+É()
+{
+ int i;
+ for (o = v,i = 1; i < y; i++)
+ o = N(o);
+ o = A(o,0,x);
+ u = o < P(c) ? v : u;
+ for (v = o; i < LINES; i++)
+ v = N(v);
+}
+void
+È()
+{
+ for (int i = LINES-1; 0 < i--; )
+ o = M(o);
+ for (u = o; 1 < y--; )
+ u = M(u);
+ o = A(o,0,x);
+}
+void
+W()
+{
+ long n = P(c);
+ while (o < n and not isspace(*Z(o)))
+ ++o;
+ while (o < n and isspace(*Z(o)))
+ ++o;
+}
+void
+ө()
+{
+ long n = P(c);
+ for (o = n * (not z); o < n and 1 < z; z--) {
+ o = A(o,0,999);
+ o += o < n;
+ }
+ u = n;
+}
+void
+I()
+{
+ int a,t;
+ long n = P(c);
+ V(o);
+ while ((a =getch()) not_eq 3 and a not_eq 27) {
+ t = S(a);
+ if (a == 8) {
+ while (n < P(c) and (192 bitand *--g) == 128)
+ ;
+ }
+ else if (g+t < h) {
+ do {
+ *g++ = a;
+ v++;
+ } while (0 < --t and (a = getch()));
+ }
+ o = P(h);
+ Y();
+ }
+ z = 0;
+}
+void
+Ô()
+{
+ long i = d;
+ if (d < 0) {
+ i = o;
+ T(14);
+ }
+ if (i < o) {
+ i xor_eq o;
+ o xor_eq i;
+ i xor_eq o;
+ }
+ free(q);
+ V(o);
+ q = strndup(h,Q = i-o);
+ d = -1;
+}
+void
+X()
+{
+ Ô();
+ h += Q;
+ o = P(h);
+}
+void
+Ó()
+{
+ ungetch('l');
+ X();
+}
+void
+Í()
+{
+ if (q) {
+ V(o);
+ memcpy(g,q,Q);
+ g += Q;
+ o = P(h);
+ v = o+1;
+ }
+}
+void
+κ()
+{
+ int i;
+ V(0);
+ write(i = creat(f,MODE),h,c-h);
+ close(i);
+}
+void
+Ф()
+{
+ f = 0;
+}
+void
+F()
+{
+ regmatch_t p[1];
+ V(P(c));
+ *g = 0;
+ if (o+l < P(c) and not regexec(&e,Z(o+l),1,p,REG_NOTBOL))
+ o += l + p->rm_so;
+ else if (not regexec(&e,b,1,p,0))
+ o = p->rm_so;
+ else {
+ l = 0;
+ return;
+ }
+ l = p->rm_eo - p->rm_so + w;
+}
+void
+Ñ()
+{
+ echo();
+ standout();
+ mvaddch(0,0,'/');
+ C();
+ mvgetnstr(0,1,g,h-g);
+ regfree(&e);
+ if (regcomp(&e,g,REG_EXTENDED bitor REG_NEWLINE))
+ beep();
+ else {
+ w = g[0] == '$' and not g[1];
+ F();
+ }
+ z = 0;
+}
+void
+Â()
+{
+ d = d < 0 ? o : -1;
+}
+char Ќ[] = "hjklbwHJKL|G/nixydPu\\WQ\003";
+void (*Κ[])(void) = {
+ H,J,K,L,B,W,
+ Ê,É,È,Ë,
+ a,ө,
+ Ñ,F,
+ I,Ó,
+ Ô,X,Í,Û,
+ Â,κ,Ф,Ф,
+ 🔥
+};
+void
+T(int m)
+{
+ int j = z,a;
+ for (z = 0; isdigit(a =getch()); )
+ z = z * 10 + a - '0';
+ z = j and z ? j*z : z ? z : j;
+ for (j = 0; Ќ[j] and a not_eq Ќ[j]; j++)
+ ;
+ if (j < m) {
+ do (*Κ[j])(); while (1 < z--);
+ }
+ z = 0;
+}
+int
+main(int i,char **j)
+{
+ setlocale(LC_ALL,"");
+ if (not initscr())
+ return 1;
+ raw();
+ h = c = b + BUF;
+ if (0 < (i = open(f = *++j,0))) {
+ g += read(i,b,c-b);
+ close(i);
+ if (g < b or c <= g)
+ return 2;
+ }
+ v = 1;
+ while (f) {
+ noecho();
+ Y();
+ T(99);
+ }
+ endwin();
+ return 0;
+}
diff --git a/2024/howe/try.sh b/2024/howe/try.sh
new file mode 100755
index 000000000..fac305f82
--- /dev/null
+++ b/2024/howe/try.sh
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+#
+# try.sh - demonstrate 2024/howe
+
+# 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
+
+read -r -n 1 -p "Press any key to form foo: "
+echo 1>&2
+rm -f foo
+cp prog.c foo
+echo 1>&2
+
+echo 'NOTE: To update file, press W' 1>&2
+echo 'NOTE: To exit, press Q or press CTRL+C' 1>&2
+echo 1>&2
+read -r -n 1 -p "Press any key to run: ./eh foo "
+echo 1>&2
+./eh foo
+echo 1>&2
diff --git a/2024/index.html b/2024/index.html
new file mode 100644
index 000000000..d34c50435
--- /dev/null
+++ b/2024/index.html
@@ -0,0 +1,856 @@
+
+
+
+
+
+
+
+
+
+
+
+
+2024 - The 28th IOCCC
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Check out the index.html web pages for each winning entry. They have
+most of the information you need to compile and run the winning program.
+Take a look at the winning source code and try to figure out how it works.
+You might also want to check out the author’s remarks for even more details.
This year marked the 40th anniversary of the IOCCC.
+The IOCCC28 opened submissions from 2025-03-05 23:19:17.131107 UTC to 2025-06-05
+04:03:02.010099 UTC after a 4 year pause.
+
A significant portion of those 4 years was an effort by a number of people,
+with over 6168+ commits, to rebuild the Official IOCCC website
+in what became known as the Great Fork Merge.
Reduce the administrative effort required by the IOCCC Judges to run the contest, and
+
Minimize the time between when the winners of the IOCCC are selected and when the source is made available.
+
+
On the last point, for IOCCC28 the Judging started on 2025-06-05 04:03:02.010099 UTC and then the winners were selected by the IOCCC Judges on 2025-07-07 20:05:07.000000 UTC:
+
+
Winners were announced during a live the Our Favorite Universe YouTube Channel that started on 2025-08-02 18:00:00.000000 UTC
No longer will there be many months between when the winners are
+announced and their source code is made available. For IOCCC28
+the time was less than 2 hours. :-)
+
Increased submission quantity and quality
+
The submissions to IOCCC28 were remarkable when compared with previous contests, in both the
+increased quantity and quality of the submissions. As a result the judging process for IOCCC28
+was more challenging and required greater effort. Thankfully due to the above mentioned improvements,
+the judging process took only 33 days. Under the previous system it would have taken much longer!
+
One thing that began to emerge after we exits the early rounds of judging and entered the middle rounds
+of judging was that we were very likely to have more winning entries than in previous contests.
+Even so, the final rounds of judging required more rounds and tool longer than in any previous IOCCC.
+
At the end of the final round of the final rounds of judging, we had a record 23 winners of IOCCC28,
+eclipsing the record of 15 winners!
+
While we suspect that the 4 year gap between IOCCC27 and IOCCC28 allowed people extra
+time to improve their submissions, we also believe that people submitting to the IOCCC have
+adept in obfuscation and have become more skilled in the programming in the C language.
+
Code size and Rule 2
+
We were pleased to observe that while the IOCCC size limit
+increased by about 21%, we received many submissions that were well under the new
+Rule 2 size limit including a fair number of quality
+small and medium sized submissions. Half of the IOCCC28 winners were less than
+2/3 of the size limit, and 10 of the IOCCC28 winners were less than
+1/2 of the size limit!
+
IMPORTANT NOTE: The IOCCC size limit increase for IOCCC28
+was the first size increase in over 10 years. Given the quality of submissions we received
+that were well under the limit, we do NOT expect to change the
+Rule 2 size limit for at least another 10 years (and likely longer).
+
IMPORTANT HINT: Only 3 of 23 the IOCCC28 winners came close to the Rule 2 size limit.
+Large code size isn’t everything. :-) Those submitting to future contents should
+take a careful note of that fact.
+
Rules and Guidelines for this contest
+
Here are the final versions of the IOCCC rules and guidelines that were in effect for this contest:
The IOCCC Judges realize that the IOCCC rules and
+the IOCCC guidelines need to be greatly improved and streamlined.
+We decided to not overhaul them for IOCCC28 so as to NOT delay the opening of the contest.
+
After the IOCCC Judges take a short IOCCC Vacation (we have been working solid
+on IOCCC28 since 2020 Dec 30), we plan to update, improve and streamline the
+IOCCC rules and the IOCCC guidelines for IOCCC29.
+Then we will address whatever bug fixes in the form of GitHub Pull Requests to both the
+IOCCC GitHub winner repo and the
+mkiocccentry toolkit repo that may be pending.
+
Once we are all caught up, we will set the opening date for IOCCC29. It is our plan
+to open IOCCC29 sometime in 2025 December.
+
Remarks on some of the winning entries
+
There were a number of remarkable winning entries for IOCCC28. We wish to call
+attention to a few of them:
This entry is a fun revisit of the theme of 2000/natori,
+only better and without using any floating point arithmetic. You are invited
+to try and understand why the constant 2551443 is common to both entries.
This entry claims to be “the world’s smallest LLM (large language
+model) inference engine”: running open-source model based on Meta’s
+LLaMA 2 with 7 billion parameters. After downloading the model via the
+2024/cable1/get_model.sh script,
+we invite you explore this ChatIOCCC tool. While not super fast,
+the tool’s output can be amusing.
+
You might wish to ask ChatIOCCC: “Why did this entry win IOCCC28?”?
+
We encourage you to read and understand the
+2024/cable1/prog.c source code. Then see
+if the ChatIOCCC tool can offer any new, or even correct insights
+into the code’s obfuscation. :-)
When you view the prog.c source code,
+notice magic numbers. This one liner packs a significant amount
+of obfuscation in only 135 bytes!
+
Try giving 10 hex digits to standard input of the program. Then try a
+different hex digits value. Then feed the MD5 hash of the
+2024/stedolan/prog.c source code and
+“C” what happens. :-)
The 2024/endoh1/try.sh will carry you on
+a journey that tests your patience as well as the patience of the C-preprocessor.
+
Building a 8x8 image requires order of 20 seconds of C-preprocessor
+time, when running 6 jobs on 4 CPU cores in parallel. Unfortunately,
+with such a tiny image, it is hard to appreciate the image being rendered.
+
So you might try building a 32x32 form of the image, invoking the
+C-preprocessor 1024 times. When using 6 jobs on 4 CPU cores in parallel,
+this might take about 5.5 minutes to complete. However, the small image
+only gives you a hint of the image being rendered.
+
If you have the time you might try building a 128x128 image, invoking
+the C-preprocessor 16384 times. With 6 jobs on 4 CPU cores in parallel,
+this will take about 1.5 hours. At this scale you might consider it
+worthwhile to render a more detailed image.
+
Using 6 jobs on 4 CPU cores in parallel, to build a 512x512 image invoking
+the C-preprocessor 262144 times over a period of about 23.5 hours, you
+will be given an image with a reasonable amount of detail to appreciate
+what is being rendered.
+
One fun aspect of the 2024/endoh1/prog.c source code
+is that when it is compiled an executed, the program outputs C code.
+That C code, call it rt.c will fail to compile! But that is OK because the C-preprocessor
+has enough work to do without bothering the C compiler. :-)
This won the “Prize in ℤ₃”, but what does that mean? Well,
+the “double-struck Z” is NOT a reference to a set of integers,
+nor is the “double-struck Z subscript 3” a reference to a ring of
+3-adic integers. Instead, it is a reference to the 3rd version of a
+certain virtual machine.
The prize, “virtual quietus”, is a virtual reference to the doom that awaits you when
+you run this code: let alone when your try to figure out how the author was able to
+encode the virtual machine in under 2.5K bytes of prog.c source code!
+
NOTE: The implementation runs without sound or mouse
+input. You will need reply on your keyboard skills. The
+2024/kurdyukov3/try.sh
+demonstration script will give you some useful keyboard hints.
Have you ever wondered would what would happen if you recursively removed
+files starting from the root directory? Are you curious what happens when
+you launch a fork bomb?
+You can safely give those and other scenarios under this virtual machine.
+
We invite you to explore the prog.c source code
+to explore this interesting virtual machine implementation. And as a bonus, a
+full-fledged C64 emulator is included!
The “Prize in yil-tas” provides a hint as to what this marvelous
+winning entry is going, provided that you are someone familiar in at
+least 3 languages (hint: One of them is C, another id English).
+
The IOCCC is honored to present this entry for your enjoyment and you ponder
+the prog.c source code.
The IOCCC has seen a number of winning entries that allow code designed to
+run on early Intel processors, however none of them emulate a processor as
+early as the Intel 4004.
+Launched in 1971, the 4004 was the core of the first commercially marketed
+microprocessor chipset.
+
The 2024/carlini/prog.c
+code runs rather slow, so patience is required to watch
+4004
+code run. This is very understandable when you realize that the
+2024/carlini/prog.c is actually
+emulating the entire
+4004 chip circuit
+by computing the output of each gate in a loop, effectively running the CPU and associated RAM/ROM chips!
+
Remarks on some of submissions that did not win
+
+
Depending on the address of a variable, as not all platforms support
+ASLR,
+as the single source of pseudo-randomness isn’t a good idea. It’s
+much better to mix in other sources of variability (e.g. time, process
+ID, etc.) so that subsequent runs will behave differently.
+
If a submission’s obfuscation strongly resembles a past IOCCC winning
+entry, and the submission’s obfuscation is mainly in the C code source,
+then the submission likely to not make it into the final rounds of judging.
+
When working with modern C compilers, it’s crucial to explicitly
+declare variable and function types. Don’t assume they’ll
+automatically default to an int.
+
Sadly, K&C-style C code does not compile well under modern C compilers.
+
A submission that only works under gcc or clang does not work as well
+as submissions that can work under either compiler.
+
Shrinking an existing open-source program to meet rule 2 size might
+be an impressive feat of code shrinking, but it might not be enough to
+make it into the final rounds of judging. Originality is key, and this
+might not be the most innovative approach.
+
If your submission relies on mathematical algorithms, be sure that the
+C code that implements the mathematics is well obfuscated.
+
Just a friendly reminder that before you upload your submissions,
+uncompress the compressed tarball into a different directory. This way,
+you can be sure you didn’t miss uploading any important files!
+
Using a lot of goto statements to make your code harder to understand
+might not help it pass the final rounds of judging.
+
+
Encouragement for those who did not win this year
+
We know many of you that submitted to the IOCCC put in a ton of effort
+into your submissions for this year’s IOCCC. We can’t just give out
+awards to everyone. That would mean taking away from the submissions
+that we think are the best and deserve to win.
+
Sometimes, a final round submission might be good enough to be a
+winning IOCCC entry, only to be beaten by a similar, but slightly better
+submission. If you think this happened with your submission, consider
+submitting an enhanced version to the next IOCCC.
+
PLEASE DO NOT give up hope! There are some submissions that have been
+submitted with revisions, multiple times before rising to the level of
+a winning IOCCC entry. You might also want to try with a different type
+of submission altogether for the next IOCCC.
+
If you’re not planning to improve and resubmit your non-winning entry
+for the next IOCCC, you’re welcome to publish it.
+
On Compiling and running winning entries
+
Some C compilers aren’t as great as they could be. If yours isn’t
+working well, you might want to try compiling with an updated version
+of clang and/or gcc instead.
+
If you encounter problems in compiling and/or running the winning entries, see the FAQ on:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/2024/kramer/.entry.json b/2024/kramer/.entry.json
new file mode 100644
index 000000000..eae88df5e
--- /dev/null
+++ b/2024/kramer/.entry.json
@@ -0,0 +1,97 @@
+{
+ "no_comment" : "mandatory comment: because comments were removed from the original JSON spec",
+ "entry_JSON_format_version" : "1.2 2024-09-25",
+ "award" : "Prize in linguistic arithmetic",
+ "year" : 2024,
+ "dir" : "kramer",
+ "entry_id" : "2024_kramer",
+ "title" : "lexicalc",
+ "abstract" : "natural language numerical calculator",
+ "author_set" : [
+ {
+ "author_handle" : "Andrew_Kramer"
+ }
+ ],
+ "manifest" : [
+ {
+ "file_path" : "prog.c",
+ "inventory_order" : 20,
+ "OK_to_edit" : true,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "entry source code"
+ },
+ {
+ "file_path" : "Makefile",
+ "inventory_order" : 30,
+ "OK_to_edit" : true,
+ "display_as" : "makefile",
+ "display_via_github" : true,
+ "entry_text" : "entry Makefile"
+ },
+ {
+ "file_path" : "prog.orig.c",
+ "inventory_order" : 50,
+ "OK_to_edit" : false,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "original source code"
+ },
+ {
+ "file_path" : "try.sh",
+ "inventory_order" : 100,
+ "OK_to_edit" : true,
+ "display_as" : "shellscript",
+ "display_via_github" : true,
+ "entry_text" : "script to try entry"
+ },
+ {
+ "file_path" : "2024_kramer.tar.bz2",
+ "inventory_order" : 1415926535,
+ "OK_to_edit" : false,
+ "display_as" : "tbz2",
+ "display_via_github" : false,
+ "entry_text" : "download entry tarball"
+ },
+ {
+ "file_path" : ".entry.json",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : true,
+ "display_as" : "json",
+ "display_via_github" : true,
+ "entry_text" : "entry summary and manifest in JSON"
+ },
+ {
+ "file_path" : ".gitignore",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : true,
+ "display_as" : "gitignore",
+ "display_via_github" : true,
+ "entry_text" : "list of files that should not be committed under git"
+ },
+ {
+ "file_path" : ".path",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : false,
+ "display_as" : "path",
+ "display_via_github" : false,
+ "entry_text" : "directory path from top level directory"
+ },
+ {
+ "file_path" : "README.md",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : true,
+ "display_as" : "markdown",
+ "display_via_github" : true,
+ "entry_text" : "markdown source for this web page"
+ },
+ {
+ "file_path" : "index.html",
+ "inventory_order" : 4294967295,
+ "OK_to_edit" : false,
+ "display_as" : "html",
+ "display_via_github" : false,
+ "entry_text" : "this web page"
+ }
+ ]
+}
diff --git a/2024/kramer/.gitignore b/2024/kramer/.gitignore
new file mode 100644
index 000000000..cb588a635
--- /dev/null
+++ b/2024/kramer/.gitignore
@@ -0,0 +1,7 @@
+#
+# sort with: ../../bin/sgi.sh
+*~
+*.dSYM
+*.o
+.DS_Store
+.*.swp
diff --git a/2024/kramer/.path b/2024/kramer/.path
new file mode 100644
index 000000000..5d36c8d7c
--- /dev/null
+++ b/2024/kramer/.path
@@ -0,0 +1 @@
+2024/kramer
diff --git a/2024/kramer/2024_kramer.tar.bz2 b/2024/kramer/2024_kramer.tar.bz2
new file mode 100644
index 000000000..705da44dd
Binary files /dev/null and b/2024/kramer/2024_kramer.tar.bz2 differ
diff --git a/2024/kramer/Makefile b/2024/kramer/Makefile
new file mode 100644
index 000000000..696ef60ae
--- /dev/null
+++ b/2024/kramer/Makefile
@@ -0,0 +1,212 @@
+#!/usr/bin/env make
+#
+# 2024/kramer
+
+#############################
+# shell used by this Makefile
+#############################
+
+SHELL= bash
+
+
+#######################
+# common tool locations
+#######################
+
+include ../../var.mk
+
+
+#####################
+# C compiler settings
+#####################
+
+# Common C compiler warnings to silence
+#
+# Example: CSILENCE= -Wno-poison-system-directories
+#
+CSILENCE= -Wno-bitwise-op-parentheses -Wno-unused-parameter -Wno-parentheses
+
+# Attempt to silence unknown warning options
+#
+CUNKNOWN= -Wno-unknown-warning-option
+
+# Common C compiler warning flags
+#
+# NOTE: The addition of -pedantic to CWARN is a challenge that
+# You may wish to avoid if it proves too problematic.
+# There is NO penalty for removing -pedantic from CWARN.
+#
+CWARN= -Wall -Wextra -pedantic ${CSILENCE} ${CUNKNOWN}
+
+# Compiler standard
+#
+CSTD= -std=gnu17
+
+# Compiler bit architecture
+#
+# Example for 32-bitness: ARCH= -m32
+# Example for 64-bitness: ARCH= -m64
+#
+# NOTE: Normally one should NOT specify a specific architecture.
+#
+ARCH=
+
+# Defines that are needed to compile
+#
+# Example: -Dfoo -Dbar=baz
+#
+CDEFINE=
+
+# Include files that are needed to compile
+#
+# Example: CINCLUDE= -include stdio.h
+#
+CINCLUDE=
+
+# Other flags to pass to the C compiler
+#
+# Example: COTHER= -fno-math-errno
+#
+COTHER=
+
+# Optimization
+#
+# NOTE: Feel free to change the level of compiler optimization.
+# The "-O3" is just a friendly default you might wish to try.
+#
+# Example: OPT= -O0 -g
+#
+OPT= -O3
+
+# Default flags for ANSI C compilation
+#
+CFLAGS= ${CSTD} ${CWARN} ${ARCH} ${CDEFINE} ${CINCLUDE} ${COTHER} ${OPT}
+
+# Libraries needed to build
+#
+# Example: LDFLAGS= -lncurses -lm
+#
+LDFLAGS=
+
+# C compiler to use
+#
+# NOTE: The IOCCC Judges recommend you leave CC as just "cc"
+# and NOT set it to clang, or gcc, or something else
+# unless you have a STRONG reason to do so.
+#
+# Setting CC to something other than "cc" makes your
+# code less portable to those who do not have your
+# particular C compiler. **hint**
+#
+# If you want to test your code with a particular C compiler,
+# use the make command line. For example:
+#
+# make all CC=clang
+# make all CC=gcc
+#
+CC= cc
+
+# Compiler add-ons or replacements for clang only
+#
+ifeq "$(findstring $(CLANG),${CC})" "$(CLANG)"
+#
+# NOTE: This code is only invoked when CC is "clang"
+# such as when you use the make command line:
+#
+# make all CC=clang
+#
+CSILENCE+= -Wno-bitwise-op-parentheses -Wno-comma -Wno-missing-prototypes \
+ -Wno-missing-variable-declarations -Wno-padded \
+ -Wno-poison-system-directories -Wno-unused-parameter \
+ -Wno-misleading-indentation -Wno-unsafe-buffer-usage
+#
+CWARN+= -Weverything
+#
+endif
+
+# Specific add-ons or replacements for gcc only
+#
+ifeq "$(findstring $(GCC),${CC})" "$(GCC)"
+#
+# NOTE: This code is only invoked when CC is "gcc"
+# such as when you use the make command line:
+#
+# make all CC=gcc
+#
+CSILENCE+=
+#
+CWARN+=
+#
+endif
+
+
+###########################################
+# Special Makefile variables for this entry
+###########################################
+
+ENTRY= prog
+PROG= ${ENTRY}
+#
+OBJ= ${PROG}.o
+TARGET= ${PROG}
+#
+ALT_OBJ=
+ALT_TARGET=
+
+# list any data files supplied with your submission
+#
+# Example: DATA= curds whey
+#
+DATA=
+
+
+#################
+# build the entry
+#################
+
+all: data ${TARGET}
+ @${TRUE}
+
+.PHONY: all alt data everything clean clobber
+
+# how to compile
+#
+${PROG}: ${PROG}.c
+ ${CC} ${CFLAGS} ${PROG}.c -o $@ ${LDFLAGS}
+
+# alternative executable
+#
+alt: data ${ALT_TARGET}
+ @${TRUE}
+
+${PROG}.alt: ${PROG}.alt.c
+ ${CC} ${CFLAGS} ${PROG}.alt.c -o $@ ${LDFLAGS}
+
+# data files
+#
+data: ${DATA}
+ @${TRUE}
+
+# both all and alt
+#
+everything: all alt
+ @${TRUE}
+
+
+###############
+# utility rules
+###############
+#
+clean:
+ ${RM} -f ${OBJ} ${ALT_OBJ}
+
+clobber: clean
+ ${RM} -f ${TARGET} ${ALT_TARGET}
+ ${RM} -rf *.dSYM
+
+
+######################################
+# optional include of 1337 hacker rulz
+######################################
+
+-include 1337.mk ../1337.mk ../../1337.mk
diff --git a/2024/kramer/README.md b/2024/kramer/README.md
new file mode 100644
index 000000000..66e65a972
--- /dev/null
+++ b/2024/kramer/README.md
@@ -0,0 +1,180 @@
+## To build:
+
+```
+ make all
+```
+
+
+### Bugs and (Mis)features:
+
+The current status of this entry is:
+
+> **STATUS: known bug - please help us fix**
+
+For more detailed information see [2024/kramer in bugs.html](../../bugs.html#2024_kramer).
+
+
+## To use:
+
+```
+ ./prog phrase1 phrase2 ...
+```
+
+
+## Try:
+
+```
+ ./prog two plus one trillion five hundred seventy five million six hundred thousand sixty one
+```
+
+Or:
+
+
+```
+ ./try.sh
+```
+
+
+## Judges' remarks:
+
+Arithmetic processing with English words: naturally obfuscated for your signed 64-bit programming amusement.
+
+Enjoy!
+
+
+## Author's remarks:
+
+
+## Overview
+
+The frequent computer user may, for reasons of ergonomics, wish to minimize the distance their hands travel while completing everyday tasks. The much beloved Thinkpad TrackPoint is a wonderful example of a technology built for this purpose, allowing the user to transition seamlessly from keyboard to mouse without the need for unnecessary repositioning of the hands. (One may wonder why a mouse would be necessary at all, given the rich text-based environment provided by the terminal, but that is a separate topic.)
+
+For users who frequently switch between natural language writing and numeric calculations, the requirement to move their hands from the home-row position all the way over to the number pad represents an extreme hardship. It wastes valuable time, causes discomfort, and may lead to any number of serious health complications on a long enough time scale.
+
+To address this problem, we present a simple calculator which operates entirely on natural language! Numbers and calculations can be entered in plain English as the program's argument vector, without the need to move away from the home-row. The program will handle the rest. Inputs of positive or negative values into the trillions are supported, with internal calculations supporting an even greater precision in the range `LLONG_MIN <= n <= LLONG_MAX`. The operators "plus" (+), "minus" (-), "times" (*), "divided by" (/), and "mod" (%) are implemented. Standard order-of-operations is respected. All calculations are performed using whole integers.
+
+Order of operations is handled through the use of the [Shunting Yard Algorithm](https://en.wikipedia.org/wiki/Shunting_yard_algorithm), which uses stacks and queues to convert the infix input array into postfix (RPN) notation to be solved. (Shout out to my boy Edsger Dijkstra for that one, sick algorithm dude!)
+
+
+## Examples
+
+```
+$ ./prog one plus one
+2
+
+$ ./prog one thousand three hundred and thirty seven
+1337
+
+$ ./prog two times three plus five
+11
+
+$ ./prog seventeen times negative two
+-34
+
+$ ./prog one hundred and two divided by six plus nine
+26
+
+$ ./prog nineteen plus one hundred mod seven
+21
+
+$ ./a.out negative three hundred and seventy two trillion thirty six billion eight hundred and fifty four million seven hundred and seventy five thousand eight hundred and eight minus nine thousand two hundred and twenty three times one trillion times one thousand
+-9223372036854775808
+```
+
+## Obfuscation
+
+Obfuscation is greatly enhanced by the use of a custom hashing function to identify each natural language term. While a series of `strcmp()`'s would certainly be sufficient, including all of those human-readable words in the source would be much too obvious (not to mention that it bloats the source file, wasting valuable disk space). After much experimentation, it was determined that the following function produces a unique set of 8-bit numeric outputs for all required input terms.
+
+```c
+char hash(char *s) {
+
+ char h = 1, i = 0;
+
+ while (s[i]) {
+ h >>= 1;
+ h ^= s[i++];
+ }
+
+ return (h & 0xf) | (((i ^ s[0]) << 4) & 0xf0);
+
+}
+```
+
+This allows the program to identify each unique term without having to explicitly declare them within the source file. The complete list of valid input terms and their cooresponding hash value is listed below for reference, sorted alphabetically.
+
+```
+ 43 and
+ 90 billion
+ 8 by
+ 55 divided
+ 2 eight
+223 eighteen
+ 48 eighty
+ 56 eleven
+ 31 fifteen
+ 49 fifty
+ 40 five
+ 47 four
+238 fourteen
+ 52 forty
+242 hundred
+170 million
+137 minus
+232 mod
+110 negative
+165 nine
+111 nineteen
+130 ninety
+201 one
+ 76 plus
+106 seven
+175 seventeen
+ 65 seventy
+ 0 six
+ 78 sixteen
+103 sixty
+113 ten
+206 thirteen
+ 39 thirty
+192 thousand
+ 17 three
+ 16 times
+202 trillion
+ 45 twelve
+ 32 twenty
+121 two
+224 zero
+```
+
+To further obfuscate the code, we golf it down a bit using all the standard tricks.
+
+
+## Limitations
+
+If you compile this with nit-picky flags like `-Wall`, the compiler is likely to be very cross. >:( It will yell a bit. So... don't do that, I guess! Both `gcc` and `clang` are happy and quiet with the defaults.
+
+Inputs into the trillions are handled, but inputs of one quadrillion or above are not. During calculation, only numbers which can be represented by an `int64_t` are supported. But honestly... who needs numbers bigger than that anyway?
+
+Input terms other than those explicitly implemented are considered undefined and will produce undefined results. Many will hash to unknown values, having no effect, while others may produce collisions when hashed, causing unexpected outputs. For instance, the term `give` hashes to the number `56` which is a collision with the term `eleven`. Thus...
+
+```
+$ ./prog never gonna give you up
+11
+```
+
+We recommend simply not doing that.
+
+
+
diff --git a/2024/kramer/index.html b/2024/kramer/index.html
new file mode 100644
index 000000000..a3fb9125a
--- /dev/null
+++ b/2024/kramer/index.html
@@ -0,0 +1,700 @@
+
+
+
+
+
+
+
+
+
+
+
+
+2024/kramer - Prize in linguistic arithmetic
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
./prog two plus one trillion five hundred seventy five million six hundred thousand sixty one
+
Or:
+
./try.sh
+
Judges’ remarks:
+
Arithmetic processing with English words: naturally obfuscated for your signed 64-bit programming amusement.
+
Enjoy!
+
Author’s remarks:
+
Overview
+
The frequent computer user may, for reasons of ergonomics, wish to minimize the distance their hands travel while completing everyday tasks. The much beloved Thinkpad TrackPoint is a wonderful example of a technology built for this purpose, allowing the user to transition seamlessly from keyboard to mouse without the need for unnecessary repositioning of the hands. (One may wonder why a mouse would be necessary at all, given the rich text-based environment provided by the terminal, but that is a separate topic.)
+
For users who frequently switch between natural language writing and numeric calculations, the requirement to move their hands from the home-row position all the way over to the number pad represents an extreme hardship. It wastes valuable time, causes discomfort, and may lead to any number of serious health complications on a long enough time scale.
+
To address this problem, we present a simple calculator which operates entirely on natural language! Numbers and calculations can be entered in plain English as the program’s argument vector, without the need to move away from the home-row. The program will handle the rest. Inputs of positive or negative values into the trillions are supported, with internal calculations supporting an even greater precision in the range LLONG_MIN <= n <= LLONG_MAX. The operators “plus” (+), “minus” (-), “times” (*), “divided by” (/), and “mod” (%) are implemented. Standard order-of-operations is respected. All calculations are performed using whole integers.
+
Order of operations is handled through the use of the Shunting Yard Algorithm, which uses stacks and queues to convert the infix input array into postfix (RPN) notation to be solved. (Shout out to my boy Edsger Dijkstra for that one, sick algorithm dude!)
+
Examples
+
$ ./prog one plus one
+2
+
+$ ./prog one thousand three hundred and thirty seven
+1337
+
+$ ./prog two times three plus five
+11
+
+$ ./prog seventeen times negative two
+-34
+
+$ ./prog one hundred and two divided by six plus nine
+26
+
+$ ./prog nineteen plus one hundred mod seven
+21
+
+$ ./a.out negative three hundred and seventy two trillion thirty six billion eight hundred and fifty four million seven hundred and seventy five thousand eight hundred and eight minus nine thousand two hundred and twenty three times one trillion times one thousand
+-9223372036854775808
+
Obfuscation
+
Obfuscation is greatly enhanced by the use of a custom hashing function to identify each natural language term. While a series of strcmp()’s would certainly be sufficient, including all of those human-readable words in the source would be much too obvious (not to mention that it bloats the source file, wasting valuable disk space). After much experimentation, it was determined that the following function produces a unique set of 8-bit numeric outputs for all required input terms.
+
char hash(char*s){
+
+char h =1, i =0;
+
+while(s[i]){
+ h >>=1;
+ h ^= s[i++];
+}
+
+return(h &0xf)|(((i ^ s[0])<<4)&0xf0);
+
+}
+
This allows the program to identify each unique term without having to explicitly declare them within the source file. The complete list of valid input terms and their cooresponding hash value is listed below for reference, sorted alphabetically.
+
43 and
+ 90 billion
+ 8 by
+ 55 divided
+ 2 eight
+223 eighteen
+ 48 eighty
+ 56 eleven
+ 31 fifteen
+ 49 fifty
+ 40 five
+ 47 four
+238 fourteen
+ 52 forty
+242 hundred
+170 million
+137 minus
+232 mod
+110 negative
+165 nine
+111 nineteen
+130 ninety
+201 one
+ 76 plus
+106 seven
+175 seventeen
+ 65 seventy
+ 0 six
+ 78 sixteen
+103 sixty
+113 ten
+206 thirteen
+ 39 thirty
+192 thousand
+ 17 three
+ 16 times
+202 trillion
+ 45 twelve
+ 32 twenty
+121 two
+224 zero
+
To further obfuscate the code, we golf it down a bit using all the standard tricks.
+
Limitations
+
If you compile this with nit-picky flags like -Wall, the compiler is likely to be very cross. >:( It will yell a bit. So… don’t do that, I guess! Both gcc and clang are happy and quiet with the defaults.
+
Inputs into the trillions are handled, but inputs of one quadrillion or above are not. During calculation, only numbers which can be represented by an int64_t are supported. But honestly… who needs numbers bigger than that anyway?
+
Input terms other than those explicitly implemented are considered undefined and will produce undefined results. Many will hash to unknown values, having no effect, while others may produce collisions when hashed, causing unexpected outputs. For instance, the term give hashes to the number 56 which is a collision with the term eleven. Thus…
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/2024/kramer/prog.c b/2024/kramer/prog.c
new file mode 100644
index 000000000..c22c22fca
--- /dev/null
+++ b/2024/kramer/prog.c
@@ -0,0 +1,32 @@
+
+#define A 1000
+#define B long int
+#include
+#define C(a,b) if(l(*v)==a){n+=b;}
+#define D(a,b) C(a,0;m+=n*o*b;n=0;)
+#define E(a) m+=n*o;f[i++]=j(m,1);o=1;m=n=0;a
+#define F(a) for(;g^A&&a>>2<=f[g].d>>2;)f[i++]=f[g++];f[--g]=j(a,0);
+
+
+typedef struct{int b;B d;}e;e f[A];B m,n,o,r,s,h,i,g=
+A;e j(B q,int x){return(e){.b=x,.d=q};}int l(char*u){
+for(r=/*-------------------------------------*/1,s=0;
+u[s];r/* nine thousand and one */>>=1,r
+^=u[ s/*-------------------------------------*/++] );
+return(r&15)|(s^*u)<<4&240;}int main(int z,char **v){
+for(o=1;*++v;){C(16,0;E(F(5)))D(90,A*A*A)C(106,7)C(52
+,40)C(/* 7 */223/* 8 */,18/* 9 */)C(/* + */31,15)
+C(165,/*----*/9)C/*----*/(1*/*----*/121/*----*/,2)C(+
+40,5)C(113,10)C(56,11)C(111,19)C(45,12)C(238,14)C(0,6
+)C(47,/* 4 */4)C/* 5 */(1*/* 6 */206/* - */,13)C(
+49,50)/*----*/C(+/*----*/55,/*----*/0;E/*----*/(F(6))
+)C(130,90)C(175,17)C(2,8)C(17,3)C(103,60)D(202,A*A*A*
+A)D(1*/* 1 */192/* 2 */,A)/* 3 */C(+/* x */65,70)
+C(137,/*----*/0;E/*----*/(F(/*----*/2))/*----*/)C(110
+,0;o=-1)C(39,30)C(201,1)C(242,n*99)C(78,16)D(170,A*A)
+C(76,0/* 0 */;E(/* = */F(1/* % */)))/* / */C(232,
+0;E(F(/*----*/7))/*----*/)C(/*----*/48,/*----*/+80)C(
++32,20)}E()for(;g^A;f[i++]=f[g++])continue;for(;h^i;)
+if(f[h].b)f[--g]=f[h++];else n=f[g++].d,o=f[g++].d,m=
+f[h++].d,f[--g]=m^1?m^2?m^5?m^6?j(o%n,1):j(o/n,1):j(n
+*o,1*1*1):j(o-n,1):j(n+o,+1);printf("%ld\n",f[g].d);}
diff --git a/2024/kramer/prog.orig.c b/2024/kramer/prog.orig.c
new file mode 100644
index 000000000..c22c22fca
--- /dev/null
+++ b/2024/kramer/prog.orig.c
@@ -0,0 +1,32 @@
+
+#define A 1000
+#define B long int
+#include
+#define C(a,b) if(l(*v)==a){n+=b;}
+#define D(a,b) C(a,0;m+=n*o*b;n=0;)
+#define E(a) m+=n*o;f[i++]=j(m,1);o=1;m=n=0;a
+#define F(a) for(;g^A&&a>>2<=f[g].d>>2;)f[i++]=f[g++];f[--g]=j(a,0);
+
+
+typedef struct{int b;B d;}e;e f[A];B m,n,o,r,s,h,i,g=
+A;e j(B q,int x){return(e){.b=x,.d=q};}int l(char*u){
+for(r=/*-------------------------------------*/1,s=0;
+u[s];r/* nine thousand and one */>>=1,r
+^=u[ s/*-------------------------------------*/++] );
+return(r&15)|(s^*u)<<4&240;}int main(int z,char **v){
+for(o=1;*++v;){C(16,0;E(F(5)))D(90,A*A*A)C(106,7)C(52
+,40)C(/* 7 */223/* 8 */,18/* 9 */)C(/* + */31,15)
+C(165,/*----*/9)C/*----*/(1*/*----*/121/*----*/,2)C(+
+40,5)C(113,10)C(56,11)C(111,19)C(45,12)C(238,14)C(0,6
+)C(47,/* 4 */4)C/* 5 */(1*/* 6 */206/* - */,13)C(
+49,50)/*----*/C(+/*----*/55,/*----*/0;E/*----*/(F(6))
+)C(130,90)C(175,17)C(2,8)C(17,3)C(103,60)D(202,A*A*A*
+A)D(1*/* 1 */192/* 2 */,A)/* 3 */C(+/* x */65,70)
+C(137,/*----*/0;E/*----*/(F(/*----*/2))/*----*/)C(110
+,0;o=-1)C(39,30)C(201,1)C(242,n*99)C(78,16)D(170,A*A)
+C(76,0/* 0 */;E(/* = */F(1/* % */)))/* / */C(232,
+0;E(F(/*----*/7))/*----*/)C(/*----*/48,/*----*/+80)C(
++32,20)}E()for(;g^A;f[i++]=f[g++])continue;for(;h^i;)
+if(f[h].b)f[--g]=f[h++];else n=f[g++].d,o=f[g++].d,m=
+f[h++].d,f[--g]=m^1?m^2?m^5?m^6?j(o%n,1):j(o/n,1):j(n
+*o,1*1*1):j(o-n,1):j(n+o,+1);printf("%ld\n",f[g].d);}
diff --git a/2024/kramer/try.sh b/2024/kramer/try.sh
new file mode 100755
index 000000000..ad467175f
--- /dev/null
+++ b/2024/kramer/try.sh
@@ -0,0 +1,40 @@
+#!/usr/bin/env bash
+#
+# try.sh - demonstrate 2024/kramer
+
+# 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.
+#
+[[ -z "$CC" ]] && CC="cc"
+
+# make sure the program and the alt program have been built
+#
+make CC="$CC" everything >/dev/null || exit 1
+
+# clear the screen
+#
+clear
+
+# try the program
+#
+read -r -n 1 -p "Press any key to run: ./prog two: "
+echo 1>&2
+echo 1>&2
+./prog two
+echo 1>&2
+
+# try the program again
+#
+read -r -n 1 -p "Press any key to run: ./prog two plus two minus one: "
+echo 1>&2
+echo 1>&2
+./prog two plus two minus one
+echo 1>&2
+
+# try the program yet again
+#
+read -r -n 1 -p "Press any key to run: ./prog eight trillion divided by fourteen million and seven plus one hundred fifty six: "
+echo 1>&2
+echo 1>&2
+./prog eight trillion divided by fourteen million and seven plus one hundred fifty six
+echo 1>&2
diff --git a/2024/kurdyukov1/.entry.json b/2024/kurdyukov1/.entry.json
new file mode 100644
index 000000000..f9c700ae9
--- /dev/null
+++ b/2024/kurdyukov1/.entry.json
@@ -0,0 +1,97 @@
+{
+ "no_comment" : "mandatory comment: because comments were removed from the original JSON spec",
+ "entry_JSON_format_version" : "1.2 2024-09-25",
+ "award" : "Prize in phased periodicity",
+ "year" : 2024,
+ "dir" : "kurdyukov1",
+ "entry_id" : "2024_kurdyukov1",
+ "title" : "moon",
+ "abstract" : "phase of the Moon",
+ "author_set" : [
+ {
+ "author_handle" : "Ilya_Kurdyukov"
+ }
+ ],
+ "manifest" : [
+ {
+ "file_path" : "prog.c",
+ "inventory_order" : 20,
+ "OK_to_edit" : true,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "entry source code"
+ },
+ {
+ "file_path" : "Makefile",
+ "inventory_order" : 30,
+ "OK_to_edit" : true,
+ "display_as" : "makefile",
+ "display_via_github" : true,
+ "entry_text" : "entry Makefile"
+ },
+ {
+ "file_path" : "prog.orig.c",
+ "inventory_order" : 50,
+ "OK_to_edit" : false,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "original source code"
+ },
+ {
+ "file_path" : "try.sh",
+ "inventory_order" : 100,
+ "OK_to_edit" : true,
+ "display_as" : "shellscript",
+ "display_via_github" : true,
+ "entry_text" : "script to try entry"
+ },
+ {
+ "file_path" : "2024_kurdyukov1.tar.bz2",
+ "inventory_order" : 1415926535,
+ "OK_to_edit" : false,
+ "display_as" : "tbz2",
+ "display_via_github" : false,
+ "entry_text" : "download entry tarball"
+ },
+ {
+ "file_path" : ".entry.json",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : true,
+ "display_as" : "json",
+ "display_via_github" : true,
+ "entry_text" : "entry summary and manifest in JSON"
+ },
+ {
+ "file_path" : ".gitignore",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : true,
+ "display_as" : "gitignore",
+ "display_via_github" : true,
+ "entry_text" : "list of files that should not be committed under git"
+ },
+ {
+ "file_path" : ".path",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : false,
+ "display_as" : "path",
+ "display_via_github" : false,
+ "entry_text" : "directory path from top level directory"
+ },
+ {
+ "file_path" : "README.md",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : true,
+ "display_as" : "markdown",
+ "display_via_github" : true,
+ "entry_text" : "markdown source for this web page"
+ },
+ {
+ "file_path" : "index.html",
+ "inventory_order" : 4294967295,
+ "OK_to_edit" : false,
+ "display_as" : "html",
+ "display_via_github" : false,
+ "entry_text" : "this web page"
+ }
+ ]
+}
diff --git a/2024/kurdyukov1/.gitignore b/2024/kurdyukov1/.gitignore
new file mode 100644
index 000000000..cb588a635
--- /dev/null
+++ b/2024/kurdyukov1/.gitignore
@@ -0,0 +1,7 @@
+#
+# sort with: ../../bin/sgi.sh
+*~
+*.dSYM
+*.o
+.DS_Store
+.*.swp
diff --git a/2024/kurdyukov1/.path b/2024/kurdyukov1/.path
new file mode 100644
index 000000000..7ed37367d
--- /dev/null
+++ b/2024/kurdyukov1/.path
@@ -0,0 +1 @@
+2024/kurdyukov1
diff --git a/2024/kurdyukov1/2024_kurdyukov1.tar.bz2 b/2024/kurdyukov1/2024_kurdyukov1.tar.bz2
new file mode 100644
index 000000000..3dbc94f7c
Binary files /dev/null and b/2024/kurdyukov1/2024_kurdyukov1.tar.bz2 differ
diff --git a/2024/kurdyukov1/Makefile b/2024/kurdyukov1/Makefile
new file mode 100644
index 000000000..eda6a0f8b
--- /dev/null
+++ b/2024/kurdyukov1/Makefile
@@ -0,0 +1,210 @@
+#!/usr/bin/env make
+#
+# 2024/kurdyukov1
+
+#############################
+# shell used by this Makefile
+#############################
+
+SHELL= bash
+
+
+#######################
+# common tool locations
+#######################
+
+include ../../var.mk
+
+
+#####################
+# C compiler settings
+#####################
+
+# Common C compiler warnings to silence
+#
+# Example: CSILENCE= -Wno-poison-system-directories
+#
+CSILENCE= -Wno-implicit-int -Wno-strict-prototypes
+
+# Attempt to silence unknown warning options
+#
+CUNKNOWN= -Wno-unknown-warning-option
+
+# Common C compiler warning flags
+#
+# NOTE: The addition of -pedantic to CWARN is a challenge that
+# You may wish to avoid if it proves too problematic.
+# There is NO penalty for removing -pedantic from CWARN.
+#
+CWARN= -Wall -Wextra -pedantic ${CSILENCE} ${CUNKNOWN}
+
+# Compiler standard
+#
+CSTD= -std=gnu17
+
+# Compiler bit architecture
+#
+# Example for 32-bitness: ARCH= -m32
+# Example for 64-bitness: ARCH= -m64
+#
+# NOTE: Normally one should NOT specify a specific architecture.
+#
+ARCH=
+
+# Defines that are needed to compile
+#
+# Example: -Dfoo -Dbar=baz
+#
+CDEFINE=
+
+# Include files that are needed to compile
+#
+# Example: CINCLUDE= -include stdio.h
+#
+CINCLUDE=
+
+# Other flags to pass to the C compiler
+#
+# Example: COTHER= -fno-math-errno
+#
+COTHER=
+
+# Optimization
+#
+# NOTE: Feel free to change the level of compiler optimization.
+# The "-O3" is just a friendly default you might wish to try.
+#
+# Example: OPT= -O0 -g
+#
+OPT= -O3
+
+# Default flags for ANSI C compilation
+#
+CFLAGS= ${CSTD} ${CWARN} ${ARCH} ${CDEFINE} ${CINCLUDE} ${COTHER} ${OPT}
+
+# Libraries needed to build
+#
+# Example: LDFLAGS= -lncurses -lm
+#
+LDFLAGS=
+
+# C compiler to use
+#
+# NOTE: The IOCCC Judges recommend you leave CC as just "cc"
+# and NOT set it to clang, or gcc, or something else
+# unless you have a STRONG reason to do so.
+#
+# Setting CC to something other than "cc" makes your
+# code less portable to those who do not have your
+# particular C compiler. **hint**
+#
+# If you want to test your code with a particular C compiler,
+# use the make command line. For example:
+#
+# make all CC=clang
+# make all CC=gcc
+#
+CC= cc
+
+# Compiler add-ons or replacements for clang only
+#
+ifeq "$(findstring $(CLANG),${CC})" "$(CLANG)"
+#
+# NOTE: This code is only invoked when CC is "clang"
+# such as when you use the make command line:
+#
+# make all CC=clang
+#
+CSILENCE+= -Wno-comma -Wno-missing-variable-declarations \
+ -Wno-poison-system-directories -Wno-shorten-64-to-32
+#
+CWARN+= -Weverything
+#
+endif
+
+# Specific add-ons or replacements for gcc only
+#
+ifeq "$(findstring $(GCC),${CC})" "$(GCC)"
+#
+# NOTE: This code is only invoked when CC is "gcc"
+# such as when you use the make command line:
+#
+# make all CC=gcc
+#
+CSILENCE+=
+#
+CWARN+=
+#
+endif
+
+
+###########################################
+# Special Makefile variables for this entry
+###########################################
+
+ENTRY= prog
+PROG= ${ENTRY}
+#
+OBJ= ${PROG}.o
+TARGET= ${PROG}
+#
+ALT_OBJ=
+ALT_TARGET=
+
+# list any data files supplied with your submission
+#
+# Example: DATA= curds whey
+#
+DATA=
+
+
+#################
+# build the entry
+#################
+
+all: data ${TARGET}
+ @${TRUE}
+
+.PHONY: all alt data everything clean clobber
+
+# how to compile
+#
+${PROG}: ${PROG}.c
+ ${CC} ${CFLAGS} ${PROG}.c -o $@ ${LDFLAGS}
+
+# alternative executable
+#
+alt: data ${ALT_TARGET}
+ @${TRUE}
+
+${PROG}.alt: ${PROG}.alt.c
+ ${CC} ${CFLAGS} ${PROG}.alt.c -o $@ ${LDFLAGS}
+
+# data files
+#
+data: ${DATA}
+ @${TRUE}
+
+# both all and alt
+#
+everything: all alt
+ @${TRUE}
+
+
+###############
+# utility rules
+###############
+#
+clean:
+ ${RM} -f ${OBJ} ${ALT_OBJ}
+
+clobber: clean
+ ${RM} -f ${TARGET} ${ALT_TARGET}
+ ${RM} -rf *.dSYM
+
+
+######################################
+# optional include of 1337 hacker rulz
+######################################
+
+-include 1337.mk ../1337.mk ../../1337.mk
diff --git a/2024/kurdyukov1/README.md b/2024/kurdyukov1/README.md
new file mode 100644
index 000000000..e9d653ede
--- /dev/null
+++ b/2024/kurdyukov1/README.md
@@ -0,0 +1,53 @@
+## To build:
+
+```
+ make all
+```
+
+## To use:
+
+```
+ ./prog
+```
+
+
+## Try:
+
+```
+ ./try.sh
+```
+
+
+## Judges' remarks:
+
+Comparing this entry to [2000/natori](https://ioccc.org/2000/natori), which does something similar, is quite instructive.
+This entry does not use floating point, and the only common magic number is 2551443 (what does it mean?).
+How is this entry able to achieve a similar result?
+
+## Author's remarks:
+
+
+### Moon Phase
+
+This code draws the current moon phase to the console. So if you're a lycanthrope, you can monitor the phase of the moon.
+
+#### Customization
+
+1. It shows a view from the northern hemisphere, to see from the southern replace `=a*(`. Can't show a view near the equator.
+
+2. The code assumes that your terminal color is dark and the text color is bright. If not, you can change `"#."` characters in the source code to suit your case.
+
+
+
diff --git a/2024/kurdyukov1/index.html b/2024/kurdyukov1/index.html
new file mode 100644
index 000000000..e6aa0d050
--- /dev/null
+++ b/2024/kurdyukov1/index.html
@@ -0,0 +1,610 @@
+
+
+
+
+
+
+
+
+
+
+
+
+2024/kurdyukov1 - Prize in phased periodicity
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Comparing this entry to 2000/natori, which does something similar, is quite instructive.
+This entry does not use floating point, and the only common magic number is 2551443 (what does it mean?).
+How is this entry able to achieve a similar result?
+
Author’s remarks:
+
Moon Phase
+
This code draws the current moon phase to the console. So if you’re a lycanthrope, you can monitor the phase of the moon.
+
Customization
+
+
It shows a view from the northern hemisphere, to see from the southern replace <a*(~ with >=a*(. Can’t show a view near the equator.
+
The code assumes that your terminal color is dark and the text color is bright. If not, you can change "#." characters in the source code to suit your case.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/2024/kurdyukov1/prog.c b/2024/kurdyukov1/prog.c
new file mode 100644
index 000000000..adc103798
--- /dev/null
+++ b/2024/kurdyukov1/prog.c
@@ -0,0 +1,16 @@
+#include
+#include
+
+ a,b=44,x,
+ y,z;main() {!a
+ ?a=2551443,x= -b
+ ,y=2-b,z=((time (
+ 0)-592531)%a<<9)/ a
+ :putchar(++x>=a?x =
+ -b,y+=4,10:x<0?x= x
+ *x+y*y> 8)
+ ^z>>8]),y> b?0
+ :main();}
+
diff --git a/2024/kurdyukov1/prog.orig.c b/2024/kurdyukov1/prog.orig.c
new file mode 100644
index 000000000..adc103798
--- /dev/null
+++ b/2024/kurdyukov1/prog.orig.c
@@ -0,0 +1,16 @@
+#include
+#include
+
+ a,b=44,x,
+ y,z;main() {!a
+ ?a=2551443,x= -b
+ ,y=2-b,z=((time (
+ 0)-592531)%a<<9)/ a
+ :putchar(++x>=a?x =
+ -b,y+=4,10:x<0?x= x
+ *x+y*y> 8)
+ ^z>>8]),y> b?0
+ :main();}
+
diff --git a/2024/kurdyukov1/try.sh b/2024/kurdyukov1/try.sh
new file mode 100755
index 000000000..7aefd4dd4
--- /dev/null
+++ b/2024/kurdyukov1/try.sh
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+#
+# try.sh - demonstrate 2024/kurdyukov1
+
+# 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.
+#
+[[ -z "$CC" ]] && CC="cc"
+
+# make sure the program has been built
+#
+make CC="$CC" all >/dev/null || exit 1
+
+# clear the screen
+#
+clear
+
+# try the program
+#
+read -r -n 1 -p "Press any key to run: ./prog: "
+echo 1>&2
+echo 1>&2
+./prog
+echo 1>&2
diff --git a/2024/kurdyukov2/.entry.json b/2024/kurdyukov2/.entry.json
new file mode 100644
index 000000000..d43282585
--- /dev/null
+++ b/2024/kurdyukov2/.entry.json
@@ -0,0 +1,161 @@
+{
+ "no_comment" : "mandatory comment: because comments were removed from the original JSON spec",
+ "entry_JSON_format_version" : "1.2 2024-09-25",
+ "award" : "Prize in art restoration",
+ "year" : 2024,
+ "dir" : "kurdyukov2",
+ "entry_id" : "2024_kurdyukov2",
+ "title" : "jpegqs",
+ "abstract" : "JPEG artifact removal",
+ "author_set" : [
+ {
+ "author_handle" : "Ilya_Kurdyukov"
+ }
+ ],
+ "manifest" : [
+ {
+ "file_path" : "prog.c",
+ "inventory_order" : 20,
+ "OK_to_edit" : true,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "entry source code"
+ },
+ {
+ "file_path" : "Makefile",
+ "inventory_order" : 30,
+ "OK_to_edit" : true,
+ "display_as" : "makefile",
+ "display_via_github" : true,
+ "entry_text" : "entry Makefile"
+ },
+ {
+ "file_path" : "prog.alt.c",
+ "inventory_order" : 40,
+ "OK_to_edit" : true,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "alternate source code"
+ },
+ {
+ "file_path" : "prog.orig.c",
+ "inventory_order" : 50,
+ "OK_to_edit" : false,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "original source code"
+ },
+ {
+ "file_path" : "diff-histeq.png",
+ "inventory_order" : 100,
+ "OK_to_edit" : true,
+ "display_as" : "image",
+ "display_via_github" : true,
+ "entry_text" : "quality24.jpg to restored.jpg difference"
+ },
+ {
+ "file_path" : "gradient.png",
+ "inventory_order" : 100,
+ "OK_to_edit" : true,
+ "display_as" : "image",
+ "display_via_github" : true,
+ "entry_text" : "original gradient image"
+ },
+ {
+ "file_path" : "input.jpg",
+ "inventory_order" : 100,
+ "OK_to_edit" : true,
+ "display_as" : "image",
+ "display_via_github" : true,
+ "entry_text" : "image with quality less than 100"
+ },
+ {
+ "file_path" : "input2.jpg",
+ "inventory_order" : 100,
+ "OK_to_edit" : true,
+ "display_as" : "image",
+ "display_via_github" : true,
+ "entry_text" : "icon image"
+ },
+ {
+ "file_path" : "quality24.png",
+ "inventory_order" : 100,
+ "OK_to_edit" : true,
+ "display_as" : "image",
+ "display_via_github" : true,
+ "entry_text" : "color gradiant image with quality less than 100"
+ },
+ {
+ "file_path" : "restored.png",
+ "inventory_order" : 100,
+ "OK_to_edit" : true,
+ "display_as" : "image",
+ "display_via_github" : true,
+ "entry_text" : "restored quality24.png gradiant image"
+ },
+ {
+ "file_path" : "try.sh",
+ "inventory_order" : 100,
+ "OK_to_edit" : true,
+ "display_as" : "shellscript",
+ "display_via_github" : true,
+ "entry_text" : "script to try entry"
+ },
+ {
+ "file_path" : "prog.nomain.c",
+ "inventory_order" : 200,
+ "OK_to_edit" : true,
+ "display_as" : "c",
+ "display_via_github" : true,
+ "entry_text" : "source where main comes from jpegtran"
+ },
+ {
+ "file_path" : "2024_kurdyukov2.tar.bz2",
+ "inventory_order" : 1415926535,
+ "OK_to_edit" : false,
+ "display_as" : "tbz2",
+ "display_via_github" : false,
+ "entry_text" : "download entry tarball"
+ },
+ {
+ "file_path" : ".entry.json",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : true,
+ "display_as" : "json",
+ "display_via_github" : true,
+ "entry_text" : "entry summary and manifest in JSON"
+ },
+ {
+ "file_path" : ".gitignore",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : true,
+ "display_as" : "gitignore",
+ "display_via_github" : true,
+ "entry_text" : "list of files that should not be committed under git"
+ },
+ {
+ "file_path" : ".path",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : false,
+ "display_as" : "path",
+ "display_via_github" : false,
+ "entry_text" : "directory path from top level directory"
+ },
+ {
+ "file_path" : "README.md",
+ "inventory_order" : 4000000000,
+ "OK_to_edit" : true,
+ "display_as" : "markdown",
+ "display_via_github" : true,
+ "entry_text" : "markdown source for this web page"
+ },
+ {
+ "file_path" : "index.html",
+ "inventory_order" : 4294967295,
+ "OK_to_edit" : false,
+ "display_as" : "html",
+ "display_via_github" : false,
+ "entry_text" : "this web page"
+ }
+ ]
+}
diff --git a/2024/kurdyukov2/.gitignore b/2024/kurdyukov2/.gitignore
new file mode 100644
index 000000000..354b8c53c
--- /dev/null
+++ b/2024/kurdyukov2/.gitignore
@@ -0,0 +1,2 @@
+output2.jpg
+output.jpg
diff --git a/2024/kurdyukov2/.path b/2024/kurdyukov2/.path
new file mode 100644
index 000000000..4191b54eb
--- /dev/null
+++ b/2024/kurdyukov2/.path
@@ -0,0 +1 @@
+2024/kurdyukov2
diff --git a/2024/kurdyukov2/2024_kurdyukov2.tar.bz2 b/2024/kurdyukov2/2024_kurdyukov2.tar.bz2
new file mode 100644
index 000000000..39d5b5fa4
Binary files /dev/null and b/2024/kurdyukov2/2024_kurdyukov2.tar.bz2 differ
diff --git a/2024/kurdyukov2/Makefile b/2024/kurdyukov2/Makefile
new file mode 100644
index 000000000..4c701c9e0
--- /dev/null
+++ b/2024/kurdyukov2/Makefile
@@ -0,0 +1,213 @@
+#!/usr/bin/env make
+#
+# 2024/kurdyukov2
+
+#############################
+# shell used by this Makefile
+#############################
+
+SHELL= bash
+
+
+#######################
+# common tool locations
+#######################
+
+include ../../var.mk
+
+
+#####################
+# C compiler settings
+#####################
+
+# Common C compiler warnings to silence
+#
+# Example: CSILENCE= -Wno-poison-system-directories
+#
+CSILENCE= -Wno-strict-prototypes -Wno-misleading-indentation
+
+# Attempt to silence unknown warning options
+#
+CUNKNOWN= -Wno-unknown-warning-option
+
+# Common C compiler warning flags
+#
+# NOTE: The addition of -pedantic to CWARN is a challenge that
+# You may wish to avoid if it proves too problematic.
+# There is NO penalty for removing -pedantic from CWARN.
+#
+CWARN= -Wall -Wextra -pedantic ${CSILENCE} ${CUNKNOWN}
+
+# Compiler standard
+#
+CSTD= -std=c99
+
+# Compiler bit architecture
+#
+# Example for 32-bitness: ARCH= -m32
+# Example for 64-bitness: ARCH= -m64
+#
+# NOTE: Normally one should NOT specify a specific architecture.
+#
+ARCH=
+
+# Defines that are needed to compile
+#
+# Example: -Dfoo -Dbar=baz
+#
+CDEFINE=
+
+# Include files that are needed to compile
+#
+# Example: CINCLUDE= -include stdio.h
+#
+CINCLUDE= -I ${HOMEBREW_PREFIX}/include -I /usr/local/include -I /opt/local/include
+
+# Other flags to pass to the C compiler
+#
+# Example: COTHER= -fno-math-errno
+#
+COTHER=
+
+# Optimization
+#
+# NOTE: Feel free to change the level of compiler optimization.
+# The "-O3" is just a friendly default you might wish to try.
+#
+# Example: OPT= -O0 -g
+#
+OPT= -O3
+
+# Default flags for ANSI C compilation
+#
+CFLAGS= ${CSTD} ${CWARN} ${ARCH} ${CDEFINE} ${CINCLUDE} ${COTHER} ${OPT}
+
+# Libraries needed to build
+#
+# Example: LDFLAGS= -lncurses -lm
+#
+LDFLAGS= -L ${HOMEBREW_PREFIX}/lib -L /usr/local/lib -ljpeg -lm
+
+# C compiler to use
+#
+# NOTE: The IOCCC Judges recommend you leave CC as just "cc"
+# and NOT set it to clang, or gcc, or something else
+# unless you have a STRONG reason to do so.
+#
+# Setting CC to something other than "cc" makes your
+# code less portable to those who do not have your
+# particular C compiler. **hint**
+#
+# If you want to test your code with a particular C compiler,
+# use the make command line. For example:
+#
+# make all CC=clang
+# make all CC=gcc
+#
+CC= cc
+
+# Compiler add-ons or replacements for clang only
+#
+ifeq "$(findstring $(CLANG),${CC})" "$(CLANG)"
+#
+# NOTE: This code is only invoked when CC is "clang"
+# such as when you use the make command line:
+#
+# make all CC=clang
+#
+CSILENCE+= -Wno-comma -Wno-float-conversion -Wno-implicit-int-conversion \
+ -Wno-missing-include-dirs -Wno-padded -Wno-poison-system-directories \
+ -Wno-shadow -Wno-sign-conversion -Wno-strict-prototypes \
+ -Wno-implicit-int-float-conversion -Wno-unsafe-buffer-usage
+#
+CWARN+= -Weverything
+#
+endif
+
+# Specific add-ons or replacements for gcc only
+#
+ifeq "$(findstring $(GCC),${CC})" "$(GCC)"
+#
+# NOTE: This code is only invoked when CC is "gcc"
+# such as when you use the make command line:
+#
+# make all CC=gcc
+#
+CSILENCE+=
+#
+CWARN+=
+#
+endif
+
+
+###########################################
+# Special Makefile variables for this entry
+###########################################
+
+ENTRY= prog
+PROG= ${ENTRY}
+#
+OBJ= ${PROG}.o
+TARGET= ${PROG}
+#
+ALT_OBJ= ${PROG}.alt.o
+ALT_TARGET= ${PROG}.alt
+
+# list any data files supplied with your submission
+#
+# Example: DATA= curds whey
+#
+DATA=
+
+
+#################
+# build the entry
+#################
+
+all: data ${TARGET}
+ @${TRUE}
+
+.PHONY: all alt data everything clean clobber
+
+# how to compile
+#
+${PROG}: ${PROG}.c
+ ${CC} ${CFLAGS} ${PROG}.c -o $@ ${LDFLAGS}
+
+# alternative executable
+#
+alt: data ${ALT_TARGET}
+ @${TRUE}
+
+${PROG}.alt: ${PROG}.alt.c
+ ${CC} ${CFLAGS} ${PROG}.alt.c -o $@ ${LDFLAGS}
+
+# data files
+#
+data: ${DATA}
+ @${TRUE}
+
+# both all and alt
+#
+everything: all alt
+ @${TRUE}
+
+
+###############
+# utility rules
+###############
+#
+clean:
+ ${RM} -f ${OBJ} ${ALT_OBJ}
+
+clobber: clean
+ ${RM} -f ${TARGET} ${ALT_TARGET}
+ ${RM} -rf *.dSYM
+ ${RM} -f output.jpg output2.jpg
+
+
+######################################
+# optional include of 1337 hacker rulz
+######################################
+
+-include 1337.mk ../1337.mk ../../1337.mk
diff --git a/2024/kurdyukov2/README.md b/2024/kurdyukov2/README.md
new file mode 100644
index 000000000..2488ab80a
--- /dev/null
+++ b/2024/kurdyukov2/README.md
@@ -0,0 +1,93 @@
+## To build:
+
+```
+ make all
+```
+
+
+## To use:
+
+```
+ ./prog < input.jpg > output.jpg
+ # where the quality of input.jpg is less than 100
+```
+
+
+## Try:
+
+Using your favorite image viewing tool, look at `gradient.png` (the original),
+`quality24.jpg`, and `restored.jpg`. The difference is noticeable but subtle.
+To see it in detail, observe `diff-histeq.png`.
+
+```
+ ./try.sh
+```
+
+
+## Alternate code:
+
+If you have the `jpegint.h` include file from the **libjpeg** package,
+then you will be able to compile the alternate code.
+
+
+### Alternate build:
+
+```
+ make alt
+```
+
+**NOTE**: The above requires the `jpegint.h` include file.
+
+
+### Alternate use:
+
+```
+ ./prog.alt < input.jpg > output.jpg
+ # where the quality of input.jpg is less than 100
+```
+
+
+## Judges' remarks:
+
+We were able to guess the meaning of some magic numbers. Can you?
+
+
+## Author's remarks:
+
+
+### JPEG artifact removal
+
+This program removes compression artifacts from JPEG images using values from quantization tables. After completing its work, the program saves the image in a another JPEG file, but as saved with 100% quality (so output file is larger).
+
+
+### Notes
+
+1. The lost precision of the DCT coefficient values cannot be gotten out of nowhere. It's an attempt to find values within possible ranges (defined by the quantization table), which will allow to produce smoother-looking image.
+
+2. If the image is saved several times with different quantization tables, the artifacts cannot be reduced, since the true range of possible coefficient values isn't known. If you save with one quality (say 50%) and then with 100%, this code will do nothing.
+
+3. Don't expect great results from images saved with extremely low quality (less than 25%). May look blurry.
+
+4. I written the code with respect of bits per sample set by libjpeg includes, but doesn't test on something different than common 8 bits.
+
+
+### Alternative versions
+
+- `prog.alt.c` uses **libjpeg** internals, which are the inverse of a DCT function that may run faster. Works with many *libjpeg* distributions.
+
+- I reduced the code even more, by a hijacking `main()` with file I/O from the `jpegtran` utility that comes with *libjpeg*. You can see this version in `prog.nomain.c`. As a useful side effect, you can use command line options comes from this tool, like: `./prog -optimize -outfile output.jpg input.jpg`. But for that you must build the program with *libjpeg* sources.
+
+
+
diff --git a/2024/kurdyukov2/diff-histeq.png b/2024/kurdyukov2/diff-histeq.png
new file mode 100644
index 000000000..8115cd9d1
Binary files /dev/null and b/2024/kurdyukov2/diff-histeq.png differ
diff --git a/2024/kurdyukov2/gradient.png b/2024/kurdyukov2/gradient.png
new file mode 100644
index 000000000..a17b0f919
Binary files /dev/null and b/2024/kurdyukov2/gradient.png differ
diff --git a/2024/kurdyukov2/index.html b/2024/kurdyukov2/index.html
new file mode 100644
index 000000000..6ef52b7ca
--- /dev/null
+++ b/2024/kurdyukov2/index.html
@@ -0,0 +1,636 @@
+
+
+
+
+
+
+
+
+
+
+
+
+2024/kurdyukov2 - Prize in art restoration
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
./prog < input.jpg > output.jpg
+ # where the quality of input.jpg is less than 100
+
Try:
+
Using your favorite image viewing tool, look at gradient.png (the original),
+quality24.jpg, and restored.jpg. The difference is noticeable but subtle.
+To see it in detail, observe diff-histeq.png.
+
./try.sh
+
Alternate code:
+
If you have the jpegint.h include file from the libjpeg package,
+then you will be able to compile the alternate code.
+
Alternate build:
+
make alt
+
NOTE: The above requires the jpegint.h include file.
+
Alternate use:
+
./prog.alt < input.jpg > output.jpg
+ # where the quality of input.jpg is less than 100
+
Judges’ remarks:
+
We were able to guess the meaning of some magic numbers. Can you?
+
Author’s remarks:
+
JPEG artifact removal
+
This program removes compression artifacts from JPEG images using values from quantization tables. After completing its work, the program saves the image in a another JPEG file, but as saved with 100% quality (so output file is larger).
+
Notes
+
+
The lost precision of the DCT coefficient values cannot be gotten out of nowhere. It’s an attempt to find values within possible ranges (defined by the quantization table), which will allow to produce smoother-looking image.
+
If the image is saved several times with different quantization tables, the artifacts cannot be reduced, since the true range of possible coefficient values isn’t known. If you save with one quality (say 50%) and then with 100%, this code will do nothing.
+
Don’t expect great results from images saved with extremely low quality (less than 25%). May look blurry.
+
I written the code with respect of bits per sample set by libjpeg includes, but doesn’t test on something different than common 8 bits.
+
+
Alternative versions
+
+
prog.alt.c uses libjpeg internals, which are the inverse of a DCT function that may run faster. Works with many libjpeg distributions.
+
I reduced the code even more, by a hijacking main() with file I/O from the jpegtran utility that comes with libjpeg. You can see this version in prog.nomain.c. As a useful side effect, you can use command line options comes from this tool, like: ./prog -optimize -outfile output.jpg input.jpg. But for that you must build the program with libjpeg sources.
This above needs the X11 development environment installed.
+
See the
+FAQ on “X11”
+for more information on how to compile and run using X11.
+
Try:
+
./try.sh
+
Alternate code:
+
While the main code is based on X11, the alternative is to use SDL2 instead.
+
Alternate build:
+
make alt
+
This above needs the SDL2 development environment installed.
+
See the
+FAQ on “SDL2”
+for more information on how to compile and run using SDL2.
+
Alternate try:
+
./try.alt.sh
+
Judges’ remarks:
+
The prize, “virtual quietus”, is a virtual reference to the doom that
+awaits the execution .. of this code, let alone when your try to figure
+out how the author was able to encode the virtual machine in under 2.5K
+bytes of prog.c source code!
+
You may face your doom in several ways. With the make all and
+try.sh you may try the X11 way into your doom. With make alt
+and try.alt.shSDL2 your way into your doom.
+
While you may meet your doom in the twisty maze of passages while running
+the program, can you reach an understanding of the maze of twisty passages
+in the prog.c source code?
+
NOTE: The implementation does without sound or mouse
+input. You will need reply on your keyboard skills. The
+2024/kurdyukov3/try.sh
+demonstration script will give you some useful keyboard hints.
+
Author’s remarks:
+
Obfuscated Gaming Virtual Machine
+
In short, it is a virtual machine capable of running Doom 1/2 at full speed on modern office computers.
+It can also be used as a sandbox for C programs and for creating ports for other games.
+
See detailed story below build/run instructions.
+
Build instructions
+
The instructions have been tested on a specific OS, on others they may differ in detail.
+
X11 (Ubuntu):
+
cc -O3 prog.c -o prog -X11
+
+
Needs “libx11-dev” package installed.
+
+
WinAPI (Msys64):
+
cc -O3 prog.win.c -o prog.exe -s -lGDI32 -lwinmm
+
SDL1.2 (Ubuntu):
+
cc -O3 -I/usr/include/SDL prog.sdl.c -o prog -lSDL
+
+
Needs “libsdl1.2-dev” package installed.
+
+
SDL2 (Ubuntu):
+
cc -O3 -I/usr/include/SDL2 prog.sdl.c -o prog -lSDL2
+
+
Needs “libsdl2-dev” package installed.
+
+
Running the game
+
./prog doomp.bin
+
+
You will need the game resources, which are a .wad archive that you can grab from Doom 1/2 or its expansion packs. Doom has a shareware version available for free, you can download doom1.wad from it here. The resource file must be in the current directory when you run the VM.
+
doomp.bin is a compressed binary of doom.bin, more on that below.
+
+
Features missing
+
+
No sound/music.
+
No network game.
+
No mouse capture.
+
+
Doom port hacks
+
You can add command line arguments after the program binary. For example:
+
./prog doomp.bin -timedemo demo1
+
This will launch performance testing.
+
+
-1, -2, -3, -4, -5: Pixel size multiplier (default is 3), the original game runs at 320x200, which is too small for modern displays. Affects performance (scaling is done at the game side).
+
-upper : with this option, the game tries to use uppercase names for .wad/.svg files if no lowercase name is found. Useful for Linux, so you don’t need to rename files copied from DOS version.
+
-ridx N : the red color index in a pixel (0 to 3), may need adjustment if default doesn’t work for you.
+
+
The story
+
An idea
+
The idea of such a VM came up when I was looking at the winning works of the IOCCC competition, in which there are many games, in these games the game data is stored in separate files. So I think that in fact the complexity of games is not limited by the code size limit, as long as the game logic can be stored in a data file and then read and interpreted.
+
I also noticed emulators of virtual machines of a real CPU’s and abstract Turing machines.
+
The idea for porting this game comes from tech fans who play this game on smartwatches, fridges, digital cameras, and even a scientific calculator.
+
So can virtual machive limited by the IOCCC rules run Doom? Yes, this is a confirmation of that.
+
Predecessor
+
This is actually VM mark II, because I was trying to write an obfuscated abstract virtual machine, it was too slow to run games, also difficult to program (but more complex than OISC), and I/O is limited by stdin/stdout. The good part is that the source code is small at ~380 bytes and that it can easily recursively emulate itself. But it was boring, so I kept thinking about how to do it better. The programs were written in assembly language consisting of handwritten NASM macros that emit opcodes for this VM (instead of x86 ones).
+
After I decided to emulate Doom in a VM, I had a question how I would compile the game source code into the binary code of a VM that never existed. And I tried the idea of a workaround of compiling it into a 32-bit i386 binary and emulating a subset of the i386 instructions. I started writing an i386 emulator, but stopped halfway because I realized that this CISC architecture is too complex, so even if it complies with Rule 2B, it will have poor performance, and the code for graphics output and keyboard input may not even fit. After that I looked at the ARM thumb architecture, but even if it seems simpler to emulate - its instructions are too simple, and more instructions would be required compared to the same x86 code, so this option was also thrown out due to poor performance.
+
So, I went back to the predecessor and started rewriting and expanding its instruction set, but keeping it as small as possible in the amount of C code.
+
C compiler
+
After expanding the instruction set and reworking the assembler, I looked at basic C compilers that have backends for different architectures to create a backend for my own architecture. There was the Little C Compiler and the Tiny C Compiler that I knew before, of which I chose LCC because it has a parser for backends written mostly in pseudocode that is easier to work with. It is of course possible to make an LLVM backend, but creating an LLVM backend is much more complicated.
+
Choosing LCC turned out to be a good idea because I have successfully written my own backend. The downside to choosing LCC is that it is not very good at optimization, the generated code matches common compilers (like GCC) used with the -O0/-O1 switch.
+
Runtime library
+
Then I started writing implementations of common libc functions which include stuff like printf, malloc, memcpy, strcmp and so on. I wrote them in assembler because they are performance critical. It also required new code on the VM side in case of file I/O and timing functions.
+
And the final step was to add support for drawing in the window and handling keyboard events.
+
The Doom sources
+
These sources are available on github from the id Software account and have been forked many times with some improvements and fixes. But I took the original code.
+
The original source code for Doom (linux-xdoom to be exact) required some fixes to run on a 64-bit OS that doesn’t need a 32-bit VM, but I fixed that so the same code would work in both the VM and linux, for a better debugging experience. Some other bugs have also been fixed, such as maintaining compatibility with the DOS version of the game and fixing the low detail mode. Some performance-critical functions have been rewritten in assembly (same as for the DOS game).
+
I’m not implemented network and sound support in a VM side, their interfaces replaced with a stub functions. I found a place for mouse support, but without mouse pointer capture (which is required for the FPS genre). Sound support isn’t very portable and difficult to fit in the contest restrictions.
+
Last improvements
+
After making the X11 version, to make this entry more portable - I also made alternate versions using WinAPI and SDL1.2/SDL2.
+
The binary code for this VM takes up a lot of space, so the Doom binary takes 1.4Mb, while x86_64 one is less than 0.5Mb. To deal with this I wrote an executable packer for the VM bytecode that reduced the size of the game binary to 0.2Mb.
+
Doom port sources
+
I don’t include modified Doom sources, but instead include a diff patch to avoid licensing issues.
+
VM SDK
+
I also include the NASM macros used to generate binary code, the VM runtime library sources and the backend for LCC-4.2 (does not include the LCC sources) and a simple patch to enable the backend.
+
Use:
+
./prog lzmadec.bin < sdk.zip.lzma > sdk.zip
+
to decompress the SDK (.zip archive is without compression).
+
Use:
+
make sdk
+
To build the LCC and Doom and all examples from source,
+for those systems with a compatible x86 processor, and the nasm(1) tool,
+the *.bin files may be produced via this make samples rule:
Can access memory at a byte granularity and read from unaligned pointers.
+
Any 32-bit aligned memory location can act as a register.
+
A program running in a VM is sandboxed, it only has access to its working memory and can only call limited functions that interact with the user or the file system.
+
+
Limitations
+
+
No floating point support.
+
No support for 64-bit integers.
+
Divide overflow is not handled, the OS will terminate the VM process if this happens.
+
The amount of RAM must be a power of two (up to 4 GBytes).
+
Possible filenames are limited to alphanumeric characters, dot and underscore, and a length of 32. Any other characters are replaced by underscore. Since forward slashes are also filtered, it can only access files in the current directory.
+
Only two file access modes: open an existing one for reading or create a new one for writing, both in binary mode.
+
Can work with up to 8 file descriptors (the first three are standard streams).
+
+
Other demo applications
+
+
hello.bin : Simple “Hello World” program.
+
fizzbuzz.bin : Solution for well-known job interview task.
+
loader.bin : Loads another application from standard input into the VM’s memory and runs it.
+
window.bin : An example for the SDK on how to draw graphics and capture keyboard and mouse events.
+
lzmadec.bin : LZMA stream decoder.
+
+
Web version
+
I also wrote a web version in javascript. It is in ogvm.html, start a local server with $ python3 -m http.server 8000 and open http://127.0.0.1:8000/ogvm.html in your browser.