Assignment 6 completed
This commit is contained in:
7
notes/work-summary-2026-04-16-to-18.md
Normal file
7
notes/work-summary-2026-04-16-to-18.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
I developed a simple application framework inside my OS by creating a menu system that lets the user switch between applications, currently music and Snake. I implemented a basic terminal input method using keyboard interrupts so the user can select an application from the menu and return back to it after use. This demonstrates integration between screen output, keyboard handling, and overall OS control flow.
|
||||||
|
|
||||||
|
For the Snake application, I designed a full game loop with its own game state, including the snake, food, score, and board representation. I used dynamic memory allocation to create and destroy the game state, which shows practical use of memory management in my OS. The game uses PIT/timing to control movement speed and game pacing, while keyboard input is used in real time to change direction, restart, or quit.
|
||||||
|
|
||||||
|
I also integrated sound through the PC speaker to give feedback for events such as eating food, dying, and winning. Overall, this task shows integration of multiple OS components, real-time system programming, practical application of operating system concepts, and creative problem-solving through building an interactive menu-driven game environment.
|
||||||
|
|
||||||
|
Finally everything is printed to the screen using existing TerminalWrite...(); infrastructure.
|
||||||
@@ -72,6 +72,7 @@ add_executable(uiaos-kernel
|
|||||||
src/memory.c
|
src/memory.c
|
||||||
src/pit.c
|
src/pit.c
|
||||||
src/songPlayer.c
|
src/songPlayer.c
|
||||||
|
src/snake.c
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
#define KEYBOARD_DATA_PORT 0x60
|
#define KEYBOARD_DATA_PORT 0x60
|
||||||
#define KEYBOARD_BUFFER_SIZE 256
|
#define KEYBOARD_BUFFER_SIZE 256
|
||||||
|
|
||||||
|
char GetLastKeyPressed(void);
|
||||||
|
|
||||||
void KeyboardHandler(struct Registers* registers);
|
void KeyboardHandler(struct Registers* registers);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -17,6 +17,8 @@
|
|||||||
#define DIVIDER (PIT_BASE_FREQ / TARGET_FREQ)
|
#define DIVIDER (PIT_BASE_FREQ / TARGET_FREQ)
|
||||||
#define TICKS_PER_MS (TARGET_FREQ / TARGET_FREQ) // = 1, needed for converting ms into ticks
|
#define TICKS_PER_MS (TARGET_FREQ / TARGET_FREQ) // = 1, needed for converting ms into ticks
|
||||||
|
|
||||||
|
uint32_t GetCurrentTick(void);
|
||||||
|
|
||||||
void PitInitialize();
|
void PitInitialize();
|
||||||
void SleepInterrupt(uint32_t ticks);
|
void SleepInterrupt(uint32_t ticks);
|
||||||
void SleepBusy(uint32_t milliseconds);
|
void SleepBusy(uint32_t milliseconds);
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ enum vga_colour{
|
|||||||
uint8_t VgaEntryColour(enum vga_colour fg, enum vga_colour bg);
|
uint8_t VgaEntryColour(enum vga_colour fg, enum vga_colour bg);
|
||||||
uint16_t VgaEntry(unsigned char uc, uint8_t color);
|
uint16_t VgaEntry(unsigned char uc, uint8_t color);
|
||||||
|
|
||||||
|
void TerminalClear(void);
|
||||||
void TerminalEntryAt(char c, uint8_t colour, size_t x, size_t y);
|
void TerminalEntryAt(char c, uint8_t colour, size_t x, size_t y);
|
||||||
void TerminalInitialize(void);
|
void TerminalInitialize(void);
|
||||||
void TerminalSetColour(uint8_t colour);
|
void TerminalSetColour(uint8_t colour);
|
||||||
@@ -35,5 +36,6 @@ void TerminalWrite(const char* data, size_t size);
|
|||||||
void TerminalWriteString(const char* data);
|
void TerminalWriteString(const char* data);
|
||||||
void TerminalWriteUInt(uint32_t num);
|
void TerminalWriteUInt(uint32_t num);
|
||||||
void TerminalWriteHex(uint32_t memory);
|
void TerminalWriteHex(uint32_t memory);
|
||||||
|
char TerminalGetChar(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,8 +1,11 @@
|
|||||||
#ifndef SNAKEAPP_SNAKE_H
|
#ifndef SNAKEAPP_SNAKE_H
|
||||||
#define SNAKEAPP_SNAKE_H
|
#define SNAKEAPP_SNAKE_H
|
||||||
|
|
||||||
#define BOARD_SIZE 25
|
#include <libc/stdint.h>
|
||||||
|
|
||||||
|
#define BOARD_SIZE 15
|
||||||
#define SNAKE_MAX_LENGTH (BOARD_SIZE * BOARD_SIZE)
|
#define SNAKE_MAX_LENGTH (BOARD_SIZE * BOARD_SIZE)
|
||||||
|
#define GAME_SPEED_MS 500
|
||||||
|
|
||||||
enum Direction {
|
enum Direction {
|
||||||
UP,
|
UP,
|
||||||
@@ -24,7 +27,7 @@ struct SnakeSegment {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct Snake {
|
struct Snake {
|
||||||
int length;
|
uint32_t length;
|
||||||
enum Direction direction;
|
enum Direction direction;
|
||||||
struct SnakeSegment body[SNAKE_MAX_LENGTH];
|
struct SnakeSegment body[SNAKE_MAX_LENGTH];
|
||||||
};
|
};
|
||||||
@@ -34,14 +37,36 @@ struct Food {
|
|||||||
int y;
|
int y;
|
||||||
};
|
};
|
||||||
|
|
||||||
void InitializeBoard(void);
|
struct GameState {
|
||||||
|
char board[BOARD_SIZE][BOARD_SIZE][3];
|
||||||
|
struct Snake* snake;
|
||||||
|
struct Food* food;
|
||||||
|
uint32_t score;
|
||||||
|
uint32_t rngState;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GameState* CreateGame(void);
|
||||||
|
void DestroyGame(struct GameState* game);
|
||||||
|
void ResetGame(struct GameState* game);
|
||||||
|
|
||||||
|
void InitializeBoard(struct GameState* game);
|
||||||
void InitializeSnake(struct Snake* snake);
|
void InitializeSnake(struct Snake* snake);
|
||||||
void InitializeFood(struct Food* food);
|
void InitializeFood(struct Food* food);
|
||||||
|
|
||||||
|
uint32_t Random(uint32_t* rngState);
|
||||||
|
void HandleInput(struct GameState* game, char input);
|
||||||
|
|
||||||
|
void PlayFoodSound(void);
|
||||||
|
void PlayDeathSound(void);
|
||||||
|
void PlayWinSound(void);
|
||||||
|
|
||||||
struct SnakeSegment MoveSnake(struct Snake* snake);
|
struct SnakeSegment MoveSnake(struct Snake* snake);
|
||||||
void SpawnFood(struct Snake* snake, struct Food* food);
|
void SpawnFood(struct GameState* game);
|
||||||
void AddSegment(struct Snake* snake, int x, int y);
|
void AddSegment(struct Snake* snake, int x, int y);
|
||||||
enum CollisionType CheckCollision(struct Snake* snake, struct Food* food);
|
enum CollisionType CheckCollision(struct Snake* snake, struct Food* food);
|
||||||
void DrawBoard(struct Snake* snake, struct Food* food);
|
|
||||||
|
void DrawBoard(struct GameState* game);
|
||||||
|
|
||||||
void PlayGame(void);
|
void PlayGame(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
#include <kernel/pit.h>
|
#include <kernel/pit.h>
|
||||||
#include <songApp/song.h>
|
#include <songApp/song.h>
|
||||||
#include <songApp/frequencies.h>
|
#include <songApp/frequencies.h>
|
||||||
|
#include <snakeApp/snake.h>
|
||||||
|
|
||||||
extern uint32_t end;
|
extern uint32_t end;
|
||||||
|
|
||||||
@@ -30,12 +31,10 @@ void PlayMusic(void) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
while(1) {
|
|
||||||
for(uint32_t i = 0; i < songCount; i++) {
|
for(uint32_t i = 0; i < songCount; i++) {
|
||||||
player->play_song(&songs[i]);
|
player->play_song(&songs[i]);
|
||||||
SleepInterrupt(1000);
|
SleepInterrupt(1000);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
@@ -50,37 +49,23 @@ void main(void) {
|
|||||||
InitPaging();
|
InitPaging();
|
||||||
PrintMemoryLayout();
|
PrintMemoryLayout();
|
||||||
|
|
||||||
/*
|
while (1) {
|
||||||
|
TerminalClear();
|
||||||
void* memory1 = malloc(48261);
|
TerminalWriteString("Enter application number (0 for music, 1 for snake): ");
|
||||||
void* memory2 = malloc(27261);
|
char input = TerminalGetChar();
|
||||||
void* memory3 = malloc(12617);
|
|
||||||
|
|
||||||
TerminalWriteString("memory1 = ");
|
|
||||||
TerminalWriteHex((uint32_t)memory1);
|
|
||||||
TerminalWriteString("\n");
|
|
||||||
|
|
||||||
TerminalWriteString("memory2 = ");
|
|
||||||
TerminalWriteHex((uint32_t)memory2);
|
|
||||||
TerminalWriteString("\n");
|
|
||||||
|
|
||||||
TerminalWriteString("memory3 = ");
|
|
||||||
TerminalWriteHex((uint32_t)memory3);
|
|
||||||
TerminalWriteString("\n");
|
|
||||||
|
|
||||||
free(memory2);
|
|
||||||
|
|
||||||
void* memory4 = malloc(1000);
|
|
||||||
|
|
||||||
TerminalWriteString("memory4 = ");
|
|
||||||
TerminalWriteHex((uint32_t)memory4);
|
|
||||||
TerminalWriteString("\n");
|
|
||||||
|
|
||||||
SleepTest();
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
switch (input) {
|
||||||
|
case '0':
|
||||||
PlayMusic();
|
PlayMusic();
|
||||||
|
break;
|
||||||
|
case '1':
|
||||||
|
PlayGame();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
TerminalWriteString("Invalid application number.\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
__asm__ volatile("hlt");
|
__asm__ volatile("hlt");
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
static uint32_t index = 0;
|
static uint32_t index = 0;
|
||||||
static uint8_t keyboardBuffer[KEYBOARD_BUFFER_SIZE];
|
static uint8_t keyboardBuffer[KEYBOARD_BUFFER_SIZE];
|
||||||
|
|
||||||
|
static volatile char lastKeyPressed = 0;
|
||||||
|
|
||||||
static const char scancodeToAscii[128] = {
|
static const char scancodeToAscii[128] = {
|
||||||
0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',
|
0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',
|
||||||
'\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',
|
'\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',
|
||||||
@@ -19,6 +21,12 @@ static const char scancodeToAscii[128] = {
|
|||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
char GetLastKeyPressed(void) {
|
||||||
|
char key = lastKeyPressed;
|
||||||
|
lastKeyPressed = 0;
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
void KeyboardHandler(struct Registers* registers) {
|
void KeyboardHandler(struct Registers* registers) {
|
||||||
(void) registers;
|
(void) registers;
|
||||||
|
|
||||||
@@ -37,7 +45,7 @@ void KeyboardHandler(struct Registers* registers) {
|
|||||||
char ascii = scancodeToAscii[scancode];
|
char ascii = scancodeToAscii[scancode];
|
||||||
|
|
||||||
if (ascii != 0) {
|
if (ascii != 0) {
|
||||||
TerminalPutChar(ascii);
|
lastKeyPressed = ascii;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
static volatile uint32_t pit_ticks = 0; // Encasulated to pit.c to avoid accidental overwrite
|
static volatile uint32_t pit_ticks = 0; // Encasulated to pit.c to avoid accidental overwrite
|
||||||
|
|
||||||
static uint32_t GetCurrentTick(void){
|
uint32_t GetCurrentTick(void){
|
||||||
return pit_ticks;
|
return pit_ticks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,70 @@
|
|||||||
#include <snakeApp/snake.h>
|
#include <snakeApp/snake.h>
|
||||||
|
#include <kernel/memory.h>
|
||||||
|
#include <kernel/pit.h>
|
||||||
|
#include <kernel/keyboard.h>
|
||||||
|
#include <kernel/terminal.h>
|
||||||
|
#include <songApp/song.h>
|
||||||
|
#include <songApp/frequencies.h>
|
||||||
|
|
||||||
char board[BOARD_SIZE][BOARD_SIZE][3];
|
struct GameState* CreateGame(void) {
|
||||||
struct Snake snake;
|
struct GameState* game = (struct GameState*)malloc(sizeof(struct GameState));
|
||||||
struct Food food;
|
if (!game) {
|
||||||
enum CollisionType collisionType;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void InitializeBoard(void) {
|
game->snake = (struct Snake*)malloc(sizeof(struct Snake));
|
||||||
for (int i = 0; i < BOARD_SIZE; i++) {
|
if (!game->snake) {
|
||||||
for (int j = 0; j < BOARD_SIZE; j++) {
|
free(game);
|
||||||
board[i][j][0] = ' ';
|
return 0;
|
||||||
board[i][j][1] = ' ';
|
}
|
||||||
board[i][j][2] = '\0';
|
|
||||||
|
game->food = (struct Food*)malloc(sizeof(struct Food));
|
||||||
|
if (!game->food) {
|
||||||
|
free(game->snake);
|
||||||
|
free(game);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
game->score = 0;
|
||||||
|
game->rngState = GetCurrentTick();
|
||||||
|
|
||||||
|
InitializeBoard(game);
|
||||||
|
InitializeSnake(game->snake);
|
||||||
|
InitializeFood(game->food);
|
||||||
|
|
||||||
|
return game;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DestroyGame(struct GameState* game) {
|
||||||
|
if (!game) return;
|
||||||
|
|
||||||
|
if (game->snake) {
|
||||||
|
free(game->snake);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (game->food) {
|
||||||
|
free(game->food);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(game);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResetGame(struct GameState* game) {
|
||||||
|
if (!game) return;
|
||||||
|
|
||||||
|
InitializeBoard(game);
|
||||||
|
InitializeSnake(game->snake);
|
||||||
|
InitializeFood(game->food);
|
||||||
|
game->score = 0;
|
||||||
|
game->rngState = GetCurrentTick();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitializeBoard(struct GameState* game) {
|
||||||
|
for (uint32_t i = 0; i < BOARD_SIZE; i++) {
|
||||||
|
for (uint32_t j = 0; j < BOARD_SIZE; j++) {
|
||||||
|
game->board[i][j][0] = ' ';
|
||||||
|
game->board[i][j][1] = ' ';
|
||||||
|
game->board[i][j][2] = '\0';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -27,6 +81,79 @@ void InitializeFood(struct Food* food) {
|
|||||||
food->y = (BOARD_SIZE / 2) - 3;
|
food->y = (BOARD_SIZE / 2) - 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t Random(uint32_t* rngState) {
|
||||||
|
*rngState = (*rngState * 1103515245) + 12345;
|
||||||
|
return *rngState;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleInput(struct GameState* game, char input) {
|
||||||
|
switch (input) {
|
||||||
|
case 'w': {
|
||||||
|
if (game->snake->direction != DOWN) {
|
||||||
|
game->snake->direction = UP;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 's': {
|
||||||
|
if (game->snake->direction != UP) {
|
||||||
|
game->snake->direction = DOWN;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'a': {
|
||||||
|
if (game->snake->direction != RIGHT) {
|
||||||
|
game->snake->direction = LEFT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'd': {
|
||||||
|
if (game->snake->direction != LEFT) {
|
||||||
|
game->snake->direction = RIGHT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'r': {
|
||||||
|
if (game) {
|
||||||
|
ResetGame(game);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'q': {
|
||||||
|
TerminalWriteString("Quitting game...\n");
|
||||||
|
DestroyGame(game);
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayFoodSound(void) {
|
||||||
|
PlaySound(B5);
|
||||||
|
SleepInterrupt(50);
|
||||||
|
StopSound();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayDeathSound(void) {
|
||||||
|
PlaySound(G3);
|
||||||
|
SleepInterrupt(100);
|
||||||
|
StopSound();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayWinSound(void) {
|
||||||
|
PlaySound(C5);
|
||||||
|
SleepInterrupt(100);
|
||||||
|
StopSound();
|
||||||
|
|
||||||
|
PlaySound(E5);
|
||||||
|
SleepInterrupt(100);
|
||||||
|
StopSound();
|
||||||
|
|
||||||
|
PlaySound(G5);
|
||||||
|
SleepInterrupt(200);
|
||||||
|
StopSound();
|
||||||
|
}
|
||||||
|
|
||||||
struct SnakeSegment MoveSnake(struct Snake* snake) {
|
struct SnakeSegment MoveSnake(struct Snake* snake) {
|
||||||
int x = snake->body[0].x;
|
int x = snake->body[0].x;
|
||||||
int y = snake->body[0].y;
|
int y = snake->body[0].y;
|
||||||
@@ -34,7 +161,7 @@ struct SnakeSegment MoveSnake(struct Snake* snake) {
|
|||||||
switch (snake->direction) {
|
switch (snake->direction) {
|
||||||
case UP: {
|
case UP: {
|
||||||
snake->body[0].y--;
|
snake->body[0].y--;
|
||||||
for (int i = 1; i < snake->length; i++) {
|
for (uint32_t i = 1; i < snake->length; i++) {
|
||||||
int tempX = snake->body[i].x;
|
int tempX = snake->body[i].x;
|
||||||
int tempY = snake->body[i].y;
|
int tempY = snake->body[i].y;
|
||||||
snake->body[i].x = x;
|
snake->body[i].x = x;
|
||||||
@@ -46,7 +173,7 @@ struct SnakeSegment MoveSnake(struct Snake* snake) {
|
|||||||
}
|
}
|
||||||
case DOWN: {
|
case DOWN: {
|
||||||
snake->body[0].y++;
|
snake->body[0].y++;
|
||||||
for (int i = 1; i < snake->length; i++) {
|
for (uint32_t i = 1; i < snake->length; i++) {
|
||||||
int tempX = snake->body[i].x;
|
int tempX = snake->body[i].x;
|
||||||
int tempY = snake->body[i].y;
|
int tempY = snake->body[i].y;
|
||||||
snake->body[i].x = x;
|
snake->body[i].x = x;
|
||||||
@@ -58,7 +185,7 @@ struct SnakeSegment MoveSnake(struct Snake* snake) {
|
|||||||
}
|
}
|
||||||
case LEFT: {
|
case LEFT: {
|
||||||
snake->body[0].x--;
|
snake->body[0].x--;
|
||||||
for (int i = 1; i < snake->length; i++) {
|
for (uint32_t i = 1; i < snake->length; i++) {
|
||||||
int tempX = snake->body[i].x;
|
int tempX = snake->body[i].x;
|
||||||
int tempY = snake->body[i].y;
|
int tempY = snake->body[i].y;
|
||||||
snake->body[i].x = x;
|
snake->body[i].x = x;
|
||||||
@@ -70,7 +197,7 @@ struct SnakeSegment MoveSnake(struct Snake* snake) {
|
|||||||
}
|
}
|
||||||
case RIGHT: {
|
case RIGHT: {
|
||||||
snake->body[0].x++;
|
snake->body[0].x++;
|
||||||
for (int i = 1; i < snake->length; i++) {
|
for (uint32_t i = 1; i < snake->length; i++) {
|
||||||
int tempX = snake->body[i].x;
|
int tempX = snake->body[i].x;
|
||||||
int tempY = snake->body[i].y;
|
int tempY = snake->body[i].y;
|
||||||
snake->body[i].x = x;
|
snake->body[i].x = x;
|
||||||
@@ -80,34 +207,37 @@ struct SnakeSegment MoveSnake(struct Snake* snake) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return (struct SnakeSegment){ x, y };
|
return (struct SnakeSegment){ x, y };
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpawnFood(struct Snake* snake, struct Food* food) {
|
void SpawnFood(struct GameState* game) {
|
||||||
int x, y;
|
int x, y;
|
||||||
int occupied;
|
uint32_t occupied;
|
||||||
|
|
||||||
if (snake->length == SNAKE_MAX_LENGTH) {
|
if (game->snake->length == SNAKE_MAX_LENGTH) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
x = rand() % BOARD_SIZE;
|
x = Random(&game->rngState) % BOARD_SIZE;
|
||||||
y = rand() % BOARD_SIZE;
|
y = Random(&game->rngState) % BOARD_SIZE;
|
||||||
|
|
||||||
occupied = 0;
|
occupied = 0;
|
||||||
|
|
||||||
for (int i = 0; i < snake->length; i++) {
|
for (uint32_t i = 0; i < game->snake->length; i++) {
|
||||||
if (snake->body[i].x == x && snake->body[i].y == y) {
|
if (game->snake->body[i].x == x && game->snake->body[i].y == y) {
|
||||||
occupied = 1;
|
occupied = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (occupied);
|
} while (occupied);
|
||||||
|
|
||||||
food->x = x;
|
game->food->x = x;
|
||||||
food->y = y;
|
game->food->y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddSegment(struct Snake* snake, int x, int y) {
|
void AddSegment(struct Snake* snake, int x, int y) {
|
||||||
@@ -124,7 +254,7 @@ enum CollisionType CheckCollision(struct Snake* snake, struct Food* food) {
|
|||||||
} else if (snake->body[0].x < 0 || snake->body[0].x >= BOARD_SIZE || snake->body[0].y < 0 || snake->body[0].y >= BOARD_SIZE) {
|
} else if (snake->body[0].x < 0 || snake->body[0].x >= BOARD_SIZE || snake->body[0].y < 0 || snake->body[0].y >= BOARD_SIZE) {
|
||||||
return WALL;
|
return WALL;
|
||||||
} else {
|
} else {
|
||||||
for (int i = 1; i < snake->length; i++) {
|
for (uint32_t i = 1; i < snake->length; i++) {
|
||||||
if (snake->body[0].x == snake->body[i].x && snake->body[0].y == snake->body[i].y) {
|
if (snake->body[0].x == snake->body[i].x && snake->body[0].y == snake->body[i].y) {
|
||||||
return SELF;
|
return SELF;
|
||||||
}
|
}
|
||||||
@@ -133,77 +263,95 @@ enum CollisionType CheckCollision(struct Snake* snake, struct Food* food) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrawBoard(struct Snake* snake, struct Food* food) {
|
void DrawBoard(struct GameState* game) {
|
||||||
InitializeBoard();
|
TerminalClear();
|
||||||
|
InitializeBoard(game);
|
||||||
|
|
||||||
if (snake->direction == UP) {
|
if (game->snake->direction == UP) {
|
||||||
board[snake->body[0].y][snake->body[0].x][0] = '^';
|
game->board[game->snake->body[0].y][game->snake->body[0].x][0] = '^';
|
||||||
board[snake->body[0].y][snake->body[0].x][1] = '^';
|
game->board[game->snake->body[0].y][game->snake->body[0].x][1] = '^';
|
||||||
} else if (snake->direction == DOWN) {
|
} else if (game->snake->direction == DOWN) {
|
||||||
board[snake->body[0].y][snake->body[0].x][0] = 'v';
|
game->board[game->snake->body[0].y][game->snake->body[0].x][0] = 'v';
|
||||||
board[snake->body[0].y][snake->body[0].x][1] = 'v';
|
game->board[game->snake->body[0].y][game->snake->body[0].x][1] = 'v';
|
||||||
} else if (snake->direction == LEFT) {
|
} else if (game->snake->direction == LEFT) {
|
||||||
board[snake->body[0].y][snake->body[0].x][0] = '<';
|
game->board[game->snake->body[0].y][game->snake->body[0].x][0] = '<';
|
||||||
board[snake->body[0].y][snake->body[0].x][1] = '<';
|
game->board[game->snake->body[0].y][game->snake->body[0].x][1] = '<';
|
||||||
} else if (snake->direction == RIGHT) {
|
} else if (game->snake->direction == RIGHT) {
|
||||||
board[snake->body[0].y][snake->body[0].x][0] = '>';
|
game->board[game->snake->body[0].y][game->snake->body[0].x][0] = '>';
|
||||||
board[snake->body[0].y][snake->body[0].x][1] = '>';
|
game->board[game->snake->body[0].y][game->snake->body[0].x][1] = '>';
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 1; i < snake->length; i++) {
|
for (uint32_t i = 1; i < game->snake->length; i++) {
|
||||||
board[snake->body[i].y][snake->body[i].x][0] = '[';
|
game->board[game->snake->body[i].y][game->snake->body[i].x][0] = '[';
|
||||||
board[snake->body[i].y][snake->body[i].x][1] = ']';
|
game->board[game->snake->body[i].y][game->snake->body[i].x][1] = ']';
|
||||||
}
|
}
|
||||||
|
|
||||||
board[food->y][food->x][0] = '{';
|
game->board[game->food->y][game->food->x][0] = '{';
|
||||||
board[food->y][food->x][1] = '}';
|
game->board[game->food->y][game->food->x][1] = '}';
|
||||||
|
|
||||||
for (int i = 0; i < BOARD_SIZE + 2; i++) {
|
for (uint32_t i = 0; i < BOARD_SIZE + 2; i++) {
|
||||||
printf("##");
|
TerminalWriteString("##");
|
||||||
}
|
}
|
||||||
printf("\n");
|
TerminalPutChar('\n');
|
||||||
|
|
||||||
for (int i = 0; i < BOARD_SIZE; i++) {
|
for (uint32_t i = 0; i < BOARD_SIZE; i++) {
|
||||||
printf("##");
|
TerminalWriteString("##");
|
||||||
for (int j = 0; j < BOARD_SIZE; j++) {
|
for (uint32_t j = 0; j < BOARD_SIZE; j++) {
|
||||||
printf("%s", board[i][j]);
|
TerminalWriteString(game->board[i][j]);
|
||||||
}
|
}
|
||||||
printf("##\n");
|
TerminalWriteString("##\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < BOARD_SIZE + 2; i++) {
|
for (uint32_t i = 0; i < BOARD_SIZE + 2; i++) {
|
||||||
printf("##");
|
TerminalWriteString("##");
|
||||||
}
|
}
|
||||||
printf("\n");
|
TerminalPutChar('\n');
|
||||||
|
|
||||||
|
TerminalWriteString("Score: ");
|
||||||
|
TerminalWriteUInt(game->score);
|
||||||
|
TerminalPutChar('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayGame(void) {
|
void PlayGame(void) {
|
||||||
InitializeSnake(&snake);
|
struct GameState* game = CreateGame();
|
||||||
InitializeFood(&food);
|
if (!game) {
|
||||||
|
TerminalWriteString("Failed to create game.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char input = 0;
|
||||||
|
struct SnakeSegment tail;
|
||||||
|
enum CollisionType collisionType = NONE;
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
if (snake.length == SNAKE_MAX_LENGTH) {
|
if (game->snake->length == SNAKE_MAX_LENGTH) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SnakeSegment tail = MoveSnake(&snake);
|
input = GetLastKeyPressed();
|
||||||
|
HandleInput(game, input);
|
||||||
|
if (input == 'q') return;
|
||||||
|
tail = MoveSnake(game->snake);
|
||||||
|
|
||||||
collisionType = CheckCollision(&snake, &food);
|
collisionType = CheckCollision(game->snake, game->food);
|
||||||
if (collisionType == FOOD) {
|
if (collisionType == FOOD) {
|
||||||
AddSegment(&snake, tail.x, tail.y);
|
game->score++;
|
||||||
SpawnFood(&snake, &food);
|
PlayFoodSound();
|
||||||
} else if (collisionType == WALL) {
|
AddSegment(game->snake, tail.x, tail.y);
|
||||||
InitializeSnake(&snake);
|
SpawnFood(game);
|
||||||
InitializeFood(&food);
|
} else if (collisionType == WALL || collisionType == SELF) {
|
||||||
} else if (collisionType == SELF) {
|
PlayDeathSound();
|
||||||
InitializeSnake(&snake);
|
ResetGame(game);
|
||||||
InitializeFood(&food);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
collisionType = NONE;
|
collisionType = NONE;
|
||||||
|
|
||||||
DrawBoard(&snake, &food);
|
DrawBoard(game);
|
||||||
|
|
||||||
|
SleepInterrupt(GAME_SPEED_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("You win!\n");
|
TerminalWriteString("You win!\n");
|
||||||
|
PlayWinSound();
|
||||||
|
DestroyGame(game);
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
#include <kernel/gdt.h>
|
#include <kernel/gdt.h>
|
||||||
#include <kernel/terminal.h>
|
#include <kernel/terminal.h>
|
||||||
#include <kernel/io.h>
|
#include <kernel/io.h>
|
||||||
|
#include <kernel/keyboard.h>
|
||||||
|
#include <kernel/pit.h>
|
||||||
|
|
||||||
const size_t VGA_HEIGHT = 25;
|
const size_t VGA_HEIGHT = 25;
|
||||||
const size_t VGA_WIDTH = 80;
|
const size_t VGA_WIDTH = 80;
|
||||||
@@ -21,6 +23,18 @@ uint16_t VgaEntry(unsigned char uc, uint8_t color) {
|
|||||||
return (uint16_t) uc | (uint16_t) color << 8;
|
return (uint16_t) uc | (uint16_t) color << 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TerminalClear(void) {
|
||||||
|
for (size_t y = 0; y < VGA_HEIGHT; y++) {
|
||||||
|
for (size_t x = 0; x < VGA_WIDTH; x++) {
|
||||||
|
TerminalEntryAt(' ', terminal_colour, x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
terminal_row = 0;
|
||||||
|
terminal_column = 0;
|
||||||
|
TerminalUpdateCursor();
|
||||||
|
}
|
||||||
|
|
||||||
void TerminalEntryAt(char c, uint8_t colour, size_t x, size_t y){
|
void TerminalEntryAt(char c, uint8_t colour, size_t x, size_t y){
|
||||||
size_t index = y * VGA_WIDTH + x;
|
size_t index = y * VGA_WIDTH + x;
|
||||||
terminal_buffer[index] = VgaEntry(c, colour);
|
terminal_buffer[index] = VgaEntry(c, colour);
|
||||||
@@ -126,3 +140,15 @@ void TerminalWriteHex(uint32_t num) {
|
|||||||
TerminalPutChar(hexChars[digit]);
|
TerminalPutChar(hexChars[digit]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char TerminalGetChar(void) {
|
||||||
|
while (1) {
|
||||||
|
char key = GetLastKeyPressed();
|
||||||
|
|
||||||
|
if (key != 0) {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
SleepInterrupt(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user