Merge pull request #1766 from xexyl/ferguson12020

This commit is contained in:
Landon Curt Noll authored and GitHub committed 2023-12-21 11:13:08 -08:00
commit b3be3fa7fb
12 files changed
+53 -3254

No files matched your search

-334
View File
@@ -1,334 +0,0 @@
<!doctype html public "-//W3C//DTD HTML 4.0 Transitional //EN">
<html>
<head>
<meta name="GENERATOR" content="mkd2html 2.2.2">
<meta http-equiv="Content-Type"
content="text/html; charset=utf-8"> <link rel="stylesheet"
type="text/css"
href="../hint.css" />
<title></title>
</head>
<body>
<CENTER>
<IMG SRC="/png/ioccc.png" ALT="IOCCC" height=78 width=267>
<P><FONT size="6"><I>The International Obfuscated C Code Contest</I></FONT></P>
<div id="bar">
<ul>
<li><a href="../index.html">About the 27th IOCCC</a></li>
<li><a href="../whowon.html">27th IOCCC Winners</a></li>
<li><a href="/index.html">IOCCC home</a></li>
<li><a href="/winners.html">List of All Winners</a></li>
<li><a href="/judges.html">The Judges</a></li>
</ul>
</div>
<P><FONT size="6"><B>Supplemental Info</B></FONT></P>
</CENTER>
<p>Current bugs and things that look like bugs but are not, as of 12 September 2020.</p>
<p><a name="toc"></a></p>
<ul>
<li><p><a href="#builtin-test-unit">Built-in test unit for some features!</a></p></li>
<li><p><a href="#stillsnake">The snake doesn't seem to be moving</a></p></li>
<li><p><a href="#getch">getch() also accepts input from some input hardware other than keyboards</a></p></li>
<li><p><a href="#size">SIZE=0 is the same as SIZE=1 and other oddities</a></p></li>
<li><p><a href="#bitetail">'I was a few places behind my tail and I ran into it!'</a></p></li>
<li><p><a href="#middleofsnake">With negative growth the snake drops from the middle of the body</a></p></li>
<li><p><a href="#buginsnake">It looks like the bug is in the snake</a></p></li>
<li><p><a href="#bugplacement">On the safety of the bug placement loop</a></p></li>
<li><p><a href="#verticalsnake">Vertical snake has more space between snake char than horizontal</a></p></li>
</ul>
<h1><a name="builtin-test-unit" href="#toc">Built-in test unit for some features!</a></h1>
<p>Fun fact: There&rsquo;s something of a built-in test unit for some features; much
like some of the other features this was not intentionally designed but is
simply a fun consequence of the features I did implement.</p>
<p>Let&rsquo;s say you want to verify that the evade mode is at the right count. How
can you verify it without modifying the code? Try:</p>
<pre><code> SIZE=0 SHED=1 SHEDS=1 EVADE=10 ./prog
</code></pre>
<p>Since you start out at size 0 and you shed every movement then when you&rsquo;re
size 10 (as long as you don&rsquo;t eat a bug of course!) the bug should evade.</p>
<p>If you set it to <code>SIZE=10</code> there would be a difference of 10. Now every
move you will see the size the snake is. But then&hellip;Why is it that it
doesn&rsquo;t seem to move until the snake is of size 20? Because you start out at
size 10 of course (but in fact if you observe the snake won&rsquo;t appear to be
of size 20 yet).</p>
<p>There probably are combinations that can test these types of things I just
don&rsquo;t at this time remember any I might have done.</p>
<h1><a name="stillsnake" href="#toc">The snake doesn&rsquo;t seem to be moving</a></h1>
<p>One way to show this is in full is to set the initial size and growth size to a
high value; then try each one individually. For example:</p>
<pre><code> SIZE=100 ./prog
</code></pre>
<p>In this case after you make the first move the snake will keep growing and
so the snake tail stays in the same spot until after it&rsquo;s the &lsquo;full size&rsquo;.
When it has reached the full size then the entire body of the snake will
start to move too (i.e. if the tail isn&rsquo;t moving it is growing or else paused).</p>
<p>In several tests I set the initial size to a high value, the max to a higher
value still and enabled cannibalism and much of the screen was full of the snake
before it started to move. The <a href="cannibalism.log">cannibalism.log</a> has some examples of both
cannibalism and a long snake that didn&rsquo;t move for most of the game.</p>
<p>If however you let the snake get to the full size then eat a bug there can
be a moment of lingering where it appears the snake moves for a few places
before it then stops moving and just grows until it&rsquo;s the full size.</p>
<p>It can also appear to be not moving when the snake is extraordinarily long
and more so when the snake has just eaten: which of course is when it would
grow (just like when shedding). Even so sometimes it takes a moment for the
snake tail to catch up with the body (so to speak) so that it could for a
few moments be difficult to know if where you&rsquo;re going is going to be
occupied or not.</p>
<p>Basically if the snake head is moving you can consider the snake to be
moving or growing and that&rsquo;s the important point (if you have the default
status line you can also see the coordinates being updated to show this).</p>
<h1><a name="getch" href="#toc">getch() also accepts input from some input hardware other than keyboards</a></h1>
<p>On my MacBook Pro the trackpad has actually triggered directions; if I were to
swipe up and then down the snake would run into itself. I believe this has to do
with the function call <code>keypad(v, 1);</code> which enables arrow keys.</p>
<h1><a name="size" href="#toc">SIZE=0 is the same as SIZE=1 and other oddities</a></h1>
<p>What this means is that for both you will only have the snake head. At this point
you can safely go back on yourself even without cannibalism enabled. This is
intentional; a snake size of 0 is pointless but why should it not be playable
anyway?</p>
<p>If SIZE &lt; 0 you&rsquo;ll likely win straight away since it&rsquo;s unsigned and it&rsquo;ll wrap
back to the maximum so you will win automatically (this is the same as the
second mode the judges suggested with <code>SIZE=-1 ./prog</code>).</p>
<p>As for the growth sizes (including shedding) if it&rsquo;s &lt; 0: the snake will still
lose its length and display will still be odd: because the snake size is
decreased any element beyond the reduced size isn&rsquo;t touched so the snake
characters will remain on the screen; only the moving snake is what matters.
But it&rsquo;s likely the game will be won fairly quickly because once it&rsquo;s -1 in size
it&rsquo;ll be at the maximum size.</p>
<p>For example if I say <code>SIZE=3 GROW=-2</code> at two bugs the game is won.</p>
<p>As for growing: anything > 0 it will grow that many; 0 it will not grow (which I
show as a gameplay mode); and &lt; 0 it will &lsquo;shrink&rsquo; as I explained above. You could
say that it&rsquo;s defying physics by growing and shrinking simultaneously but either
way negative size will force a win.</p>
<p>Here&rsquo;s a fun output:</p>
<pre><code> &lt; &lt;&lt;&lt;+
</code></pre>
<p>That&rsquo;s from:</p>
<pre><code> SHED=1 SHEDS=-1 ./prog
</code></pre>
<p>And right after that you would see:</p>
<pre><code> YOU WIN!
X:72/156 Y:20/41 S:997/997 B:0
</code></pre>
<p>Try this though:</p>
<pre><code> SHEDS=-1 SHED=25 ./prog
</code></pre>
<p>And you&rsquo;ll see that you start to be the normal size but then you leave your
head several places until you end up getting to the max size (by way of it
being unsigned). This isn&rsquo;t a bug even if it might seem like one. In fact
this is the basis of the grow/shrink mode of play that I talk about in the
<a href="gameplay.md">gameplay.md</a> (<a href="gameplay.html">gameplay.html</a>) file.</p>
<p>Here&rsquo;s another thing to be aware of. Let&rsquo;s say you do:</p>
<pre><code> SIZE=1 GROW=-1 ./prog
</code></pre>
<p>How many bugs will it take before you win? In fact it&rsquo;s two: you would see the
head twice: the second time once you &lsquo;shrink&rsquo; down to size 0; it would then be
that if you get another bug you will be at the &lsquo;max size&rsquo;:</p>
<pre><code> YOU WIN!
X:81/156 Y:35/41 S:997/997 B:2
</code></pre>
<h1><a name="bitetail" href="#toc">&lsquo;I was a few places behind my tail and I ran into it!&rsquo;</a></h1>
<p>I.e. what happens if you&rsquo;re growing - for example after just eating a bug - and
you&rsquo;re racing towards your tail? If you&rsquo;re behind it should be fine since you&rsquo;re
going the same speed as the snake is, right? Not quite. Because you&rsquo;re growing
you might end up running into your tail (depending on how much you&rsquo;ve left to
grow and how far away from your tail)! This happened to me once and it surprised
me and I figured I better note it.</p>
<p><strong>Remember: the tail at that point isn&rsquo;t moving yet; the snake is growing!</strong></p>
<h1><a name="middleofsnake" href="#toc">With negative growth the snake drops from the middle of the body</a></h1>
<p>For instance it might look like this (the first line is as it happens, the
second pointing to where it happens and the third being what&rsquo;s left after the
rest of the snake has gone through). Doing <code>SHED=100 SHEDS=-1</code>:</p>
<pre><code> ooooooooo&gt;ooo&gt;
^
&gt;
</code></pre>
<p>The ^ points to the part that&rsquo;s split from the snake and which will be
there on its own after the snake passes through it. Here&rsquo;s an example with
it being <code>SHEDS=-3</code>:</p>
<pre><code> &lt;ooo&lt;ooooo
^^^
&lt;oo
</code></pre>
<p>If you go through the part that has split (which for some might be difficult
to see whilst the snake has not fully left its skin) you won&rsquo;t run into
yourself; if you run into another part though you do. This might be a bit
confusing I know but what kind of animal shrinks in size by leaving its head
behind only to sprout up a new head? Actually&hellip;on second thought, I won&rsquo;t
go there! :)</p>
<p>Anyway it&rsquo;s an odd idea for the snake to shrink by leaving part of its skin:
that&rsquo;s how they grow in the wild so it&rsquo;s a misnomer. The shrinking was only
&lsquo;discovered&rsquo; because it&rsquo;s an unsigned number but happily it allows for different
gameplay modes.</p>
<h1><a name="buginsnake" href="#toc">It looks like the bug is in the snake</a></h1>
<p>I show a different example in the <a href="crazy.log">crazy.log</a> file but what defines a coordinate
which the snake occupies? If the snake breaks apart then the only part
of the screen the snake is occupying is the place which is actually moving: if
the snake decreases in size by 3 then the three respective characters you can go
through safely. But this also means that a bug can go there! So you might see
something like:</p>
<pre><code> &lt;*oooooooo
</code></pre>
<p>This is because the snake is no longer there: in fact in this run the snake was
quite a bit lower on the screen and 25 in length.</p>
<h1><a name="bugplacement" href="#toc">On the safety of the bug placement loop</a></h1>
<p>Ilya Kurdyukov shared concern for the loop in the bug placement routine: is it
safe? What he refers to is that it&rsquo;s a potential infinite loop. But is it? I
understand the concern and it&rsquo;s something I played with a lot to be sure that it
doesn&rsquo;t happen. This is how it works.</p>
<p>To explain it I will go back to the make test program <code>termcaps</code> (which is
imperfect for the recommended terminal size but the max snake size is exactly
how it&rsquo;s done in Snake and works well). The minimum terminal size I require in
the game is 10 x 10. This includes the walls and score line.</p>
<p>Now the default max snake size is 997 but when the terminal is too small it
adjusts the max snake size. For 10 lines and 10 columns you would see:</p>
<pre><code> $ make test
terminal supports cursor movement
terminal supports making cursor invisible
terminal supports bold
terminal supports colours
terminal rows 10 (7 playable)
terminal cols 10 (8 playable)
snake size: 49 (max size: 49)
bugs: 9 (max size: 9)
at least 28 columns recommended for snake size 49 (is 10)
at least 28 columns recommended for snake size 49 (is 10)
1 problem detected (0 fatal).
make: *** [test] Error 1
</code></pre>
<p>First: what&rsquo;s the problem? It&rsquo;s just a warning that for the snake size of 49 the
recommended size of columns is 28. However this is just for the score text; with
only 10 columns it will overflow and wrap to the next line(s). But if you observe
that 49 is the max snake size. How is this derived and why?</p>
<p>With 10 rows and columns it&rsquo;s calculated as 7 * 7 (i.e. it&rsquo;s
<code>(cols-3)*(rows-3)</code>. However the number of playable locations is in this case 56
(<code>playable_rows * playable_columns</code>). I have played with this many
times and I do not believe there should be a problem. If there is it&rsquo;s from a
very poor implementation of rand() and I discuss this in
<a href="troubleshooting.md">troubleshooting.md</a> (<a href="troubleshooting.html">troubleshooting.html</a>).</p>
<p>There I also give some test outputs without the cap in place to give an idea of
when it became a problem (or would have). In short this is known but I do not
think it will be a problem and I have given resolutions. In any event without
cannibal mode it&rsquo;s even less likely that you&rsquo;ll ever run into this problem.</p>
<p>The obvious question is why didn&rsquo;t I put in a break? Because of the IOCCC size
rule 2 and what would it do anyway? I guess it would win but to my mind that is
a bug and I prefer putting in restrictions to try and make it very unlikely.</p>
<h1><a name="verticalsnake" href="#toc">Vertical snake has more space between snake char than horizontal snake</a></h1>
<p>Ilya Kurdyukov also pointed out that depending on orientation of the snake there
are different amount of spaces between the snake char &lsquo;o&rsquo;. This is what he
had to say on it:</p>
<blockquote><p>Yes, it is the problem, space in character terminal is not isotropic
from a viewer (gamer) perspective so one step up look like two steps
right.</p>
<p>MATE Terminal 1.20.0, and font &ldquo;Ubuntu Mono Regular 13&rdquo;</p>
<p>But, as I said, there is no terminal problem itself, it&rsquo;s because
character tiles are not square (except for Japanese/Chinese, Japanese
even have so called full-width English characters in their encoding,
presented in UTF too).</p>
<p><a href="https://en.wikipedia.org/wiki/Halfwidth_and_fullwidth_forms">https://en.wikipedia.org/wiki/Halfwidth_and_fullwidth_forms</a></p>
<p>So the typical fonts are Half-width or close to it.</p>
<p><img src="halfwidth_vs_fullwidth.png"></p></blockquote>
<p>However the function <code>mvaddch()</code> takes a <code>chtype</code> which amounts to a C char
with additional information and so the full width Ois too big for the
function call. He reminded me of the old DOS box chars but even if this was
easily duplicable (and it might be and I don&rsquo;t remember) the logic would
have to be changed for drawing the snake and in such a way that would change
the source code layout too much - to say nothing else of the fact I have
also forgotten some of what I did obfuscation wise (and the
<a href="spoilers.markdown">spoilers</a> aren&rsquo;t enough here!).</p>
<p>That being said the font and font size does seem to have somewhat of an
effect on it since his screenshots have wider gaps than mine.</p>
<p>Once again thank you mate for bringing this to my attention and also playing
with it and providing the resources! Much appreciated! (And although you
suggested it is bugging me I once again here say it&rsquo;s not at all bugging me
but it is very much appreciated and it means a great deal to me. Cheers.)</p>
<BR>
<HR>
<TABLE><TR>
<TD><a rel="license" href="https://creativecommons.org/licenses/by-sa/3.0/"><img alt="Creative Commons License" style="border-width:0" src="/png/by-sa-3.0-88x31.png" /></a></TD>
<TD><P>&copy; Copyright 1984-2020,
<A HREF="/judges.html">Leo Broukhis, Simon Cooper, Landon Curt Noll</A>
- All rights reserved<BR>
This work is licensed under a <a rel="license" href="https://creativecommons.org/licenses/by-sa/3.0/">Creative Commons Attribution-ShareAlike 3.0 Unported License</a>.</P></TD>
<TD>&nbsp;<!--<a href="https://validator.w3.org/check?uri=referer"><img src="https://www.w3.org/Icons/valid-html401" alt="Valid HTML 4.01 Transitional" height="31" width="88"></a>--></TD>
</TR></TABLE>
</body>
</html>
-203
View File
@@ -1,203 +0,0 @@
<!doctype html public "-//W3C//DTD HTML 4.0 Transitional //EN">
<html>
<head>
<meta name="GENERATOR" content="mkd2html 2.2.2">
<meta http-equiv="Content-Type"
content="text/html; charset=utf-8"> <link rel="stylesheet"
type="text/css"
href="../hint.css" />
<title></title>
</head>
<body>
<CENTER>
<IMG SRC="/png/ioccc.png" ALT="IOCCC" height=78 width=267>
<P><FONT size="6"><I>The International Obfuscated C Code Contest</I></FONT></P>
<div id="bar">
<ul>
<li><a href="../index.html">About the 27th IOCCC</a></li>
<li><a href="../whowon.html">27th IOCCC Winners</a></li>
<li><a href="/index.html">IOCCC home</a></li>
<li><a href="/winners.html">List of All Winners</a></li>
<li><a href="/judges.html">The Judges</a></li>
</ul>
</div>
<P><FONT size="6"><B>Supplemental Info</B></FONT></P>
</CENTER>
<h1>Double-layered Chocolate Fudge Cake</h1>
<p>Here's a delicious double-layered chocolate fudge cake that is
something of my mum's speciality. It's complicated and I should warn that nobody
has seemed to get it down as well as she has but it's well worth the effort if
you love chocolate. My late stepmum who only liked white chocolate loved this
cake!</p>
<p><img src='cake.jpg' alt='picture of the double-layered chocolate fudge cake'></p>
<p>There are two sets of ingredients and instructions; the cake and the icing. In
addition there are some notes to pay attention to; some will be repeated because
they're really important for the quality of the cake.</p>
<p>Below I have included the ingredients separately but I include them within the
instructions as well and in bold. Also in bold are some of the special notes.</p>
<p>Finally note that depending on where you are in the world this might not work in
the warmer months of the year for the icing in particular. Oh and here's an
amusing fact about the <a href="http://www.gomc.com/firstpage/200103068.pdf">IOCCC and chocolate</a>. Did I say 'the IOCCC'? I actually
meant <strong>'an IOCCC'</strong>: it stands also for <strong>'International Office of Cocoa, Chocolate
and Sugar Confectionery'</strong>. Perfect.</p>
<p>See also the <a href="https://web.archive.org/web/20200805053007/https://twitter.com/ilyakurdyukov/status/1290520266087571458">International Original Chocolate Cake Contest tweet</a> from
<a href="https://www.ioccc.org/winners.html#Ilya_Kurdyukov">fellow IOCCC winner Ilya Kurdyukov</a> (<a href="https://github.com/ilyakurdyukov">GitHub</a>) as well as the
<a href="ioccc-cake.jpg">IOCCC cake source image</a> of the picture in the tweet (which he painted over
my photo of the cake with GIMP).</p>
<h2>Measurements</h2>
<p>This was originally from an American cookery book so the measurements are in the
US standards. A nice resource (that has much more than just cooking) is
<a href="http://www.onlineconversion.com/cooking.htm">http://www.onlineconversion.com/cooking.htm</a>. This will particularly matter
for cups, teaspoons, tablespoons and ounces.</p>
<h2>Baker's chocolate</h2>
<p>Baker's chocolate is a brand name and the product in question is unsweetened
chocolate bars used for baking. According to a <a href="https://www.davidlebovitz.com/chocolate-faqs/">chocolates FAQ</a> it might be
called different things:</p>
<pre><code>Bitter chocolate contains no sugar and is often called 'unsweetened' or
'baking' chocolate. In some countries it's called 100% cacao since it's
composed only of ground up cocoa beans, and nothing else.
</code></pre>
<p>The FAQ suggests that you might have to look for a baking supply shop but I
cannot offer any specific advice other than it's unsweetened chocolate bars for
baking. The FAQ talks about what looks like substitutes but I have no idea what
that would turn out as; I somehow suspect it wouldn't be good.</p>
<p>Either way please <strong>still pay attention to the notes on the chocolate in the recipe and
recipe notes because they're really important!</strong></p>
<h2>Special notes for the cake</h2>
<p><strong>PAY CLOSE ATTENTION TO THESE:</strong></p>
<ul>
<li><p><strong>USE MARGARINE</strong>. Butter does not work well. If you think it will come out
better by using butter you're very mistaken; it will come out badly!</p></li>
<li><p>Over the years they changed the size of the unsweetened chocolate squares;
they used to be one ounce each now they are 1/4 ounce each square so be sure to
note the amount is by ounce not squares as listed. See the measurements link
if there's any doubt.</p></li>
<li><p>Pay careful attention to <strong>COOK FOR ONLY THE INDICATED TIME</strong>.</p></li>
<li><p><strong>REMOVE THE CAKE FROM THE PANS 2 MINUTES AFTER REMOVING FROM OVEN</strong>. Then allow
to fully cool on racks. The important point is that they don't overcook.</p></li>
<li><p>When the recipe was first written they sold powdered sugar in a box; now
it's confectioners sugar in a bag. My mum experimented with the amount and
found that 4 cups seems about right.</p></li>
<li><p>She uses <strong>WHOLE MILK</strong> for this recipe; she doesn't know if it really matters
but given that she and I both prefer skim milk except for here and in
chocolate milk I would recommend whole milk for this recipe too. In any case
it turns out great <strong>if you follow <em>everything</em> to a T!</strong></p></li>
<li><p>Use only <strong>PURE VANILLA EXTRACT</strong>! Do <strong>NOT USE imitation vanilla!</strong></p></li>
</ul>
<h2>Cake Ingredients</h2>
<ul>
<li>3 oz unsweetened (Baker's) chocolate</li>
<li>2 and 1/4 cups flour</li>
<li>2 tbsp baking soda</li>
<li>1/2 tsp salt</li>
<li>2 and 1/4 cups packed brown sugar</li>
<li>3 eggs</li>
<li>1 and 1/2 tsp vanilla</li>
<li>1/2 cups margarine</li>
<li>1 cup (boiling) water</li>
<li>1 cup sour cream</li>
</ul>
<h2>Cake Preparation</h2>
<ol>
<li><p>Lightly grease two 9 x 1.5 inch round pans; lightly dust with flour.</p></li>
<li><p>Preheat oven to 350 F (176.67 C).</p></li>
</ol>
<h2>Cake Directions</h2>
<ol>
<li><p>Melt <strong>3 oz unsweetened chocolate</strong> in double boiler or small bowl over
<strong>hot (<em>but not boiling</em>) water</strong>; let cool whilst proceeding.</p></li>
<li><p>Sift <strong>2 1/4 cups flour</strong>, <strong>2 tsp baking soda</strong>, and <strong>1/2 tsp salt</strong></p></li>
<li><p>Beat <strong>1 stick margarine</strong> in large bowl <em>until soft</em>.</p></li>
<li><p>Add <strong>2 1/4 cups packed brown sugar</strong> and <strong>3 eggs</strong>. Beat until light and
fluffy.</p></li>
<li><p>Beat in <strong>1 1/2 tsp vanilla</strong> and <strong>cooled melted chocolate</strong>.</p></li>
<li><p>Stir in dry ingredients alternately with <strong>1 cup sour cream</strong>; always beat
until smooth.</p></li>
<li><p>Stir in <strong>1 cup boiling water</strong>.</p></li>
<li><p>Pour into prepared pans.</p></li>
<li><p>Bake for <strong>ONLY 35 minutes</strong> (NO LONGER) at 350 F (176.67 C).</p></li>
<li><p>When you take the cake out put the cake pans on a cooling rack for <strong>TWO
MINUTES ONLY AND THEN IMMEDIATELY TURN CAKES OUT ON TO RACK</strong>. Let cool
completely.</p></li>
</ol>
<h2>Icing Ingredients</h2>
<ul>
<li>4 oz unsweetened chocolate (Baker's chocolate)</li>
<li>1/2 cup margarine</li>
<li>4 cups powdered sugar</li>
<li>1/2 cup whole milk</li>
<li>2 tsp vanilla</li>
</ul>
<p>You will also need a bigger pan or bowl that can have ice water that the icing
bowl can sit in.</p>
<h2>Special notes for the icing</h2>
<p><strong>PAY CLOSE ATTENTION TO THESE:</strong></p>
<ul>
<li><p>Make sure that the melted chocolate and margarine does not get solid.</p></li>
<li><p>For step #4 put <strong>8 to 10 ice cubes</strong> in a pan or big bowl (that's big
enough that another bowl can fit in it). Add an inch of water and then set
the bowl with the icing in the pan or bowl of ice water. <strong>Do not let the
icing get wet!</strong></p></li>
<li><p>Do not let icing get too thick.</p></li>
<li><p>Use <strong>whole milk.</strong></p></li>
<li><p>Use only <strong>pure vanilla extract</strong>! Do <strong>not use imitation vanilla!</strong></p></li>
</ul>
<h2>Icing Directions</h2>
<ol>
<li><p>Combine <strong>4 oz unsweetened chocolate</strong> and <strong>1/2 cup margarine</strong> in pan.
Melt and remove from heat. <strong>DO NOT LET IT GET SOLID.</strong></p></li>
<li><p>Combine <strong>3 1/4 cups powdered sugar</strong>, <strong>1/2 cups whole milk</strong> and <strong>2 tsp
vanilla</strong> into a bowl. <strong>Stir until smooth</strong>.</p></li>
<li><p>Add chocolate mixture.</p></li>
<li><p>Set bowl in pan/bowl of ice and water. Beat with spoon/mixer until it's
thick BUT not too thick. Make sure icing doesn't get wet! The idea is to
<strong>MAKE THE BOWL IT'S IN COLD <em>but not let the icing get wet</em></strong>.</p></li>
</ol>
<TABLE><TR>
<TD><a rel="license" href="https://creativecommons.org/licenses/by-sa/3.0/"><img alt="Creative Commons License" style="border-width:0" src="/png/by-sa-3.0-88x31.png" /></a></TD>
<TD><P>&copy; Copyright 1984-2020,
<A HREF="/judges.html">Leo Broukhis, Simon Cooper, Landon Curt Noll</A>
- All rights reserved<BR>
This work is licensed under a <a rel="license" href="https://creativecommons.org/licenses/by-sa/3.0/">Creative Commons Attribution-ShareAlike 3.0 Unported License</a>.</P></TD>
<TD>&nbsp;<!--<a href="https://validator.w3.org/check?uri=referer"><img src="https://www.w3.org/Icons/valid-html401" alt="Valid HTML 4.01 Transitional" height="31" width="88"></a>--></TD>
</TR></TABLE>
</body>
</html>
+17 -11
View File
@@ -3,7 +3,7 @@
Here's a delicious double-layered chocolate fudge cake that is
something of my mum's speciality. It's complicated and I should warn that nobody
has seemed to get it down as well as she has but it's well worth the effort if
you love chocolate. My late stepmum who only liked white chocolate loved this
you love chocolate. My late stepmum who only liked white 'chocolate' loved this
cake!
![picture of the Double-layered chocolate fudge cake](cake.jpg)
@@ -69,21 +69,23 @@ recipe notes because they're really important!**
note the amount is by ounce not squares as listed. See the measurements link
if there's any doubt.
* Pay careful attention to **COOK FOR ONLY THE INDICATED TIME**.
* Pay careful attention to **COOK FOR ONLY THE INDICATED TIME**. Note that if
your oven cooks a bit hotter you might have to adjust the timing a bit. This
is likely the case if the cake comes out a little bit dry.
* **REMOVE THE CAKE FROM THE PANS 2 MINUTES AFTER REMOVING FROM OVEN**. Then allow
to fully cool on racks. The important point is that they don't overcook.
* **REMOVE THE CAKE FROM THE PANS 2 MINUTES AFTER REMOVING FROM OVEN** and
then allow to **FULLY COOL *ON RACKS*!** The important point is that they
don't overcook.
* When the recipe was first written they sold powdered sugar in a box; now
it's confectionery sugar in a bag. My mum experimented with the amount and
found that 4 cups seems about right.
* She uses **WHOLE MILK** for this recipe; she doesn't know if it really matters
but given that she and I both prefer skim milk except for here and in
chocolate milk I would recommend whole milk for this recipe too. In any case
it turns out great **IF YOU FOLLOW *EVERYTHING* TO A T!**
* Use **WHOLE MILK**. It's just better for something like this and skim milk
or low fat milk is completely untested.
* Use only **PURE VANILLA EXTRACT**! Do **NOT USE imitation vanilla!**
* Use only **PURE VANILLA EXTRACT**! Do **NOT USE imitation vanilla!** Not
following this rule will lead to a worse outcome.
## Cake Ingredients
@@ -161,7 +163,11 @@ bowl can sit in.
* Use **WHOLE MILK.**
* Use **ONLY PURE VANILLA EXTRACT**! **DO NOT USE IMITATION VANILLA!**
* Use **ONLY PURE VANILLA EXTRACT**! **DO NOT USE IMITATION VANILLA!** Not
following this rule will lead to a worse outcome. As I recall the icing was
quite a bit worse (but still good) the times we had imitation vanilla. Just
don't do it.
## Icing Directions
@@ -181,7 +187,7 @@ bowl can sit in.
[picture]: cake.jpg
[http://www.onlineconversion.com/cooking.htm]: http://www.onlineconversion.com/cooking.htm
[IOCCC and chocolate]: http://www.gomc.com/firstpage/200103068.pdf
[IOCCC and chocolate]: ioccc-and-chocolate.pdf
[International Original Chocolate Cake Contest tweet]: https://web.archive.org/web/20200805053007/https://twitter.com/ilyakurdyukov/status/1290520266087571458
[fellow IOCCC winner Ilya Kurdyukov GitHub]: https://github.com/ilyakurdyukov
[GitHub]: https://github.com/ilyakurdyukov
-838
View File
@@ -1,838 +0,0 @@
<!doctype html public "-//W3C//DTD HTML 4.0 Transitional //EN">
<html>
<head>
<meta name="GENERATOR" content="mkd2html 2.2.2">
<meta http-equiv="Content-Type"
content="text/html; charset=utf-8"> <link rel="stylesheet"
type="text/css"
href="../hint.css" />
<title></title>
</head>
<body>
<CENTER>
<IMG SRC="/png/ioccc.png" ALT="IOCCC" height=78 width=267>
<P><FONT size="6"><I>The International Obfuscated C Code Contest</I></FONT></P>
<div id="bar">
<ul>
<li><a href="../index.html">About the 27th IOCCC</a></li>
<li><a href="../whowon.html">27th IOCCC Winners</a></li>
<li><a href="/index.html">IOCCC home</a></li>
<li><a href="/winners.html">List of All Winners</a></li>
<li><a href="/judges.html">The Judges</a></li>
</ul>
</div>
<P><FONT size="6"><B>Supplemental Info</B></FONT></P>
</CENTER>
<p>Playing the game is very simple but because there are many different modes I
have included much more than just the input keys and a few printouts of the
game. For normal play you probably don&rsquo;t even need this file at all unless it be
for the input keys.</p>
<p><a name="toc"></a></p>
<ol>
<li><p><a href="#support">Testing terminal environment/capabilities</a></p></li>
<li><p><a href="#input">Input keys</a></p></li>
<li><p><a href="#gameplay">Gameplay</a></p>
<ul>
<li><p><a href="#initial">The initial screen</a></p></li>
<li><p><a href="#playing">Playing the game</a></p></li>
<li><p><a href="#walls">Walls</a></p></li>
<li><p><a href="#cannibalism">Cannibalism</a></p></li>
<li><p><a href="#shedding">Stretching (shedding)</a></p></li>
<li><p><a href="#winning">Winning</a></p></li>
<li><p><a href="#quitting">Quitting</a></p></li>
</ul>
</li>
<li><p><a href="#modes">Gameplay modes</a></p>
<ul>
<li><p><a href="#warning"><strong>Photosensitive epilepsy/Stimulation overload trigger warnings</strong></a></p></li>
<li><p><a href="#drawing">Drawing / Practice mode</a></p></li>
<li><p><a href="#auto">Computer playing / Automatic mode (<strong>Photosensitive epilepsy/Stimulation overload trigger</strong>)</a></p>
<ul>
<li><a href="#auto-variations">Variations</a></li>
</ul>
</li>
<li><p><a href="#grow-shrink">Grow-Shrink (Positive/Negative Winning) mode</a></p></li>
<li><p><a href="#hypnotic">Hypnotic / Sleepy mode (<strong>Photosensitive epilepsy/Stimulation overload trigger</strong>)</a></p></li>
<li><p><a href="#stim">Stimulation / Calming mode</a></p></li>
<li><p><a href="#other-ideas">Other ideas</a></p></li>
</ul>
</li>
<li><p><a href="#scripts">Scripts</a></p>
<ul>
<li><p><a href="#colours">Colours selection</a></p></li>
<li><p><a href="#preset">Automate the above gameplay modes</a></p></li>
</ul>
</li>
<li><p><a href="#variables">Notes about some of the game variables</a></p>
<ul>
<li><p><a href="#wait">WAIT - Snake speed</a></p></li>
<li><p><a href="#evade">EVADE - Bug evasion frequency</a></p></li>
<li><p><a href="#sizes">SIZE / MAXSIZE - Initial snake / max sizes</a></p></li>
<li><p><a href="#growth">GROW / SHEDS - Growth / Shedding sizes</a></p></li>
</ul>
</li>
<li><p><a href="#conclusions">Conclusion (and inspirational words for everyone)</a></p></li>
</ol>
<h1>1. <a name="support" href="#toc">Testing terminal environment/capabilities</a></h1>
<p>Most people probably won&rsquo;t have any issue at all but for those who have any
problems with the terminal see the <a href="terminals.md">terminals.md</a> file for more
information on the terminal capabilities testing utility I include.</p>
<p>For troubleshooting other problems see <a href="troubleshooting.md">troubleshooting.md</a>
(<a href="troubleshooting.html">troubleshooting.html</a>) and <a href="bugs.md">bugs.md</a> (<a href="bugs.html">bugs.html</a>).</p>
<h1>2. <a name="input" href="#toc">Input keys</a></h1>
<ul>
<li><p>Left, right, up and down <strong>arrow keys</strong>: Move that direction.</p></li>
<li><p>&lsquo;q&rsquo; (and &lsquo;Q&rsquo;): Quit the game.</p></li>
<li><p>Space (<code>' '</code>): Pause/resume the game (direction keys will also resume).
Note that no other keys will resume the game; however if you press a key
that <code>getch()</code> picks up on and the game is not paused then it will be as if
you pressed the current direction key (assuming you already moved the snake).</p></li>
</ul>
<h1>3. <a name="gameplay" href="#toc">Gameplay</a></h1>
<p>Here I will show the initial screen as well as what a few things look like. If
you don&rsquo;t feel you need this but you want to configure colours jump to <a href="#colours">colour
selection</a>. You can also jump to <a href="#modes">gameplay modes</a> or <a href="#variables">game
variables</a>.</p>
<p>The bug colour by default is white; the snake head colour is red and the snake
body colour is green. The walls are cyan.</p>
<h2><a name="initial" href="#toc">Gameplay: The initial screen</a></h2>
<p>When you load the game you will see a screen that looks something like the
below. Note that the top line is the score/status line: the top wall is at line
1 and the left wall is column 0. Below I use the coordinates in the X/Y order
(ncurses is the opposite: Y/X). I will parenthesise the numbers below to refer
to the number in the diagram:</p>
<pre><code> X:24/49 Y:8/16 S:5/658 B:0
##################################################
# #
# #
# #
# #
# #
# #
# + #
# #
# * #
# #
# #
# #
# #
# #
##################################################
</code></pre>
<ul>
<li><p>The snake (<code>+</code>) is at (24),(8). The bug char is <code>*</code> and the wall char is
<code>#</code>. When the snake moves the head will be an arrow facing the direction it
is moving; the body is &lsquo;o&rsquo;.</p></li>
<li><p>The top wall is always line (1), the left wall is always column (0), the
bottom wall is line (16) and the right wall is column (49). If walls are
impassable and you run into any of these the game is over (you can slither
at the edge of the wall); else you&rsquo;ll come out the opposite side.</p></li>
<li><p>The snake size is (5): but until you start to move it&rsquo;s technically 1 (even
if you set <strong>SIZE=0</strong> this applies). This is so that you can decide which
direction from the centre of the screen. By default the head colour is red;
the body is green. The snake will grow by one until it reaches the right
size.</p></li>
<li><p>The maximum snake size is (997): this is the default; it can be changed but
it will always have an upper limit depending on the terminal size.</p></li>
<li><p>The number of bugs eaten so far is 0.</p></li>
</ul>
<h2><a name="playing" href="#toc">Gameplay: Playing the game</a></h2>
<pre><code> X:39/49 Y:8/16 S:5/658 B:0
##################################################
# #
# #
# #
# #
# #
# #
# oooo&gt; #
# #
# * #
# #
# #
# #
# #
# #
##################################################
</code></pre>
<p>I let the snake grow to its full size (with the head at (39),(8)) and I&rsquo;m two
places above the bug so let&rsquo;s go down:</p>
<pre><code> X:39/49 Y:9/16 S:5/658 B:0
##################################################
# #
# #
# #
# #
# #
# #
# oooo #
# v #
# * #
# #
# #
# #
# #
# #
##################################################
</code></pre>
<p>Now you see that the snake is going down and in one move the bug will be eaten.
Let&rsquo;s do that:</p>
<pre><code> X:36/49 Y:10/16 S:10/658 B:1
##################################################
# #
# #
# #
# * #
# #
# #
# #
# #
# ^ o #
# oooo #
# #
# #
# #
# #
##################################################
</code></pre>
<p>Observe that the bug was eaten and a new bug spawned elsewhere. I went left
three and then up one and could slither on to the bug.</p>
<h1><a name="walls" href="#toc">Gameplay: Walls</a></h1>
<p>By default walls are passable (<strong>WALLS=1</strong>). Let&rsquo;s get to full size and go
through the top wall:</p>
<pre><code> X:36/49 Y:15/16 S:10/658 B:1
##################################################
# o #
# o #
# o #
# * o #
# o #
# o #
# o #
# o #
# o #
# #
# #
# #
# #
# ^ #
##################################################
</code></pre>
<p>There you can see I have grown to the full size and went through the top wall;
the head is now at the opposite wall. Continuing:</p>
<pre><code> X:36/49 Y:11/16 S:10/658 B:1
##################################################
# o #
# o #
# o #
# * o #
# o #
# #
# #
# #
# #
# ^ #
# o #
# o #
# o #
# o #
##################################################
</code></pre>
<p>I might then have turned to the left and then shortly go up to get the bug. This
goes on until you lose, quit or win the game.</p>
<p>When you specify <strong>WALLS=0</strong> the walls become an obstacle that end the game. It
might look like (I set the starting size to 150 and had only just started):</p>
<pre><code> X:20/49 Y:2/16 S:150/658 B:0
##################################################
# ^ #
# o #
# o * #
# o #
# o #
# o #
# ooooo #
# #
# #
# #
# #
# #
# #
# #
##################################################
</code></pre>
<p>If I continue going up I will see:</p>
<pre><code> OUCH!
X:20/49 Y:1/16 S:150/658 B:0
</code></pre>
<h1><a name="cannibalism" href="#toc">Gameplay: Cannibalism</a></h1>
<p>By default cannibalism is disabled (<strong>CANNIBAL=0</strong>) so if you run into yourself it might look
something like:</p>
<pre><code> X:45/49 Y:10/16 S:10/658 B:1
##################################################
# #
# #
# #
# * #
# #
# #
# #
# ooooo #
# ^ o #
# ooo #
# #
# #
# #
# #
##################################################
</code></pre>
<p>If I were to do any movement but turn to the left I would run into myself. I&rsquo;ll
go to the right two spaces:</p>
<pre><code> OW!
X:47/49 Y:10/16 S:10/658 B:1
</code></pre>
<p>But <strong>CANNIBAL=1</strong> can look very funny both in movement and still especially
when you go through yourself several times when the snake is rather long. For
example going through walls and the snake a few times:</p>
<pre><code> X:4/49 Y:12/16 S:165/658 B:3
##################################################
#oo o ooooo o o o#
# oooo o ooo o#
# ooooooooooooooooooo#
# o #
# oooooooooo o #
# o o o #
# o oooo o o #
# o o o o #
# ooooooooooooooo #
# o o* #
# oo&gt; o o #
# o oooooooo o #
#oooooooooooooo o oooo oooooooo#
# o o o o o #
##################################################
</code></pre>
<p>I&rsquo;ll go back through myself now:</p>
<pre><code> X:6/49 Y:14/16 S:165/658 B:3
##################################################
#oo o ooooo o o o#
# oooo o ooo o#
# ooooooooooooooooooo#
# o #
# oooooooooo o #
# o o o #
# o oooo o o #
# o o o o #
# ooooooooooooooo #
# o o* #
# ooo o o #
# oo oooooooo o #
#ooooo&gt;oooooooo o oooo oooooooo#
# o o o o o #
##################################################
</code></pre>
<p>If you note that the head is at (6),(14) I will go one more to the right and you
will see that the arrow has moved over:</p>
<pre><code> X:7/49 Y:14/16 S:165/658 B:3
##################################################
#oo o ooooo o o o#
# oooo o ooo o#
# ooooooooooooooooooo#
# o #
# oooooooooo o #
# o o o #
# o oooo o o #
# o o o o #
# ooooooooooooooo #
# o o* #
# ooo o o #
# oo oooooooo o #
#oooooo&gt;ooooooo o oooo oooooooo#
# o o o o o #
##################################################
</code></pre>
<p>Try this: Get a reasonable length and then go back on yourself (if you&rsquo;re going
left go right etc.) and then after some length (but before you get beyond the
snake) turn (so that you go perpendicular) and then watch as the snake starts
unwinding at one place and then suddenly unwinds another direction.</p>
<p>An example of extreme cannibalism is in the <a href="cannibalism.log">cannibalism.log</a> file. It has
more than one run the first of one has several dumps. I didn&rsquo;t move for a long
time: the initial size was 1500 and I would have won before moving if I went
after bugs right away. In the last two captures of the first invocation (the
third and second to last dump) the bug, head and tail of the snake are at:</p>
<pre><code> Bug: line 87, col 47
Head: line 88, col 62; and line 115, col 48
Tail: line 84, col 46; and line 112, col 29
</code></pre>
<p>The final example has the snake inside itself.</p>
<h1><a name="shedding" href="#toc">Gameplay: Shedding (stretching)</a></h1>
<p>This feature will make you grow by the value of <strong>SHEDS</strong> for every <strong>SHED</strong>
movements (the counter isn&rsquo;t incremented when you eat a bug). Basically growing
without eating a bug (stretching would be better name here).</p>
<h1><a name="winning" href="#toc">Gameplay: Winning</a></h1>
<p>If you ever get to the <strong>MAXSIZE</strong> the game is won. You can force a win by
setting the max size to a smaller value than the size you specify (or the
default) or setting the size to higher than the default (or &lt; 0 which will end
up being > the max size though I suppose there might be some value that makes it
less than again - I&rsquo;m not going to try and figure that out however). Anyway:</p>
<pre><code> SIZE=-1 ./prog
YOU WIN!
X:24/49 Y:8/16 S:658/658 B:0
</code></pre>
<p>Observe that the size isn&rsquo;t the default 997: because the screen size is too
small for that value (see <a href="terminals.md">terminals.md</a>).</p>
<p>The reason I chose 997 is that it leaves a bit of a challenge for some (maybe
most) people but it&rsquo;s still winnable. Previously even I couldn&rsquo;t have won unless
maybe a much bigger screen, if both cheat modes were disabled. I probably could
win without any cheat mode enabled on my 24" monitor but I probably would need
at least one cheat mode on my 13" laptop (I don&rsquo;t need both enabled).</p>
<p>The beauty though is the game can be winnable by anyone since you can define the
max size to win. Games are meant to be fun: who enjoys games that can never be
won? Very few probably do and those who do enjoy them it probably are games that
are relaxing and stimulating (which admittedly this game can be - but still I
want it to be winnable too).</p>
<p>Another reason I chose 997: it&rsquo;s prime and the judges love prime numbers.
Actually, this is the main reason for the number: I had changed it down to 1000
but then it occurred to me that there are prime numbers close to 1000 so why not
choose one instead (that was less than 1000)? And so I did. Another fun fact: at
the default starting size and growth size of 5 the number of bugs needed before
the game is won is 199 - also a prime!</p>
<h1><a name="quitting" href="#toc">Gameplay: Quitting</a></h1>
<p>If you wish to quit you can hit &lsquo;q&rsquo; (case-insensitive). For example:</p>
<pre><code> X:24/49 Y:8/16 S:5/658 B:0
</code></pre>
<h1>4. <a name="modes" href="#toc">Gameplay modes</a></h1>
<p>Here I list a number of different modes of play. In the <a href="bugs.md">bugs.md</a>
(<a href="bugs.html">bugs.html</a>) file I even show how there&rsquo;s a built-in test unit for some
modes! There are certainly other modes that could be imagined: the modes below
happened over time and some were simply an accidental discovery or something I
thought of by a chance; others were thought out from the beginning but were
improved over time.</p>
<p>The <a href="play.sh">play.sh</a> script sets up some of these automatically; I describe it after
the modes below.</p>
<h2><a name="warning" href="#toc">Photosensitive epilepsy/Stimulation overload trigger warnings</a></h2>
<p>If you have <strong>photosensitive epilepsy please be careful</strong> especially with low values
for both <strong>WAIT</strong> and <strong>EVADE</strong>. It appears that the <a href="https://www.epilepsysociety.org.uk/photosensitive-epilepsy#.Xjgpwi2ZOgQ">number of hertz (flashes)
per second triggering seizures</a> is wide but depending on the variables it
easily can be in the range.</p>
<p>There are different patterns and lights flashing at different speeds so please
exercise caution. This could trigger seizures and <strong>it might also be too much
stimulation for some people.</strong></p>
<p><strong>Please be careful of these if these types of things have ever affected you or if
you have any form of epilepsy. Thank you.</strong></p>
<h2><a name="drawing" href="#toc">Gameplay mode: Drawing / Practice mode</a></h2>
<p>If you want to draw the snake wherever you like on the screen you can do this by
modifying the wait time (for input) to -1 (or any value &lt; 0): then the snake
does not move until you press a movement key. For example:</p>
<pre><code> WAIT=-1 ./prog
</code></pre>
<p>When you eat a bug the snake will grow and you can draw more. If you want to
make it so you can go through yourself:</p>
<pre><code> WAIT=-1 CANNIBAL=1 ./prog
</code></pre>
<p>If you don&rsquo;t want to start out so small (i.e. you want to be able to draw more
quickly) you can just set the size to a bigger number (and you could do the same
with growth and moult/shed):</p>
<pre><code> SIZE=50 CANNIBAL=1 WAIT=-1 ./prog
</code></pre>
<p>Do note that although you&rsquo;re a bigger size you still grow one movement at a
time.</p>
<p>Okay but then if you get too many bugs the drawing will be over. If this proves
to be a problem simply do:</p>
<pre><code> SIZE=100 CANNIBAL=1 WAIT=-1 GROW=0 ./prog
</code></pre>
<p>Or something like that (maybe make the size bigger but that&rsquo;s up to you). You
could also set the max size to be the highest possible by saying</p>
<pre><code> MAXSIZE=-1
</code></pre>
<p>Which I&rsquo;ve done in the <a href="play.sh">play.sh</a> script.</p>
<p>I discuss how this mode works in <a href="spoilers.markdown">spoilers.markdown</a>.</p>
<p>Here&rsquo;s an example run where I spelt &lsquo;SNAKE&rsquo;. As you can see it&rsquo;s far from
perfect: the snake after all does not leave gaps and the game does not support
diagonal movement and I also made a mistake and had to modify what I was aiming
for. But you can consider this mode drawing or practice mode.</p>
<pre><code> oooooooooo ooooo o oo ooooo
o o oo o oo o ooo o
oooo o oo ooooooo oooo ooooo
o o ooo oo o ooo o
oooo o oo ooo oooooooo&gt;
</code></pre>
<h2><a name="auto" href="#toc">Gameplay mode: Computer playing / Automatic mode (Photosensitive epilepsy/Stimulation overload trigger)</a></h2>
<p><strong>Photosensitive epilepsy/stimulation overload trigger warning:</strong>
For those who have epilepsy or are susceptible to stimulation overload from
flashing lights please do be careful with this mode. Depending on your
susceptibility this could very well trigger seizures or other discomforts and I
wouldn&rsquo;t want that to happen to anyone. This mode has a lot of flashing of
different colours and depending on the exact parameters you specify it could
easily be in the trigger range for epilepsy but potentially stimulation overload
too.</p>
<p>If you&rsquo;re still here you can create this effect like:</p>
<pre><code> WAIT=0 WALLS=1 CANNIBAL=1 ./prog
</code></pre>
<p>As long as the bug evades you&rsquo;ll find that the snake is growing because it&rsquo;s
actually eating bugs; the computer is actually playing the game by itself! You
can still move the snake though it won&rsquo;t seem like you have much control over
it. If you pause the game you can see that it&rsquo;s bigger (you probably will be
able to even without pausing it).</p>
<p>Basically the snake is moving so fast that because the bug evades the bug will
inevitably move in the snake path&rsquo;s and therefore be eaten.</p>
<p>You might find it goes quicker if you set the evade count to a lower value for
example 1. Or you might not. But as long as the bug moves the computer can play
by itself.</p>
<p>Quick tests suggest that bigger dimensions it gets bigger quicker. But it also
seems to take longer for it to get a bug as it gets longer. I believe these
happen because the bug has to find a X and Y coordinate that&rsquo;s not occupied and
so with fewer available it has a harder time finding a place in that one line.</p>
<h3><a name="auto-variations" href="#toc">Computer player variations</a></h3>
<p>Here&rsquo;s how to make the bug move every time the snake moves:</p>
<pre><code> CANNIBAL=1 WALLS=1 WAIT=0 EVADE=1 ./prog
</code></pre>
<h4>Help the computer win fairly quickly</h4>
<p>If you want to see the game &lsquo;win&rsquo; try something like:</p>
<pre><code> CANNIBAL=1 WALLS=1 WAIT=0 EVADE=1 MAXSIZE=10 ./prog
</code></pre>
<h4>Negative growth (Shrink) Automatic mode</h4>
<p>Here&rsquo;s a fun one I just thought of (a long time after these other modes were
thought of):</p>
<pre><code> WAIT=0 EVADE=1 GROW=-1 SIZE=9 MAXSIZE=10 CANNIBAL=1 ./prog
</code></pre>
<p>What you&rsquo;ll see is that first the snake will get to the size of 9 - whether it
shows to be 10 characters depends on whether or not it gets a bug before it can
get to that length - and then it&rsquo;ll start shrinking until it&rsquo;s just the head
then the head again (i.e. 1 then 0 in size) and then win! This is also in the
<a href="play.sh">play.sh</a> script.</p>
<h4>Adjusting the time/speed</h4>
<p>Of course you can also do something like:</p>
<pre><code> WAIT=5 WALLS=1 CANNIBAL=1 ./prog
</code></pre>
<p>Which although might not seem like it is significantly slower.</p>
<h4>Moving the snake about to create patterns</h4>
<p>If you press different direction keys in some pattern you will see a pattern
form too (entirely dependent on how fast you react, what keys you press and I
suppose also how much the bug moves and the chance of being eaten also).</p>
<h4>Other ideas</h4>
<p>Here&rsquo;s an idea: how many moves is needed to make it possible to have some sort
of success in catching bugs? Obviously the dimensions will affect this value.</p>
<p>How long will it take for the snake to run into itself? For instance by doing:</p>
<pre><code> WAIT=0 ./prog
</code></pre>
<p>On my 13" MacBook Pro at the default settings going horizontally the snake ran
into itself at:</p>
<pre><code> OW!
X:57/156 Y:20/41 S:155/997 B:30
</code></pre>
<p>What if you set the size to a high value? The lowest? There are bound to be
other games to play with this feature!</p>
<h2><a name="grow-shrink" href="#toc">Gameplay mode: Grow-Shrink mode (Positive and Negative Winning)</a></h2>
<p>In this mode you&rsquo;re simultaneously growing and shrinking but because the max
size is unsigned you can win both by shrinking to the point of losing your body
or growing to the full size directly. This is how it works:</p>
<p>You have a negative shedding growth and a positive growth size: negative and
positive winning. Depending on the parameters specified it might go one way over
the other. Try:</p>
<pre><code> SIZE=150 SHEDS=-5 GROW=10 SHED=50 MAXSIZE=250 ./prog
</code></pre>
<p>What this does is set the size to 150 (to make it not go down so quickly) and
then for each bug you eat it adds 5 to the size; for every 50 moves (that you
don&rsquo;t get the bug) you shrink by 5. You will find that at times you might only
decrease in size but then at other times - depending on size of screen and how
lucky you are with where the bug is relative to where it last was - you might be
growing. Combining this with the drawing mode could be interesting but I never
actually tried it.</p>
<p>The parameters above were chosen after playing with the mode a bit to find a
value that wouldn&rsquo;t take that much time but still would pose a challenge. One
could reverse it so that one shrinks more than growing.</p>
<p>The <a href="crazy.log">crazy.log</a> file has several screen dumps with this idea.</p>
<p>You could also have it so that eating a bug makes you shrink and moving so many
moves you grow. I tried this and for me it was far more fun. The <a href="play.sh">play.sh</a>
also has this mode:</p>
<pre><code> SIZE=100 SHEDS=5 GROW=-10 SHED=50 MAXSIZE=250 ./prog
</code></pre>
<p>Obviously there are many other variations. The <a href="play.sh">play.sh</a> script has some
of them (the above is option 5; others are 4, 15 and 16 but only options 4 and 5
are called Grow / Shrink).</p>
<h2><a name="hypnotic" href="#toc">Hypnotic / Sleepy mode (<strong>Photosensitive epilepsy/Stimulation overload trigger</strong>)</a></h2>
<p><strong>Photosensitive epilepsy/stimulation overload trigger warning:</strong>
For those who have epilepsy or are susceptible to stimulation overload from
flashing lights and patterns please do be careful with this mode. Depending on your
susceptibility this could very well trigger seizures or other discomforts and I
wouldn&rsquo;t want that to happen to anyone. The default wait time is 231ms, the
typical range of seizures is 3 to 30 flashes per seconds (but can be higher) and
that means that at <strong>EVADE=1</strong> every 231ms there will be a flash in addition to the
snake moving too.</p>
<p>Anyway this might sound absurd but it can be somewhat hypnotic by doing:</p>
<pre><code> EVADE=1 CANNIBAL=1 ./prog
</code></pre>
<p>And just moving the snake about not trying to catch any bugs - just let whatever
happens happen.</p>
<h2><a name="stim" href="#toc">Gameplay mode: Stimulation / Calming mode</a></h2>
<p>If you just need something to stimulate your mind to keep you calm or simply you
want to play a game without having to worry about winning or losing you can set
the growth size to 0 and then just move the snake round and round eating bugs
until you want to quit. You can enable cannibalism so that you don&rsquo;t have to
worry about even running into yourself and losing:</p>
<pre><code> GROW=0 CANNIBAL=1 ./prog
</code></pre>
<h2><a name="expansibility" href="#toc">Gameplay mode: Expansibility</a></h2>
<p>As I was writing this document and the game modes I have thought of other game
modes (they were added) and I have come back to this document to add more modes.
That&rsquo;s the beauty of the variables I have implemented: together with the
imagination and even just chance different modes of play can be devised. The
drawing mode was a happy chance of how the <code>timeout()</code> function works for
example.</p>
<p>As a person who was heavily involved in MUD development and design I know very
well how games need to be fun and have different options, not be too easy but
not be too hard either. And a game developer who does not play their games is a
game developer who is detached from their player base and the wants and needs
are therefore disregarded if even heard. I have played this game a lot for this
reason as well as I simply enjoy it and thinking up new modes.</p>
<h1>5. <a name="scripts" href="#toc">Scripts</a></h1>
<p>The following scripts are provided to simplify and automate some of the things
this file discusses as well as allowing to easily change the colours.</p>
<h2><a name="colours" href="#toc">Colours selection: snake-colours</a></h2>
<p>To do this use the <a href="snake-colours">snake-colours</a> script like so:</p>
<pre><code> ./snake-colours
</code></pre>
<p>If you want to pass in specific variables you can do that too e.g.:</p>
<pre><code> CANNIBAL=1 ./snake-colours
</code></pre>
<p>The script will prompt you for the colour of the walls, snake head, body and the
bug.</p>
<h2><a name="preset" href="#toc">Automate the above gameplay modes</a></h2>
<p>The <a href="play.sh">play.sh</a> script has the gameplay modes described in this file and is menu
based (there might be differences and some of the modes I include a variation).
The script tests the terminal (allowing you to continue even if problems are
detected), prompts you if you want to select colours (like those in
snake-colours above) and then gives you a list of game modes to play. You can
pass in the game variables but note that if you pass in a variable that the mode
you choose uses then the script will override what you pass in.</p>
<p>To use you can do something like:</p>
<pre><code> ./play.sh
</code></pre>
<p>Or to make it so walls are an obstacle:</p>
<pre><code> WALLS=0 ./play.sh
</code></pre>
<h1>6. <a name="variables" href="#toc">Notes about some of the game variables</a></h1>
<p>The game variables can be used for a variety of things including different
gameplay modes (as shown above) but here are some notes about a few of them.</p>
<h2><a name="wait" href="#toc">WAIT: Snake speed</a></h2>
<p>Besides the different game modes, if you find it too fast/slow you can change it
to a value that&rsquo;s better for you. Remember it&rsquo;s a wait time so if you want the
snake to move slower you have to increase the wait time!</p>
<h2><a name="evade" href="#toc">EVADE: Bug evasion frequency</a></h2>
<p>For every <strong>EVADE</strong> snake movements the bug will try and find a new place to
occupy. It might be very close to it and I do not ensure it&rsquo;s a new place at
all.</p>
<p>Each time the bug is placed the counter will be reset whether from eating the
bug or not reaching it in time. Default 300 moves.</p>
<p>This can help you get out of a trap but it can also sometimes make it harder.</p>
<h2><a name="sizes" href="#toc">SIZE / MAXSIZE: Initial / Max snake sizes</a></h2>
<p>997 might be a bit high for many people. Or maybe you don&rsquo;t have enough time. Or
you&rsquo;re not in the mood to lose. Or you want to get close to a size you were last
time but quickly. It might be in conjunction with drawing mode.</p>
<p>Note on snake size: there&rsquo;s a stated size (in the score line) which is what
the snake will &lsquo;populate&rsquo; in the snake arrays and the visible size: as I have
discussed here and there the snake doesn&rsquo;t grow immediately so it takes time
before the snake is visibly that many characters. In other words just because it
says SIZE 29 doesn&rsquo;t mean it will instantly be 29 characters on the screen.</p>
<h2><a name="growth" href="#toc">GROW / SHEDS : Growth / Shedding sizes</a></h2>
<p>Similar to the initial size. Notice that the above point on size applies here:
it will take the number of movements before it is &lsquo;its full size&rsquo;.</p>
<h1>7. <a name="conclusions" href="#toc">Conclusion (and inspirational words for everyone)</a></h1>
<p>I believe that this file has given more than enough information for anyone to
get an idea of what is possible with my implementation of Snake. I realise also
that most people won&rsquo;t have read this far and that&rsquo;s quite all right; I&rsquo;m very
thorough and pay attention to details obsessively. Creating this game was a
delight and I am quite proud of what I have done.</p>
<p>Thank you for whatever level of attention you felt you could or wanted to give
and enjoy it in whatever way you see fit!</p>
<p><strong>Much more importantly is that Snake aside I hope I have demonstrated how with
the imagination and creativity almost anything is possible.</strong> This is something
<strong>that applies in our world in every way and <em>everyone</em> can do something amazing if
they believe in themselves!</strong> I would have never thought this the case for me
years ago but I know it&rsquo;s true now. <strong>Believe in yourself. Always.</strong></p>
<BR>
<HR>
<TABLE><TR>
<TD><a rel="license" href="https://creativecommons.org/licenses/by-sa/3.0/"><img alt="Creative Commons License" style="border-width:0" src="/png/by-sa-3.0-88x31.png" /></a></TD>
<TD><P>&copy; Copyright 1984-2020,
<A HREF="/judges.html">Leo Broukhis, Simon Cooper, Landon Curt Noll</A>
- All rights reserved<BR>
This work is licensed under a <a rel="license" href="https://creativecommons.org/licenses/by-sa/3.0/">Creative Commons Attribution-ShareAlike 3.0 Unported License</a>.</P></TD>
<TD>&nbsp;<!--<a href="https://validator.w3.org/check?uri=referer"><img src="https://www.w3.org/Icons/valid-html401" alt="Valid HTML 4.01 Transitional" height="31" width="88"></a>--></TD>
</TR></TABLE>
</body>
</html>
Binary file not shown.
+1 -1
View File
@@ -229,7 +229,7 @@ function play()
while true; do
menu
read -rp "Make your selection (0 - 7 or any other key to exit): " mode
read -rp "Make your selection (0 - 16 or any other key to exit): " mode
case "${mode}" in
0) # Drawing mode 0
-970
View File
@@ -1,970 +0,0 @@
<!doctype html public "-//W3C//DTD HTML 4.0 Transitional //EN">
<html>
<head>
<meta name="GENERATOR" content="mkd2html 2.2.2">
<meta http-equiv="Content-Type"
content="text/html; charset=utf-8"> <link rel="stylesheet"
type="text/css"
href="../hint.css" />
<title></title>
</head>
<body>
<CENTER>
<IMG SRC="/png/ioccc.png" ALT="IOCCC" height=78 width=267>
<P><FONT size="6"><I>The International Obfuscated C Code Contest</I></FONT></P>
<div id="bar">
<ul>
<li><a href="../index.html">About the 27th IOCCC</a></li>
<li><a href="../whowon.html">27th IOCCC Winners</a></li>
<li><a href="/index.html">IOCCC home</a></li>
<li><a href="/winners.html">List of All Winners</a></li>
<li><a href="/judges.html">The Judges</a></li>
</ul>
</div>
<P><FONT size="6"><B>Supplemental Info</B></FONT></P>
</CENTER>
<h1>Introduction (SPOILER ALERT)</h1>
<p>In the <a href="gameplay.md">gameplay.md</a> (<a href="gameplay.html">gameplay.html</a>) file I have given enough
information to know how the game looks, how to move the snake, how to pause etc.
In this file I am including (some) information on how the game actually works:
the technical details as it were, obfuscation techniques and also some of the
ways I reduced the iocccsize so I could do more with the code. Probably this
file causes more spoilage than the other files though that&rsquo;s not to say
everything will be answered here.</p>
<p>If you&rsquo;re still interested in this file (i.e. you&rsquo;re a judge or someone who
wants to know more about it) read on. Yes I write a lot. But you probably
already knew that so no harm there, hey?</p>
<p><a name="toc"></a></p>
<ul>
<li><p><a href="#works">How does it work?</a></p></li>
<li><p><a href="#movement">How does the snake movement work?</a></p></li>
<li><p><a href="#manual-automatic">Drawing (manual) and computer playing (automatic) modes</a></p></li>
<li><p><a href="#collision">Collision detection</a></p>
<ul>
<li><p><a href="#cannibalcollision">Cannibal collision detection</a></p></li>
<li><p><a href="#resizing">Collision detection when resizing the window of the game</a></p></li>
</ul>
</li>
<li><p><a href="#obfuscation">Obfuscation</a></p></li>
<li><p><a href="#skinning">Skinning the snake (i.e. decreasing the iocccsize)</a></p></li>
<li><p><a href="#size">A few more interesting size optimisations</a></p></li>
</ul>
<h1><a name="works" href="#toc">How does it work?</a></h1>
<p>The gameplay I have already described but this explains the way things are
actually done in more detail.</p>
<p>First I initialise curses; if this fails I print an error message (&lsquo;curses
error&rsquo;) and return 1. Next the screen size is determined and I subtract 1 from
each the x/y. If it&rsquo;s too small curses is ended and an error message (&lsquo;screen
too small&rsquo;) is printed - returning 1.</p>
<p>Next the max size of the snake is determined: if <code>MAXSIZE</code> is specified then
it&rsquo;s the value of that; otherwise it&rsquo;s the default. But in either case if it&rsquo;s
too big based on the screen dimensions it&rsquo;s capsized. The arrays for the snake
are this size + 1. Other environmental variables are also processed.</p>
<p>Then the arrays are allocated; if either return NULL curses is ended, an error
message (&lsquo;memory error&rsquo;) is printed and return 1.</p>
<p>If no errors have occurred I set up colours, turn on bold, set up the keypad
etc., place the snake, the bug, draw the walls and then it waits for the first
move (or quit of course). Technically I don&rsquo;t &lsquo;wait&rsquo; for input as such: unless
the wait time is negative (drawing mode) it&rsquo;s just a non-blocking call up to the
WAIT milliseconds but in no event will the snake move until it is told to at
least once (in drawing mode it will always wait).</p>
<p>In drawing mode if you pause then when you resume (hit space) the snake will
move the last direction it had been told to move - because the direction is set
and input was detected (the same goes for another key e.g. &lsquo;g&rsquo; - just like in
normal mode). But it will then wait again for input.</p>
<p>The snake function both draws the snake and updates the arrays; if the new size
is >= the max size the game is won (the winning size will be shown as the max).</p>
<p>Else the arrays are updated; when the array is being updated the body of the
snake is drawn. After this the head is drawn. Depending on the length of the
snake wrt the size the snake technically it might be that the number of
characters the snake takes is increased rather than having moved the snake
forward (i.e. the tail moved by one). This registers where the snake is and
where it was but no longer is (important particularly for negative growth/shed
sizes).</p>
<p>After that a bug is placed (but not drawn) in a pseudo-randomly selected area of
the field. This function takes a parameter which if not 0 and the bug had
already been placed somewhere (in other words if the bug was just eaten) call
the snake function. As long as the game isn&rsquo;t won at that point find a new place
to place the bug.</p>
<p>Next the score line is updated and then whilst the game is not over (player
loses/quits/wins) the movement proceeds; if the game hasn&rsquo;t started yet it will
jump to the top of the loop. If it&rsquo;s paused the same thing until it&rsquo;s resumed.
The rest of the loop can be described thusly.</p>
<p>It checks the current max y/x, draws the walls, bug, gets any input from
keyboard, and then if there is movement checks for collisions; if current max
x/y are is/are smaller than original then it&rsquo;s automatically a game over from
running into walls regardless of that feature status - this simplifies things
greatly (see below for more details).</p>
<p>If cannibal mode is disabled (the default) and the snake runs into itself then
it&rsquo;s also game over. Or did it run into the wall? If walls are passable (the
default) it will come out from the other side; else it&rsquo;s game over. If it comes
out on the other side and the snake is there and cannibal mode is disabled then
it&rsquo;s also game over.</p>
<p>As the snake moves it will for each move grow by one up to the technical size.
This might at times look a bit different from other times but it&rsquo;s a visual
thing based on the internal data of the game and the features enabled for
example shedding and shedding size.</p>
<p>Finally if the snake&rsquo;s new coordinates are on a bug a new bug is placed on the
field, the snake grows and the score is updated. Otherwise if the bug has waited
the number of moves that it waits before it finds a new place the bug is placed
in another location too (and the snake does not grow). In either event the snake
location is updated and redrawn.</p>
<p>There&rsquo;s also the processing of any shedding at this point. If the snake eats a
bug the snake will not shed; if it sheds the snake will not move in the same
manner as if it simply moved. Growth/movement can in some ways be conflated.</p>
<h1><a name="movement" href="#toc">How does the snake movement work?</a></h1>
<p>The way the snake looks to move is that every time the snake moves the last
position (the tail) is replaced with a space (<code>' '</code>). If the snake eats a bug
then the snake will get bigger in the next <code>N</code> movements. Note that if the snake
isn&rsquo;t its full size it will only be growing and so might not appear to be
moving at the tail end; I have discussed this more than enough elsewhere.</p>
<p>There are two arrays that store the last Y/X coordinates of the snake&rsquo;s
positions that are shifted forward as the snake moves about the field looking
for bugs.</p>
<h1><a name="manual-automatic" href="#toc">Drawing (manual) and computer playing (automatic) modes</a></h1>
<p>How do these modes work? The <code>timeout()</code> function takes a signed int: if it&rsquo;s &lt;
0 it waits indefinitely; if it&rsquo;s 0 it returns immediately even if there&rsquo;s no
input waiting (if input is there then it&rsquo;s used instead); and if it&rsquo;s > 0 it
waits that many milliseconds. Thus a negative value allows for complete control
over the snake&rsquo;s movement (speed and otherwise), a value of 0 means the snake
will move as long as it&rsquo;s not paused etc. and otherwise it waits up to that many
milliseconds (which is how the 0 value comes into play).</p>
<h1><a name="collision" href="#toc">Collision detection</a></h1>
<p>This was an interesting thing to work out. Because the snake could occupy more
than one row and more than one column at a time the two arrays approach seemed
good to me.</p>
<p>I already mentioned how the array is shifted but to be clear: the snake head is
always at element size - 1 and the tail is at 0 and so it&rsquo;s just a matter of
verifying if the snake head is at a place that&rsquo;s occupied by the snake, the wall
or the bug.</p>
<p>The bug does its best to avoid landing where the snake is but given that snakes
are very flexible and cunning who can tell what might happen? As I noted these
bugs are not bugs! :)</p>
<h2><a name="cannibalcollision" href="#toc">Cannibal collision detection</a></h2>
<p>How does cannibalism change collision detection? The fact that each time the
snake function is called there is a space printed at the tail end was a problem
to resolve: what happened is if the snake went through itself then at some point
there would be a space that breaks the snake into more than one piece (where the
tail was but that had been another part of the snake)!</p>
<p>So what I do: first the tail is cleared, then as the snake coordinates arrays is
being updated I redraw the snake chars. Then at the end the head is drawn (it
used to be the head was drawn first but by drawing it after you can see where
the head is inside itself, creepy as it is). Thinking on it this very possibly
is why (or partly) the negative shedding leaves the head somewhere in the middle
of the snake (or that the head of the snake is left behind) but again I don&rsquo;t
think that as a problem.</p>
<p>There are other strange ways this looks. Not only does it look like lines
intersecting at any number of places but it looks particularly strange when the
snake goes the opposite direction: it has to unwind as it were, and for a moment
you might not see what is truly happening. There are two ways you can look at
this I think.</p>
<p>First is that it&rsquo;s physically impossible in real life so the fact this cheat
mode exists for a different kind of play means it should look unnatural: for it
<em>is</em> unnatural!</p>
<p>The second is you can look at it as if two more snakes are having fun with each
other. This can also appear to defy physics!</p>
<p>Choose your poison. Or rather your venom.</p>
<h2><a name="resizing" href="#toc">Collision detection when resizing the window of the game</a></h2>
<p>What happens if the window is resized during the game? If the size is increased
then the border can (and will) stay the same; but if the window is shrunk then
what? It would be very difficult if not impossible to redraw the snake: where
would the snake be and what about the border? The arrays would have to be
adjusted too! Another issue: what if the snake is beyond the new walls?</p>
<p>The best thing I could think of is that if the window is shrunk then the snake
is assumed to run into the wall: in other words the game is at that point over.
If the window is increased in size nothing happens other than the game won&rsquo;t be
the full window size (or technically a few rows/columns fewer): everything will
remain the same. This GREATLY simplified things.</p>
<p>There was another problem at some point where the snake would quickly grow if it
was increased in size but I believe that&rsquo;s resolved. Anyway what kind of field
in real life increases in size like that so suddenly? :)</p>
<h1><a name="obfuscation" href="#toc">Obfuscation</a></h1>
<ul>
<li><p>I make use of the C token pasting operator. Although this is well known it&rsquo;s
probably less known and either way it&rsquo;s not as simple as just having the code
that it translates to. For example why have:</p>
<pre><code> attroff(COLOR_PAIR(L));
</code></pre>
<p> When you can have instead:</p>
<pre><code> attroff(m(PAIR(L)));
</code></pre>
<p> It&rsquo;s an extra layer of indirection. This used to be more used but when
making it easier for users to change the colour pairs I no longer used it to
set up colour pairs. It might not defeat <code>cpp</code> but it does make for more
reading otherwise (depending on how you look at it maybe less?).</p>
<p> It also helps save iocccsize bytes (but not as many as it used to!).</p></li>
<li><p>What is this block of code?</p>
<pre><code> F(MAXSIZE)g d g = f((a)((*y-2)*(y[-2]-2)),g);
F(GROW)N d
F(SIZE)A d
F(WAIT)y[-3] = (int) strtol(z,NULL,0));
F(EVADE)W d
/* and so on */
</code></pre>
<p> There are several things going on here but I&rsquo;ll focus on the main one here and
leave the others to their own: the <code>F</code> macro and the associated <code>d</code> macro are
here important.</p>
<p> In addition to saving many bytes this also makes for interesting reading.
What this actually is doing is checking for environmental variables. If
<code>getenv()</code> does not return NULL then strtoul() is called on it (except for
the one that clearly shows strtol()).</p>
<p> There are other things going on (below).</p>
<p> Now it might not defeat the cpp but can you tell me what this is even with the
cpp?</p>
<pre><code> f((a)((*y-2)*(y[-2]-2)),g);
</code></pre>
<p> The cpp might get it closer to what you might expect in a normal program but I
refer to the array offsets (below also).</p></li>
<li><p>Stringification: there isn&rsquo;t a single <code>"</code> in the source code! The <code>F</code> macro
uses the macro <code>Z</code> which does the real work. At first <code>F</code> was only <code>getenv</code> but
I changed it to use stringification. Following the creation of the <code>Z</code> macro I
made it use it instead. If I remember rightly that uses extra bytes but somehow
it felt better this way in my head. Then to save many bytes I made the macro do
much more than that (that is the <code>F</code> macro).</p>
<p> As for the Z() macro it means that I could remove <code>"</code>s; for example:</p>
<pre><code> #define J Z(X:%d/%d Y:%d/%d S:%zu/%zu B:%zu\n), Y, y[-2], X,*y,A,g, c);
</code></pre>
<p> Which as I have discussed elsewhere is the entire set of parameters to both
<code>mvprintw()</code> and <code>printf()</code> plus the end of the function call (i.e. <code>);</code>.</p>
<p> BTW: There&rsquo;s another really cool benefit of stringification: because more than
one space is converted to a single space I can have it spread across columns on
the format and even new lines if necessary. This fact along with the next
technique causes some beautifiers problems too.</p></li>
<li><p>Another use of the <code>Z</code> macro is this curious line:</p>
<pre><code> static char s[]=Z(; +&lt;&gt;^v);
</code></pre>
<p> There are a number of curious parts. First is the Z() part makes it look
like a function call. Of course that wouldn&rsquo;t work as such because an array
initialiser needs an initialiser list or a string literal. Whether that&rsquo;s
immediately obvious to others I don&rsquo;t know but then how is this even possible?
A <code>;</code> followed by <code></code>, <code>+</code>, <code>&lt;</code>, <code>&gt;</code>, <code>^</code>, <code>v</code>?</p>
<p> A very minor factor is that the character &lsquo;v&rsquo; is there and it&rsquo;s (<code>v</code>) also
used as a macro (well, define) &lsquo;might&rsquo; be of something to some people. Or
programs maybe? For instance using in vim <code>*</code> on the <code>v</code> in that array and
it takes you other instances of <code>v</code>: as in <code>\&lt;v\&gt;</code>: which happens to be
something else entirely. That itself however might or might not be
significant for this instance!</p>
<p> But what function would take the string (&hellip;function and string?) that it takes?
The sequence of characters would normally cause compiler errors like that.
I have it in the function that uses it; static since it need never change:
only one copy is needed. Why I have it in the function is to move it further
away from the definition of <code>Z()</code>. I will also be returning to this one
again.</p>
<p> Another example is using the <code>E()</code> function e.g.:</p>
<pre><code> E(Z(YOU WIN!));
</code></pre>
<p> Which happens to be in the same function the above char array is defined. Also
it&rsquo;s more like a string than anything but yet it&rsquo;s not visibly a string.</p>
<p> Some beautifiers don&rsquo;t like this.</p></li>
<li><p>There&rsquo;s an <code>#undef</code> following an <code>if</code> in a way to draw attention from what to
do if the if is true.</p></li>
<li><p>There are a couple case statements that fall through to the next case
condition. Actually one falls twice: into the one below which falls into the one
below that. This means the order it is in is required. It also reduces the
iocccsize a reasonable amount (by having it in the main loop I could do these
things which reduced the number of keywords needed).</p>
<p> When quit is requested it falls into pause. But then pause falls into the
default (so no recognised key is pressed) which does <code>x = 0;</code>. Outside the
switch block there&rsquo;s <code>if (x) P = 0;</code>. So what this amounts to is: if quit
is requested pause will be changed to the opposite state. This will then
fall to setting x to 0. And because x is 0 the state of pause won&rsquo;t be
updated again. Now because <code>Q = 1;</code> (or actually <code>l</code>) it doesn&rsquo;t matter if
<code>P || !P</code> because Q will also jump to the top of the &lsquo;loop&rsquo; only to exit
since the condition no longer is true.</p>
<p> But then if pause is pressed the same thing applies: it will be updated to
the opposite state and then it will fall to the default case which sets <code>x =
0;</code> which means it won&rsquo;t update pause outside the switch block. If pause was
enabled then the loop will start over only this time because quit wasn&rsquo;t
requested it will re-enter the loop.</p>
<p> So basically quit can both pause and resume but it doesn&rsquo;t matter because it
will still quit; and pause will fall to the default statement without being
updated again either. In other words the only time pause will be updated
(disabled) <em>outside the switch</em> is if a direction key is pressed. But of
course it&rsquo;s disabled inside the switch if pause key is pressed when it&rsquo;s
already paused! This removed three break statements because the order allows
it; if the order was changed then the code would break in another way and
not the good kind!</p></li>
<li><p>On the note of pausing there&rsquo;s at least one instance of removing <code>if..else</code>
(besides those in e.g. environmental variable processing) that&rsquo;s curious: I
converted this:</p>
<pre><code> if (!P) P = 1;
else P = 0;
</code></pre>
<p> To this:</p>
<pre><code> (!P &amp;&amp; (P = 1))||(P=0);
</code></pre></li>
<li><p>Makes use of the different &lsquo;namespaces&rsquo; to have variables and labels be the
same identifier. For example in main() there&rsquo;s a variable that also have the
same name label for <code>goto</code> (there used to be two pairs in main()).</p></li>
<li><p>And on that note: makes use of the ugly <code>goto</code> in numerous places. This
includes simulating a while() loop, breaking out of that &lsquo;loop&rsquo;, breaking out of
two loops (a for() in the &lsquo;while()&rsquo;), re-entering (as in starting over) a for()
loop and for dealing with errors.</p></li>
<li><p>Why do I check for <code>Q || P</code> and then goto x only to then check for <code>!Q &amp;&amp; !D</code>
to then goto x? Do I need to check Q at all? In fact I do but at a quick glance
it might be easy to miss.</p></li>
<li><p>Uses an unnamed array (compound literal) for several different game variables.
The pointer to the first element is defined like <code>int *j</code>:</p>
<pre><code> static int Y,X,*j = (int[8]){231,0}, *U, *V, *e, *n, Q, P,x,*y,l=4,*D;
</code></pre>
<p> Does the 231 seem familiar? It should: it&rsquo;s the default key delay for the
<code>timeout()</code> call (which I will return to again). The rest are 0 default. But
what about <code>j</code>? Is it even used? Actually in main:</p>
<pre><code> y = j+3;
</code></pre>
<p> But aside from that <code>j</code> is not used. However&hellip;</p></li>
<li><p>Major abuse of negative pointer offsets along with confusing names. I&rsquo;ll say
this in two parts: the negative offsets and then the confusing names.</p>
<p> Can you honestly tell me that this is easy to follow?</p>
<pre><code> if (Y &lt; 1 || Y &gt;= y[-2] || X &lt; 2 || X &gt;= *y || y[-2] &gt;= y[-1] || *y &gt;= 1[y])
{
if (*p &amp;&amp; !(*y&gt;=1[y]||y[-2]&gt;=y[-1]))
{
if (Y&lt;1||Y&gt;=y[-2])
Y = Y&lt;1?y[-2]-1:1;
if (X&lt;2||X&gt;=*y)
X = X&lt;2?*y-1:2;
}
/* ... */
}
</code></pre>
<p> That&rsquo;s not the only place negative offsets occur! Observe the ternary operators
there too.</p>
<p> I&rsquo;ll go back to the F() macro and in particular what follows one of them:</p>
<pre><code> g d g = f((a)((*y-2)*(y[-2]-2)),g);
</code></pre>
<p> To parse that at the very least you have to know that <code>y</code> points to <code>j + 3</code>.
Then you have to know that <code>j</code> points to the first element of an unnamed
array (compound literal). But then you also have to know that that array has
different types of data. Once you figure out the elements in question you
then have to account for the offset that <code>y</code> is. Then once you have that
figured out you need to consider the negative offsets to <code>y</code> (this also
applies to the block above of course and maybe more so). Then you have to
think of operator precedence etc. I mean what is:</p>
<pre><code> (*y-2) * (y[-2]-2])
</code></pre>
<p> &hellip;about? An offset of -2 and subtract -2 from that. Multiply that by the <code>*y</code>
(which is <code>j[3]</code>) - 2.</p>
<p> But why is there a <code>g d g =</code> when the other lines only have the variable (or
location) and a d? (Excepting the one that doesn&rsquo;t refer to <code>d</code>.)</p></li>
<li><p>On the confusing names etc.: the <code>getmaxyx()</code> function gets the maximum Y, X
dimensions. Now in the first call in main() I have the code and tests following:</p>
<pre><code> getmaxyx(v, *y, y[-2]);
--*y; --y[-2];
if (y[-2] &lt; 9 || *y &lt; 9)
return E(Z(term too small));
</code></pre>
<p> Clearly the max x must be stored in <code>*y</code> and the max y must be stored in ..
<code>y[-2]</code>. After all anyone knows that the coordinates are in the order (X,Y)!
In fact the output of my entry and my documentation demonstrates this
clearly: X before Y! It&rsquo;s so true in fact that the documentation for curses
more than once states that it&rsquo;s actually (Y,X)! But the fact I don&rsquo;t even
refer to a <code>x</code> is possibly confusing even without the negative offset.</p>
<p> Of course I don&rsquo;t have to use negative offsets at all! I could use positive
offsets for every time I use negative offsets. But where&rsquo;s the fun in that?
:)</p>
<p> BTW: Some of these are not in the table of expressions in the HACKING file.
Also there might be some code in there that is no longer correct (it was
before I started obfuscation) though it might be able to give an idea.
Spoilers abound in that file (in addition to this file) but the HACKING file
states things that are no longer true: a way of obfuscation itself! Instead
of misleading comments it&rsquo;s misleading statements in the file that explains
what some of the things are for!</p></li>
<li><p>Misleading variable names for coordinates. In other words the Y coordinate is
called X and the X coordinate is called Y. This adds to the already confusing
array references but it also adds to the confusion of the order of the curses
functions coordinates: it appears that yes X does come first because the
function calls that take coordinates suggest it - but in actuality it&rsquo;s just
that the names are deliberately swapped. Of course that&rsquo;s after you determine
that the variables <code>X</code> and <code>Y</code> are only the snake head but at that point you
still have to figure out the array confusions. Also if you&rsquo;re tired <code>V</code> could
easily be read as <code>Y</code> and I have a lot of fun with <code>V</code> which I will get to next
(and again). Finally why not have them be two different names unrelated to
coordinates? I thought of this and I think it&rsquo;s more confusing to have something
that is associated to what it is but incorrectly rather than something unrelated
entirely: the mind constructs things from what it has seen, what it experiences,
what it knows, and since X and Y are used for coordinates the natural response
of the brain is to assume Y is what is really X and X is what is really Y.</p></li>
<li><p>More confusion with variable names: If you notice the <code>int *U, *V</code> they are
also part of the compound literal: that is they point into it:</p>
<pre><code> U=y+2; V=U+1;
</code></pre>
<p> Except that these two are done in two different places: away from the
assignment of <code>y</code> to remove them further away from the contexts they are
used in.</p>
<p> There&rsquo;s another reason for moving it further down: if you look at the bug
drawing function (which comes before main()) you will see that there I set
the bug location to refer to the <code>y</code> &lsquo;array&rsquo;. I do blank out the old
location at <code>*U, *V</code> but then assign the new location differently. Then in
main() I draw it at <code>*U, *V</code> and also check for the bug being eaten there
too.</p></li>
<li><p>There&rsquo;s another array that holds a variety of data.</p>
<pre><code> static k p[5]={1,0},W=300;
</code></pre>
<p> It holds the following information (but not necessarily in this order):</p>
<pre><code> WALLS
CANNIBAL
SHED
SHEDS
EVADE
</code></pre>
<p> But how will you know that just looking at the declaration? Many variables
and they&rsquo;re part of collections but the many layers of indirection cause
confusion to the already unhelpful variable names (for those that even have
names!).</p></li>
<li><p>There&rsquo;s an array of pointers to functions too: it holds three functions but
rather than always use the array I only do some of the times. I even use the
same function in the same general area with both names in order to mislead.
Incidentally <code>splint</code> seems to have a parse error on the declaration though I
don&rsquo;t know why.</p></li>
<li><p>On arrays/pointers in general I also use e.g. <code>3[p]</code> and <code>p[3]</code> (there are
many other examples that I have already shown).</p></li>
<li><p>Expanding on referring to the same thing in more than one way take a look at:</p>
<pre><code> case KEY_LEFT:
V[1] = l-3;
break;
case KEY_RIGHT:
V[l/l] = l/2;
break;
case KEY_UP:
V[l-3] = l-1;
break;
case KEY_DOWN:
V[l/4] = l;
break;
</code></pre>
<p> What&rsquo;s going on there? First of all the letter ell looks very much like the
digit one but above there are only two references to the digit <code>1</code>; the
others are the letter <code>l</code>. If you&rsquo;re tired though, don&rsquo;t have the best
vision (I&rsquo;m speaking from experience here and that&rsquo;s not even considering
the font) it would be easy to miss. Online in a text editor you have syntax
highlighting of course but there&rsquo;s more to it than that. Also in other parts
of the code there are references to the digit 1 instead of the letter ell as
part of array indexes too (so which is it?).</p>
<p> Second is that the index referenced in each of the case statements evaluate
to the same: 1. That&rsquo;s all accomplished by taking advantage of the value of
<code>l</code>: 4.</p>
<p> And then to further make use I have done the same for the value to assign to
that element: 4 - 3 is 1, 4 / 2 is 2, 4 - 1 is 3 and 4 is obviously 4.</p>
<p> But doing it this way means you have to first of all know that there&rsquo;s the
variable <code>l</code> (conveniently declared at the top of the file); then you have
to determine (once you&rsquo;re at this place in the code) if it&rsquo;s the digit or
the letter - for each reference (since both exist)! After all it&rsquo;s entirely
possible that I could have negative offsets here (and there&rsquo;s nothing that
would prevent negating a variable either in this case): I have done it many
other places! But even after all of that you still need to do the
calculations when I could simply have had:</p>
<pre><code> V[1] = 1; V[1] = 2; ...
</code></pre>
<p> Etc.</p></li>
<li><p>Variable reuse. For example in the function E() there&rsquo;s a variable that keeps
track of whether or not it&rsquo;s been called; that variable is <code>h</code> and it says
whether to call <code>endwin()</code> or not in as in some cases E() is called more than
once. Now instead of setting the variable <code>h</code> to 1 I set it to <code>l</code>: it looks
like a 1 yes but it&rsquo;s actually 4. Does it matter that it&rsquo;s 4? No. The only
thing that matters is that it&rsquo;s a non-zero value. The same applies to <code>Q</code> which
I also set to <code>l</code>.</p></li>
<li><p>I also use <code>*y</code> as a boolean. If you observe that I set x to <code>*y</code> (which
itself might make one believe they&rsquo;re related in some form): it used to be just
a 1. However it is only used as a boolean. <code>*y</code> as I described as the LINES
variable on invocation of the program. Since I check if it&rsquo;s &lt; 10 before
continuing the game I know that it will always be non-zero. But what if someone
tries LINES=0? In fact it will be ignored: if the terminal is 25 lines and you
specify 0 lines then it&rsquo;ll be 25. Therefore I can use it as a boolean here since
it needs there to be non-zero. Then in order to get the opposite, 0, I can do
<code>!*y</code> which I do elsewhere.</p></li>
<li><p>More generally on variable reuse: the compound literals and arrays of the same
data type but which are completely different things means I can use the same
name in different parts and so it&rsquo;s then a matter of determining which
element/offset to use.</p></li>
<li><p>Why do I compare if the original dimensions are >= the current when the idea
is to make sure that they&rsquo;re actually bigger? How does that work? Why not just
check if it&rsquo;s > than the current?</p></li>
<li><p>More confusion with the max x/y dimensions: Going back to max x/y dimensions
and coordinates of the snake; I showed this code before:</p>
<pre><code> if (Y &lt; 1 || Y &gt;= y[-2] || X &lt; 2 || X &gt;= *y || y[-2] &gt;= y[-1] || *y &gt;= 1[y])
{
if (*p &amp;&amp; !(*y&gt;=1[y]||y[-2]&gt;=y[-1]))
{
if (Y&lt;1||Y&gt;=y[-2])
Y = Y&lt;1?y[-2]-1:1;
if (X&lt;2||X&gt;=*y)
X = X&lt;2?*y-1:2;
}
else
{
/* ... */
}
}
</code></pre>
<p> I asked if you could honestly figure that out easily. But here&rsquo;s a bit more
elaboration. I already talked about the negative offsets - and they should
talk enough themselves - but look at the mess. Even if they weren&rsquo;t negative
offsets there are a lot of array references (though by a pointer to an
element in the unnamed array) and comparisons all jumbled together. There&rsquo;s
more.</p>
<p> I have the <code>!</code> of a <code>||</code> to flip the logic: that&rsquo;s not how a normal person
would write code. Well&hellip;not usually, I guess; I have done it in times where
it seems more appropriate but it&rsquo;s not the way it&rsquo;s usually done (I think?).</p>
<p> Even so that part is doing more than one thing: Not only is that code making
sure the max dimensions aren&rsquo;t smaller (from the original) but it also makes
sure that the wall isn&rsquo;t hit (when it&rsquo;s not allowed) as well as making the
snake go through to the other side of the wall if the snake is allowed to
and hits the wall! And even when the snake is allowed to go through walls if
the screen size has shrunk it will reach the else part.</p>
<p> It also has the ternary operator to adjust the coordinates of the snake head
should the snake go through a wall and those also have negative offsets. But
how can you figure that out just looking at that mess? Unhelpfully the X/Y
seem to both be compared to <code>y</code> but never <code>x</code> (that variable is unrelated
and not even in this part of the code).</p></li>
<li><p>The function <code>B()</code> ends with a <code>goto</code>. Why? It&rsquo;s also another place where
there&rsquo;s at least one negative offset.</p></li>
<li><p>A note on the many <code>#define</code>s in my entry. You say you dislike them:</p>
<pre><code> Doing masses of #defines to obscure the source has become 'old'. We
tend to 'see thru' masses of #defines due to our pre-processor tests
that we apply. Simply abusing #defines or -Dfoo=bar won't go as far
as a program that is more well rounded in confusion.
</code></pre>
<p> As I have noted though many of these save quite a lot of bytes too. It&rsquo;s
true that they might aid (but barely) in obfuscation but I think that my
entry is more rounded in confusion; certainly the other techniques I have
mentioned include much more than just <code>#define</code>s. One of the <code>#define</code>s that
saves a significant number of bytes is of course <code>J</code>: I use that twice and
it would be a huge burden to include it twice!</p>
<p> At the same time I have removed some <code>#define</code>s that have added bytes; I&rsquo;ve
also removed some that saved bytes and in fact I think it makes it more
obscure if in no other way but making it more difficult to look at (for
example I might have been able to save bytes by defining for the array
offsets but I find that it looks much better - which is to say much worse -
the way I have it now).</p></li>
<li><p>Going back to the curious <code>static char s[]=Z(; +&lt;&gt;^v);</code>: there&rsquo;s something
magical about the number 7 isn&rsquo;t there? I do not refer to primes although
certainly one could say that primes have a magic to them. No. I&rsquo;m instead
referring to another property: bitwise AND. For example consider the following:</p>
<pre><code> 7 &amp; 0
7 &amp; 1
7 &amp; 2
7 &amp; 3
7 &amp; 4
7 &amp; 5
7 &amp; 6
7 &amp; 7
</code></pre>
<p> What is the result of each operation? Quite simply it&rsquo;s the number itself!
How does this relate to the <code>s</code> array though? Let me back up. Is there any
place in the code that has the number 7 (by itself - 997 doesn&rsquo;t count)? A
quick check will answer that: no. But here&rsquo;s a curious thing:</p>
<pre><code> q X, Y, s[*D+2&amp;(1&lt;&lt;3)-!Q]);
</code></pre>
<p> We KNOW that at this place <code>Q</code> is 0 so the <code>!Q</code> has to be 1. Now <code>1 &lt;&lt; 3</code> is 8. Therefore</p>
<pre><code> (1 &lt;&lt; 3) - !Q == 7
</code></pre>
<p> But what&rsquo;s <code>*D</code>? If the snake hasn&rsquo;t moved once yet it&rsquo;s 0; otherwise it&rsquo;s the number
of the direction the snake is currently facing. Thus</p>
<pre><code> *D&amp;(1&lt;&lt;3)-!Q
</code></pre>
<p> &hellip;refers to <code>*D</code>. However if I were to have that be the element it wouldn&rsquo;t
work right: I wanted the semicolon in there but the space was needed to
reduce the iocccsize down by one (ironic that adding a byte reduces it by
one but there it is). I could have had it later in the array but this felt
slightly more confusing: more operators (so precedence) to consider (and in
fact GCC complains about this but as is clearly demonstrated it&rsquo;s not
important). By adding a <code>+2</code> it adjusts the index to be the correct value in
order to show the proper index of the char array.</p>
<p> But how do you know this? You have to know first of all that Q will always
be 0 at this point (so therefore !Q == 1). You also have to understand that
in the range N = 0..7 the value of <code>N &amp; 7</code> is <code>N</code> (which might not be
something everyone realises). Obviously you need to know that (1 &lt;&lt; 3) is 8
in order to get the final <code>*D &amp; 7</code>.</p>
<p> You furthermore need to know that <code>*D</code> will always be in the range <code>0..4</code>
which means that <code>*D &amp; 7</code> will always be in the range <code>0..4</code> (If I were to
have added a <code>&amp; 7</code> to the end it&rsquo;d still be the correct value! But the use
of bytes couldn&rsquo;t be justified there.) Finally adding 2 will get the correct
value of the array index. After all that it will print the correct character
for the head!</p>
<p> But there&rsquo;s another trick here: there&rsquo;s never a direct assignment to <code>*D</code>:
<code>D</code> is set to <code>1 + V</code> and <code>*D</code> is never touched directly: it&rsquo;s all through
<code>1[V]</code>. The references to directions i.e. <code>KEY_LEFT</code> etc. and also the
switch() to see how to modify X/Y are all done through the <code>V</code> pointer. But
then what is <code>V</code> anyway? It&rsquo;s <code>U + 1</code>; and <code>U</code> happens to be <code>y + 2</code>. But
<code>y</code> happens to be <code>j + 3</code>. Of course <code>j</code> is a pointer to the first element
of the compound literal! So there are quite a lot of levels of indirection
in this part alone (not to mention other places)!</p></li>
</ul>
<h1>Obfuscation in prog.3.c and prog.3-j.c</h1>
<p>There are a few differences in this version that are worth noting. First of all
is a define that&rsquo;s in the compiler invocation Makefile is in the source file
itself. Second are the following obfuscation techniques. To simplify integrating
the explanations I have simply yanked and pasted them below:</p>
<ul>
<li><p>Variable reuse in ways that might not be so intuitive. For example in the
function E() there&rsquo;s a variable that keeps track of whether or not it&rsquo;s been
called; that variable is <code>h</code> and it says whether to call <code>endwin()</code> or not as in
some cases E() is called more than once. Now instead of setting the variable <code>h</code>
to 1 I set it to <code>*y</code>. Now as you can see <code>*y</code> starts as a NULL pointer; this is
set to the compound literal <code>j</code> + 3. This in turn is what LINES is (number of
lines). So <code>y = j + 3;</code> and <code>j</code> I discuss elsewhere. But what if LINES is set to
0? LINES being set to 0 sets it to the terminal max size but in any event I test
for values &lt; 10 and if either LINES or COLUMNS is &lt; 10 then E() is called.
However E() always returns 1 and since this is in main() and it&rsquo;s an error I
simply return E() and thus it&rsquo;s only called once. Similarly for <code>Q</code> I set it to
<code>l</code>. But then..what is <code>l</code>?</p></li>
<li><p>In fact <code>l</code> is assigned a value 4 via a compound literal. It&rsquo;s declared at the
top of the code and then in main() assigned like: <code>l = ++(int) { 3 } ;</code> which
equates to 4. I think that&rsquo;s pretty cool!</p></li>
<li><p>What is this? <code>for(I=0; A&amp;&amp;I&lt;A-(A-A||A); ++I)</code> In fact the <code>A-(A-A||A)</code> is
equivalent to <code>A-1</code>: <code>A</code> here is always > 0 so <code>A-A</code> is 0; however because <code>A</code>
is non-zero the expression <code>A-A||A</code> is equivalent to <code>0 || A</code> and since A is
non-zero we know that the value is <code>1</code> and thus it&rsquo;s <code>A - 1</code>! I quite like this
technique: it doesn&rsquo;t make sense at first glance and it probably remains elusive
until you look at it more thoroughly. It compares that <code>I &lt; A - 1</code> but the <code>1</code>
is calculated by subtracting from <code>A</code> the value of subtracting <code>A</code> from itself
<code>|| A</code> and <code>A</code> is always non-zero (as the condition says) which means it&rsquo;s
<code>A - 1</code>!</p></li>
</ul>
<p>There might be more things that differ but those are the significant ones.</p>
<p>Of course none of the above is so easy to see without a beautifier. Why did I
choose the format I did? Well it came about in a sequence of possible layouts. I
tried first to make it look like the game might itself but the trouble with that
is it&rsquo;s too random. Then I thought maybe I could spell out the words SNAKE 2020
or IOCCC 2020 or something like that. But these were proving to be a problem for
me; what I was seeing on the screen just wasn&rsquo;t looking right in my head.</p>
<p>At that point I just started playing with different patterns and I quite like
what it&rsquo;s turned out to be. I don&rsquo;t know what I would call it but one could look
at it and think of columns holding up a structure. There&rsquo;s also a symmetry to it
and almost certainly that&rsquo;s what is most attractive about it to me for I love
symmetry.</p>
<p>Some final notes on the layout I&rsquo;d like to point out. First there are 53 lines
counting blank lines. Second is that if you count the number of lines (of code)
in each &lsquo;block&rsquo; they should all be a prime (except the two blocks of 1, I
guess). Third is that I tried to make sure that each column of the code (not
counting the preprocessor - see below on that) start and stop at the same
position (as in column in the row/column kind) on each row. Below I show the
start and end column of each horizontal block. The <code>#undef</code> in the middle should
be centred based on its length and the 120 columns for total. The preprocessor
directives should also be centred in that way (that was my goal anyway).</p>
<p>The following were intentional:</p>
<ul>
<li><p>53 lines.</p></li>
<li><p>The number of lines per vertical block (3, 5, 3, 11, 7, 1, 1, 5, 7).</p></li>
<li><p>Number of horizontal blocks (5)</p></li>
<li><p>Number of vertical blocks (9)</p></li>
<li><p>iocccsize 2053.</p></li>
</ul>
<p>The symmetry was even more important to my mind; observe that each vertical
block (or column) starts and ends on the same column (or at least that was my
goal; I think I did it but maybe I missed one here and/or there):</p>
<ul>
<li>Vertical column #1: 5, 22</li>
<li>Vertical column #2: 25, 41</li>
<li>Vertical column #3: 49, 64</li>
<li>Vertical column #4: 73, 90</li>
<li>Vertical column #5: 97, 120</li>
</ul>
<p>Furthermore based on the length of each C preprocessor directive (the
<code>#define</code>s, the <code>#includes</code>, the <code>#undef</code>) I have attempted to centre them in
the file based on the 120 columns total. I believe I have succeeded in that
though again maybe I have an off by one or two here and/or there.</p>
<p>Most of the primes above were intentional.</p>
<h1><a name="skinning" href="#toc">Skinning the snake (i.e. decreasing the iocccsize)</a></h1>
<p>This happened in a number of ways and I have already documented some in other
parts. Now there are a number of reasons to do this: amongst them to make it
possible to obfuscate (plus a more unique layout) but also to add more features.</p>
<p>Interestingly some of the obfuscation saved bytes; others of course added bytes.
For example token pasting saved a few bytes; on the other hand the combining
<code>if</code>s to the complicated one above added 9 bytes: but another one saved a byte.
I have done this more than once so it&rsquo;s entirely possible there are others I am
forgetting.</p>
<p>Obviously a more significant one is <code>#define q mvprintw</code>: this saved a total of
47 bytes! This was however done towards the end (or so I thought it was the end;
it was anything but) when I started looking at obfuscation rather than adding
features. But then because of this I looked at adding more features!</p>
<p>Another thing that reduced a lot of bytes - 34 to be exact - is using the
<code>mvvline()</code> and <code>mvhline()</code> ncurses functions rather than use three for loops to
draw the walls.</p>
<p>Much later on I made it so that the E() function returns 1; this was a clever
way to have what I already did have - return 1 if there&rsquo;s an error (i.e. memory
error or curses error or screen too small) but otherwise return 0 without having
to have a separate int and I could get rid of two <code>{}</code> pairs as well as add
another use for the E() function: it calls endwin() exactly once (even though
when there isn&rsquo;t an error condition it can be called more than once) as well as
printing the final score - or else an error. And now it also allows for printing
an error and returning from main() at the same time! This also means that by
returning E() I am returning 1 but if the end of main() is reached 0 is
returned. In either case curses is ended.</p>
<p>One of these optimisations saved four bytes simply by taking advantage of the
value of a loop iterator after the loop. The loop is:</p>
<pre><code> for (I = 0; A &amp;&amp; I &lt; A - 1; ++I)
</code></pre>
<p>However after the loop I had this:</p>
<pre><code> A &gt; 1 &amp;&amp; q(n[A - 1],e[A - 1], 'o');
</code></pre>
<p>When I was considering moving that line to before the loop it occurred to me
that as long as <code>A &gt; 0</code> then <code>A - 1 == I</code> after the loop. I still had to check
for <code>A &gt; 1</code> but I could refer to just <code>I</code> instead of <code>A - 1</code>!</p>
<p>There were quite a few other things besides these and these gains were useful to
add additional features and also to add proper error reporting (when <code>calloc()</code>
failed I called <code>abort()</code> and before that if initialising ncurses failed I also
called <code>abort()</code> and did not report any errors in either event but I do now).</p>
<h1><a name="size" href="#toc">A few more interesting size optimisations</a></h1>
<p>As I was getting to the end of obfuscation (wrt size available - and it was
getting pretty obfuscated too - the majority of the techniques were already in
place at this point) I was looking at the code to see if I could figure out how
to save even more bytes. Here are some that I found interesting ways to go about
the problem.</p>
<p>First, the function that turns on colours looked like:</p>
<pre><code> if (h) attron(m(PAIR(L)));
else attroff(m(PAIR(L)));
</code></pre>
<p>But I thought is that else actually needed? If I were to switch the order so
that the <code>attroff()</code> is called first then I could just do an <code>if (h)</code> -
therefore getting rid of the <code>else</code>! But then I thought why not do what I&rsquo;ve
done elsewhere? I had:</p>
<pre><code> attroff(m(PAIR(L)));
if (h) attron(m(PAIR(L)));
</code></pre>
<p>But I then saved an extra byte by making it:</p>
<pre><code> attroff(m(PAIR(L)));
h &amp;&amp; attron(m(PAIR(L)));
</code></pre>
<p>That saved two bytes.</p>
<p>Second let&rsquo;s look at the B() function: there were two things I thought of that
would save some bytes (I no longer know how many but a few at least possibly six
or even more). I had the following code:</p>
<pre><code> if (V &amp;&amp; U &amp;&amp; o) { S(N); b(1); }
</code></pre>
<p>This made sure that only if the snake has caught a bug should it grow by the
growth size and increase the bug count. But was checking for the <code>V</code> or <code>U</code>
necessary? I gave it a look over and it occurred to me: the only time B() is
called with <code>1</code> (thus <code>o</code> is 1 so the if is true) was if the bug actually is
caught. That means I could remove the <code>V &amp;&amp; U &amp;&amp;</code> part of the if! Thus it became
instead:</p>
<pre><code> if (o) { S(N); b(1); }
</code></pre>
<p>Then this</p>
<pre><code> !o &amp;&amp; V &amp;&amp; U &amp;&amp; q U,V,' ');
</code></pre>
<p>&hellip;is to make sure to only clear the spot the bug is (or was) at if
the bug was NOT eaten. Why not eaten? Because if it was eaten it means the
snake&rsquo;s head will be there!</p>
<p>But why did I check for the bug having coordinates? Because I thought that if
the bug has coordinates obviously the function has been called before which
means that we do clear (write a space) over a place the bug was actually at. But
I thought could there maybe be another way of verifying if the game has started
yet?</p>
<p>Before I ask that question I&rsquo;ll point out this: is there a reason it has to be
checked? Yes because right after this line new coordinates are found. But
unfortunately the snake has to be placed first since the bug cannot be placed
where the snake already is. So if I had to make sure the game had started (the
snake has moved at least once) what could I check? In fact that means the
direction is not 0! So I could just replace it with:</p>
<pre><code> !o &amp;&amp; D &amp;&amp; q *U,*V,' ');
</code></pre>
<p>That reduced the count further. But then I wondered if even that much is needed.
The condition is that the bug has evaded which means the snake has moved already
(so game started). What calls to this function happen before the game starts
though? The original placement of the bug. Well if the above check makes sure
that the bug isn&rsquo;t where the snake is at it means that the snake has already
been placed, right? Going further the snake always starts out at the centre (or
rather the close as possible - rounding maybe an issue depending on the max
y/x): in other words not at 0, 0. This means that the only thing I should have
to check for is that <code>!o</code>: because after this call before the game even starts
the score line is updated: so the empty space will be overwritten anyway. And if
the score line is made an empty string it doesn&rsquo;t matter because it&rsquo;ll appear as
all spaces anyway. Thus I could save another three bytes by changing it to:</p>
<pre><code> !o &amp;&amp; q *U,*V,' ');
</code></pre>
<p>Technically it would be a <code>" "</code> (see <a href="HACKING">HACKING</a> file) else for N (not referring to
the variable though it might very well matter here too) movements (i.e. due to
sizes) you will at times (e.g. after eating a bug) see the snake body char at
0,0. I&rsquo;m not bothered about that though because the score line is meant to
display something, it squeezes a few more bytes and having a space is hardly an
imposition on usage (and for that matter having a &lsquo;o&rsquo; at 0,0 isn&rsquo;t either).</p>
<BR>
<HR>
<TABLE><TR>
<TD><a rel="license" href="https://creativecommons.org/licenses/by-sa/3.0/"><img alt="Creative Commons License" style="border-width:0" src="/png/by-sa-3.0-88x31.png" /></a></TD>
<TD><P>&copy; Copyright 1984-2020,
<A HREF="/judges.html">Leo Broukhis, Simon Cooper, Landon Curt Noll</A>
- All rights reserved<BR>
This work is licensed under a <a rel="license" href="https://creativecommons.org/licenses/by-sa/3.0/">Creative Commons Attribution-ShareAlike 3.0 Unported License</a>.</P></TD>
<TD>&nbsp;<!--<a href="https://validator.w3.org/check?uri=referer"><img src="https://www.w3.org/Icons/valid-html401" alt="Valid HTML 4.01 Transitional" height="31" width="88"></a>--></TD>
</TR></TABLE>
</body>
</html>
+26 -27
View File
@@ -274,7 +274,7 @@ technique causes some beautifiers problems too.
- Another use of the `Z` macro is this curious line:
static char s[]=Z(; +<>^v);
static const char*s =Z( ; +<>^v);
There are a number of curious parts. First is the Z() part makes it look
like a function call. Of course that wouldn't work as such because an array
@@ -285,7 +285,7 @@ technique causes some beautifiers problems too.
A very minor factor is that the character 'v' is there and it's (`v`) also
used as a macro (well, define) 'might' be of something to some people. Or
programs maybe? For instance using in vim `*` on the `v` in that array and
it takes you other instances of `v`: as in `\<v\>`: which happens to be
it takes you to other instances of `v`: as in `\<v\>`: which happens to be
something else entirely. That itself however might or might not be
significant for this instance!
@@ -301,9 +301,9 @@ technique causes some beautifiers problems too.
E(Z(YOU WIN!));
Which happens to be in the same function the above char array is defined. Also
it's more like a string than anything but yet it's not visibly a string.
it's more like a string than anything but yet it's not visibly a string.
Some beautifiers don't like this.
Some beautifiers didn't like this at all.
- There's an `#undef` following an `if` in a way to draw attention from what to
do if the if is true.
@@ -353,14 +353,14 @@ converted this:
- Makes use of the different namespaces to have variables and labels be the
same identifier. For example in main() there's a variable that also have the
same name label for `goto` (there used to be two pairs in main()).
same name label for `goto` (there used to be two pairs in `main()`).
- And on that note: makes use of the ugly `goto` in numerous places. This
includes simulating a while() loop, breaking out of that 'loop', breaking out of
two loops (a for() in the 'while()'), re-entering (as in starting over) a for()
loop and for dealing with errors.
includes simulating a `while()` loop, breaking out of that 'loop', breaking out of
two loops (a `for()` in the `'while()'`), re-entering (as in starting over) a
`for()` loop and for dealing with errors.
- Why do I check for `Q || P` and then goto x only to then check for `!Q && !D`
- Why do I check for `Q || P` and then `goto x` only to then check for `!Q && !D`
to then `goto x`? Do I need to check `Q` at all? In fact I do but at a quick glance
it might be easy to miss.
@@ -397,7 +397,7 @@ this in two parts: the negative offsets and then the confusing names.
That's not the only place negative offsets occur! Observe the ternary operators
there too.
I'll go back to the F() macro and in particular what follows one of them:
I'll go back to the `F()` macro and in particular what follows one of them:
g d g = f((a)((*y-2)*(y[-2]-2)),g);
@@ -412,30 +412,29 @@ this in two parts: the negative offsets and then the confusing names.
(*y-2) * (y[-2]-2])
...about? An offset of -2 and subtract -2 from that. Multiply that by the `*y`
(which is `j[3]`) - 2.
...about? An offset of `-2` and subtract `-2` from that. Multiply that by the `*y`
(which is `j[3]`) `- 2`.
But why is there a `g d g =` when the other lines only have the variable (or
location) and a d? (Excepting the one that doesn't refer to `d`.)
location) and a `d`? (Excepting the one that doesn't refer to `d`.)
- On the confusing names etc.: the `getmaxyx()` function gets the maximum Y, X
dimensions. Now in the first call in main() I have the code and tests following:
dimensions. Now in the first call in `main()` I have the code and tests following:
getmaxyx(v, *y, y[-2]);
--*y; --y[-2];
if (y[-2] < 9 || *y < 9)
return E(Z(term too small));
Clearly the max x must be stored in `*y` and the max y must be stored in ..
`y[-2]`. After all anyone knows that the coordinates are in the order (X,Y)!
Clearly the `max x` must be stored in `*y` and the `max y` must be stored in ..
`y[-2]`. After all anyone knows that the coordinates are in the order `(X,Y)`!
In fact the output of my entry and my documentation demonstrates this
clearly: X before Y! It's so true in fact that the documentation for curses
more than once states that it's actually (Y,X)! But the fact I don't even
clearly: `X` before `Y`! It's so true in fact that the documentation for curses
more than once states that it's actually `(Y,X)`! But the fact I don't even
refer to a `x` is possibly confusing even without the negative offset.
Of course I don't have to use negative offsets at all! I could use positive
offsets for every time I use negative offsets. But where's the fun in that?
:)
offsets for every time I use negative offsets. But where's the fun in that? :)
BTW: Some of these are not in the table of expressions in the
[HACKING.html][] ([HACKING.md][] on GitHub) file. Also there might be some
@@ -446,10 +445,10 @@ dimensions. Now in the first call in main() I have the code and tests following:
itself! Instead of misleading comments it's misleading statements in the
file that explains what some of the things are for!
- Misleading variable names for coordinates. In other words the Y coordinate is
called X and the X coordinate is called Y. This adds to the already confusing
- Misleading variable names for coordinates. In other words the `Y` coordinate is
called `X` and the `X` coordinate is called `Y`. This adds to the already confusing
array references but it also adds to the confusion of the order of the curses
functions coordinates: it appears that yes X does come first because the
functions coordinates: it _appears_ that yes `X` does come first because the
function calls that take coordinates suggest it - but in actuality it's just
that the names are deliberately swapped. Of course that's after you determine
that the variables `X` and `Y` are only the snake head but at that point you
@@ -459,8 +458,8 @@ easily be read as `Y` and I have a lot of fun with `V` which I will get to next
coordinates? I thought of this and I think it's more confusing to have something
that is associated to what it is but incorrectly rather than something unrelated
entirely: the mind constructs things from what it has seen, what it experiences,
what it knows, and since X and Y are used for coordinates the natural response
of the brain is to assume Y is what is really X and X is what is really Y.
what it knows, and since `X` and `Y` are used for coordinates the natural response
of the brain is to assume `Y` is what is really `X` and `X` is what is really `Y`.
- More confusion with variable names: If you notice the `int *U, *V` they are
@@ -473,10 +472,10 @@ also part of the compound literal: that is they point into it:
used in.
There's another reason for moving it further down: if you look at the bug
drawing function (which comes before main()) you will see that there I set
drawing function (which comes before `main()`) you will see that there I set
the bug location to refer to the `y` 'array'. I do blank out the old
location at `*U, *V` but then assign the new location differently. Then in
main() I draw it at `*U, *V` and also check for the bug being eaten there
`main()` I draw it at `*U, *V` and also check for the bug being eaten there
too.
-394
View File
@@ -1,394 +0,0 @@
<!doctype html public "-//W3C//DTD HTML 4.0 Transitional //EN">
<html>
<head>
<meta name="GENERATOR" content="mkd2html 2.2.2">
<meta http-equiv="Content-Type"
content="text/html; charset=utf-8"> <link rel="stylesheet"
type="text/css"
href="../hint.css" />
<title></title>
</head>
<body>
<CENTER>
<IMG SRC="/png/ioccc.png" ALT="IOCCC" height=78 width=267>
<P><FONT size="6"><I>The International Obfuscated C Code Contest</I></FONT></P>
<div id="bar">
<ul>
<li><a href="../index.html">About the 27th IOCCC</a></li>
<li><a href="../whowon.html">27th IOCCC Winners</a></li>
<li><a href="/index.html">IOCCC home</a></li>
<li><a href="/winners.html">List of All Winners</a></li>
<li><a href="/judges.html">The Judges</a></li>
</ul>
</div>
<P><FONT size="6"><B>Supplemental Info</B></FONT></P>
</CENTER>
<h1>Terminals</h1>
<p>Terminals are very easy to mess up and for that reason they deserve their own
file. I discuss terminal capabilities, dimensions (setting and how to restore
sanity if it causes any problems) as well as colours (limitations etc.).</p>
<p><a name="toc"></a></p>
<ul>
<li><p><a href="#termcaps">Capabilities support testing program</a></p></li>
<li><p><a href="#dimensions">Setting the game dimensions</a></p>
<ul>
<li><p><a href="#linescolumns">The LINES and COLUMNS environmental variables</a></p></li>
<li><p><a href="#insanity">Terminal insanity</a></p></li>
<li><p><a href="#restore">Restoring the terminal</a></p></li>
<li><p><a href="#abuse">Terminal size abuse</a></p></li>
</ul>
</li>
<li><p><a href="#termlimitations">Terminal limitations</a></p></li>
<li><p><a href="#colours">Terminal colours</a></p>
<ul>
<li><p><a href="#background">Curses background</a></p></li>
<li><p><a href="#monochrome">Monochrome terminals</a></p></li>
<li><p><a href="#colourlimitations">Colour limitations</a></p></li>
<li><p><a href="#disablecolour">Disabling colour</a></p></li>
</ul>
</li>
</ul>
<h1><a name="termcaps" href="#toc">Capabilities support testing program</a></h1>
<p>Although it should be playable without the features I use (except that cursor
movement is required) I have provided a source file that can test your terminal
for the capabilities I use in the entry.</p>
<p>It also tries to determine the minimum number of columns to play without the
status line overflowing - even with the dynamic length. Try:</p>
<pre><code> $ make test
</code></pre>
<p>This compiles the program and runs it; you should see something like:</p>
<pre><code> terminal supports cursor movement
terminal supports making cursor invisible
terminal supports bold
terminal supports colours
terminal rows 42 (39 playable)
terminal cols 157 (155 playable)
snake size: 997 (max size: 6006)
bugs: 199 (max size: 1201)
at least 34 columns recommended for snake size 997 (is 157)
at least 37 columns recommended for snake size 6006 (is 157)
No problems detected.
</code></pre>
<p>If I pass in any of the variables <strong>GROW</strong>, <strong>MAXSIZE</strong>, <strong>SIZE</strong> and/or
<strong>LINES</strong> or <strong>COLUMNS</strong> it bases its calculations on those variables. For
example:</p>
<pre><code> $ MAXSIZE=-1 GROW=1 make test
terminal supports cursor movement
terminal supports making cursor invisible
terminal supports bold
terminal supports colours
terminal rows 42 (39 playable)
terminal cols 157 (155 playable)
snake size: 6006 (max size: 6006)
bugs: 6001 (max size: 6001)
at least 37 columns recommended for snake size 6006 (is 157)
at least 37 columns recommended for snake size 6006 (is 157)
No problems detected.
</code></pre>
<p>As you can see it tells you the max size (the &lsquo;capsized&rsquo; snake) as well as
the requested max size (if the requested size is bigger than the capsize then it
will be set to that value instead) of the snake. The capped size is like in the
Snake game itself but the suggested minimum number of columns is based on a
number of variables.</p>
<p>If I were to do the above but set columns to less &lt; 35 then there would be a
problem. But why if the utility recommends at least 37? This is because the
max size of the snake also depends on the terminal size. This utility is not
perfect: I don&rsquo;t consider shedding; I set growth to 5 if it&rsquo;s 0 (since it would
be indeterminate how many bugs are possible before &lsquo;winning&rsquo; since there would
be no &lsquo;winning&rsquo;); and there are probably other things too.</p>
<p>As for capabilities: besides cursor movement the others are just nice to have.
From my tests keeping the cursor visible doesn&rsquo;t ruin gameplay but it is less
distracting if nothing else to have it invisible (in fact due to the sequence of
function calls the cursor would mostly appear to be not in the game field itself -
from memory at least).</p>
<p>Maybe there are other capabilities I should check for that I&rsquo;m unaware of but
this should give you an idea.</p>
<p>If there are any problems it will say how many (fatal and otherwise). The fatal
problems are if curses fails to initialise or if movement of cursor cannot be
done (both seem odd).</p>
<p>Both scripts run this utility and prompt if there are any problems;
you can continue either way.</p>
<h1><a name="dimensions" href="#toc">Setting the game dimensions</a></h1>
<p>There are a number of ways to do this and only one will keep the terminal sane
all the time but that&rsquo;s by running it under a terminal emulator that you can
resize the window with first. But what if you want exacts?</p>
<h2><a name="linescolumns" href="#toc">The LINES and COLUMNS environmental variables</a></h2>
<p>To specify the lines/columns of curses program per instance use the <code>LINES</code> and
<code>COLUMNS</code> environmental variables.</p>
<p>For demonstration consider the following:</p>
<pre><code> $ echo $LINES $COLUMNS
42 157
</code></pre>
<p>Note: I subtract 1 from the max y/x and the max coords in the game output
include the walls and score line but these values are for the terminal itself.</p>
<p>Say you want 55 columns:</p>
<pre><code> $ COLUMNS=55 ./prog
</code></pre>
<p>This will force curses to detect the max columns (X) of your terminal (for the
game dimensions) - to be 55; it might look like this instead:</p>
<pre><code> X:27/54 Y:20/41 S:5/997 B:0
</code></pre>
<p>But problems can arise with messing with dimensions: in my tests this held only
to lines.</p>
<h2><a name="insanity" href="#toc">Terminal insanity</a></h2>
<p>Terminal sanity can be compromised and it can cause all sorts of output
problems; it might not appear right away but it will show its ugly head
eventually if you use it. For example pager output might be screwy, echo might
be turned off, output of commands might overwrite the input of those commands,
etc. For the game you might not see the final score.</p>
<h3><a name="restore" href="#toc">Restoring the terminal</a></h3>
<p>In my tests there is one thing that at least allows you to see the final score
and that is by running <code>clear</code> before running the program. That&rsquo;s what the
prog.alt version does. You might run it as one of:</p>
<pre><code> LINES=20 ./prog.alt
LINES=20 ./snake.alt
</code></pre>
<p>Even if the final score is visible though the terminal may very well still be
messed up. There are numerous things you might try but probably the easiest is
to run the game again without modifying the dimensions (and then just quit) or
even just the <code>reset</code> command.</p>
<p>The Linux man page says:</p>
<pre><code>You might have to run the `reset` tool like:
&lt;LF&gt;reset&lt;LF&gt;
(the line-feed character is normally control-J) to get the terminal
to work, as carriage-return may no longer work in the abnormal state.
</code></pre>
<p>If you don&rsquo;t have the reset utility you can try:</p>
<pre><code> echo -e \\033c
</code></pre>
<p>Otherwise try <code>clear; stty sane</code> (that will turn on echo also) or if all else
fails log out and back in.</p>
<p>For more information on this subject generally see the <a href="https://www.tldp.org/HOWTO/Keyboard-and-Console-HOWTO.html">Linux keyboard and
console HOWTO</a> (specifically <a href="https://www.tldp.org/HOWTO/Keyboard-and-Console-HOWTO-4.html">Linux keyboard and console HOWTO section 4</a>).
Yes this works under macOS (at least it did for me).</p>
<h3><a name="abuse" href="#toc">Terminal size abuse</a></h3>
<p>So players 1, 2 and 3 are content with not meddling with the terminal sizes
outside what&rsquo;s actually possible with their screen. But then player 4 comes
along and thinks he/she will be clever and mess with the dimensions a bit. Let&rsquo;s
say they have a 13" monitor and they think it&rsquo;d be funny to see how 997 lines
would work; they might try something like:</p>
<pre><code> LINES=997 ./prog
</code></pre>
<p>What then? Well expect trouble; curses will not know any better and the max
number of lines will be 997. If they were to do:</p>
<pre><code> COLUMNS=997 ./prog
</code></pre>
<p>Then they will see a different effect. Again the same reason: the player trying
to be funny.</p>
<p>The game will try and be funny in return and you can expect it to not function
properly. Because that&rsquo;s what funny means in this context.</p>
<h1><a name="termlimitations" href="#toc">Terminal limitations</a></h1>
<p>It&rsquo;d be nice if curses could detect hitting more than one arrow key at the
same time so that diagonal directions would be possible but unfortunately it&rsquo;s
not (<code>cat -v</code> confirms this). Even if I were to define four extra keys what
would they be? And what about the head character? The HACKING file has
information on this.</p>
<p>I also limit the terminal size to 10 lines/columns but most likely it would
require the cheat modes to win and in any event allowing certain low values
causes problems e.g. <strong>LINES=6 COLUMNS=6</strong> and <strong>LINES=3 COLUMNS=3</strong> caused some
nasty issues.</p>
<h1><a name="colours" href="#toc">Terminal colours</a></h1>
<p>N.B.: If all you&rsquo;re after is wanting to change the colours see the script
<a href="snake-colours.sh">snake-colours.sh</a> instead. The rest of this file was mostly notes for the
judges; here I discuss the background, foreground as well as limitations (in
particular runtime limitations).</p>
<h2><a name="background" href="#toc">Curses background</a></h2>
<p>The documentation I have seen says that the background will always be black and
from a quick test this holds even with a terminal that has a white background.
There is a way to force the background to remain white though that&rsquo;s by way of
monochrome (so no colours); I discuss that and another related terminal specific
in the troubleshooting guide (there&rsquo;s another way but it would take me over the
iocccsize; I talk about it in the HACKING file).</p>
<h2><a name="monochrome" href="#toc">Monochrome terminals</a></h2>
<p>According to my tests for monochrome terminals the screen has the white and
black background; if terminal is configured to be black background white
foreground that is the order it is too. You can try that like:</p>
<pre><code> TERM=linux-m ./prog
</code></pre>
<p>But I do not specifically check if the terminal has colours. Is there a curses
implementation that has a problem here? Below I explain what to comment out
should you need colours to be disabled but I personally have not run into any
problems even with monochrome terminals. Later I say what to do to remove colour
support in the source code itself.</p>
<h2><a name="colourlimitations" href="#toc">Colour limitations</a></h2>
<p>According to X/Open Curses, Issue 7 (pg. 57):</p>
<pre><code>With init_pair() and pair_content(), the value of pair must be in a range
from 0 to and including COLOR_PAIRS-1. (There may be an
implementation-specific upper limit on the valid value of pair, but any such
limit is at least 63.) Valid values for f and b are the range from 0 to and
including COLORS-1.
</code></pre>
<p>The manpage for <code>init_pair()</code> says this:</p>
<pre><code> These limits apply to color values and color pairs. Values outside these limits are not legal, and may result in a runtime error:
[...]
COLOR_PAIRS corresponds to the terminal database's max_pairs capability, (see terminfo(5)).
</code></pre>
<p>Based on the two as well as the fact that monochrome terminals (I&rsquo;ve tried under
both Linux and macOS) seem to work fine I believe I am fine here too. And to
confirm this I wrote the following code with the output below:</p>
<pre><code> #include &lt;curses.h&gt;
int main()
{
initscr();
start_color();
printw("COLORS: %d\nCOLOR_PAIRS: %d\n", COLORS, COLOR_PAIRS);
getch();
endwin();
}
TERM=linux-m ./colour_pairs
COLORS: 0
COLOR_PAIRS: 0
</code></pre>
<p>Without specifying the TERM I get:</p>
<pre><code> COLORS: 256
COLOR_PAIRS: 32767
</code></pre>
<p>In the case that colour is supported the standard states that there will be more
possible colour pairs than I have used so that&rsquo;s not a problem either. Perhaps
even it would only be a runtime error if the colours are supported and the
number is out of the range? To try and figure this out I did another test:</p>
<pre><code> int main()
{
initscr();
start_color();
init_pair(COLOR_PAIRS+1, COLOR_WHITE, COLOR_GREEN);
bkgd(COLOR_PAIR(COLOR_PAIRS+1));
init_pair(1, COLOR_WHITE, COLOR_BLACK);
attron(COLOR_PAIR(1));
printw("COLORS: %d\nCOLOR_PAIRS: %d\n", COLORS, COLOR_PAIRS);
getch();
endwin();
}
</code></pre>
<p>Running it like</p>
<pre><code> TERM=linux-m ./colour_pairs
</code></pre>
<p>I got the output as if colours weren&rsquo;t used: 0 and 0. With coloured terminals
however it was not visible. If I however comment out the call to <code>bkgd()</code> I get
instead:</p>
<pre><code> COLORS: 256
COLOR_PAIRS: 32767
</code></pre>
<p>Which leads me to believe that if you try using a value outside the range it
won&rsquo;t work for a colour-capable terminal but it doesn&rsquo;t matter for monochrome
terminals one way or another. And since I don&rsquo;t go beyond the ranges (as I cited
earlier) there shouldn&rsquo;t be any problem here.</p>
<h2><a name="disablecolour" href="#toc">Disabling colour</a></h2>
<p>Nevertheless if it is a problem and you don&rsquo;t want to use a monochrome terminal
(or can&rsquo;t):</p>
<p>First comment out the code that has <code>start_color();</code> and then add <code>return;</code> to the
top of the <code>C()</code> function (the rest of the code won&rsquo;t be reached). If necessary
you can also comment out the <code>init_pair()</code> calls.</p>
<p>Perhaps you only need to add the <code>return;</code> to <code>C()</code>. My guess is that&rsquo;s the case
but I do not know for certain.</p>
<BR>
<HR>
<TABLE><TR>
<TD><a rel="license" href="https://creativecommons.org/licenses/by-sa/3.0/"><img alt="Creative Commons License" style="border-width:0" src="/png/by-sa-3.0-88x31.png" /></a></TD>
<TD><P>&copy; Copyright 1984-2020,
<A HREF="/judges.html">Leo Broukhis, Simon Cooper, Landon Curt Noll</A>
- All rights reserved<BR>
This work is licensed under a <a rel="license" href="https://creativecommons.org/licenses/by-sa/3.0/">Creative Commons Attribution-ShareAlike 3.0 Unported License</a>.</P></TD>
<TD>&nbsp;<!--<a href="https://validator.w3.org/check?uri=referer"><img src="https://www.w3.org/Icons/valid-html401" alt="Valid HTML 4.01 Transitional" height="31" width="88"></a>--></TD>
</TR></TABLE>
</body>
</html>
-474
View File
@@ -1,474 +0,0 @@
<!doctype html public "-//W3C//DTD HTML 4.0 Transitional //EN">
<html>
<head>
<meta name="GENERATOR" content="mkd2html 2.2.2">
<meta http-equiv="Content-Type"
content="text/html; charset=utf-8"> <link rel="stylesheet"
type="text/css"
href="../hint.css" />
<title></title>
</head>
<body>
<CENTER>
<IMG SRC="/png/ioccc.png" ALT="IOCCC" height=78 width=267>
<P><FONT size="6"><I>The International Obfuscated C Code Contest</I></FONT></P>
<div id="bar">
<ul>
<li><a href="../index.html">About the 27th IOCCC</a></li>
<li><a href="../whowon.html">27th IOCCC Winners</a></li>
<li><a href="/index.html">IOCCC home</a></li>
<li><a href="/winners.html">List of All Winners</a></li>
<li><a href="/judges.html">The Judges</a></li>
</ul>
</div>
<P><FONT size="6"><B>Supplemental Info</B></FONT></P>
</CENTER>
<h1>Troubleshooting Snake</h1>
<p>In this file I have a list of a number of possible problems that could show up
under some situations as well as some things that might appear to be happening
or be a problem but actually are not. For each one I have included a summary, a
more thorough description and any resolutions (from easiest to hardest). For
anything that can cause more than one issue I will list those separately to keep
it as structured as possible/easiest to find.</p>
<p><a name="toc"></a>
- <a href="#topwall">The top wall isn&rsquo;t (all/some of the time) visible!</a>
- <a href="#notmoving">The snake isn&rsquo;t moving!</a>
- <a href="#invisiblehead">I can&rsquo;t see the snake head (or other part of the snake)!</a>
- <a href="#invisiblebug">I can&rsquo;t see the bug!</a>
- <a href="#froze">The game froze!</a>
- <a href="#bigsnake">The game gets slower as the snake gets bigger!</a>
- <a href="#headonly">I set SIZE=0 GROW=1, ate a bug but still only the head was visible! Why?</a>
- <a href="#monochrome">I like black text on a white background but even with a white background terminal it ends up black!</a>
- <a href="#toodark">The text is hard to see (not bright enough)!</a>
- <a href="#movefaster">Can I move the snake faster temporarily without having to modify the wait time?</a>
- <a href="#envvars">On environmental variables more generally and string to int conversions</a>
- <a href="#errors">Errors and error reporting</a></p>
<h2><a name="topwall" href="#toc">The top wall isn&rsquo;t (all/some of the time) visible!</a></h2>
<p>Because the score line is dynamic in length depending on the terminal size it
can happen that the score/status wraps to the next line(s). This can be fixed by
modifying the status line (see <a href="HACKING">HACKING</a>) but you shouldn&rsquo;t need it to be very
wide.</p>
<ul>
<li><p>RESOLUTION #0: Use a bigger screen (it doesn&rsquo;t take that many columns)</p>
<p> <strong>Tip:</strong> try running <code>make test</code> to get an estimate of the minimum number of columns
needed. This won&rsquo;t work right if you change the score line!</p>
<p> Note that this utility is not perfect; I describe this elsewhere. Either way a
small screen will make it harder to play esp without the cheat modes enabled
(but they can still be fun with large screens).</p></li>
<li><p>RESOLUTION #1: Open the <a href="prog.c">prog.c</a> and change the line</p>
<pre><code> #define J Z(X:%d/%d Y:%d/%d S:%zu/%zu B:%zu\n),Y,y[-2],X, *y, A, g, c );
</code></pre>
<p> To be something like:</p>
<pre><code> #define J Z(B:%zu\n), c);
</code></pre>
<p> Recompile and try again. That will then show only the number of bugs eaten. See
the HACKING file for other data you can include (though there are some
discrepancies here and there as you&rsquo;ll see).</p></li>
</ul>
<h2><a name="notmoving" href="#toc">The snake isn&rsquo;t moving!</a></h2>
<p>Unless the game is paused this should not be happening. It can appear sometimes
that there isn&rsquo;t movement and sometimes it might have to take a moment to
&lsquo;unwind&rsquo; but as long as the head is moving then everything is fine.</p>
<p>The tail might not always be moving which could make it seem like the snake
isn&rsquo;t moving but as long as the head is moving then the snake can be assumed to
be moving.</p>
<ul>
<li><p>RESOLUTION #0: Unless the game is paused as long as the snake head is moving
everything is fine even if it seems sometimes that the snake tail is still: this
is normal and there are a few conditions that this might especially show itself
e.g. when the snake is growing.</p>
<p> If you want to see this in action try:</p>
<pre><code> SIZE=150 SHEDS=10 SHED=1 ./prog
</code></pre>
<p> Once you start moving you&rsquo;ll see that the tail stays still for a while and
when it does move you&rsquo;ll see it doesn&rsquo;t move for long.</p>
<p> Sometimes also it might appear that the movement is delayed but there are
numerous causes for this some of which are a busy computer but ultimately
it&rsquo;ll catch up; just give it the time it needs.</p></li>
<li><p>BOTTOM LINE: If you want more information then see the <a href="bugs.md">bugs.md</a> file.</p></li>
</ul>
<h2><a name="invisiblehead" href="#toc">I can&rsquo;t see the snake head (or other part of the snake)!</a></h2>
<p>Possibly this could happen with too long a score line which I already discussed.
It also used to be possible during cannibal mode whilst cannibalising: you would
just have to continue moving on and you&rsquo;d eventually find your head (assuming
the rest of the screen isn&rsquo;t covered with your body!). And what else could you
expect if you decided to shove your head up your &hellip;. ? :))</p>
<ul>
<li><p>RESOLUTION #0: Actually I thought it would look better that you could see the
head even when cannibalising so you should be able to lose your head and at the
same time see it!</p></li>
<li><p>RESOLUTION #1: If the terminal width is too small then it could be that the
score line is covering the wall, snake and even bug; I gave two resolutions to
that earlier in this file. To get a recommended number of columns use <code>make
test</code>.</p></li>
</ul>
<h2><a name="invisiblebug" href="#toc">I can&rsquo;t see the bug!</a></h2>
<p>This has happened to me a number of times and early in development there were
times that I could swear I even saw it beyond the walls but this should not be a
problem now if it ever was.</p>
<p>However I have made a lot of effort to think of situations that might make the
bug location calculation and placement be a problem and even did some debug
output and wrote another test program to calculate the maximum number of places
the bug could be put etc.</p>
<p>One of the reasons I have the terminal dimensions have a minimum and also a
maximum has to do with the way the bug placement and max size of the snake (and
so arrays) are calculated: it could happen that because of it being unsigned
without there being restrictions it could end up being a bad value that causes
the bug placement loop to never end (in this case the snake would also stop
moving).</p>
<ul>
<li><p>RESOLUTION #0: If evasion mode is enabled (default after 300 moves) just wait
it out and the bug will move to a new place and it might be easier to see in the
new place.</p></li>
<li><p>RESOLUTION #1: The terminal size is too small for the score line. See the
earlier problem for how to resolve this if that&rsquo;s the case.</p></li>
<li><p>RESOLUTION #2: Sometimes you have to look closely for it can be easy to miss.
If it&rsquo;s against the wall and the screen is <a href="https://www.hp-lexicon.org/character/gaunt-family/morfin-gaunt/">Snakey</a> or you&rsquo;re tired or the colour
contrast isn&rsquo;t right for you or something like that it might be harder to see.
Try pausing the game (space) and scan the screen for it. If you really are
desperate copy and paste the entire file into a document and search for the bug
char (if it&rsquo;s an editor like vi/vim you will have to be sure to escape the char
since <code>*</code> is a regexp metacharacter). This has happened to me numerous times.</p></li>
<li><p>RESOLUTION #3: If the colour contrast is not good for your eyes use the
<a href="snake-colours">snake-colours</a> script to select a different colour scheme.</p></li>
</ul>
<h2><a name="froze" href="#toc">The game froze!</a></h2>
<p>This should not be possible either but without certain safety checks in place I
have caused this (and I did this deliberately in development to find all the
conditions I could to resolve them).</p>
<ul>
<li><p>RESOLUTION #0: If this does happen it likely is to do with placement of the
bug; that is why I have the max size of the snake capped a fair bit below the
maximum number of coordinates in the game field: because the bug isn&rsquo;t to be at
a place the snake already occupies.</p></li>
<li><p>RESOLUTION #1: If the system <code>rand()</code> implementation is really bad maybe it&rsquo;s
having a problem finding a location to place the bug. The best I can think of is
to try increasing the screen size or decrease the max size of the snake.</p></li>
<li><p>BOTTOM LINE: If the bug cannot find a place to be this will likely cause the
game to freeze because the game loops until it finds an available place for the
bug to be; if the pRNG is so bad wrt where the snake occupies it could
theoretically happen. If this happens you will have to kill the game by e.g.
ctrl-c. Try increasing the screen size and/or decreasing the max size of the
snake. See below for some tests.</p>
<p> I removed caps in a test and then:</p>
<pre><code> GROW=1 COLUMNS=30 LINES=10 CANNIBAL=1 MAXSIZE=10000 ./prog
</code></pre>
<p> It froze at this point:</p>
<pre><code> X:14/29 Y:5/9 S:323/10000 B:318
</code></pre>
<p> This is because there was only one place for the bug - where the snake head
was to be. With these parameters the limit is actually 189! This could
perhaps be increased but the calculation I have used is easy and although I
certainly could make it so it&rsquo;s one less than the max that takes more bytes
and I don&rsquo;t see it actually mattering.</p>
<p> Another time I tried:</p>
<pre><code> LINES=6 COLUMNS=6
</code></pre>
<p> And it also froze (as noted I impose a minimum of >= 10 for both LINES and
COLUMNS).</p>
<p> Ultimately I had to kill the program due to the game being stuck in the bug
placement routine. I could have put in a maximum number of loops but what
good would that do? It would use more bytes and what would it do anyway,
win? Well that&rsquo;s what the max size is for.</p></li>
<li><p>TERMINAL SIZE TO MAX SNAKE SIZE CALCULATION ETC.</p>
<p> For this information and more use the termcaps utility:</p>
<pre><code> make test
</code></pre>
<p> An example:</p>
<pre><code> terminal supports cursor movement
terminal supports making cursor invisible
terminal supports bold
terminal supports colours
terminal rows 42 (39 playable)
terminal cols 157 (155 playable)
snake size: 997 (max size: 6006)
bugs: 199 (max size: 1201)
at least 34 columns recommended for snake size 997 (is 157)
at least 37 columns recommended for snake size 6006 (is 157)
No problems detected.
</code></pre>
<p> Why are there only 39 playable lines for 42 rows? The first row is the score
line, the second is the top wall, the last is the bottom wall. For columns
you have the left and rightmost columns for the walls.</p>
<p> The calculation for max size takes place after decrementing the max y/x;
then it&rsquo;s <code>(maxy - 2) * (maxx - 2)</code>; above that would be:</p>
<pre><code> (41 - 2) * (156 - 2) == 6006
</code></pre>
<p> If for some reason the game were to stall for this purpose you would have to
kill the game by e.g. ctrl-c since the bug placement is stuck in a loop.
This shouldn&rsquo;t happen though.</p></li>
</ul>
<h2><a name="bigsnake" href="#toc">The game gets slower as the snake gets bigger!</a></h2>
<p>Realistically the game shouldn&rsquo;t take that much memory but maybe in some very
busy systems it would have a problem.</p>
<ul>
<li><p>RESOLUTION #0: If the rand() implementation is particularly poor then it might
be that the bug placement is taking more time.</p></li>
<li><p>RESOLUTION #1: It could also be the arrays being updated as the snake gets
bigger.</p></li>
<li><p>BOTTOM LINE: I find it unlikely that either of these happen and I don&rsquo;t know
what to say; you can try decreasing the max size to see if it doesn&rsquo;t reach this
problem. Otherwise it would be good to see if you can find a pattern: is it when
the snake is bigger i.e. the screen is rather fuller than when you first begin?
Or is the system rather busy?</p></li>
</ul>
<h2><a name="headonly" href="#toc">I set <code>SIZE=0 GROW=1</code>, ate a bug but still only the head was visible! Why?</a></h2>
<ul>
<li><p>RESOLUTION #0: The size includes the head but what should it show if the size
is 0? The head is the obvious choice so once you do get to size 1 you will still
only have the head. When you get to size 2 you&rsquo;ll have part of the body too.
Try:</p>
<pre><code> SIZE=1 GROW=1
</code></pre>
<p> And you will see that at one bug you&rsquo;ll have size two and just as if you had
two bugs with the previous invocation.</p>
<p> BTW: When you are size 1 you can go back on yourself even if cannibalism is
disabled because there really isn&rsquo;t anything to go back through: it&rsquo;s just
you moving the head until you find a body to use! Once you have size >= 2
then cannibalism mode counts.</p></li>
<li><p>BOTTOM LINE: In some senses SIZE=0 and SIZE=1 are the same thing.</p></li>
</ul>
<h2><a name="monochrome" href="#toc">I like black text on a white background but even with a white background terminal it ends up black!</a></h2>
<p>This is a curses thing but fortunately it should be easy enough to solve.</p>
<ul>
<li><p>RESOLUTION #0: Try setting the terminal to monochrome for the invocation of
the game. Depending on what is installed on your system you might not have a
monochrome terminal but you can certainly get them. In Red Hat systems these can
be found in the package ncurses-term but maybe that will vary on others. I don&rsquo;t
recall having to install it under macOS nor Fedora but those systems have GUIs
so that&rsquo;s probably why; in CentOS I did have to install it specially.</p>
<p> The <code>-m</code> suffix to terminal names means monochrome. Under Linux this
terminal is under <code>/usr/share/terminfo/l/linux-m</code> and under macOS (Catalina
at least) it&rsquo;s at <code>/usr/share/terminfo/6c/linux-m</code>.</p></li>
<li><p>BOTTOM LINE: Try using a monochrome terminal for the game by e.g.:</p>
<pre><code> TERM=linux-m ./prog
</code></pre>
<p> And then on your white background terminal the game should keep the
background white and the foreground black. This will of course mean you have
no colour but unfortunately changing the background colour of curses would
eat too many bytes in the entry (I cite the functions in the HACKING file).</p>
<p> I discuss colours and terminals in much more detail in
<a href="terminals.md">terminals.md</a> (<a href="terminals.html">terminals.html</a>).</p></li>
</ul>
<h2><a name="toodark" href="#toc">The text is hard to see (not bright enough)!</a></h2>
<ul>
<li><p>RESOLUTION #0: Make sure that your terminal settings have for bold text a
brighter font. The way I have my terminal profiles set up is to use bright
colours for bold text. I specifically enable bold in the program so try and find
out if enabling brighter colours is possible.</p>
<p> If it&rsquo;s already set at brighter colours I do not know what to say. Try
playing with the colours in your terminal, maybe the font size or various
other settings. Probably better to make a new profile for this first in case
you mess up your old one. FWIW I haven&rsquo;t had this problem on consoles only
and in my systems I have the option to enable brighter colours for bold - it
was only in testing that I came across this problem.</p></li>
</ul>
<h2><a name="movefaster" href="#toc">Can I move the snake faster temporarily without having to modify the wait time?</a></h2>
<p>Yes. The <code>getch()</code> call is non-blocking when the timeout value is positive so
it&rsquo;s up to that number of milliseconds.</p>
<ul>
<li><p>RESOLUTION #0: All you need to do then is hold down the direction key (or for
that matter any other key that <code>getch()</code> will pick up on). You can also rapidly
push the key instead of holding it down.</p></li>
<li><p>BOTTOM LINE: Depending on the key repeat rate and/or how fast you repeatedly
hit the key you can have more control over the speed - as long as it is quicker
than the regular wait time. For negative wait time (drawing mode) you have to
hit a key every time to move because it is blocking.</p></li>
</ul>
<h2><a name="envvars" href="#toc">On environmental variables more generally and string to int conversions</a></h2>
<p>What happens if you do:</p>
<pre><code> WALLS= ./prog
</code></pre>
<p>Can you run into the wall since you didn&rsquo;t specify a value and the default is 1?
No. That&rsquo;s not the way it works. By saying WALLS= you have told the system that
there is that environmental variable. However the way the <code>strtoul()</code> functions
work is that if there&rsquo;s no valid input it returns 0. This can be detected but
it&rsquo;s wasteful (iocccsize wise) and I have never felt that having invalid input
for a number could have a better value than 0.</p>
<p>If however you were to give valid input followed by invalid input the valid
input would be parsed. For example:</p>
<pre><code> WALLS=1test ./prog
</code></pre>
<p>Would let you go through the walls. On the other hand</p>
<pre><code> WALLS=test1 ./prog
</code></pre>
<p>Would not. Furthermore if you specify the same variable more than once it&rsquo;s the
last one that counts. For example:</p>
<pre><code> WALLS=0 WALLS=1 CANNIBAL=1 CANNIBAL=0 ./prog
</code></pre>
<p>Would allow you to go through walls but you could not cannibalise.</p>
<p>Also note that I specify base 0 which means that you can also have it in hex and
octal. These are all the same:</p>
<pre><code> SIZE=0x3
SIZE=3
SIZE=03
</code></pre>
<p>The way the functions work is if 0x (or 0X) it&rsquo;s considered hex; if prefixed
with a 0 it&rsquo;s octal and otherwise it&rsquo;s decimal. If you specify invalid data
(even if only at the beginning of the string) the functions return 0. For
example</p>
<pre><code> SIZE=0
SIZE=f
SIZE=-
SIZE=f1
</code></pre>
<p>Are all equivalent.</p>
<p>Observe that</p>
<pre><code> SIZE=08
</code></pre>
<p>Is invalid input because octal only has digits 0 - 7: the resulting size will be
0.</p>
<p>I discuss the signed/unsigned issue to do with curses and sizes in C being
unsigned in <a href="bugs.md">bugs.md</a> but probably there isn&rsquo;t anything more to say here.</p>
<h2><a name="errors" href="#toc">Errors and error reporting</a></h2>
<p>If curses fails to initialise you should get an error that says &lsquo;curses error&rsquo;
and you have every right to curse it to hell if that&rsquo;s what you so wish.
Apparently curses will report an error itself if that function fails but that
escaped my notice until later on so you might get two errors in that case.</p>
<p>Assuming it succeeds the game obtains the maximum y/x of the terminal. The
screen size must be at least 10 lines/columns (though in code the number will
not be 10); if either is smaller you will get &lsquo;screen too small&rsquo; and the game
will end (yes things that haven&rsquo;t begun can be ended).</p>
<p>If calloc() fails to obtain the needed memory you&rsquo;ll see something like (here it
was before I added proper - to make the perfect and obvious pun - capsizing
so that by setting the size to -1 it went to the max unsigned value):</p>
<pre><code> $ MAXSIZE=-1 ./prog
memory error
X:0/157 Y:0/42 S:3/18446744073709551614 B:0
</code></pre>
<p>BTW: There are two arrays that have to be <strong>MAXSIZE</strong> (technically + 1).</p>
<p>Is it possible that some value specified by the user could mess this up? I do
not know but what I do know is that because it&rsquo;s unsigned it can&rsquo;t be negative;
if the max size is 0 then the array size will be 1 but it won&rsquo;t matter because
the snake size will be >= that max anyway. But here&rsquo;s a curious output:</p>
<pre><code> SIZE=1 MAXSIZE=0 ./prog
YOU WIN!
X:78/156 Y:20/41 S:0/0 B:0
</code></pre>
<p>Why does it show snake size as 0 when I specified 1? It&rsquo;s because the max size
is 0 and I limit the size to be no bigger than the max size.</p>
<BR>
<HR>
<TABLE><TR>
<TD><a rel="license" href="https://creativecommons.org/licenses/by-sa/3.0/"><img alt="Creative Commons License" style="border-width:0" src="/png/by-sa-3.0-88x31.png" /></a></TD>
<TD><P>&copy; Copyright 1984-2020,
<A HREF="/judges.html">Leo Broukhis, Simon Cooper, Landon Curt Noll</A>
- All rights reserved<BR>
This work is licensed under a <a rel="license" href="https://creativecommons.org/licenses/by-sa/3.0/">Creative Commons Attribution-ShareAlike 3.0 Unported License</a>.</P></TD>
<TD>&nbsp;<!--<a href="https://validator.w3.org/check?uri=referer"><img src="https://www.w3.org/Icons/valid-html401" alt="Valid HTML 4.01 Transitional" height="31" width="88"></a>--></TD>
</TR></TABLE>
</body>
</html>
+1 -1
View File
@@ -3601,7 +3601,7 @@ If you have audible bells enabled the program will beep at every turn.
### Information: [2020/ferguson1/README.md](2020/ferguson1/README.md)
There are some things that might appear to be bugs but are actually features or
things that are misinterpreted as bugs. See his
things that are misinterpreted as bugs. See the
[bugs.md](2020/ferguson1/bugs.md) and
[troubleshooting.md](2020/ferguson1/troubleshooting.md) files for details.
+8 -1
View File
@@ -4359,7 +4359,8 @@ layered chocolate fudge cake recipe](/2020/ferguson1/chocolate-cake.md) :-)
Yes the irony here is as rich as the chocolate cake: the question is do you know
how rich it is? If not and you like chocolate I (that is Cody :-) ) highly
recommend you give it a go! :-)
recommend you give it a go! :-) You're welcome to ask me questions if you wish
and I encourage you to do so as the cake is quite picky!
## <a name="2020_ferguson2"></a>[2020/ferguson2](/2020/ferguson2/prog.c) ([README.md](/2020/ferguson2/README.md))
@@ -4374,6 +4375,12 @@ Most importantly he also added some corrections to the vital [Double
layered chocolate fudge cake recipe](/2020/ferguson2/chocolate-cake.md),
enciphered though it is :-)
Yes the irony here is as rich as the chocolate cake: the question is do you know
how rich it is? If not and you like chocolate I (that is Cody :-) ) highly
recommend you give it a go! :-) You're welcome to ask me questions if you wish
and I encourage you to do so as the cake is quite picky!
## <a name="2020_kurdyukov2"></a>[2020/kurdyukov2](/2020/kurdyukov2/prog.c) ([README.md](/2020/kurdyukov2/README.md))