File Coverage

lib/Term/Maze.xs
Criterion Covered Total %
statement 0 128 0.0
branch 0 82 0.0
condition n/a
subroutine n/a
pod n/a
total 0 210 0.0


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