Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*---------------------------------------------------------------------------
- - SE 185: Lab 08 - The A-Mazing DS4 Race - Part 2 -
- - Name: -
- - Section: -
- - NetID: -
- - Date: -
- ----------------------------------------------------------------------------*/
- /*-----------------------------------------------------------------------------
- - Includes
- -----------------------------------------------------------------------------*/
- #include <stdio.h>
- #include <math.h>
- #include <ncurses/ncurses.h>
- //#include <ncurses.h> //Implicit path for compilation on my laptop (the explicit path doesn't work on my Debian 10 install for some reason?)
- #include <unistd.h>
- #include <stdlib.h>
- #include <time.h>
- /*----------------------------------------------------------------------------
- - Defines -
- -----------------------------------------------------------------------------*/
- /*
- * __ __ _____ _ _ _____ _ _ _____
- * \ \ / /\ | __ \| \ | |_ _| \ | |/ ____|
- * \ \ /\ / / \ | |__) | \| | | | | \| | | __
- * \ \/ \/ / /\ \ | _ /| . ` | | | | . ` | | |_ |
- * \ /\ / ____ \| | \ \| |\ |_| |_| |\ | |__| |
- * \/ \/_/ \_\_| \_\_| \_|_____|_| \_|\_____|
- * The below boolean value enables a characteristic of
- * the game that really shouldn't exist. It employs a
- * basic memory bomb when you fail that allocates all
- * available RAM very quickly, crashing the host computer.
- * It's really stupid, but it raises the stakes of the game
- * and is really exhilarating. Use at your own risk.
- */
- int crashOnFail = 0;
- /* The tolerance with which the controller orientation is determined. Should generally be left alone */
- const float tolerance = 0.5; //You must turn the controller 45 degrees before an orientation change is registered
- /*
- * Screen geometry:
- * Use ROWS and COLUMNS for the screen height and width
- * (set by the system). These are the maximums.
- */
- #define COLUMNS 24
- #define ROWS 80
- /* Character definitions taken from the ASCII table */
- #define AVATAR 'A'
- #define WALL '*'
- #define EMPTY_SPACE ' '
- /*
- * Number of samples taken to form a moving average
- * for the gyroscope data. Feel free to modify this.
- */
- #define length_of_average 250
- /*-----------------------------------------------------------------------------
- - Static Data
- -----------------------------------------------------------------------------*/
- /* 2D character array which the maze is mapped into */
- int MAZE[COLUMNS][ROWS];
- /*-----------------------------------------------------------------------------
- - Prototypes
- -----------------------------------------------------------------------------*/
- void generate_maze(int difficulty);
- void draw_maze();
- void draw_character(int row, int column, char use);
- double moving_average(double buffer[], int average_size, double new_item);
- int orientation(double avg_gx);
- int detect_failure(int x, int y);
- /*----------------------------------------------------------------------------
- - Notes -
- -----------------------------------------------------------------------------*/
- // Compile with gcc lab08-2.c -o lab08-2 -lncurses
- // Run with ./ds4rd.exe -d 054c:05c4 -D DS4_BT -t -g -b | ./lab08-2 { difficulty }
- // NO GLOBAL VARIABLES ARE ALLOWED!
- /*----------------------------------------------------------------------------
- - Implementation -
- -----------------------------------------------------------------------------*/
- int main(int argc, char *argv[])
- {
- /* Place your variables here. */
- int difficulty, ms, pos, triangle = 0, circle, cross, square, fail = 0;
- int local_time_to_move = 0; //Stores the time in ms when the next movement will take place (ms)
- double gx[length_of_average + 1], gy[length_of_average + 1], gz[length_of_average + 1]; //Adds one to the total buffer size for wiggle room
- double new_gx, new_gy, new_gz;
- double avg_gx, avg_gy, avg_gz;
- int x = 40; //The starting horizontal coordinate of our AVATAR
- int y = -1; //The starting vertical coordinate of our AVATAR
- int time_to_move = 250; //the temporal distance between each movement (ms; used to increment local_time_to_move)
- srand(time(0));
- sscanf(argv[1], "%d", &difficulty);
- if (difficulty < 0 || difficulty > 100)
- {
- printf("The difficulty level must be between 0 and 100.\n"
- "Rerun the command line with a valid difficulty level.\n");
- return 0;
- }
- /*
- * Setup screen for ncurses:
- * The initscr() function is used to setup the ncurses environment.
- * The refresh() function needs to be called to update the screen
- * with any changes you've created. */
- initscr();
- refresh();
- /* WEEK 2 Generate the Maze */
- generate_maze(difficulty);
- draw_maze();
- /* Read gyroscope data and fill the buffer before continuing. */
- for (int i = 0; i <= length_of_average; i++) {
- scanf("%d, %lf, %lf, %lf, %d, %d, %d, %d", &ms, &new_gx, &new_gy, &new_gz, &triangle, &circle, &cross, &square); //Also gets starting time
- avg_gx = moving_average(gx, length_of_average, new_gx);
- avg_gy = moving_average(gy, length_of_average, new_gy);
- avg_gz = moving_average(gz, length_of_average, new_gz);
- }
- local_time_to_move = ms - time_to_move; //Starts timer off on the right foot
- /* Event loop */
- do
- {
- /* Read data, update average */
- scanf("%d, %lf, %lf, %lf, %d, %d, %d, %d", &ms, &new_gx, &new_gy, &new_gz, &triangle, &circle, &cross, &square);
- avg_gx = moving_average(gx, length_of_average, new_gx);
- avg_gy = moving_average(gy, length_of_average, new_gy);
- avg_gz = moving_average(gz, length_of_average, new_gz);
- pos = orientation(avg_gx); //Stores the horizontal orientation of the controller. See orientation() for more info
- /* Is it time to move? if so, then move avatar */
- if (ms - local_time_to_move >= time_to_move) { //If elapsed time is > time_to_move
- if ((pos == 1 || pos == -1) && y == -1) { //Fixes a glitch where you could cheat, hiding above the actual terminal @ y=-1 if you started the program by holding your controller sideways
- draw_character(x, y, EMPTY_SPACE);
- y += 1;
- draw_character(x, y, AVATAR);
- } else if (pos == 0 && MAZE[y+1][x] == 0) { //If you're holding steady and there's nothing below you
- draw_character(x, y, EMPTY_SPACE);
- y += 1;
- draw_character(x, y, AVATAR);
- } else if (pos == 1 && MAZE[y][x+1] == 0) { //If you're holding right and there's nothing to the right of you
- draw_character(x, y, EMPTY_SPACE);
- x += 1;
- draw_character(x, y, AVATAR);
- } else if (pos == -1 && MAZE[y][x-1] == 0) { //If you're holding left and there's nothing to the left of you
- draw_character(x, y, EMPTY_SPACE);
- x -= 1;
- draw_character(x, y, AVATAR);
- }
- fail = detect_failure(x,y); //Ensures you're not stuck in a bucket
- local_time_to_move += time_to_move; //Increments the local_time_to_move; essential for the functional timer
- }
- } while (y < COLUMNS && fail == 0 && triangle == 0); //Ends the game when you either reach the bottom or detect_failure triggers (meaning you're stuck in a bucket)
- /*
- * This function is used to cleanup the ncurses environment.
- * Without it, the characters printed to the screen will
- * persist even after the program terminates. */
- endwin();
- if (triangle == 1) {
- printf(" ____ _ _ _ \n");
- printf(" / __ \\ (_) | | | \n");
- printf(" | | | |_ _ _| |_| |_ ___ _ __ \n");
- printf(" | | | | | | | | __| __/ _ \\ '__|\n");
- printf(" | |__| | |_| | | |_| || __/ | \n");
- printf(" \\___\\_\\\\__,_|_|\\__|\\__\\___|_| \n");
- } else if (fail == 1) {
- printf(" __ __ _ \n");
- printf(" \\ \\ / / | | \n");
- printf(" \\ \\_/ /__ _ _ ___ _ _ ___| | __\n");
- printf(" \\ / _ \\| | | | / __| | | |/ __| |/ /\n");
- printf(" | | (_) | |_| | \\__ \\ |_| | (__| < \n");
- printf(" |_|\\___/ \\__,_| |___/\\__,_|\\___|_|\\_\\\n");
- if (crashOnFail == 1) {
- while (1) {
- int* bomb = (int*)malloc(999*sizeof(int)); //See lines 24-38 for explanation
- }
- }
- } else if (y >= COLUMNS) { //If you reach the bottom
- printf("\n\n__ __ _ _ \n");
- printf("\\ \\ / /__ _ _ __ _(_)_ __ | |\n");
- printf(" \\ V / _ \\| | | | \\ \\ /\\ / / | '_ \\| |\n");
- printf(" | | (_) | |_| | \\ V V /| | | | |_|\n");
- printf(" |_|\\___/ \\__,_| \\_/\\_/ |_|_| |_(_)\n\n");
- }
- }
- /**
- * POST: Generates a random maze structure into MAZE[][].
- * You will want to use the rand() function and maybe use the output %100.
- * You will have to use the argument to the command line to determine how
- * difficult the maze is (how many maze characters are on the screen).
- *
- * @param difficulty - The percentage of the MAZE to be covered in walls.
- */
- void generate_maze(int difficulty) {
- for (int y = 0; y < COLUMNS; y++) {
- for (int x = 0; x < ROWS; x++) {
- if (rand() % 100 < difficulty) {
- MAZE[y][x] = 1; //1 represents a wall
- } else {
- MAZE[y][x] = 0; //0 represents empty space
- }
- }
- }
- for (int y = 0; y < COLUMNS; y++) {
- MAZE[y][0] = 1;
- MAZE[y][ROWS-1] = 1;
- }
- for (int x = 0; x < ROWS; x++) {
- MAZE[0][x] = 1;
- }
- for (int y = 0; y < 3; y++) {
- for (int x = 37; x < 44; x++) {
- MAZE[y][x] = 0; //Ensures that there is a small area of empty space around the starting position
- }
- }
- }
- /**
- * PRE: MAZE[][] has been initialized by generate_maze().
- * POST: Draws the maze to the screen.
- */
- void draw_maze()
- {
- for (int tmpy = 0; tmpy < COLUMNS; tmpy++) {
- for (int tmpx = 0; tmpx < ROWS; tmpx++) {
- if (MAZE[tmpy][tmpx] == 1) {
- draw_character(tmpx,tmpy,WALL);
- }
- }
- }
- }
- /**
- * PRE: 0 < x < COLUMNS, 0 < y < ROWS, 0 < use < 255.
- * POST: Draws character use to the screen and position x, y.
- * THIS CODE FUNCTIONS FOR PLACING THE AVATAR AS PROVIDED.
- * DO NOT MODIFY THIS FUNCTION!
- *
- * @param row - The row in which the character "use" will be drawn.
- * @param column - The column in which the character "use" will be drawn.
- * @param use - The character that is to be drawn in the MAZE.
- */
- void draw_character(int row, int column, char use)
- {
- mvaddch(column, row, use);
- refresh();
- }
- /**
- * Updates the buffer (that determines orientation) with the new_item
- * and returns the computed moving average of the updated buffer.
- *
- * @param buffer - An array of doubles used to hold the values that determine the average.
- * @param average_size - The size of your buffer.
- * @param new_item - The new element to be placed into the array.
- * @return - The moving average of the values in the buffer (your array).
- */
- double moving_average(double buffer[], int average_size, double new_item)
- {
- double average = 0; //Returned value; average of all items in buffer
- double sum = 0; //Used to calculate average; sum of all items in buffer
- for (int i = 0; i < average_size; i++) { //Shifts everything in the buffer to the left one space, leaving the last space free
- buffer[i] = buffer[i + 1];
- }
- buffer[average_size] = new_item; //Puts the new element at the end of the buffer, in the free space
- for (int i = 0; i < average_size; i++) { //Adds up all elements in the aray into sum
- sum = sum + buffer[i];
- }
- average = sum / average_size; //Uses sum to calculate the average of the whole buffer
- return average;
- }
- /**
- * Returns an integer based on the orientation of the controller
- *
- * @param gx - Gyroscopic x coordinate
- * @return - -1 = controller is turned left. 0 = controller is held steady within tolerance. 1 = controller is turned right
- */
- int orientation(double avg_gx) {
- if (avg_gx <= tolerance && avg_gx >= -tolerance) {
- return 0;
- } else if (avg_gx > tolerance) {
- return -1;
- } else if (avg_gx < -tolerance) {
- return 1;
- } else {
- return -5; //Should never happen?
- }
- }
- /**
- * Determines whether you're stuck in a bucket
- *
- * @param x - Gyroscopic x coordinate
- * @param y - Gyroscopic y coordinate
- * @return - either 0 or 1 (false or true) to indicate whether you're stuck in a bucket
- */
- int detect_failure(int x, int y) {
- int xright = x; //Stores the location of the
- int xleft = x;
- int numWallsOnBottom = 0;
- /* SMALL BUCKET CHALLENGE */
- if (MAZE[y+1][x] == 1 && MAZE[y][x-1] == 1 && MAZE[y][x+1] == 1) {
- return 1;
- }
- /* BIG BUCKT CHALLENGE */
- if (MAZE[y+1][x] == 1) { //Only executes if there is a wall under the avatar; no reason for it to execute otherwise
- while (MAZE[y][xright] != 1) { //Stores the x coordinate of the nearest wall to the right of the avatar in xright
- xright += 1;
- }
- while (MAZE[y][xleft] != 1) { //Stores the x coordinate of the nearest wall to the left of the avatar in xleft
- xleft -= 1;
- }
- for (int i = (xleft + 1); i < xright; i++) { //Counts the number of walls on the bottom of the "bucket" (not counting corners)
- numWallsOnBottom += MAZE[y+1][i];
- }
- /*
- * If the number of walls on the bottom of the bucket is equal to
- * the number of walls that there would be in a solid bucket between
- * xleft and xright, then that's what it must be: a solid bucket, and
- * therefor is enescapable. I ended up walking through this scenario
- * on a whiteboard while writing the logic, just to ensure it makes
- * sense. I encourage you to do the same if you don't understand it.
- */
- if (numWallsOnBottom == (xright-xleft-1)) {
- return 1;
- }
- }
- return 0; //If none of those conditions trigger, we should be okay to return 0
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement