Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Snake Game Final Implementation #99

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ UPROGS=\
$U/_mkdir\
$U/_rm\
$U/_sh\
$U/_snake\
$U/_stressfs\
$U/_usertests\
$U/_grind\
Expand Down
38 changes: 38 additions & 0 deletions kernel/console.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,43 @@ consoleread(int user_dst, uint64 dst, int n)
return target - n;
}

//Get current keypress from console with no delay.
int
consolekeys(int user_dst, uint64 dst, int n)
{
uint target;
int c;
char cbuf;

target = n;
acquire(&cons.lock);
while(n > 0){

if(killed(myproc())){
release(&cons.lock);
return -1;
}

c = cons.buf[cons.r++ % INPUT_BUF_SIZE];
// copy the input byte to the user-space buffer.
cons.w = cons.e;
cbuf = c;
if (c != '\033' && c!= '[' && c != 'A' && c != 'B' && c != 'C' && c != 'D'){
cons.r--;
break;
}

if(either_copyout(user_dst, dst, &cbuf, 1) == -1)
break;

dst++;
--n;
}
release(&cons.lock);

return target - n;
}

//
// the console input interrupt handler.
// uartintr() calls this for input character.
Expand Down Expand Up @@ -188,5 +225,6 @@ consoleinit(void)
// connect read and write system calls
// to consoleread and consolewrite.
devsw[CONSOLE].read = consoleread;
devsw[CONSOLE].keys = consolekeys;
devsw[CONSOLE].write = consolewrite;
}
1 change: 1 addition & 0 deletions kernel/defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ struct file* filealloc(void);
void fileclose(struct file*);
struct file* filedup(struct file*);
void fileinit(void);
int filekeys(struct file*, uint64, int n);
int fileread(struct file*, uint64, int n);
int filestat(struct file*, uint64 addr);
int filewrite(struct file*, uint64, int n);
Expand Down
28 changes: 28 additions & 0 deletions kernel/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,34 @@ fileread(struct file *f, uint64 addr, int n)
return r;
}

// Read keys from file f.
// addr is a user virtual address.
int
filekeys(struct file *f, uint64 addr, int n)
{
int r = 0;

if(f->readable == 0)
return -1;

if(f->type == FD_PIPE){
r = piperead(f->pipe, addr, n);
} else if(f->type == FD_DEVICE){
if(f->major < 0 || f->major >= NDEV || !devsw[f->major].keys)
return -1;
r = devsw[f->major].keys(1, addr, n);
} else if(f->type == FD_INODE){
ilock(f->ip);
if((r = readi(f->ip, 1, addr, f->off, n)) > 0)
f->off += r;
iunlock(f->ip);
} else {
panic("fileread");
}

return r;
}

// Write to file f.
// addr is a user virtual address.
int
Expand Down
1 change: 1 addition & 0 deletions kernel/file.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ struct inode {
struct devsw {
int (*read)(int, uint64, int);
int (*write)(int, uint64, int);
int (*keys)(int, uint64, int);
};

extern struct devsw devsw[];
Expand Down
2 changes: 2 additions & 0 deletions kernel/syscall.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ extern uint64 sys_unlink(void);
extern uint64 sys_link(void);
extern uint64 sys_mkdir(void);
extern uint64 sys_close(void);
extern uint64 sys_keys(void);

// An array mapping syscall numbers from syscall.h
// to the function that handles the system call.
Expand All @@ -126,6 +127,7 @@ static uint64 (*syscalls[])(void) = {
[SYS_link] sys_link,
[SYS_mkdir] sys_mkdir,
[SYS_close] sys_close,
[SYS_keys] sys_keys,
};

void
Expand Down
1 change: 1 addition & 0 deletions kernel/syscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@
#define SYS_link 19
#define SYS_mkdir 20
#define SYS_close 21
#define SYS_keys 22
14 changes: 14 additions & 0 deletions kernel/sysfile.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,20 @@ sys_read(void)
return fileread(f, p, n);
}

uint64
sys_keys(void)
{
struct file *f;
int n;
uint64 p;

argaddr(1, &p);
argint(2, &n);
if(argfd(0, 0, &f) < 0)
return -1;
return filekeys(f, p, n);
}

uint64
sys_write(void)
{
Expand Down
10 changes: 10 additions & 0 deletions kernel/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,13 @@ typedef unsigned int uint32;
typedef unsigned long uint64;

typedef uint64 pde_t;

typedef struct {
int x, y;
} Point;

typedef struct {
Point body[sizeof(Point)*20];
int length;
Point direction;
} Snake;
133 changes: 133 additions & 0 deletions user/snake.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"

#define WIDTH 20
#define HEIGHT 10
#define SNAKE_MAX_LENGTH 20

uint32 rand() {
uint32 x = uptime();
x ^= x << 13;
x ^= x >> 17;
x ^= x << 5;
return x;
}

void move_cursor() {
printf("\033[%d;1H", HEIGHT + 3);
}

void clear_screen() {
printf("\033[H\033[J");
}

void draw_border() {
for (int i = 0; i < WIDTH + 2; i++) printf("#");
printf("\n");
for (int i = 0; i < HEIGHT; i++) {
printf("#");
for (int j = 0; j < WIDTH; j++) printf(" ");
printf("#\n");
}
for (int i = 0; i < WIDTH + 2; i++) printf("#");
printf("\n");
}

void draw_snake(Snake *snake) {
for (int i = 0; i < snake->length; i++) {
printf("\033[%d;%dH@", snake->body[i].y + 2, snake->body[i].x + 2);
}
}

void draw_food(Point *food) {
printf("\033[%d;%dH*", food->y + 2, food->x + 2);
}

void update_snake(Snake *snake) {
for (int i = snake->length - 1; i > 0; i--) {
snake->body[i] = snake->body[i - 1];
}
snake->body[0].x += snake->direction.x;
snake->body[0].y += snake->direction.y;
}

int check_collision(Snake *snake) {
Point head = snake->body[0];
if (head.x < 0 || head.x >= WIDTH || head.y < 0 || head.y >= HEIGHT) return 1;
for (int i = 1; i < snake->length; i++) {
if (head.x == snake->body[i].x && head.y == snake->body[i].y) return 1;
}
return 0;
}

void place_food(Point *food, Snake *snake) {
int valid;
do {
valid = 1;
food->x = rand() % WIDTH;
food->y = rand() % HEIGHT;
for (int i = 0; i < snake->length; i++) {
if (food->x == snake->body[i].x && food->y == snake->body[i].y) {
valid = 0;
break;
}
}
} while (!valid);
}

void game_over(Snake *snake) {
printf("\033[%d;%dHGame Over!\n", HEIGHT / 2 + 2, WIDTH / 2 - 4);
printf("\033[%d;%dHYou scored %d!\n", HEIGHT / 2 + 3, WIDTH / 2 - 4, snake->length-1);
move_cursor();
return;
}

int main() {
Snake snake;
Point food;
snake.length = 1;
snake.body[0].x = WIDTH / 2;
snake.body[0].y = HEIGHT / 2;
snake.direction.x = 1;
snake.direction.y = 0;

place_food(&food, &snake);

clear_screen();
draw_border();
draw_snake(&snake);
draw_food(&food);

while (1) {
char input[3]; // Buffer to store escape sequences
int n = keys(0, input, 3); // Read up to 3 characters
if (n > 0) {
if (n == 3 && input[0] == '\033' && input[1] == '[') {
switch (input[2]) {
case 'A': if (snake.direction.y == 0) { snake.direction.x = 0; snake.direction.y = -1; } break; // Up
case 'B': if (snake.direction.y == 0) { snake.direction.x = 0; snake.direction.y = 1; } break; // Down
case 'C': if (snake.direction.x == 0) { snake.direction.x = 1; snake.direction.y = 0; } break; // Right
case 'D': if (snake.direction.x == 0) { snake.direction.x = -1; snake.direction.y = 0; } break; // Left
}
}
}
if (check_collision(&snake)){
game_over(&snake);
return 0;
}
if (snake.body[0].x == food.x && snake.body[0].y == food.y) {
if (snake.length < SNAKE_MAX_LENGTH) snake.length++;
place_food(&food, &snake);
}
update_snake(&snake);
clear_screen();
draw_border();
draw_snake(&snake);
draw_food(&food);
move_cursor();
sleep(3);
}
return 0;
}

1 change: 1 addition & 0 deletions user/user.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ int getpid(void);
char* sbrk(int);
int sleep(int);
int uptime(void);
int keys(int, void*, int);

// ulib.c
int stat(const char*, struct stat*);
Expand Down
1 change: 1 addition & 0 deletions user/usys.pl
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@ sub entry {
entry("sbrk");
entry("sleep");
entry("uptime");
entry("keys");