ECE 2036 Project

Dependencies:   mbed wave_player 4DGL-uLCD-SE

Files at this revision

API Documentation at this revision

Comitter:
abraha2d
Date:
Thu Nov 21 16:10:57 2019 +0000
Parent:
1:c18c231cb299
Commit message:
Because other peeps is wanting dis...

Changed in this revision

Speaker.h Show annotated file Show diff for this revision Revisions of this file
doublely_linked_list.cpp Show annotated file Show diff for this revision Revisions of this file
game.cpp Show annotated file Show diff for this revision Revisions of this file
game.h Show annotated file Show diff for this revision Revisions of this file
globals.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
physics.cpp Show annotated file Show diff for this revision Revisions of this file
physics.h Show annotated file Show diff for this revision Revisions of this file
wall.cpp Show annotated file Show diff for this revision Revisions of this file
wall.h Show annotated file Show diff for this revision Revisions of this file
diff -r c18c231cb299 -r 2042f29de6b7 Speaker.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Speaker.h	Thu Nov 21 16:10:57 2019 +0000
@@ -0,0 +1,52 @@
+class Speaker
+{
+public:
+    Speaker(PinName pin) : _pin(pin) {
+// _pin(pin) means pass pin to the Speaker Constructor
+// precompute 32 sample points on one sine wave cycle
+// used for continuous sine wave output later
+        for(int k=0; k<32; k++) {
+            Analog_out_data[k] = int (65536.0 * ((1.0 + sin((float(k)/32.0*6.28318530717959)))/2.0));
+            // scale the sine wave to 16-bits - as needed for AnalogOut write_u16 arg
+        }
+
+    }
+// class method to play a note based on AnalogOut class
+    void PlayNote(float frequency, float duration, float volume) {
+        // scale samples using current volume level arg
+        for(int k=0; k<32; k++) {
+            Analog_scaled_data[k] = Analog_out_data[k] * volume;
+        }
+        // reset to start of sample array
+        i=0;
+        // turn on timer interrupts to start sine wave output
+        Sample_Period.attach(this, &Speaker::Sample_timer_interrupt, 1.0/(frequency*32.0));
+        // play note for specified time
+        wait(duration);
+        // turns off timer interrupts
+        Sample_Period.detach();
+        // sets output to mid range - analog zero
+        this->_pin.write_u16(32768);
+
+    }
+private:
+// sets up specified pin for analog using AnalogOut class
+    AnalogOut _pin;
+    // set up a timer to be used for sample rate interrupts
+    Ticker Sample_Period;
+
+    //variables used by interrupt routine and PlayNote
+    volatile int i;
+    short unsigned Analog_out_data[32];
+    short unsigned Analog_scaled_data[32];
+
+// Interrupt routine
+// used to output next analog sample whenever a timer interrupt occurs
+    void Sample_timer_interrupt(void) {
+        // send next analog sample out to D to A
+        this->_pin.write_u16(Analog_scaled_data[i]);
+        // increment pointer and wrap around back to 0 at 32
+        i = (i+1) & 0x01F;
+    }
+};
+
diff -r c18c231cb299 -r 2042f29de6b7 doublely_linked_list.cpp
--- a/doublely_linked_list.cpp	Wed Nov 08 21:01:43 2017 +0000
+++ b/doublely_linked_list.cpp	Thu Nov 21 16:10:57 2019 +0000
@@ -2,147 +2,396 @@
 #include <stdio.h>
 #include "doublely_linked_list.h"
 
-DLinkedList* create_dlinkedlist(void) {
-    DLinkedList* newList = (DLinkedList*)malloc(sizeof(DLinkedList));
+DLinkedList* create_dlinkedlist(void)
+{
+
+//    printf("create_dlinkedlist\n");
+
+    DLinkedList* newList = (DLinkedList*) malloc(sizeof(DLinkedList));
+
+    newList->size = 0;
     newList->head = NULL;
+    newList->current = NULL;
     newList->tail = NULL;
-    newList->current = NULL;
-    newList->size = 0;
+
     return newList;
+
 }
 
-LLNode* create_llnode(void* data) {
+LLNode* create_llnode(void* data)
+{
+
+//    printf("create_llnode\n");
+
+    LLNode* newNode = (LLNode*) malloc(sizeof(LLNode));
+
+    newNode->previous = NULL;
+    newNode->next = NULL;
+    newNode->data = data;
+
+    return newNode;
+
+}
+
+
+void insertHead(DLinkedList* dLinkedList, void* data)
+{
 
-    // Your code here
-    return NULL;
+//    printf("insertHead\n");
+
+    LLNode* newNode = create_llnode(data);
+
+    if (dLinkedList->head == NULL) {
+
+        dLinkedList->size++;
+        dLinkedList->head = newNode;
+        dLinkedList->tail = newNode;
+
+    } else {
+
+        dLinkedList->size++;
+        newNode->next = dLinkedList->head;
+        (dLinkedList->head)->previous = newNode;
+        dLinkedList->head = newNode;
+
+    }
 
 }
 
 
-void insertHead(DLinkedList* dLinkedList, void* data){
-  LLNode* newNode = create_llnode(data);
-  if(dLinkedList->head == NULL){
-    dLinkedList->size++;
-    dLinkedList->head = newNode;
-    dLinkedList->tail = newNode;
-  }else{
-    dLinkedList->size++;
-    newNode->next = dLinkedList->head;
-    (dLinkedList->head)->previous = newNode;
-    dLinkedList->head = newNode;
-  }
-}
+void insertTail(DLinkedList* dLinkedList, void* data)
+{
+
+//    printf("insertTail\n");
+
+    LLNode* newNode = create_llnode(data);
+
+    if (dLinkedList->tail == NULL) {
 
+        dLinkedList->size++;
+        dLinkedList->tail = newNode;
+        dLinkedList->head = newNode;
 
-void insertTail(DLinkedList* dLinkedList, void* data){
+    } else {
 
-    // Your code here
+        dLinkedList->size++;
+        newNode->previous = dLinkedList->tail;
+        (dLinkedList->tail)->next = newNode;
+        dLinkedList->tail = newNode;
+
+    }
 
 }
 
-int insertAfter(DLinkedList* dLinkedList, void* newData){
+int insertAfter(DLinkedList* dLinkedList, void* newData)
+{
+
+//    printf("insertAfter\n");
+
+    if (dLinkedList->current == NULL) {
+        return 0;
+    }
+
+    LLNode* newNode = create_llnode(newData);
 
-    // Your code here
-    return 0;
+    dLinkedList->size++;
+    newNode->next = (dLinkedList->current)->next;
+    newNode->previous = dLinkedList->current;
+    if (newNode->next == NULL) {
+        dLinkedList->tail = newNode;
+    } else {
+        (newNode->next)->previous = newNode;
+    }
+    (newNode->previous)->next = newNode;
+
+    return 1;
 
 }
 
-int insertBefore(DLinkedList* dLinkedList, void* newData){
+int insertBefore(DLinkedList* dLinkedList, void* newData)
+{
+
+//    printf("insertBefore\n");
+
+    if (dLinkedList->current == NULL) {
+        return 0;
+    }
+
+    LLNode* newNode = create_llnode(newData);
 
-    // Your code here
-    return 0;
+    dLinkedList->size++;
+    newNode->next = dLinkedList->current;
+    newNode->previous = (dLinkedList->current)->previous;
+    (newNode->next)->previous = newNode;
+    if (newNode->previous == NULL) {
+        dLinkedList->head = newNode;
+    } else {
+        (newNode->previous)->next = newNode;
+    }
+
+    return 1;
 
 }
 
 
-void* deleteBackward(DLinkedList* dLinkedList){
+void* deleteBackward(DLinkedList* dLinkedList)
+{
+
+//    printf("deleteBackward\n");
+
+    if (dLinkedList->current == NULL) {
+        return NULL;
+    }
+
+    dLinkedList->size--;
+
+    free((dLinkedList->current)->data);
 
-    //Your code here.
-    return NULL;
+    if ((dLinkedList->current)->previous == NULL) {
+        dLinkedList->head = (dLinkedList->current)->next;
+    } else {
+        ((dLinkedList->current)->previous)->next = (dLinkedList->current)->next;
+    }
+
+    if ((dLinkedList->current)->next == NULL) {
+        dLinkedList->tail = (dLinkedList->current)->previous;
+    } else {
+        ((dLinkedList->current)->next)->previous = (dLinkedList->current)->previous;
+    }
+
+    LLNode* newCurrent = (dLinkedList->current)->previous;
+
+    free(dLinkedList->current);
+    dLinkedList->current = newCurrent;
+
+    if (dLinkedList->current == NULL) {
+        return NULL;
+    }
+
+    return (dLinkedList->current)->data;
 
 }
 
 
 
-void* deleteForward(DLinkedList* dLinkedList){
+void* deleteForward(DLinkedList* dLinkedList)
+{
+
+//    printf("deleteForward\n");
+
+    if (dLinkedList->current == NULL) {
+        return NULL;
+    }
+
+    dLinkedList->size--;
+
+    free((dLinkedList->current)->data);
 
-    //Your code here.
-    return NULL;
+    if ((dLinkedList->current)->previous == NULL) {
+        dLinkedList->head = (dLinkedList->current)->next;
+    } else {
+        ((dLinkedList->current)->previous)->next = (dLinkedList->current)->next;
+    }
+
+    if ((dLinkedList->current)->next == NULL) {
+        dLinkedList->tail = (dLinkedList->current)->previous;
+    } else {
+        ((dLinkedList->current)->next)->previous = (dLinkedList->current)->previous;
+    }
+
+    LLNode* newCurrent = (dLinkedList->current)->next;
+
+    free(dLinkedList->current);
+    dLinkedList->current = newCurrent;
+
+    if (dLinkedList->current == NULL) {
+        return NULL;
+    }
+
+    return (dLinkedList->current)->data;
 
 }
 
 
-void* removeBackward(DLinkedList* dLinkedList){
+void* removeBackward(DLinkedList* dLinkedList)
+{
+
+//    printf("removeBackward\n");
+
+    if (dLinkedList->current == NULL) {
+        return NULL;
+    }
+
+    dLinkedList->size--;
 
-    //Your code here.
-    return NULL;
+    if ((dLinkedList->current)->previous == NULL) {
+        dLinkedList->head = (dLinkedList->current)->next;
+    } else {
+        ((dLinkedList->current)->previous)->next = (dLinkedList->current)->next;
+    }
+
+    if ((dLinkedList->current)->next == NULL) {
+        dLinkedList->tail = (dLinkedList->current)->previous;
+    } else {
+        ((dLinkedList->current)->next)->previous = (dLinkedList->current)->previous;
+    }
+
+    void* oldData = (dLinkedList->current)->data;
+
+    LLNode* newCurrent = (dLinkedList->current)->previous;
+
+    free(dLinkedList->current);
+    dLinkedList->current = newCurrent;
+
+    return oldData;
 
 }
 
-void* removeForward(DLinkedList* dLinkedList){
+void* removeForward(DLinkedList* dLinkedList)
+{
+
+//    printf("removeForward\n");
+
+    if (dLinkedList->current == NULL) {
+        return NULL;
+    }
+
+    dLinkedList->size--;
 
-    //Your code here.
-    return NULL;
+    if ((dLinkedList->current)->previous == NULL) {
+        dLinkedList->head = (dLinkedList->current)->next;
+    } else {
+        ((dLinkedList->current)->previous)->next = (dLinkedList->current)->next;
+    }
+
+    if ((dLinkedList->current)->next == NULL) {
+        dLinkedList->tail = (dLinkedList->current)->previous;
+    } else {
+        ((dLinkedList->current)->next)->previous = (dLinkedList->current)->previous;
+    }
+
+    void* oldData = (dLinkedList->current)->data;
+
+    LLNode* newCurrent = (dLinkedList->current)->next;
+
+    free(dLinkedList->current);
+    dLinkedList->current = newCurrent;
+
+    return oldData;
 
 }
 
 
-void destroyList(DLinkedList* dLinkedList){
-  if(dLinkedList->head != NULL){
-    getHead(dLinkedList);
-    while(deleteForward(dLinkedList)){};
-  }
-  free(dLinkedList);
+void destroyList(DLinkedList* dLinkedList)
+{
+
+//    printf("destroyList\n");
+
+    if (dLinkedList->head != NULL) {
+        getHead(dLinkedList);
+        while(deleteForward(dLinkedList)) {};
+    }
+
+    free(dLinkedList);
+
 }
 
 
-void* getHead(DLinkedList* dLinkedList){
+void* getHead(DLinkedList* dLinkedList)
+{
+
+//    printf("getHead\n");
 
-    //Your code here.
-    return NULL;
+    dLinkedList->current = dLinkedList->head;
+
+    if (dLinkedList->head == NULL) {
+        return NULL;
+    }
+
+    return (dLinkedList->head)->data;
 
 }
 
 
 
-void* getTail(DLinkedList* dLinkedList){
+void* getTail(DLinkedList* dLinkedList)
+{
+
+//    printf("getTail\n");
+
+    dLinkedList->current = dLinkedList->tail;
 
-    //Your code here.
+    if (dLinkedList->tail == NULL) {
+        return NULL;
+    }
 
-    return NULL;
+    return (dLinkedList->tail)->data;
+
 }
 
 
 
-void* getCurrent(DLinkedList* dLinkedList){
+void* getCurrent(DLinkedList* dLinkedList)
+{
+
+//    printf("getCurrent\n");
 
-    //Your code here.
-    return NULL;
+    if (dLinkedList->current == NULL) {
+        return NULL;
+    }
+
+    return (dLinkedList->current)->data;
 
 }
 
 
 
-void* getNext(DLinkedList* dLinkedList){
+void* getNext(DLinkedList* dLinkedList)
+{
+
+//    printf("getNext\n");
+
+    if (dLinkedList->current == NULL) {
+        return NULL;
+    }
 
-    //Your code here.
+    dLinkedList->current = (dLinkedList->current)->next;
 
-    return NULL;
+    if (dLinkedList->current == NULL) {
+        return NULL;
+    }
+
+    return (dLinkedList->current)->data;
+
 }
 
 
 
-void* getPrevious(DLinkedList* dLinkedList){
+void* getPrevious(DLinkedList* dLinkedList)
+{
+
+//    printf("getPrevious\n");
+
+    if (dLinkedList->current == NULL) {
+        return NULL;
+    }
 
-    //Your code here.
+    dLinkedList->current = (dLinkedList->current)->previous;
 
-    return NULL;
+    if (dLinkedList->current == NULL) {
+        return NULL;
+    }
+
+    return (dLinkedList->current)->data;
+
 }
 
 
-int getSize(DLinkedList* dLinkedList){
+int getSize(DLinkedList* dLinkedList)
+{
 
-    //Your code here.
-    return 0;
+//    printf("getSize\n");
+
+    return dLinkedList->size;
 
 }
\ No newline at end of file
diff -r c18c231cb299 -r 2042f29de6b7 game.cpp
--- a/game.cpp	Wed Nov 08 21:01:43 2017 +0000
+++ b/game.cpp	Thu Nov 21 16:10:57 2019 +0000
@@ -8,14 +8,64 @@
 /** Erases the ball from the screen by drawing over it with the background color. */
 void erase_ball(Ball* ball)
 {
-    // TODO: Draw background color over curriously drawn ball location
+    // Draw background color over previously drawn ball location
+    uLCD.filled_circle(ball->x, ball->y, radius, BLACK);
 }
 
 /** Draws the ball on the screen at the updated location (according to the state) */
 void draw_ball(Ball* ball, Physics* state)
 {
-    // TODO: Save that updated ball position for later erasing
-    // TODO: Draw ball in its updated location
+    // Draw ball in its updated location
+    uLCD.filled_circle(state->px, state->py, radius, WHITE);
+    // Save that updated ball position for later erasing
+    ball->x = state->px;
+    ball->y = state->py;
+}
+
+/** Draws a hole on the screen */
+void draw_hole(Hole* hole)
+{
+    if (hole->should_draw) {
+        // Draw hole in its location
+        uLCD.filled_circle(hole->x, hole->y, radius - 1, RED);
+        hole->should_draw = 0;
+    }
+}
+
+/** Checks whether the ball has hit a hole */
+int do_hole(Hole* hole, Physics* curr)
+{
+    double dist = sqrt(pow(curr->px - hole->x, 2) + pow(curr->py - hole->y, 2));
+    if (dist < radius * 2) {
+        hole->should_draw = 1;
+    }
+    if (dist < radius) {
+        return 2;
+    }
+    return 0;
+}
+
+/** Draws the goal on the screen */
+void draw_goal(Goal* goal)
+{
+    if (goal->should_draw) {
+        // Draw goal in its location
+        uLCD.filled_circle(goal->x, goal->y, radius + 1, GREEN);
+        goal->should_draw = 0;
+    }
+}
+
+/** Checks whether the ball has hit the goal */
+int do_goal(Goal* goal, Physics* curr)
+{
+    double dist = sqrt(pow(curr->px - goal->x, 2) + pow(curr->py - goal->y, 2));
+    if (dist < radius * 2) {
+        goal->should_draw = 1;
+    }
+    if (dist < radius) {
+        return 1;
+    }
+    return 0;
 }
 
 /** Reads inputs to the game, such as accelerometer and buttons */
@@ -23,22 +73,65 @@
 {
     GameInputs inputs = {0};
 
-    // TODO: Get acceleration vector from accelerometer
-    // TODO: Read buttons
+    // Get acceleration vector from accelerometer
+    acc.readXYZGravity(&inputs.ax, &inputs.ay, &inputs.az);
 
     return inputs;
 }
 
-int update_game(DLinkedList* arena, Physics* curr, GameInputs inputs, float delta)
+int lrpb = left_pb || right_pb;
+int lpb = 1;
+int upb = up_pb;
+int dpb = down_pb;
+
+int update_game(DLinkedList* arena, Physics* curr, GameInputs inputs, DLinkedList* checkpoints, float delta)
 {
+
+    // Cheat codes!
+    if (left_pb == 0 && right_pb == 0 && lrpb == 1) {
+        lpb = 1;
+        uLCD.cls();
+        uLCD.printf("\n\n\n\n    Cheat code!");
+        wait(0.5);
+        return 30;
+    }
+
+    // Help!
+    if (left_pb == 1 && lpb == 0) {
+        lpb = 1;
+        return 32;
+    }
+
+    // Save/restore state
+    if (up_pb == 0 && upb == 1) {
+        greenLED = 1;
+        Physics* saveState = (Physics*) malloc(sizeof(Physics));
+        *saveState = *curr;
+        insertTail(checkpoints, saveState);
+    }
+    if (down_pb == 0 && dpb == 1) {
+        Physics* restoreState = (Physics*) getTail(checkpoints);
+        if (restoreState != NULL) {
+            *curr = *restoreState;
+        }
+    }
+
+    // Save previous inputs
+    lrpb = left_pb || right_pb;
+    lpb = left_pb;
+    upb = up_pb;
+    dpb = down_pb;
+
     ///////////////////////////////
     // Prepare for physics update
     ///////////////////////////////
     // Make a copy of the current state for modification
     Physics next = *curr;
+
     // No acceleration unless the ArenaElements apply them. (Newton's 1st law)
     next.ax = next.ay = 0.0;
 
+
     // Loop over all arena elements
     ArenaElement* elem = (ArenaElement*)getHead(arena);
     do {
@@ -47,8 +140,20 @@
                 do_wall(&next, curr, (Wall*) elem, delta);
                 break;
             case BALL:
+                next.ax += inputs.ay * ACCELERATION;
+                next.ay += inputs.ax * ACCELERATION;
                 forward_euler(&next, delta);
                 break;
+            case HOLE:
+                if (do_hole((Hole*) elem, curr)) {
+                    return 31;
+                }
+                break;
+            case GOAL:
+                if (do_goal((Goal*) elem, curr)) {
+                    return 1;
+                }
+                break;
             default:
                 break;
         }
@@ -56,8 +161,12 @@
 
     // Last thing! Update state, so it will be saved for the next iteration.
     *curr = next;
-    
+
     // Zero means we aren't done yet
+    // 1 means we've hit the goal
+    // 31 means we've hit a pothole
+    // 32 means we need help!
+    // 30 means we used the cheat code
     return 0;
 }
 
@@ -75,17 +184,24 @@
     int count = 0;
     int count2 = 0;
 
+    // Initialize checkpoint list
+    DLinkedList* checkpoints = create_dlinkedlist();
+
     // Initial draw of the game
     uLCD.background_color(BLACK);
     uLCD.cls();
 
+    // Save start time
+    set_time(0);
+    time_t startTime = time(NULL);
+
     ///////////////////
     // Main game loop
     ///////////////////
     while(1) {
         // Read timer to determine how long the last loop took
         tick = timer.read_ms();
-        
+
         ///////////////////
         // Physics Update
         ///////////////////
@@ -101,8 +217,9 @@
         GameInputs inputs = read_inputs();
 
         // Update game state
-        int done = update_game(arena, state, inputs, delta);
-        if (done) return done;
+        int done = update_game(arena, state, inputs, checkpoints, delta);
+        if (done == 1) return 30 - (time(NULL) - startTime);
+        if (done != 0) return done;
 
         // Debug: Count physics updates
         count2++;
@@ -121,7 +238,8 @@
                 case BALL:
                     erase_ball((Ball*) elem);
                     break;
-                default: break;
+                default:
+                    break;
             }
         } while(elem = (ArenaElement*)getNext(arena));
 
@@ -135,11 +253,20 @@
                 case BALL:
                     draw_ball((Ball*) elem, state);
                     break;
+                case HOLE:
+                    draw_hole((Hole*) elem);
+                    break;
+                case GOAL:
+                    draw_goal((Goal*) elem);
+                    break;
                 default:
                     break;
             }
         } while(elem = (ArenaElement*)getNext(arena));
 
+        uLCD.line(0, 0, 127, 0, 0);
+        uLCD.line(0, 0, (30 - (time(NULL) - startTime)) * (127/30), 0, GREEN);
+
         ///////////////
         // Debug info
         ///////////////
@@ -148,11 +275,11 @@
         //  Second number is how many physics iterations between drawing frames
         //  Only displayed every 10th render update (roughly 2.5 Hz)
         // TODO: Take this out before you turn your code in!
-        if ((count = (count+1)%10) == 0) {
-            uLCD.locate(0, 0);
-            uLCD.printf("%d %d \r\n", timer.read_ms()-tick, count2);
-        }
-        
+        //if ((count = (count+1)%10) == 0) {
+        //    uLCD.locate(0, 0);
+        //    uLCD.printf("%d %d \r\n", timer.read_ms()-tick, count2);
+        //}
+
         // Reset physics iteration counter after every render update
         count2 = 0;
     }
diff -r c18c231cb299 -r 2042f29de6b7 game.h
--- a/game.h	Wed Nov 08 21:01:43 2017 +0000
+++ b/game.h	Thu Nov 21 16:10:57 2019 +0000
@@ -4,8 +4,7 @@
 #include "doublely_linked_list.h"
 
 /* A structure for holding all the game inputs */
-struct GameInputs
-{
+struct GameInputs {
     // Measurements from the accelerometer
     double ax, ay, az;
 };
@@ -24,6 +23,8 @@
 // Element types
 #define WALL        0
 #define BALL        1
+#define GOAL        2
+#define HOLE        3
 
 /** An ArenaElement struct representing the ball. */
 struct Ball {
@@ -33,6 +34,24 @@
     int x, y;
 };
 
+/** An ArenaElement struct representing the goal. */
+struct Goal {
+    // ArenaElement type (must be first element)
+    int type;
+    // Drawing info
+    int x, y;
+    int should_draw;
+};
+
+/** An ArenaElement struct representing a hole. */
+struct Hole {
+    // ArenaElement type (must be first element)
+    int type;
+    // Drawing info
+    int x, y;
+    int should_draw;
+};
+
 /////////////////////////
 // ArenaElement helpers
 /////////////////////////
@@ -43,8 +62,13 @@
 
 /* Add additional helpers for other ArenaElement types here */
 
+/** Draws the goal */
+void draw_goal(Goal* goal);
+/** Draws a hole */
+void draw_hole(Hole* hole);
+
 ///////////////////////////
-// Game control functions 
+// Game control functions
 ///////////////////////////
 /* Reads all game inputs */
 GameInputs read_inputs();
diff -r c18c231cb299 -r 2042f29de6b7 globals.h
--- a/globals.h	Wed Nov 08 21:01:43 2017 +0000
+++ b/globals.h	Thu Nov 21 16:10:57 2019 +0000
@@ -32,6 +32,9 @@
 #include "wave_player.h"
 #include "SDFileSystem.h"
 #include "MMA8452.h"
+#include "Speaker.h"
+
+#define ACCELERATION 500
 
 // Hardware declarations. Initialization is in main.cpp
 extern uLCD_4DGL uLCD;      // Screen
@@ -45,9 +48,14 @@
 extern wave_player waver;   // wav player
 extern SDFileSystem sd;     // SD card and filesystem (mosi, miso, sck, cs)
 
+extern DigitalOut redLED;   // Red LED
+extern DigitalOut greenLED;   // Green LED
+extern Speaker speaker;  // Speaker
+
 // Global parameters. Initialized in main.cpp
 extern const float mass;
 extern const int radius;
 extern const float bounce;
+extern int sound;
 
 #endif //GLOBAL_H
\ No newline at end of file
diff -r c18c231cb299 -r 2042f29de6b7 main.cpp
--- a/main.cpp	Wed Nov 08 21:01:43 2017 +0000
+++ b/main.cpp	Thu Nov 21 16:10:57 2019 +0000
@@ -32,22 +32,38 @@
 #include "doublely_linked_list.h"
 
 // Hardware initialization
-DigitalIn left_pb(p21);  // push button
-DigitalIn right_pb(p22); // push button
-DigitalIn up_pb(p23);    // push button
-DigitalIn down_pb(p24);  // push button
+DigitalIn left_pb(p21);     // push button
+DigitalIn right_pb(p22);    // push button
+DigitalIn up_pb(p23);       // push button
+DigitalIn down_pb(p24);     // push button
 uLCD_4DGL uLCD(p9,p10,p11); // LCD (serial tx, serial rx, reset pin;)
 Serial pc(USBTX,USBRX);     // used by Accelerometer
-MMA8452 acc(p28, p27, 100000); // Accelerometer
-SDFileSystem sd(p5, p6, p7, p8, "sd"); // SD card and filesystem (mosi, miso, sck, cs)
+MMA8452 acc(p28, p27, 100000);  // Accelerometer
+//SDFileSystem sd(p5, p6, p7, p8, "sd");  // SD card and filesystem
+
+DigitalOut redLED(p25);     // Red LED
+DigitalOut greenLED(p26);   // Green LED
+Speaker speaker(p18);       // Speaker
+
+// Menu screen drawing functions
+void do_main_menu();
+void do_setup_menu();
+void do_help_menu();
+void do_level_start(int);
+void do_level_complete(int, int);
+void do_game_over();
 
 // Level creation method declaration
 DLinkedList* create_blank_level();
+DLinkedList* create_level_1();
+DLinkedList* create_level_2();
+DLinkedList* create_level_3();
 
 // Parameters. Declared in globals.h
 const float mass = 0.001;
 const int radius = 4;
-const float bounce=0.5;
+const float bounce = 0.5;
+int sound = 1;
 
 /** Main() is where you start your implementation */
 int main()
@@ -55,6 +71,7 @@
     ////////////////////////////
     // Power-on initialization
     ////////////////////////////
+
     // Turn up the serial data rate so we don't lag
     uLCD.baudrate(3000000);
     pc.baud(115200);
@@ -68,28 +85,557 @@
 
     // Other hardware initialization here (SD card, speaker, etc.)
 
+    DLinkedList* levels = create_dlinkedlist();
+    insertTail(levels, create_level_1());
+    insertTail(levels, create_level_2());
+    insertTail(levels, create_level_3());
+
+    do_main_menu();
+
     ///////////////
     // Reset loop
     ///////////////
     // This is where control between major phases of the game happens
     // This is a good place to add choose levels, add the game menu, etc.
-    while(1) 
-    {
-        // Initialze game state
-        DLinkedList* arena = create_blank_level();
+
+    // Start with the first level
+    DLinkedList* arena = (DLinkedList*)getHead(levels);
+    int level = 1;
+
+    int gameOver = 0;
+    while(gameOver == 0) {
+
+        do_level_start(level);
+
+        uLCD.cls();
+
+        // (Re)Initialze game state
         Physics state = {0};
-        state.px = 64.0;        // Position in the center of the screen
-        state.py = 64.0;
-        state.vx = 0.0;         // Initially unmoving
+        int ix, iy;
+        state.px = ix = ((Ball*)getTail(arena))->x;     // Initial position of ball
+        state.py = iy = ((Ball*)getTail(arena))->y;
+        state.vx = 0.0;         // Initial velocity of ball
         state.vy = 0.0;
 
         // Delegate to the game loop to execute the level
         // run_game() is in game.cpp
-        run_game(arena, &state);
+        int ret = run_game(arena, &state);
+
+        // If we hit the goal, advance to the next level
+        if (ret <= 30) {
+
+            do_level_complete(level++, ret);
+
+            // Destroy the arena and entities once we're done with the level
+            destroyList(arena);
+
+            // Get the next level
+            arena = (DLinkedList*)getNext(levels);
+            // If the next level is NULL, game over!
+            if (arena == NULL) {
+                gameOver = 1;
+            }
+
+        } else {
+
+            if (ret == 32) {
+                // Show help screen
+                do_help_menu();
+            } else {
+                // Collision effect
+                redLED = 1;
+                for (int i = 4; i < 29; i++) {
+                    redLED = !redLED;
+                    int tone = (29 - i) * 5 + 100;
+                    speaker.PlayNote(tone, 0.01, sound);
+                    uLCD.circle(64, 64, i, RED);
+                    uLCD.circle(64, 64, i - 1, 0xFFCC00);
+                    uLCD.circle(64, 64, i - 2, WHITE);
+                    uLCD.circle(64, 64, i - 3, 0);
+                }
+            }
+
+            // If we hit a pothole, restart the level by redrawing all elements
+            // and resetting the state
+            ArenaElement* elem = (ArenaElement*)getHead(arena);
+            do {
+                switch(elem->type) {
+                    case WALL:
+                        // Redraw walls
+                        ((Wall*)elem)->should_draw = 1;
+                        break;
+                    case BALL:
+                        // Reset ball position
+                        ((Ball*)elem)->x = ix;
+                        ((Ball*)elem)->y = iy;
+                        break;
+                    case HOLE:
+                        // Redraw holes
+                        ((Hole*)elem)->should_draw = 1;
+                        break;
+                    case GOAL:
+                        // Redraw goal
+                        ((Goal*)elem)->should_draw = 1;
+                        break;
+                    default:
+                        break;
+                }
+            } while(elem = (ArenaElement*)getNext(arena));
+
+        }
+
+    }
+
+    do_game_over();
+
+}
+
+void do_main_menu()
+{
+
+    int cont = 1;
+    while (cont) {
+
+        uLCD.cls();
+        uLCD.color(WHITE);
+        uLCD.printf("\n\n");
+        uLCD.printf("   Maze Runner!   ");
+        uLCD.printf("\n\n");
+        uLCD.printf("      Play        ");
+        uLCD.printf("\n");
+        uLCD.printf("      Setup       ");
+        uLCD.printf("\n");
+        uLCD.printf("      Help        ");
+        uLCD.printf("\n\n");
+
+        uLCD.rectangle(15, 34, 112, 51, WHITE);
+        uLCD.rectangle(15, 51, 112, 67, WHITE);
+        uLCD.rectangle(15, 67, 112, 84, WHITE);
+        uLCD.rectangle(16, 35, 111, 51, WHITE);
+        uLCD.rectangle(16, 51, 111, 67, WHITE);
+        uLCD.rectangle(16, 67, 111, 83, WHITE);
+
+        int offset = 35;
+        uLCD.rectangle(16, 0 + offset, 111, 16 + offset, BLUE);
+
+        int rpb = right_pb;
+        int upb = up_pb;
+        int dpb = down_pb;
+        int rpb2 = rpb;
+        int upb2 = upb;
+        int dpb2 = dpb;
+
+        int cont2 = 1;
+        while(cont2) {
+
+            int crpb = right_pb;
+            int cupb = up_pb;
+            int cdpb = down_pb;
+
+            if (!cupb && upb && upb2) {
+                uLCD.rectangle(16, 0 + offset, 111, 16 + offset, WHITE);
+                if (offset > 35) {
+                    offset -= 16;
+                }
+                uLCD.rectangle(16, 0 + offset, 111, 16 + offset, BLUE);
+                speaker.PlayNote(100, 0.01, sound);
+            }
+
+            if (!cdpb && dpb && dpb2) {
+                uLCD.rectangle(16, 0 + offset, 111, 16 + offset, WHITE);
+                if (offset < 67) {
+                    offset += 16;
+                }
+                uLCD.rectangle(16, 0 + offset, 111, 16 + offset, BLUE);
+                speaker.PlayNote(100, 0.01, sound);
+            }
+
+            if (!crpb && rpb && rpb2) {
+
+                uLCD.rectangle(16, 0 + offset, 111, 16 + offset, GREEN);
+                speaker.PlayNote(100, 0.01, sound);
+                wait(0.25);
+
+                if (offset == 51) {
+                    do_setup_menu();
+                    cont2 = 0;
+                } else if (offset == 67) {
+                    do_help_menu();
+                    cont2 = 0;
+                } else {
+                    cont = 0;
+                    cont2 = 0;
+                }
+
+            }
+
+            rpb2 = rpb;
+            upb2 = upb;
+            dpb2 = dpb;
+            rpb = crpb;
+            upb = cupb;
+            dpb = cdpb;
+
+        }
+
+    }
+
+}
+
+void do_setup_menu()
+{
+
+    int cont = 1;
+    while (cont) {
+
+        uLCD.cls();
+        uLCD.color(WHITE);
+        uLCD.printf("\n\n");
+        uLCD.printf("      Setup       ");
+        uLCD.printf("\n\n");
+        if (sound) {
+            uLCD.printf("    Sound ON      ");
+        } else {
+            uLCD.printf("    Sound OFF     ");
+        }
+
+        int offset = 35;
+        uLCD.rectangle(16, 0 + offset, 111, 16 + offset, BLUE);
+
+        int lpb = left_pb;
+        int rpb = right_pb;
+
+        int cont2 = 1;
+        while(cont2) {
+
+            int clpb = left_pb;
+            int crpb = right_pb;
+
+            if (!crpb && rpb) {
+                uLCD.rectangle(16, 0 + offset, 111, 16 + offset, GREEN);
+                wait(0.25);
+                if (sound == 1) {
+                    sound = 0;
+                } else {
+                    sound = 1;
+                }
+                speaker.PlayNote(100, 0.01, sound);
+                cont2 = 0;
+            }
+
+            if (!clpb && lpb) {
+                speaker.PlayNote(100, 0.01, sound);
+                cont = 0;
+                cont2 = 0;
+            }
+
+            lpb = clpb;
+            rpb = crpb;
+
+        }
+
+    }
+
+}
+
+void do_help_menu()
+{
+    uLCD.cls();
+    uLCD.color(WHITE);
+    uLCD.printf("\n\n");
+    uLCD.printf("      Help        ");
+    uLCD.printf("\n\n");
+
+    uLCD.printf("Tilt the game to  ");
+    uLCD.printf("get through the   ");
+    uLCD.printf("maze to the ");
+    uLCD.color(GREEN);
+    uLCD.printf("green ");
+    uLCD.color(WHITE);
+    uLCD.printf("dot. Don't touch  ");
+    uLCD.printf("the ");
+    uLCD.color(RED);
+    uLCD.printf("red");
+    uLCD.color(WHITE);
+    uLCD.printf(" dots!     ");
+    uLCD.printf("\n");
+
+    uLCD.color(BLUE);
+    uLCD.printf("UP");
+    uLCD.color(WHITE);
+    uLCD.printf(" saves state.   ");
+    uLCD.printf("\n");
+
+    uLCD.color(BLUE);
+    uLCD.printf("DOWN");
+    uLCD.color(WHITE);
+    uLCD.printf(" jumps to the ");
+    uLCD.printf("last saved state. ");
+
+    while(left_pb) {}
+
+    speaker.PlayNote(100, 0.01, sound);
+
+}
 
-        // Destory the arena and entities once we're done with the level
-        destroyList(arena);
+void do_level_start(int level)
+{
+
+    uLCD.cls();
+    uLCD.color(WHITE);
+    uLCD.printf("\n\n\n\n");
+    uLCD.printf("     Level %d      ", level);
+    uLCD.printf("\n\n\n");
+
+    uLCD.rectangle(16, 19, 103, 51, WHITE);
+
+    uLCD.printf("  ");
+    for (int i = 3; i > 0; i--) {
+        redLED = 1;
+        uLCD.printf("%i... ", i);
+        speaker.PlayNote(293.665, 0.25, sound);
+        redLED = 0;
+        wait(0.75);
     }
+    greenLED = 1;
+    uLCD.printf("\n\n       Go!");
+    speaker.PlayNote(391.995, 0.75, sound);
+    greenLED = 0;
+
+}
+
+void do_level_complete(int level, int time)
+{
+
+    uLCD.cls();
+    uLCD.color(WHITE);
+    uLCD.printf("\n\n\n\n");
+    uLCD.printf("     Level %d      \n", level);
+    uLCD.printf("    Complete!     ");
+    uLCD.printf("\n\n\n");
+    uLCD.printf("  Score:  %d/30   ", time);
+
+    uLCD.rectangle(16, 19, 103, 67, WHITE);
+
+    greenLED = 1;
+    speaker.PlayNote(391.995, 0.12, sound);
+    greenLED = 0;
+    wait(0.12);
+    greenLED = 1;
+    speaker.PlayNote(493.883, 0.12, sound);
+    speaker.PlayNote(587.330, 0.24, sound);
+    greenLED = 0;
+    wait(1);
+
+}
+
+void do_game_over()
+{
+    uLCD.cls();
+    uLCD.color(WHITE);
+    uLCD.printf("\n\n\n\n");
+    uLCD.printf("    Game Over!    ");
+    uLCD.printf("\n\n\n");
+
+    uLCD.rectangle(16, 19, 103, 51, WHITE);
+
+    uLCD.printf("  Press the blue  ");
+    uLCD.printf("  button to play  ");
+    uLCD.printf("      again!      ");
+
+
+
+    greenLED = 1;
+    speaker.PlayNote(587.330, 0.2, sound);
+    greenLED = 0;
+    wait(0.2);
+    greenLED = 1;
+    speaker.PlayNote(587.330, 0.1, sound);
+    wait(0.1);
+    greenLED = 0;
+    speaker.PlayNote(587.330, 0.2, sound);
+    greenLED = 1;
+    speaker.PlayNote(493.883, 0.2, sound);
+    greenLED = 0;
+    speaker.PlayNote(587.330, 0.1, sound);
+    wait(0.1);
+    greenLED = 1;
+    speaker.PlayNote(783.991, 0.5, sound);
+    greenLED = 0;
+}
+
+/** Creates the first level. */
+DLinkedList* create_level_1()
+{
+    DLinkedList* arena = create_dlinkedlist();
+
+    // Initialize the walls
+    Wall* walls[12];
+    walls[0] = create_wall(HORIZONTAL, 0, 2, 127, bounce);  // top
+    walls[1] = create_wall(HORIZONTAL, 0, 127, 127, bounce);// bottom
+    walls[2] = create_wall(VERTICAL, 0, 2, 127, bounce);    // left
+    walls[3] = create_wall(VERTICAL, 127, 2, 127, bounce);  // right
+    walls[4] = create_wall(VERTICAL, 21, 21, 84, bounce);
+    walls[5] = create_wall(VERTICAL, 42, 2, 42, bounce);
+    walls[6] = create_wall(VERTICAL, 63, 21, 106, bounce);
+    walls[7] = create_wall(VERTICAL, 84, 64, 32, bounce);
+    walls[8] = create_wall(VERTICAL, 42, 84, 21, bounce);
+    walls[9] = create_wall(HORIZONTAL, 21, 64, 42, bounce);
+    walls[10] = create_wall(HORIZONTAL, 21, 105, 21, bounce);
+    walls[11] = create_wall(HORIZONTAL, 84, 64, 43, bounce);
+
+    // Add the walls to the arena
+    for (int i = 0; i < 12; i++)
+        insertTail(arena, (void*)walls[i]);
+
+    // Initialize the goal
+    Goal* goal = (Goal*) malloc(sizeof(Goal));
+    goal->type = GOAL;
+    goal->x = 95;
+    goal->y = 80;
+    goal->should_draw = 1;
+
+    // Add goal to the arena
+    insertTail(arena, (void*)goal);
+
+    // Initialize the ball
+    Ball* ball = (Ball*) malloc(sizeof(Ball));
+    ball->type = BALL;
+    ball->x = 31;
+    ball->y = 95;
+
+    // Add ball to the arena
+    insertTail(arena, (void*)ball);
+
+    return arena;
+}
+
+/** Creates the second level. */
+DLinkedList* create_level_2()
+{
+    DLinkedList* arena = create_dlinkedlist();
+
+    // Initialize the walls
+    Wall* walls[15];
+    walls[0] = create_wall(HORIZONTAL, 0, 2, 127, bounce);  // top
+    walls[1] = create_wall(HORIZONTAL, 0, 127, 127, bounce);// bottom
+    walls[2] = create_wall(VERTICAL, 0, 2, 127, bounce);    // left
+    walls[3] = create_wall(VERTICAL, 127, 2, 127, bounce);  // right
+    walls[4] = create_wall(VERTICAL, 64, 2, 21, bounce);
+    walls[5] = create_wall(HORIZONTAL, 0, 21, 32, bounce);
+    walls[6] = create_wall(VERTICAL, 32, 21, 43, bounce);
+    walls[7] = create_wall(VERTICAL, 96, 21, 22, bounce);
+    walls[8] = create_wall(HORIZONTAL, 64, 43, 63, bounce);
+    walls[9] = create_wall(HORIZONTAL, 32, 64, 32, bounce);
+    walls[10] = create_wall(HORIZONTAL, 64, 85, 32, bounce);
+    walls[11] = create_wall(VERTICAL, 64, 85, 42, bounce);
+    walls[12] = create_wall(HORIZONTAL, 0, 85, 32, bounce);
+    walls[13] = create_wall(VERTICAL, 32, 85, 22, bounce);
+    walls[14] = create_wall(HORIZONTAL, 96, 107, 31, bounce);
+
+    // Add the walls to the arena
+    for (int i = 0; i < 15; i++)
+        insertTail(arena, (void*)walls[i]);
+
+    // Initialize a hole
+    Hole* hole = (Hole*) malloc(sizeof(Hole));
+    hole->type = HOLE;
+    hole->x = 96;
+    hole->y = 64;
+    hole->should_draw = 1;
+
+    // Add hole to the arena
+    insertTail(arena, (void*)hole);
+
+    // Initialize the goal
+    Goal* goal = (Goal*) malloc(sizeof(Goal));
+    goal->type = GOAL;
+    goal->x = 112;
+    goal->y = 21;
+    goal->should_draw = 1;
+
+    // Add goal to the arena
+    insertTail(arena, (void*)goal);
+
+    // Initialize the ball
+    Ball* ball = (Ball*) malloc(sizeof(Ball));
+    ball->type = BALL;
+    ball->x = 16;
+    ball->y = 96;
+
+    // Add ball to the arena
+    insertTail(arena, (void*)ball);
+
+    return arena;
+}
+
+/** Creates the third level. */
+DLinkedList* create_level_3()
+{
+    DLinkedList* arena = create_dlinkedlist();
+
+    // Initialize the walls
+    Wall* walls[15];
+    walls[0] = create_wall(HORIZONTAL, 0, 2, 127, bounce);  // top
+    walls[1] = create_wall(HORIZONTAL, 0, 127, 127, bounce);// bottom
+    walls[2] = create_wall(VERTICAL, 0, 2, 127, bounce);    // left
+    walls[3] = create_wall(VERTICAL, 127, 2, 127, bounce);  // right
+    walls[4] = create_wall(HORIZONTAL, 0, 18, 107, bounce);
+    walls[5] = create_wall(VERTICAL, 107, 18, 92, bounce);
+    walls[6] = create_wall(HORIZONTAL, 64, 110, 43, bounce);
+    walls[7] = create_wall(HORIZONTAL, 43, 91, 42, bounce);
+    walls[8] = create_wall(VERTICAL, 43, 91, 36, bounce);
+    walls[9] = create_wall(HORIZONTAL, 0, 91, 21, bounce);
+    walls[10] = create_wall(VERTICAL, 21, 73, 18, bounce);
+    walls[11] = create_wall(HORIZONTAL, 21, 73, 64, bounce);
+    walls[12] = create_wall(VERTICAL, 85, 37, 36, bounce);
+    walls[13] = create_wall(HORIZONTAL, 21, 37, 64, bounce);
+    walls[14] = create_wall(HORIZONTAL, 0, 55, 43, bounce);
+
+    // Add the walls to the arena
+    for (int i = 0; i < 15; i++)
+        insertTail(arena, (void*)walls[i]);
+
+    // Initialize a hole
+    Hole* hole = (Hole*) malloc(sizeof(Hole));
+    hole->type = HOLE;
+    hole->x = 96;
+    hole->y = 82;
+    hole->should_draw = 1;
+
+    // Add hole to the arena
+    insertTail(arena, (void*)hole);
+
+    // Initialize a hole
+    Hole* hole2 = (Hole*) malloc(sizeof(Hole));
+    hole2->type = HOLE;
+    hole2->x = 64;
+    hole2->y = 55;
+    hole2->should_draw = 1;
+
+    // Add hole to the arena
+    insertTail(arena, (void*)hole2);
+
+    // Initialize the goal
+    Goal* goal = (Goal*) malloc(sizeof(Goal));
+    goal->type = GOAL;
+    goal->x = 11;
+    goal->y = 82;
+    goal->should_draw = 1;
+
+    // Add goal to the arena
+    insertTail(arena, (void*)goal);
+
+    // Initialize the ball
+    Ball* ball = (Ball*) malloc(sizeof(Ball));
+    ball->type = BALL;
+    ball->x = 21;
+    ball->y = 110;
+
+    // Add ball to the arena
+    insertTail(arena, (void*)ball);
+
+    return arena;
 }
 
 /** Creates a level with only bounding walls and a ball. */
@@ -99,11 +645,11 @@
 
     // Initialize the walls
     Wall* walls[4];
-    walls[0] = create_wall(HORIZONTAL, 0, 0, 127, bounce);  // top
+    walls[0] = create_wall(HORIZONTAL, 0, 2, 127, bounce);  // top
     walls[1] = create_wall(HORIZONTAL, 0, 127, 127, bounce);// bottom
     walls[2] = create_wall(VERTICAL, 0, 0, 127, bounce);    // left
     walls[3] = create_wall(VERTICAL, 127, 0, 127, bounce);  // right
-    
+
     // Add the walls to the arena
     for (int i = 0; i < 4; i++)
         insertTail(arena, (void*)walls[i]);
@@ -113,12 +659,12 @@
     ball->type = BALL;
     ball->x = 20;
     ball->y = 20;
-    
-    // Add ball to the arena 
-    // NOTE: The ball should always be last in the arena list, so that the other 
-    // ArenaElements have a chance to compute the Physics updates before the 
+
+    // Add ball to the arena
+    // NOTE: The ball should always be last in the arena list, so that the other
+    // ArenaElements have a chance to compute the Physics updates before the
     // ball applies forward euler method.
     insertTail(arena, (void*)ball);
-    
+
     return arena;
 }
\ No newline at end of file
diff -r c18c231cb299 -r 2042f29de6b7 physics.cpp
--- a/physics.cpp	Wed Nov 08 21:01:43 2017 +0000
+++ b/physics.cpp	Thu Nov 21 16:10:57 2019 +0000
@@ -2,17 +2,23 @@
 #include "math_extra.h"
 
 void forward_euler(Physics* state, float delta)
-{ 
+{
     // TODO: Implement proper forward euler updates for position and velocity
-  
+
     // Compute random motion
-    float damp = 0.5;
-    float dx = damp*coin_flip();
-    float dy = damp*coin_flip();
+//    float damp = 0.5;
+//    float dx = damp*coin_flip();
+//    float dy = damp*coin_flip();
+
+//    state->px = state->px + dx;
+//    state->py = state->py + dy;
+//    state->vx = dx;
+//    state->vy = dy;
 
     // Update position and velocity
-    state->px = state->px + dx;
-    state->py = state->py + dy;
-    state->vx = dx;
-    state->vy = dy;
+    state->vx += state->ax * delta;
+    state->vy += state->ay * delta;
+    state->px += state->vx * delta;
+    state->py += state->vy * delta;
+
 }
\ No newline at end of file
diff -r c18c231cb299 -r 2042f29de6b7 physics.h
--- a/physics.h	Wed Nov 08 21:01:43 2017 +0000
+++ b/physics.h	Thu Nov 21 16:10:57 2019 +0000
@@ -3,10 +3,10 @@
 /**
  * The main state structure for the game.
  * This structure holds all the global state for the game, and is updated during
- * the game loop. When you implement the "jump back" feature, this is the 
+ * the game loop. When you implement the "jump back" feature, this is the
  * structure you need to save/restore.
  */
-struct Physics {    
+struct Physics {
     float px, py; // Ball position
     float vx, vy; // Ball velocity
     float ax, ay; // Ball acceleration
diff -r c18c231cb299 -r 2042f29de6b7 wall.cpp
--- a/wall.cpp	Wed Nov 08 21:01:43 2017 +0000
+++ b/wall.cpp	Thu Nov 21 16:10:57 2019 +0000
@@ -9,19 +9,19 @@
 {
     // Alocate memory for wall
     Wall* wall = (Wall*) malloc(sizeof(Wall));
-    
+
     // Initialize type info.
     // Always draw on the first frame
     wall->type = WALL;
     wall->should_draw = 1;
-    
+
     // Set user parameters
     wall->direction = direction;
     wall->x = x;
     wall->y = y;
     wall->length = length;
     wall->bounce = bounce;
-    
+
     return wall;
 }
 
@@ -29,56 +29,55 @@
 {
     // Debug info
 //    pc.printf("wall: %d %d %d %d\r\n", wall->direction, wall->x, wall->y, wall->length);
-    
+
     float adj, percent, contact;
 
-    if (wall->direction == VERTICAL)
-    {
+    if (wall->direction == VERTICAL) {
         // Step 0: Adjust the wall location based on ball radius
         adj = wall->x - sgn(curr->vx)*(radius+1);
 
         // Step 1: Compute percent of motion before bounce
         percent = (adj - curr->px) / (curr->vx*delta);
-        
+
         // Negative percent means we're moving away from the wall
         // >=100% means we don't need to bounce yet
-        if (percent >= 0.0 && percent < 1.0)
-        {
+        if (percent >= 0.0 && percent < 1.0) {
             // Compute the bounce location
             contact = curr->py + curr->vy*percent*delta;
-            if (in_range(contact, wall->y, wall->y + wall->length))
-            {
-                
+            if (in_range(contact, wall->y, wall->y + wall->length)) {
+                // SGFX
+                redLED = 1;
+                speaker.PlayNote(100, 0.01, sound);
+                redLED = 0;
+
                 // Reverse velocity and slow down
                 next->vx = -wall->bounce*curr->vx;
 
                 // Adjust X position.
-                // This dampens the integration based on how far the ball had 
+                // This dampens the integration based on how far the ball had
                 // to travel before reflecting.
                 next->px = adj - percent*next->vx*delta;
             }
             // Draw the wall if we're close by
             wall->should_draw = 1;
         }
-        
+
         // Make sure we aren't inside the wall
         if (in_range((int)curr->px, wall->x - (radius+1), wall->x + (radius+1))
-             && in_range((int)curr->py, wall->y, wall->y + wall->length))
-        {
+                && in_range((int)curr->py, wall->y, wall->y + wall->length)) {
             next->px = wall->x + sgn(curr->px - wall->x)*(radius+1);
             wall->should_draw = 1;
         }
-    }
-    else //direction == HORIZONTAL
-    {
+    } else { //direction == HORIZONTAL
         // Same as vertical case, but swap x/y
-        adj = wall->y - sgn(curr->vy)*(radius+1); 
+        adj = wall->y - sgn(curr->vy)*(radius+1);
         percent = (adj - curr->py) / (curr->vy*delta);
-        if (percent >= 0.0 && percent < 1.0)
-        {
+        if (percent >= 0.0 && percent < 1.0) {
             contact = curr->px + curr->vx*percent*delta;
-            if (in_range(contact, wall->x, wall->x + wall->length))
-            {
+            if (in_range(contact, wall->x, wall->x + wall->length)) {
+                redLED = 1;
+                speaker.PlayNote(100, 0.01, sound);
+                redLED = 0;
                 next->vy = -wall->bounce*curr->vy;
                 next->py = adj - percent*next->vy*delta;
             }
@@ -86,8 +85,7 @@
             wall->should_draw = 1;
         }
         if (in_range((int)curr->py, wall->y - (radius+1), wall->y + (radius+1))
-         && in_range((int)curr->px, wall->x, wall->x + wall->length))
-        {
+                && in_range((int)curr->px, wall->x, wall->x + wall->length)) {
             next->py = wall->y + sgn(curr->py - wall->y)*(radius+1);
             wall->should_draw = 1;
         }
@@ -96,16 +94,15 @@
 
 void draw_wall(Wall* wall)
 {
-    if (wall->should_draw)
-    {
+    if (wall->should_draw) {
         int wx1, wx2, wy1, wy2;
         wx1 = wall->x;
         wy1 = wall->y;
         wx2 = wx1 + ((wall->direction == HORIZONTAL) ? wall->length : 0);
         wy2 = wy1 + ((wall->direction == VERTICAL) ? wall->length : 0);
         uLCD.line(wx1, wy1, wx2, wy2, WHITE);
-        
+
         // Don't draw again unless requested
         wall->should_draw = 0;
     }
-}    
\ No newline at end of file
+}
\ No newline at end of file
diff -r c18c231cb299 -r 2042f29de6b7 wall.h
--- a/wall.h	Wed Nov 08 21:01:43 2017 +0000
+++ b/wall.h	Thu Nov 21 16:10:57 2019 +0000
@@ -6,7 +6,7 @@
 
 /**
  * Structure to represent a Wall in the arena.
- * 
+ *
  * This structure is a ArenaElement; its first data element is an integer (type)
  * whose value is always WALL.
  */
@@ -47,7 +47,7 @@
 
 /**
  * Draws a given wall to the screen.
- * 
+ *
  * @param[in] wall  The wall to draw
  */
 void draw_wall(Wall* wall);