Subversion Repositories Code-Repo

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
240 Kevin 1
#include "defines.h"
2
#include "CONTROLLERS.h"
3
#include "SNAKE.h"
4
 
5
static SNAKE_DATA *data_p;
242 Kevin 6
static uint32_t rand_value __attribute__((persistent));
240 Kevin 7
 
8
void Snake_Init(SNAKE_DATA *data) {
9
    data_p = data;
10
 
11
    // Set starting point
241 Kevin 12
    data_p->body[0] = (SNAKE_POINT){0,0,7};
240 Kevin 13
 
14
    data_p->pos_head = 0;
15
    data_p->pos_tail = 0;
16
    data_p->length = 1;
17
    data_p->level = 1;
18
    data_p->delay = 800;
19
 
242 Kevin 20
    srand(rand_value);
21
 
240 Kevin 22
    // Generate a starting location for the candy
23
    data_p->candy_loc = Snake_Generate_Candy();
24
 
25
    // Draw the snake (head)
26
    Cube_Clear();
27
    uint32_t index = data_p->pos_head;
28
    Cube_Set_Pixel(data_p->body[index].z, data_p->body[index].x, data_p->body[index].y, SNAKE_HEAD_COLOR);
29
    while (index != data_p->pos_tail) {
30
        if (data_p->length > 1) {
31
            index = (index == 0) ? CUBE_PIXELS - 1 : index - 1;
32
            Cube_Set_Pixel(data_p->body[index].z, data_p->body[index].x, data_p->body[index].y, SNAKE_BODY_COLOR);
33
        }
34
    }
35
}
36
 
37
void Snake_Main(void) {
241 Kevin 38
    // Main function, loops and delays while updating the frame every x milliseconds
240 Kevin 39
    Delay_MS(2000);
40
    while (1) {
242 Kevin 41
        // Regenerate the seed upon each update so that the candy starts somewhere new every time
42
        rand_value = rand();
43
 
240 Kevin 44
        Snake_Update_Frame();
45
        Delay_MS(data_p->delay);
46
    }
47
}
48
 
49
void Snake_Update_Direction(uint8_t p1, uint8_t p2) {
50
    // Determine the next direction for the snake based off the last button press
51
    SNAKE_DIRECTION dir;
52
    dir.value = p1 | p2;
53
    data_p->last_direction = dir.value;
54
 
55
    SNAKE_POINT point = data_p->body[data_p->pos_head];
56
 
57
    if (dir.up) {
58
        point.z = (point.z == CUBE_LAYER_COUNT - 1) ? 0 : point.z + 1;
59
    } else if (dir.down) {
60
        point.z = (point.z == 0) ? CUBE_LAYER_COUNT - 1 : point.z - 1;
61
    } else if (dir.forward) {
62
        point.x = (point.x == CUBE_ROW_COUNT - 1) ? 0 : point.x + 1;
63
    } else if (dir.right) {
64
        point.y = (point.y == CUBE_COLUMN_COUNT - 1) ? 0 : point.y + 1;
65
    } else if (dir.backward) {
66
        point.x = (point.x == 0) ? CUBE_ROW_COUNT - 1 : point.x - 1;
67
    } else if (dir.left) {
68
        point.y = (point.y== 0) ? CUBE_COLUMN_COUNT - 1 : point.y - 1;
69
    }
70
 
71
    data_p->direction = point;
72
 
73
    // Update the overlay with the candy location
74
    Cube_Overlay_Clear();
75
    Cube_Overlay_Set_Pixel(data_p->candy_loc.z, data_p->candy_loc.x, data_p->candy_loc.y, SNAKE_CANDY_COLOR);
76
}
77
 
78
void Snake_Update_Frame(void) {
79
    uint8_t om_nom_nom = 0;
80
 
81
    // Check if we are moving onto a candy, if so extend body
82
    if (data_p->direction.x == data_p->candy_loc.x &&
83
            data_p->direction.y == data_p->candy_loc.y &&
84
            data_p->direction.z == data_p->candy_loc.z) {
85
        data_p->pos_head = (data_p->pos_head == CUBE_PIXELS - 1) ? 0 : data_p->pos_head + 1;
86
        data_p->body[data_p->pos_head] = data_p->direction;
87
        data_p->length++;
88
        data_p->candy_loc = Snake_Generate_Candy();
89
        om_nom_nom = 1;
90
    }
91
 
92
    // Check if the location that we are moving to is overlapping the body
93
    uint32_t pos = data_p->pos_tail;
94
    while (pos != data_p->pos_head) {
95
        if (data_p->direction.x == data_p->body[pos].x &&
96
                data_p->direction.y == data_p->body[pos].y &&
97
                data_p->direction.z == data_p->body[pos].z) {
241 Kevin 98
            // Indicate the overlapping pixel, delay, then return to idle state
242 Kevin 99
            Cube_Set_Pixel(data_p->direction.z, data_p->direction.x, data_p->direction.y, SNAKE_COLLISION_COLOR);
240 Kevin 100
            Delay_MS(3000);
242 Kevin 101
            Cube_Overlay_Clear();
102
            Animation_Cube_In_Out(200, ORANGE);
240 Kevin 103
            Reset_Board(BOARD_MODE_IDLE);
104
        }
105
        pos = (pos == CUBE_PIXELS - 1) ? 0 : pos + 1;
106
    }
107
 
108
    // If we didnt eat a candy, increment the frame to move the body along
109
    if (!om_nom_nom) {
110
        data_p->pos_head = (data_p->pos_head == CUBE_PIXELS - 1) ? 0 : data_p->pos_head + 1;
111
        data_p->pos_tail = (data_p->pos_tail == CUBE_PIXELS - 1) ? 0 : data_p->pos_tail + 1;
112
        data_p->body[data_p->pos_head] = data_p->direction;
113
    }
114
 
115
    // Draw updated snake location
116
    Cube_Clear();
117
    uint32_t index = data_p->pos_head;
118
    Cube_Set_Pixel(data_p->body[index].z, data_p->body[index].x, data_p->body[index].y, SNAKE_HEAD_COLOR);
119
    while (index != data_p->pos_tail) {
120
        if (data_p->length > 1) {
121
            index = (index == 0) ? CUBE_PIXELS - 1 : index - 1;
122
            Cube_Set_Pixel(data_p->body[index].z, data_p->body[index].x, data_p->body[index].y, SNAKE_BODY_COLOR);
123
        }
124
    }
125
 
126
    // Determine the next direction to take
127
    Snake_Update_Direction(data_p->last_direction, 0x0);
128
 
129
    // If we ate a candy, delay for a bit to rest
130
    if (om_nom_nom) {
241 Kevin 131
        // Increase the level by one, show on controller if necessary
132
        data_p->level += 1;
240 Kevin 133
        if (data_p->level % SNAKE_LEVEL_STEP == 0) {
134
            uint8_t tier = data_p->level / SNAKE_LEVEL_STEP;
135
            Controller_Set_Leds(tier, tier);
136
        }
241 Kevin 137
        // Decrease the delay between frame updates by 5ms
138
        data_p->delay -= 5;
139
        // Clear the watchdog timer to prevent resets in a middle of a game
140
        ClearWDT();
240 Kevin 141
    }
142
}
143
 
144
SNAKE_POINT Snake_Generate_Candy(void) {
145
    // Generates a random position within the cube that doesnt overlap anything
146
    SNAKE_POINT ret;
147
    uint32_t x, y, z, brk = 0;
148
    while(1) {
149
        x = rand() % 8;
150
        y = rand() % 8;
151
        z = rand() % 8;
152
 
153
        if (data_p->length != 1) {
154
            uint32_t pos = data_p->pos_tail;
155
            uint32_t overlap = 0;
156
            // Iterate through the frame till we finish or find an overlap
157
            while (pos != data_p->pos_head) {
158
                if (data_p->body[pos].x == x &&
159
                        data_p->body[pos].y == y &&
160
                        data_p->body[pos].z == z) {
161
                    overlap = 1;
162
                    break;
163
                } else {
164
                    pos = (pos == CUBE_PIXELS - 1) ? 0 : pos + 1;
165
                }
166
            }
167
            if (!overlap)
168
                brk = 1;
169
        } else {
170
            uint32_t pos = data_p->pos_tail;
171
            if (data_p->body[pos].x != x &&
172
                    data_p->body[pos].y != y &&
173
                    data_p->body[pos].z != z) {
174
                brk = 1;
175
            }
176
        }
177
 
178
        if (brk)
179
            break;
180
    }
181
 
182
    ret.x = x;
183
    ret.y = y;
184
    ret.z = z;
185
    return ret;
186
}