basekernel/user/snake.c

210 lines
4.1 KiB
C
Raw Normal View History

2024-10-14 23:09:36 +02:00
/*
Copyright (C) 2016-2019 The University of Notre Dame
This software is distributed under the GNU General Public License.
See the file LICENSE for details.
*/
#include "library/string.h"
#include "library/syscalls.h"
#include "library/stdio.h"
#include "library/nwindow.h"
#define SNAKE_MAX 128
#define THICK 5
struct coords { int x; int y; };
struct nwindow *nw = 0;
int randint(int min, int max)
{
// Could be a lot better but at the moment it works
uint32_t tm;
syscall_system_time(&tm);
int state = tm;
if(state % 5 == 0) {
state += 50000;
} else if(state % 4 == 0) {
state += 1000;
} else if(state % 3 == 0) {
state += 10000;
} else if(state % 2 == 0) {
state += 25000;
} else {
state += 16000;
}
int diff = max - min;
return state % diff + min;
}
void init_snake_coords(struct coords *snake, int *length, int xsteps, int ysteps )
{
*length = 3;
snake[0].x = xsteps/2;
snake[0].y = ysteps/2;
int i;
for(i=1;i<*length++;i++) {
snake[i].x = snake[i-1].x-1;
snake[i].y = snake[0].y;
}
}
void scaled_rect( struct nwindow *nw, int x, int y, int scale )
{
nw_rect(nw,x*scale,y*scale,scale,scale);
}
void update_snake(struct coords *snake, int *length, int x, int y, int grow )
{
int i;
if(!grow) {
nw_fgcolor(nw,0,0,0);
scaled_rect(nw,snake[*length-1].x,snake[*length-1].y,THICK);
}
*length += grow;
for(i=*length-1;i>0;i--) {
snake[i] = snake[i-1];
}
snake[0].x = x;
snake[0].y = y;
nw_fgcolor(nw,0,255,0);
scaled_rect(nw,x,y,THICK);
}
int check_snake_collision( struct coords *snake, int length )
{
int i;
for(i=1;i<length;i++) {
if(snake[i].x==snake[0].x && snake[i].y==snake[0].y) return 1;
}
return 0;
}
void init_apple( struct coords *apple, int xsteps, int ysteps )
{
apple->x = randint(0,xsteps);
apple->y = randint(0,ysteps);
nw_fgcolor(nw,255, 0, 0);
scaled_rect(nw,apple->x,apple->y,THICK);
}
int move_snake(struct coords *snake, int *length, struct coords *apple, int xsteps, int ysteps, char dir)
{
int x, y;
switch (dir) {
case 'a':
x = snake[0].x - 1;
y = snake[0].y;
break;
case 'd':
x = snake[0].x + 1;
y = snake[0].y;
break;
case 'w':
x = snake[0].x;
y = snake[0].y - 1;
break;
case 's':
x = snake[0].x;
y = snake[0].y + 1;
break;
default:
x = snake[0].x;
y = snake[0].y;
break;
}
if(x<=-1 || x>=xsteps || y<=-1 || y>=ysteps ) return -1;
if(x==apple->x && y==apple->y) {
update_snake(snake, length, x, y, 5);
init_apple(apple,xsteps,ysteps);
} else {
update_snake(snake, length, x, y, 0);
}
if(check_snake_collision(snake,*length)) {
return -1;
}
return 0;
}
int main(int argc, char *argv[])
{
struct coords snake[SNAKE_MAX];
struct coords apple;
int snake_length = 3;
int speed = 100;
nw = nw_create_default();
int width = nw_width(nw);
int height = nw_height(nw);
// Board dimensions in snake blocks
int xsteps = width / THICK;
int ysteps = height / THICK;
nw_clear(nw,0, 0, width, height);
nw_string(nw,THICK * 3, THICK * 4, "Press any key to start");
nw_string(nw,THICK * 3, THICK * 8, "w: up");
nw_string(nw,THICK * 3, THICK * 12, "s: down");
nw_string(nw,THICK * 3, THICK * 16, "a: left");
nw_string(nw,THICK * 3, THICK * 20, "d: right");
nw_flush(nw);
char c = nw_getchar(nw,1);
while(1) {
char dir = 'd';
nw_clear(nw,0,0,width,height);
init_snake_coords(snake, &snake_length, xsteps, ysteps);
init_apple(&apple,xsteps, ysteps);
while(1) {
syscall_process_sleep(speed);
c = nw_getchar(nw,0);
if((c == 'a' && dir == 'd') || (c == 'd' && dir == 'a') || (c == 'w' && dir == 's') || (c == 's' && dir == 'w')) {
// reject conflicting input
} else if(c == 'w' || c == 'a' || c == 's' || c == 'd') {
dir = c;
} else if(c=='q') {
break;
}
int status = move_snake(snake, &snake_length, &apple, xsteps, ysteps, dir);
nw_flush(nw);
if(status<0) break;
}
nw_flush(nw);
nw_fgcolor(nw,255, 255, 255);
nw_string(nw,THICK * 3, THICK * 4, "You lose!");
nw_string(nw,THICK * 3, THICK * 8, "Enter q to quit");
nw_string(nw,THICK * 3, THICK * 12, "Press any key to start");
nw_flush(nw);
c = nw_getchar(nw,1);
if (c == 'q') return 0;
}
}