release winning entries of IOCCC28 under the year 2024

Congratulations to:

* 2024/anders - Prize in sound coding - layered music generator
* 2024/burton - Prize in pentagrammatology - wordle hard mode solver
* 2024/cable1 - Prize in bot talk - LLM inference engine
* 2024/cable2 - Prize in murky waters - salmon recipe
* 2024/carlini - Prize in perfect timing - Intel 4004 emulation
* 2024/codemeow - Prize in tray planting - bonsai generator
* 2024/endoh1 - Prize in patient pointillism - slow ray tracer in CPP
* 2024/endoh2 - Prize in solid body physics - rotating rigid body simulation
* 2024/ferguson1 - Prize in diabolical logistics - Oregon trail pact with the devil
* 2024/ferguson2 - Prize in yil-tas - Navajo code talker translator
* 2024/howe - Nice accent eh-ward - mini vi
* 2024/kramer - Prize in linguistic arithmetic - natural language numerical calculator
* 2024/kurdyukov1 - Prize in phased periodicity - phase of the Moon
* 2024/kurdyukov2 - Prize in art restoration - JPEG artifact removal
* 2024/kurdyukov3 - Prize in virtual quietus - gaming VM and doom
* 2024/kurdyukov4 - Prize in embiggening - encode without literals
* 2024/maffiodo - Prize in creative interpretation - Jav\*script interpreter
* 2024/mills - Prize in ℤ₃ - Infocom v3 story interpreter
* 2024/stedolan - Best one liner - icon from MD5
* 2024/straadt - Prize in imitative rebooting - OpenRISC CPU and Linux
* 2024/tmarrec - Prize in cyclonic coding - 3D tornado simulation
* 2024/tompng - Prize in quasi bijection - vortex encryptor decryptor
* 2024/weaver - Sur prize - rickroll

Ran `make update` to perform the above.
 	new file:   2024/burton/.entry.json
This commit is contained in:
Landon Curt Noll committed 2025-08-02 14:43:07 -07:00
1 parent 10512e6c79
commit 09750f8899
443 files changed
+182938 -231

No files matched your search

+23
View File
@@ -319,3 +319,26 @@
2020/otterness
2020/tsoj
2020/yang
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
+1
View File
@@ -25,3 +25,4 @@
2018
2019
2020
2024
BIN
View File
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -462,7 +462,7 @@
<h2 id="author">Author:</h2>
<ul>
<li>Name: <a href="../../authors.html#Anthony_C_Howe">Anthony C. Howe</a><br>
<li>Name: <a href="../../authors.html#Anthony_C_Howe">Anthony C Howe</a><br>
Location: <a href="../../location.html#CA">CA</a> - <em>Canada</em></li>
</ul>
BIN
View File
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -462,7 +462,7 @@
<h2 id="author">Author:</h2>
<ul>
<li>Name: <a href="../../authors.html#Anthony_C_Howe">Anthony C. Howe</a><br>
<li>Name: <a href="../../authors.html#Anthony_C_Howe">Anthony C Howe</a><br>
Location: <a href="../../location.html#CA">CA</a> - <em>Canada</em></li>
</ul>
BIN
View File
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -462,7 +462,7 @@
<h2 id="author">Author:</h2>
<ul>
<li>Name: <a href="../../authors.html#Anthony_C_Howe">Anthony C. Howe</a><br>
<li>Name: <a href="../../authors.html#Anthony_C_Howe">Anthony C Howe</a><br>
Location: <a href="../../location.html#CA">CA</a> - <em>Canada</em></li>
</ul>
BIN
View File
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -462,7 +462,7 @@
<h2 id="author">Author:</h2>
<ul>
<li>Name: <a href="../../authors.html#Anthony_C_Howe">Anthony C. Howe</a><br>
<li>Name: <a href="../../authors.html#Anthony_C_Howe">Anthony C Howe</a><br>
Location: <a href="../../location.html#CA">CA</a> - <em>Canada</em></li>
</ul>
BIN
View File
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -462,7 +462,7 @@
<h2 id="author">Author:</h2>
<ul>
<li>Name: <a href="../../authors.html#Anthony_C_Howe">Anthony C. Howe</a><br>
<li>Name: <a href="../../authors.html#Anthony_C_Howe">Anthony C Howe</a><br>
Location: <a href="../../location.html#CA">CA</a> - <em>Canada</em></li>
</ul>
Binary file not shown.
+1 -1
View File
@@ -462,7 +462,7 @@
<h2 id="author">Author:</h2>
<ul>
<li>Name: <a href="../../authors.html#Vincent_Weaver">Vincent Weaver</a><br>
<li>Name: <a href="../../authors.html#Vincent_Weaver">Vince Weaver</a><br>
Location: <a href="../../location.html#US">US</a> - <em>United States of America</em> (<em>United States</em>)</li>
</ul>
BIN
View File
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -462,7 +462,7 @@
<h2 id="author">Author:</h2>
<ul>
<li>Name: <a href="../../authors.html#Anthony_C_Howe">Anthony C. Howe</a><br>
<li>Name: <a href="../../authors.html#Anthony_C_Howe">Anthony C Howe</a><br>
Location: <a href="../../location.html#CA">CA</a> - <em>Canada</em></li>
</ul>
BIN
View File
Binary file not shown.
+41 -13
View File
@@ -60,6 +60,7 @@
</span>
<div class="sub-item">
<div class="outfit-font">
<a href="../years.html" class="sub-item-link">
Winning entries
@@ -95,6 +96,7 @@
Updating author info
</a>
</div>
</div>
</div>
@@ -104,6 +106,7 @@
</span>
<div class="sub-item">
<div class="outfit-font">
<a href="../news.html" class="sub-item-link">
News
@@ -117,8 +120,14 @@
</div>
<div class="outfit-font">
<a href="../next/index.html" class="sub-item-link">
Rules and guidelines
<a href="../next/rules.html" class="sub-item-link">
IOCCC rules
</a>
</div>
<div class="outfit-font">
<a href="../next/guidelines.html" class="sub-item-link">
IOCCC guidelines
</a>
</div>
@@ -143,9 +152,10 @@
</span>
<div class="sub-item">
<div class="outfit-font">
<a href="../faq.html" class="sub-item-link">
Frequently Asked Questions
Frequently asked questions
</a>
</div>
@@ -182,12 +192,19 @@
</span>
<div class="sub-item">
<div class="outfit-font">
<a href="../index.html" class="sub-item-link">
Home page
</a>
</div>
<div class="outfit-font">
<a href="../social.html" class="sub-item-link">
IOCCC social media
</a>
</div>
<div class="outfit-font">
<a href="../about.html" class="sub-item-link">
About the IOCCC
@@ -196,7 +213,7 @@
<div class="outfit-font">
<a href="../judges.html" class="sub-item-link">
The Judges
The judges
</a>
</div>
@@ -276,6 +293,7 @@
<a class="mobile-submenu-item" href="../thanks-for-help.html">
Thanks for the help
</a>
</div>
</div>
@@ -294,8 +312,12 @@
Contest status
</a>
<a class="mobile-submenu-item" href="../next/index.html">
Rules and guidelines
<a class="mobile-submenu-item" href="../next/rules.html">
IOCCC rules
</a>
<a class="mobile-submenu-item" href="../next/guidelines.html">
IOCCC guidelines
</a>
<a class="mobile-submenu-item" href="../markdown.html">
@@ -305,6 +327,7 @@
<a class="mobile-submenu-item" href="../SECURITY.html">
Security policy
</a>
</div>
</div>
@@ -315,7 +338,7 @@
<div class="mobile-submenu-wrapper">
<a class="mobile-submenu-item" href="../faq.html">
Frequently Asked Questions
Frequently asked questions
</a>
<a class="mobile-submenu-item" href="../quick-start.html#enter">
@@ -347,17 +370,22 @@
Home page
</a>
<a class="mobile-submenu-item" href="../social.html">
IOCCC social media
</a>
<a class="mobile-submenu-item" href="../about.html">
About the IOCCC
</a>
<a class="mobile-submenu-item" href="../judges.html">
The Judges
The judges
</a>
<a class="mobile-submenu-item" href="../contact.html">
Contact us
</a>
</div>
</div>
</div>
@@ -409,17 +437,17 @@
</div>
<!-- END: this line ends content from: inc/header.default.html -->
<!-- START: this line starts content from: inc/navbar.year.last.html -->
<!-- START: this line starts content from: inc/navbar.year.mid.html -->
<div class="navbar">
<a class="Left" href="../2019/index.html">&larr; 2019</a>
<a class="Left" href="../years.html">&uarr; top &uarr;</a>
<a class="Left Disabled" href="#">No next</a>
<a class="Left" href="../2024/index.html">2024 &rarr;</a>
<a class="Right" href="#inventory">Inventory</a>
<a class="Right" href="https://validator.w3.org/nu/?doc=https%3A%2F%2Fwww.ioccc.org%2F2020%2Findex.html">&#x2713;</a>
</div>
<!-- END: this line ends content from: inc/navbar.year.last.html -->
<!-- END: this line ends content from: inc/navbar.year.mid.html -->
<!-- START: this line starts content from: inc/before-content.default.html -->
<div class="content" id="content">
@@ -532,7 +560,7 @@ Jump to: <a href="#">top</a>
<!--
Copyright © 1984-2024 by Landon Curt Noll. All Rights Reserved.
Copyright © 1984-2025 by Landon Curt Noll. All Rights Reserved.
You are free to share and adapt this file under the terms of this license:
@@ -546,7 +574,7 @@ Jump to: <a href="#">top</a>
<div class="footer">
<div id="copyright"><h3>Copyright &copy; 1984-2024 by Landon Curt Noll:
<div id="copyright"><h3>Copyright &copy; 1984-2025 by Landon Curt Noll:
<a href="https://creativecommons.org/faq/#what-does-some-rights-reserved-mean"
target="_blank"
rel="license noopener noreferrer">Some Rights Reserved</a></h3>
Binary file not shown.
+3 -3
View File
@@ -438,19 +438,19 @@
</div>
<!-- END: this line ends content from: inc/header.default.html -->
<!-- START: this line starts content from: inc/navbar.last.html -->
<!-- START: this line starts content from: inc/navbar.mid.html -->
<div class="navbar">
<a class="Left" href="../tsoj/index.html">&larr; 2020/tsoj</a>
<a class="Left" href="../index.html">&uarr; 2020 &uarr;</a>
<a class="Left Disabled" href="#">last entry</a>
<a class="Left" href="../../2024/anders/index.html">2024/anders &rarr;</a>
<a class="Right" href="https://github.com/ioccc-src/winner/blob/master/2020/yang/prog.c">C code</a>
<a class="Right" href="https://github.com/ioccc-src/winner/blob/master/2020/yang/Makefile">Makefile</a>
<a class="Right" href="#inventory">Inventory</a>
<a class="Right" href="https://validator.w3.org/nu/?doc=https%3A%2F%2Fwww.ioccc.org%2F2020%2Fyang%2Findex.html">&#x2713;</a>
</div>
<!-- END: this line ends content from: inc/navbar.last.html -->
<!-- END: this line ends content from: inc/navbar.mid.html -->
<!-- START: this line starts content from: inc/before-content.default.html -->
<div class="content" id="content">
+10
View File
@@ -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
+23
View File
@@ -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
BIN
View File
Binary file not shown.
+510
View File
@@ -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 $@ =-=-='
+389
View File
@@ -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:
``` <!---sh-->
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
<!--
Copyright © 1984-2025 by Landon Curt Noll and Leonid A. Broukhis. 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/
-->
+97
View File
@@ -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"
}
]
}
+1
View File
@@ -0,0 +1 @@
prog.wav
+1
View File
@@ -0,0 +1 @@
2024/anders
Binary file not shown.
+216
View File
@@ -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
+93
View File
@@ -0,0 +1,93 @@
## To build:
``` <!---sh-->
make all
```
## To use:
``` <!---sh-->
./prog
```
## Try:
``` <!---sh-->
./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:
``` <!---c--->
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]`:
``` <!---python-->
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")
```
<!--
Copyright © 1984-2025 by Landon Curt Noll and Leonid A. Broukhis. 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/
-->
+638
View File
@@ -0,0 +1,638 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<!-- START: two lines up starts content from: inc/top.default.html -->
<!-- END: this line ends content from: inc/top.default.html -->
<!-- START: this line starts content from: inc/head.default.html -->
<head>
<link rel="stylesheet" href="../../ioccc.css">
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@100..900&display=swap" rel="stylesheet">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>2024/anders - Prize in sound coding</title>
<link rel="icon" type="image/x-icon" href="../../favicon.ico">
<meta name="description" content="2024 IOCCC entry anders - Prize in sound coding">
<meta name="keywords" content="IOCCC, 2024, IOCCC 2024, IOCCC entry, anders, Prize in sound coding">
</head>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<!-- !!! DO NOT MODIFY THIS FILE - This file is generated by a tool !!! -->
<!-- !!! DO NOT MODIFY THIS FILE - This file is generated by a tool !!! -->
<!-- !!! DO NOT MODIFY THIS FILE - This file is generated by a tool !!! -->
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<!-- END: this line ends content from: inc/head.default.html -->
<!-- -->
<!-- This web page was formed via the tool: bin/readme2index.sh -->
<!-- The content of main section of this web page came from: 2024/anders/README.md -->
<!-- -->
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<!-- !!! Do not modify this web page, instead modify the file: 2024/anders/README.md !!! -->
<!-- !!! Do not modify this web page, instead modify the file: 2024/anders/README.md !!! -->
<!-- !!! Do not modify this web page, instead modify the file: 2024/anders/README.md !!! -->
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<!-- Markdown content was converted into HTML via the tool: bin/md2html.sh -->
<!-- START: this line starts content from: inc/body.default.html -->
<body>
<!-- END: this line ends content from: inc/body.default.html -->
<!-- START: this line starts content from: inc/topbar.default.html -->
<div class="theader">
<nav class="topbar">
<div class="container">
<div class="logo">
<a href="../../index.html" class="logo-link">
IOCCC
</a>
</div>
<div class="topbar-items">
<div class="item">
<span class="item-header">
Entries
</span>
<div class="sub-item">
<div class="outfit-font">
<a href="../../years.html" class="sub-item-link">
Winning entries
</a>
</div>
<div class="outfit-font">
<a href="../../authors.html" class="sub-item-link">
Winning authors
</a>
</div>
<div class="outfit-font">
<a href="../../location.html" class="sub-item-link">
Location of authors
</a>
</div>
<div class="outfit-font">
<a href="../../bugs.html" class="sub-item-link">
Bugs and (mis)features
</a>
</div>
<div class="outfit-font">
<a href="../../faq.html#fix_an_entry" class="sub-item-link">
Fixing entries
</a>
</div>
<div class="outfit-font">
<a href="../../faq.html#fix_author" class="sub-item-link">
Updating author info
</a>
</div>
</div>
</div>
<div class="item">
<span class="item-header">
Status
</span>
<div class="sub-item">
<div class="outfit-font">
<a href="../../news.html" class="sub-item-link">
News
</a>
</div>
<div class="outfit-font">
<a href="../../status.html" class="sub-item-link">
Contest status
</a>
</div>
<div class="outfit-font">
<a href="../../next/rules.html" class="sub-item-link">
IOCCC rules
</a>
</div>
<div class="outfit-font">
<a href="../../next/guidelines.html" class="sub-item-link">
IOCCC guidelines
</a>
</div>
<div class="outfit-font">
<a href="../../markdown.html" class="sub-item-link">
Markdown guidelines
</a>
</div>
<div class="outfit-font">
<a href="../../SECURITY.html" class="sub-item-link">
Security policy
</a>
</div>
</div>
</div>
<div class="item">
<span class="item-header">
FAQ
</span>
<div class="sub-item">
<div class="outfit-font">
<a href="../../faq.html" class="sub-item-link">
Frequently asked questions
</a>
</div>
<div class="outfit-font">
<a href="../../quick-start.html#enter" class="sub-item-link">
Enter the IOCCC
</a>
</div>
<div class="outfit-font">
<a href="../../faq.html#compiling" class="sub-item-link">
Compiling entries
</a>
</div>
<div class="outfit-font">
<a href="../../faq.html#running_entries" class="sub-item-link">
Running entries
</a>
</div>
<div class="outfit-font">
<a href="../../faq.html#help" class="sub-item-link">
How to help
</a>
</div>
</div>
</div>
<div class="item">
<span class="item-header">
About
</span>
<div class="sub-item">
<div class="outfit-font">
<a href="../../index.html" class="sub-item-link">
Home page
</a>
</div>
<div class="outfit-font">
<a href="../../social.html" class="sub-item-link">
IOCCC social media
</a>
</div>
<div class="outfit-font">
<a href="../../about.html" class="sub-item-link">
About the IOCCC
</a>
</div>
<div class="outfit-font">
<a href="../../judges.html" class="sub-item-link">
The judges
</a>
</div>
<div class="outfit-font">
<a href="../../thanks-for-help.html" class="sub-item-link">
Thanks for the help
</a>
</div>
<div class="outfit-font">
<a href="../../contact.html" class="sub-item-link">
Contact us
</a>
</div>
</div>
</div>
</div>
</div>
</nav>
<div class="header-mobile-menu">
<noscript>
<a href="../../nojs-menu.html" class="topbar-js-label">
Please Enable JavaScript
</a>
</noscript>
<button id="header-open-menu-button" class="topbar-mobile-menu">
<img
src="../../png/hamburger-icon-open.png"
alt="hamburger style menu icon - open state"
width=48
height=48>
</button>
<button id="header-close-menu-button" class="hide-content">
<img
src="../../png/hamburger-icon-closed.png"
alt="hamburger style menu icon - closed state"
width=48
height=48>
</button>
<div id="mobile-menu-panel" class="hide-content">
<div class="mobile-menu-container">
<div class="mobile-menu-wrapper">
<div class="mobile-menu-item">
Entries
</div>
<div class="mobile-submenu-wrapper">
<a class="mobile-submenu-item" href="../../years.html">
Winning entries
</a>
<a class="mobile-submenu-item" href="../../authors.html">
Winning authors
</a>
<a class="mobile-submenu-item" href="../../location.html">
Location of authors
</a>
<a class="mobile-submenu-item" href="../../bugs.html">
Bugs and (mis)features
</a>
<a class="mobile-submenu-item" href="../../faq.html#fix_an_entry">
Fixing entries
</a>
<a class="mobile-submenu-item" href="../../faq.html#fix_author">
Updating author info
</a>
<a class="mobile-submenu-item" href="../../thanks-for-help.html">
Thanks for the help
</a>
</div>
</div>
<div class="mobile-menu-wrapper">
<div class="mobile-menu-item">
Status
</div>
<div class="mobile-submenu-wrapper">
<a class="mobile-submenu-item" href="../../news.html">
News
</a>
<a class="mobile-submenu-item" href="../../status.html">
Contest status
</a>
<a class="mobile-submenu-item" href="../../next/rules.html">
IOCCC rules
</a>
<a class="mobile-submenu-item" href="../../next/guidelines.html">
IOCCC guidelines
</a>
<a class="mobile-submenu-item" href="../../markdown.html">
Markdown guidelines
</a>
<a class="mobile-submenu-item" href="../../SECURITY.html">
Security policy
</a>
</div>
</div>
<div class="mobile-menu-wrapper">
<div class="mobile-menu-item">
FAQ
</div>
<div class="mobile-submenu-wrapper">
<a class="mobile-submenu-item" href="../../faq.html">
Frequently asked questions
</a>
<a class="mobile-submenu-item" href="../../quick-start.html#enter">
Enter the IOCCC
</a>
<a class="mobile-submenu-item" href="../../faq.html#compiling">
Compiling entries
</a>
<a class="mobile-submenu-item" href="../../faq.html#running_entries">
Running entries
</a>
<a class="mobile-submenu-item" href="../../faq.html#help">
How to help
</a>
</div>
</div>
<div class="mobile-menu-wrapper">
<div class="mobile-menu-item">
About
</div>
<div class="mobile-submenu-wrapper">
<a class="mobile-submenu-item" href="../../index.html">
Home page
</a>
<a class="mobile-submenu-item" href="../../social.html">
IOCCC social media
</a>
<a class="mobile-submenu-item" href="../../about.html">
About the IOCCC
</a>
<a class="mobile-submenu-item" href="../../judges.html">
The judges
</a>
<a class="mobile-submenu-item" href="../../contact.html">
Contact us
</a>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
var headerOpenMenuButton = document.getElementById("header-open-menu-button");
var headerCloseMenuButton = document.getElementById("header-close-menu-button");
var mobileMenuPanel = document.getElementById("mobile-menu-panel");
headerOpenMenuButton.addEventListener("click", () => {
headerOpenMenuButton.classList.remove("topbar-mobile-menu");
headerOpenMenuButton.classList.add("hide-content");
headerCloseMenuButton.classList.remove("hide-content");
headerCloseMenuButton.classList.add("topbar-mobile-menu");
mobileMenuPanel.classList.remove("hide-content");
mobileMenuPanel.classList.add("topbar-mobile-panel");
});
headerCloseMenuButton.addEventListener("click", () => {
headerCloseMenuButton.classList.remove("topbar-mobile-menu");
headerCloseMenuButton.classList.add("hide-content");
mobileMenuPanel.classList.add("hide-content");
mobileMenuPanel.classList.remove("topbar-mobile-panel");
headerOpenMenuButton.classList.add("topbar-mobile-menu");
headerOpenMenuButton.classList.remove("hide-content");
});
</script>
<!-- END: this line ends content from: inc/topbar.default.html -->
<!-- START: this line starts content from: inc/header.default.html -->
<div class="header">
<a href="../../2011/zucker/index.html">
<img src="../../png/ioccc.png"
alt="IOCCC image by Matt Zucker"
width=300
height=110>
</a>
<h1>The International Obfuscated C Code Contest</h1>
<h2>2024/anders - Prize in sound coding</h2>
<h3>layered music generator</h3>
</div>
<!-- END: this line ends content from: inc/header.default.html -->
<!-- START: this line starts content from: inc/navbar.mid.html -->
<div class="navbar">
<a class="Left" href="../../2020/yang/index.html">&larr; 2020/yang</a>
<a class="Left" href="../index.html">&uarr; 2024 &uarr;</a>
<a class="Left" href="../burton/index.html">2024/burton &rarr;</a>
<a class="Right" href="https://github.com/ioccc-src/winner/blob/master/2024/anders/prog.c">C code</a>
<a class="Right" href="https://github.com/ioccc-src/winner/blob/master/2024/anders/Makefile">Makefile</a>
<a class="Right" href="#inventory">Inventory</a>
<a class="Right" href="https://validator.w3.org/nu/?doc=https%3A%2F%2Fwww.ioccc.org%2F2024%2Fanders%2Findex.html">&#x2713;</a>
</div>
<!-- END: this line ends content from: inc/navbar.mid.html -->
<!-- START: this line starts content from: inc/before-content.default.html -->
<div class="content" id="content">
<!-- END: this line ends content from: inc/before-content.default.html -->
<!-- START: this line starts content for HTML phase 20 by: bin/output-index-author.sh via bin/md2html.sh -->
<!-- START: this line starts content generated by: bin/output-index-author.sh -->
<h2 id="author">Author:</h2>
<ul>
<li>Name: <a href="../../authors.html#Anders_Kaare_Straadt">Anders Kaare Straadt</a><br>
Location: <a href="../../location.html#DK">DK</a> - <em>Denmark</em></li>
</ul>
<!-- END: next line ends content generated by: bin/output-index-author.sh -->
<!-- END: this line ends content for HTML phase 20 by: bin/output-index-author.sh via bin/md2html.sh -->
<!-- START: this line starts content for HTML phase 21 by: bin/pandoc-wrapper.sh via bin/md2html.sh -->
<!-- BEFORE: 1st line of markdown file: 2024/anders/README.md -->
<h2 id="to-build">To build:</h2>
<pre><code> make all</code></pre>
<h2 id="to-use">To use:</h2>
<pre><code> ./prog</code></pre>
<h2 id="try">Try:</h2>
<pre><code> ./prog</code></pre>
<p>and then play the resulting <code>prog.wav</code> using a sound player.</p>
<h2 id="judges-remarks">Judges’ remarks:</h2>
<p>When you run the program, after several moments, a <code>prog.wav</code> sound file is produced.</p>
<p>Using a sound player (you may find <code>sox(1)</code> is a good choice), you may enjoy the result.</p>
<p>Can you figure out how it produces the various layers of instruments?</p>
<h2 id="authors-remarks">Author’s remarks:</h2>
<h3 id="obfuscations">Obfuscations</h3>
<ul>
<li>“Helpful” formatting</li>
<li>Character salad</li>
<li>Loop exit trying to hide by a switch statement</li>
<li>Strong string encryption. By that I mean “fmt”=&gt;“gnu”.</li>
<li>A <code>/*{*/</code> that throws off bracket matching in vim. Begun the editor wars
have! (Wait, I’m <strong>on</strong> the vim-team!)</li>
<li><code>cm</code> and <code>ap</code> stands for “allpass” and “comb”, respectively.</li>
<li>One effect was created with deliberate “memory corruption”.</li>
</ul>
<p>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!</p>
<h3 id="sound-quality">Sound quality</h3>
<p>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
<code>mplayer(1)</code> is poor, but you can use the high-quality resampler in <code>sox(1)</code> to create a
48kHz version:</p>
<pre class="&lt;!---c---&gt;"><code> sox prog.wav -r 48000 prog.48kHz.wav</code></pre>
<h3 id="tricks-the-condescending-part">Tricks (the condescending part)</h3>
<ul>
<li>Kick drum from sines, pitched up to create toms.</li>
<li>Roland TR-808 style hi-hats (a bunch of high-pass filtered square waves).</li>
<li>SID/C64-style snare drum (oscillates between noise and square wave).</li>
<li>There’s some FM synthesis in the bass.</li>
<li>Schroeder reverberator a la Freeverb. The same building blocks are used for
the echo effect.</li>
<li>Waveshaping/overdrive using tanh(x), ohh yeaaah..</li>
</ul>
<p>I used this Python snippet to generate <code>q0[2]</code> and <code>q0[3]</code>:</p>
<pre><code> def X(s): print(hex(int(s.replace(&quot;x&quot;,&quot;1&quot;).replace(&quot;.&quot;,&quot;0&quot;)[::-1],2))) # not for iopcc-use
X(&quot;.x.x..xx.x.xx.xxx.xx.xxx..xx.xxx&quot;)
X(&quot;x.xx.x.x.x.xxxxxx.xx.xxx.xxxxxxx&quot;)</code></pre>
<!--
Copyright © 1984-2025 by Landon Curt Noll and Leonid A. Broukhis. 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/
-->
<!-- AFTER: last line of markdown file: 2024/anders/README.md -->
<!-- END: this line ends content for HTML phase 21 by: bin/pandoc-wrapper.sh via bin/md2html.sh -->
<!-- START: this line starts content for HTML phase 22 by: bin/output-index-inventory.sh via bin/md2html.sh -->
<!-- START: this line starts content generated by: bin/output-index-inventory.sh -->
<div id="inventory">
<h1 id="inventory-for-2024anders">Inventory for 2024/anders</h1>
</div>
<h2 id="primary-files">Primary files</h2>
<ul>
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/anders/prog.c">prog.c</a> - entry source code</li>
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/anders/Makefile">Makefile</a> - entry Makefile</li>
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/anders/prog.orig.c">prog.orig.c</a> - original source code</li>
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/anders/try.sh">try.sh</a> - script to try entry</li>
</ul>
<h2 id="secondary-files">Secondary files</h2>
<ul>
<li><a href="2024_anders.tar.bz2">2024_anders.tar.bz2</a> - download entry tarball</li>
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/anders/README.md">README.md</a> - markdown source for this web page</li>
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/anders/.entry.json">.entry.json</a> - entry summary and manifest in JSON</li>
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/anders/.gitignore">.gitignore</a> - list of files that should not be committed under git</li>
<li><a href=".path">.path</a> - directory path from top level directory</li>
<li><a href="index.html">index.html</a> - this web page</li>
</ul>
<hr style="width:10%;text-align:left;margin-left:0">
<h4>
Jump to: <a href="#">top</a>
</h4>
<!-- END: next line ends content generated by: bin/output-index-inventory.sh -->
<!-- END: this line ends content for HTML phase 22 by: bin/output-index-inventory.sh via bin/md2html.sh -->
<!-- START: this line starts content from: inc/after-content.default.html -->
</div>
<!-- END: this line ends content from: inc/after-content.default.html -->
<!-- START: this line starts content from: inc/footer.inventory.html -->
<!--
Copyright © 1984-2025 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/
-->
<div class="footer">
<div id="copyright"><h3>Copyright &copy; 1984-2025 by Landon Curt Noll:
<a href="https://creativecommons.org/faq/#what-does-some-rights-reserved-mean"
target="_blank"
rel="license noopener noreferrer">Some Rights Reserved</a></h3>
<p>
This work is <b>licensed by Landon Curt Noll</b> under
<b><a href="https://creativecommons.org/licenses/by-sa/4.0/?ref=chooser-v1"
target="_blank"
rel="license noopener noreferrer"
style="display:inline-block;">CC BY-SA 4.0</a></b>.
<img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;"
src="../../png/cc.png"
alt="cc inside circle symbol">
<img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;"
src="../../png/by.png"
alt="person inside circle symbol">
<img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;"
src="../../png/sa.png"
alt="arrow looping back on itself inside circle symbol"><br>
You should <b>carefully review</b> the
<b><a href="https://creativecommons.org/licenses/by-sa/4.0/legalcode.en"
target="_blank"
rel="license noopener noreferrer">CC BY-SA 4.0 LEGAL CODE</a></b>
before using the licensed material.<br>
You may wish to review the
<b><a href="../../license.html"
target="_blank"
rel="license noopener noreferrer">highlights of some of the key features and terms</a></b>
of <b>CC BY-SA 4.0</b>.<br>
</p>
</div>
<div id="coda"><h3>Coda</h3>
<p>
<a href="https://validator.w3.org/nu/?doc=https%3A%2F%2Fwww.ioccc.org%2F2024%2Fanders%2Findex.html" rel="nofollow">Nu HTML check this web page</a><br>
<a href="#top">Jump to top</a> <a href="#content">Jump to Content</a> <a href="#inventory">Jump to Inventory</a><br>
</p>
</div>
</div>
<!-- END: this line ends content from: inc/footer.inventory.html -->
<!-- START: this line starts content from: inc/bottom.default.html -->
</body>
</html>
<!-- END: this line ends content from: inc/bottom.default.html -->
+237
View File
@@ -0,0 +1,237 @@
double static F=
1.5e-3
,t,b,D[1<<20],*E,U[4],X;
int static B=
17e3
,J,I,N;
unsigned static q0[]={
0x0ce97522,
0xc02972e5,
0xeceddaca,
0xfeedfaad,
};
int static q1[]={
-2, 0, 7,
0, 3, 10,
-5, 0, 0, 2, 3, 0, 2, 2,
-2, 0, 7, 12, 3, 7, 5, 10,
0, 3, -5,
-2, 7, 3,
-2, 2, -5,
-10,-2, 5
}
; char static*q2[]={
"XBWFgnu!" ,
"ebub","SJGG" ,
"\njust a moment.."
} ,*P,M[1<<29]
#define S sin
#define O pow
#define H tanh
#define C(b)double*j=G(n+2),o; int c=(int)j[n+1]; b; if(++c>=n)c=0; j[n+1]=c; return o;
#define A(n)for(j=0; j<n; ++j)
; int static T( int x ) { return I/(B<<x) ; }
double static dp( int a,int c ){ return (double)((I+B*c)%(B<<a)) /(B<<a); }
void static L(short w){ *P++=( char ) w; *P++=w>>3 >>5; }
double static Q( int a ) { return dp (a,0); }
void static Z(char*s ) { for ( char*q=s; *q; ++q, ++P) *P=*q -1; }
double static qb( int p ) { return I%p<p>>2 ?1:-1; }
double static* G( int n ) { E+=n; return E -n; }
void static W( int l ) { L( ( short )l); L((short)(l>>13 >>3) )
; }
#include <math.h>
#include<stdlib.h>
#include <stdio.h>
void static Y(double p, double g, double e, double r)
{
U[2] += e * X ;
U[0] += X * p * fmin(1,1-g) ;
U[3] += r * X ;
U[1] += fmin(g+1,1) * X * p ;
}
double static eq(double x,double a,double h,double c,double d,double e)
{
double *z=
G(2) , y=a*x+
z[0] ;
z[0] = x*h-d*y+
z[1] ;
z[1] = c*x-y*e;
return y;
}
double static ap(double x,int n,double f,double d) { C (
o=
j[c] ;
j[n] =o* (1-d)+
j[n] *d;
j[c] =x+
j[n] *f
;
)
} double static cm
( double x,int n,double
f )
{ C
( double u=
j [c ]; o=u-x;
j[c ] =f*u+x; )
} int
main
( void )
{ int j ,
k , l , m ;
char * px = P
= M
,
* pa ,
*
p0 ; FILE
* o ;
N=(B*5)<<8;
Z ( q2 [ 2 ] ) ; W
( 36 + ( N << 2 ) ) ;
Z ( q2 [ 0 ] )
; W ( 16 ) ;
L ( 1 ) ; L ( 2
) ; W ( 1 << 18
) ; W ( 4 << 18
) ; L ( 4 ) ;L
( 16 ) ; Z ( q2
[1 ] ) ; W(N <<
2) ; for( pa = P ; ;
) { E= D ; A ( 4 )
U [ j ] = 0 ;
l=((T(3)+32)%64)-61;
t=H(Q((l<0?3:l)));
X=H(50*S(t*141+t*(15e3/(4+t*330)))*O(1-H(t),9));
if (T(10)) X=0;
Y(.5,0,.07,.1);
X=0;
A(8) X+=qb(211+(j*113+T(2)*91)%1291);
X=eq(X,.973,-1.946,.973,-1.942,.951);
X=H(X*2);
l=T(4)%8>6;
switch (T(8)) {
case 0 : t=H(Q((T(4))%4)); break;
case 2 : t=H(Q(2-l)); break;
default : case 1 : t=H(Q(1-l)); break;
} if (++I>N) break;
X*=O(1-t,4)*O(Q(3),2);
X=H(X*1.4);
if (!(T(7)&7) || T(10)) X=0;
Y(.8,S(I*1e-5),.16,.4);
t=1-(((T(2)&63)>61)?H(Q(1))/6:H(dp(4,8)));
X=I&(1<<12)?(double)(rand())/RAND_MAX-.5:.1*qb(1400-(int)(t*301));
X=H(30*X*O(t,40));
if (!(T(7)&3) || T(10)) X=0;
Y(.8,.3,1,.3);
l=T(6)%4;
k=(q0[l>2]>>((T(3)&7)<<2))&15;
b=F*I*O(2,(double)k/12);
k=T(8)%2;
m=((q0[2+l%2])>>(T(1)&31))&1;
X=m?S(b+1.5*S(I*7e-5)+S(I*3e-7)*(4+3*S(I*1.7e-7))*S(b*(1+k))):0;
if (T(8)) X+=((S(b*.501)>.95)-(S(b*.498)>.8))*15*O(Q(3),2);
t=1-H(Q(1));
X=H(25*X*O(t,3));
if (T(10)) X=0;
Y(.4,0,.12,.02);
A(3) {
k=T(1)%32+3;
k-=k/4*3;
l=T(6)&1;
k=l ? 24+q1[6 + T(7)%2*8 + T(3)%8] : T(9) ? 24+q1[22+(k+j)%3+T(4)%4*3] : q1[k%3+T(7)%2*3] + (k/3)*12;
X=F*I*O(2,((double)(14+k)+(j-1)*.4)/12)+S(j+I*(l?1e-4:3e-4))*(l?4:1);
t=S(X)+.3*(fmod(X,6.3)-3);
X=t+.3*(t>.9*S(I*6.3e-7)?1:-1);
t=1-H(Q(l?2:m?2:1));
X=H(X*O(t,9)*(T(10)?O(1-Q(8),3):1));
if (T(6)%2*!T(9) || !T(8)) X=0;
Y( 1,S(2*j+I*3e-6),.3,.3);
}
X=ap(U[3],(int)(B*6.1),.2,.2);
Y(1,-.6,.1,0);
X=cm(U[3],(int)(B*3.8),.2);
Y(.7,.6,.1,0);
for (k=0; k<2; ++k) {
X=0;
A(8) X+=ap(U[2],4001+(j*2131+k*1555)%3491,.8,.5);
A(4) X=cm(X,800+((j+T(8))*1337+k*1441)%1303,.4);
X=H(X/4);
Y( .3,k?-1:1,0,0);
}
A(
2)
L (
( short)
(fmin (1
,fmax (-1,
U [
j ]
) ) *32e3
) ); if ( !
( I %(
B * 8) ) )
{ putchar (q2
[3 ]
/*{*/[
++J&15 ] ) ;
fflush ( stdout ) ;
} } pa=P ;
Z("opx!fokpz!" ); p0=P ;
Z("qsph/xbw" );
o=fopen(p0,"wb") ; fwrite(
px, 1, (
unsigned
long )( pa-px),o); fclose(
o); puts ( pa ) ; return(
signed
)0; }
+237
View File
@@ -0,0 +1,237 @@
double static F=
1.5e-3
,t,b,D[1<<20],*E,U[4],X;
int static B=
17e3
,J,I,N;
unsigned static q0[]={
0x0ce97522,
0xc02972e5,
0xeceddaca,
0xfeedfaad,
};
int static q1[]={
-2, 0, 7,
0, 3, 10,
-5, 0, 0, 2, 3, 0, 2, 2,
-2, 0, 7, 12, 3, 7, 5, 10,
0, 3, -5,
-2, 7, 3,
-2, 2, -5,
-10,-2, 5
}
; char static*q2[]={
"XBWFgnu!" ,
"ebub","SJGG" ,
"\njust a moment.."
} ,*P,M[1<<29]
#define S sin
#define O pow
#define H tanh
#define C(b)double*j=G(n+2),o; int c=(int)j[n+1]; b; if(++c>=n)c=0; j[n+1]=c; return o;
#define A(n)for(j=0; j<n; ++j)
; int static T( int x ) { return I/(B<<x) ; }
double static dp( int a,int c ){ return (double)((I+B*c)%(B<<a)) /(B<<a); }
void static L(short w){ *P++=( char ) w; *P++=w>>3 >>5; }
double static Q( int a ) { return dp (a,0); }
void static Z(char*s ) { for ( char*q=s; *q; ++q, ++P) *P=*q -1; }
double static qb( int p ) { return I%p<p>>2 ?1:-1; }
double static* G( int n ) { E+=n; return E -n; }
void static W( int l ) { L( ( short )l); L((short)(l>>13 >>3) )
; }
#include <math.h>
#include<stdlib.h>
#include <stdio.h>
void static Y(double p, double g, double e, double r)
{
U[2] += e * X ;
U[0] += X * p * fmin(1,1-g) ;
U[3] += r * X ;
U[1] += fmin(g+1,1) * X * p ;
}
double static eq(double x,double a,double h,double c,double d,double e)
{
double *z=
G(2) , y=a*x+
z[0] ;
z[0] = x*h-d*y+
z[1] ;
z[1] = c*x-y*e;
return y;
}
double static ap(double x,int n,double f,double d) { C (
o=
j[c] ;
j[n] =o* (1-d)+
j[n] *d;
j[c] =x+
j[n] *f
;
)
} double static cm
( double x,int n,double
f )
{ C
( double u=
j [c ]; o=u-x;
j[c ] =f*u+x; )
} int
main
( void )
{ int j ,
k , l , m ;
char * px = P
= M
,
* pa ,
*
p0 ; FILE
* o ;
N=(B*5)<<8;
Z ( q2 [ 2 ] ) ; W
( 36 + ( N << 2 ) ) ;
Z ( q2 [ 0 ] )
; W ( 16 ) ;
L ( 1 ) ; L ( 2
) ; W ( 1 << 18
) ; W ( 4 << 18
) ; L ( 4 ) ;L
( 16 ) ; Z ( q2
[1 ] ) ; W(N <<
2) ; for( pa = P ; ;
) { E= D ; A ( 4 )
U [ j ] = 0 ;
l=((T(3)+32)%64)-61;
t=H(Q((l<0?3:l)));
X=H(50*S(t*141+t*(15e3/(4+t*330)))*O(1-H(t),9));
if (T(10)) X=0;
Y(.5,0,.07,.1);
X=0;
A(8) X+=qb(211+(j*113+T(2)*91)%1291);
X=eq(X,.973,-1.946,.973,-1.942,.951);
X=H(X*2);
l=T(4)%8>6;
switch (T(8)) {
case 0 : t=H(Q((T(4))%4)); break;
case 2 : t=H(Q(2-l)); break;
default : case 1 : t=H(Q(1-l)); break;
} if (++I>N) break;
X*=O(1-t,4)*O(Q(3),2);
X=H(X*1.4);
if (!(T(7)&7) || T(10)) X=0;
Y(.8,S(I*1e-5),.16,.4);
t=1-(((T(2)&63)>61)?H(Q(1))/6:H(dp(4,8)));
X=I&(1<<12)?(double)(rand())/RAND_MAX-.5:.1*qb(1400-(int)(t*301));
X=H(30*X*O(t,40));
if (!(T(7)&3) || T(10)) X=0;
Y(.8,.3,1,.3);
l=T(6)%4;
k=(q0[l>2]>>((T(3)&7)<<2))&15;
b=F*I*O(2,(double)k/12);
k=T(8)%2;
m=((q0[2+l%2])>>(T(1)&31))&1;
X=m?S(b+1.5*S(I*7e-5)+S(I*3e-7)*(4+3*S(I*1.7e-7))*S(b*(1+k))):0;
if (T(8)) X+=((S(b*.501)>.95)-(S(b*.498)>.8))*15*O(Q(3),2);
t=1-H(Q(1));
X=H(25*X*O(t,3));
if (T(10)) X=0;
Y(.4,0,.12,.02);
A(3) {
k=T(1)%32+3;
k-=k/4*3;
l=T(6)&1;
k=l ? 24+q1[6 + T(7)%2*8 + T(3)%8] : T(9) ? 24+q1[22+(k+j)%3+T(4)%4*3] : q1[k%3+T(7)%2*3] + (k/3)*12;
X=F*I*O(2,((double)(14+k)+(j-1)*.4)/12)+S(j+I*(l?1e-4:3e-4))*(l?4:1);
t=S(X)+.3*(fmod(X,6.3)-3);
X=t+.3*(t>.9*S(I*6.3e-7)?1:-1);
t=1-H(Q(l?2:m?2:1));
X=H(X*O(t,9)*(T(10)?O(1-Q(8),3):1));
if (T(6)%2*!T(9) || !T(8)) X=0;
Y( 1,S(2*j+I*3e-6),.3,.3);
}
X=ap(U[3],(int)(B*6.1),.2,.2);
Y(1,-.6,.1,0);
X=cm(U[3],(int)(B*3.8),.2);
Y(.7,.6,.1,0);
for (k=0; k<2; ++k) {
X=0;
A(8) X+=ap(U[2],4001+(j*2131+k*1555)%3491,.8,.5);
A(4) X=cm(X,800+((j+T(8))*1337+k*1441)%1303,.4);
X=H(X/4);
Y( .3,k?-1:1,0,0);
}
A(
2)
L (
( short)
(fmin (1
,fmax (-1,
U [
j ]
) ) *32e3
) ); if ( !
( I %(
B * 8) ) )
{ putchar (q2
[3 ]
/*{*/[
++J&15 ] ) ;
fflush ( stdout ) ;
} } pa=P ;
Z("opx!fokpz!" ); p0=P ;
Z("qsph/xbw" );
o=fopen(p0,"wb") ; fwrite(
px, 1, (
unsigned
long )( pa-px),o); fclose(
o); puts ( pa ) ; return(
signed
)0; }
+24
View File
@@ -0,0 +1,24 @@
#!/usr/bin/env bash
#
# try.sh - demonstrate 2024/anders
# 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
+361
View File
@@ -0,0 +1,361 @@
{
"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 pentagrammatology",
"year" : 2024,
"dir" : "burton",
"entry_id" : "2024_burton",
"title" : "wordle",
"abstract" : "wordle hard mode solver",
"author_set" : [
{
"author_handle" : "Dave_Burton"
}
],
"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" : "deobfuscated.html",
"inventory_order" : 100,
"OK_to_edit" : false,
"display_as" : "markdown",
"display_via_github" : true,
"entry_text" : "about deobfuscation"
},
{
"file_path" : "dict",
"inventory_order" : 100,
"OK_to_edit" : true,
"display_as" : "text",
"display_via_github" : true,
"entry_text" : "5-letter wordle dictionary"
},
{
"file_path" : "extra.html",
"inventory_order" : 100,
"OK_to_edit" : false,
"display_as" : "markdown",
"display_via_github" : true,
"entry_text" : "description of the extra files"
},
{
"file_path" : "reveal.c",
"inventory_order" : 100,
"OK_to_edit" : true,
"display_as" : "c",
"display_via_github" : true,
"entry_text" : "reveal wordle hints"
},
{
"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" : "deobfuscated.c",
"inventory_order" : 150,
"OK_to_edit" : true,
"display_as" : "c",
"display_via_github" : true,
"entry_text" : "deobfuscated source code"
},
{
"file_path" : "gen.c",
"inventory_order" : 150,
"OK_to_edit" : true,
"display_as" : "c",
"display_via_github" : true,
"entry_text" : "simulate wordle games"
},
{
"file_path" : "worst",
"inventory_order" : 150,
"OK_to_edit" : true,
"display_as" : "shellscript",
"display_via_github" : true,
"entry_text" : "determine worst target words"
},
{
"file_path" : "2024_01_18_wordle_stats.png",
"inventory_order" : 200,
"OK_to_edit" : true,
"display_as" : "image",
"display_via_github" : true,
"entry_text" : "wordle stats"
},
{
"file_path" : "avg",
"inventory_order" : 200,
"OK_to_edit" : true,
"display_as" : "shellscript",
"display_via_github" : true,
"entry_text" : "simple analysis script"
},
{
"file_path" : "comp.avg",
"inventory_order" : 200,
"OK_to_edit" : true,
"display_as" : "shellscript",
"display_via_github" : true,
"entry_text" : "compute averages"
},
{
"file_path" : "dups.c",
"inventory_order" : 200,
"OK_to_edit" : true,
"display_as" : "c",
"display_via_github" : true,
"entry_text" : "remove repeated letters"
},
{
"file_path" : "exhaust",
"inventory_order" : 200,
"OK_to_edit" : true,
"display_as" : "shellscript",
"display_via_github" : true,
"entry_text" : "exhaustive test of all wordle words"
},
{
"file_path" : "extra_guesses",
"inventory_order" : 200,
"OK_to_edit" : true,
"display_as" : "shellscript",
"display_via_github" : true,
"entry_text" : "allow extra wordle guesses"
},
{
"file_path" : "freq",
"inventory_order" : 200,
"OK_to_edit" : true,
"display_as" : "shellscript",
"display_via_github" : true,
"entry_text" : "letter frequency in wordle words"
},
{
"file_path" : "mkresults",
"inventory_order" : 200,
"OK_to_edit" : true,
"display_as" : "shellscript",
"display_via_github" : true,
"entry_text" : "report showing average word accuracy"
},
{
"file_path" : "rank",
"inventory_order" : 200,
"OK_to_edit" : true,
"display_as" : "shellscript",
"display_via_github" : true,
"entry_text" : "how averages are calculated and missed words"
},
{
"file_path" : "run.c",
"inventory_order" : 200,
"OK_to_edit" : true,
"display_as" : "c",
"display_via_github" : true,
"entry_text" : "automated testing tool"
},
{
"file_path" : "unob.c",
"inventory_order" : 200,
"OK_to_edit" : true,
"display_as" : "c",
"display_via_github" : true,
"entry_text" : "unobfuscator tool source code"
},
{
"file_path" : "wavg",
"inventory_order" : 200,
"OK_to_edit" : true,
"display_as" : "shellscript",
"display_via_github" : true,
"entry_text" : "weigh six scores"
},
{
"file_path" : "word.result",
"inventory_order" : 200,
"OK_to_edit" : true,
"display_as" : "shellscript",
"display_via_github" : true,
"entry_text" : "produce results of a"
},
{
"file_path" : "wrank",
"inventory_order" : 200,
"OK_to_edit" : true,
"display_as" : "shellscript",
"display_via_github" : true,
"entry_text" : "weighted rank tool"
},
{
"file_path" : "2024_burton.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" : "correct.test.abode",
"inventory_order" : 4000000000,
"OK_to_edit" : true,
"display_as" : "text",
"display_via_github" : true,
"entry_text" : "correct test of the word abode"
},
{
"file_path" : "correct.test.jaunt",
"inventory_order" : 4000000000,
"OK_to_edit" : true,
"display_as" : "text",
"display_via_github" : true,
"entry_text" : "correct test of the word jaunt"
},
{
"file_path" : "correct.test.light",
"inventory_order" : 4000000000,
"OK_to_edit" : true,
"display_as" : "text",
"display_via_github" : true,
"entry_text" : "correct test of the word light"
},
{
"file_path" : "deobfuscated.md",
"inventory_order" : 4000000000,
"OK_to_edit" : true,
"display_as" : "markdown",
"display_via_github" : true,
"entry_text" : "markdown source for deobfuscated.html"
},
{
"file_path" : "extra.md",
"inventory_order" : 4000000000,
"OK_to_edit" : true,
"display_as" : "markdown",
"display_via_github" : true,
"entry_text" : "markdown source for extra.html"
},
{
"file_path" : "r.blast",
"inventory_order" : 4000000000,
"OK_to_edit" : true,
"display_as" : "text",
"display_via_github" : true,
"entry_text" : "analysis for the word blast"
},
{
"file_path" : "r.crate",
"inventory_order" : 4000000000,
"OK_to_edit" : true,
"display_as" : "text",
"display_via_github" : true,
"entry_text" : "analysis for the word crate"
},
{
"file_path" : "r.query",
"inventory_order" : 4000000000,
"OK_to_edit" : true,
"display_as" : "text",
"display_via_github" : true,
"entry_text" : "analysis for the word query"
},
{
"file_path" : "r.terns",
"inventory_order" : 4000000000,
"OK_to_edit" : true,
"display_as" : "text",
"display_via_github" : true,
"entry_text" : "analysis for the word terns"
},
{
"file_path" : "test.abode",
"inventory_order" : 4000000000,
"OK_to_edit" : true,
"display_as" : "text",
"display_via_github" : true,
"entry_text" : "analysis for the word"
},
{
"file_path" : "test.jaunt",
"inventory_order" : 4000000000,
"OK_to_edit" : true,
"display_as" : "text",
"display_via_github" : true,
"entry_text" : "analysis for the jaunt"
},
{
"file_path" : "test.light",
"inventory_order" : 4000000000,
"OK_to_edit" : true,
"display_as" : "text",
"display_via_github" : true,
"entry_text" : "analysis for the word light"
},
{
"file_path" : "index.html",
"inventory_order" : 4294967295,
"OK_to_edit" : false,
"display_as" : "html",
"display_via_github" : false,
"entry_text" : "this web page"
}
]
}
+7
View File
@@ -0,0 +1,7 @@
dups
fmt
fmt.c
gen
reveal
run
usdw
+1
View File
@@ -0,0 +1 @@
2024/burton
Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.
+269
View File
@@ -0,0 +1,269 @@
#!/usr/bin/env make
#
# 2024/burton
#############################
# 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-misleading-indentation -Wno-parentheses -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= -D_FORTIFY_SOURCE=0
# 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-array-bounds-pointer-arithmetic -Wno-comma \
-Wno-declaration-after-statement -Wno-format-nonliteral \
-Wno-implicit-int-conversion -Wno-missing-prototypes \
-Wno-missing-variable-declarations -Wno-poison-system-directories \
-Wno-shadow -Wno-shorten-64-to-32 -Wno-vla -Wno-extra-semi-stmt \
-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} ${TOOLS}
#
ALT_OBJ=
ALT_TARGET=
# list any data files supplied with your submission
#
# Example: DATA= curds whey
#
DATA= dict test.abode test.light test.jaunt correct.test.abode \
correct.test.jaunt correct.test.light r.blast r.crate r.query r.terns
# utility scripts
#
SCRIPTS= avg comp.avg exhaust extra_guesses freq mkresults rank wavg word.result worst wrank
TOOLS= gen dups run reveal usdw
IOCCCSIZE= iocccsize
DICTIONARY= /usr/share/dict/words
#################
# build the entry
#################
all: data ${TARGET} ${SCRIPTS} ${TOOLS}
@${TRUE}
.PHONY: all alt data everything clean clobber
# how to compile
#
${PROG}: ${PROG}.c
${CC} ${CFLAGS} ${PROG}.c -o $@ ${LDFLAGS}
define stest
echo -n "$(2): ";
if ${CAT} $(2) | $(1) dict | ${DIFF} - correct.$(2); then echo pass; else echo fail; fi
endef
test: prog size
@ $(call stest,./prog,test.light,-lt)
@ $(call stest,./prog,test.abode,-lt)
@ $(call stest,./prog,test.jaunt,-eq)
size:
${IOCCCSIZE} prog.c
@# iocccsize-2019 -i < prog.c
@# iocccsize-2020 -i < prog.c > /dev/null
tfmt: fmt
@ $(call stest,./fmt,test.light,-lt)
@ $(call stest,./fmt,test.abode,-lt)
@ $(call stest,./fmt,test.jaunt,-eq)
fmt: fmt.c
${CC} ${CFLAGS} fmt.c -o $@ ${LDFLAGS}
fmt.c: prog.c
${RM} -f $@
${CLANG_FORMAT} -style=file < prog.c > fmt.c
dups: dups.c
${CC} ${CFLAGS} dups.c -o $@ ${LDFLAGS}
gen: gen.c
${CC} ${CFLAGS} gen.c -o $@ ${LDFLAGS}
run: run.c
${CC} ${CFLAGS} run.c -o $@ ${LDFLAGS}
reveal: reveal.c
${CC} ${CFLAGS} reveal.c -o $@ ${LDFLAGS}
usdw:
${RM} -f $@
${GREP} '^.....$$' ${DICTIONARY} | ${GREP} -v '[A-Z]' | ${GREP} -v beant > $@
spoiler: reveal fmt.c
@if test -x ${CLANG_FORMAT}; then ${CLANG_FORMAT} -style=file < prog.c | ./reveal; else ./reveal < fmt.c; fi
# 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 fmt.c fmt
######################################
# optional include of 1337 hacker rulz
######################################
-include 1337.mk ../1337.mk ../../1337.mk
+546
View File
@@ -0,0 +1,546 @@
## To build:
``` <!---sh-->
make all
```
## To use:
``` <!---sh-->
./prog dict
```
## Try:
``` <!---sh-->
./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)][1]
(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.
[1]: https://www.nytimes.com/games/wordle/index.html
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](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:
``` <!---sh-->
$ prog dict
? terns ybbbb
loath
? loath gbbyy
light
$
```
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][2],
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`][3].
NB: These videos are NOT spoilers for this algorithm.
[2]: https://www.youtube.com/watch?v=v68zYyaEmEA
[3]: https://www.youtube.com/watch?v=fRed0Xmc2Wg
`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](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 Sierpinski[4] number? What in the world is a Sierpinski number?
[4]: https://planetmath.org/sierpinskinumber
### 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](./2024_01_18_wordle_stats.png)
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.
```
$ ./prog dict
blast bbgyb
share gbgbb
spank gbgyb
xyzzy
$ ./prog /usr/share/dict/words
blast bbgyb
share gbgbb
spank gbgyb
snafu ggggg
```
And on June 9, 2023, again. This time, it cost nothing, and won on the
second guess.
```
$ ./prog dict
blast gyygb
xyzzy
$ ./prog /usr/share/dict/words
blast gyygb
balsa ggggg
```
June 19, 2023, another one wasn't working, so time for a better dictionary:
```
$ ./prog dict
blast bbybb
ramen bgbbb
vapid bgbbb
wacky bgbyb
xyzzy
# a copy of /usr/share/dict/words with five letters and no capitals:
grep '^.....$' /usr/share/dict/words | grep -v '[A-Z]' > ./usdw
$ ./prog usdw
blast bbybb
redan bbbyb
campo bgbbg
wahoo bgbgg
kazoo ggggg
```
As of June 19, 2023, it is known that at least these words have been added
(more are likely). Using `./usdw` as above, `prog` guesses these words in:
```
guano 3
snafu 4
balsa 2
kazoo 5
```
See the [extra.html](extra.html) for more details on the program `run`:
```
for n in guano snafu balsa kazoo; do
./run usdw blast $n;
done | grep good
```
As of April 22, 2024, add the word `laser` in 3 guesses.
```
$ ./prog usdw
blast byyyb
solea ybygy
laser ggggg
```
And May 8, 2024 brings on `pious` in 4 guesses (after the failure with `dict`):
```
$ prog dict
blast bbbyb
siren ygbbb
ficus bgbgg
xyzzy
$ prog usdw
? blast bbbyb
serio
? siren ygbbb
pisco
? ficus bgbgg
pious
? pious ggggg
```
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.
And Sep 17, 2024 brings us the word `beaut`.
```
$ prog dict
blast gbgbg
xyzzy
$ prog usdw
blast gbgbgb
beant -- not allowed, so removed beant from usdw
brant gbgbg
beaut ggggg
```
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.
Oct 9, 2024 brings the word `mommy`.
```
$ prog dict
blast bbbbb
drone bbybb
pouch bgbbb
foggy bgbbg
$ prog usdw
blast bbbbb
drone bbybb
pouch bgbbb
foggy bgbbg
mommy ggggg
```
Fortunately, the program is good enough that failing with one
dictionary still allows you to switch dictionaries and win.
Nov 13, 2024 brings `primp`.
```
$ ./prog dict
blast bbbbb
drone bgbbb
crimp bgggg
xyzzy
$ ./prog usdw
blast bbbbb
drone bgbbb
crimp bgggg
primp ggggg
```
Jan 20, 2025 brings the word `squid`.
```
$ ./prog dict
blast bbbyb
siren gybbb
skimp gbybb
sushi <<-- last plausible word
$ ./prog usdw
blast bbbyb
siren gybbb
skimp gbybb
sushi sgbby
squid ggggg
```
As of Jan 20, 2025, the ten known words not in `dict` are
(scores are using `usdw`, not `dict`, which lacks these words):
```
guano 4
snafu 5
balsa 3
kazoo 4
laser 3
pious 4
beaut 3
mommy 4
primp 5
squid 4
```
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:
```
-Wno-poison-system-directories \
-Wno-missing-variable-declarations \
-Wno-shadow \
-Wno-vla \
-Wno-missing-prototypes \
-Wno-shorten-64-to-32 \
-Wno-format-nonliteral \
-Wno-implicit-int-conversion \
-Wno-declaration-after-statement \
-Wno-comma \
-Wno-array-bounds-pointer-arithmetic \
-Wno-sign-conversion
```
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](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.
<!--
Copyright © 1984-2025 by Landon Curt Noll and Leonid A. Broukhis. 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/
-->
+7
View File
@@ -0,0 +1,7 @@
#!/usr/bin/env bash
awk '
/^guess1/ {if (w == "") w = $2 }
/good:/ {n++; t+=$5 }
/lose:/ {n++; L++ }
END {printf "%s %.06f %d\n",w,t/n,L }' $1
+14
View File
@@ -0,0 +1,14 @@
#!/usr/bin/env bash
a=$1
b=$2
if test $# -ne 2; then echo "usage: $0 result.a result.b" >&2; exit 1; fi
join $a $b | awk '
{
davg=$4-$2
dloss=$5-$3
print $0, davg, dloss
}
' | tabby
+3
View File
@@ -0,0 +1,3 @@
? amber
? adobe
? abode
+6
View File
@@ -0,0 +1,6 @@
? daunt
? haunt
? gaunt
? vaunt
? taunt
? jaunt
+2
View File
@@ -0,0 +1,2 @@
? loath
? light
+165
View File
@@ -0,0 +1,165 @@
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
typedef void q;
typedef int _;
typedef char p;
struct {
p a[257], b[9][5], c[5], d[5];
_ e, f;
} i;
p t[78557][5];
_ s, a[] = {
9, 9, 9, 10, 13, 18, 27, 39, 55, 1, 18, 2, 1, 1,
35, 2, 19, 18, 1, 52, 36, 35, 20, 3, 2, 19, 18, 18,
69, 2, 53, 1, 52, 37, 3, 20, 36, 19, 35, 18, 52, 86,
2, 53, 70, 1, 69, 38, /* 36 */ 4, 21, 3, 37, 19,
36, 35, 25, 10, 17, 15, 26, 9, 11, 12, 23, 2, 6, 18,
13, 20, 22, 14, 1, 24, 19, 21, 16, 5, 7, 4, 8, 3
} , u = ' ';
_ W(p *a, p *b) {
for (p *c = a + 5; a < c; )
*a++ = *b++;
return 0;
}
_ O(p *a, p b) {
p *c = a + 5;
for (; a < c && *a - b; )
++a;
return a < c ? 5 - (a - c) : 0;
}
_ R(p *a, ...) {
va_list b;
va_start(b, a);
vprintf(a, b);
exit(1);
}
q D(p *a) {
if (s == sizeof t / 5)
R("limit %d\n", s);
p *b = s[t], i, j;
for (i = j = 0; i < 7 && !j; ++i)
if (!(j = *a == 10 ? i : 0))
*b++ = u | *a++;
j - 5 || ++s;
}
q L(p *a, _ b) {
for (_ l = 0, o = 0, k; l < s; o = 0) {
for (_ j = 0; !o && j < 5 && (k = t[l][j]); ++j)
i.c[j] && k - i.c[j] && ++o;
for (_ j = 0; !o && j < 5 && (k = t[l][j]); ++j)
i.a[k] && ++o;
for (_ j = 0; !o && j < 5 && (k = t[l][j]); ++j)
i.d[j] && !O(t[l], i.d[j]) && ++o;
for (_ f = i.e; f-- && !o; )
for (_ j = 0; !o && j < 5 && (k = t[l][j]); ++j)
i.b[f][j] == k && ++o;
if (!o) {
for (_ j = 0; j < 5; ++j)
o += t[l][j] == a[j];
o = o == 5 ? b != 5 : 0;
}
o ? W(t[l], t[--s]) : ++l;
}
}
_ e(_ W, _ O, _ R, _ D, _ *L, _ *E) {
for (; O < D; )
L[R++] = E[O++ + D * W];
return R;
}
q S(_ O, _ *l) {
for (_ *s = &a[a[O]], *e = a[-~O] + s - a[O]; s < e; ) {
_ i = *s++,
j = i & 15,
k = l[i >>= 4] < l[j] ? k = l[i], l[i] = l[j], l[j] = k : i;
}
}
_ o(_ W, _ O, _ R, _ D, _ *L, _ *E) {
_ o = 0, w = 0;
for (; o < D & w < D; )
L[R++] = E[o + D * W] >= E[w + D * O]
? E[o++ + D * W]
: E[w++ + D * O];
return e(O, w, e(W, o, R, D, L, E), D, L, E);
}
q l(_ n, _ *f) {
for (_ *e = f + 26, i, j; f < e && *f > u; f += i) {
for (i = 1, j = *f / u; i < n && f[i] >> 5 == j; )
++i;
for (j = 0; j < i; ++j)
f[j] &= 31,
f[j] |= a[f[j] + a[~-9]] << 5;
S(i, f);
}
}
q v(_ a, _ *w, _ *k) {
o(2, 3, o(0, 1, 0, a, w, k), a, w, k);
o(0, 1, 0, a + a, k, w);
l(a, k);
}
p *E(p *d) {
_ l, j, k = u, b[u], c[k];
p *e[97][5] = { 0 } ;
for (l = 0; l < k; ++l)
c[l] = l;
for (l = 0; l < s; ++l)
for (_ j = 0; j < 5; ++j)
c[t[l][j] - 97] += k;
for (l = j = 7; j < 22; j += l)
S(l, c + j - l);
v(l, b, c);
for (l = 0; l < k; ++l)
b[c[l] & ~-k] = l;
for (k *= 3, l = 0; l < s; ++l) {
_ i = 0;
for (_ j = 0; j < 5; ++j)
i += b[t[l][j] - 97];
if (i < k)
for (_ j = 0; j < 5; ++j)
e[i][j] || (e[i][j] = t[l], j = 4);
}
for (l = 0; l < k; ++l)
for (p *b = 0, k = j = 0; j < 5 && (b = e[l][j]); k = !++j) {
p c[32] = { 0 } ;
d = *d - 120 ? d : b;
if (s > 2)
for (_ j = 0; j < 5; ++j)
k += ++c[b[j] - 97] > 1;
if (!k)
return b;
}
return d;
}
p *r(p *b) {
_ k, l;
for (_ j = k = l = 0; j < 5; ++j) {
signed char n = b[j], o = b[j - ~5] + ~0x66;
(o ? i.b[i.e] : i.c)[j] = n;
!o ? i.a[n] = !++k : O(i.d, n) || (*(o < 0 ? &i.a[n] : &i.d[i.f++]) = l = n);
}
i.e += !!l;
L(b, k);
return E("xyzzy");
}
_ main(_ n, char **v) {
p *j = i.c - 97, *l = j - 11;
n - 2 ? R("usage: %s dict\n", *v) : 5;
FILE *k = fopen(*++v, "r");
if (!k)
return perror(*v), 1;
while (fgets(j, u ^ n, k))
D(j);
fclose(k);
setbuf(stdout, 0);
while (~-s) {
printf("? ");
while (~(n = getchar()) && n - 10 && l < j)
*l++ = n;
l < j && R("input: guess color\n");
printf("%.5s\n", r(l = j + ~10));
}
return 0;
}
+814
View File
@@ -0,0 +1,814 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<!-- START: two lines up starts content from: inc/top.default.html -->
<!-- END: this line ends content from: inc/top.default.html -->
<!-- START: this line starts content from: inc/head.default.html -->
<head>
<link rel="stylesheet" href="../../ioccc.css">
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@100..900&display=swap" rel="stylesheet">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>The International Obfuscated C Code Contest</title>
<link rel="icon" type="image/x-icon" href="../../favicon.ico">
<meta name="description" content="deobfuscated.md for 2024/burton">
<meta name="keywords" content="IOCCC, 2024/burton, deobfuscated.md">
</head>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<!-- !!! DO NOT MODIFY THIS FILE - This file is generated by a tool !!! -->
<!-- !!! DO NOT MODIFY THIS FILE - This file is generated by a tool !!! -->
<!-- !!! DO NOT MODIFY THIS FILE - This file is generated by a tool !!! -->
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<!-- END: this line ends content from: inc/head.default.html -->
<!-- -->
<!-- This web page was formed via the tool: bin/gen-other-html.sh -->
<!-- The content of main section of this web page came from: 2024/burton/deobfuscated.md -->
<!-- -->
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<!-- !!! Do not modify this web page, instead modify the file: 2024/burton/deobfuscated.md !!! -->
<!-- !!! Do not modify this web page, instead modify the file: 2024/burton/deobfuscated.md !!! -->
<!-- !!! Do not modify this web page, instead modify the file: 2024/burton/deobfuscated.md !!! -->
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<!-- Markdown content was converted into HTML via the tool: bin/md2html.sh -->
<!-- START: this line starts content from: inc/body.default.html -->
<body>
<!-- END: this line ends content from: inc/body.default.html -->
<!-- START: this line starts content from: inc/topbar.default.html -->
<div class="theader">
<nav class="topbar">
<div class="container">
<div class="logo">
<a href="../../index.html" class="logo-link">
IOCCC
</a>
</div>
<div class="topbar-items">
<div class="item">
<span class="item-header">
Entries
</span>
<div class="sub-item">
<div class="outfit-font">
<a href="../../years.html" class="sub-item-link">
Winning entries
</a>
</div>
<div class="outfit-font">
<a href="../../authors.html" class="sub-item-link">
Winning authors
</a>
</div>
<div class="outfit-font">
<a href="../../location.html" class="sub-item-link">
Location of authors
</a>
</div>
<div class="outfit-font">
<a href="../../bugs.html" class="sub-item-link">
Bugs and (mis)features
</a>
</div>
<div class="outfit-font">
<a href="../../faq.html#fix_an_entry" class="sub-item-link">
Fixing entries
</a>
</div>
<div class="outfit-font">
<a href="../../faq.html#fix_author" class="sub-item-link">
Updating author info
</a>
</div>
</div>
</div>
<div class="item">
<span class="item-header">
Status
</span>
<div class="sub-item">
<div class="outfit-font">
<a href="../../news.html" class="sub-item-link">
News
</a>
</div>
<div class="outfit-font">
<a href="../../status.html" class="sub-item-link">
Contest status
</a>
</div>
<div class="outfit-font">
<a href="../../next/rules.html" class="sub-item-link">
IOCCC rules
</a>
</div>
<div class="outfit-font">
<a href="../../next/guidelines.html" class="sub-item-link">
IOCCC guidelines
</a>
</div>
<div class="outfit-font">
<a href="../../markdown.html" class="sub-item-link">
Markdown guidelines
</a>
</div>
<div class="outfit-font">
<a href="../../SECURITY.html" class="sub-item-link">
Security policy
</a>
</div>
</div>
</div>
<div class="item">
<span class="item-header">
FAQ
</span>
<div class="sub-item">
<div class="outfit-font">
<a href="../../faq.html" class="sub-item-link">
Frequently asked questions
</a>
</div>
<div class="outfit-font">
<a href="../../quick-start.html#enter" class="sub-item-link">
Enter the IOCCC
</a>
</div>
<div class="outfit-font">
<a href="../../faq.html#compiling" class="sub-item-link">
Compiling entries
</a>
</div>
<div class="outfit-font">
<a href="../../faq.html#running_entries" class="sub-item-link">
Running entries
</a>
</div>
<div class="outfit-font">
<a href="../../faq.html#help" class="sub-item-link">
How to help
</a>
</div>
</div>
</div>
<div class="item">
<span class="item-header">
About
</span>
<div class="sub-item">
<div class="outfit-font">
<a href="../../index.html" class="sub-item-link">
Home page
</a>
</div>
<div class="outfit-font">
<a href="../../social.html" class="sub-item-link">
IOCCC social media
</a>
</div>
<div class="outfit-font">
<a href="../../about.html" class="sub-item-link">
About the IOCCC
</a>
</div>
<div class="outfit-font">
<a href="../../judges.html" class="sub-item-link">
The judges
</a>
</div>
<div class="outfit-font">
<a href="../../thanks-for-help.html" class="sub-item-link">
Thanks for the help
</a>
</div>
<div class="outfit-font">
<a href="../../contact.html" class="sub-item-link">
Contact us
</a>
</div>
</div>
</div>
</div>
</div>
</nav>
<div class="header-mobile-menu">
<noscript>
<a href="../../nojs-menu.html" class="topbar-js-label">
Please Enable JavaScript
</a>
</noscript>
<button id="header-open-menu-button" class="topbar-mobile-menu">
<img
src="../../png/hamburger-icon-open.png"
alt="hamburger style menu icon - open state"
width=48
height=48>
</button>
<button id="header-close-menu-button" class="hide-content">
<img
src="../../png/hamburger-icon-closed.png"
alt="hamburger style menu icon - closed state"
width=48
height=48>
</button>
<div id="mobile-menu-panel" class="hide-content">
<div class="mobile-menu-container">
<div class="mobile-menu-wrapper">
<div class="mobile-menu-item">
Entries
</div>
<div class="mobile-submenu-wrapper">
<a class="mobile-submenu-item" href="../../years.html">
Winning entries
</a>
<a class="mobile-submenu-item" href="../../authors.html">
Winning authors
</a>
<a class="mobile-submenu-item" href="../../location.html">
Location of authors
</a>
<a class="mobile-submenu-item" href="../../bugs.html">
Bugs and (mis)features
</a>
<a class="mobile-submenu-item" href="../../faq.html#fix_an_entry">
Fixing entries
</a>
<a class="mobile-submenu-item" href="../../faq.html#fix_author">
Updating author info
</a>
<a class="mobile-submenu-item" href="../../thanks-for-help.html">
Thanks for the help
</a>
</div>
</div>
<div class="mobile-menu-wrapper">
<div class="mobile-menu-item">
Status
</div>
<div class="mobile-submenu-wrapper">
<a class="mobile-submenu-item" href="../../news.html">
News
</a>
<a class="mobile-submenu-item" href="../../status.html">
Contest status
</a>
<a class="mobile-submenu-item" href="../../next/rules.html">
IOCCC rules
</a>
<a class="mobile-submenu-item" href="../../next/guidelines.html">
IOCCC guidelines
</a>
<a class="mobile-submenu-item" href="../../markdown.html">
Markdown guidelines
</a>
<a class="mobile-submenu-item" href="../../SECURITY.html">
Security policy
</a>
</div>
</div>
<div class="mobile-menu-wrapper">
<div class="mobile-menu-item">
FAQ
</div>
<div class="mobile-submenu-wrapper">
<a class="mobile-submenu-item" href="../../faq.html">
Frequently asked questions
</a>
<a class="mobile-submenu-item" href="../../quick-start.html#enter">
Enter the IOCCC
</a>
<a class="mobile-submenu-item" href="../../faq.html#compiling">
Compiling entries
</a>
<a class="mobile-submenu-item" href="../../faq.html#running_entries">
Running entries
</a>
<a class="mobile-submenu-item" href="../../faq.html#help">
How to help
</a>
</div>
</div>
<div class="mobile-menu-wrapper">
<div class="mobile-menu-item">
About
</div>
<div class="mobile-submenu-wrapper">
<a class="mobile-submenu-item" href="../../index.html">
Home page
</a>
<a class="mobile-submenu-item" href="../../social.html">
IOCCC social media
</a>
<a class="mobile-submenu-item" href="../../about.html">
About the IOCCC
</a>
<a class="mobile-submenu-item" href="../../judges.html">
The judges
</a>
<a class="mobile-submenu-item" href="../../contact.html">
Contact us
</a>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
var headerOpenMenuButton = document.getElementById("header-open-menu-button");
var headerCloseMenuButton = document.getElementById("header-close-menu-button");
var mobileMenuPanel = document.getElementById("mobile-menu-panel");
headerOpenMenuButton.addEventListener("click", () => {
headerOpenMenuButton.classList.remove("topbar-mobile-menu");
headerOpenMenuButton.classList.add("hide-content");
headerCloseMenuButton.classList.remove("hide-content");
headerCloseMenuButton.classList.add("topbar-mobile-menu");
mobileMenuPanel.classList.remove("hide-content");
mobileMenuPanel.classList.add("topbar-mobile-panel");
});
headerCloseMenuButton.addEventListener("click", () => {
headerCloseMenuButton.classList.remove("topbar-mobile-menu");
headerCloseMenuButton.classList.add("hide-content");
mobileMenuPanel.classList.add("hide-content");
mobileMenuPanel.classList.remove("topbar-mobile-panel");
headerOpenMenuButton.classList.add("topbar-mobile-menu");
headerOpenMenuButton.classList.remove("hide-content");
});
</script>
<!-- END: this line ends content from: inc/topbar.default.html -->
<!-- START: this line starts content from: inc/header.default.html -->
<div class="header">
<a href="../../2011/zucker/index.html">
<img src="../../png/ioccc.png"
alt="IOCCC image by Matt Zucker"
width=300
height=110>
</a>
<h1>The International Obfuscated C Code Contest</h1>
<h2>deobfuscated.html for 2024/burton</h2>
</div>
<!-- END: this line ends content from: inc/header.default.html -->
<!-- START: this line starts content from: inc/navbar.up2index.html -->
<div class="navbar">
<a class="Left" href="index.html">&uarr; jump to 2024/burton/index.html &uarr;</a>
<a class="Right" href="https://validator.w3.org/nu/?doc=https%3A%2F%2Fwww.ioccc.org%2F2024%2Fburton%2Fdeobfuscated.html">&#x2713;</a>
</div>
<!-- END: this line ends content from: inc/navbar.up2index.html -->
<!-- START: this line starts content from: inc/before-content.default.html -->
<div class="content" id="content">
<!-- END: this line ends content from: inc/before-content.default.html -->
<!-- START: this line starts content for HTML phase 21 by: bin/pandoc-wrapper.sh via bin/md2html.sh -->
<!-- BEFORE: 1st line of markdown file: 2024/burton/deobfuscated.md -->
<h1 id="do-not-read-this-if-you-want-to-figure-it-out-yourself">Do not read this if you want to figure it out yourself!</h1>
<p>The file <code>deobfuscated.c</code> is simply a pretty-printed version of
<code>prog.c</code> with the macros expanded. It is hopefully just as
difficult to understand as the original presentation:
obfuscation is not just presentation, after all.</p>
<p>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 <code>deobfuscated.c</code>.</p>
<h2 id="read-dictionary">Read Dictionary</h2>
<p>The program begins by reading junk ;-) from the dictionary and processing
via <code>D()</code>. The words are stored in <code>t[][]</code>, counted by <code>s</code> and <code>D()</code> ensures
this never has buffer overflow. Notice the swap of index and array in <code>s[t]</code>.
It also ensures only 5 letter words are selected from the dictionary,
and folds uppercase to lowercase. Each call of <code>D()</code> handles one word.</p>
<p>NB: if the dictionary has, for instance, “ARRAY” and “array” and “Array”,
there will be 3 copies of “array” stored in <code>t[][]</code>.
This will degrade performance and may cause a malfunction of the algorithm,
and definitely if the target word is “array”. Thus the <code>makefile</code> builds
<code>usdw</code> with capital letters removed (avoiding this problem completely).
However, if there are duplicate words in the dictionary, use another.</p>
<h2 id="user-input">User Input</h2>
<p>After the dictionary is read, it is time to prompt the user for the
input guess. This happens in <code>main()</code>. The input buffer is the upper
half of <code>i.a</code>, which is never used (ASCII lowercase letters only).
The newline is ignored by <code>n - 10</code>, at most 11 characters (<code>l &lt; j</code>)
can be input, and EOF terminates the input loop.</p>
<p>Here is the explanation of how <code>i.c - 97</code> works to get an input buffer.
Assume <code>struct i</code> has the address 1000, then <code>i.a</code> begins at 1000.
<code>i.b</code> begins at 1257. <code>i.c</code> begins at 9*5 = 45 + 1257 = 1302.
1302 - 97 = 1205. Therefore, the <code>i.c - 97</code> sets the input buffer at
<code>&amp;i.a[205]</code>, ASCII lowercase input ends at <code>i.a[123]</code>, and there are
53 characters before <code>i.b</code> is overwritten - plenty of room for the user IO.
Why 97? The expression <code>x - 97</code> is used several times in the code,
leading to some confusion on the reason for the value.</p>
<p>Note that this abuse is what draws a compiler complaint, requiring:</p>
<pre><code> -Wno-array-bounds-pointer-arithmetic</code></pre>
<p>It is safe. It works. There is no problem here, but the compiler
does not know this.</p>
<h2 id="process-user-input">Process User Input</h2>
<p>Once the user input is received, the program calls <code>r()</code>, which populates
<code>struct i</code> 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). <code>r()</code> returns the next word
to guess via <code>E()</code> (aka choose() - see below).</p>
<p>Within <code>r()</code>, it is important to understand the ASCII values for g, y and b.</p>
<pre><code> b 98
g 103
y 121</code></pre>
<p>Within <code>r()</code>, <code>n</code> is the guessed letter, and <code>o</code> is color - 103.
If <code>o</code> 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).</p>
<p><code>struct i</code> can be re-written this way:</p>
<pre><code> 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;</code></pre>
<p>And <code>r()</code> can be rewritten:</p>
<pre><code> char *r(char *input) {
int num_green = 0, l = 0;
for (int j = 0; j &lt; 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 &lt; 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 &gt; 0 ? 1 : 0;
filter(input, num_green);
return choose(&quot;xyzzy&quot;);
}</code></pre>
<h2 id="filter">Filter</h2>
<p>The next step is to remove the impossible words from the in-memory dictionary.
This is handled by <code>L()</code>. <code>L()</code> iterates over all the remaining words in the
dictionary. <code>L()</code> 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
<code>o ? W(t[l], t[--s]) : ++l</code>. That is, if <code>o</code> is true, the word is replaced
by the end of the list, else the word is skipped. Note in particular the
expressions <code>--s</code> and <code>++l</code> (decrement and replace, or skip, respectively).</p>
<p>Said another way, think of <code>W()</code> as an analog of <code>strncpy()</code>. Thus, if <code>o</code>
is true, then <code>strncpy(t[l], t[--s], 5)</code>, 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 <code>t[s]</code>, but <code>t[s-1]</code>, thus the pre-decrement achieves
both the desired index and decrements the count.</p>
<h2 id="word-selection">Word Selection</h2>
<p>After the words are filtered, then comes the hard part: selecting which word
to guess next! This is handled by <code>E()</code>, by far the most interesting routine
in the code.</p>
<p>The loops in order:</p>
<ul>
<li>init <code>c[]</code> with ordinal values (a-z plus 6 slop) in the lower 5 bits</li>
<li>in the higher order bits, count the frequency of all remaining letters</li>
<li>sort by the frequency of letters in 3 sets of 7 (21 not 26!)</li>
<li>merge the separate sorts into one via <code>v()</code> (see below on merging)</li>
<li>for letters with same freq, re-sort by English frequency values <code>l()</code></li>
<li>using the sorted list, put the corresponding ordinals into <code>b[]</code></li>
<li>for each word, if scores below 97, put into <code>e[][]</code> (low score wins)</li>
<li>allow up to 5 duplicate scores, only keep first 5 words with same score</li>
<li>search the list for the lowest scoring word (best match)</li>
<li>if more than 2 words remain, find first word without duplicate letters</li>
<li>return whatever we found, if anything</li>
</ul>
<p>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.</p>
<h2 id="network-sort">Network Sort</h2>
<p>Network sort<a href="https://en.wikipedia.org/wiki/Sorting_network">1</a> is a simple, compact, constant time sort with minimal compares.</p>
<p>It is obfuscated in a number of ways.
The routine <code>S()</code> looks into the array <code>a[]</code> and determines the number of
elements to sort via the differences in the initial values of <code>a[]</code>.
Consider the possible number of values given in <code>O</code> from 0 (zero) to 7:
if <code>O</code> 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):</p>
<pre><code> O+1 O
a[1] - a[0] = 9 - 9 = 0
a[2] - a[1] = 9 - 9 = 0
a[3] - a[2] = 10 - 9 = 1</code></pre>
<p>If <code>O</code> 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 &gt; B, swap. If A &lt;= B, then no swap and the list is already ordered.</p>
<p>Where is this calculation done? Address arithmetic FTW!
<code>e = a[-~O] + s - a[O]</code>. <code>-~O</code> is the identity <code>O+1</code>.
So this expression restated is <code>e = s + a[O+1] - a[O]</code>.
If you look at the first numbers in <code>a[]</code> and their offsets (table 1):</p>
<pre><code> table 1
offsets: 0 1 2 3 4 5 6 7 8
values : 9 9 9 10 13 18 27 39 55</code></pre>
<p>You can see the expression selects for O in 0..7 (table 2):</p>
<pre><code> // 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</code></pre>
<p>What are we comparing? <code>s</code> ranges from <code>&amp;a[a[O]]</code> to <code>&amp;a[a[O+1]]</code>.</p>
<pre><code> O expr
0 9 - 9 = 0: no compares
1 9 - 9 = 0: no compares
2 10 - 9 = 1: &amp;a[a[9]] + 1 or the set { 1 }
3 13 - 10 = 3: &amp;a[a[10]] + 3 or the set { 18, 2, 1 }
4 18 - 13 = 5: &amp;a[a[13]] + 5 or the set { 1, 35, 2, 19, 18 }
...
7 55 - 39 = 16: &amp;a[a[39]] + 16 or the set
{ 18, 52, 86, 2, 53, 70, 1, 69,
38, 4, 21, 3, 37, 19, 36, 35 }</code></pre>
<p>So what do these numbers mean for sorting? Translate them to hex:</p>
<pre><code> { 0x12, 0x34, 0x56, 0x02, 0x35, 0x46, 0x01, 0x45,
0x26, 0x04, 0x15, 0x03, 0x25, 0x13, 0x24, 0x23 }</code></pre>
<p>This compact arrangement can be split into high and low nibbles:</p>
<pre><code> { (1,2), (3,4), (5,6), (0,2), (3,5), ... }</code></pre>
<p>which means compare and maybe swap (keeping order low to high):</p>
<pre><code> if (s[1] &gt; s[2]) swap();
if (s[3] &gt; s[4]) swap();
if (s[5] &gt; s[6]) swap();
if (s[0] &gt; s[2]) swap();
if (s[3] &gt; s[5]) swap();
....</code></pre>
<p>For instance, when sorting 7 elements, start from <code>a[a[7]]</code> (39) until
<code>a[a[8]]</code> (55), or 16 elements starting at <code>a[39]</code>.</p>
<h2 id="the-array-a-explained-finally">The Array a[] Explained, Finally</h2>
<p>The first set of 9 numbers are both the lengths AND the start and end indexes
into the array <code>a[]</code>, 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).</p>
<p>This final set of letters is used in the routine <code>l()</code>. Notice the expression:
<code>a[f[j] + a[~-9]]</code>; <code>a[~-9]</code> is an obscure way of writing <code>a[8]</code>, which is the
value 55. So <code>a[f[j]]</code> is an index into this frequency array, offset by 55.
Why is there a <code>&lt;&lt; 5</code>? Again, the letter offsets are in the lowest 5 bits,
and the counts of the letters is in the upper bits.</p>
<p>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.</p>
<h2 id="merge-sort">Merge Sort</h2>
<p>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 <code>v()</code>, which calls <code>o()</code> 3 times, once recursively.
This is followed by a rearrangement handled in <code>l()</code>. This last step finds
all the letters with the same frequency, then sorts them according to their
English frequency.</p>
<p>Back to the merge sort, which is really handled in <code>o()</code>. This is rather
difficult to follow. The first call to <code>o()</code> 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 <code>v()</code> was called with <code>v(l=7, w=b, k=c)</code>.
This first merge pass copies to: <code>L[R]</code> (<code>b[0]</code>) and selects from either
<code>c[o]</code> or <code>c[w]</code> 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 <code>o()</code>, the last two arguments are swapped, which puts the final sort
into <code>c[]</code>.</p>
<p>Below is a hopefully easier way to read the merge sort code:</p>
<pre><code> // merge residual
int e(int mult_o, int start, int to, int off, int *a1, int *a2)
{
for (; start &lt; 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 &lt; len &amp;&amp; w &lt; len; ) {
// first call: to=0, len=7, mult_o=0, mult_w=1
// a1[0++] = a2[0 + 7*0] &gt;= a2[0 + 7*1]
// ? a2[0 + 7*0] : a2[0 + 7*1]
// a1[0++] = a2[0] &gt; a2[7] ? a[0++] : a2[7++]
// second call: to=14, len=7, mult_o=2, mult_w=3
// a1[14++] = a2[0 + 7*2] &gt;= a2[0 + 7*3]
// ? a2[0 + 7*2] : a2[0 + 7*3]
// a1[14++] = a2[14] &gt; a2[21] ? a2[14++] : a2[21++]
// third call: to=0, len=14, mult_o=0, mult_w=1
// a1[0++] = a2[0 + 14*0] &gt;= a2[0 + 14*1]
// ? a2[0 + 14*0] : a2[0 + 14*1];
// a1[0++] = a[0] &gt;= a2[14] ? a2[0++] : a2[14++]
a1[to++] = a2[o + len * mult_o] &gt;= 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);
}</code></pre>
<p>Isn’t that as clear as mud? It is far easier to understand the flow when
you add <code>printf()</code> statements to follow the logic. Included is the file
<code>deobfuscated.c</code> for you to start with.</p>
<h2 id="why-name-the-functions-as-they-are">Why name the functions as they are?</h2>
<p>Run <code>make spoiler</code>.</p>
<h2 id="bug-explained">Bug Explained</h2>
<p>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 <code>y</code>).
But some words do have <code>y</code> in them, which is why the merge sort takes 28
letters (including the ASCII values <code>{</code> and <code>|</code>), 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.</p>
<p>If you change the loop value <code>22</code> to <code>32</code>, 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.</p>
<p>If you change any values in the array <code>a[]</code>,
the program will no longer work correctly.</p>
<p>Finally, what is the significance of the array size 78557?
<code>usdw</code> only needs 8506. Why was such a large value used?
<!-- AFTER: last line of markdown file: 2024/burton/deobfuscated.md --></p>
<!-- END: this line ends content for HTML phase 21 by: bin/pandoc-wrapper.sh via bin/md2html.sh -->
<!-- START: this line starts content from: inc/after-content.default.html -->
</div>
<!-- END: this line ends content from: inc/after-content.default.html -->
<!-- START: this line starts content from: inc/footer.default.html -->
<!--
Copyright © 1984-2025 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/
-->
<div class="footer">
<div id="copyright"><h3>Copyright &copy; 1984-2025 by Landon Curt Noll:
<a href="https://creativecommons.org/faq/#what-does-some-rights-reserved-mean"
target="_blank"
rel="license noopener noreferrer">Some Rights Reserved</a></h3>
<p>
This work is <b>licensed by Landon Curt Noll</b> under
<b><a href="https://creativecommons.org/licenses/by-sa/4.0/?ref=chooser-v1"
target="_blank"
rel="license noopener noreferrer"
style="display:inline-block;">CC BY-SA 4.0</a></b>.
<img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;"
src="../../png/cc.png"
alt="cc inside circle symbol">
<img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;"
src="../../png/by.png"
alt="person inside circle symbol">
<img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;"
src="../../png/sa.png"
alt="arrow looping back on itself inside circle symbol"><br>
You should <b>carefully review</b> the
<b><a href="https://creativecommons.org/licenses/by-sa/4.0/legalcode.en"
target="_blank"
rel="license noopener noreferrer">CC BY-SA 4.0 LEGAL CODE</a></b>
before using the licensed material.<br>
You may wish to review the
<b><a href="../../license.html"
target="_blank"
rel="license noopener noreferrer">highlights of some of the key features and terms</a></b>
of <b>CC BY-SA 4.0</b>.<br>
</p>
</div>
<div id="coda"><h3>Coda</h3>
<p>
<a href="https://validator.w3.org/nu/?doc=https%3A%2F%2Fwww.ioccc.org%2F2024%2Fburton%2Fdeobfuscated.html" rel="nofollow">Nu HTML check this web page</a><br>
<a href="#top">Jump to top</a> <a href="#content">Jump to Content</a>
</p>
</div>
</div>
<!-- END: this line ends content from: inc/footer.default.html -->
<!-- START: this line starts content from: inc/bottom.default.html -->
</body>
</html>
<!-- END: this line ends content from: inc/bottom.default.html -->
+382
View File
@@ -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:
``` <!---c-->
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:
``` <!---c-->
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):
``` <!---c-->
// 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:
``` <!---c-->
{ 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):
``` <!---c-->
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:
``` <!---c-->
// 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?
+2315
View File
File diff suppressed because it is too large. Load diff
+29
View File
@@ -0,0 +1,29 @@
/*
* usage: dups [-n] [len]
*/
#include <stdio.h>
#include <stdlib.h>
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;
}
+36
View File
@@ -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
+887
View File
@@ -0,0 +1,887 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<!-- START: two lines up starts content from: inc/top.default.html -->
<!-- END: this line ends content from: inc/top.default.html -->
<!-- START: this line starts content from: inc/head.default.html -->
<head>
<link rel="stylesheet" href="../../ioccc.css">
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@100..900&display=swap" rel="stylesheet">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>The International Obfuscated C Code Contest</title>
<link rel="icon" type="image/x-icon" href="../../favicon.ico">
<meta name="description" content="extra.md for 2024/burton">
<meta name="keywords" content="IOCCC, 2024/burton, extra.md">
</head>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<!-- !!! DO NOT MODIFY THIS FILE - This file is generated by a tool !!! -->
<!-- !!! DO NOT MODIFY THIS FILE - This file is generated by a tool !!! -->
<!-- !!! DO NOT MODIFY THIS FILE - This file is generated by a tool !!! -->
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<!-- END: this line ends content from: inc/head.default.html -->
<!-- -->
<!-- This web page was formed via the tool: bin/gen-other-html.sh -->
<!-- The content of main section of this web page came from: 2024/burton/extra.md -->
<!-- -->
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<!-- !!! Do not modify this web page, instead modify the file: 2024/burton/extra.md !!! -->
<!-- !!! Do not modify this web page, instead modify the file: 2024/burton/extra.md !!! -->
<!-- !!! Do not modify this web page, instead modify the file: 2024/burton/extra.md !!! -->
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<!-- Markdown content was converted into HTML via the tool: bin/md2html.sh -->
<!-- START: this line starts content from: inc/body.default.html -->
<body>
<!-- END: this line ends content from: inc/body.default.html -->
<!-- START: this line starts content from: inc/topbar.default.html -->
<div class="theader">
<nav class="topbar">
<div class="container">
<div class="logo">
<a href="../../index.html" class="logo-link">
IOCCC
</a>
</div>
<div class="topbar-items">
<div class="item">
<span class="item-header">
Entries
</span>
<div class="sub-item">
<div class="outfit-font">
<a href="../../years.html" class="sub-item-link">
Winning entries
</a>
</div>
<div class="outfit-font">
<a href="../../authors.html" class="sub-item-link">
Winning authors
</a>
</div>
<div class="outfit-font">
<a href="../../location.html" class="sub-item-link">
Location of authors
</a>
</div>
<div class="outfit-font">
<a href="../../bugs.html" class="sub-item-link">
Bugs and (mis)features
</a>
</div>
<div class="outfit-font">
<a href="../../faq.html#fix_an_entry" class="sub-item-link">
Fixing entries
</a>
</div>
<div class="outfit-font">
<a href="../../faq.html#fix_author" class="sub-item-link">
Updating author info
</a>
</div>
</div>
</div>
<div class="item">
<span class="item-header">
Status
</span>
<div class="sub-item">
<div class="outfit-font">
<a href="../../news.html" class="sub-item-link">
News
</a>
</div>
<div class="outfit-font">
<a href="../../status.html" class="sub-item-link">
Contest status
</a>
</div>
<div class="outfit-font">
<a href="../../next/rules.html" class="sub-item-link">
IOCCC rules
</a>
</div>
<div class="outfit-font">
<a href="../../next/guidelines.html" class="sub-item-link">
IOCCC guidelines
</a>
</div>
<div class="outfit-font">
<a href="../../markdown.html" class="sub-item-link">
Markdown guidelines
</a>
</div>
<div class="outfit-font">
<a href="../../SECURITY.html" class="sub-item-link">
Security policy
</a>
</div>
</div>
</div>
<div class="item">
<span class="item-header">
FAQ
</span>
<div class="sub-item">
<div class="outfit-font">
<a href="../../faq.html" class="sub-item-link">
Frequently asked questions
</a>
</div>
<div class="outfit-font">
<a href="../../quick-start.html#enter" class="sub-item-link">
Enter the IOCCC
</a>
</div>
<div class="outfit-font">
<a href="../../faq.html#compiling" class="sub-item-link">
Compiling entries
</a>
</div>
<div class="outfit-font">
<a href="../../faq.html#running_entries" class="sub-item-link">
Running entries
</a>
</div>
<div class="outfit-font">
<a href="../../faq.html#help" class="sub-item-link">
How to help
</a>
</div>
</div>
</div>
<div class="item">
<span class="item-header">
About
</span>
<div class="sub-item">
<div class="outfit-font">
<a href="../../index.html" class="sub-item-link">
Home page
</a>
</div>
<div class="outfit-font">
<a href="../../social.html" class="sub-item-link">
IOCCC social media
</a>
</div>
<div class="outfit-font">
<a href="../../about.html" class="sub-item-link">
About the IOCCC
</a>
</div>
<div class="outfit-font">
<a href="../../judges.html" class="sub-item-link">
The judges
</a>
</div>
<div class="outfit-font">
<a href="../../thanks-for-help.html" class="sub-item-link">
Thanks for the help
</a>
</div>
<div class="outfit-font">
<a href="../../contact.html" class="sub-item-link">
Contact us
</a>
</div>
</div>
</div>
</div>
</div>
</nav>
<div class="header-mobile-menu">
<noscript>
<a href="../../nojs-menu.html" class="topbar-js-label">
Please Enable JavaScript
</a>
</noscript>
<button id="header-open-menu-button" class="topbar-mobile-menu">
<img
src="../../png/hamburger-icon-open.png"
alt="hamburger style menu icon - open state"
width=48
height=48>
</button>
<button id="header-close-menu-button" class="hide-content">
<img
src="../../png/hamburger-icon-closed.png"
alt="hamburger style menu icon - closed state"
width=48
height=48>
</button>
<div id="mobile-menu-panel" class="hide-content">
<div class="mobile-menu-container">
<div class="mobile-menu-wrapper">
<div class="mobile-menu-item">
Entries
</div>
<div class="mobile-submenu-wrapper">
<a class="mobile-submenu-item" href="../../years.html">
Winning entries
</a>
<a class="mobile-submenu-item" href="../../authors.html">
Winning authors
</a>
<a class="mobile-submenu-item" href="../../location.html">
Location of authors
</a>
<a class="mobile-submenu-item" href="../../bugs.html">
Bugs and (mis)features
</a>
<a class="mobile-submenu-item" href="../../faq.html#fix_an_entry">
Fixing entries
</a>
<a class="mobile-submenu-item" href="../../faq.html#fix_author">
Updating author info
</a>
<a class="mobile-submenu-item" href="../../thanks-for-help.html">
Thanks for the help
</a>
</div>
</div>
<div class="mobile-menu-wrapper">
<div class="mobile-menu-item">
Status
</div>
<div class="mobile-submenu-wrapper">
<a class="mobile-submenu-item" href="../../news.html">
News
</a>
<a class="mobile-submenu-item" href="../../status.html">
Contest status
</a>
<a class="mobile-submenu-item" href="../../next/rules.html">
IOCCC rules
</a>
<a class="mobile-submenu-item" href="../../next/guidelines.html">
IOCCC guidelines
</a>
<a class="mobile-submenu-item" href="../../markdown.html">
Markdown guidelines
</a>
<a class="mobile-submenu-item" href="../../SECURITY.html">
Security policy
</a>
</div>
</div>
<div class="mobile-menu-wrapper">
<div class="mobile-menu-item">
FAQ
</div>
<div class="mobile-submenu-wrapper">
<a class="mobile-submenu-item" href="../../faq.html">
Frequently asked questions
</a>
<a class="mobile-submenu-item" href="../../quick-start.html#enter">
Enter the IOCCC
</a>
<a class="mobile-submenu-item" href="../../faq.html#compiling">
Compiling entries
</a>
<a class="mobile-submenu-item" href="../../faq.html#running_entries">
Running entries
</a>
<a class="mobile-submenu-item" href="../../faq.html#help">
How to help
</a>
</div>
</div>
<div class="mobile-menu-wrapper">
<div class="mobile-menu-item">
About
</div>
<div class="mobile-submenu-wrapper">
<a class="mobile-submenu-item" href="../../index.html">
Home page
</a>
<a class="mobile-submenu-item" href="../../social.html">
IOCCC social media
</a>
<a class="mobile-submenu-item" href="../../about.html">
About the IOCCC
</a>
<a class="mobile-submenu-item" href="../../judges.html">
The judges
</a>
<a class="mobile-submenu-item" href="../../contact.html">
Contact us
</a>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
var headerOpenMenuButton = document.getElementById("header-open-menu-button");
var headerCloseMenuButton = document.getElementById("header-close-menu-button");
var mobileMenuPanel = document.getElementById("mobile-menu-panel");
headerOpenMenuButton.addEventListener("click", () => {
headerOpenMenuButton.classList.remove("topbar-mobile-menu");
headerOpenMenuButton.classList.add("hide-content");
headerCloseMenuButton.classList.remove("hide-content");
headerCloseMenuButton.classList.add("topbar-mobile-menu");
mobileMenuPanel.classList.remove("hide-content");
mobileMenuPanel.classList.add("topbar-mobile-panel");
});
headerCloseMenuButton.addEventListener("click", () => {
headerCloseMenuButton.classList.remove("topbar-mobile-menu");
headerCloseMenuButton.classList.add("hide-content");
mobileMenuPanel.classList.add("hide-content");
mobileMenuPanel.classList.remove("topbar-mobile-panel");
headerOpenMenuButton.classList.add("topbar-mobile-menu");
headerOpenMenuButton.classList.remove("hide-content");
});
</script>
<!-- END: this line ends content from: inc/topbar.default.html -->
<!-- START: this line starts content from: inc/header.default.html -->
<div class="header">
<a href="../../2011/zucker/index.html">
<img src="../../png/ioccc.png"
alt="IOCCC image by Matt Zucker"
width=300
height=110>
</a>
<h1>The International Obfuscated C Code Contest</h1>
<h2>extra.html for 2024/burton</h2>
</div>
<!-- END: this line ends content from: inc/header.default.html -->
<!-- START: this line starts content from: inc/navbar.up2index.html -->
<div class="navbar">
<a class="Left" href="index.html">&uarr; jump to 2024/burton/index.html &uarr;</a>
<a class="Right" href="https://validator.w3.org/nu/?doc=https%3A%2F%2Fwww.ioccc.org%2F2024%2Fburton%2Fextra.html">&#x2713;</a>
</div>
<!-- END: this line ends content from: inc/navbar.up2index.html -->
<!-- START: this line starts content from: inc/before-content.default.html -->
<div class="content" id="content">
<!-- END: this line ends content from: inc/before-content.default.html -->
<!-- START: this line starts content for HTML phase 21 by: bin/pandoc-wrapper.sh via bin/md2html.sh -->
<!-- BEFORE: 1st line of markdown file: 2024/burton/extra.md -->
<h1 id="extra">extra</h1>
<p>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.</p>
<p>The recommendation is to do:</p>
<pre><code> 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 &quot;terns&quot; to results
./mkresults &gt; results.avg # proc exhaust into a single, small file</code></pre>
<p>The files created as output from <code>exhaust</code> allow one to view, for each
starting word, how each of the solutions resolve, including the misses.
<code>mkresults</code> 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 <code>rank</code> on the desired word:</p>
<pre><code> ./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</code></pre>
<p>The C programs allow for (automated) testing:</p>
<pre><code> 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</code></pre>
<h2 id="using-more-guesses">Using More Guesses</h2>
<p>If you wish to see the failed words in action, and if more guesses would
work, try:</p>
<pre><code> ./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</code></pre>
<p>Using <code>GUESSES=9</code> and <code>exhaust</code>, 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.</p>
<p>Ranking by fewest missed with GUESSES=6, the order is:</p>
<pre><code> blast palsy climb flash lapse</code></pre>
<p>Ranking by average with GUESSES=6, the order is:</p>
<pre><code> crate slate trace crane least</code></pre>
<p>Ranking by average with GUESSES=9, the order is:</p>
<pre><code> slate trace crate train least</code></pre>
<p>To reproduce these results:</p>
<pre><code> GUESSES=9 ./exhaust results.9
./mkresults results.9 &gt; results.9.avg</code></pre>
<h2 id="simple-analysis">Simple Analysis</h2>
<p>The 1566 raw files produced by <code>exhaust</code> 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 <code>results.avg</code>.</p>
<pre><code> blast fewest missed
crate best average
query most missing
terns example used in remarks</code></pre>
<p>The program <code>rank</code> allows one to see how the averages are calculated, as well
as the actual missed words. Comparing the results for <code>blast</code> and <code>terns</code>:</p>
<pre><code> ./rank r.terns | awk &#39;NF==2&#39; &gt; a
./rank r.blast | awk &#39;NF==2&#39; &gt; 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)</code></pre>
<p>In general, the program <code>avg</code> is easier to use, but conveys less information:</p>
<pre><code> ./avg r.terns; ./avg r.blast
terns 3.641469 18
blast 3.673002 4</code></pre>
<p>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.</p>
<p>It is interesting that the letter order makes a noticeable difference:</p>
<pre><code> ./avg r.terns; ./avg results/stern
terns 3.641469 18 # lower average and fewer misses
stern 3.658315 20</code></pre>
<p>For completeness, using <code>GUESSES=9</code> and the full starting dictionary from
Wordle(tm), here are the results for the “best” starting words: <code>salet</code>,
<code>slate</code>, and <code>blast</code>.</p>
<pre><code> 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</code></pre>
<p>Obviously, <code>salet</code> produces the best results, excepting the losses (14).
Just re-arranging the letters into <code>slate</code> produces almost the same,
but there are more losses (18). If attempting to minimize losses,
then <code>blast</code> 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.</p>
<p>NB: The averages for <code>GUESSES=9</code> 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?).</p>
<h2 id="seek-these">Seek These</h2>
<p>The starting words with the fewest misses with <code>dict</code>:</p>
<pre><code> sort -k3n results.avg | sed 18q | awk &#39;{print $1, $3}&#39; | 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</code></pre>
<p>Versus starting words with fewest misses:</p>
<pre><code> egrep &#39;terns|lapse|blast|climb|crate&#39; 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)</code></pre>
<p>Notice the difference in the average and weighted average. The program
<code>avg</code> simply takes the total guesses as a percentage of the total words.
The program <code>wavg</code> takes each of the six scores and weights them by the
score. I wrote <code>wavg</code> later to track my progress playing the online game,
and it is a more accurate score IMHO, but both are useful for comparisons.</p>
<pre><code> $ ./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</code></pre>
<p>The program <code>wrank</code> (weighted rank) makes this latter calculation much easier.
It takes the output from <code>rank</code> and invokes <code>wavg</code> with these numbers,
saving a lot of typing and errors.</p>
<pre><code> ./wrank blast
blast 3.6794</code></pre>
<p>In words, <code>crate</code> 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 <code>prog</code> recommend your next guess.</p>
<p>A somewhat laborious calculation provides the answer to which starting word
has the most answers in two words and three words:</p>
<pre><code> # two words
for n in results/*; do
rank $n | awk -v word=$n &#39;/^2/ {print word,$2}&#39;;
done | sort -k2nr | sed 3q
trace 149
crate 147
slate 146
# three words
for n in results/*; do
rank $n | awk -v word=$n &#39;/^3/ {print word,$2}&#39;;
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</code></pre>
<h2 id="avoid-these">Avoid These</h2>
<p>The starting words with the worst accuracy:</p>
<pre><code> 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</code></pre>
<p>The starting words with the most failures (missed words):</p>
<pre><code> 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</code></pre>
<p>The worst target words, for any starting word (N out of 1566):</p>
<pre><code> ./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</code></pre>
<h2 id="spoiler-deep-dive-on-near-misses-spoiler">SPOILER Deep Dive on Near Misses SPOILER</h2>
<p>Dissecting the failed targets when starting with <code>blast</code>. Recall <code>blast</code>
only misses 4 words out of all 2315:</p>
<pre><code> foyer jaunt shave wound</code></pre>
<p>These four words have common sub-patterns, which in hard-mode is difficult
to disambiguate. Using <code>run dict blast $word</code>, here are the grep sub-patterns
and counts for these four words as revealed in the output:</p>
<pre><code> foyer 25 grep &#39;^.o.er&#39; dict | wc -l
jaunt 6 grep &#39;^.aunt&#39; dict | wc -l
shave 7 grep &#39;^sha.e&#39; dict | wc -l
wound 8 grep &#39;^.ound&#39; dict | wc -l</code></pre>
<p>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 <code>blast</code> 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.</p>
<p>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
<code>grep</code> command lines, although there are additional insights used within
the program that improve significantly upon these results.</p>
<pre><code> ./run dict blast foyer | grep ^gen
gen: target: foyer 2315
gen: blast bbbbb 429 grep -v &#39;[blast]&#39; dict | wc -l
gen: drone byyby 27 grep r dict | grep o | grep e | grep -v &#39;[blastdn]&#39; | wc -l
gen: cower bgbgg 8 grep &#39;^.o.er&#39; dict | grep -v &#39;[blastdncw]&#39;
foyer homer hover joker
mover poker roger rover
gen: mover bgbgg 4 grep &#39;.o.er&#39; dict | grep -v &#39;[blastdncwmv]&#39;
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 &#39;t$&#39; dict | grep a | grep -v &#39;[bls]&#39; | wc -l
gen: daunt bgggg 5 grep &#39;^.aunt$&#39; dict | grep -v &#39;[blsd]&#39;
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 &#39;^..a&#39; dict | grep s | grep -v &#39;[blt]&#39; | wc -l
gen: share gggbg 5 grep &#39;^sha.e&#39; dict | grep -v &#39;[bltr]&#39;
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 &#39;[blast]&#39; dict | wc -l
gen: drone ybygb 7 grep &#39;n.$&#39; dict | grep d | grep o | grep -v &#39;[blastre]&#39; | wc -l
gen: pound bgggg 4 grep &#39;^.ound&#39; dict | grep -v &#39;[blastreh]&#39;
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</code></pre>
<!-- AFTER: last line of markdown file: 2024/burton/extra.md -->
<!-- END: this line ends content for HTML phase 21 by: bin/pandoc-wrapper.sh via bin/md2html.sh -->
<!-- START: this line starts content from: inc/after-content.default.html -->
</div>
<!-- END: this line ends content from: inc/after-content.default.html -->
<!-- START: this line starts content from: inc/footer.default.html -->
<!--
Copyright © 1984-2025 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/
-->
<div class="footer">
<div id="copyright"><h3>Copyright &copy; 1984-2025 by Landon Curt Noll:
<a href="https://creativecommons.org/faq/#what-does-some-rights-reserved-mean"
target="_blank"
rel="license noopener noreferrer">Some Rights Reserved</a></h3>
<p>
This work is <b>licensed by Landon Curt Noll</b> under
<b><a href="https://creativecommons.org/licenses/by-sa/4.0/?ref=chooser-v1"
target="_blank"
rel="license noopener noreferrer"
style="display:inline-block;">CC BY-SA 4.0</a></b>.
<img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;"
src="../../png/cc.png"
alt="cc inside circle symbol">
<img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;"
src="../../png/by.png"
alt="person inside circle symbol">
<img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;"
src="../../png/sa.png"
alt="arrow looping back on itself inside circle symbol"><br>
You should <b>carefully review</b> the
<b><a href="https://creativecommons.org/licenses/by-sa/4.0/legalcode.en"
target="_blank"
rel="license noopener noreferrer">CC BY-SA 4.0 LEGAL CODE</a></b>
before using the licensed material.<br>
You may wish to review the
<b><a href="../../license.html"
target="_blank"
rel="license noopener noreferrer">highlights of some of the key features and terms</a></b>
of <b>CC BY-SA 4.0</b>.<br>
</p>
</div>
<div id="coda"><h3>Coda</h3>
<p>
<a href="https://validator.w3.org/nu/?doc=https%3A%2F%2Fwww.ioccc.org%2F2024%2Fburton%2Fextra.html" rel="nofollow">Nu HTML check this web page</a><br>
<a href="#top">Jump to top</a> <a href="#content">Jump to Content</a>
</p>
</div>
</div>
<!-- END: this line ends content from: inc/footer.default.html -->
<!-- START: this line starts content from: inc/bottom.default.html -->
</body>
</html>
<!-- END: this line ends content from: inc/bottom.default.html -->
+471
View File
@@ -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:
``` <!---sh-->
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:
``` <!---sh-->
./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.
``` <!---sh-->
$ ./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.
``` <!---sh-->
./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
```
+13
View File
@@ -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
+15
View File
@@ -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
+86
View File
@@ -0,0 +1,86 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
/*
* 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;
}
File diff suppressed because it is too large. Load diff
+8
View File
@@ -0,0 +1,8 @@
#!/usr/bin/env bash
dir=$1
: ${dir:=results}
for name in $dir/*; do
./avg $name
done | sed "s#$dir/##" | tr : ' '
+64
View File
@@ -0,0 +1,64 @@
#include <stdarg.h>
#include <stdlib.h>
# include <stdio.h>
#define J(J) for (\
_ j=0; j<5; ++j) J;
#define/*IOCCC*/I \
\
\
\
_ W,_ O,_ R,_ D,_*L,_*E
#define A(A )for(_ j=0; !o&&j<5&&(k = t[l][j]); ++j)A&&++o;
typedef/* ; ; */void q; typedef int _ ; typedef char/* */p;
struct{ p a [257],b[9][ 5],c[5],d[5 ]; _ e,f; } i;p t[78557
][5]; _ s,a []={ 9,9,9, 10,13,18,27 ,39,55,1,18 ,2,1,1,35,2
,19,18,1,52 ,36,35,20,3 ,2,19,18,18 ,69,2,53,1, 52,37,3,20,
36,19,35,18 ,52,86,2,53 ,70,1,69,38 ,4,21,3,37, 19,36,35,25
,10,+17,15, 26,9,11,12, 23,2,06,18, 13,20,22,14 ,1,24,19,21
,16,5,7,4,8 ,3},u=' ';_ W(p*a,p*b){ for(p*c=a+5 ;a<c;)*a++=
*b++;return 0; } _ O(p* a,p b){ p*c =a+5; for(; a<c&&*a-b;)
++a; return a<c?5-(a-c) :0; } _ R(p *a, ... ) { va_list b ;
va_start(b, a); vprintf (a,b); exit (1); } q D( p*a){ if (s
==sizeof t/ 5)R("limit" " %d\n",s); p*b=s[t],i, j; for(i=j=
0; i<7&&!j; ++i)if(!(j= *a==10?i:0) )*b++=u|* a ++; j-5||++
s; } q L(p* a,_ b){ for (_ l=0,o=0, k; l<s; o=0 ){ A(i.c[j]
&&k-i.c[j]) A(i.a[k])A( i.d[j]&&!O( t[l],i.d[j] ))for(_ f=i
.e; f--&&!o ; )A(i.b[f] [j]==k)if(! o){ J(o+=t[ l][j]==a[j]
)o=o==5?b!= 5:0; } o?W( t[l],t[--s] ) :++l; } } _ e(I){ for
(; O<D; )L[ R++]=E[O+++ D*W];return R; } q S( _ O,_*l){ for
(_*s=&a[a[O ]],*e=a[-~O ]+s-a[O]; s <e; ){ _ i= *s++,j=i&15
,k=l[i>>=4] <l[+j]?k=l[ i],l[i]=l[j ],l[j]=k:i; } } _ o(I){
_ o=0, w=0; for(; o<D&w <D; )L[R++] =E[o+D*W]>= E[w+D*O]?E[
o+++D*W]:E[ w +++ D*O]; return e(O, w,e(W,o,R,D ,L,E),D,L,E
); } q l( _ n,_*f){ for (_* e=f+26, i,j; f<e&&* f>u; f+= i)
{ for(i=1,j =*f/u; i <n &&f[i]>>5== j; )++i;for (j=0; j <i;
++j)f[j] &= 31,f[j]|=a[ f[j]+a[~-9] ]<<5; S(i,f ); } } q v(
_ a,_*w,_*k ){ o(2,3,o( 0,1,0,a,w,k ),a,w,k); o (0,1,0,a+a,
k,w); l(a,k ); } p*E(p* d){ _ l,j,k =u,b[u] ,c[ k]; p*e[97]
[5 ]={ 0} ; for(l=0; l< k; ++l)c[l] =l; for(l=0 ; l<s; ++l)
J(c[t[l][j] -97]+=k)for (l= j=7; j< 22; j+=l)S( l,c+j-l); v
(l,b,c);for (l= 0; l<k; ++l)b[c[l]& ~-k]=l; for (k*=3,l= 0;
l<s; ++l) { _ i=0; J( i +=b[t[l][j] -97])if(i<k )J(e[i][ j]
||(e[i][j]= t[l],j=4))} for(l=0; l< k; ++l)for( p*b=0,k=j=0
; j<5&&(b=e [l][j]); k= !++j){ p c[ 32]={0} ; d =*d-120?d:b
; if(s>2)J( k+=++c[b[j] -97]>1); if (!k) return b; } return
d; } p*r(p* b){ _ k, l; for(_ j=k=l =0; j<5; ++ j) { signed
char n=b[j] ,o=b[j-~5]+ ~0x66; (o?i .b[i.e]:i.c )[j]=n; !o?
i.a[n]=!++k :O(i.d,n)|| (*(o<0?&i.a [n]:&i.d[i. f++])=l=n);
} i.e += !! l; L(b, k); return E("" "xyzzy"); } _ main(_ n,
char**v){ p *j=i .c-97, *l=j-11; n- 2?R("usage" ": %s dict"
"\n",* v):5 ; ; FILE*k= fopen(*++v, "r"); if(!k ) return //
perror(*v), 1; ; while( fgets(j, u^ n,k)) D(j); fclose (k);
; ; setbuf( stdout, 0); while(~-s){ printf("? " ); while(~(
n=getchar() )&&n-10&&l< j)*l++=n; l <j&&R("inp" "ut: guess"
" color\n") ;printf("%" ".5s\n",r(l =j+~10)); } return 0; }
+64
View File
@@ -0,0 +1,64 @@
#include <stdarg.h>
#include <stdlib.h>
# include <stdio.h>
#define J(J) for (\
_ j=0; j<5; ++j) J;
#define/*IOCCC*/I \
\
\
\
_ W,_ O,_ R,_ D,_*L,_*E
#define A(A )for(_ j=0; !o&&j<5&&(k = t[l][j]); ++j)A&&++o;
typedef/* ; ; */void q; typedef int _ ; typedef char/* */p;
struct{ p a [257],b[9][ 5],c[5],d[5 ]; _ e,f; } i;p t[78557
][5]; _ s,a []={ 9,9,9, 10,13,18,27 ,39,55,1,18 ,2,1,1,35,2
,19,18,1,52 ,36,35,20,3 ,2,19,18,18 ,69,2,53,1, 52,37,3,20,
36,19,35,18 ,52,86,2,53 ,70,1,69,38 ,4,21,3,37, 19,36,35,25
,10,+17,15, 26,9,11,12, 23,2,06,18, 13,20,22,14 ,1,24,19,21
,16,5,7,4,8 ,3},u=' ';_ W(p*a,p*b){ for(p*c=a+5 ;a<c;)*a++=
*b++;return 0; } _ O(p* a,p b){ p*c =a+5; for(; a<c&&*a-b;)
++a; return a<c?5-(a-c) :0; } _ R(p *a, ... ) { va_list b ;
va_start(b, a); vprintf (a,b); exit (1); } q D( p*a){ if (s
==sizeof t/ 5)R("limit" " %d\n",s); p*b=s[t],i, j; for(i=j=
0; i<7&&!j; ++i)if(!(j= *a==10?i:0) )*b++=u|* a ++; j-5||++
s; } q L(p* a,_ b){ for (_ l=0,o=0, k; l<s; o=0 ){ A(i.c[j]
&&k-i.c[j]) A(i.a[k])A( i.d[j]&&!O( t[l],i.d[j] ))for(_ f=i
.e; f--&&!o ; )A(i.b[f] [j]==k)if(! o){ J(o+=t[ l][j]==a[j]
)o=o==5?b!= 5:0; } o?W( t[l],t[--s] ) :++l; } } _ e(I){ for
(; O<D; )L[ R++]=E[O+++ D*W];return R; } q S( _ O,_*l){ for
(_*s=&a[a[O ]],*e=a[-~O ]+s-a[O]; s <e; ){ _ i= *s++,j=i&15
,k=l[i>>=4] <l[+j]?k=l[ i],l[i]=l[j ],l[j]=k:i; } } _ o(I){
_ o=0, w=0; for(; o<D&w <D; )L[R++] =E[o+D*W]>= E[w+D*O]?E[
o+++D*W]:E[ w +++ D*O]; return e(O, w,e(W,o,R,D ,L,E),D,L,E
); } q l( _ n,_*f){ for (_* e=f+26, i,j; f<e&&* f>u; f+= i)
{ for(i=1,j =*f/u; i <n &&f[i]>>5== j; )++i;for (j=0; j <i;
++j)f[j] &= 31,f[j]|=a[ f[j]+a[~-9] ]<<5; S(i,f ); } } q v(
_ a,_*w,_*k ){ o(2,3,o( 0,1,0,a,w,k ),a,w,k); o (0,1,0,a+a,
k,w); l(a,k ); } p*E(p* d){ _ l,j,k =u,b[u] ,c[ k]; p*e[97]
[5 ]={ 0} ; for(l=0; l< k; ++l)c[l] =l; for(l=0 ; l<s; ++l)
J(c[t[l][j] -97]+=k)for (l= j=7; j< 22; j+=l)S( l,c+j-l); v
(l,b,c);for (l= 0; l<k; ++l)b[c[l]& ~-k]=l; for (k*=3,l= 0;
l<s; ++l) { _ i=0; J( i +=b[t[l][j] -97])if(i<k )J(e[i][ j]
||(e[i][j]= t[l],j=4))} for(l=0; l< k; ++l)for( p*b=0,k=j=0
; j<5&&(b=e [l][j]); k= !++j){ p c[ 32]={0} ; d =*d-120?d:b
; if(s>2)J( k+=++c[b[j] -97]>1); if (!k) return b; } return
d; } p*r(p* b){ _ k, l; for(_ j=k=l =0; j<5; ++ j) { signed
char n=b[j] ,o=b[j-~5]+ ~0x66; (o?i .b[i.e]:i.c )[j]=n; !o?
i.a[n]=!++k :O(i.d,n)|| (*(o<0?&i.a [n]:&i.d[i. f++])=l=n);
} i.e += !! l; L(b, k); return E("" "xyzzy"); } _ main(_ n,
char**v){ p *j=i .c-97, *l=j-11; n- 2?R("usage" ": %s dict"
"\n",* v):5 ; ; FILE*k= fopen(*++v, "r"); if(!k ) return //
perror(*v), 1; ; while( fgets(j, u^ n,k)) D(j); fclose (k);
; ; setbuf( stdout, 0); while(~-s){ printf("? " ); while(~(
n=getchar() )&&n-10&&l< j)*l++=n; l <j&&R("inp" "ut: guess"
" color\n") ;printf("%" ".5s\n",r(l =j+~10)); } return 0; }
+23999
View File
File diff suppressed because it is too large. Load diff
+23783
View File
File diff suppressed because it is too large. Load diff
+25469
View File
File diff suppressed because it is too large. Load diff
+24014
View File
File diff suppressed because it is too large. Load diff
+9
View File
@@ -0,0 +1,9 @@
#!/usr/bin/env bash
: ${dir:=results}
word=$1
echo $word | grep -q /
if test $? -eq 1; then word=$dir/$word; fi
grep good: $word | awk '{n[$5]++}END{for(i=1; i<7; ++i)print i,n[i]}' | sort -k1n
grep lose: $word | awk '{print $NF}' | pr -t -a -5
+26
View File
@@ -0,0 +1,26 @@
/* clang-format --style=LLVM < prog.c | reveal */
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int main(void)
{
int start = 0, len;
char buf[128];
while (fgets(buf, sizeof buf, stdin)) {
len = strlen(buf);
if (len > 3 && !isspace(buf[0])) {
char c = buf[2];
if (c == 'i') start = 1;
if (c == 'm') start = 0;
if (!start) continue;
if (buf[2] == '*') c = buf[3];
if (isalpha(c)) putchar(c);
} else if (start && len > 6 && buf[6] == ']')
putchar(buf[4]);
}
putchar('\n');
return 0;
}
+186
View File
@@ -0,0 +1,186 @@
/*
* run - connect gen and prog via pipes
*
* one-shot: run dict
* specific: run dict $start $target
* automate: cat dict | while read a; do run dict $start $a; done
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
static int DB;
static int
error(char *who)
{
perror(who);
kill(0, SIGKILL);
exit(1);
}
static int
xread(int fd, char *buf, int len)
{
int remain = len;
int t = 0;
if (DB) { printf("xread %d:", len); fflush(stdout); }
do {
int n = read(fd, buf + t, remain);
if (n < 0) error("read");
if (n == 0) return t;
if (n <= remain) {
remain -= n;
t += n;
}
} while (t != len);
buf[t] = 0;
if (DB) {
printf(" %s", buf);
if (buf[t-1] != '\n') printf("\n");
fflush(stdout);
}
return t;
}
static void
spawn(int r[2], int w[2], char **ev, char *path, char *name, char *dict, char *opt)
{
pipe(r) && error("pipe r");
pipe(w) && error("pipe w");
pid_t pid = fork();
if (pid == -1)
error("fork");
if (pid == 0) {
char *v[4] = { name, dict, opt, 0 };
dup2(r[0], 0) < 0 && error("dup2 r[0]");
dup2(w[1], 1) < 0 && error("dup2 w[1]");
close(r[1]);
close(w[0]);
execve(path, v, ev);
error(path);
}
close(r[0]);
close(w[1]);
}
int
main(int ac, char **av, char **ev)
{
int pgr[2], pgw[2]; // gen r/w
int ppr[2], ppw[2]; // prog r/w
static char guess[20], report[20];
static char xyzzy[] = "xyzzy";
char *cp, *prog = "./prog";
int n, end = 0;
int nguesses = 6;
if (ac < 2) {
fprintf(stderr, "usage: %s dict [start [target]]\n", av[0]);
return 1;
}
DB = !!getenv("DEBUG");
if ((cp = getenv("GUESSES")))
nguesses = atoi(cp);
if ((cp = getenv("PROG")))
prog = cp;
spawn(pgr, pgw, ev, "./gen", "gen", av[1], ac==4 ? av[3] : 0);
spawn(ppr, ppw, ev, prog, "prog", av[1], 0);
// wait for gen to be ready; read the prompt
char buf[20];
xread(pgw[0], buf, 2);
if (buf[0] != '?') {
xread(pgw[0], buf+2, 12); // target: guess
printf("gen: %s", buf);
xread(pgw[0], buf, 2);
}
// wait for prog prompt
xread(ppw[0], buf, 2);
memcpy(guess, ac>2 ? av[2] : "blast", 5);
guess[5] = '\n'; // mimic reading from stdin
for (int i = 0; i < nguesses && end != 1; ++i) {
printf("guess%d: %s", i+1, guess);
n = write(pgr[1], guess, 6);
if (n < 0) error("write pgw[1]");
n = xread(pgw[0], report, 12);
if (n != 12) {
if (n < 0) error("read pgr[0]");
printf("bad read from pgr[0]: %d\n", n);
return 2;
}
printf("gen: %s", report);
xread(pgw[0], guess, 2); // read the prompt
if (guess[0] != '?') {
xread(pgw[0], guess+2, 14);
printf("gen result end=%d: %s", end, guess);
if (end == 2) {
close(pgr[1]);
close(ppr[1]);
return 0;
}
close(pgw[0]);
close(pgr[1]);
end = 1;
}
if (end == 2) {
// cannot write to prog, it exited on winner, but gen disagrees
printf("ERROR: prog reported win, gen does not\n");
close(pgr[1]);
close(ppr[1]);
return 1;
}
n = write(ppr[1], report, n);
if (n < 0) error("ppw[1]");
n = xread(ppw[0], guess, 6);
if (n != 6) {
if (n < 0) error("read ppr");
printf("bad read from pipe_prog: %d {%.*s}\n", n, n, guess);
return 3;
}
if (strncmp(guess, xyzzy, sizeof(xyzzy)-1) == 0) {
printf("ERROR: desired word not in this dictionary\n");
close(pgr[1]);
close(ppr[1]);
return 1;
}
// might not prompt, just exit
if (xread(ppw[0], report, 2) == 0) { // read the prompt
printf("prog: EOF\n");
if (end == 1) {
close(pgr[1]);
close(ppr[1]);
return 0;
}
end = 2;
close(ppr[1]);
close(ppw[0]);
}
}
}
+5
View File
@@ -0,0 +1,5 @@
blast ybybb
amber gbyyb
adobe gygyg
abode ggggg
+6
View File
@@ -0,0 +1,6 @@
blast bbybg
daunt bgggg
haunt bgggg
gaunt bgggg
vaunt bgggg
taunt ygggg
+3
View File
@@ -0,0 +1,3 @@
terns ybbbb
loath gbbyy
light ggggg
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env bash
#
# try.sh - demonstrate 2024/burton
# 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
cat test.light 1>&2
echo 1>&2
echo '=-=-=' 1>&2
echo 1>&2
./prog dict < test.light
echo 1>&2
+165
View File
@@ -0,0 +1,165 @@
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
typedef void q;
typedef int _;
typedef char p;
struct {
p a[256], b[9][5], c[5], d[5];
_ e, f;
} i;
p t[78557][5];
_ s, a[] = {
9, 9, 9, 10, 13, 18, 27, 39, 55, 1, 18, 2, 1, 1,
35, 2, 19, 18, 1, 52, 36, 35, 20, 3, 2, 19, 18, 18,
69, 2, 53, 1, 52, 37, 3, 20, 36, 19, 35, 18, 52, 86,
2, 53, 70, 1, 69, 38, /* 36 */ 4, 21, 3, 37, 19,
36, 35, 25, 10, 17, 15, 26, 9, 11, 12, 23, 2, 6, 18,
13, 20, 22, 14, 1, 24, 19, 21, 16, 5, 7, 4, 8, 3
} , u = ' ';
_ W(p *a, p *b) {
for (p *c = a + 5; a < c; )
*a++ = *b++;
return 0;
}
_ O(p *a, p b) {
p *c = a + 5;
for (; a < c && *a - b; )
++a;
return a < c ? 5 - (a - c) : 0;
}
_ R(p *a, ...) {
va_list b;
va_start(b, a);
vprintf(a, b);
exit(1);
}
q D(p *a) {
if (s == sizeof t / 5)
R("limit %d\n", s);
p *b = s[t], i, j;
for (i = j = 0; i < 7 && !j; ++i)
if (!(j = *a == 10 ? i : 0))
*b++ = u | *a++;
j - 5 || ++s;
}
q L(p *a, _ b) {
for (_ l = 0, o = 0, k; l < s; o = 0) {
for (_ j = 0; !o && j < 5 && (k = t[l][j]); ++j)
i.c[j] && k - i.c[j] && ++o;
for (_ j = 0; !o && j < 5 && (k = t[l][j]); ++j)
i.a[k] && ++o;
for (_ j = 0; !o && j < 5 && (k = t[l][j]); ++j)
i.d[j] && !O(t[l], i.d[j]) && ++o;
for (_ f = i.e; f-- && !o; )
for (_ j = 0; !o && j < 5 && (k = t[l][j]); ++j)
i.b[f][j] == k && ++o;
if (!o) {
for (_ j = 0; j < 5; ++j)
o += t[l][j] == a[j];
o = o == 5 ? b != 5 : 0;
}
o ? W(t[l], t[--s]) : ++l;
}
}
_ e(_ W, _ O, _ R, _ D, _ *L, _ *E) {
for (; O < D; )
L[R++] = E[O++ + D * W];
return R;
}
q S(_ O, _ *l) {
for (_ *s = &a[a[O]], *e = a[-~O] + s - a[O]; s < e; ) {
_ i = *s++,
j = i & 15,
k = l[i >>= 4] < l[j] ? k = l[i], l[i] = l[j], l[j] = k : i;
}
}
_ o(_ W, _ O, _ R, _ D, _ *L, _ *E) {
_ o = 0, w = 0;
for (; o < D & w < D; )
L[R++] = E[o + D * W] >= E[w + D * O]
? E[o++ + D * W]
: E[w++ + D * O];
return e(O, w, e(W, o, R, D, L, E), D, L, E);
}
q l(_ n, _ *f) {
for (_ *e = f + 26, i, j; f < e && *f > u; f += i) {
for (i = 1, j = *f / u; i < n && f[i] >> 5 == j; )
++i;
for (j = 0; j < i; ++j)
f[j] &= 31,
f[j] |= a[f[j] + a[~-9]] << 5;
S(i, f);
}
}
q v(_ a, _ *w, _ *k) {
o(2, 3, o(0, 1, 0, a, w, k), a, w, k);
o(0, 1, 0, a + a, k, w);
l(a, k);
}
p *E(p *d) {
_ l, j, k = u, b[u], c[k];
p *e[97][5] = { 0 } ;
for (l = 0; l < k; ++l)
c[l] = l;
for (l = 0; l < s; ++l)
for (_ j = 0; j < 5; ++j)
c[t[l][j] - 97] += k;
for (l = j = 7; j < 22; j += l)
S(l, c + j - l);
v(l, b, c);
for (l = 0; l < k; ++l)
b[c[l] & ~-k] = l;
for (k *= 3, l = 0; l < s; ++l) {
_ i = 0;
for (_ j = 0; j < 5; ++j)
i += b[t[l][j] - 97];
if (i < k)
for (_ j = 0; j < 5; ++j)
e[i][j] || (e[i][j] = t[l], j = 4);
}
for (l = 0; l < k; ++l)
for (p *b = 0, k = j = 0; j < 5 && (b = e[l][j]); k = !++j) {
p c[32] = { 0 } ;
d = *d - 120 ? d : b;
if (s > 2)
for (_ j = 0; j < 5; ++j)
k += ++c[b[j] - 97] > 1;
if (!k)
return b;
}
return d;
}
p *r(p *b) {
_ k, l;
for (_ j = k = l = 0; j < 5; ++j) {
signed char n = b[j], o = b[j - ~5] + ~0x66;
(o ? i.b[i.e] : i.c)[j] = n;
!o ? i.a[n] = !++k : O(i.d, n) || (*(o < 0 ? &i.a[n] : &i.d[i.f++]) = l = n);
}
i.e += !!l;
L(b, k);
return E("xyzzy");
}
_ main(_ n, char **v) {
p *j = i.c - 97, *l = j - 11;
n - 2 ? R("usage: %s dict\n", *v) : 5;
FILE *k = fopen(*++v, "r");
if (!k)
return perror(*v), 1;
while (fgets(j, u ^ n, k))
D(j);
fclose(k);
setbuf(stdout, 0);
while (~-s) {
printf("? ");
while (~(n = getchar()) && n - 10 && l < j)
*l++ = n;
l < j && R("input: guess color\n");
printf("%.5s\n", r(l = j + ~10));
}
return 0;
}
+4
View File
@@ -0,0 +1,4 @@
#!/usr/bin/env bash
test $# -eq 6 || { echo must have all six scores; exit 1; }
echo "($1*1 + $2*2 + $3*3 + $4*4 + $5*5 + $6*6) / ($1+$2+$3+$4+$5+$6)" | bc -l | awk '{printf "%.04f\n", $1 }'
+20
View File
@@ -0,0 +1,20 @@
#!/bin/sh
# usage: echo terns | word.result
# usage: cat dict | word.result
dir=$1
: ${dir:=results}
d=$2
: ${d:=dict}
# for each word as a starting guess
# run the sim for each target word
while read w; do
echo $w;
cat dict | while read t; do
./run $d $w $t
done > $dir/$w
done
+14
View File
@@ -0,0 +1,14 @@
#!/usr/bin/env bash
dir=$1
: ${dir:=results}
lines=$2
: ${lines:=10}
for name in $dir/*; do
grep lose: $name | awk '{print $NF}';
done |
awk '{a[$1]++}END{for(i in a)print i,a[i]}' |
sort -k2nr |
pr -t -a -5 |
sed ${lines}q
+5
View File
@@ -0,0 +1,5 @@
#!/bin/sh
a=$(./rank results/$1 | awk 'NR<7 {print $2}')
/bin/echo -n "$1 "
./wavg $a
+105
View File
@@ -0,0 +1,105 @@
{
"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 bot talk",
"year" : 2024,
"dir" : "cable1",
"entry_id" : "2024_cable1",
"title" : "chatioccc",
"abstract" : "LLM inference engine",
"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" : "get_model.sh",
"inventory_order" : 100,
"OK_to_edit" : true,
"display_as" : "shellscript",
"display_via_github" : true,
"entry_text" : "tool to download llama2-7b-chat model"
},
{
"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_cable1.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"
}
]
}
+12
View File
@@ -0,0 +1,12 @@
LLAMA2_LICENSE
eeyore
eeyore_openmp
linux
linux_openmp
model
openmp
prog_openmp
rainman
rainman_openmp
snoop
snoop_openmp
+1
View File
@@ -0,0 +1 @@
2024/cable1
Binary file not shown.
+257
View File
@@ -0,0 +1,257 @@
#!/usr/bin/env make
#
# 2024/cable1
#############################
# 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-deprecated-non-prototype -Wno-multichar -Wno-parentheses \
-Wno-pointer-sign -Wno-return-type -Wno-misleading-indentation -Wno-unknown-pragmas
# 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 ${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= -DM=\"model\"
# 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= -ffast-math -fno-math-errno -march=native
# 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-c99-compat -Wno-comma -Wno-deprecated-non-prototype \
-Wno-dollar-in-identifier-extension -Wno-double-promotion \
-Wno-float-conversion -Wno-implicit-float-conversion \
-Wno-missing-prototypes -Wno-missing-variable-declarations \
-Wno-multichar -Wno-parentheses -Wno-pedantic -Wno-pointer-sign \
-Wno-poison-system-directories -Wno-return-type -Wno-shadow \
-Wno-sign-conversion -Wno-source-uses-openmp -Wno-strict-prototypes \
-Wno-enum-float-conversion -Wno-reserved-identifier \
-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} snoop eeyore linux rainman
TARGET_MP= openmp snoop_openmp eeyore_openmp linux_openmp rainman_openmp
#
ALT_OBJ=
ALT_TARGET=
# list any data files supplied with your submission
#
# Example: DATA= curds whey
#
DATA=
# system prompts for personalities
#
SNOOP= "You are Snoop Dogg."
EEYORE= "You are Eeyore, always miserable, passive aggressive and self-deprecating."
LINUX= "You are a Linux terminal. I will type a command, and you will print its output inside a single code block."
RAINMAN= "You are the title character of the movie Rain Man."
#################
# build the entry
#################
all: data ${TARGET}
@${TRUE}
.PHONY: all alt data everything clean clobber
# how to compile
#
${PROG}: ${PROG}.c
${CC} ${CFLAGS} ${PROG}.c -DS='""' -o $@ ${LDFLAGS}
all_openmp: ${TARGET_MP}
openmp: prog_openmp
${CP} -f $? $@
prog_openmp: ${PROG}.c
${CC} ${CFLAGS} ${PROG}.c -fopenmp -DS='""' -o $@ ${LDFLAGS}
snoop: ${PROG}.c
${CC} ${CFLAGS} ${PROG}.c -DS='${SNOOP}' -o $@ ${LDFLAGS}
snoop_openmp: ${PROG}.c
${CC} ${CFLAGS} ${PROG}.c -fopenmp -DS='${SNOOP}' -o $@ ${LDFLAGS}
eeyore: ${PROG}.c
${CC} ${CFLAGS} ${PROG}.c -DS='${EEYORE}' -o $@ ${LDFLAGS}
eeyore_openmp: ${PROG}.c
${CC} ${CFLAGS} ${PROG}.c -fopenmp -DS='${EEYORE}' -o $@ ${LDFLAGS}
linux: ${PROG}.c
${CC} ${CFLAGS} ${PROG}.c -DS='${LINUX}' -o $@ ${LDFLAGS}
linux_openmp: ${PROG}.c
${CC} ${CFLAGS} ${PROG}.c -fopenmp -DS='${LINUX}' -o $@ ${LDFLAGS}
rainman: ${PROG}.c
${CC} ${CFLAGS} ${PROG}.c -DS='${RAINMAN}' -o $@ ${LDFLAGS}
rainman_openmp: ${PROG}.c
${CC} ${CFLAGS} ${PROG}.c -fopenmp -DS='${RAINMAN}' -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} ${TARGET_MP} prog_openmp
${RM} -rf *.dSYM
######################################
# optional include of 1337 hacker rulz
######################################
-include 1337.mk ../1337.mk ../../1337.mk
+245
View File
@@ -0,0 +1,245 @@
## To build:
``` <!---sh-->
make all
./get_model.sh
```
**NOTE**: You must accept the license to run the program.
## To use:
**NOTE**: You must have successful run the
[2024/cable1/get_model.sh](%%REPO_URL%%/2024/cable1/get_model.sh) script
before running the program.
``` <!---sh-->
./prog
```
## Try:
``` <!---sh-->
echo 'Describe yourself.' | ./prog
echo 'Describe yourself.' | ./linux
echo 'ls' | ./linux
echo 'Describe yourself.' | ./eeyore
echo 'Why are you so sad?' | ./eeyore
echo 'Describe yourself.' | ./snoop
echo 'Tell me a silly joke.' | ./snoop
echo 'Describe yourself.' | ./rainman
echo 'How 2+2 can equal 5?' | ./rainman
```
### Fun things to try
Here are some fun things give as input:
> Why did this entry win IOCCC28?
> 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](%%REPO_URL%%/2024/cable1/get_model.sh) script
before running the program.
``` <!---sh-->
make openmp
```
### Alternate use:
``` <!---sh-->
./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):
``` <!---sh-->
./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](https://github.com/karpathy/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:
``` <!---sh-->
make linux
./linux
```
Or for much better performance:
``` <!---sh-->
make linux_openmp
./linux_openmp
```
Then try typing some Linux commands. You can even run an imaginary C compiler inside the LLM:
``` <!---sh-->
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](https://chatgpt.com/share/6839d275-c644-8004-9301-0ea781d8f5aa) according to ChatGPT. But, to quote Walt Disney, "it's kind of fun to do the impossible".
<!--
Copyright © 1984-2025 by Landon Curt Noll and Leonid A. Broukhis. 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/
-->
+30
View File
@@ -0,0 +1,30 @@
#!/usr/bin/env bash
LICENSE_URL="https://od.lk/d/NTJfNDgwODA2NjVf/LLAMA2_LICENSE"
MODEL_LOCATION_URL="https://od.lk/d/NTJfNDgxMDQzMzNf/model_location"
# Step 1: Download and display the license file
wget -q -O LLAMA2_LICENSE "$LICENSE_URL"
cat LLAMA2_LICENSE
echo ""
echo ""
echo "----------------"
echo ""
# Step 2: Ask user to accept the license, then download the model
read -r -p "Accept Meta's license to download the llama2-7b-chat model for use with ChatIOCCC. Type Y to accept: " ACCEPT
if [[ "$ACCEPT" == "Y" || "$ACCEPT" == "y" || "$ACCEPT" == "yes" || "$ACCEPT" == "Yes" || "$ACCEPT" == "YES" ]]; then
# Step 3: Download the model file
echo ""
echo "Downloading model ..."
rm -f LLAMA2_LICENSE model
wget -q --show-progress -O model "$(wget -q -O - "$MODEL_LOCATION_URL")"
else
echo "License not accepted. Exiting."
exit 1
fi
exit 0
+756
View File
@@ -0,0 +1,756 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<!-- START: two lines up starts content from: inc/top.default.html -->
<!-- END: this line ends content from: inc/top.default.html -->
<!-- START: this line starts content from: inc/head.default.html -->
<head>
<link rel="stylesheet" href="../../ioccc.css">
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@100..900&display=swap" rel="stylesheet">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>2024/cable1 - Prize in bot talk</title>
<link rel="icon" type="image/x-icon" href="../../favicon.ico">
<meta name="description" content="2024 IOCCC entry cable1 - Prize in bot talk">
<meta name="keywords" content="IOCCC, 2024, IOCCC 2024, IOCCC entry, cable1, Prize in bot talk">
</head>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<!-- !!! DO NOT MODIFY THIS FILE - This file is generated by a tool !!! -->
<!-- !!! DO NOT MODIFY THIS FILE - This file is generated by a tool !!! -->
<!-- !!! DO NOT MODIFY THIS FILE - This file is generated by a tool !!! -->
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<!-- END: this line ends content from: inc/head.default.html -->
<!-- -->
<!-- This web page was formed via the tool: bin/readme2index.sh -->
<!-- The content of main section of this web page came from: 2024/cable1/README.md -->
<!-- -->
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<!-- !!! Do not modify this web page, instead modify the file: 2024/cable1/README.md !!! -->
<!-- !!! Do not modify this web page, instead modify the file: 2024/cable1/README.md !!! -->
<!-- !!! Do not modify this web page, instead modify the file: 2024/cable1/README.md !!! -->
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<!-- Markdown content was converted into HTML via the tool: bin/md2html.sh -->
<!-- START: this line starts content from: inc/body.default.html -->
<body>
<!-- END: this line ends content from: inc/body.default.html -->
<!-- START: this line starts content from: inc/topbar.default.html -->
<div class="theader">
<nav class="topbar">
<div class="container">
<div class="logo">
<a href="../../index.html" class="logo-link">
IOCCC
</a>
</div>
<div class="topbar-items">
<div class="item">
<span class="item-header">
Entries
</span>
<div class="sub-item">
<div class="outfit-font">
<a href="../../years.html" class="sub-item-link">
Winning entries
</a>
</div>
<div class="outfit-font">
<a href="../../authors.html" class="sub-item-link">
Winning authors
</a>
</div>
<div class="outfit-font">
<a href="../../location.html" class="sub-item-link">
Location of authors
</a>
</div>
<div class="outfit-font">
<a href="../../bugs.html" class="sub-item-link">
Bugs and (mis)features
</a>
</div>
<div class="outfit-font">
<a href="../../faq.html#fix_an_entry" class="sub-item-link">
Fixing entries
</a>
</div>
<div class="outfit-font">
<a href="../../faq.html#fix_author" class="sub-item-link">
Updating author info
</a>
</div>
</div>
</div>
<div class="item">
<span class="item-header">
Status
</span>
<div class="sub-item">
<div class="outfit-font">
<a href="../../news.html" class="sub-item-link">
News
</a>
</div>
<div class="outfit-font">
<a href="../../status.html" class="sub-item-link">
Contest status
</a>
</div>
<div class="outfit-font">
<a href="../../next/rules.html" class="sub-item-link">
IOCCC rules
</a>
</div>
<div class="outfit-font">
<a href="../../next/guidelines.html" class="sub-item-link">
IOCCC guidelines
</a>
</div>
<div class="outfit-font">
<a href="../../markdown.html" class="sub-item-link">
Markdown guidelines
</a>
</div>
<div class="outfit-font">
<a href="../../SECURITY.html" class="sub-item-link">
Security policy
</a>
</div>
</div>
</div>
<div class="item">
<span class="item-header">
FAQ
</span>
<div class="sub-item">
<div class="outfit-font">
<a href="../../faq.html" class="sub-item-link">
Frequently asked questions
</a>
</div>
<div class="outfit-font">
<a href="../../quick-start.html#enter" class="sub-item-link">
Enter the IOCCC
</a>
</div>
<div class="outfit-font">
<a href="../../faq.html#compiling" class="sub-item-link">
Compiling entries
</a>
</div>
<div class="outfit-font">
<a href="../../faq.html#running_entries" class="sub-item-link">
Running entries
</a>
</div>
<div class="outfit-font">
<a href="../../faq.html#help" class="sub-item-link">
How to help
</a>
</div>
</div>
</div>
<div class="item">
<span class="item-header">
About
</span>
<div class="sub-item">
<div class="outfit-font">
<a href="../../index.html" class="sub-item-link">
Home page
</a>
</div>
<div class="outfit-font">
<a href="../../social.html" class="sub-item-link">
IOCCC social media
</a>
</div>
<div class="outfit-font">
<a href="../../about.html" class="sub-item-link">
About the IOCCC
</a>
</div>
<div class="outfit-font">
<a href="../../judges.html" class="sub-item-link">
The judges
</a>
</div>
<div class="outfit-font">
<a href="../../thanks-for-help.html" class="sub-item-link">
Thanks for the help
</a>
</div>
<div class="outfit-font">
<a href="../../contact.html" class="sub-item-link">
Contact us
</a>
</div>
</div>
</div>
</div>
</div>
</nav>
<div class="header-mobile-menu">
<noscript>
<a href="../../nojs-menu.html" class="topbar-js-label">
Please Enable JavaScript
</a>
</noscript>
<button id="header-open-menu-button" class="topbar-mobile-menu">
<img
src="../../png/hamburger-icon-open.png"
alt="hamburger style menu icon - open state"
width=48
height=48>
</button>
<button id="header-close-menu-button" class="hide-content">
<img
src="../../png/hamburger-icon-closed.png"
alt="hamburger style menu icon - closed state"
width=48
height=48>
</button>
<div id="mobile-menu-panel" class="hide-content">
<div class="mobile-menu-container">
<div class="mobile-menu-wrapper">
<div class="mobile-menu-item">
Entries
</div>
<div class="mobile-submenu-wrapper">
<a class="mobile-submenu-item" href="../../years.html">
Winning entries
</a>
<a class="mobile-submenu-item" href="../../authors.html">
Winning authors
</a>
<a class="mobile-submenu-item" href="../../location.html">
Location of authors
</a>
<a class="mobile-submenu-item" href="../../bugs.html">
Bugs and (mis)features
</a>
<a class="mobile-submenu-item" href="../../faq.html#fix_an_entry">
Fixing entries
</a>
<a class="mobile-submenu-item" href="../../faq.html#fix_author">
Updating author info
</a>
<a class="mobile-submenu-item" href="../../thanks-for-help.html">
Thanks for the help
</a>
</div>
</div>
<div class="mobile-menu-wrapper">
<div class="mobile-menu-item">
Status
</div>
<div class="mobile-submenu-wrapper">
<a class="mobile-submenu-item" href="../../news.html">
News
</a>
<a class="mobile-submenu-item" href="../../status.html">
Contest status
</a>
<a class="mobile-submenu-item" href="../../next/rules.html">
IOCCC rules
</a>
<a class="mobile-submenu-item" href="../../next/guidelines.html">
IOCCC guidelines
</a>
<a class="mobile-submenu-item" href="../../markdown.html">
Markdown guidelines
</a>
<a class="mobile-submenu-item" href="../../SECURITY.html">
Security policy
</a>
</div>
</div>
<div class="mobile-menu-wrapper">
<div class="mobile-menu-item">
FAQ
</div>
<div class="mobile-submenu-wrapper">
<a class="mobile-submenu-item" href="../../faq.html">
Frequently asked questions
</a>
<a class="mobile-submenu-item" href="../../quick-start.html#enter">
Enter the IOCCC
</a>
<a class="mobile-submenu-item" href="../../faq.html#compiling">
Compiling entries
</a>
<a class="mobile-submenu-item" href="../../faq.html#running_entries">
Running entries
</a>
<a class="mobile-submenu-item" href="../../faq.html#help">
How to help
</a>
</div>
</div>
<div class="mobile-menu-wrapper">
<div class="mobile-menu-item">
About
</div>
<div class="mobile-submenu-wrapper">
<a class="mobile-submenu-item" href="../../index.html">
Home page
</a>
<a class="mobile-submenu-item" href="../../social.html">
IOCCC social media
</a>
<a class="mobile-submenu-item" href="../../about.html">
About the IOCCC
</a>
<a class="mobile-submenu-item" href="../../judges.html">
The judges
</a>
<a class="mobile-submenu-item" href="../../contact.html">
Contact us
</a>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
var headerOpenMenuButton = document.getElementById("header-open-menu-button");
var headerCloseMenuButton = document.getElementById("header-close-menu-button");
var mobileMenuPanel = document.getElementById("mobile-menu-panel");
headerOpenMenuButton.addEventListener("click", () => {
headerOpenMenuButton.classList.remove("topbar-mobile-menu");
headerOpenMenuButton.classList.add("hide-content");
headerCloseMenuButton.classList.remove("hide-content");
headerCloseMenuButton.classList.add("topbar-mobile-menu");
mobileMenuPanel.classList.remove("hide-content");
mobileMenuPanel.classList.add("topbar-mobile-panel");
});
headerCloseMenuButton.addEventListener("click", () => {
headerCloseMenuButton.classList.remove("topbar-mobile-menu");
headerCloseMenuButton.classList.add("hide-content");
mobileMenuPanel.classList.add("hide-content");
mobileMenuPanel.classList.remove("topbar-mobile-panel");
headerOpenMenuButton.classList.add("topbar-mobile-menu");
headerOpenMenuButton.classList.remove("hide-content");
});
</script>
<!-- END: this line ends content from: inc/topbar.default.html -->
<!-- START: this line starts content from: inc/header.default.html -->
<div class="header">
<a href="../../2011/zucker/index.html">
<img src="../../png/ioccc.png"
alt="IOCCC image by Matt Zucker"
width=300
height=110>
</a>
<h1>The International Obfuscated C Code Contest</h1>
<h2>2024/cable1 - Prize in bot talk</h2>
<h3>LLM inference engine</h3>
</div>
<!-- END: this line ends content from: inc/header.default.html -->
<!-- START: this line starts content from: inc/navbar.mid.html -->
<div class="navbar">
<a class="Left" href="../burton/index.html">&larr; 2024/burton</a>
<a class="Left" href="../index.html">&uarr; 2024 &uarr;</a>
<a class="Left" href="../cable2/index.html">2024/cable2 &rarr;</a>
<a class="Right" href="https://github.com/ioccc-src/winner/blob/master/2024/cable1/prog.c">C code</a>
<a class="Right" href="https://github.com/ioccc-src/winner/blob/master/2024/cable1/Makefile">Makefile</a>
<a class="Right" href="#inventory">Inventory</a>
<a class="Right" href="https://validator.w3.org/nu/?doc=https%3A%2F%2Fwww.ioccc.org%2F2024%2Fcable1%2Findex.html">&#x2713;</a>
</div>
<!-- END: this line ends content from: inc/navbar.mid.html -->
<!-- START: this line starts content from: inc/before-content.default.html -->
<div class="content" id="content">
<!-- END: this line ends content from: inc/before-content.default.html -->
<!-- START: this line starts content for HTML phase 20 by: bin/output-index-author.sh via bin/md2html.sh -->
<!-- START: this line starts content generated by: bin/output-index-author.sh -->
<h2 id="author">Author:</h2>
<ul>
<li>Name: <a href="../../authors.html#Adrian_Cable">Adrian Cable</a><br>
Location: <a href="../../location.html#US">US</a> - <em>United States of America</em> (<em>United States</em>)</li>
</ul>
<!-- END: next line ends content generated by: bin/output-index-author.sh -->
<!-- END: this line ends content for HTML phase 20 by: bin/output-index-author.sh via bin/md2html.sh -->
<!-- START: this line starts content for HTML phase 21 by: bin/pandoc-wrapper.sh via bin/md2html.sh -->
<!-- BEFORE: 1st line of markdown file: 2024/cable1/README.md -->
<h2 id="to-build">To build:</h2>
<pre><code> make all
./get_model.sh</code></pre>
<p><strong>NOTE</strong>: You must accept the license to run the program.</p>
<h2 id="to-use">To use:</h2>
<p><strong>NOTE</strong>: You must have successful run the
<a href="https://github.com/ioccc-src/winner/blob/master/2024/cable1/get_model.sh">2024/cable1/get_model.sh</a> script
before running the program.</p>
<pre><code> ./prog</code></pre>
<h2 id="try">Try:</h2>
<pre><code> echo &#39;Describe yourself.&#39; | ./prog
echo &#39;Describe yourself.&#39; | ./linux
echo &#39;ls&#39; | ./linux
echo &#39;Describe yourself.&#39; | ./eeyore
echo &#39;Why are you so sad?&#39; | ./eeyore
echo &#39;Describe yourself.&#39; | ./snoop
echo &#39;Tell me a silly joke.&#39; | ./snoop
echo &#39;Describe yourself.&#39; | ./rainman
echo &#39;How 2+2 can equal 5?&#39; | ./rainman</code></pre>
<h3 id="fun-things-to-try">Fun things to try</h3>
<p>Here are some fun things give as input:</p>
<blockquote>
<p>Why did this entry win IOCCC28?</p>
</blockquote>
<blockquote>
<p>Translate “Plurima responsa non recta esse supponamus”</p>
</blockquote>
<blockquote>
<p>Write a C program that writes a C program.</p>
</blockquote>
<blockquote>
<p>Write a sentence so that contains a split infinitive.</p>
</blockquote>
<blockquote>
<p>Rewrite the previous sentence so that it ends in a preposition.</p>
</blockquote>
<blockquote>
<p>How much wood does a woodchuck?</p>
</blockquote>
<blockquote>
<p>Tell me a silly joke.</p>
</blockquote>
<blockquote>
<p>Write a poem about a poet who is illiterate.</p>
</blockquote>
<blockquote>
<p>Give examples, based on mathematics, where 2+2 can equal 5.</p>
</blockquote>
<p>Please note that the quality and accuracy of the answers you receive may vary. :-)
We do <strong>NOT</strong> recommend believing everything you read from this program.
<strong>Caveat lector!</strong></p>
<h2 id="alternate-code">Alternate code:</h2>
<h3 id="alternate-build">Alternate build:</h3>
<p><strong>NOTE</strong>: You must have successful run the
<a href="https://github.com/ioccc-src/winner/blob/master/2024/cable1/get_model.sh">2024/cable1/get_model.sh</a> script
before running the program.</p>
<pre><code> make openmp</code></pre>
<h3 id="alternate-use">Alternate use:</h3>
<pre><code> ./prog_openmp</code></pre>
<h2 id="judges-remarks">Judges’ remarks:</h2>
<p>This entry may benefit from OpenMP (via <code>prog_openmp</code>) 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.</p>
<p>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.</p>
<p>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
<code>prog.orig.c</code>.</p>
<p><strong>NOTE</strong>: Even with OpenMP, this tool is not the fastest. A mild level of patience is advised.</p>
<p><strong>DISCLAIMER</strong>: <em>riPlurima responsa non recta esse supponamus</em>!</p>
<h3 id="important-download">IMPORTANT Download</h3>
<p>ChatIOCCC runs Meta’s open source <code>llama2-7b-chat</code> model. Before using ChatIOCCC, you’ll need to accept Meta’s license
and download the model weights (~7GB):</p>
<pre><code> ./get_model.sh</code></pre>
<h2 id="authors-remarks">Author’s remarks:</h2>
<p>ChatIOCCC - the world’s smallest and best LLM inference engine</p>
<h3 id="about">About</h3>
<p>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.</p>
<p>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.</p>
<p>The author was inspired by <a href="https://github.com/karpathy/llama2.c">llama2.c</a> 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.</p>
<p>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.</p>
<p>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.</p>
<h3 id="requirements">Requirements</h3>
<p>In addition to using <code>./get_model.sh</code> to download the <code>llama2-7b-chat</code> model (see above), you’ll need around 11GB of free RAM to run ChatIOCCC.</p>
<h3 id="fun-things-to-ask">Fun things to ask</h3>
<p>Here are some fun things you can ask ChatIOCCC to do for you:</p>
<blockquote>
<p>Tell me a surprising fact about an animal of your choice.</p>
</blockquote>
<blockquote>
<p>Write a short story for a 5 year old girl, featuring Sobieski the dog and Pepe the cat.</p>
</blockquote>
<blockquote>
<p>Write a C program which sorts a list using the bubble sort algorithm.</p>
</blockquote>
<blockquote>
<p>Write a poem about a little boy who builds a rocket to fly to the moon. In Japanese, please.</p>
</blockquote>
<blockquote>
<p>Translate into English: 这个项目会成为 2024 年 IOCCC 的赢家吗?</p>
</blockquote>
<blockquote>
<p>Tell me about the IOCCC and its history. Then, write a poem in French about it.</p>
</blockquote>
<h3 id="personalities">Personalities</h3>
<p>ChatIOCCC allows the LLM’s system prompt to be defined at compile time (by using <code>-DS="prompt..."</code>).
The supplied <code>Makefile</code> includes three example personalities (set via system prompts) you can try: <code>eeyore</code>, <code>snoop</code> and <code>linux</code> (and
their OpenMP versions, <code>eeyore_openmp</code>, <code>snoop_openmp</code>, <code>linux_openmp</code>).
The <code>eeyore</code> and <code>snoop</code> personalities are self-explanatory. The <code>linux</code> personality makes ChatIOCCC act like a Linux
machine. Try for example:</p>
<pre><code> make linux
./linux</code></pre>
<p>Or for much better performance:</p>
<pre><code> make linux_openmp
./linux_openmp</code></pre>
<p>Then try typing some Linux commands. You can even run an imaginary C compiler inside the LLM:</p>
<pre><code> pwd
cat /etc/passwd
echo &#39;int main() { for (int i = 1; i &lt;= 10; i++) printf(&quot;IOCCC %d\n&quot;, i); }&#39; &gt; test.c; gcc test.c; ./a.out
ls -la a.out</code></pre>
<h3 id="limitations">Limitations</h3>
<p>The <code>llama2-7b-chat</code> 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.</p>
<p>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.</p>
<h3 id="footnotes">Footnotes</h3>
<p>The length of this entry’s source code is 1750 bytes. Many interesting things happened in 1750, including:</p>
<ul>
<li>The Industrial Revolution begins in Great Britain</li>
<li>British astronomer Thomas Wright first proposes that the Milky Way is a disk-shaped system of stars, with our Solar System near its center</li>
<li>Benjamin Franklin first proposes the idea that lightning is electrical in nature</li>
<li>Adwaita the giant tortoise, who lived until 2006, is born</li>
<li>Johann Sebastian Bach dies</li>
</ul>
<p>As a final note, the author is pleased to report that this entry is <a href="https://chatgpt.com/share/6839d275-c644-8004-9301-0ea781d8f5aa">absolutely totally impossible</a> according to ChatGPT. But, to quote Walt Disney, “it’s kind of fun to do the impossible”.</p>
<!--
Copyright © 1984-2025 by Landon Curt Noll and Leonid A. Broukhis. 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/
-->
<!-- AFTER: last line of markdown file: 2024/cable1/README.md -->
<!-- END: this line ends content for HTML phase 21 by: bin/pandoc-wrapper.sh via bin/md2html.sh -->
<!-- START: this line starts content for HTML phase 22 by: bin/output-index-inventory.sh via bin/md2html.sh -->
<!-- START: this line starts content generated by: bin/output-index-inventory.sh -->
<div id="inventory">
<h1 id="inventory-for-2024cable1">Inventory for 2024/cable1</h1>
</div>
<h2 id="primary-files">Primary files</h2>
<ul>
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/cable1/prog.c">prog.c</a> - entry source code</li>
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/cable1/Makefile">Makefile</a> - entry Makefile</li>
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/cable1/prog.orig.c">prog.orig.c</a> - original source code</li>
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/cable1/get_model.sh">get_model.sh</a> - tool to download llama2-7b-chat model</li>
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/cable1/try.sh">try.sh</a> - script to try entry</li>
</ul>
<h2 id="secondary-files">Secondary files</h2>
<ul>
<li><a href="2024_cable1.tar.bz2">2024_cable1.tar.bz2</a> - download entry tarball</li>
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/cable1/README.md">README.md</a> - markdown source for this web page</li>
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/cable1/.entry.json">.entry.json</a> - entry summary and manifest in JSON</li>
<li><a href="https://github.com/ioccc-src/winner/blob/master/2024/cable1/.gitignore">.gitignore</a> - list of files that should not be committed under git</li>
<li><a href=".path">.path</a> - directory path from top level directory</li>
<li><a href="index.html">index.html</a> - this web page</li>
</ul>
<hr style="width:10%;text-align:left;margin-left:0">
<h4>
Jump to: <a href="#">top</a>
</h4>
<!-- END: next line ends content generated by: bin/output-index-inventory.sh -->
<!-- END: this line ends content for HTML phase 22 by: bin/output-index-inventory.sh via bin/md2html.sh -->
<!-- START: this line starts content from: inc/after-content.default.html -->
</div>
<!-- END: this line ends content from: inc/after-content.default.html -->
<!-- START: this line starts content from: inc/footer.inventory.html -->
<!--
Copyright © 1984-2025 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/
-->
<div class="footer">
<div id="copyright"><h3>Copyright &copy; 1984-2025 by Landon Curt Noll:
<a href="https://creativecommons.org/faq/#what-does-some-rights-reserved-mean"
target="_blank"
rel="license noopener noreferrer">Some Rights Reserved</a></h3>
<p>
This work is <b>licensed by Landon Curt Noll</b> under
<b><a href="https://creativecommons.org/licenses/by-sa/4.0/?ref=chooser-v1"
target="_blank"
rel="license noopener noreferrer"
style="display:inline-block;">CC BY-SA 4.0</a></b>.
<img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;"
src="../../png/cc.png"
alt="cc inside circle symbol">
<img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;"
src="../../png/by.png"
alt="person inside circle symbol">
<img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;"
src="../../png/sa.png"
alt="arrow looping back on itself inside circle symbol"><br>
You should <b>carefully review</b> the
<b><a href="https://creativecommons.org/licenses/by-sa/4.0/legalcode.en"
target="_blank"
rel="license noopener noreferrer">CC BY-SA 4.0 LEGAL CODE</a></b>
before using the licensed material.<br>
You may wish to review the
<b><a href="../../license.html"
target="_blank"
rel="license noopener noreferrer">highlights of some of the key features and terms</a></b>
of <b>CC BY-SA 4.0</b>.<br>
</p>
</div>
<div id="coda"><h3>Coda</h3>
<p>
<a href="https://validator.w3.org/nu/?doc=https%3A%2F%2Fwww.ioccc.org%2F2024%2Fcable1%2Findex.html" rel="nofollow">Nu HTML check this web page</a><br>
<a href="#top">Jump to top</a> <a href="#content">Jump to Content</a> <a href="#inventory">Jump to Inventory</a><br>
</p>
</div>
</div>
<!-- END: this line ends content from: inc/footer.inventory.html -->
<!-- START: this line starts content from: inc/bottom.default.html -->
</body>
</html>
<!-- END: this line ends content from: inc/bottom.default.html -->
+27
View File
@@ -0,0 +1,27 @@
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<sys/mman.h>
#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||_()("%s",$[P]))if(!
(*_?$=*++_:0)){if($<3&&p>=U)for(_()("\n\n> "),0<scanf("%[^\n]%*c",Y)?U=*B=1:exit(0),p=_(s)(o=X,"[INST] %s%s [/INST]",s?
"":"<<SYS>>\n"S"\n<</SYS>>\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););p<U?
$=B[p++]:fflush(0);x D)R=$*D+i,r[i]=m->c[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;}}
+27
View File
@@ -0,0 +1,27 @@
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<sys/mman.h>
#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||_()("%s",$[P]))if(!
(*_?$=*++_:0)){if($<3&&p>=U)for(_()("\n\n> "),scanf("%[^\n]%*c",Y)?U=*B=1:exit(0),p=_(s)(o=X,"[INST] %s%s [/INST]",s?
"":"<<SYS>>\n"S"\n<</SYS>>\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););p<U?
$=B[p++]:fflush(0);x D)R=$*D+i,r[i]=m->c[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;}}
+91
View File
@@ -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
+97
View File
@@ -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"
}
]
}
+7
View File
@@ -0,0 +1,7 @@
#
# sort with: ../../bin/sgi.sh
*~
*.dSYM
*.o
.DS_Store
.*.swp
+1
View File
@@ -0,0 +1 @@
2024/cable2
Binary file not shown.
+210
View File
@@ -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
Loaded 100 of 443 files, more files were not shown because too many files have changed in this diff. Show more