Bouncing a cursor on the display screen is a enjoyable programming train, and you should use widespread C library methods and ANSI escape sequences to make it occur in a terminal window, as coated in final week’s Lesson. At this level, most programmers could be content material and go away properly sufficient alone. Not me!
The primary, and main, change I made to the code is to show the one asterisk right into a line of asterisks — a snake. So as an alternative of a single asterisk bouncing across the terminal display screen, a conga line of asterisks bounces across the display screen. The impact appears like a snake making an attempt to flee.
2024_10_12-Lesson-a.c
#embrace <stdio.h> #embrace <time.h> #embrace <unistd.h> #embrace <sys/ioctl.h> #outline house() printf("e[H") #define clear() printf("e[He[2J") int kbhit(void) { int k; ioctl(STDIN_FILENO,FIONREAD,&k); return(k); } void putat(x,y,c) { printf("e[%d;%dH%c",y,x,c); } void delay(int m) { long pause; clock_t now,then; pause = m*(CLOCKS_PER_SEC/1000); now = then = clock(); while( (now-then) < pause ) now = clock(); } int main() { int rows,columns,vert,horz,a; const int length = 7; struct winsize w; struct coord { int y; int x; } tail[length]; char buffer[BUFSIZ]; ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); rows = w.ws_row; columns = w.ws_col; setvbuf(stdout,buffer,_IONBF,BUFSIZ); clear(); places("Press Enter to finish"); vert=1; horz=1; for( a=0; a<size; a++ ) { tail[a].y = columns/2; tail[a].x = rows/2; } whereas(1) { if( kbhit() ) { getchar(); break; } putat( tail[0].y, tail[0].x, ' '); for( a=1; a<size; a++ ) putat( tail[a].y, tail[a].x, '*'); for( a=0; a<length-1; a++ ) { tail[a].y = tail[a+1].y; tail[a].x = tail[a+1].x; } tail[length-1].x += horz; tail[length-1].y += vert; delay(125); if( tail[length-1].y==columns-1 || tail[length-1].y==1 ) vert=-vert; if( tail[length-1].x==rows-1 || tail[length-1].x==2 ) horz=-horz; } putat(1,rows-1,'B'); places("ye!"); return 0; }
This code requires an enormous replace to the foremost() perform to account for plotting a number of asterisks in a line. To perform this activity, the coord construction is created, which comprises members y
and x
for rows and columns. This construction is asserted as an array, tail
, with a given size
outlined as a continuing integer.
Your entire “snake” is initialized to the middle display screen place in a for loop:
for( a=0; a<size; a++ )
{
tail[a].y = columns/2;
tail[a].x = rows/2;
}
Throughout the countless whereas loop, an asterisk is ready at each place within the tail construction array:
for( a=1; a<size; a++ )
putat( tail[a].y, tail[a].x, '*');
Then the snake’s place is up to date, copying every array component from the top (the final component, tail[length-1]
) again all the way down to the tail (tail[0]
):
for( a=0; a<length-1; a++ )
{
tail[a].y = tail[a+1].y;
tail[a].x = tail[a+1].x;
}
Lastly, the top is moved in response to the route variables horz
and vert
:
tail[length-1].x += horz;
tail[length-1].y += vert;
A delay happens, adopted by if statements to verify the boundaries and reverse the horz
and vert
route variables if obligatory.
Determine 1 illustrates the outcomes. You possibly can change the snake’s size by resetting the size
variable, although as a continuing it could’t be adjusted because the code runs.

Determine 1. The snake!
Not content material with my messing round, I attempted one other replace to the code, one so as to add shade. This transformation is finished by updating solely the putat() perform, proven right here:
void putat(x,y,c) { int shade; shade = x/10; change(shade) { case 0: printf("e[31me[%d;%dH%c",y,x,c); break; case 1: printf("e[32me[%d;%dH%c",y,x,c); break; case 2: printf("e[33me[%d;%dH%c",y,x,c); break; case 3: printf("e[34me[%d;%dH%c",y,x,c); break; case 4: printf("e[35me[%d;%dH%c",y,x,c); break; case 5: printf("e[36me[%d;%dH%c",y,x,c); break; default: printf("e[37me[%d;%dH%c",y,x,c); } }
The column position is divided by ten — which is a guess, assuming an 80-column screen. Using the screen’s actual width would be a better determination. These ANSI color codes were covered in an earlier blog post.
You can obtain the full code for this update from GitHub. Its output looks like Figure 1, but with colors applied as the snake horizontally traverses the screen. (The GIF I made doesn’t capture the colors adequately.)