Created
April 5, 2022 23:20
-
-
Save TorNATO-PRO/aad33370bc0a8dcdbef43bf839c299ec to your computer and use it in GitHub Desktop.
A snake program I threw together for a cyber security thing.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @file main.c | |
* | |
* @author Nathan Waltz (nathan.waltz@wsu.edu) | |
* @brief A snake game to demonstrate a covert channel. | |
* @version 0.1 | |
* @date 2022-04-05 | |
* | |
* @copyright Copyright (c) 2022 | |
* | |
*/ | |
#include <tice.h> | |
#include <keypadc.h> | |
#include <graphx.h> | |
#include <time.h> | |
#define SNAKE_SIZE 5 | |
#define FOOD_SIZE SNAKE_SIZE | |
#define UPDATE_FREQUENCY 6 | |
#define SNAKE_MOVEMENT_INCREMENT SNAKE_SIZE | |
#define MESSAGE_LENGTH 43 | |
#define SCREEN_UPDATE_FREQUENCY (UPDATE_FREQUENCY / 3) | |
#define SCOREBOARD_HEIGHT 10 | |
/** | |
* @brief The directions that we can go. | |
* | |
* Define the potential directions that the | |
* snake can move. | |
*/ | |
typedef enum | |
{ | |
LEFT = 0x00, | |
RIGHT = 0x01, | |
UP = 0x02, | |
DOWN = 0x03, | |
NONE = 0x04 | |
} turn_direction; | |
/** | |
* @brief Our snake's data structure | |
* | |
* Defines a data structure for the snake, | |
* this will define all of the snake's X and Y coordinates | |
* | |
*/ | |
typedef struct node | |
{ | |
int x; | |
int y; | |
struct node *tail; | |
} snake_node; | |
typedef struct food | |
{ | |
int x; | |
int y; | |
} food_struct; | |
/* Function Prototypes */ | |
void DrawScoreboard(int score, float time); | |
void DrawSnake(snake_node *head); | |
void DrawSquare(int x, int y, int size); | |
void FreeSnake(snake_node *head); | |
snake_node *InitializeSnake(); | |
food_struct *InitializeFood(); | |
bool LostGame(snake_node *the_snake); | |
snake_node *MoveSnake(snake_node *head, int dx, int dy); | |
snake_node *PopLast(snake_node *head); | |
void PrintBoundedInteger(int num); | |
/* The heart of our program */ | |
int main(void) | |
{ | |
/* Variables */ | |
kb_key_t key; | |
int score = 0; | |
int dx = 0, dy = 0; | |
int i = 0; | |
turn_direction direction = NONE; | |
uint8_t colors[2] = {0x30, 0x28}; | |
char message[] = "The game sucks, it will be released in May"; | |
/* Initialize snake and food */ | |
snake_node *the_snake = InitializeSnake(); | |
food_struct *food = InitializeFood(); | |
if (the_snake == NULL || food == NULL) | |
{ | |
return 1; | |
} | |
/* Initialize graphics drawing */ | |
gfx_Begin(); | |
/* Draw to buffer to avoid tearing */ | |
gfx_SetDrawBuffer(); | |
/* Record the start time */ | |
clock_t start = clock(); | |
/* Loop until 2nd is pressed */ | |
do | |
{ | |
/* Update kb_Data */ | |
kb_Scan(); | |
/* Get current time */ | |
clock_t now = clock(); | |
float time = (float)(now - start) / CLOCKS_PER_SEC; | |
int elapsed = (int)UPDATE_FREQUENCY * time; | |
int arrIndex = (int)(time / 8) % MESSAGE_LENGTH; | |
int bitIndex = (int)time % 8; | |
int index = (message[arrIndex] & (bitIndex)) > 0; | |
/* Color the screen */ | |
gfx_FillScreen(colors[index]); | |
/* Draw the scoreboard */ | |
DrawScoreboard(score, time); | |
/* draw the snake */ | |
gfx_SetColor(0xD8); | |
DrawSnake(the_snake); | |
gfx_SetColor(0x37); | |
DrawSquare(food->x, food->y, FOOD_SIZE); | |
if (elapsed > i) | |
{ | |
/* Load group 7 registers */ | |
key = kb_Data[7]; | |
if (key) | |
{ | |
switch (key) | |
{ | |
case kb_Down: | |
if (direction != UP) | |
{ | |
dx = 0; | |
dy = SNAKE_MOVEMENT_INCREMENT; | |
direction = DOWN; | |
} | |
break; | |
case kb_Right: | |
if (direction != LEFT) | |
{ | |
dx = SNAKE_MOVEMENT_INCREMENT; | |
dy = 0; | |
direction = RIGHT; | |
} | |
break; | |
case kb_Up: | |
if (direction != DOWN) | |
{ | |
dx = 0; | |
dy = -SNAKE_MOVEMENT_INCREMENT; | |
direction = UP; | |
} | |
break; | |
case kb_Left: | |
if (direction != RIGHT) | |
{ | |
dx = -SNAKE_MOVEMENT_INCREMENT; | |
dy = 0; | |
direction = LEFT; | |
} | |
break; | |
default: | |
break; | |
} | |
} | |
if (dx != 0 || dy != 0) | |
{ | |
the_snake = MoveSnake(the_snake, dx, dy); | |
if (the_snake->x == food->x && the_snake->y == food->y) | |
{ | |
free(food); | |
food = InitializeFood(); | |
score += 10; | |
} | |
else | |
{ | |
PopLast(the_snake); | |
} | |
} | |
if (LostGame(the_snake)) | |
{ | |
/* Free the current snake */ | |
FreeSnake(the_snake); | |
/* Initialize snake and food */ | |
the_snake = InitializeSnake(); | |
if (the_snake == NULL) | |
{ | |
return 1; | |
} | |
free(food); | |
food = InitializeFood(); | |
dx = 0; | |
dy = 0; | |
} | |
/* Update i */ | |
i = elapsed; | |
} | |
/* Blit buffer */ | |
gfx_BlitBuffer(); | |
} while (kb_Data[6] != kb_Clear & kb_Data[6] != kb_Enter); | |
/* End graphics drawing */ | |
gfx_End(); | |
/* Free the allocations */ | |
FreeSnake(the_snake); | |
return 0; | |
} | |
/** | |
* @brief Draws the scoreboard. | |
* | |
* @param score The game's current score. | |
* @param time The game's current time. | |
*/ | |
void DrawScoreboard(int score, float time) | |
{ | |
/* Define the top */ | |
gfx_SetColor(0x00); | |
gfx_FillRectangle(0, 0, LCD_WIDTH, SCOREBOARD_HEIGHT); | |
/* Display the current time */ | |
gfx_SetTextFGColor(0xDF); | |
gfx_SetTextXY(0, 0); | |
PrintBoundedInteger((int)time); | |
/* Display the score */ | |
gfx_SetTextFGColor(0xDF); | |
gfx_SetTextXY(LCD_WIDTH - gfx_GetStringWidth("Score: 9999"), 0); | |
gfx_PrintString("Score:"); | |
gfx_SetTextXY(LCD_WIDTH - gfx_GetStringWidth("9999"), 0); | |
PrintBoundedInteger(score); | |
} | |
/** | |
* @brief A utility function to print bounded integers. | |
* | |
* @param num The integer to print. | |
*/ | |
void PrintBoundedInteger(int num) | |
{ | |
if (num > 9999) | |
{ | |
// handle edge case | |
gfx_PrintInt(9999, 4); | |
} | |
else | |
{ | |
gfx_PrintInt(num, 4); | |
} | |
} | |
/** | |
* @brief Initializes the food to some random index. | |
* | |
* @return food_struct* The struct that contains information on the food. | |
*/ | |
food_struct *InitializeFood() | |
{ | |
food_struct *food = malloc(sizeof(food_struct)); | |
srand(rtc_Time()); | |
food->x = randInt(0, (LCD_WIDTH / SNAKE_MOVEMENT_INCREMENT) - SNAKE_MOVEMENT_INCREMENT) * SNAKE_MOVEMENT_INCREMENT; | |
food->y = randInt(SCOREBOARD_HEIGHT, (LCD_HEIGHT / SNAKE_MOVEMENT_INCREMENT) - SNAKE_MOVEMENT_INCREMENT) * SNAKE_MOVEMENT_INCREMENT; | |
return food; | |
} | |
/** | |
* @brief Moves the snake to a given location. | |
* | |
* @param head The head of the snake. | |
* @param dx The amount we wish to move the snake by on the x-axis. | |
* @param dy The amount we wish to move the snake by on the y-axis. | |
* @return snake_node* A moved snake. | |
*/ | |
snake_node *MoveSnake(snake_node *head, int dx, int dy) | |
{ | |
int x = head->x + dx; | |
int y = head->y + dy; | |
snake_node *temp = malloc(sizeof(snake_node)); | |
/* Check for problem with allocation */ | |
if (temp == NULL) | |
{ | |
return NULL; | |
} | |
/* Initialize new values */ | |
temp->x = x; | |
temp->y = y; | |
temp->tail = head; | |
return temp; | |
} | |
/** | |
* @brief Pops the last value from the LinkedList. | |
* | |
* @param head The head of the snake. | |
* @return snake_node* The list with the last value popped. | |
*/ | |
snake_node *PopLast(snake_node *head) | |
{ | |
/* Capture base cases */ | |
if (head == NULL) | |
{ | |
return NULL; | |
} | |
else if (head->tail == NULL) | |
{ | |
free(head); | |
return NULL; | |
} | |
snake_node *temp = head; | |
while (temp->tail->tail) | |
{ | |
temp = temp->tail; | |
} | |
snake_node *freeNode = temp->tail; | |
temp->tail = NULL; | |
free(freeNode); | |
return head; | |
} | |
/** | |
* @brief Initializes the snake. | |
* | |
* @return snake_node* A pointer to the snake node. | |
*/ | |
snake_node *InitializeSnake() | |
{ | |
/* Allocate the memory for the snake */ | |
snake_node *the_snake = malloc(sizeof(snake_node)); | |
/* Check for problem with allocation */ | |
if (the_snake == NULL) | |
{ | |
return NULL; | |
} | |
the_snake->x = (LCD_WIDTH / 2) - SNAKE_SIZE; | |
the_snake->y = (LCD_HEIGHT / 2) - SNAKE_SIZE; | |
the_snake->tail = NULL; | |
return the_snake; | |
} | |
/** | |
* @brief Checks if the player lost a game. | |
* | |
* @param the_snake The snake object. | |
* @return true They lost the game. | |
* @return false They haven't lost yet. | |
*/ | |
bool LostGame(snake_node *the_snake) | |
{ | |
/* Check for null pointer */ | |
if (the_snake == NULL) | |
{ | |
return true; | |
} | |
int head_x = the_snake->x; | |
int head_y = the_snake->y; | |
snake_node *temp = the_snake->tail; | |
while (temp) | |
{ | |
if (temp->x == head_x && temp->y == head_y) | |
{ | |
return true; | |
} | |
temp = temp->tail; | |
} | |
return the_snake->x < 0 || the_snake->x > LCD_WIDTH - SNAKE_SIZE || the_snake->y < SCOREBOARD_HEIGHT || the_snake->y > LCD_HEIGHT - SNAKE_SIZE; | |
} | |
/** | |
* @brief Draws a square to the screen. | |
* | |
* Draws a square to the screen at the specified | |
* x and y locations, with a given size. | |
* | |
* @param x The x-coordinate to draw the square. | |
* @param y The y-coordinate to draw the square. | |
* @param size The size of the square (i.e. the width and the height). | |
*/ | |
void DrawSquare(int x, int y, int size) | |
{ | |
gfx_FillRectangle(x, | |
y, | |
size, | |
size); | |
} | |
/** | |
* @brief Draws the snake to the screen. | |
* | |
* @param head | |
*/ | |
void DrawSnake(snake_node *head) | |
{ | |
struct node *current = head; | |
while (current) | |
{ | |
struct node *temp = current; | |
current = current->tail; | |
DrawSquare(temp->x, temp->y, SNAKE_SIZE); | |
} | |
} | |
/** | |
* @brief Frees the snake. | |
* | |
* @param head The head of the snake. | |
*/ | |
void FreeSnake(snake_node *head) | |
{ | |
struct node *current = head; | |
while (current) | |
{ | |
struct node *temp = current; | |
current = current->tail; | |
free(temp); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment