File Coverage

lib/Game/Xomb.xs
Criterion Covered Total %
statement 100 100 100.0
branch 55 72 76.3
condition n/a
subroutine n/a
pod n/a
total 155 172 90.1


line stmt bran cond sub pod time code
1             /* Xomb.xs - line drawing and random number generation utility functions */
2              
3             #define PERL_NO_GET_CONTEXT
4              
5             #include "EXTERN.h"
6             #include "perl.h"
7             #include "XSUB.h"
8              
9             #include "ppport.h"
10              
11             #include "jsf.h"
12              
13             /* NOTE these MUST be kept in sync with similar in Xomb.pm */
14             #define MAP_COLS 78
15             #define MAP_ROWS 22
16              
17             MODULE = Game::Xomb PACKAGE = Game::Xomb
18             PROTOTYPES: DISABLE
19              
20             void
21             bypair (callback, ...)
22             SV *callback;
23             PREINIT:
24             int i;
25             SV *x, *y;
26             PPCODE:
27 3 100         if (!(items & 1)) croak("uneven number of arguments");
28             dSP;
29 5 100         for (i = 1; i < items; i += 2) {
30 3           x = ST(i);
31 3           y = ST(i + 1);
32 3           ENTER;
33 3           SAVETMPS;
34 3 50         PUSHMARK(SP);
35 3 50         EXTEND(SP, 2);
36 3           PUSHs(x);
37 3           PUSHs(y);
38 3           PUTBACK;
39 3           call_sv(callback, G_DISCARD);
40 3           SPAGAIN;
41 3 50         FREETMPS;
42 3           LEAVE;
43             }
44              
45             UV
46             coinflip ()
47             CODE:
48 10000           RETVAL = ranval() & 1;
49             OUTPUT:
50             RETVAL
51              
52             # NOTE this distance differs from the iters count in linecb() as that
53             # function can do [0,0] .. [3,3] in 3 steps while this will calculate
54             # 4.24, lround'd to 4
55             UV
56             distance (uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1)
57             PREINIT:
58             int dx, dy;
59             CODE:
60 47           dx = x1 - x0;
61 47           dy = y1 - y0;
62 47           RETVAL = lround(sqrt(dx*dx + dy*dy));
63             OUTPUT:
64             RETVAL
65              
66             # splice a random element out of an array reference
67             # NOTE this does not preserve the order of the array as that requires a
68             # series of copies anytime an item is extracted from not the end which
69             # for large lists will be most of the time (previous versions of this
70             # code did such a waterfall copy)
71             SV *
72             extract (avref)
73             AV *avref;
74             PREINIT:
75             SSize_t i, len, rnd;
76             SV *dunno, **swap;
77             CODE:
78 182           len = av_len(avref) + 1;
79 182 100         if (len == 0) XSRETURN_UNDEF;
80 181           rnd = ranval() % len;
81 181           dunno = av_delete(avref, rnd, 0);
82 181 100         if (rnd != len - 1) {
83 172           swap = av_fetch(avref, len - 1, FALSE);
84 172           av_store(avref, rnd, *swap);
85 172           AvFILLp(avref) -= 1;
86 172           AvMAX(avref) -= 1;
87             }
88             SvREFCNT_inc(dunno);
89             RETVAL = dunno;
90             OUTPUT:
91             RETVAL
92              
93             # init_jsf - setup the RNG (see src/jsf.*)
94             void
95             init_jsf (seed)
96             UV seed
97             PPCODE:
98 106           raninit(seed);
99              
100             UV
101             irand (uint32_t max)
102             CODE:
103 11892           RETVAL = ranval() % max;
104             OUTPUT:
105             RETVAL
106              
107             # linecb - Bresenham with some features to keep it from going off of
108             # the map and to skip the first point and abort should the callback
109             # return -1
110             void
111             linecb (callback, int x0, int y0, int x1, int y1)
112             SV *callback;
113             PREINIT:
114             int answer, dx, dy, err, e2, sx, sy, online, iters;
115             PPCODE:
116 36           dSP;
117 36           dx = abs(x1 - x0);
118 36           dy = abs(y1 - y0);
119 36 100         sx = x0 < x1 ? 1 : -1;
120 36 100         sy = y0 < y1 ? 1 : -1;
121 36 100         err = (dx > dy ? dx : -dy) / 2;
122             iters = 0;
123             online = 0;
124             while (1) {
125 1047 100         if (x0 < 0 || x0 >= MAP_COLS || y0 < 0 || y0 >= MAP_ROWS) break;
    50          
126 1046 100         if (online) {
127 1010           ENTER;
128 1010           SAVETMPS;
129 1010 50         PUSHMARK(SP);
130 1010 50         EXTEND(SP, 3);
131 1010           mPUSHs(newSViv(x0));
132 1010           mPUSHs(newSViv(y0));
133 1010           mPUSHs(newSViv(iters));
134 1010           PUTBACK;
135 1010           call_sv(callback, G_SCALAR);
136 1010           SPAGAIN;
137 1010 100         answer = POPi;
138 1010 50         FREETMPS;
139 1010           LEAVE;
140 1010 100         if (answer == -1) break;
141             }
142 1045 100         if (x0 == x1 && y0 == y1) break;
143             e2 = err;
144 1011 100         if (e2 > -dx) {
145 976           err -= dy;
146 976           x0 += sx;
147             }
148 1011 100         if (e2 < dy) {
149 255           err += dx;
150 255           y0 += sy;
151             }
152             online = 1;
153 1011           iters++;
154 1011           }
155              
156             UV
157             onein (uint32_t N)
158             CODE:
159 378           RETVAL = 0 == ranval() % N;
160             OUTPUT:
161             RETVAL
162              
163             UV
164             roll (uint32_t count, uint32_t sides)
165             PREINIT:
166             uint32_t sum;
167             CODE:
168             sum = count;
169 96 100         while (count--) sum += ranval() % sides;
170 30           RETVAL = sum;
171             OUTPUT:
172             RETVAL
173              
174             # pick a random element of an array ref
175             SV *
176             pick (avref)
177             AV *avref;
178             PREINIT:
179             SSize_t len, rnd;
180             SV **svp;
181             CODE:
182 7889           len = av_len(avref) + 1;
183 7889 100         if (len == 0) XSRETURN_UNDEF;
184 7888           rnd = ranval() % len;
185 7888           svp = av_fetch(avref, rnd, FALSE);
186 7888           SvREFCNT_inc(*svp);
187 7888           RETVAL = *svp;
188             OUTPUT:
189             RETVAL
190              
191             # walkcb - linecb, but does not stop at x1,y1. used by Trolls to find
192             # what gets busted, which may or may not be the player
193             void
194             walkcb (callback, int x0, int y0, int x1, int y1)
195             SV *callback;
196             PREINIT:
197             int answer, dx, dy, err, e2, sx, sy, online, iters;
198             PPCODE:
199 2           dSP;
200 2           dx = abs(x1 - x0);
201 2           dy = abs(y1 - y0);
202 2 50         sx = x0 < x1 ? 1 : -1;
203 2 50         sy = y0 < y1 ? 1 : -1;
204 2 50         err = (dx > dy ? dx : -dy) / 2;
205             iters = 0;
206             online = 0;
207             while (1) {
208 8 100         if (x0 < 0 || x0 >= MAP_COLS || y0 < 0 || y0 >= MAP_ROWS) break;
    50          
209 7 100         if (online) {
210 5           ENTER;
211 5           SAVETMPS;
212 5 50         PUSHMARK(SP);
213 5 50         EXTEND(SP, 3);
214 5           mPUSHs(newSViv(x0));
215 5           mPUSHs(newSViv(y0));
216 5           mPUSHs(newSViv(iters));
217 5           PUTBACK;
218 5           call_sv(callback, G_SCALAR);
219 5           SPAGAIN;
220 5 50         answer = POPi;
221 5 50         FREETMPS;
222 5           LEAVE;
223 5 100         if (answer == -1) break;
224             }
225             e2 = err;
226 6 50         if (e2 > -dx) {
227 6           err -= dy;
228 6           x0 += sx;
229             }
230 6 50         if (e2 < dy) {
231 6           err += dx;
232 6           y0 += sy;
233             }
234             online = 1;
235 6           iters++;
236 6           }