IOCCC image by Matt Zucker

The International Obfuscated C Code Contest

troubleshooting.html for 2020/ferguson1

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

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


Jump to: top