Skip to content

Instantly share code, notes, and snippets.

@TorNATO-PRO
Created April 5, 2022 23:20
Show Gist options
  • Save TorNATO-PRO/aad33370bc0a8dcdbef43bf839c299ec to your computer and use it in GitHub Desktop.
Save TorNATO-PRO/aad33370bc0a8dcdbef43bf839c299ec to your computer and use it in GitHub Desktop.
A snake program I threw together for a cyber security thing.
/**
* @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