Mercurial > repo
comparison interps/bfjoust/egojoust.c @ 996:859f9b4339e6
<Gregor> tar xf egobot.tar.xz
author | HackBot |
---|---|
date | Sun, 09 Dec 2012 19:30:08 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
995:6883f5911eb7 | 996:859f9b4339e6 |
---|---|
1 #include <stdio.h> | |
2 #include <stdlib.h> | |
3 #include <string.h> | |
4 #include <time.h> | |
5 | |
6 #include "buffer.h" | |
7 | |
8 #define MINTAPELEN 10 | |
9 #define MAXTAPELEN 30 | |
10 #define POLARITIES 4 | |
11 #define RUNCOUNT (((MAXTAPELEN-MINTAPELEN) + 1) * POLARITIES) | |
12 | |
13 /* parse a BFJoust program */ | |
14 int parseFile(struct Buffer_char *progp) | |
15 { | |
16 int i, end, inner, iend, llen, ilen, rlen, times, rep, loc; | |
17 struct Buffer_char prog = *progp; | |
18 struct Buffer_char temp; | |
19 | |
20 /* go through looking for things to expand */ | |
21 for (i = 0; i < prog.bufused; i++) { | |
22 if (prog.buf[i] == '(') { | |
23 /* look for the match */ | |
24 int depth = 1; | |
25 inner = iend = -1; | |
26 for (end = i + 1; end < prog.bufused && depth; end++) { | |
27 if (prog.buf[end] == '(') { | |
28 depth++; | |
29 } else if (prog.buf[end] == ')') { | |
30 depth--; | |
31 } else if (depth == 1 && prog.buf[end] == '{') { | |
32 inner = end; | |
33 } else if (depth == 1 && prog.buf[end] == '}') { | |
34 iend = end; | |
35 } | |
36 } | |
37 | |
38 /* make sure it's sensible */ | |
39 end--; | |
40 if (end + 2 >= prog.bufused) return 0; | |
41 | |
42 /* expand it only if it includes [ or ], or is a '%' loop (which make interpretation basically impossible if unexpanded) */ | |
43 llen = end - i; | |
44 if (strcspn(prog.buf + i, "[]") >= llen && prog.buf[end+1] == '*') { | |
45 continue; | |
46 } | |
47 | |
48 /* check what comes next */ | |
49 times = atoi(prog.buf + end + 2); | |
50 if (times < 0 || times > 10000) times = 10000; | |
51 if (prog.buf[end+1] == '*') { | |
52 llen = end - i - 1; | |
53 | |
54 /* the simple case, just repeat n times */ | |
55 INIT_BUFFER(temp); | |
56 temp.bufused = times * llen; | |
57 while (temp.bufsz < temp.bufused) { | |
58 EXPAND_BUFFER(temp); | |
59 } | |
60 for (rep = 0; rep < times; rep++) { | |
61 memcpy(temp.buf + rep * llen, prog.buf + i + 1, llen); | |
62 } | |
63 | |
64 } else if (prog.buf[end+1] == '%') { | |
65 /* make sure there's a {} */ | |
66 if (inner == -1 || iend == -1) return 0; | |
67 | |
68 llen = inner - i - 1; | |
69 ilen = iend - inner - 1; | |
70 rlen = end - iend - 1; | |
71 if (llen < 0 || ilen < 0 || rlen < 0) return 0; | |
72 | |
73 /* set up the buffer */ | |
74 INIT_BUFFER(temp); | |
75 temp.bufused = times * llen + ilen + times * rlen; | |
76 while (temp.bufsz < temp.bufused) { | |
77 EXPAND_BUFFER(temp); | |
78 } | |
79 | |
80 /* now the left */ | |
81 loc = 0; | |
82 for (rep = 0; rep < times; rep++) { | |
83 memcpy(temp.buf + loc + rep * llen, prog.buf + i + 1, llen); | |
84 } | |
85 loc = times * llen; | |
86 | |
87 /* the inner */ | |
88 memcpy(temp.buf + loc, prog.buf + inner + 1, ilen); | |
89 loc += ilen; | |
90 | |
91 /* and the right */ | |
92 for (rep = 0; rep < times; rep++) { | |
93 memcpy(temp.buf + loc + rep * rlen, prog.buf + iend + 1, rlen); | |
94 } | |
95 | |
96 } else { | |
97 return 0; | |
98 | |
99 } | |
100 | |
101 /* now copy it back into prog */ | |
102 while (prog.bufsz < prog.bufused + temp.bufused + 1) { | |
103 EXPAND_BUFFER(prog); | |
104 } | |
105 memmove(prog.buf + i + temp.bufused, prog.buf + end + 1, prog.bufused - end - 1); | |
106 memcpy(prog.buf + i, temp.buf, temp.bufused); | |
107 prog.bufused = prog.bufused - end + i - 1 + temp.bufused; | |
108 WRITE_BUFFER(prog, "", 1); prog.bufused--; | |
109 | |
110 FREE_BUFFER(temp); | |
111 | |
112 i--; | |
113 } | |
114 } | |
115 | |
116 memcpy(progp, &prog, sizeof(prog)); | |
117 return 1; | |
118 } | |
119 | |
120 /* returns true if this is a BF comment */ | |
121 int isComment(char c) | |
122 { | |
123 return (c != '<' && c != '>' && c != '-' && c != '+' && c != '[' && c != ']' && c != '(' && c != ')' && c != '.'); | |
124 } | |
125 | |
126 /* run an execution step */ | |
127 void runStep(struct Buffer_char prog, int *loops, int *pip, | |
128 char *tape, char *otape, int tapelen, int *tip, | |
129 int tapedir, int polarity, | |
130 struct Buffer_int *pstack, struct Buffer_int *pmax) | |
131 { | |
132 int pi = *pip; | |
133 int ti = *tip; | |
134 int reps = 0; | |
135 | |
136 /* find a non-comment character */ | |
137 rerun: | |
138 if (++reps > 16) return; | |
139 if (pi < 0) return; | |
140 for (; pi < prog.bufused && isComment(prog.buf[pi]); pi++); | |
141 *pip = pi; | |
142 if (pi >= prog.bufused) return; | |
143 | |
144 /* run it */ | |
145 switch (prog.buf[pi]) { | |
146 case '<': | |
147 ti -= tapedir; | |
148 break; | |
149 | |
150 case '>': | |
151 ti += tapedir; | |
152 break; | |
153 | |
154 case '-': | |
155 otape[ti] -= polarity; | |
156 break; | |
157 | |
158 case '+': | |
159 otape[ti] += polarity; | |
160 break; | |
161 | |
162 case '[': | |
163 if (tape[ti] == 0) { | |
164 /* first check the cache */ | |
165 if (loops[pi] != -1) { | |
166 pi = loops[pi]; | |
167 } else { | |
168 int depth = 1; | |
169 int opi = pi; | |
170 for (pi++; pi < prog.bufused && depth; pi++) { | |
171 switch (prog.buf[pi]) { | |
172 case '[': | |
173 depth++; | |
174 break; | |
175 | |
176 case ']': | |
177 depth--; | |
178 break; | |
179 } | |
180 } | |
181 pi--; | |
182 | |
183 loops[opi] = pi; | |
184 loops[pi] = opi; | |
185 } | |
186 } | |
187 break; | |
188 | |
189 case ']': | |
190 if (tape[ti] != 0) { | |
191 /* check the cache */ | |
192 if (loops[pi] != -1) { | |
193 pi = loops[pi]; | |
194 } else { | |
195 int depth = 1; | |
196 for (pi--; pi >= 0 && depth; pi--) { | |
197 switch (prog.buf[pi]) { | |
198 case ']': | |
199 depth++; | |
200 break; | |
201 | |
202 case '[': | |
203 depth--; | |
204 break; | |
205 } | |
206 } | |
207 pi++; | |
208 } | |
209 } | |
210 break; | |
211 | |
212 case '(': | |
213 /* make sure this is cached */ | |
214 if (loops[pi] == -1) { | |
215 int depth = 1; | |
216 int ipi; | |
217 for (ipi = pi + 1; ipi < prog.bufused && depth; ipi++) { | |
218 switch (prog.buf[ipi]) { | |
219 case '(': | |
220 depth++; | |
221 break; | |
222 | |
223 case ')': | |
224 depth--; | |
225 break; | |
226 } | |
227 } | |
228 ipi--; | |
229 | |
230 loops[pi] = ipi; | |
231 loops[ipi] = pi; | |
232 } | |
233 | |
234 /* push the counter */ | |
235 { | |
236 int count = atoi(prog.buf + loops[pi] + 2); | |
237 if (BUFFER_SPACE(*pstack) < 1) { | |
238 EXPAND_BUFFER(*pstack); | |
239 EXPAND_BUFFER(*pmax); | |
240 } | |
241 pstack->buf[pstack->bufused++] = 0; | |
242 pmax->buf[pmax->bufused++] = count; | |
243 } | |
244 | |
245 /* then continue immediately */ | |
246 pi++; | |
247 goto rerun; | |
248 | |
249 case ')': | |
250 /* increment the counter */ | |
251 if (pstack->bufused > 0) { | |
252 pstack->buf[pstack->bufused-1]++; | |
253 } | |
254 | |
255 /* either reloop or don't */ | |
256 if (pstack->buf[pstack->bufused-1] < pmax->buf[pstack->bufused-1]) { | |
257 pi = loops[pi]; | |
258 } else { | |
259 pstack->bufused = pmax->bufused = pstack->bufused - 1; | |
260 } | |
261 pi++; | |
262 goto rerun; | |
263 | |
264 case '.': | |
265 /* nop */ | |
266 break; | |
267 } | |
268 pi++; | |
269 | |
270 *pip = pi; | |
271 *tip = ti; | |
272 } | |
273 | |
274 /* simple hashing function, same as is used in sdbm */ | |
275 size_t simpleHash(size_t slen, unsigned char *str) | |
276 { | |
277 size_t hash = 0; | |
278 | |
279 for (; slen > 0; slen--) | |
280 hash = (*str++) + (hash << 6) + (hash << 16) - hash; | |
281 | |
282 return hash; | |
283 } | |
284 | |
285 int main(int argc, char **argv) | |
286 { | |
287 struct Buffer_char lprog, rprog; | |
288 struct Buffer_int lloops, rloops; | |
289 struct Buffer_int lpstack, rpstack, lpmax, rpmax; | |
290 FILE *lfh, *rfh; | |
291 int lparse, rparse; | |
292 char *tape, *otape; | |
293 int lt, rt, tapelen; | |
294 int polarity, lpol, rpol; | |
295 int lpi, rpi; | |
296 int lwins, rwins; | |
297 int lloss, rloss; | |
298 int step; | |
299 | |
300 if (argc < 3) { | |
301 fprintf(stderr, "Use: egojoust <left program> <right program>\n"); | |
302 return 0; | |
303 } | |
304 | |
305 /* read in the files */ | |
306 INIT_BUFFER(lprog); | |
307 SF(lfh, fopen, NULL, (argv[1], "r")); | |
308 READ_FILE_BUFFER(lprog, lfh); | |
309 WRITE_BUFFER(lprog, "", 1); lprog.bufused--; | |
310 | |
311 INIT_BUFFER(rprog); | |
312 SF(rfh, fopen, NULL, (argv[2], "r")); | |
313 READ_FILE_BUFFER(rprog, rfh); | |
314 WRITE_BUFFER(rprog, "", 1); rprog.bufused--; | |
315 | |
316 /* parse them */ | |
317 lparse = parseFile(&lprog); | |
318 rparse = parseFile(&rprog); | |
319 if (!lparse) { | |
320 if (!rparse) { | |
321 printf("Both warriors failed to parse. Tie!\n"); | |
322 return 0; | |
323 } else { | |
324 printf("Left warrior failed to parse, right warrior wins!\n"); | |
325 return RUNCOUNT; | |
326 } | |
327 } else if (!rparse) { | |
328 printf("Right warrior failed to parse, left warrior wins!\n"); | |
329 return -RUNCOUNT; | |
330 } | |
331 | |
332 /* allocate the tape */ | |
333 SF(tape, malloc, NULL, (30)); | |
334 SF(otape, malloc, NULL, (30)); | |
335 | |
336 /* prepare the caches */ | |
337 INIT_BUFFER(lloops); | |
338 INIT_BUFFER(rloops); | |
339 while (lloops.bufsz < lprog.bufused) EXPAND_BUFFER(lloops); | |
340 memset(lloops.buf, -1, lprog.bufused * sizeof(int)); | |
341 while (rloops.bufsz < rprog.bufused) EXPAND_BUFFER(rloops); | |
342 memset(rloops.buf, -1, rprog.bufused * sizeof(int)); | |
343 | |
344 INIT_BUFFER(lpstack); | |
345 INIT_BUFFER(rpstack); | |
346 INIT_BUFFER(lpmax); | |
347 INIT_BUFFER(rpmax); | |
348 | |
349 /* run for each polarity, for each length from 10 to 30 */ | |
350 lwins = 0; | |
351 rwins = 0; | |
352 | |
353 printf("%s vs %s:\n", argv[1], argv[2]); | |
354 | |
355 for (polarity = 0; polarity < POLARITIES; polarity++) { | |
356 /* set up the polarity */ | |
357 if (polarity & 0x2) { | |
358 lpol = -1; | |
359 } else { | |
360 lpol = 1; | |
361 } | |
362 | |
363 if (polarity & 0x1) { | |
364 rpol = -1; | |
365 } else { | |
366 rpol = 1; | |
367 } | |
368 | |
369 for (tapelen = MINTAPELEN; tapelen <= MAXTAPELEN; tapelen++) { | |
370 /* make the tape */ | |
371 memset(tape, 0, tapelen); | |
372 tape[0] = tape[tapelen-1] = (char) (unsigned char) 128; | |
373 lt = 0; | |
374 rt = tapelen - 1; | |
375 memcpy(otape, tape, tapelen); | |
376 | |
377 /* then run */ | |
378 lpi = rpi = lloss = rloss = 0; | |
379 for (step = 0; step < 100000 && lloss < 2 && rloss < 2; step++) { | |
380 /* run the left */ | |
381 runStep(lprog, lloops.buf, &lpi, tape, otape, tapelen, <, 1, lpol, &lpstack, &lpmax); | |
382 | |
383 /* and the right */ | |
384 runStep(rprog, rloops.buf, &rpi, tape, otape, tapelen, &rt, -1, rpol, &rpstack, &rpmax); | |
385 | |
386 /* commit the tape */ | |
387 memcpy(tape, otape, tapelen); | |
388 | |
389 /* check for loss conditions */ | |
390 if (tape[0] == 0) { | |
391 lloss++; | |
392 } else { | |
393 lloss = 0; | |
394 } | |
395 if (lt < 0 || lt >= tapelen) { | |
396 fprintf(stderr, "Left ran off the tape (%d/%d)!\n", lt, tapelen); | |
397 lloss = 3; | |
398 } | |
399 if (tape[tapelen-1] == 0) { | |
400 rloss++; | |
401 } else { | |
402 rloss = 0; | |
403 } | |
404 if (rt < 0 || rt >= tapelen) { | |
405 fprintf(stderr, "Right ran off the tape (%d/%d)!\n", rt, tapelen); | |
406 rloss = 3; | |
407 } | |
408 } | |
409 | |
410 /* now find the victor */ | |
411 if (lloss > rloss) { | |
412 /*printf("%d/%d: %s wins!\n", polarity, tapelen, argv[2]);*/ | |
413 printf(">"); | |
414 rwins++; | |
415 } else if (rloss > lloss) { | |
416 /*printf("%d/%d: %s wins!\n", polarity, tapelen, argv[1]);*/ | |
417 printf("<"); | |
418 lwins++; | |
419 } else { | |
420 /*printf("%d/%d: Tie!\n", polarity, tapelen);*/ | |
421 printf("X"); | |
422 } | |
423 } | |
424 | |
425 printf(" "); | |
426 } | |
427 | |
428 printf("\n"); | |
429 | |
430 if (lwins > rwins) { | |
431 printf("%s wins\n\n", argv[1]); | |
432 } else if (rwins > lwins) { | |
433 printf("%s wins\n\n", argv[2]); | |
434 } else { | |
435 printf("Tie\n\n"); | |
436 } | |
437 return rwins - lwins; | |
438 } |