Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
zmx0142857
GitHub Repository: zmx0142857/mini-games
Path: blob/master/c/siege/siege.c
363 views
1
/* honeycomb with 121 cells:
2
* each cell can be determined with a pair of numbers (column,row),
3
* the origin (0,0) is marked by % and (0,4) is marked by #
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
#include "game.h"
34
#include "string.h"
35
36
#define LEN 122
37
38
// cells
39
#define BLANK 0
40
#define WALL 1
41
#define BALL 2
42
#define CELL 3
43
#define CURSOR 4
44
#define QUESTION_MARK 5
45
#define EXCLAMATION_MARK 6
46
47
// directions 8 - 13
48
#define VISITED 8
49
50
// status
51
#define PLAYING 0
52
#define WIN 1
53
#define LOSE 2
54
#define QUIT 3
55
56
int cur_x, cur_y, ball_x, ball_y;
57
int honeycomb[17][17];
58
59
#define BUFLEN 256
60
char title[BUFLEN];
61
62
#ifdef DEBUG
63
FILE *logfile;
64
#endif
65
66
void help()
67
{
68
printf("siege: try to trap the ball!\n"
69
"controls:\n"
70
" u: go upper left\n"
71
" i: go up\n"
72
" o: go upper right\n"
73
" j: go lower left\n"
74
" k: go down\n"
75
" l: go lower right\n"
76
" hold down shift to move item\n");
77
}
78
79
bool isvalid(int x, int y)
80
{
81
return (x <= 12 && y >= 4 && y-x <= 4)
82
|| (y <= 12 && x >= 4 && x-y <= 4);
83
}
84
85
void print_cell(int x, int y, int type)
86
{
87
int a = 5-x+2*y, b = 3*x+1;
88
switch (type) {
89
case BALL: mvprint(a, b, "\033[34m()\033[0m"); break;
90
case QUESTION_MARK: mvprint(a, b, "\033[34m??\033[0m"); break;
91
case EXCLAMATION_MARK: mvprint(a, b, "\033[34m!!\033[0m"); break;
92
case WALL: mvprint(a, b, "\033[31m##\033[0m"); break;
93
case BLANK: mvprint(a, b, " "); break;
94
case CELL:
95
mvprint(a-1, b, "__");
96
mvprint(a, b-1, "/ \\");
97
mvprint(a+1, b-1, "\\__/");
98
break;
99
default: break; // CURSOR
100
}
101
a = 5 - cur_x + 2 * cur_y;
102
b = 3 * cur_x + 1;
103
cursor_goto(a, b);
104
}
105
106
#ifdef DEBUG
107
void dump()
108
{
109
for (int y = 0; y < 17; ++y) {
110
for (int x = 0; x < 17; ++x) {
111
if (honeycomb[x][y] == 0)
112
fputc(' ', logfile);
113
else
114
fprintf(logfile, "%d", honeycomb[x][y]);
115
}
116
fputc('\n', logfile);
117
}
118
fputc('\n', logfile);
119
fflush(logfile);
120
}
121
#endif
122
123
int escape()
124
{
125
Sleep(300);
126
127
// bfs
128
int qx[LEN], qy[LEN]; // queue
129
int front = 0, rear = 0;
130
int next_x, next_y;
131
const int dxs[6] = {-1, -1, 0, 0, 1, 1};
132
const int dys[6] = {-1, 0, -1, 1, 0, 1};
133
bool found = false;
134
// enqueue
135
qx[rear] = ball_x;
136
qy[rear] = ball_y;
137
rear = (rear+1) % LEN;
138
while (!found && front != rear) {
139
// dequeue
140
int x = qx[front];
141
int y = qy[front];
142
front = (front+1) % LEN;
143
for (int i = 0; i < 6; ++i) {
144
x += dxs[i];
145
y += dys[i];
146
if (!isvalid(x, y)) {
147
x -= dxs[i];
148
y -= dys[i];
149
if (x == ball_x && y == ball_y) {
150
print_cell(x, y, EXCLAMATION_MARK);
151
return LOSE;
152
}
153
found = true;
154
while (honeycomb[x][y] != BALL) {
155
int j = honeycomb[x][y]-VISITED;
156
next_x = x;
157
next_y = y;
158
x += dxs[j];
159
y += dys[j];
160
}
161
break;
162
} else if (honeycomb[x][y] == BLANK) {
163
// reverse direction
164
honeycomb[x][y] = VISITED+5-i;
165
// enqueue
166
qx[rear] = x;
167
qy[rear] = y;
168
rear = (rear+1) % LEN;
169
}
170
x -= dxs[i];
171
y -= dys[i];
172
}
173
}
174
for (int x = 0; x < 17; ++x)
175
for (int y = 0; y < 17; ++y)
176
if (honeycomb[x][y] >= VISITED)
177
honeycomb[x][y] = BLANK;
178
if (found) {
179
honeycomb[ball_x][ball_y] = BLANK;
180
print_cell(ball_x, ball_y, BLANK);
181
ball_x = next_x; ball_y = next_y;
182
honeycomb[ball_x][ball_y] = BALL;
183
print_cell(ball_x, ball_y, BALL);
184
return PLAYING;
185
} else {
186
print_cell(ball_x, ball_y, QUESTION_MARK);
187
return WIN;
188
}
189
}
190
191
void move_cursor(int dx, int dy)
192
{
193
if (isvalid(cur_x + dx, cur_y + dy)) {
194
cur_x += dx, cur_y += dy;
195
print_cell(cur_x, cur_y, CURSOR);
196
}
197
}
198
199
int move_wall(int dx, int dy)
200
{
201
int *from = &honeycomb[cur_x][cur_y];
202
int *to = &honeycomb[cur_x + dx][cur_y + dy];
203
if (isvalid(cur_x + dx, cur_y + dy)
204
&& *from == WALL && *to == BLANK) {
205
print_cell(cur_x, cur_y, *from = BLANK);
206
cur_x += dx, cur_y += dy;
207
print_cell(cur_x, cur_y, *to = WALL);
208
return escape();
209
}
210
return PLAYING;
211
}
212
213
bool init(char *filename)
214
{
215
FILE *f = fopen(filename, "r");
216
if (!f)
217
return false;
218
// set title
219
fgets(title, BUFLEN, f);
220
221
// set global varibles
222
cur_x = cur_y = 8;
223
memset(honeycomb, BLANK, sizeof(int)*17*17);
224
225
// the ball
226
fscanf(f, "%d %d", &ball_x, &ball_y);
227
honeycomb[ball_x][ball_y] = BALL;
228
229
// walls
230
int x, y;
231
while (fscanf(f, "%d %d", &x, &y) == 2)
232
honeycomb[x][y] = WALL;
233
234
fclose(f);
235
return true;
236
}
237
238
void print_map()
239
{
240
for (int x = 0; x < 17; ++x)
241
for (int y = 0; y < 17; ++y)
242
if (isvalid(x, y)) {
243
int type = honeycomb[x][y];
244
print_cell(x, y, CELL);
245
if (type != BLANK)
246
print_cell(x, y, type);
247
}
248
print_cell(cur_x, cur_y, CURSOR);
249
}
250
251
int play()
252
{
253
int status = PLAYING;
254
int ch;
255
while (status == PLAYING) {
256
ch = getch();
257
switch (ch) {
258
case 'u': move_cursor(-1, -1); break;
259
case 'i': move_cursor(0, -1); break;
260
case 'o': move_cursor(1, 0); break;
261
case 'j': move_cursor(-1, 0); break;
262
case 'k': move_cursor(0, 1); break;
263
case 'l': move_cursor(1, 1); break;
264
265
case 'U': status = move_wall(-1, -1); break;
266
case 'I': status = move_wall(0, -1); break;
267
case 'O': status = move_wall(1, 0); break;
268
case 'J': status = move_wall(-1, 0); break;
269
case 'K': status = move_wall(0, 1); break;
270
case 'L': status = move_wall(1, 1); break;
271
272
case EOF: case 4: status = QUIT; break; // ctrl-d
273
case 'r': status = LOSE; break; // restart
274
}
275
}
276
return status;
277
}
278
279
int main(int argc, char **argv)
280
{
281
#ifdef DEBUG
282
// logfile
283
logfile = fopen("log", "w");
284
if (!logfile) return 0;
285
#endif
286
287
int i = 1;
288
if (argc == 2) {
289
if (strcmp(argv[1], "-h") == 0) {
290
help();
291
return 0;
292
} else if ((i = atoi(argv[1])) <= 0) {
293
i = 1;
294
}
295
}
296
screen_clear();
297
char buf[BUFLEN];
298
while (true) {
299
sprintf(buf, "level/%02d.level", i);
300
if (!init(buf))
301
break;
302
cursor_goto(27, 0);
303
line_clear();
304
printf("Lv %d: %s", i, title);
305
print_map();
306
int status = play();
307
if (status == WIN) {
308
fflush(stdout);
309
Sleep(500);
310
++i;
311
} else if (status == LOSE) {
312
fflush(stdout);
313
Sleep(500);
314
} else if (status == QUIT) {
315
break;
316
}
317
}
318
cursor_goto(28, 0);
319
320
#ifdef DEBUG
321
fclose(logfile);
322
#endif
323
return 0;
324
}
325
326