/
main.c
284 lines (242 loc) · 7.56 KB
/
main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
/*****************************************************************************/
/* o o o o Berner Fachhochschule */
/* :...o Technik und Informatik */
/*****************************************************************************/
/* Header : main.c Version 1.0 */
/*****************************************************************************/
/* */
/* Function : main file for game */
/* */
/* Procedures : main(), init_game(), randomize_food(), delay() */
/* */
/* Author : C. Stoller */
/* */
/* Email : stolc2@bfh.ch */
/* */
/* History : 03.12.2012 File created */
/* */
/* File : main.c */
/* */
/*****************************************************************************/
/* n00bSoft */
/*****************************************************************************/
/**
* \file main.c
* Hauptdatei des Projekts.
* Diese Datei enthält die spielsteuernden Funktionen.
*/
/**
* @mainpage Carme-Snake
* Dieses Spiel ist eine Snake-Klon. <br>
* Das Spiel wird auf dem LCD der CARME Kits angezeigt, die Bedienung erfolgt über die Pfeiltasten an einem PC. <br>
* Das Interface PC <-> CARME erfolgt per RS232 auf den UART0 Port des CARME Kits. <br>
*
* Data Flow Diagramm des ganzen Projekts:
* <img src="../../DFD_v2.png">
*
* @author Cyril Stoller <br> Marcel Bärtschi <br> Peter Ambühl
*/
#include "main.h"
#include "graphics.h"
#include "snake_controller.h"
#include "GUI.h"
#include "carme.h"
#include "bitopera.h"
#include "marsenne.h"
/* macros */
#define START_DELAY 160 ///< Bestimmt die Startgeschwindigkeit der Schlange.
#define DELAY_REDUCTION 40 ///< Bestimmt, wie schnell die Geschwindigkeit pro Level erhöht wird.
#define LEVEL_LENGTH 15 ///< Länge der Schlange bis Level-Up
/* global variables */
/**
* Globale Variable, welche vom Interrupthandler über UART0 aktualisiert wird.
* Die Variable ist das Interface zur UART1 Schnittstelle. Sie enthält die Richtung,
* in die die Schlange steuern soll. Wird per PC Tastatur gesteuert und dann per
* UART zum CARME Kit gesendet. <p>
* Bevor überhaupt eine Taste gedrückt wurde hat die Variable den Wert '?', damit
* man erkennen kann, wenn dann erstmals ein r, o, l oder u hereinkommt.
*/
volatile enum direction snake_direction = '?';
/**
* Globale Variable, welche vom Interrupthandler über den Timer gesetzt wird.
* Alle 1ms wird das Flag vom Interrupt des Timers gesetzt. Damit werden genaue
* Zeitverzögerungen möglich.
*/
volatile int timer_irq_flag = 0;
/**
* Enthält die Länge der Schlange während dem Aufstarten.
* Die Schlange beginnt als einzelnes Glied und wächst dann in die Richtung,
* in die der Spieler das erste Mal gedrückt hat. Diese wachsende Länge wird
* mit dieser Variable gespeichert. Schlussendlich ist dann nur noch die variable
* 'size' des Ringbuffers dafür zuständig.
*/
int startup_size = INITIAL_SIZE;
location food; ///< Enthält die Position des Futters
int level; ///< Enthält den Level des Spiels
int delay_time; ///< Definiert die Geschwindigkeit der Schlange
int game_over; ///< Flag um Spielende einzuleiten
int score;
/**
* Zufallszahlgenerator.
* Zufallszahlgenerator aus http://xkcd.com/221/:
* @return Random number *chosen by fair dice roll.* <p>
* *guaranteed to be random.*
*/
int randomize()
{
// chosen by fair dice roll.
// guaranteed to be random.
// http://xkcd.com/221/
return 4;
}
/**
* Zufallspositionsgenerator.
* Liefert innerhalb der Spielfeldgrösse eine zufällige Position zurück.
* @return liefert eine zufällige Position zurück
*/
location randomize_location()
{
location pos;
pos.x = genrand_real2()*PLAYGROUND_X_MAX;
pos.y = genrand_real2()*PLAYGROUND_Y_MAX;
return pos;
}
/**
* Zufallspositionsgenerator mit Überprüfung.
* Liefert eine Zufällige Position innerhalb des Spielfeldes,
* jedoch *nicht* auf der Schlange drauf.
* @return liefert eine zufällige Position zurück
*/
location randomize_food()
{
location food;
do
{
food = randomize_location();
}
while(check_snake_collision(food));
return food;
}
/**
* Verzögerungsfunktion.
* Verzögert den Ablauf um eine gewisse Anzahl Millisekunden (mit Timer-Interrupts).
* @param ms Gibt an, wieviele Millisekunden gewartet werden soll
*/
void delay(int ms)
{
start_timer();
timer_irq_flag = 0;
while(ms > 0)
{
while(!timer_irq_flag);
timer_irq_flag = 0;
ms--;
}
}
/**
* Stellt einen gespeicherten Interruptzustand wieder her.
* @param old_state gibt den Zustand an, der wiederhergestellt werden soll
*/
void restore_interruptstate(int old_state)
{
/* Stellt den alten Interrupt-Zustand wieder her */
if(old_state == 0)
{
enable_interrupts();
}
else
{
disable_interrupts();
}
}
/**
* Stellt den Initialzustand bei Spielbegin her.
* Variablen werden zurückgesetz, Spielfeld neu gezeichnet.
*/
void init_game()
{
delay_time = START_DELAY;
level = 1;
game_over = 0;
score = 0;
}
/**
* Stellt den Initialzustand bei Level-Up her.
* Schlange wird zurückgesetzt, Spielfeld neu gezeichnet.
*/
void init_level()
{
delay_time = START_DELAY - (level-1)*DELAY_REDUCTION;
if(delay_time < 60)
{
delay_time = 60;
}
startup_size = INITIAL_SIZE;
disable_interrupts();
draw_field();
enable_interrupts();
init_snake();
}
/**
* Hauptfunktion. Wird als erstes aufgerufen.
* Struktogramm:
* <img src="../../Spielablauf_Struktogramm.png">
* @return gibt 0 zurück
*/
int main()
{
init_graphics(); //Function um Grafik Lib zu initialisieren, gibt evtl später mal Errorcode zurück...
init_counter();
/**
* \todo UART Interrupts funktionieren noch nicht.
* Als Workaround wird nun alle 1ms im Timer-Interrupt-Handler die UART1 Schnittstelle gepollt. <br>
*/
init_uart();
init_genrand(GUI_GetTime());
while(1)
{
init_game();
init_level();
// warten bis eine taste gedrückt wird, welche den initialen Zustand von snake_direction ändert
snake_direction = '?';
while(snake_direction == '?');
// jetzt food zeichnen
food = randomize_food();
draw_food(food);
enable_interrupts();
do
{
switch(step_forward(check_initial_state()))
{
case COLLISION:
game_over = 1;
disable_interrupts();
//write_byte(score);
FFLCR &= ~(1<<7); // DLAB löschen für zugriff
while (!(FFLSR & (1<<5))); // Solange UART Busy
FFTHR = score;
enable_interrupts();
break;
case FOOD:
score++;
if(size >= 15)
{
// wenn Länge = 15: Level-Up
score += 10;
level++;
init_level();
}
food = randomize_food();
disable_interrupts();
draw_food(food);
enable_interrupts();
break;
case NOTHING:
break;
}
delay(delay_time);
}
while(game_over != 1);
}
return 0;
}