| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
#include "EXTERN.h" |
|
2
|
|
|
|
|
|
|
#include "perl.h" |
|
3
|
|
|
|
|
|
|
#include "XSUB.h" |
|
4
|
|
|
|
|
|
|
#include |
|
5
|
|
|
|
|
|
|
#include |
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
#define WALL '#' |
|
8
|
|
|
|
|
|
|
#define PATH ' ' |
|
9
|
|
|
|
|
|
|
#define START 'S' |
|
10
|
|
|
|
|
|
|
#define END 'E' |
|
11
|
|
|
|
|
|
|
#define PLAYER '@' |
|
12
|
|
|
|
|
|
|
|
|
13
|
0
|
|
|
|
|
|
static int hv_get_int(HV *hv, const char *key) { |
|
14
|
0
|
|
|
|
|
|
SV **svp = hv_fetch(hv, key, strlen(key), 0); |
|
15
|
0
|
0
|
|
|
|
|
return svp ? SvIV(*svp) : 0; |
|
16
|
|
|
|
|
|
|
} |
|
17
|
|
|
|
|
|
|
|
|
18
|
0
|
|
|
|
|
|
static char* av_get_str(AV *av, int index) { |
|
19
|
0
|
|
|
|
|
|
SV **svp = av_fetch(av, index, 0); |
|
20
|
0
|
0
|
|
|
|
|
return svp ? SvPV_nolen(*svp) : NULL; |
|
21
|
|
|
|
|
|
|
} |
|
22
|
|
|
|
|
|
|
|
|
23
|
0
|
|
|
|
|
|
static void hv_set_int(HV *hv, const char *key, int val) { |
|
24
|
0
|
|
|
|
|
|
hv_store(hv, key, strlen(key), newSViv(val), 0); |
|
25
|
0
|
|
|
|
|
|
} |
|
26
|
|
|
|
|
|
|
|
|
27
|
0
|
|
|
|
|
|
static AV* hv_get_av(HV *hv, const char *key) { |
|
28
|
0
|
|
|
|
|
|
SV **svp = hv_fetch(hv, key, strlen(key), 0); |
|
29
|
0
|
0
|
|
|
|
|
return (svp && SvROK(*svp) && SvTYPE(SvRV(*svp)) == SVt_PVAV) ? (AV*)SvRV(*svp) : NULL; |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
} |
|
31
|
|
|
|
|
|
|
|
|
32
|
0
|
|
|
|
|
|
static void hv_set_av(HV *hv, const char *key, AV *av) { |
|
33
|
0
|
|
|
|
|
|
hv_store(hv, key, strlen(key), newRV_noinc((SV*)av), 0); |
|
34
|
0
|
|
|
|
|
|
} |
|
35
|
|
|
|
|
|
|
|
|
36
|
0
|
|
|
|
|
|
static void carve(HV *hv, int x, int y) { |
|
37
|
0
|
|
|
|
|
|
int width = hv_get_int(hv, "width"); |
|
38
|
0
|
|
|
|
|
|
int height = hv_get_int(hv, "height"); |
|
39
|
0
|
|
|
|
|
|
AV *maze = hv_get_av(hv, "maze"); |
|
40
|
0
|
|
|
|
|
|
int dirs[4][2] = { {0,-1}, {1,0}, {0,1}, {-1,0} }; |
|
41
|
0
|
0
|
|
|
|
|
for (int i = 0; i < 4; ++i) { |
|
42
|
0
|
|
|
|
|
|
int j = rand() % 4; |
|
43
|
0
|
|
|
|
|
|
int tmp0 = dirs[i][0], tmp1 = dirs[i][1]; |
|
44
|
0
|
|
|
|
|
|
dirs[i][0] = dirs[j][0]; |
|
45
|
0
|
|
|
|
|
|
dirs[i][1] = dirs[j][1]; |
|
46
|
0
|
|
|
|
|
|
dirs[j][0] = tmp0; |
|
47
|
0
|
|
|
|
|
|
dirs[j][1] = tmp1; |
|
48
|
|
|
|
|
|
|
} |
|
49
|
0
|
|
|
|
|
|
char *row = av_get_str(maze, y); |
|
50
|
0
|
|
|
|
|
|
row[x] = PATH; |
|
51
|
0
|
0
|
|
|
|
|
for (int i = 0; i < 4; ++i) { |
|
52
|
0
|
|
|
|
|
|
int dx = dirs[i][0], dy = dirs[i][1]; |
|
53
|
0
|
|
|
|
|
|
int nx = x + 2*dx, ny = y + 2*dy; |
|
54
|
0
|
0
|
|
|
|
|
if (nx > 0 && nx < width-1 && ny > 0 && ny < height-1) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
55
|
0
|
|
|
|
|
|
char *nrow = av_get_str(maze, ny); |
|
56
|
0
|
0
|
|
|
|
|
if (nrow[nx] == WALL) { |
|
57
|
0
|
|
|
|
|
|
char *midrow = av_get_str(maze, y+dy); |
|
58
|
0
|
|
|
|
|
|
midrow[x+dx] = PATH; |
|
59
|
0
|
|
|
|
|
|
carve(hv, nx, ny); |
|
60
|
|
|
|
|
|
|
} |
|
61
|
|
|
|
|
|
|
} |
|
62
|
|
|
|
|
|
|
} |
|
63
|
0
|
|
|
|
|
|
} |
|
64
|
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
MODULE = Term::Maze PACKAGE = Term::Maze PREFIX = maze_ |
|
66
|
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
SV* |
|
68
|
|
|
|
|
|
|
maze_new(class, width_in, height_in) |
|
69
|
|
|
|
|
|
|
char *class |
|
70
|
|
|
|
|
|
|
int width_in |
|
71
|
|
|
|
|
|
|
int height_in |
|
72
|
|
|
|
|
|
|
PREINIT: |
|
73
|
|
|
|
|
|
|
HV *hv; |
|
74
|
|
|
|
|
|
|
AV *maze; |
|
75
|
|
|
|
|
|
|
int width, height, i, j; |
|
76
|
|
|
|
|
|
|
CODE: |
|
77
|
0
|
0
|
|
|
|
|
width = (width_in % 2 == 0) ? width_in+1 : width_in; |
|
78
|
0
|
0
|
|
|
|
|
height = (height_in % 2 == 0) ? height_in+1 : height_in; |
|
79
|
0
|
|
|
|
|
|
hv = newHV(); |
|
80
|
0
|
|
|
|
|
|
maze = newAV(); |
|
81
|
0
|
0
|
|
|
|
|
for (i = 0; i < height; ++i) { |
|
82
|
0
|
|
|
|
|
|
SV *row = newSVpv("", width); |
|
83
|
0
|
0
|
|
|
|
|
SvGROW(row, width+1); |
|
|
|
0
|
|
|
|
|
|
|
84
|
0
|
|
|
|
|
|
char *s = SvPV_nolen(row); |
|
85
|
0
|
0
|
|
|
|
|
for (j = 0; j < width; ++j) |
|
86
|
0
|
|
|
|
|
|
s[j] = WALL; |
|
87
|
0
|
|
|
|
|
|
s[width] = '\0'; |
|
88
|
0
|
|
|
|
|
|
SvCUR_set(row, width); |
|
89
|
0
|
|
|
|
|
|
av_push(maze, row); |
|
90
|
|
|
|
|
|
|
} |
|
91
|
0
|
|
|
|
|
|
hv_set_int(hv, "width", width); |
|
92
|
0
|
|
|
|
|
|
hv_set_int(hv, "height", height); |
|
93
|
0
|
|
|
|
|
|
hv_set_int(hv, "px", 1); |
|
94
|
0
|
|
|
|
|
|
hv_set_int(hv, "py", 1); |
|
95
|
0
|
|
|
|
|
|
hv_set_av(hv, "maze", maze); |
|
96
|
0
|
|
|
|
|
|
carve(hv, 1, 1); |
|
97
|
0
|
|
|
|
|
|
char *start_row = av_get_str(maze, 1); |
|
98
|
0
|
0
|
|
|
|
|
if (start_row) start_row[1] = START; |
|
99
|
0
|
|
|
|
|
|
char *end_row = av_get_str(maze, height-2); |
|
100
|
0
|
0
|
|
|
|
|
if (end_row) end_row[width-2] = END; |
|
101
|
0
|
|
|
|
|
|
RETVAL = sv_bless(newRV_noinc((SV*)hv), gv_stashpv(class, GV_ADD)); |
|
102
|
|
|
|
|
|
|
OUTPUT: |
|
103
|
|
|
|
|
|
|
RETVAL |
|
104
|
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
void |
|
106
|
|
|
|
|
|
|
maze_move_player(self, direction) |
|
107
|
|
|
|
|
|
|
SV *self |
|
108
|
|
|
|
|
|
|
char direction |
|
109
|
|
|
|
|
|
|
PREINIT: |
|
110
|
|
|
|
|
|
|
HV *hv; |
|
111
|
0
|
|
|
|
|
|
int dx = 0, dy = 0; |
|
112
|
|
|
|
|
|
|
int nx, ny, width, height; |
|
113
|
|
|
|
|
|
|
AV *maze; |
|
114
|
|
|
|
|
|
|
CODE: |
|
115
|
0
|
|
|
|
|
|
hv = (HV*)SvRV(self); |
|
116
|
0
|
|
|
|
|
|
int px = hv_get_int(hv, "px"); |
|
117
|
0
|
|
|
|
|
|
int py = hv_get_int(hv, "py"); |
|
118
|
0
|
|
|
|
|
|
width = hv_get_int(hv, "width"); |
|
119
|
0
|
|
|
|
|
|
height = hv_get_int(hv, "height"); |
|
120
|
0
|
|
|
|
|
|
maze = hv_get_av(hv, "maze"); |
|
121
|
0
|
|
|
|
|
|
switch (direction) { |
|
122
|
0
|
|
|
|
|
|
case 'w': dy = -1; break; |
|
123
|
0
|
|
|
|
|
|
case 'a': dx = -1; break; |
|
124
|
0
|
|
|
|
|
|
case 's': dy = 1; break; |
|
125
|
0
|
|
|
|
|
|
case 'd': dx = 1; break; |
|
126
|
0
|
|
|
|
|
|
case 'h': dx = -1; break; |
|
127
|
0
|
|
|
|
|
|
case 'j': dy = 1; break; |
|
128
|
0
|
|
|
|
|
|
case 'k': dy = -1; break; |
|
129
|
0
|
|
|
|
|
|
case 'l': dx = 1; break; |
|
130
|
0
|
|
|
|
|
|
default: XSRETURN_EMPTY; |
|
131
|
|
|
|
|
|
|
} |
|
132
|
0
|
|
|
|
|
|
nx = px + dx; |
|
133
|
0
|
|
|
|
|
|
ny = py + dy; |
|
134
|
0
|
0
|
|
|
|
|
if (nx >= 0 && nx < width && ny >= 0 && ny < height) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
135
|
0
|
|
|
|
|
|
SV **svp = av_fetch(maze, ny, 0); |
|
136
|
0
|
0
|
|
|
|
|
if (svp) { |
|
137
|
0
|
|
|
|
|
|
char *row = SvPV_nolen(*svp); |
|
138
|
0
|
0
|
|
|
|
|
if (row[nx] != WALL) { |
|
139
|
0
|
|
|
|
|
|
hv_set_int(hv, "px", nx); |
|
140
|
0
|
|
|
|
|
|
hv_set_int(hv, "py", ny); |
|
141
|
|
|
|
|
|
|
} |
|
142
|
|
|
|
|
|
|
} |
|
143
|
|
|
|
|
|
|
} |
|
144
|
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
AV * |
|
146
|
|
|
|
|
|
|
maze_get_maze_with_player(self) |
|
147
|
|
|
|
|
|
|
SV *self |
|
148
|
|
|
|
|
|
|
PREINIT: |
|
149
|
|
|
|
|
|
|
HV *hv; |
|
150
|
|
|
|
|
|
|
int i, j, width, height, px, py; |
|
151
|
|
|
|
|
|
|
AV *maze, *rows; |
|
152
|
|
|
|
|
|
|
char *row, *src; |
|
153
|
|
|
|
|
|
|
CODE: |
|
154
|
0
|
|
|
|
|
|
hv = (HV*)SvRV(self); |
|
155
|
0
|
|
|
|
|
|
width = hv_get_int(hv, "width"); |
|
156
|
0
|
|
|
|
|
|
height = hv_get_int(hv, "height"); |
|
157
|
0
|
|
|
|
|
|
px = hv_get_int(hv, "px"); |
|
158
|
0
|
|
|
|
|
|
py = hv_get_int(hv, "py"); |
|
159
|
0
|
|
|
|
|
|
maze = hv_get_av(hv, "maze"); |
|
160
|
0
|
|
|
|
|
|
rows = newAV(); |
|
161
|
0
|
0
|
|
|
|
|
for (i = 0; i < height; ++i) { |
|
162
|
0
|
|
|
|
|
|
SV **svp = av_fetch(maze, i, 0); |
|
163
|
0
|
0
|
|
|
|
|
src = svp ? SvPV_nolen(*svp) : NULL; |
|
164
|
0
|
|
|
|
|
|
row = (char *)malloc(width * 16 + 1); |
|
165
|
0
|
|
|
|
|
|
int pos = 0; |
|
166
|
0
|
0
|
|
|
|
|
for (j = 0; j < width; ++j) { |
|
167
|
0
|
0
|
|
|
|
|
if (i == py && j == px) { |
|
|
|
0
|
|
|
|
|
|
|
168
|
0
|
|
|
|
|
|
pos += sprintf(row + pos, "\033[34m%c\033[0m", PLAYER); |
|
169
|
0
|
0
|
|
|
|
|
} else if (src && src[j] == WALL) { |
|
|
|
0
|
|
|
|
|
|
|
170
|
0
|
|
|
|
|
|
pos += sprintf(row + pos, "\033[31m%c\033[0m", WALL); |
|
171
|
0
|
0
|
|
|
|
|
} else if (src && (src[j] == START || src[j] == END)) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
172
|
0
|
|
|
|
|
|
pos += sprintf(row + pos, "\033[32m%c\033[0m", src[j]); |
|
173
|
0
|
0
|
|
|
|
|
} else if (src) { |
|
174
|
0
|
|
|
|
|
|
row[pos++] = src[j]; |
|
175
|
|
|
|
|
|
|
} else { |
|
176
|
0
|
|
|
|
|
|
row[pos++] = ' '; |
|
177
|
|
|
|
|
|
|
} |
|
178
|
|
|
|
|
|
|
} |
|
179
|
0
|
|
|
|
|
|
row[pos] = '\0'; |
|
180
|
0
|
|
|
|
|
|
av_push(rows, newSVpv(row, 0)); |
|
181
|
0
|
|
|
|
|
|
free(row); |
|
182
|
|
|
|
|
|
|
} |
|
183
|
0
|
|
|
|
|
|
RETVAL = rows; |
|
184
|
|
|
|
|
|
|
OUTPUT: |
|
185
|
|
|
|
|
|
|
RETVAL |
|
186
|
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
int |
|
188
|
|
|
|
|
|
|
maze_at_exit(self) |
|
189
|
|
|
|
|
|
|
SV *self |
|
190
|
|
|
|
|
|
|
PREINIT: |
|
191
|
|
|
|
|
|
|
HV *hv; |
|
192
|
|
|
|
|
|
|
int px, py; |
|
193
|
|
|
|
|
|
|
AV *maze; |
|
194
|
|
|
|
|
|
|
int width, height; |
|
195
|
|
|
|
|
|
|
CODE: |
|
196
|
0
|
|
|
|
|
|
hv = (HV*)SvRV(self); |
|
197
|
0
|
|
|
|
|
|
px = hv_get_int(hv, "px"); |
|
198
|
0
|
|
|
|
|
|
py = hv_get_int(hv, "py"); |
|
199
|
0
|
|
|
|
|
|
maze = hv_get_av(hv, "maze"); |
|
200
|
0
|
|
|
|
|
|
width = hv_get_int(hv, "width"); |
|
201
|
0
|
|
|
|
|
|
height = hv_get_int(hv, "height"); |
|
202
|
0
|
0
|
|
|
|
|
if (maze && py >= 0 && py < height) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
203
|
0
|
|
|
|
|
|
SV **svp = av_fetch(maze, py, 0); |
|
204
|
0
|
0
|
|
|
|
|
if (svp) { |
|
205
|
0
|
|
|
|
|
|
char *row = SvPV_nolen(*svp); |
|
206
|
0
|
|
|
|
|
|
RETVAL = (row[px] == END); |
|
207
|
|
|
|
|
|
|
} else { |
|
208
|
0
|
|
|
|
|
|
RETVAL = 0; |
|
209
|
|
|
|
|
|
|
} |
|
210
|
|
|
|
|
|
|
} else { |
|
211
|
0
|
|
|
|
|
|
RETVAL = 0; |
|
212
|
|
|
|
|
|
|
} |
|
213
|
|
|
|
|
|
|
OUTPUT: |
|
214
|
|
|
|
|
|
|
RETVAL |