File Coverage

blib/lib/Games/Roguelike/Utils/Pov_C.pm
Criterion Covered Total %
statement 4 6 66.6
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 6 8 75.0


line stmt bran cond sub pod time code
1             package Games::Roguelike::Utils::Pov_C;
2              
3             # broken undil perl 5.8
4             # use Exporter qw(import);
5              
6             BEGIN {
7 5     5   32 require Exporter;
8 5         18 *{import} = \&Exporter::import;
9 5         507 our @EXPORT = qw(checkpov_c distance findclose_c);
10             }
11              
12             our $VERSION = '0.4.' . [qw$Revision: 236 $]->[1];
13              
14 5     5   2450 use Inline C => <<'END_C';
  0            
  0            
15              
16             #include
17              
18             #define printf PerlIO_stdoutf
19              
20             AV * mapav(SV *mapr) {
21             AV *map;
22             // SV **v;
23             if (SvTYPE(mapr) != SVt_RV)
24             croak("map must be a reference");
25              
26             mapr = SvRV(mapr);
27             if (SvTYPE(mapr) != SVt_PVAV)
28             croak("map must be an array ref");
29              
30             map = (AV*) mapr;
31              
32             // v = av_fetch((AV *) map, 0, 0);
33             // if (!v || SvTYPE(*v) != SVt_RV || (SvTYPE(SvRV(*v)) != SVt_PVAV)) {
34             // croak("map should be doubly-indexed array");
35             // }
36             return map;
37             }
38              
39             double distance(int x1, int y1, int x2, int y2) {
40             return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
41             }
42              
43             int hv_int(HV *h, char *k, U32 klen, int errv) {
44             SV ** svp = hv_fetch(h, k, klen, 0);
45             if (svp) return SvIV(*svp);
46             return errv;
47             }
48              
49             SV * hv_sv(HV *h, char *k, U32 klen) {
50             SV ** svp = hv_fetch(h, k, klen, 0);
51             if (svp) return *svp;
52             return NULL;
53             }
54              
55              
56             char mapat(AV *map, int x, int y) {
57             SV **v;
58             v = av_fetch(map, (I32) x, 0); if (!v) return 0;
59             v = av_fetch((AV *) SvRV(*v), (I32) y, 0); if (!v) return 0;
60             if (SvTYPE(*v) == SVt_PVHV) {
61             v = hv_fetch((HV *) v, "sym", 3, 0);
62             if (!v) return 0;
63             }
64             if (!SvPOK(*v)) croak("not a string %d, %d", x, y);
65             char *pc = SvPVX(*v);
66             if (pc) return *pc;
67             return 0;
68              
69             }
70              
71             int checkpov_c(int vx, int vy, int rx, int ry, SV *mapr, char *blocksyms, bool debug) {
72             AV * map = mapav(mapr);
73             if (!map) return 0;
74             double dist = distance(vx, vy, rx, ry);
75             double dx = rx-vx;
76             double dy = ry-vy;
77              
78             char ok[4];
79             memset(ok, 1, 4);
80             double i;
81             for (i = 1; i <= dist; i+=0.5) {
82             double tx = vx+(i/dist)*dx; // delta-fraction of distance
83             double ty = vy+(i/dist)*dy;
84              
85             double x[4];
86             double y[4];
87              
88             x[0] = (0.1+tx); // not quite the corners
89             y[0] = (0.1+ty);
90             x[1] = (0.9+tx);
91             y[1] = (0.9+ty);
92             x[2] = (0.9+tx);
93             y[2] = (0.1+ty);
94             x[3] = (0.1+tx);
95             y[3] = (0.9+ty);
96              
97             int j;
98             for (j = 0; j < 4; ++j) {
99             if (!ok[j]) continue;
100             if ((((int)x[j]) == rx) && (((int)y[j]) == ry)) {
101             if (debug) printf("%.1f: sub %d: %f,%f SAME\n",i,j,x[j],y[j]);
102             continue;
103             }
104             if (dx != 0 && dy != 0 && (fabs(dx/dy) > 0.1) && (fabs(dy/dx) > 0.1)) {
105             // allow peeking around corners if target is near the edge
106             if (lround(x[j]) == rx && lround(y[j]) == ry && i >= (dist-1)) {
107             if (debug) printf("%.1f: sub %d: %f,%f PEEK\n",i,j,x[j],y[j]);
108             continue;
109             }
110             }
111             if (strchr(blocksyms,mapat(map, x[j],y[j]))) {
112             if (debug) printf("%.1f: sub %d: %f,%f WALL\n",i,j,x[j],y[j]);
113             ok[j] = 0;
114             } else {
115             if (debug) printf("%.1f: sub %d: %f,%f OK\n",i,j,x[j],y[j]);
116             }
117             }
118             if (!ok[0] && !ok[1] && !ok[2] && !ok[3]) {
119             return 0;
120             }
121             }
122             return 1;
123             }
124              
125             #define MAXP 1024
126             typedef struct {int x;int y;} point;
127              
128             point f[MAXP];
129             point DD[9] = {{0,-1},{0,1},{1,0},{-1,0},{1,-1},{1,1},{-1,-1},{-1,1},{0,0}};
130              
131             void findclose_c (SV *r, int x1, int y1, int x2, int y2) {
132             if (SvTYPE(r) != SVt_RV) croak("world must be a ref");
133             r = SvRV(r);
134             if (SvTYPE(r) != SVt_PVHV) croak("world must be a hash ref");
135             int w = hv_int((HV *) r, "w", 1, 0);
136             int h = hv_int((HV *) r, "h", 1, 0);
137             if (!w || !h) croak("world must have w & h");
138              
139             SV * mapr = hv_sv((HV *)r, "m", 1);
140             if (!mapr) croak("world must have map m");
141             AV * map = mapav(mapr);
142             if (!map) croak("world must have array ref map m");
143              
144             bool bread[w*h]; memset(bread, 0, sizeof(bool)*w*h);
145              
146             // flood fill return closest you can get to x2/y2 without going thru a barrier
147              
148             int p = 0; f[p].x=x1; f[p].y=y1;
149             int mindist = distance(x1, y1, x2, y2);
150             int tx, ty;
151             point c = {x1, y1};
152             while (p >= 0) {
153             int d;
154             c = f[p--];
155             for (d = 0; d < 8; ++d) {
156             tx = DD[d].x+c.x;
157             ty = DD[d].y+c.y;
158             char sym = mapat(map, tx, ty);
159             printf("%c", sym);
160             if (sym == '#' || !sym) continue;
161             if (tx < 0 || ty <0|| tx > w || ty >h) continue;
162             if (bread[ty*w+tx]) continue;
163             bread[ty*w+tx]=1;
164             if (tx == x2 && ty == y2) break;
165             int td;
166             if ((td = distance(tx, ty, x2, y2)) < mindist) {
167             c.x=tx;
168             c.y=ty;
169             }
170             if (p >= MAXP) croak("path is too long");
171             f[++p].x=tx; f[p].y=ty;
172             }
173             if (tx == x2 && ty == y2) break;
174             }
175             Inline_Stack_Vars;
176             Inline_Stack_Reset;
177             Inline_Stack_Push(newSViv(c.x));
178             Inline_Stack_Push(newSViv(c.y));
179             Inline_Stack_Push(newSViv(mindist));
180             Inline_Stack_Done;
181             Inline_Stack_Return(3);
182             }
183              
184             END_C
185              
186             1;