There are probably easier ways to implement this, but I really enjoy working within self imposed constraints. I wanted it to be on the 128x64 pixel OLED that I have, so I could not afford to waste screen real estate on big sprites. The sprites I use are only 4x4 pixels! I wanted it to be written in MicroPython, because I enjoy the interactivity and super fast no compile dev cycles.
After many false starts I settled to build the snake out of four curves: A, B, C, and D.
By drawing the four sprites at various offsets, I was able to draw the snake slithering in all horizontal and vertical directions.
The challenge is how to draw a continuous snake when turning. Some turns are naturally easy, but some are problematic depending on which phase of the slithering the snake is at when user asks for a turn.
For example if snake is going left to right, and user press down when head is C would require a different curve when the head is B, or A, or D.
Since we need to know when the snake's head hit an apple, the actual head point must be consistently maintained. Note the dots on the diagram below. That's the actual snake segment positions, the slithering curves are drawn relative to those points.
Not so obvious is when going the opposite direction, it is not a simple matter of reversing the sequence of segments. Note that going left to right, head is on the bottom right corner of C. However going right to left, head needs to be on the bottom left side of C otherwise, the snake would lag when eating an apple in that direction :-(
I actually end up writing a utility to visualize the snake segments and create lookup tables. It is ugly, but I was unable to find an elegant solution.
Surprisingly MicroPython is more than fast enough to do all these lookups and draw the snake basically pixel by pixel!