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