diff --git a/2020/ferguson1/bugs.html b/2020/ferguson1/bugs.html deleted file mode 100644 index d2ee86395..000000000 --- a/2020/ferguson1/bugs.html +++ /dev/null @@ -1,334 +0,0 @@ - - - - - - - - -
- IOCCC -

The International Obfuscated C Code Contest

-
- -
-

Supplemental Info

-
- - -

Current bugs and things that look like bugs but are not, as of 12 September 2020.

- -

- - -

Built-in test unit for some features!

- -

Fun fact: There’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.

- -

Let’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:

- -
    SIZE=0 SHED=1 SHEDS=1 EVADE=10 ./prog
-
- -

Since you start out at size 0 and you shed every movement then when you’re -size 10 (as long as you don’t eat a bug of course!) the bug should evade.

- -

If you set it to SIZE=10 there would be a difference of 10. Now every -move you will see the size the snake is. But then…Why is it that it -doesn’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’t appear to be -of size 20 yet).

- -

There probably are combinations that can test these types of things I just -don’t at this time remember any I might have done.

- -

The snake doesn’t seem to be moving

- -

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:

- -
        SIZE=100 ./prog
-
- -

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’s the ‘full size’. -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’t moving it is growing or else paused).

- -

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 cannibalism.log has some examples of both -cannibalism and a long snake that didn’t move for most of the game.

- -

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’s the full size.

- -

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’re going is going to be -occupied or not.

- -

Basically if the snake head is moving you can consider the snake to be -moving or growing and that’s the important point (if you have the default -status line you can also see the coordinates being updated to show this).

- -

getch() also accepts input from some input hardware other than keyboards

- -

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 keypad(v, 1); which enables arrow keys.

- -

SIZE=0 is the same as SIZE=1 and other oddities

- -

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?

- -

If SIZE < 0 you’ll likely win straight away since it’s unsigned and it’ll wrap -back to the maximum so you will win automatically (this is the same as the -second mode the judges suggested with SIZE=-1 ./prog).

- -

As for the growth sizes (including shedding) if it’s < 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’t touched so the snake -characters will remain on the screen; only the moving snake is what matters. -But it’s likely the game will be won fairly quickly because once it’s -1 in size -it’ll be at the maximum size.

- -

For example if I say SIZE=3 GROW=-2 at two bugs the game is won.

- -

As for growing: anything > 0 it will grow that many; 0 it will not grow (which I -show as a gameplay mode); and < 0 it will ‘shrink’ as I explained above. You could -say that it’s defying physics by growing and shrinking simultaneously but either -way negative size will force a win.

- -

Here’s a fun output:

- -
        < <<<+
-
- -

That’s from:

- -
        SHED=1 SHEDS=-1 ./prog
-
- -

And right after that you would see:

- -
        YOU WIN!
-        X:72/156 Y:20/41 S:997/997 B:0
-
- -

Try this though:

- -
        SHEDS=-1 SHED=25 ./prog
-
- -

And you’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’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 -gameplay.md (gameplay.html) file.

- -

Here’s another thing to be aware of. Let’s say you do:

- -
        SIZE=1 GROW=-1 ./prog
-
- -

How many bugs will it take before you win? In fact it’s two: you would see the -head twice: the second time once you ‘shrink’ down to size 0; it would then be -that if you get another bug you will be at the ‘max size’:

- -
        YOU WIN!
-        X:81/156 Y:35/41 S:997/997 B:2
-
- -

‘I was a few places behind my tail and I ran into it!’

- -

I.e. what happens if you’re growing - for example after just eating a bug - and -you’re racing towards your tail? If you’re behind it should be fine since you’re -going the same speed as the snake is, right? Not quite. Because you’re growing -you might end up running into your tail (depending on how much you’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.

- -

Remember: the tail at that point isn’t moving yet; the snake is growing!

- -

With negative growth the snake drops from the middle of the body

- -

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’s left after the -rest of the snake has gone through). Doing SHED=100 SHEDS=-1:

- -
        ooooooooo>ooo>
-             ^
-             >
-
- -

The ^ points to the part that’s split from the snake and which will be -there on its own after the snake passes through it. Here’s an example with -it being SHEDS=-3:

- -
        <ooo<ooooo
-        ^^^
-        <oo
-
- -

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’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…on second thought, I won’t -go there! :)

- -

Anyway it’s an odd idea for the snake to shrink by leaving part of its skin: -that’s how they grow in the wild so it’s a misnomer. The shrinking was only -‘discovered’ because it’s an unsigned number but happily it allows for different -gameplay modes.

- -

It looks like the bug is in the snake

- -

I show a different example in the crazy.log 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:

- -
    <*oooooooo
-
- -

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.

- -

On the safety of the bug placement loop

- -

Ilya Kurdyukov shared concern for the loop in the bug placement routine: is it -safe? What he refers to is that it’s a potential infinite loop. But is it? I -understand the concern and it’s something I played with a lot to be sure that it -doesn’t happen. This is how it works.

- -

To explain it I will go back to the make test program termcaps (which is -imperfect for the recommended terminal size but the max snake size is exactly -how it’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.

- -

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:

- -
    $ 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
-
- -

First: what’s the problem? It’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?

- -

With 10 rows and columns it’s calculated as 7 * 7 (i.e. it’s -(cols-3)*(rows-3). However the number of playable locations is in this case 56 -(playable_rows * playable_columns). I have played with this many -times and I do not believe there should be a problem. If there is it’s from a -very poor implementation of rand() and I discuss this in -troubleshooting.md (troubleshooting.html).

- -

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’s even less likely that you’ll ever run into this problem.

- -

The obvious question is why didn’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.

- -

Vertical snake has more space between snake char than horizontal snake

- -

Ilya Kurdyukov also pointed out that depending on orientation of the snake there -are different amount of spaces between the snake char ‘o’. This is what he -had to say on it:

- -

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.

- -

MATE Terminal 1.20.0, and font “Ubuntu Mono Regular 13”

- -

But, as I said, there is no terminal problem itself, it’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).

- -

https://en.wikipedia.org/wiki/Halfwidth_and_fullwidth_forms

- -

So the typical fonts are Half-width or close to it.

- -

- -

However the function mvaddch() takes a chtype 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’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 -spoilers aren’t enough here!).

- -

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.

- -

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’s not at all bugging me -but it is very much appreciated and it means a great deal to me. Cheers.)

-
-
- - - - -
Creative Commons License

© Copyright 1984-2020, -Leo Broukhis, Simon Cooper, Landon Curt Noll -- All rights reserved
-This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.

 
- - diff --git a/2020/ferguson1/chocolate-cake.html b/2020/ferguson1/chocolate-cake.html deleted file mode 100644 index 2c842761e..000000000 --- a/2020/ferguson1/chocolate-cake.html +++ /dev/null @@ -1,203 +0,0 @@ - - - - - - - - -
- IOCCC -

The International Obfuscated C Code Contest

-
- -
-

Supplemental Info

-
- -

Double-layered Chocolate Fudge Cake

- -

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!

- -

picture of the double-layered chocolate fudge cake

- -

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.

- -

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.

- -

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 IOCCC and chocolate. Did I say 'the IOCCC'? I actually -meant 'an IOCCC': it stands also for 'International Office of Cocoa, Chocolate -and Sugar Confectionery'. Perfect.

- -

See also the International Original Chocolate Cake Contest tweet from -fellow IOCCC winner Ilya Kurdyukov (GitHub) as well as the -IOCCC cake source image of the picture in the tweet (which he painted over -my photo of the cake with GIMP).

- -

Measurements

- -

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 -http://www.onlineconversion.com/cooking.htm. This will particularly matter -for cups, teaspoons, tablespoons and ounces.

- -

Baker's chocolate

- -

Baker's chocolate is a brand name and the product in question is unsweetened -chocolate bars used for baking. According to a chocolates FAQ it might be -called different things:

- -
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.
-
- -

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.

- -

Either way please still pay attention to the notes on the chocolate in the recipe and -recipe notes because they're really important!

- -

Special notes for the cake

- -

PAY CLOSE ATTENTION TO THESE:

- - - - -

Cake Ingredients

- - - - -

Cake Preparation

- -
    -
  1. Lightly grease two 9 x 1.5 inch round pans; lightly dust with flour.

  2. -
  3. Preheat oven to 350 F (176.67 C).

  4. -
- - -

Cake Directions

- -
    -
  1. Melt 3 oz unsweetened chocolate in double boiler or small bowl over -hot (but not boiling) water; let cool whilst proceeding.

  2. -
  3. Sift 2 1/4 cups flour, 2 tsp baking soda, and 1/2 tsp salt

  4. -
  5. Beat 1 stick margarine in large bowl until soft.

  6. -
  7. Add 2 1/4 cups packed brown sugar and 3 eggs. Beat until light and -fluffy.

  8. -
  9. Beat in 1 1/2 tsp vanilla and cooled melted chocolate.

  10. -
  11. Stir in dry ingredients alternately with 1 cup sour cream; always beat -until smooth.

  12. -
  13. Stir in 1 cup boiling water.

  14. -
  15. Pour into prepared pans.

  16. -
  17. Bake for ONLY 35 minutes (NO LONGER) at 350 F (176.67 C).

  18. -
  19. When you take the cake out put the cake pans on a cooling rack for TWO -MINUTES ONLY AND THEN IMMEDIATELY TURN CAKES OUT ON TO RACK. Let cool -completely.

  20. -
- - -

Icing Ingredients

- - - - -

You will also need a bigger pan or bowl that can have ice water that the icing -bowl can sit in.

- -

Special notes for the icing

- -

PAY CLOSE ATTENTION TO THESE:

- - - - -

Icing Directions

- -
    -
  1. Combine 4 oz unsweetened chocolate and 1/2 cup margarine in pan. -Melt and remove from heat. DO NOT LET IT GET SOLID.

  2. -
  3. Combine 3 1/4 cups powdered sugar, 1/2 cups whole milk and 2 tsp -vanilla into a bowl. Stir until smooth.

  4. -
  5. Add chocolate mixture.

  6. -
  7. 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 -MAKE THE BOWL IT'S IN COLD but not let the icing get wet.

  8. -
- - - - - -
Creative Commons License

© Copyright 1984-2020, -Leo Broukhis, Simon Cooper, Landon Curt Noll -- All rights reserved
-This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.

 
- - diff --git a/2020/ferguson1/chocolate-cake.md b/2020/ferguson1/chocolate-cake.md index f464165cd..72be853aa 100644 --- a/2020/ferguson1/chocolate-cake.md +++ b/2020/ferguson1/chocolate-cake.md @@ -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 diff --git a/2020/ferguson1/gameplay.html b/2020/ferguson1/gameplay.html deleted file mode 100644 index fa6ca3b9e..000000000 --- a/2020/ferguson1/gameplay.html +++ /dev/null @@ -1,838 +0,0 @@ - - - - - - - - -
- IOCCC -

The International Obfuscated C Code Contest

-
- -
-

Supplemental Info

-
- - -

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’t even need this file at all unless it be -for the input keys.

- -

- -
    -
  1. Testing terminal environment/capabilities

  2. -
  3. Input keys

  4. -
  5. Gameplay

    - - -
  6. -
  7. Gameplay modes

    - - -
  8. -
  9. Scripts

    - - -
  10. -
  11. Notes about some of the game variables

    - - -
  12. -
  13. Conclusion (and inspirational words for everyone)

  14. -
- - -

1. Testing terminal environment/capabilities

- -

Most people probably won’t have any issue at all but for those who have any -problems with the terminal see the terminals.md file for more -information on the terminal capabilities testing utility I include.

- -

For troubleshooting other problems see troubleshooting.md -(troubleshooting.html) and bugs.md (bugs.html).

- -

2. Input keys

- - - - -

3. Gameplay

- -

Here I will show the initial screen as well as what a few things look like. If -you don’t feel you need this but you want to configure colours jump to colour -selection. You can also jump to gameplay modes or game -variables.

- -

The bug colour by default is white; the snake head colour is red and the snake -body colour is green. The walls are cyan.

- -

Gameplay: The initial screen

- -

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:

- -
    X:24/49 Y:8/16 S:5/658 B:0
-    ##################################################
-    #                                                #
-    #                                                #
-    #                                                #
-    #                                                #
-    #                                                #
-    #                                                #
-    #                       +                        #
-    #                                                #
-    #                                      *         #
-    #                                                #
-    #                                                #
-    #                                                #
-    #                                                #
-    #                                                #
-    ##################################################
-
- - - - -

Gameplay: Playing the game

- -
    X:39/49 Y:8/16 S:5/658 B:0
-    ##################################################
-    #                                                #
-    #                                                #
-    #                                                #
-    #                                                #
-    #                                                #
-    #                                                #
-    #                                  oooo>         #
-    #                                                #
-    #                                      *         #
-    #                                                #
-    #                                                #
-    #                                                #
-    #                                                #
-    #                                                #
-    ##################################################
-
- -

I let the snake grow to its full size (with the head at (39),(8)) and I’m two -places above the bug so let’s go down:

- -
    X:39/49 Y:9/16 S:5/658 B:0
-    ##################################################
-    #                                                #
-    #                                                #
-    #                                                #
-    #                                                #
-    #                                                #
-    #                                                #
-    #                                   oooo         #
-    #                                      v         #
-    #                                      *         #
-    #                                                #
-    #                                                #
-    #                                                #
-    #                                                #
-    #                                                #
-    ##################################################
-
- -

Now you see that the snake is going down and in one move the bug will be eaten. -Let’s do that:

- -
    X:36/49 Y:10/16 S:10/658 B:1
-    ##################################################
-    #                                                #
-    #                                                #
-    #                                                #
-    #                 *                              #
-    #                                                #
-    #                                                #
-    #                                                #
-    #                                                #
-    #                                   ^  o         #
-    #                                   oooo         #
-    #                                                #
-    #                                                #
-    #                                                #
-    #                                                #
-    ##################################################
-
- -

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.

- -

Gameplay: Walls

- -

By default walls are passable (WALLS=1). Let’s get to full size and go -through the top wall:

- -
    X:36/49 Y:15/16 S:10/658 B:1
-    ##################################################
-    #                                   o            #
-    #                                   o            #
-    #                                   o            #
-    #                 *                 o            #
-    #                                   o            #
-    #                                   o            #
-    #                                   o            #
-    #                                   o            #
-    #                                   o            #
-    #                                                #
-    #                                                #
-    #                                                #
-    #                                                #
-    #                                   ^            #
-    ##################################################
-
- -

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:

- -
    X:36/49 Y:11/16 S:10/658 B:1
-    ##################################################
-    #                                   o            #
-    #                                   o            #
-    #                                   o            #
-    #                 *                 o            #
-    #                                   o            #
-    #                                                #
-    #                                                #
-    #                                                #
-    #                                                #
-    #                                   ^            #
-    #                                   o            #
-    #                                   o            #
-    #                                   o            #
-    #                                   o            #
-    ##################################################
-
- -

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.

- -

When you specify WALLS=0 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):

- -
    X:20/49 Y:2/16 S:150/658 B:0
-    ##################################################
-    #                   ^                            #
-    #                   o                            #
-    #                   o          *                 #
-    #                   o                            #
-    #                   o                            #
-    #                   o                            #
-    #                   ooooo                        #
-    #                                                #
-    #                                                #
-    #                                                #
-    #                                                #
-    #                                                #
-    #                                                #
-    #                                                #
-    ##################################################
-
- -

If I continue going up I will see:

- -
    OUCH!
-    X:20/49 Y:1/16 S:150/658 B:0
-
- -

Gameplay: Cannibalism

- -

By default cannibalism is disabled (CANNIBAL=0) so if you run into yourself it might look -something like:

- -
    X:45/49 Y:10/16 S:10/658 B:1
-    ##################################################
-    #                                                #
-    #                                                #
-    #                                                #
-    #                 *                              #
-    #                                                #
-    #                                                #
-    #                                                #
-    #                                          ooooo #
-    #                                            ^ o #
-    #                                            ooo #
-    #                                                #
-    #                                                #
-    #                                                #
-    #                                                #
-    ##################################################
-
- -

If I were to do any movement but turn to the left I would run into myself. I’ll -go to the right two spaces:

- -
    OW!
-    X:47/49 Y:10/16 S:10/658 B:1
-
- -

But CANNIBAL=1 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:

- -
    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>                o     o                     #
-    # o           oooooooo     o                     #
-    #oooooooooooooo            o        oooo oooooooo#
-    # o                        o        o  o o       #
-    ##################################################
-
- -

I’ll go back through myself now:

- -
    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>oooooooo            o        oooo oooooooo#
-    # o                        o        o  o o       #
-    ##################################################
-
- -

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:

- -
    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>ooooooo            o        oooo oooooooo#
-    # o                        o        o  o o       #
-    ##################################################
-
- -

Try this: Get a reasonable length and then go back on yourself (if you’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.

- -

An example of extreme cannibalism is in the cannibalism.log file. It has -more than one run the first of one has several dumps. I didn’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:

- -
     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
-
- -

The final example has the snake inside itself.

- -

Gameplay: Shedding (stretching)

- -

This feature will make you grow by the value of SHEDS for every SHED -movements (the counter isn’t incremented when you eat a bug). Basically growing -without eating a bug (stretching would be better name here).

- -

Gameplay: Winning

- -

If you ever get to the MAXSIZE 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 < 0 which will end -up being > the max size though I suppose there might be some value that makes it -less than again - I’m not going to try and figure that out however). Anyway:

- -
    SIZE=-1 ./prog
-    YOU WIN!
-    X:24/49 Y:8/16 S:658/658 B:0
-
- -

Observe that the size isn’t the default 997: because the screen size is too -small for that value (see terminals.md).

- -

The reason I chose 997 is that it leaves a bit of a challenge for some (maybe -most) people but it’s still winnable. Previously even I couldn’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’t need both enabled).

- -

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).

- -

Another reason I chose 997: it’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!

- -

Gameplay: Quitting

- -

If you wish to quit you can hit ‘q’ (case-insensitive). For example:

- -
    X:24/49 Y:8/16 S:5/658 B:0
-
- -

4. Gameplay modes

- -

Here I list a number of different modes of play. In the bugs.md -(bugs.html) file I even show how there’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.

- -

The play.sh script sets up some of these automatically; I describe it after -the modes below.

- -

Photosensitive epilepsy/Stimulation overload trigger warnings

- -

If you have photosensitive epilepsy please be careful especially with low values -for both WAIT and EVADE. It appears that the number of hertz (flashes) -per second triggering seizures is wide but depending on the variables it -easily can be in the range.

- -

There are different patterns and lights flashing at different speeds so please -exercise caution. This could trigger seizures and it might also be too much -stimulation for some people.

- -

Please be careful of these if these types of things have ever affected you or if -you have any form of epilepsy. Thank you.

- -

Gameplay mode: Drawing / Practice mode

- -

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 < 0): then the snake -does not move until you press a movement key. For example:

- -
    WAIT=-1 ./prog
-
- -

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:

- -
    WAIT=-1 CANNIBAL=1 ./prog
-
- -

If you don’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):

- -
    SIZE=50 CANNIBAL=1 WAIT=-1 ./prog
-
- -

Do note that although you’re a bigger size you still grow one movement at a -time.

- -

Okay but then if you get too many bugs the drawing will be over. If this proves -to be a problem simply do:

- -
    SIZE=100 CANNIBAL=1 WAIT=-1 GROW=0 ./prog
-
- -

Or something like that (maybe make the size bigger but that’s up to you). You -could also set the max size to be the highest possible by saying

- -
    MAXSIZE=-1
-
- -

Which I’ve done in the play.sh script.

- -

I discuss how this mode works in spoilers.markdown.

- -

Here’s an example run where I spelt ‘SNAKE’. As you can see it’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.

- -
       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>
-
- -

Gameplay mode: Computer playing / Automatic mode (Photosensitive epilepsy/Stimulation overload trigger)

- -

Photosensitive epilepsy/stimulation overload trigger warning: -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’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.

- -

If you’re still here you can create this effect like:

- -
    WAIT=0 WALLS=1 CANNIBAL=1 ./prog
-
- -

As long as the bug evades you’ll find that the snake is growing because it’s -actually eating bugs; the computer is actually playing the game by itself! You -can still move the snake though it won’t seem like you have much control over -it. If you pause the game you can see that it’s bigger (you probably will be -able to even without pausing it).

- -

Basically the snake is moving so fast that because the bug evades the bug will -inevitably move in the snake path’s and therefore be eaten.

- -

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.

- -

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’s not occupied and -so with fewer available it has a harder time finding a place in that one line.

- -

Computer player variations

- -

Here’s how to make the bug move every time the snake moves:

- -
    CANNIBAL=1 WALLS=1 WAIT=0 EVADE=1 ./prog
-
- -

Help the computer win fairly quickly

- -

If you want to see the game ‘win’ try something like:

- -
    CANNIBAL=1 WALLS=1 WAIT=0 EVADE=1 MAXSIZE=10 ./prog
-
- -

Negative growth (Shrink) Automatic mode

- -

Here’s a fun one I just thought of (a long time after these other modes were -thought of):

- -
    WAIT=0 EVADE=1 GROW=-1 SIZE=9 MAXSIZE=10 CANNIBAL=1 ./prog
-
- -

What you’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’ll start shrinking until it’s just the head -then the head again (i.e. 1 then 0 in size) and then win! This is also in the -play.sh script.

- -

Adjusting the time/speed

- -

Of course you can also do something like:

- -
    WAIT=5 WALLS=1 CANNIBAL=1 ./prog
-
- -

Which although might not seem like it is significantly slower.

- -

Moving the snake about to create patterns

- -

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).

- -

Other ideas

- -

Here’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.

- -

How long will it take for the snake to run into itself? For instance by doing:

- -
    WAIT=0 ./prog
-
- -

On my 13" MacBook Pro at the default settings going horizontally the snake ran -into itself at:

- -
    OW!
-    X:57/156 Y:20/41 S:155/997 B:30
-
- -

What if you set the size to a high value? The lowest? There are bound to be -other games to play with this feature!

- -

Gameplay mode: Grow-Shrink mode (Positive and Negative Winning)

- -

In this mode you’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:

- -

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:

- -
    SIZE=150 SHEDS=-5 GROW=10 SHED=50 MAXSIZE=250 ./prog
-
- -

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’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.

- -

The parameters above were chosen after playing with the mode a bit to find a -value that wouldn’t take that much time but still would pose a challenge. One -could reverse it so that one shrinks more than growing.

- -

The crazy.log file has several screen dumps with this idea.

- -

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 play.sh -also has this mode:

- -
    SIZE=100 SHEDS=5 GROW=-10 SHED=50 MAXSIZE=250 ./prog
-
- -

Obviously there are many other variations. The play.sh 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).

- -

Hypnotic / Sleepy mode (Photosensitive epilepsy/Stimulation overload trigger)

- -

Photosensitive epilepsy/stimulation overload trigger warning: -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’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 EVADE=1 every 231ms there will be a flash in addition to the -snake moving too.

- -

Anyway this might sound absurd but it can be somewhat hypnotic by doing:

- -
    EVADE=1 CANNIBAL=1 ./prog
-
- -

And just moving the snake about not trying to catch any bugs - just let whatever -happens happen.

- -

Gameplay mode: Stimulation / Calming mode

- -

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’t have to -worry about even running into yourself and losing:

- -
    GROW=0 CANNIBAL=1 ./prog
-
- -

Gameplay mode: Expansibility

- -

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’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 timeout() function works for -example.

- -

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.

- -

5. Scripts

- -

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.

- -

Colours selection: snake-colours

- -

To do this use the snake-colours script like so:

- -
    ./snake-colours
-
- -

If you want to pass in specific variables you can do that too e.g.:

- -
    CANNIBAL=1 ./snake-colours
-
- -

The script will prompt you for the colour of the walls, snake head, body and the -bug.

- -

Automate the above gameplay modes

- -

The play.sh 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.

- -

To use you can do something like:

- -
    ./play.sh
-
- -

Or to make it so walls are an obstacle:

- -
    WALLS=0 ./play.sh
-
- -

6. Notes about some of the game variables

- -

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.

- -

WAIT: Snake speed

- -

Besides the different game modes, if you find it too fast/slow you can change it -to a value that’s better for you. Remember it’s a wait time so if you want the -snake to move slower you have to increase the wait time!

- -

EVADE: Bug evasion frequency

- -

For every EVADE 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’s a new place at -all.

- -

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.

- -

This can help you get out of a trap but it can also sometimes make it harder.

- -

SIZE / MAXSIZE: Initial / Max snake sizes

- -

997 might be a bit high for many people. Or maybe you don’t have enough time. Or -you’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.

- -

Note on snake size: there’s a stated size (in the score line) which is what -the snake will ‘populate’ in the snake arrays and the visible size: as I have -discussed here and there the snake doesn’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’t mean it will instantly be 29 characters on the screen.

- -

GROW / SHEDS : Growth / Shedding sizes

- -

Similar to the initial size. Notice that the above point on size applies here: -it will take the number of movements before it is ‘its full size’.

- -

7. Conclusion (and inspirational words for everyone)

- -

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’t have read this far and that’s quite all right; I’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.

- -

Thank you for whatever level of attention you felt you could or wanted to give -and enjoy it in whatever way you see fit!

- -

Much more importantly is that Snake aside I hope I have demonstrated how with -the imagination and creativity almost anything is possible. This is something -that applies in our world in every way and everyone can do something amazing if -they believe in themselves! I would have never thought this the case for me -years ago but I know it’s true now. Believe in yourself. Always.

-
-
- - - - -
Creative Commons License

© Copyright 1984-2020, -Leo Broukhis, Simon Cooper, Landon Curt Noll -- All rights reserved
-This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.

 
- - diff --git a/2020/ferguson1/ioccc-and-chocolate.pdf b/2020/ferguson1/ioccc-and-chocolate.pdf new file mode 100644 index 000000000..2ca469d15 Binary files /dev/null and b/2020/ferguson1/ioccc-and-chocolate.pdf differ diff --git a/2020/ferguson1/play.sh b/2020/ferguson1/play.sh index 56914d47d..ac153dc15 100755 --- a/2020/ferguson1/play.sh +++ b/2020/ferguson1/play.sh @@ -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 diff --git a/2020/ferguson1/spoilers.html b/2020/ferguson1/spoilers.html deleted file mode 100644 index 8424e3e84..000000000 --- a/2020/ferguson1/spoilers.html +++ /dev/null @@ -1,970 +0,0 @@ - - - - - - - - -
- IOCCC -

The International Obfuscated C Code Contest

-
- -
-

Supplemental Info

-
- - -

Introduction (SPOILER ALERT)

- -

In the gameplay.md (gameplay.html) 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’s not to say -everything will be answered here.

- -

If you’re still interested in this file (i.e. you’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?

- -

- - - -

How does it work?

- -

The gameplay I have already described but this explains the way things are -actually done in more detail.

- -

First I initialise curses; if this fails I print an error message (‘curses -error’) and return 1. Next the screen size is determined and I subtract 1 from -each the x/y. If it’s too small curses is ended and an error message (‘screen -too small’) is printed - returning 1.

- -

Next the max size of the snake is determined: if MAXSIZE is specified then -it’s the value of that; otherwise it’s the default. But in either case if it’s -too big based on the screen dimensions it’s capsized. The arrays for the snake -are this size + 1. Other environmental variables are also processed.

- -

Then the arrays are allocated; if either return NULL curses is ended, an error -message (‘memory error’) is printed and return 1.

- -

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’t ‘wait’ for input as such: unless -the wait time is negative (drawing mode) it’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).

- -

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. ‘g’ - just like in -normal mode). But it will then wait again for input.

- -

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).

- -

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).

- -

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’t won at that point find a new place -to place the bug.

- -

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’t started yet it will -jump to the top of the loop. If it’s paused the same thing until it’s resumed. -The rest of the loop can be described thusly.

- -

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’s automatically a game over from -running into walls regardless of that feature status - this simplifies things -greatly (see below for more details).

- -

If cannibal mode is disabled (the default) and the snake runs into itself then -it’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’s game over. If it comes -out on the other side and the snake is there and cannibal mode is disabled then -it’s also game over.

- -

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’s a visual -thing based on the internal data of the game and the features enabled for -example shedding and shedding size.

- -

Finally if the snake’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.

- -

There’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.

- -

How does the snake movement work?

- -

The way the snake looks to move is that every time the snake moves the last -position (the tail) is replaced with a space (' '). If the snake eats a bug -then the snake will get bigger in the next N movements. Note that if the snake -isn’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.

- -

There are two arrays that store the last Y/X coordinates of the snake’s -positions that are shifted forward as the snake moves about the field looking -for bugs.

- -

Drawing (manual) and computer playing (automatic) modes

- -

How do these modes work? The timeout() function takes a signed int: if it’s < -0 it waits indefinitely; if it’s 0 it returns immediately even if there’s no -input waiting (if input is there then it’s used instead); and if it’s > 0 it -waits that many milliseconds. Thus a negative value allows for complete control -over the snake’s movement (speed and otherwise), a value of 0 means the snake -will move as long as it’s not paused etc. and otherwise it waits up to that many -milliseconds (which is how the 0 value comes into play).

- -

Collision detection

- -

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.

- -

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’s just a matter of -verifying if the snake head is at a place that’s occupied by the snake, the wall -or the bug.

- -

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! :)

- -

Cannibal collision detection

- -

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)!

- -

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’t -think that as a problem.

- -

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.

- -

First is that it’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 -is unnatural!

- -

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!

- -

Choose your poison. Or rather your venom.

- -

Collision detection when resizing the window of the game

- -

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?

- -

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’t be -the full window size (or technically a few rows/columns fewer): everything will -remain the same. This GREATLY simplified things.

- -

There was another problem at some point where the snake would quickly grow if it -was increased in size but I believe that’s resolved. Anyway what kind of field -in real life increases in size like that so suddenly? :)

- -

Obfuscation

- - - - -

Obfuscation in prog.3.c and prog.3-j.c

- -

There are a few differences in this version that are worth noting. First of all -is a define that’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:

- - - - -

There might be more things that differ but those are the significant ones.

- -

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’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’t looking right in my head.

- -

At that point I just started playing with different patterns and I quite like -what it’s turned out to be. I don’t know what I would call it but one could look -at it and think of columns holding up a structure. There’s also a symmetry to it -and almost certainly that’s what is most attractive about it to me for I love -symmetry.

- -

Some final notes on the layout I’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 ‘block’ 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 #undef 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).

- -

The following were intentional:

- - - - -

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):

- - - - -

Furthermore based on the length of each C preprocessor directive (the -#defines, the #includes, the #undef) 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.

- -

Most of the primes above were intentional.

- -

Skinning the snake (i.e. decreasing the iocccsize)

- -

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.

- -

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 -ifs to the complicated one above added 9 bytes: but another one saved a byte. -I have done this more than once so it’s entirely possible there are others I am -forgetting.

- -

Obviously a more significant one is #define q mvprintw: 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!

- -

Another thing that reduced a lot of bytes - 34 to be exact - is using the -mvvline() and mvhline() ncurses functions rather than use three for loops to -draw the walls.

- -

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’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 {} pairs as well as add -another use for the E() function: it calls endwin() exactly once (even though -when there isn’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.

- -

One of these optimisations saved four bytes simply by taking advantage of the -value of a loop iterator after the loop. The loop is:

- -
    for (I = 0; A && I < A - 1; ++I)
-
- -

However after the loop I had this:

- -
    A > 1 && q(n[A - 1],e[A - 1], 'o');
-
- -

When I was considering moving that line to before the loop it occurred to me -that as long as A > 0 then A - 1 == I after the loop. I still had to check -for A > 1 but I could refer to just I instead of A - 1!

- -

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 calloc() -failed I called abort() and before that if initialising ncurses failed I also -called abort() and did not report any errors in either event but I do now).

- -

A few more interesting size optimisations

- -

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.

- -

First, the function that turns on colours looked like:

- -
    if (h) attron(m(PAIR(L)));
-    else attroff(m(PAIR(L)));
-
- -

But I thought is that else actually needed? If I were to switch the order so -that the attroff() is called first then I could just do an if (h) - -therefore getting rid of the else! But then I thought why not do what I’ve -done elsewhere? I had:

- -
    attroff(m(PAIR(L)));
-    if (h) attron(m(PAIR(L)));
-
- -

But I then saved an extra byte by making it:

- -
    attroff(m(PAIR(L)));
-    h && attron(m(PAIR(L)));
-
- -

That saved two bytes.

- -

Second let’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:

- -
    if (V && U && o) { S(N); b(1); }
-
- -

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 V or U -necessary? I gave it a look over and it occurred to me: the only time B() is -called with 1 (thus o is 1 so the if is true) was if the bug actually is -caught. That means I could remove the V && U && part of the if! Thus it became -instead:

- -
    if (o) { S(N); b(1); }
-
- -

Then this

- -
    !o && V && U && q U,V,' ');
-
- -

…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’s head will be there!

- -

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?

- -

Before I ask that question I’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:

- -
    !o && D && q *U,*V,' ');
-
- -

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’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 !o: 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’t matter because it’ll appear as -all spaces anyway. Thus I could save another three bytes by changing it to:

- -
    !o  && q *U,*V,' ');
-
- -

Technically it would be a " " (see HACKING 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’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 ‘o’ at 0,0 isn’t either).

-
-
- - - - -
Creative Commons License

© Copyright 1984-2020, -Leo Broukhis, Simon Cooper, Landon Curt Noll -- All rights reserved
-This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.

 
- - diff --git a/2020/ferguson1/spoilers.md b/2020/ferguson1/spoilers.md index db4a58625..f392b8981 100644 --- a/2020/ferguson1/spoilers.md +++ b/2020/ferguson1/spoilers.md @@ -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 `\`: which happens to be + it takes you to other instances of `v`: as in `\`: 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. diff --git a/2020/ferguson1/terminals.html b/2020/ferguson1/terminals.html deleted file mode 100644 index 759677aca..000000000 --- a/2020/ferguson1/terminals.html +++ /dev/null @@ -1,394 +0,0 @@ - - - - - - - - -
- IOCCC -

The International Obfuscated C Code Contest

- -

Supplemental Info

-
- - -

Terminals

- -

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.).

- -

- - - -

Capabilities support testing program

- -

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.

- -

It also tries to determine the minimum number of columns to play without the -status line overflowing - even with the dynamic length. Try:

- -
    $ make test
-
- -

This compiles the program and runs it; you should see something like:

- -
    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.
-
- -

If I pass in any of the variables GROW, MAXSIZE, SIZE and/or -LINES or COLUMNS it bases its calculations on those variables. For -example:

- -
    $ 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.
-
- -

As you can see it tells you the max size (the ‘capsized’ 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.

- -

If I were to do the above but set columns to less < 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’t consider shedding; I set growth to 5 if it’s 0 (since it would -be indeterminate how many bugs are possible before ‘winning’ since there would -be no ‘winning’); and there are probably other things too.

- -

As for capabilities: besides cursor movement the others are just nice to have. -From my tests keeping the cursor visible doesn’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).

- -

Maybe there are other capabilities I should check for that I’m unaware of but -this should give you an idea.

- -

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).

- -

Both scripts run this utility and prompt if there are any problems; -you can continue either way.

- -

Setting the game dimensions

- -

There are a number of ways to do this and only one will keep the terminal sane -all the time but that’s by running it under a terminal emulator that you can -resize the window with first. But what if you want exacts?

- -

The LINES and COLUMNS environmental variables

- -

To specify the lines/columns of curses program per instance use the LINES and -COLUMNS environmental variables.

- -

For demonstration consider the following:

- -
    $ echo $LINES $COLUMNS
-    42 157
-
- -

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.

- -

Say you want 55 columns:

- -
    $ COLUMNS=55 ./prog
-
- -

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:

- -
    X:27/54 Y:20/41 S:5/997 B:0
-
- -

But problems can arise with messing with dimensions: in my tests this held only -to lines.

- -

Terminal insanity

- -

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.

- -

Restoring the terminal

- -

In my tests there is one thing that at least allows you to see the final score -and that is by running clear before running the program. That’s what the -prog.alt version does. You might run it as one of:

- -
    LINES=20 ./prog.alt
-    LINES=20 ./snake.alt
-
- -

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 reset command.

- -

The Linux man page says:

- -
You might have to run the `reset` tool like:
-
-       <LF>reset<LF>
-
-       (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.
-
- -

If you don’t have the reset utility you can try:

- -
    echo -e \\033c
-
- -

Otherwise try clear; stty sane (that will turn on echo also) or if all else -fails log out and back in.

- -

For more information on this subject generally see the Linux keyboard and -console HOWTO (specifically Linux keyboard and console HOWTO section 4). -Yes this works under macOS (at least it did for me).

- -

Terminal size abuse

- -

So players 1, 2 and 3 are content with not meddling with the terminal sizes -outside what’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’s -say they have a 13" monitor and they think it’d be funny to see how 997 lines -would work; they might try something like:

- -
    LINES=997 ./prog
-
- -

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:

- -
    COLUMNS=997 ./prog
-
- -

Then they will see a different effect. Again the same reason: the player trying -to be funny.

- -

The game will try and be funny in return and you can expect it to not function -properly. Because that’s what funny means in this context.

- -

Terminal limitations

- -

It’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’s -not (cat -v 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.

- -

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. LINES=6 COLUMNS=6 and LINES=3 COLUMNS=3 caused some -nasty issues.

- -

Terminal colours

- -

N.B.: If all you’re after is wanting to change the colours see the script -snake-colours.sh 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).

- -

Curses background

- -

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’s by way of -monochrome (so no colours); I discuss that and another related terminal specific -in the troubleshooting guide (there’s another way but it would take me over the -iocccsize; I talk about it in the HACKING file).

- -

Monochrome terminals

- -

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:

- -
    TERM=linux-m ./prog
-
- -

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.

- -

Colour limitations

- -

According to X/Open Curses, Issue 7 (pg. 57):

- -
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.
-
- -

The manpage for init_pair() says this:

- -
       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)).
-
- -

Based on the two as well as the fact that monochrome terminals (I’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:

- -
    #include <curses.h>
-
-    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
-
- -

Without specifying the TERM I get:

- -
    COLORS: 256
-    COLOR_PAIRS: 32767
-
- -

In the case that colour is supported the standard states that there will be more -possible colour pairs than I have used so that’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:

- -
    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();
-    }
-
- -

Running it like

- -
    TERM=linux-m ./colour_pairs
-
- -

I got the output as if colours weren’t used: 0 and 0. With coloured terminals -however it was not visible. If I however comment out the call to bkgd() I get -instead:

- -
    COLORS: 256
-    COLOR_PAIRS: 32767
-
- -

Which leads me to believe that if you try using a value outside the range it -won’t work for a colour-capable terminal but it doesn’t matter for monochrome -terminals one way or another. And since I don’t go beyond the ranges (as I cited -earlier) there shouldn’t be any problem here.

- -

Disabling colour

- -

Nevertheless if it is a problem and you don’t want to use a monochrome terminal -(or can’t):

- -

First comment out the code that has start_color(); and then add return; to the -top of the C() function (the rest of the code won’t be reached). If necessary -you can also comment out the init_pair() calls.

- -

Perhaps you only need to add the return; to C(). My guess is that’s the case -but I do not know for certain.

-
-
- - - - -
Creative Commons License

© Copyright 1984-2020, -Leo Broukhis, Simon Cooper, Landon Curt Noll -- All rights reserved
-This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.

 
- - diff --git a/2020/ferguson1/troubleshooting.html b/2020/ferguson1/troubleshooting.html deleted file mode 100644 index 4de9e88de..000000000 --- a/2020/ferguson1/troubleshooting.html +++ /dev/null @@ -1,474 +0,0 @@ - - - - - - - - -
- IOCCC -

The International Obfuscated C Code Contest

- -

Supplemental Info

-
- - -

Troubleshooting Snake

- -

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.

- -

-- The top wall isn’t (all/some of the time) visible! -- The snake isn’t moving! -- I can’t see the snake head (or other part of the snake)! -- I can’t see the bug! -- The game froze! -- The game gets slower as the snake gets bigger! -- I set SIZE=0 GROW=1, ate a bug but still only the head was visible! Why? -- I like black text on a white background but even with a white background terminal it ends up black! -- The text is hard to see (not bright enough)! -- Can I move the snake faster temporarily without having to modify the wait time? -- On environmental variables more generally and string to int conversions -- Errors and error reporting

- -

The top wall isn’t (all/some of the time) visible!

- -

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 HACKING) but you shouldn’t need it to be very -wide.

- - - - -

The snake isn’t moving!

- -

Unless the game is paused this should not be happening. It can appear sometimes -that there isn’t movement and sometimes it might have to take a moment to -‘unwind’ but as long as the head is moving then everything is fine.

- -

The tail might not always be moving which could make it seem like the snake -isn’t moving but as long as the head is moving then the snake can be assumed to -be moving.

- - - - -

I can’t see the snake head (or other part of the snake)!

- -

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’d eventually find your head (assuming -the rest of the screen isn’t covered with your body!). And what else could you -expect if you decided to shove your head up your …. ? :))

- - - - -

I can’t see the bug!

- -

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.

- -

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.

- -

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).

- - - - -

The game froze!

- -

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).

- - - - -

The game gets slower as the snake gets bigger!

- -

Realistically the game shouldn’t take that much memory but maybe in some very -busy systems it would have a problem.

- - - - -

I set SIZE=0 GROW=1, ate a bug but still only the head was visible! Why?

- - - - -

I like black text on a white background but even with a white background terminal it ends up black!

- -

This is a curses thing but fortunately it should be easy enough to solve.

- - - - -

The text is hard to see (not bright enough)!

- - - - -

Can I move the snake faster temporarily without having to modify the wait time?

- -

Yes. The getch() call is non-blocking when the timeout value is positive so -it’s up to that number of milliseconds.

- - - - -

On environmental variables more generally and string to int conversions

- -

What happens if you do:

- -
    WALLS= ./prog
-
- -

Can you run into the wall since you didn’t specify a value and the default is 1? -No. That’s not the way it works. By saying WALLS= you have told the system that -there is that environmental variable. However the way the strtoul() functions -work is that if there’s no valid input it returns 0. This can be detected but -it’s wasteful (iocccsize wise) and I have never felt that having invalid input -for a number could have a better value than 0.

- -

If however you were to give valid input followed by invalid input the valid -input would be parsed. For example:

- -
    WALLS=1test ./prog
-
- -

Would let you go through the walls. On the other hand

- -
    WALLS=test1 ./prog
-
- -

Would not. Furthermore if you specify the same variable more than once it’s the -last one that counts. For example:

- -
    WALLS=0 WALLS=1 CANNIBAL=1 CANNIBAL=0 ./prog
-
- -

Would allow you to go through walls but you could not cannibalise.

- -

Also note that I specify base 0 which means that you can also have it in hex and -octal. These are all the same:

- -
    SIZE=0x3
-    SIZE=3
-    SIZE=03
-
- -

The way the functions work is if 0x (or 0X) it’s considered hex; if prefixed -with a 0 it’s octal and otherwise it’s decimal. If you specify invalid data -(even if only at the beginning of the string) the functions return 0. For -example

- -
    SIZE=0
-    SIZE=f
-    SIZE=-
-    SIZE=f1
-
- -

Are all equivalent.

- -

Observe that

- -
    SIZE=08
-
- -

Is invalid input because octal only has digits 0 - 7: the resulting size will be -0.

- -

I discuss the signed/unsigned issue to do with curses and sizes in C being -unsigned in bugs.md but probably there isn’t anything more to say here.

- -

Errors and error reporting

- -

If curses fails to initialise you should get an error that says ‘curses error’ -and you have every right to curse it to hell if that’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.

- -

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 ‘screen too small’ and the game -will end (yes things that haven’t begun can be ended).

- -

If calloc() fails to obtain the needed memory you’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):

- -
    $ MAXSIZE=-1 ./prog
-    memory error
-    X:0/157 Y:0/42 S:3/18446744073709551614 B:0
-
- -

BTW: There are two arrays that have to be MAXSIZE (technically + 1).

- -

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’s unsigned it can’t be negative; -if the max size is 0 then the array size will be 1 but it won’t matter because -the snake size will be >= that max anyway. But here’s a curious output:

- -
    SIZE=1 MAXSIZE=0 ./prog
-    YOU WIN!
-    X:78/156 Y:20/41 S:0/0 B:0
-
- -

Why does it show snake size as 0 when I specified 1? It’s because the max size -is 0 and I limit the size to be no bigger than the max size.

-
-
- - - - -
Creative Commons License

© Copyright 1984-2020, -Leo Broukhis, Simon Cooper, Landon Curt Noll -- All rights reserved
-This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.

 
- - diff --git a/bugs.md b/bugs.md index b30bf7859..3a30e9342 100644 --- a/bugs.md +++ b/bugs.md @@ -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. diff --git a/thanks-for-help.md b/thanks-for-help.md index bdd735afb..20519e210 100644 --- a/thanks-for-help.md +++ b/thanks-for-help.md @@ -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! ## [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! + + ## [2020/kurdyukov2](/2020/kurdyukov2/prog.c) ([README.md](/2020/kurdyukov2/README.md))