For the sake of better helping people who are programming in GAME Code understand the language, this page displays an up-to-date, script-generated copy of the PHP code that handles its processing of Polish notation expressions, complete with line numbering and syntax highlighting. This code includes all the operators and built-in functions available in GAME Code expressions, including any that may be undocumented. For simplicity of terminology, operator means any operator or built-in function, and operand means an argument to an operator. The operators are grouped by how many operands they take. The outer switch statement directs most operators to an inner switch statement, which is where you will find the code for particular operators. Within the same group, operators should be listed alphabetically. The outer switch also handles operators that take variable numbers of operands. So, you can find code for a particular operator by searching for its name once or twice within double quotation marks. Note that this code is provided here only for educational purposes and should not be copied or downloaded.
Copyright © Fergus Duniho, 2016.
1.
<?
2.
3. // Here is the main function for evaluating Polish notation expressions.
4.
5. function polish ($input, $linenum, $substitutions = NULL, $myvars = NULL) {
6. global $ALIAS, $REALNAME, $background, $constants, $debug, $dest, $excode, $file, $filename, $filenum, $firstplayer, $flag, $flipped, $functions, $ifhead, $label, $legalmoves, $lastcaptured, $map, $maxmln, $mline, $mln, $movenum, $piecekeys, $pieces, $players, $prison, $puremoves, $rank, $rankname, $ranknum, $set, $settings, $space, $scope, $starpath, $status, $sub, $submit, $userset, $uservar;
7.
8. static $target, $screen;
9. static $operators = array(
10. "!=" => "2",
11. "!==" => "2",
12. "%" => "2",
13. "&" => "2",
14. "&&" => "1|2",
15. "*" => "2",
16. "+" => "2",
17. "-" => "2",
18. "." => "2",
19. "." => "2",
20. "/" => "2",
21. "<" => "2",
22. "<<" => "2",
23. "<=" => "2",
24. "==" => "2",
25. "===" => "2",
26. ">" => "2",
27. ">=" => "2",
28. ">>" => "2",
29. "abs" => "1",
30. "alias" => "1",
31. "and" => "1|2",
32. "args" => "0",
33. "asort" => "1",
34. "base" => "2",
35. "baseurl" => "0",
36. "behindscreen" => "3",
37. "best2drop" => "0",
38. "best2free" => "0",
39. "bitand" => "2",
40. "bitnot" => "1",
41. "bitor" => "2",
42. "bits" => "1",
43. "bitxor" => "2",
44. "boardflags" => "0",
45. "capture" => "0",
46. "captured" => "0",
47. "capturedpieces" => "0",
48. "char" => "2",
49. "chars" => "1",
50. "check" => "1",
51. "checkahop" => "4a",
52. "checkaleap" => "4a",
53. "checkaride" => "4a",
54. "checkgrasshop" => "4s",
55. "checkhop" => "4s",
56. "checkleap" => "4s",
57. "checklongleap" => "4s",
58. "checkmaxsteps"=> "3",
59. "checknsteps" => "3",
60. "checkrhombus" => "2",
61. "checkride" => "4s",
62. "chr" => "1",
63. "cmp" => "2",
64. "color" => "1",
65. "cond" => "3",
66. "const" => "1",
67. "count" => "1",
68. "currentpieces" => "0",
69. "dec" => "1",
70. "dechex" => "1",
71. "diff" => "2",
72. "direction" => "2",
73. "distance" => "2",
74. "div" => "2",
75. "elem" => "2",
76. "empty" => "1",
77. "equal" => "2",
78. "eval" => "1",
79. "even" => "1",
80. "excode" => "0",
81. "explode" => "2",
82. "false" => "0",
83. "fencode" => "0",
84. "file" => "1",
85. "filename" => "1",
86. "findinhand" => "1",
87. "firstrankname" => "0",
88. "flag" => "1",
89. "flags" => "0",
90. "flipcase" => "1",
91. "flipimg" => "1",
92. "fnmatch" => "2",
93. "function" => "1",
94. "gcd" => "2",
95. "global" => "1",
96. "greater" => "2",
97. "hamming" => "2",
98. "hasalnum" => "1",
99. "hasalpha" => "1",
100. "hasdigit" => "1",
101. "haslower" => "1",
102. "hasupper" => "1",
103. "hexdec" => "1",
104. "htmllink" => "2",
105. "hyphen" => "0",
106. "identical" => "2",
107. "inc" => "1",
108. "int" => "1",
109. "insight" => "3",
110. "invisible" => "1",
111. "isalnum" => "1",
112. "isalpha" => "1",
113. "isarray" => "1",
114. "isconst" => "1",
115. "isdigit" => "1",
116. "isfunc" => "1",
117. "islower" => "1",
118. "isopponent" => "0",
119. "isplayer" => "0",
120. "isplayer1" => "0",
121. "isplayer2" => "0",
122. "isset" => "1",
123. "issub" => "1",
124. "isupper" => "1",
125. "isvisible" => "1",
126. "join" => "2",
127. "keys" => "1",
128. "ksort" => "1",
129. "lambda" => "1",
130. "lastfile" => "0",
131. "lastmoved" => "0",
132. "lastrank" => "0",
133. "lastrankname" => "0",
134. "leaps" => "3",
135. "leftstr" => "2",
136. "less" => "2",
137. "levenshtein" => "2",
138. "literal" => "1",
139. "markedlegal" => "1",
140. "max" => "2",
141. "maxmovenum" => "0",
142. "merge" => "1|2",
143. "min" => "2",
144. "minus" => "2",
145. "mln" => "0",
146. "mod" => "2",
147. "move" => "1",
148. "movenum" => "0",
149. "mult" => "2",
150. "nand" => "2",
151. "natsort" => "1",
152. "near" => "3",
153. "neg" => "1",
154. "nil" => "0",
155. "nolower" => "0",
156. "nor" => "2",
157. "not" => "1",
158. "noupper" => "0",
159. "null" => "0",
160. "odd" => "1",
161. "onboard" => "1",
162. "onebits" => "1",
163. "onfile" => "2",
164. "onlyif" => "1|2",
165. "onlylower" => "0",
166. "onlyupper" => "0",
167. "opponent" => "0",
168. "or" => "1|2",
169. "ord" => "1",
170. "path" => "2",
171. "piececount" => "0",
172. "pieceimg" => "1",
173. "piecekeys" => "0",
174. "pieces" => "0",
175. "pieceset" => "0",
176. "plus" => "2",
177. "pow" => "2",
178. "rand" => "2",
179. "range" => "2",
180. "rank" => "1",
181. "rankname" => "1",
182. "ray" => "3",
183. "rays" => "3",
184. "realname" => "1",
185. "regmatch" => "2",
186. "remove" => "1",
187. "revealed" => "2",
188. "reverse" => "1",
189. "ride" => "3",
190. "rightstr" => "2",
191. "same" => "2",
192. "samecase" => "2",
193. "screen" => "0",
194. "search" => "2",
195. "shuffle" => "1",
196. "sign" => "1",
197. "slope" => "2",
198. "space" => "1",
199. "spaces" => "0",
200. "status" => "0",
201. "str_replace" => "3",
202. "string" => "1",
203. "strlen" => "1",
204. "strstr" => "2",
205. "submit" => "0",
206. "substr" => "3",
207. "system" => "1",
208. "target" => "1",
209. "thismove" => "0",
210. "thismovenum" => "0",
211. "time" => "0",
212. "tolower" => "1",
213. "toupper" => "1",
214. "trim" => "1|2",
215. "true" => "0",
216. "turn" => "0",
217. "twinonfile" => "1",
218. "type" => "1",
219. "unequal" => "2",
220. "unique" => "1",
221. "unless" => "1|2",
222. "urlencode" => "1",
223. "user" => "0",
224. "var" => "1",
225. "var_export" => "1",
226. "void" => "0",
227. "voidride" => "4s",
228. "what" => "2|3",
229. "where" => "2|3",
230. "whitespace" => "0",
231. "ws" => "0",
232. "xor" => "2",
233. "|" => "2",
234. "||" => "1|2");
235.
236. $higherscope = $scope + 1;
237. $output = array();
238. // $substitions = func_num_args() ? func_get_arg (1) : NULL;
239. // $substitutions = func_num_args() ? func_get_arg (1) : NULL;
240. if (!empty($myvars) && is_array($myvars)) {
241. $scope = $higherscope;
242. $sub[$scope] = $sub[$scope - 1];
243. $ifhead[$scope] = "func";
244. foreach ($myvars as $key => $val) {
245. $uservar[$scope][$sub[$scope]][$key] = $val;
246. }
247. }
248. while (count($input) > 0) {
249. $arg = array_pop($input);
250. // debug2("arg type", gettype($arg));
251. if (!is_string($arg)) {
252. array_push ($output, $arg);
253. continue;
254. }
255. $car = empty($arg[0]) ? "" : $arg[0];
256. $cdr = substr($arg, 1);
257. if ($car == "#") {
258. if (ctype_digit($cdr) && isset($substitutions[$cdr])) {
259. array_push ($output, $substitutions[$cdr]);
260. continue;
261. }
262. array_push ($output, evalvar($arg));
263. continue;
264. }
265. elseif (!empty($cdr) && (($car == "?") || ($car == "$") || ($car == "@"))) {
266. array_push ($output, evalvar($arg));
267. continue;
268. }
269. elseif ($car == "=") {
270. $scope = $higherscope;
271. $sub[$scope] = $sub[$scope - 1];
272. $ifhead[$scope] = "func";
273. if (!empty($cdr) && ctype_alpha($cdr[0]) && ctype_alnum($cdr)) {
274. if (empty($output)) {
275. if (!empty($substitutions))
276. $uservar[$scope][$sub[$scope]][$cdr] = array_pop($substitutions);
277. }
278. elseif (count($output) == 1) {
279. $uservar[$scope][$sub[$scope]][$cdr] = array_pop($output);
280. }
281. else {
282. $uservar[$scope][$sub[$scope]][$cdr] = $output;
283. $output = array();
284. }
285. continue;
286. }
287. }
288. if (isset($operators[$arg]))
289. $opcase = $operators[$arg];
290. elseif ($car == "#")
291. $opcase = "0";
292. else
293. $opcase = "default";
294. switch ($opcase) {
295. case "0": // nullary operators
296. switch ($arg) {
297. case "args":
298. array_push ($output, $substitutions);
299. break;
300. case "baseurl":
301. array_push ($output, PLAY_SCRIPT . "?");
302. break;
303. case "best2drop": // Designed for Hostage Chess
304. // Returns highest valued piece in hand
305. array_push ($output, best2drop());
306. break;
307. case "best2free": // Designed for Hostage Chess
308. // Returns highest valued piece in opponent's prison
309. array_push ($output, best2free());
310. break;
311. case "boardflags": // Returns sorted list of spaces with flags set
312. array_push ($output, boardflags());
313. break;
314. case "capture": // Boolean: was last move a capture?
315. array_push ($output, (($lastcaptured != "@") && ($lastcaptured != "-")));
316. break;
317. case "captured": // Returns piece captured on last move
318. // Returns @ if move was to empty space
319. array_push ($output, $lastcaptured);
320. break;
321. case "capturedpieces": // Calculates up-to-date list of captured pieces for the current move
322. array_push ($output, capturedpieces());
323. break;
324. case "currentpieces": // Calculates up-to-date list of pieces currently on the board
325. array_push ($output, currentpieces());
326. break;
327. case "destination": // Returns destination of last move
328. array_push ($output, $dest);
329. break;
330. case "excode": // Returns expanded FEN code, an array
331. // representing the original position.
332. array_push ($output, $excode);
333. break;
334. case "false": // Returns Boolean value of false
335. array_push ($output, false);
336. break;
337. case "fencode": // Returns FEN code for current position
338. array_push ($output, fencode());
339. break;
340. case "flags": // Returns an array of all flags
341. array_push ($output, $flag);
342. break;
343. case "hyphen": // Returns the hyphen character
344. array_push ($output, "-");
345. break;
346. case "isopponent":
347. array_push ($output, ($_SESSION["userid"] ?? "") == $GLOBALS["opponent"]);
348. break;
349. case "isplayer":
350. array_push ($output, ($_SESSION["userid"] ?? "") == $GLOBALS["player"]);
351. break;
352. case "isplayer1":
353. if (!empty($_SESSION["userid"]) && !empty($players)) {
354. list($player1, $player2) = explode(" ", $players);
355. array_push ($output, $_SESSION["userid"] == $player1);
356. }
357. else
358. array_push ($output, false);
359. break;
360. case "isplayer2":
361. if (!empty($_SESSION["userid"]) && !empty($players)) {
362. list($player1, $player2) = explode(" ", $players);
363. array_push ($output, $_SESSION["userid"] == $player2);
364. }
365. else
366. array_push ($output, false);
367. break;
368. case "lastfile": // Returns numeric index of last file
369. array_push ($output, count($file)-1);
370. break;
371. case "lastmoved":
372. array_push ($output, $lastmoved);
373. break;
374. case "lastrank": // Returns numeric index of last rank
375. array_push ($output, count($rank)-1);
376. break;
377. case "mln": // Returns index value of array of moves
378. array_push ($output, $mln);
379. break;
380. case "maxmovenum":
381. if (!empty($mline[$maxmln]))
382. array_push ($output, $mline[$maxmln]->movenum);
383. else
384. array_push ($output, 0);
385. break;
386. case "movenum": // Returns latest move number in game,
387. // no matter how far along the code is in evaluating the moves
388. array_push ($output, $movenum);
389. break;
390. case "nil": // Returns value of empty space, the @ string
391. array_push ($output, "@");
392. break;
393. case "nolower": // Returns array of all piece labels not
394. // entirely lowercase.
395. array_push ($output, array_filter($space, "notlower"));
396. break;
397. case "noupper":
398. array_push ($output, array_filter($space, "notupper"));
399. break;
400. case "null": // Returns NULL value
401. array_push ($output, NULL);
402. break;
403. case "onlylower":
404. array_push ($output, array_filter($space, "ctype_lower"));
405. break;
406. case "onlyupper":
407. array_push ($output, array_filter($space, "ctype_upper"));
408. break;
409. case "opponent":
410. array_push ($output, $GLOBALS["opponent"]);
411. break;
412. case "piececount":
413. $temp = array();
414. foreach ($space as $p) {
415. if (($p != "@") && ($p != "-"))
416. $temp[$p] = isset($temp[$p]) ? $temp[$p] + 1 : 1;
417. }
418. array_push ($output, $temp);
419. break;
420. case "piecekeys":
421. array_push ($output, is_array($piecekeys) ? $piecekeys : array());
422. break;
423. case "pieces":
424. array_push ($output, $space);
425. break;
426. case "pieceset":
427. if (empty($userset) || empty($GLOBALS[$userset]))
428. array_push ($output, $set);
429. else
430. array_push ($output, $GLOBALS[$userset]);
431. break;
432. case "screen":
433. array_push ($output, $screen);
434. break;
435. case "spaces":
436. array_push ($output, array_keys($space));
437. break;
438. case "status":
439. array_push ($output, $status);
440. break;
441. case "submit":
442. array_push ($output, $submit);
443. break;
444. case "thismove":
445. if (!empty($mline[$mln]))
446. array_push ($output, trim($mline[$mln]->move, " ;\t\n\r\0\x0B"));
447. else
448. array_push ($output, null);
449. break;
450. case "thismovenum":
451. if (!empty($mline[$mln]))
452. array_push ($output, $mline[$mln]->movenum);
453. else
454. array_push ($output, 0);
455. break;
456. case "time":
457. array_push ($output, time());
458. break;
459. case "true":
460. array_push ($output, true);
461. break;
462. case "turn":
463. array_push ($output, $mline[$mln]->turn);
464. break;
465. case "user":
466. array_push ($output, $_SESSION["userid"] ?? "");
467. break;
468. case "void":
469. array_push ($output, "-");
470. break;
471. case "whitespace": case "ws":
472. array_push ($output, " ");
473. break;
474. // Substitutions for function placeholders
475. case (($arg[0] == "#") ? $arg : "false"):
476. $n = substr($arg, 1);
477. array_push ($output, (ctype_digit($n) && isset($substitutions[$n])) ? $substitutions[$n] : $arg);
478. break;
479. }
480. break;
481. case "1": // Unary operators
482. // This mysteriously caused an error in a line without the designated operator.
483. // if (count($output) < 1)
484. // error("The {$arg} operator requires at least 1 argument.", $linenum);
485. $op1 = array_pop ($output);
486. switch ($arg) {
487. case "abs":
488. array_push ($output, abs($op1));
489. break;
490. case "alias":
491. if (!is_array($op1))
492. array_push ($output, isset($ALIAS[$op1]) ? $ALIAS[$op1] : $op1);
493. else
494. array_push ($output, null);
495. break;
496. case "asort":
497. asort($op1);
498. array_push ($output, $op1);
499. break;
500. case "bitnot":
501. array_push ($output, ~$op1);
502. break;
503. case "bits":
504. $bits = 0;
505. while ($op1) {
506. $bits++;
507. $op1 >>= 1;
508. }
509. array_push ($output, $bits);
510. break;
511. case "chars":
512. array_push($output, str_split($op1, 1));
513. break;
514. case "check":
515. // debug2 ("target", $target);
516. // debug2 ("op1", $op1);
517. if (($target == $op1) || (is_array($target) && in_array($op1, $target))) {
518. $output = array(true);
519. $input = array();
520. }
521. // debug2 ("match?", is_array($target) && in_array($op1, $target));
522. break;
523. case "chr":
524. array_push ($output, chr($op1));
525. break;
526. case "color":
527. array_push ($output, $background[$op1] ?? NULL);
528. break;
529. case "const":
530. if (isset($constants) && is_array($constants) && !is_array($op1) && array_key_exists($op1, $constants))
531. array_push ($output, $constants[$op1]);
532. else
533. array_push ($output, NULL);
534. break;
535. case "count":
536. array_push ($output, is_array($op1) ? count($op1) : 0);
537. break;
538. case "count_values":
539. array_push ($output, array_count_values($op1));
540. break;
541. case "dec":
542. array_push ($output, $op1-1);
543. break;
544. case "dechex":
545. array_push ($output, dechex($op1));
546. break;
547. case "empty":
548. array_push ($output, isset($space[$op1]) && ($space[$op1] == "@"));
549. // debug2("space[$op1] == ", $space[$op1]);
550. break;
551. case "eval":
552. array_push ($output, polish($op1, $linenum, $substitutions));
553. break;
554. case "even":
555. array_push ($output, ((int)$op1 & 1)==0);
556. break;
557. case "findinhand":
558. array_push ($output, findpiece($op1, $starpath[$firstplayer]));
559. break;
560. case "file":
561. array_push ($output, isset($filenum[$op1]) ? $filenum[$op1] : false);
562. break;
563. case "filename":
564. array_push ($output, isset($filename[$op1]) ? $filename[$op1] : (isset($file[$op1]) ? $file[$op1] : ""));
565. break;
566. case "flag":
567. // Since flags are Booleans, this works.
568. array_push ($output, !empty($flag[$op1]));
569. break;
570. case "flipcase":
571. array_push ($output, flipcase($op1));
572. break;
573. case "flipimg":
574. array_push ($output, $flipped[$op1] ?? $pieces[$op1] ?? "");
575. break;
576. case "global": case "system":
577. switch ($op1) {
578. case "answered":
579. case "board":
580. case "cases":
581. case "code":
582. case "columns":
583. case "debug":
584. case "dest":
585. case "dir":
586. case "lastcaptured":
587. case "lastmoved":
588. case "legalmoves":
589. case "maxmln";
590. case "maxmove":
591. case "movelist";
592. case "moves":
593. case "noerrorcheck":
594. case "omitmoves":
595. case "orientation":
596. case "origin":
597. case "originalpieces":
598. case "piecekeys":
599. case "piecevals":
600. case "prison":
601. case "sets":
602. case "showoutput":
603. case "side";
604. case "space";
605. case "starpath":
606. case "submit":
607. array_push ($output, $GLOBALS[$op1]);
608. break;
609. default:
610. error ("No variable named \${$op1} has been whitelisted for the <b>{$arg}</b> function.", $linenum);
611. }
612. break;
613. case "hasalnum":
614. array_push ($output, hasalnum($op1));
615. break;
616. case "hasalpha":
617. array_push ($output, hasalpha($op1));
618. break;
619. case "hasdigit":
620. array_push ($output, hasdigit($op1));
621. break;
622. case "haslower":
623. array_push ($output, haslower($op1));
624. break;
625. case "hasupper":
626. array_push ($output, hasupper($op1));
627. break;
628. case "hexdec":
629. array_push ($output, hexdec($op1));
630. break;
631. case "inc":
632. array_push ($output, $op1+1);
633. break;
634. case "int":
635. if ($op1[0] == 0) {
636. if ($op1[1] == "x")
637. $base = 16;
638. elseif ($op1[1] == "b")
639. $base = 2;
640. else
641. $base = 7;
642. }
643. else
644. $base = 10;
645. array_push ($output, intval($op1, $base));
646. break;
647. case "isalnum":
648. array_push ($output, ctype_alnum((string)$op1));
649. break;
650. case "isalpha":
651. array_push ($output, ctype_alpha((string)$op1));
652. break;
653. case "isarray":
654. array_push ($output, is_array($op1));
655. break;
656. case "isconst":
657. array_push ($output, is_array($constants) && array_key_exists($op1, $constants));
658. break;
659. case "isdigit":
660. array_push ($output, ctype_digit($op1));
661. break;
662. case "isfunc":
663. array_push ($output, isset($functions[$op1]));
664. break;
665. case "islower":
666. array_push ($output, ctype_lower((string)$op1));
667. break;
668. case "isset":
669. array_push ($output, issetuservar($op1));
670. break;
671. case "issub":
672. array_push ($output, isset($label[$op1]));
673. break;
674. case "isupper":
675. array_push ($output, ctype_upper((string)$op1));
676. break;
677. case "invisible":
678. array_push($output, ($filename[$op1][0] == "!") || ($rankname[$op1][0] == "!"));
679. break;
680. case "isvisible":
681. array_push($output, (isset($filename[$op1][0]) && ($filename[$op1][0] != "!")) && (isset($rankname[$op1][0]) && ($rankname[$op1][0] != "!")));
682. break;
683. case "keys":
684. array_push ($output, array_keys($op1));
685. break;
686. case "ksort":
687. ksort($op1);
688. array_push ($output, $op1);
689. break;
690. case "lambda":
691. if (is_array($op1))
692. array_push ($output, new Lambda($op1));
693. elseif (isset($functions[$op1]))
694. array_push ($output, new Lambda($functions[$op1]));
695. elseif (strstr($op1, " "))
696. array_push ($output, new Lambda(explode(" ", $op1)));
697. else {
698. $result = new Lambda($output);
699. unset($output);
700. $output[0] = $result;
701. }
702. break;
703. case "literal":
704. if ($op1 instanceof Lambda)
705. array_push ($output, array_literal($op1->stack));
706. elseif (is_array($op1))
707. array_push ($output, array_literal($op1));
708. elseif (isset($functions[$op1]))
709. array_push ($output, function_literal($functions[$op1]));
710. else
711. array_push ($output, $op1);
712. break;
713. case "markedlegal":
714. array_push ($output, in_array($op1, $legalmoves) ? true : false);
715. break;
716. case "move":
717. array_push ($output, $puremoves[$op1] ?? "");
718. break;
719. case "natsort":
720. natsort($op1);
721. array_push ($output, $op1);
722. break;
723. case "neg":
724. array_push ($output, -$op1);
725. break;
726. case "not":
727. array_push ($output, ((array)$op1 === $op1) ? !polish($op1, $linenum, $substitutions) : !$op1);
728. break;
729. case "odd":
730. array_push ($output, (int)$op1 & 1);
731. break;
732. case "onboard":
733. if (is_array($op1))
734. badinput ("onboard expects a string, not an array.");
735. array_push ($output, (!empty($space[(string)$op1])&&($space[(string)$op1] != "-")));
736. break;
737. case "onebits":
738. $bits= 0;
739. $op1 = intval($op1);
740. while ($op1) {
741. if ($op1 & 1)
742. $bits++;
743. $op1 >>= 1;
744. }
745. array_push ($output, $bits);
746. break;
747. case "ord":
748. array_push ($output, ord($op1));
749. break;
750. case "pieceimg":
751. array_push ($output, $pieces[$op1] ?? "");
752. break;
753. case "rank":
754. array_push ($output, get_ranknum($op1));
755. break;
756. case "rankname":
757. array_push ($output, isset($rankname[$op1]) ? $rankname[$op1] : (isset($rank[$op1]) ? $rank[$op1] : ""));
758. break;
759. case "realname":
760. array_push ($output, isset($REALNAME[$op1]) ? $REALNAME[$op1] : $op1);
761. break;
762. case "remove":
763. if (is_array($op1)) {
764. foreach ($op1 as $val) {
765. if (array_key_exists($val, $space))
766. $space[$val] = '@';
767. else
768. error_log (strval($val) . " is not in \$space");
769. }
770. }
771. else
772. $space[$op1] = '@';
773. $output = array(true);
774. $input = array();
775. break;
776. case "reverse":
777. if ((array)$op1 === $op1)
778. array_push ($output, array_reverse($op1, false));
779. else
780. array_push ($output, strrev($op1));
781. break;
782. case "shuffle":
783. array_push($output, shufflearray($op1));
784. break;
785. case "sign":
786. array_push ($output, (($op1 < 0) ? -1 : (($op1 > 0) ? 1 : 0)));
787. break;
788. case "space":
789. array_push ($output, empty($space[$op1]) ? false : $space[$op1]);
790. // debug2("<FONT COLOR=\"red\">space == </FONT>", $space);
791. break;
792. case "string":
793. if (is_array($op1))
794. array_push($output, implode("", $op1));
795. else
796. array_push($output, strval($op1));
797. break;
798. case "strlen":
799. array_push ($output, strlen($op1));
800. break;
801. case "target":
802. $target = $op1;
803. // returns no value. used with check.
804. break;
805. case "tolower":
806. array_push ($output, strtolower($op1));
807. break;
808. case "toupper":
809. array_push ($output, strtoupper($op1));
810. break;
811. case "twinonfile":
812. foreach ($rank as $key => $val) {
813. if ($ranknum[$op1] == $key)
814. continue;
815. $c = $filename[$op1] . $val;
816. if ($space[$op1] == $space[$c])
817. break;
818. }
819. array_push ($output, ($space[$op1] == $space[$c]));
820. break;
821. case "type":
822. array_push ($output, gettype($op1));
823. break;
824. case "unique":
825. array_push ($output, array_unique($op1));
826. break;
827. case "urlencode":
828. array_push ($output, urlencode($op1));
829. break;
830. case "var":
831. array_push ($output, getuservar($op1));
832. break;
833. case "var_export":
834. array_push ($output, var_export($op1, true));
835. break;
836. }
837. break;
838. case "1|2":
839. // This caused an error with an and operator
840. // if (count($output) < 1)
841. // error("The {$arg} operator requires at least 1 argument.", $linenum);
842. // debug2 ("BEFORE AND Output", $output);
843. if (count($output) == 1) {
844. $op1 = array_pop ($output);
845. $op2 = NULL;
846. }
847. else {
848. $op1 = array_pop ($output);
849. $op2 = array_pop ($output);
850. }
851. switch ($arg) {
852. case "and": case "&&":
853. // debug2 ("AND op1", $op1);
854. // debug2 ("AND op2", ($op2 !== NULL) ? $op2 : "NULL");
855. if ($op2 === NULL) {
856. if (((array)$op1 === $op1) ? !polish($op1, $linenum, $substitutions) : !$op1) {
857. // debug2 ("FALSE", "FALSE");
858. $output = array(false);
859. $input = array();
860. }
861. // debug2 ("AND1 output", $output);
862. }
863. else {
864. $output[] = (((array)$op1 === $op1) ? polish($op1, $linenum, $substitutions) : $op1) && (((array)$op2 === $op2) ? polish($op2, $linenum, $substitutions) : $op2);
865. // debug2("AND2 Output", $output);
866. }
867. break;
868. case "merge":
869. // Just in case merge gets NULL for one value
870. $ar1 = is_array($op1) ? $op1 : array($op1);
871. $ar2 = is_array($op2) ? $op2 : array($op2);
872. array_push ($output, array_merge($ar1, $ar2));
873. break;
874. case "onlyif":
875. if ($op1 == false) {
876. $output = array(($op2 === NULL) ? $op1 : $op2);
877. $input = array();
878. }
879. break;
880. case "or": case "||":
881. // debug2 ("op1", $op1);
882. // debug2 ("op2", $op2);
883. if ($op2 === NULL) {
884. if (((array)$op1 === $op1) ? polish($op1, $linenum, $substitutions) : $op1) {
885. $output = array(true);
886. $input = array();
887. }
888. }
889. else
890. $output[] = (((array)$op1 === $op1) ? polish($op1, $linenum, $substitutions) : $op1)
891. || (((array)$op2 === $op2) ? polish($op2, $linenum, $substitutions) : $op2);
892. break;
893. case "trim":
894. if ($op2 === NULL)
895. array_push ($output, trim($op1));
896. else
897. array_push ($output, trim($op1, $op2));
898. break;
899. case "unless":
900. if ($op1 != false) {
901. $output = array(($op2 === NULL) ? false : $op2);
902. $input = array();
903. }
904. break;
905. }
906. break;
907. case "2":
908. if (count($output) < 2)
909. error ("The {$arg} operator requires at least two arguments.", $linenum);
910.
911. $op1 = array_pop($output);
912. $op2 = array_pop($output);
913. switch ($arg) {
914. case "!==":
915. array_push ($output, ($op1 !== $op2));
916. break;
917. case "<=":
918. array_push ($output, ($op1 <= $op2));
919. break;
920. case ">=":
921. array_push ($output, ($op1 >= $op2));
922. break;
923. case "<<":
924. array_push ($output, ($op1 << $op2));
925. break;
926. case ">>":
927. array_push ($output, ($op1 >> $op2));
928. break;
929. case "base":
930. // op1 is base, op2 is number
931. array_push ($output, base_convert($op2, 10, $op1));
932. break;
933. case "bitand": case "&":
934. array_push($output, ((int)$op1 & (int)$op2));
935. break;
936. case "bitor": case "|":
937. array_push($output, ((int)$op1 | (int)$op2));
938. break;
939. case "bitxor":
940. array_push($output, ((int)$op1 ^ (int)$op2));
941. break;
942. case "char":
943. if (!is_string($op1))
944. error("The char function requires the first operand to be a string.", $linenum);
945. if ($op2 > strlen($op1))
946. array_push ($output, "");
947. else
948. array_push ($output, $op1[$op2]);
949. break;
950. case "checkrhombus":
951. $f1 = $filenum[$op1]; $r1 = $ranknum[$op1];
952. $f2 = $filenum[$op2]; $r2 = $ranknum[$op2];
953. $fdist = abs($f1-$f2);
954. $rdist = abs($r1-$r2);
955. $mindist = min($fdist, $rdist);
956. $maxdist = max($fdist, $rdist);
957. if ($maxdist != 2*$mindist)
958. $legal = false;
959. else {
960. $legal = true;
961. $xdir = ($f2-$f1)/$fdist;
962. $ydir = ($r2-$r1)/$rdist;
963. if ($fdist > $rdist) {
964. for ($i = 1; $i <= $mindist; $i++) {
965. $c = $file[$f1 + $i*$xdir] . $rank[$r1];
966. if ($space[$c] != "@") {
967. $legal = false;
968. break;
969. }
970. }
971. if ($legal == true) {
972. for ($i = 1; $i <= $mindist; $i++) {
973. $c = $file[$f2 - $i*$xdir] . $rank[$r2 - $i*$ydir];
974. if ($space[$c] != "@") {
975. $legal = false;
976. break;
977. }
978. }
979. }
980. if ($legal == false) {
981. $legal = true;
982. for ($i = 1; $i <= $mindist; $i++) {
983. $c = $file[$f1 + $i*$xdir] . $rank[$r1 + $i*$ydir];
984. if ($space[$c] != "@") {
985. $legal = false;
986. break;
987. }
988. }
989. if ($legal == true) {
990. for ($i = 1; $i <= $mindist; $i++) {
991. $c = $file[$f2 - $i*$xdir] . $rank[$r2];
992. if ($space[$c] != "@") {
993. $legal = false;
994. break;
995. }
996. }
997. }
998. }
999. }
1000. else {
1001. for ($i = 1; $i <= $mindist; $i++) {
1002. $c = $file[$f1] . $rank[$r1 + $i*$ydir];
1003. if ($space[$c] != "@") {
1004. $legal = false;
1005. break;
1006. }
1007. }
1008. if ($legal == true) {
1009. for ($i = 1; $i <= $mindist; $i++) {
1010. $c = $file[$f2 - $i*$xdir] . $rank[$r2 - $i*$ydir];
1011. if ($space[$c] != "@") {
1012. $legal = false;
1013. break;
1014. }
1015. }
1016. }
1017. if ($legal == false) {
1018. $legal = true;
1019. for ($i = 1; $i <= $mindist; $i++) {
1020. $c = $file[$f1 + $i*$xdir] . $rank[$r1 + $i*$ydir];
1021. if ($space[$c] != "@") {
1022. $legal = false;
1023. break;
1024. }
1025. }
1026. if ($legal == true) {
1027. for ($i = 1; $i <= $mindist; $i++) {
1028. $c = $file[$f2] . $rank[$r2 - $i*$ydir];
1029. if ($space[$c] != "@") {
1030. $legal = false;
1031. break;
1032. }
1033. }
1034. }
1035. }
1036. }
1037. }
1038. array_push ($output, $legal);
1039. break;
1040. case "cmp":
1041. array_push ($output, ($op1 == $op2) ? 0 : (($op1 > $op2) ? 1 : -1));
1042. break;
1043. case "diff":
1044. $ar1 = is_array($op1) ? $op1 : array($op1);
1045. $ar2 = is_array($op2) ? $op2 : array($op2);
1046. array_push ($output, array_diff($ar1, $ar2));
1047. break;
1048. case "direction":
1049. $f1 = get_filenum($op1);
1050. if (!is_numeric($f1))
1051. error("First argument {$op1} has no file number", $linenum);
1052. $r1 = get_ranknum($op1);
1053. if (!is_numeric($r1))
1054. error("First argument {$op1} has no rank number", $linenum);
1055. $f2 = get_filenum($op2);
1056. if (!is_numeric($f2))
1057. error("Second argument {$op2} has no file number", $linenum);
1058. $r2 = get_ranknum($op2);
1059. if (!is_numeric($r2))
1060. error("Second argument {$op2} has no rank number", $linenum);
1061. $rd = $r2 - $r1;
1062. $fd = $f2 - $f1;
1063. $gd = gcd(abs($rd), abs($fd));
1064. if ($gd != 0) {
1065. $rd /= $gd;
1066. $fd /= $gd;
1067. }
1068. $d = ($rd < 0) ? str_pad("", abs($rd), "s") : str_pad("", $rd, "n");
1069. $d .= ($fd < 0) ? str_pad("", abs($fd), "w") : str_pad("", $fd, "e");
1070. array_push ($output, $d ? $d : false);
1071. break;
1072. case "distance":
1073. $f1 = get_filenum($op1);
1074. if (!is_numeric($f1))
1075. error("First argument {$op1} has no file number", $linenum);
1076. $r1 = get_ranknum($op1);
1077. if (!is_numeric($r1))
1078. error("First argument {$op1} has no rank number", $linenum);
1079. $f2 = get_filenum($op2);
1080. if (!is_numeric($f2))
1081. error("Second argument {$op2} has no file number", $linenum);
1082. $r2 = get_ranknum($op2);
1083. if (!is_numeric($r2))
1084. error("Second argument {$op2} has no rank number", $linenum);
1085. $rd = abs ($r2 - $r1);
1086. $fd = abs ($f2 - $f1);
1087. array_push ($output, max($rd, $fd));
1088. break;
1089. case "div": case "/":
1090. array_push ($output, (($op1 - ($op1 % $op2)) / $op2));
1091. break;
1092. case "elem":
1093. if ((array)$op1 === $op1)
1094. $op1 = current($op1);
1095. if ((array)$op2 === $op2) {
1096. array_push ($output, $op2[$op1] ?? NULL);
1097. }
1098. else {
1099. array_push ($output, getuservar("{$op2}.{$op1}"));
1100. }
1101. break;
1102. case "equal": case "==":
1103. array_push ($output, ($op1 == $op2));
1104. break;
1105. case "explode":
1106. if (empty($op1))
1107. array_push ($output, str_split($op2, 1));
1108. else
1109. array_push ($output, explode($op1, $op2));
1110. break;
1111. case "fnmatch":
1112. array_push ($output, fnmatch($op1, $op2));
1113. break;
1114. case "gcd":
1115. array_push($output, gcd($op1, $op2));
1116. break;
1117. case "greater": case ">":
1118. array_push ($output, ($op1 > $op2));
1119. break;
1120. case "hamming":
1121. $l = strlen($op1);
1122. if ($l != strlen($op2))
1123. error ("The hamming function requires two strings of the same length.", $linenum);
1124. for ($i = 0, $hd = 0; $i < $l; $i++) {
1125. if ($op1[$i] != $op2[$i])
1126. $hd++;
1127. }
1128. array_push ($output, $hd);
1129. break;
1130. case "htmllink":
1131. array_push ($output, "<A HREF=\"{$op1}\">{$op2}</A>");
1132. break;
1133. case "identical": case "===":
1134. array_push ($output, ($op1 === $op2));
1135. break;
1136. case "join": case ".":
1137. if (((array)$op1 === $op1) || ((array)$op2 === $op2)) {
1138. $newarray = array();
1139. if ((array)$op1 !== $op1) {
1140. foreach ($op1 as $e1)
1141. array_push ($newarray, $e1 . $op2);
1142. }
1143. elseif ((array)$op2 !== $op2) {
1144. foreach ($op2 as $e2)
1145. array_push ($newarray, $op1 . $e2);
1146. }
1147. else {
1148. foreach ($op2 as $e2)
1149. foreach ($op1 as $e1)
1150. array_push ($newarray, $e1 . $e2);
1151. }
1152. array_push ($output, $newarray);
1153. }
1154. else
1155. array_push ($output, $op1 . $op2);
1156. break;
1157. case "leftstr":
1158. array_push ($output, substr($op1, 0, $op2));
1159. break;
1160. case "less": case "<":
1161. array_push ($output, ($op1 < $op2));
1162. break;
1163. case "levenshtein":
1164. array_push ($output, levenshtein($op1, $op2));
1165. break;
1166. case "max":
1167. array_push ($output, max($op1, $op2));
1168. break;
1169. case "min":
1170. array_push ($output, min($op1, $op2));
1171. break;
1172. case "minus": case "-":
1173. if (is_string($op1)) {
1174. if (substr_count($op1, ".") == 1)
1175. $op1 = floatval($op1);
1176. else
1177. $op1 = intval($op1);
1178. }
1179. if (is_string($op2)) {
1180. if (substr_count($op2, ".") == 1)
1181. $op2 = floatval($op2);
1182. else
1183. $op2 = intval($op2);
1184. }
1185. if (is_numeric($op1) && is_numeric($op2))
1186. array_push ($output, ($op1 - $op2));
1187. else
1188. error ("<B>minus</B> or <B>-</B> was used with a non-numeric value.", $linenum);
1189. break;
1190. case "mod": case "%":
1191. // x mod y = x - floor(x/y)*y
1192. // The % operator will return a division by zero error.
1193. // But since anything multiplied by zero should be zero,
1194. // the value of (x/y) becomes irrelevant when y is 0.
1195. // The product of 0 * (x/0) should still be 0.
1196. // Since x - 0 = x, the value of x is returned.
1197. array_push ($output, ($op2 ? ($op1 % $op2) : $op1));
1198. break;
1199. case "mult": case "*":
1200. array_push ($output, ($op1 * $op2));
1201. break;
1202. case "nand":
1203. // De Morgans: (!p or !q) == !(p and q) == p nand q
1204. $output[] = !(((array)$op1 === $op1) ? polish($op1, $linenum, $substitutions) : $op1) || !(((array)$op2 === $op2) ? polish($op2, $linenum, $substitutions) : $op2);
1205. break;
1206. case "nor":
1207. // De Morgans: (!p and !q) == !(p or q) == neither p nor q
1208. $output[] = !(((array)$op1 === $op1) ? polish($op1, $linenum, $substitutions) : $op1) && !(((array)$op2 === $op2) ? polish($op2, $linenum, $substitutions) : $op2);
1209. break;
1210. case "onfile":
1211. foreach ($rank as $key => $val) {
1212. $c = $op1 . $val;
1213. if ($space[$c] == $op2)
1214. break;
1215. }
1216. array_push ($output, ($op2 == $space[$c]));
1217. break;
1218. case "path":
1219. if (array_key_exists($op1, $space) && array_key_exists($op2, $space)) {
1220. $f1 = get_filenum($op1); $r1 = get_ranknum($op1);
1221. $f2 = get_filenum($op2); $r2 = get_ranknum($op2);
1222. $rd = $r2 - $r1;
1223. $fd = $f2 - $f1;
1224. $gd = gcd(abs($rd), abs($fd));
1225. if ($gd) {
1226. $rd /= $gd;
1227. $fd /= $gd;
1228. }
1229. $newarray = array();
1230. do {
1231. $f1 += $fd;
1232. $r1 += $rd;
1233. $c = get_file($f1) . get_rank($r1);
1234. if ($c == $op2)
1235. break;
1236. $newarray[] = $c;
1237. } while (1);
1238. // return $newarray;
1239. array_push ($output, $newarray);
1240. }
1241. else
1242. array_push ($output, array());
1243. break;
1244. case "plus": case "+":
1245. if (is_numeric($op1) && is_numeric($op2))
1246. array_push ($output, ($op1 + $op2));
1247. else
1248. array_push ($output, 0);
1249. break;
1250. case "pow":
1251. array_push ($output, pow($op1, $op2));
1252. break;
1253. case "rand":
1254. array_push ($output, mt_rand($op1, $op2));
1255. break;
1256. case "range":
1257. array_push ($output, range($op1, $op2));
1258. break;
1259. case "regmatch":
1260. array_push ($output, preg_match($op1, $op2));
1261. break;
1262. case "revealed":
1263. $f1 = get_filenum($op1); $r1 = get_ranknum($op1);
1264. $f2 = get_filenum($op2); $r2 = get_ranknum($op2);
1265. $rd = $r2 - $r1;
1266. $fd = $f2 - $f1;
1267. $gd = gcd(abs($rd), abs($fd));
1268. if ($gd) {
1269. $rd /= $gd;
1270. $fd /= $gd;
1271. }
1272. do {
1273. $f1 += $fd;
1274. $r1 += $rd;
1275. if (isset($file[$f1]) && isset($rank[$r1]))
1276. $c = $file[$f1] . $rank[$r1];
1277. else
1278. $c = "";
1279. } while (isset($space[$c]) && ($space[$c] == "@"));
1280. array_push ($output, isset($space[$c]) ? $c : false);
1281. break;
1282. case "rightstr":
1283. array_push ($output, substr($op1, -$op2));
1284. break;
1285. case "same":
1286. array_push ($output, !strcasecmp($op1, $op2));
1287. break;
1288. case "samecase":
1289. $case1 = $case2 = 0;
1290. if ($op1 != strtoupper($op1)) $case1 |= 1;
1291. if ($op1 != strtolower($op1)) $case1 |= 2;
1292. if ($op2 != strtoupper($op2)) $case2 |= 1;
1293. if ($op2 != strtolower($op2)) $case2 |= 2;
1294. array_push ($output, ($case1 == $case2));
1295. break;
1296. case "search":
1297. array_push ($output, array_search($op1, $op2));
1298. break;
1299. case "slope":
1300. $f1 = $filenum[$op1] ?? 0; $r1 = $ranknum[$op1] ?? 0;
1301. $f2 = $filenum[$op2] ?? 0; $r2 = $ranknum[$op2] ?? 0;
1302. $d = $f1-$f2;
1303. array_push ($output, $d ? ($r1 - $r2)/$d : 0);
1304. break;
1305. case "strstr":
1306. if (!is_string($op1) || !is_string($op2))
1307. error ("Tried to pass non-string to strstr", $linenum);
1308. array_push ($output, strstr($op1, $op2));
1309. break;
1310. case "unequal": case "!=":
1311. array_push ($output, ($op1 != $op2));
1312. break;
1313. case "union":
1314. if (isset($op1) && is_array($op1))
1315. if (isset($op2) && is_array($op2))
1316. $newarray = array_merge($op1, $op2);
1317. else {
1318. $newarray = $op1;
1319. array_push($$newarray, $op2);
1320. }
1321. elseif (is_array($op2)) {
1322. $newarray = $op2;
1323. array_push($newarray, $op1);
1324. }
1325. else
1326. $newarray = array($op1, $op2);
1327. array_push ($output, $newarray);
1328. break;
1329. case "xor":
1330. array_push ($output, ($op1 xor $op2));
1331. break;
1332. }
1333. break;
1334. case "2|3":
1335. if (count($output) < 2)
1336. error("The {$arg} operator requires at least two arguments.", $linenum);
1337. $op1 = array_pop($output);
1338. $op2 = array_pop($output);
1339. $op3 = array_pop($output);
1340. switch ($arg) {
1341. case "what":
1342. case "where":
1343. if ($op3 === NULL) {
1344. // Use logical directions if the third argument is absent
1345. if (array_key_exists($op1, $map) && is_array($map[$op1])) {
1346. if (is_array($op2)) {
1347. // $op2 should be an array containing a series of logical directions.
1348. // echo "<P>where {$op1} " . implode($op2) . "</P>";
1349. $c = $op1;
1350. foreach ($op2 as $d) {
1351. // echo "<P>d is {$d}</P>";
1352. if (array_key_exists($d, $map[$c])) {
1353. $c = $map[$c][$d];
1354. // echo "<P>c is {$c}</P>";
1355. }
1356. else {
1357. $c = false;
1358. // echo "<P>c is false</P>";
1359. break;
1360. }
1361. }
1362. }
1363. elseif (array_key_exists($op2, $map[$op1]))
1364. $c = $map[$op1][$op2]; // $op2 should be a single logical direction
1365. }
1366. else
1367. $c = false;
1368. }
1369. else {
1370. // $op2 and $op3 are the number of files and ranks away that the space to be identified is
1371. $f = get_filenum($op1); $r = get_ranknum($op1);
1372. $f += (int)$op2;
1373. $r += (int)$op3;
1374. $c = get_file($f) . get_rank($r);
1375. }
1376. if ($arg == "what")
1377. array_push ($output, empty($space[$c]) ? false : $space[$c]);
1378. else
1379. array_push ($output, (empty($c) || !array_key_exists($c, $space)) ? false : $c);
1380. break;
1381. }
1382. break;
1383. case "3":
1384. if (count($output) < 3)
1385. error("The {$arg} operator requires at least three arguments.", $linenum);
1386. $op1 = array_pop($output);
1387. $op2 = array_pop($output);
1388. $op3 = array_pop($output);
1389. switch ($arg) {
1390. case "behindscreen":
1391. $f = $filenum[$op1]; $r = $ranknum[$op1];
1392. for ($hops = 0; $hops < 2; $hops++) {
1393. do {
1394. $f += $op2;
1395. $r += $op3;
1396. $c = get_file($f) . get_rank($r);
1397. } while (isset($space[$c]) && ($space[$c] == "@"));
1398. }
1399. array_push ($output, isset($space[$c]) ? $space[$c] : false);
1400. break;
1401. case "checknsteps": case "checkmaxsteps":
1402. $f1 = $filenum[$op1]; $r1 = $ranknum[$op1];
1403. $f2 = $filenum[$op2]; $r2 = $ranknum[$op2];
1404. if (($f1 === false) || ($f2 === false))
1405. $ret = false;
1406. else {
1407. $occupant = $space[$op1];
1408. $space[$op1] = "@";
1409. $ret = checknsteps($f1, $r1, $f2, $r2, $op3, $arg == "checkmaxsteps");
1410. $space[$op1] = $occupant;
1411. }
1412. array_push ($output, $ret);
1413. break;
1414. case "cond":
1415. if ($op1) {
1416. if ((array)$op2 === $op2)
1417. $op2 = polish($op2, $linenum, $substitutions);
1418. array_push ($output, $op2);
1419. }
1420. else {
1421. if ((array)$op3 === $op3)
1422. $op3 = polish($op3, $linenum, $substitutions);
1423. array_push ($output, $op3);
1424. }
1425. /*
1426. array_push (
1427. $output, $op1 ?
1428. (
1429. ((array)$op2 === $op2)
1430. ?
1431. polish($op2, $linenum, $substitutions)
1432. :
1433. $op2
1434. )
1435. :
1436. (
1437. ((array)$op3 === $op3)
1438. ?
1439. polish($op3, $linenum, $substitutions)
1440. :
1441. $op3
1442. )
1443. );
1444. */
1445. break;
1446. case "insight":
1447. $f = get_filenum($op1); $r = get_ranknum($op1);
1448. $c = "";
1449. do {
1450. $f += $op2;
1451. $r += $op3;
1452. if (!isset($file[$f]) || !isset($rank[$r]))
1453. break;
1454. $c = $file[$f] . $rank[$r];
1455. } while (isset($space[$c]) && ($space[$c] == "@"));
1456. array_push ($output, isset($space[$c]) ? $space[$c] : false);
1457. break;
1458. case "leaps":
1459. $f = get_filenum($op1); $r = get_ranknum($op1);
1460. $op2 = abs($op2);
1461. $op3 = abs($op3);
1462. $temp = array();
1463. if (isset($file[$f + $op2]) && isset($rank[$r + $op3]))
1464. $temp[] = $file[$f + $op2] . $rank[$r + $op3];
1465. if ($op2 && isset($file[$f - $op2]) && isset($rank[$r + $op3]))
1466. $temp[] = $file[$f - $op2] . $rank[$r + $op3];
1467. if ($op3 && isset($rank[$r - $op3])) {
1468. if (isset($file[$f + $op2]))
1469. $temp[] = $file[$f + $op2] . $rank[$r - $op3];
1470. if ($op2 && isset($file[$f - $op2]))
1471. $temp[] = $file[$f - $op2] . $rank[$r - $op3];
1472. }
1473. if ($op2 != $op3) {
1474. if (isset($file[$f + $op3]) && isset($rank[$r + $op2]))
1475. $temp[] = $file[$f + $op3] . $rank[$r + $op2];
1476. if ($op3 && isset($file[$f - $op3]) && isset($rank[$r + $op2]))
1477. $temp[] = $file[$f - $op3] . $rank[$r + $op2];
1478. if ($op2 && isset($rank[$r - $op2])) {
1479. if (isset($file[$f + $op3]))
1480. $temp[] = $file[$f + $op3] . $rank[$r - $op2];
1481. if ($op3 && isset($file[$f - $op3]))
1482. $temp[] = $file[$f - $op3] . $rank[$r - $op2];
1483. }
1484. }
1485. $leaps = array();
1486. $max = count($temp);
1487. for ($j = 0; $j < $max; $j++)
1488. if (isset($space[$temp[$j]]))
1489. $leaps[] = $temp[$j];
1490. array_push ($output, $leaps);
1491. break;
1492. case "near": // coordinate, piece, distance
1493. $f = get_filenum($op1); $r = get_ranknum($op1);
1494. $ret = false;
1495. $maxx = min(count($file)-1, $f+$op3);
1496. $maxy = min(count($rank)-1, $r+$op3);
1497. for ($x = max(0, $f - $op3); $x <= $maxx; $x++) {
1498. for ($y = max(0, $r - $op3); $y <= $maxy; $y++) {
1499. $c = $file[$x] . $rank[$y];
1500. if ($space[$c] == $op2) {
1501. $ret = $c;
1502. break 2;
1503. }
1504. }
1505. }
1506. array_push ($output, $ret);
1507. break;
1508. case "ray":
1509. $temp = array();
1510. if (array_key_exists($op1, $filenum) && array_key_exists($op1, $ranknum)) {
1511. $f = get_filenum($op1); $r = get_ranknum($op1);
1512. for ($i = 1; true; $i++) {
1513. if ((get_file($f + $i*$op2, "null") == "null") || (get_rank($r + $i*$op3, "null") == "null"))
1514. break;
1515. $c = get_file($f + $i*$op2) . get_rank($r + $i*$op3);
1516. if (!array_key_exists($c, $space))
1517. break;
1518. $temp[] = $c;
1519. }
1520. }
1521. array_push ($output, $temp);
1522. break;
1523. case "rays":
1524. $temp = array();
1525. if (isset($filenum[$op1]) && isset($ranknum[$op1])) {
1526. $f = $filenum[$op1]; $r = $ranknum[$op1];
1527. $op2 = abs($op2);
1528. $op3 = abs($op3);
1529. if ($space[$op1]) {
1530. for ($i = 1; true; $i++) {
1531. if (!isset($file[$f + $i*$op2]) || !isset($rank[$r + $i*$op3]))
1532. break;
1533. $c = $file[$f + $i*$op2] . $rank[$r + $i*$op3];
1534. if (empty($space[$c]))
1535. break;
1536. $temp[] = $c;
1537. }
1538. if ($op3) {
1539. for ($i = 1; true; $i++) {
1540. if (!isset($file[$f + $i*$op2]) || !isset($rank[$r - $i*$op3]))
1541. break;
1542. $c = $file[$f + $i*$op2] . $rank[$r - $i*$op3];
1543. if (empty($space[$c]))
1544. break;
1545. $temp[] = $c;
1546. }
1547. }
1548. if ($op2) {
1549. for ($i = 1; true; $i++) {
1550. if (!isset($file[$f - $i*$op2]) || !isset($rank[$r + $i*$op3]))
1551. break;
1552. $c = $file[$f - $i*$op2] . $rank[$r + $i*$op3];
1553. if (empty($space[$c]))
1554. break;
1555. $temp[] = $c;
1556. }
1557. }
1558. if ($op2 && $op3) {
1559. for ($i = 1; true; $i++) {
1560. if (!isset($file[$f - $i*$op2]) || !isset($rank[$r - $i*$op3]))
1561. break;
1562. $c = $file[$f - $i*$op2] . $rank[$r - $i*$op3];
1563. if (empty($space[$c]))
1564. break;
1565. $temp[] = $c;
1566. }
1567. }
1568. if ($op2 != $op3) {
1569. for ($i = 1; true; $i++) {
1570. if (!isset($file[$f + $i*$op3]) || !isset($rank[$r + $i*$op2]))
1571. break;
1572. $c = $file[$f + $i*$op3] . $rank[$r + $i*$op2];
1573. if (empty($space[$c]))
1574. break;
1575. $temp[] = $c;
1576. }
1577. if ($op2) {
1578. for ($i = 1; true; $i++) {
1579. if (!isset($file[$f + $i*$op3]) || !isset($rank[$r - $i*$op2]))
1580. break;
1581. $c = $file[$f + $i*$op3] . $rank[$r - $i*$op2];
1582. if (empty($space[$c]))
1583. break;
1584. $temp[] = $c;
1585. }
1586. }
1587. if ($op3) {
1588. for ($i = 1; true; $i++) {
1589. if (!isset($file[$f - $i*$op3]) || !isset($rank[$r + $i*$op2]))
1590. break;
1591. $c = $file[$f - $i*$op3] . $rank[$r + $i*$op2];
1592. if (empty($space[$c]))
1593. break;
1594. $temp[] = $c;
1595. }
1596. }
1597. if ($op2 && $op3) {
1598. for ($i = 1; true; $i++) {
1599. if (!isset($file[$f - $i*$op3]) || !isset($rank[$r - $i*$op2]))
1600. break;
1601. $c = $file[$f - $i*$op3] . $rank[$r - $i*$op2];
1602. if (empty($space[$c]))
1603. break;
1604. $temp[] = $c;
1605. }
1606. }
1607. }
1608. }
1609. }
1610. array_push ($output, $temp);
1611. break;
1612. case "ride":
1613. $f = get_filenum($op1); $r = get_ranknum($op1);
1614. $ride = array();
1615. do {
1616. $f = $f + $op2;
1617. $r = $r + $op3;
1618. if (empty($file[$f]) || empty($rank[$r])) {
1619. $c = "";
1620. break;
1621. }
1622. $c = get_file($f) . get_rank($r);
1623. if (!isset($space[$c]) || ($space[$c] == "-"))
1624. break;
1625. $ride[] = $c;
1626. } while ($space[$c] == "@");
1627. array_push ($output, $ride);
1628. break;
1629. case "str_replace":
1630. array_push ($output, str_replace($op1, $op2, $op3 ?? ""));
1631. break;
1632. case "substr":
1633. array_push ($output, $op3 ? substr($op1, $op2, $op3) : substr($op1, $op2));
1634. break;
1635. }
1636. break;
1637. case "4a": // Checks asymmetrically-defined moves
1638. if (count($output) < 4)
1639. error("The {$arg} operator requires at least four arguments.", $linenum);
1640. $op1 = array_pop($output);
1641. $op2 = array_pop($output);
1642. $op3 = array_pop($output);
1643. $op4 = array_pop($output);
1644. // debug2 ("op1", $op1);// debug2 ("op2", $op2);// debug2 ("op3", $op3);// debug2 ("op4", $op4);
1645. $f1 = get_filenum($op1); $r1 = get_ranknum($op1);
1646. $f2 = get_filenum($op2); $r2 = get_ranknum($op2);
1647. $fmove = $f2 - $f1;
1648. $rmove = $r2 - $r1;
1649. // debug2("fmove", $fmove); // debug2("rmove", $rmove);
1650. $result = (($fmove == $op3) && ($rmove == $op4));
1651. switch ($arg) {
1652. case "checkaleap":
1653. array_push ($output, $result);
1654. break;
1655. case "checkaride":
1656. if ($result)
1657. array_push ($output, true); // made single leap in right direction
1658. elseif (($fmove * $op4) != ($rmove * $op3))
1659. array_push ($output, false); // did not move multiple of basic leap
1660. elseif ((sgn($fmove) != sgn($op3)) || (sgn($rmove) != sgn($op4)))
1661. array_push ($output, false); // wrong direction
1662. else {
1663. $rungs = max(abs($fmove), abs($rmove)) / max(abs($op3), abs($op4));
1664. $fstep = $fmove / $rungs;
1665. $rstep = $rmove / $rungs;
1666. // debug ("rungs", $rungs);
1667. for ($i = 1; $i <= $rungs; $i++) {
1668. // debug2 ("i", $i);
1669. $c = $file[$f1 + $i*$fstep] . $rank[$r1 + $i*$rstep];
1670. // debug2 ("c", $c);
1671. if (($c == $op2) || ($space[$c] != "@"))
1672. break;
1673. }
1674. array_push ($output, ($c == $op2));
1675. }
1676. break;
1677. case "checkahop":
1678. if ($result)
1679. array_push ($output, false); // made single leap, not hopping over anything
1680. elseif (($fmove * $op4) != ($rmove * $op3))
1681. array_push ($output, false); // did not move multiple of basic leap
1682. elseif ((sgn($fmove) != sgn($op3)) || (sgn($rmove) != sgn($op4)))
1683. array_push ($output, false); // wrong direction
1684. else {
1685. $rungs = (max(abs($fmove), abs($rmove)) / max(abs($op3), abs($op4)));
1686. $fstep = $fmove / $rungs;
1687. $rstep = $rmove / $rungs;
1688. $hops = 0;
1689. for ($i = 1; $i < $rungs; $i++) {
1690. $c = $file[$f1 + $i*$fstep] . $rank[$r1 + $i*$rstep];
1691. if ($space[$c] == "-")
1692. break;
1693. if ($space[$c] != "@") {
1694. $hops++;
1695. if ($hops == 1)
1696. $screen = $c;
1697. }
1698. }
1699. array_push ($output, (($space[$c] != "-") && ($hops == 1)));
1700. }
1701. break;
1702. }
1703. break;
1704. case "4s": // Checks symmetrically-defined moves
1705. if (count($output) < 4)
1706. error("The {$arg} operator requires at least four arguments.", $linenum);
1707. $op1 = array_pop($output);
1708. $op2 = array_pop($output);
1709. $op3 = abs(array_pop($output));
1710. $op4 = abs(array_pop($output));
1711. $f1 = get_filenum($op1); $r1 = get_ranknum($op1);
1712. $f2 = get_filenum($op2); $r2 = get_ranknum($op2);
1713. $fdist = abs($f2 - $f1);
1714. $rdist = abs($r2 - $r1);
1715. $result = ((($fdist == $op3) && ($rdist == $op4)) || (($fdist == $op4) && ($rdist == $op3)));
1716. // debug ("Result", $result);
1717. switch ($arg) {
1718. case "checkgrasshop":
1719. if ($result)
1720. array_push ($output, false); // made only a single leap, not hopping over anything
1721. elseif ((($fdist * $op3) != ($rdist * $op4)) && (($rdist * $op3) != ($fdist * $op4)))
1722. array_push ($output, false); // distance moved is not multiple of basic leap
1723. elseif ((($op3*$op4 == 0) && ($fdist*$rdist == 0)) && (max($fdist, $rdist) % max($op3, $op4))) {
1724. array_push ($output, false); // distance moved is not multiple of basic leap
1725. }
1726. elseif ((($op3==$op4) && ($fdist==$rdist)) && ($rdist % $op3)) {
1727. array_push ($output, false); // distance moved is not multiple of basic leap
1728. }
1729. else {
1730. $rungs = (max($fdist, $rdist) / max($op3, $op4));
1731. $fmove = $f2 - $f1;
1732. $rmove = $r2 - $r1;
1733. $fstep = $fmove / $rungs;
1734. $rstep = $rmove / $rungs;
1735. do {
1736. $f1 += $fstep;
1737. $r1 += $rstep;
1738. $c = get_file($f1, "null") . get_rank($r1, "null");
1739. } while (array_key_exists($c, $space) && ($space[$c] == "@"));
1740. if ($c == $op2) // no screen
1741. array_push ($output, false);
1742. else {
1743. $screen = $c;
1744. $f1 += $fstep;
1745. $r1 += $rstep;
1746. $c = get_file($f1, "null") . get_rank($r1, "null");
1747. array_push ($output, ($c == $op2));
1748. }
1749. }
1750. break;
1751. case "checkhop":
1752. if ($result)
1753. array_push ($output, false); // made only a single leap, not hopping over anything
1754. elseif ((($fdist * $op3) != ($rdist * $op4)) && (($rdist * $op3) != ($fdist * $op4)))
1755. array_push ($output, false); // distance moved is not multiple of basic leap
1756. elseif ((($op3*$op4 == 0) && ($fdist*$rdist == 0)) && (max($fdist, $rdist) % max($op3, $op4))) {
1757. array_push ($output, false); // distance moved is not multiple of basic leap
1758. }
1759. elseif ((($op3==$op4) && ($fdist==$rdist)) && ($rdist % $op3)) {
1760. array_push ($output, false); // distance moved is not multiple of basic leap
1761. }
1762. else {
1763. $rungs = (max($fdist, $rdist) / max($op3, $op4));
1764. $fmove = $f2 - $f1;
1765. $rmove = $r2 - $r1;
1766. $fstep = $fmove / $rungs;
1767. $rstep = $rmove / $rungs;
1768. do {
1769. $f1 += $fstep;
1770. $r1 += $rstep;
1771. $c = get_file($f1) . get_rank($r1);
1772. } while (array_key_exists($c, $space) && ($space[$c] == "@"));
1773. if ($c == $op2) // no screen
1774. array_push ($output, false);
1775. else {
1776. $screen = $c;
1777. do {
1778. $f1 += $fstep;
1779. $r1 += $rstep;
1780. $c = get_file($f1) . get_rank($r1);
1781. } while (($c != $op2) && (array_key_exists($c, $space) && ($space[$c] == "@")));
1782. array_push ($output, ($c == $op2));
1783. }
1784. }
1785. break;
1786. case "checkleap":
1787. array_push ($output, $result);
1788. break;
1789. case "checklongleap":
1790. if ($lastcaptured != "@")
1791. array_push ($output, false); // Longleapers don't capture by displacement
1792. elseif ($result)
1793. array_push ($output, true); // made only a single leap, not capturing
1794. elseif ((($fdist * $op3) != ($rdist * $op4)) && (($rdist * $op3) != ($fdist * $op4)))
1795. array_push ($output, false); // distance moved is not multiple of basic leap
1796. elseif ((($op3*$op4 == 0) && ($fdist*$rdist == 0)) && (max($fdist, $rdist) % max($op3, $op4))) {
1797. array_push ($output, false); // distance moved is not multiple of basic leap
1798. }
1799. elseif ((($op3==$op4) && ($fdist==$rdist)) && ($rdist % $op3)) {
1800. array_push ($output, false); // distance moved is not multiple of basic leap
1801. }
1802. else {
1803. $rungs = (max($fdist, $rdist) / max($op3, $op4));
1804. $fmove = $f2 - $f1;
1805. $rmove = $r2 - $r1;
1806. $fstep = $fmove / $rungs;
1807. $rstep = $rmove / $rungs;
1808. for ($i = 1; $i < $rungs; $i++) {
1809. $c = get_file($f1 + $i*$fstep) . get_rank($r1 + $i*$rstep);
1810. if (($space[$c] != "@") && ($space[$c] == $space[$c-1]))
1811. break;
1812. }
1813. array_push ($output, (($space[$c] != "@") && ($space[$c] == $space[$c-1])));
1814. }
1815. break;
1816. case "checkride":
1817. if ($result)
1818. array_push ($output, true); // made only a single leap
1819. elseif ((($fdist * $op3) != ($rdist * $op4)) && (($rdist * $op3) != ($fdist * $op4))) {
1820. array_push ($output, false); // distance moved is not multiple of basic leap
1821. }
1822. elseif ((($op3*$op4 == 0) && ($fdist*$rdist == 0)) && (max($fdist, $rdist) % max($op3, $op4))) {
1823. array_push ($output, false); // distance moved is not multiple of basic leap
1824. }
1825. elseif ((($op3==$op4) && ($fdist==$rdist)) && ($rdist % $op3)) {
1826. array_push ($output, false); // distance moved is not multiple of basic leap
1827. }
1828. else {
1829. $rungs = (max($fdist, $rdist) / max($op3, $op4));
1830. $fmove = $f2 - $f1;
1831. $rmove = $r2 - $r1;
1832. $fstep = $rungs ? ($fmove / $rungs) : 0;
1833. $rstep = $rungs ? ($rmove / $rungs) : 0;
1834. $c = "";
1835. for ($i = 1; $i < $rungs; $i++) {
1836. $c = get_file($f1 + $i*$fstep) . get_rank($r1 + $i*$rstep);
1837. if (!array_key_exists($c, $space) || ($space[$c] != "@"))
1838. break;
1839. }
1840. array_push ($output, array_key_exists($c, $space) && ($space[$c] == "@"));
1841. }
1842. break;
1843. case "voidride":
1844. if ($result)
1845. array_push ($output, true); // made only a single leap
1846. elseif ((($fdist * $op3) != ($rdist * $op4)) && (($rdist * $op3) != ($fdist * $op4))) {
1847. array_push ($output, false); // distance moved is not multiple of basic leap
1848. }
1849. elseif ((($op3*$op4 == 0) && ($fdist*$rdist == 0)) && (max($fdist, $rdist) % max($op3, $op4))) {
1850. array_push ($output, false); // distance moved is not multiple of basic leap
1851. }
1852. elseif ((($op3==$op4) && ($fdist==$rdist)) && ($rdist % $op3)) {
1853. array_push ($output, false); // distance moved is not multiple of basic leap
1854. }
1855. else {
1856. $rungs = (max($fdist, $rdist) / max($op3, $op4));
1857. $fmove = $f2 - $f1;
1858. $rmove = $r2 - $r1;
1859. $fstep = $rungs ? ($fmove / $rungs) : 0;
1860. $rstep = $rungs ? ($rmove / $rungs) : 0;
1861. for ($i = 1; $i < $rungs; $i++) {
1862. $c = get_file($f1 + $i*$fstep) . get_rank($r1 + $i*$rstep);
1863. if ($space[$c] != "-")
1864. break;
1865. }
1866. array_push ($output, ($space[$c] == "-"));
1867. }
1868. break;
1869. }
1870. break;
1871. default:
1872. switch ($arg) {
1873. case "inrange":
1874. if (count($output) < 4)
1875. error("The {$arg} operator requires at least four arguments.", $linenum);
1876. $op1 = array_pop($output);
1877. $op2 = array_pop($output);
1878. $op3 = array_pop($output);
1879. $op4 = array_pop($output);
1880. $f = $filenum[$op1]; $r = $ranknum[$op1];
1881. for ($i = 0; $i < $op4; $i++) {
1882. $f += $op2;
1883. $r += $op3;
1884. if (isset($file[$f]) && isset($rank[$r]))
1885. $c = $file[$f] . $rank[$r];
1886. else
1887. $c = "";
1888. if (!isset($space[$c]) || ($space[$c] != "@"))
1889. break;
1890. }
1891. array_push ($output, isset($space[$c]) ? $space[$c] : false);
1892. break;
1893. case "voidleap":
1894. if (count($output) < 2)
1895. error("The {$arg} operator requires at least two arguments.", $linenum);
1896. $op1 = array_pop($output);
1897. $op2 = array_pop($output);
1898. $f1 = get_filenum($op1); $r1 = get_ranknum($op1);
1899. $f2 = get_filenum($op2); $r2 = get_ranknum($op2);
1900. $fmove = $f2 - $f1;
1901. $rmove = $r2 - $r1;
1902. $fd = ($fmove >= 0) ? 1 : -1;
1903. $rd = ($rmove >= 0) ? 1 : -1;
1904. // debug2 ("fd", $fd);
1905. // debug2 ("rd", $rd);
1906. $temp = $output;
1907. $f = $f1;
1908. $r = $r1;
1909. while (count($output) > 1) {
1910. $op3 = abs(array_pop($output));
1911. $op4 = abs(array_pop($output));
1912. do {
1913. $f += $op3*$fd;
1914. $r += $op4*$rd;
1915. $c = get_file($f, "null") . get_rank($r, "null");
1916. } while (array_key_exists($c, $space) && ($space[$c] == "-"));
1917. }
1918. if ($c == $op2) {
1919. unset ($output);
1920. unset ($temp);
1921. $output[0] = true;
1922. }
1923. else {
1924. $f = $f1;
1925. $r = $r1;
1926. while (count($temp) > 1) {
1927. $op3 = abs(array_pop($temp));
1928. $op4 = abs(array_pop($temp));
1929. do {
1930. $f += $op4*$fd;
1931. $r += $op3*$rd;
1932. $c = get_file($f, "null") . get_rank($r, "null");
1933. } while (array_key_exists($c, $space) && ($space[$c] == "-"));
1934. }
1935. unset ($output);
1936. unset ($temp);
1937. $output[0] = ($c == $op2);
1938. }
1939. break;
1940. case "checkatwostep":
1941. if (count($output) < 6)
1942. error("The {$arg} operator requires at least six arguments.", $linenum);
1943. $op1 = array_pop($output);
1944. $op2 = array_pop($output);
1945. $op3 = array_pop($output);
1946. $op4 = array_pop($output);
1947. $op5 = array_pop($output);
1948. $op6 = array_pop($output);
1949. $f1 = $filenum[$op1]; $r1 = $ranknum[$op1];
1950. $f2 = $filenum[$op2]; $r2 = $ranknum[$op2];
1951. if ((($f2 - $f1) != ($op3 + $op5)) || (($r2 - $r1) != ($op4 + $op6)))
1952. array_push ($output, false); // Space cannot be reached by these two steps.
1953. else {
1954. $c = get_file($f1 + $op3, "null") . get_rank($r1 + $op4, "null");
1955. array_push ($output, (($space[$c] ?? "") == "@"));
1956. }
1957. break;
1958. case "checktwostep":
1959. if (count($output) < 6)
1960. error("The {$arg} operator requires at least six arguments.", $linenum);
1961. $op1 = array_pop($output);
1962. $op2 = array_pop($output);
1963. $op3 = abs(array_pop($output));
1964. $op4 = abs(array_pop($output));
1965. $op5 = abs(array_pop($output));
1966. $op6 = abs(array_pop($output));
1967. $f1 = get_filenum($op1); $r1 = get_ranknum($op1);
1968. $f2 = get_filenum($op2); $r2 = get_ranknum($op2);
1969. $fdist = abs($f2 - $f1);
1970. $rdist = abs($r2 - $r1);
1971. $fsteps = $op3 + $op5;
1972. $rsteps = $op4 + $op6;
1973. if ((($fdist != $fsteps) || ($rdist != $rsteps)) && (($fdist != $rsteps) || ($rdist != $fsteps)))
1974. array_push ($output, false); // Space cannot be reached by these two steps.
1975. else {
1976. $fdir = (($f2 - $f1) < 0) ? -1 : 1;
1977. $rdir = (($r2 - $r1) < 0) ? -1 : 1;
1978. if (($fdist == $fsteps) && ($rdist == $rsteps)) {
1979. $fstep = $op3 * $fdir;
1980. $rstep = $op4 * $rdir;
1981. }
1982. else {
1983. $fstep = $op4 * $fdir;
1984. $rstep = $op3 * $rdir;
1985. }
1986. $passthru = $file[$f1 + $fstep] . $rank[$r1 + $rstep];
1987. array_push ($output, ($space[$passthru] == "@"));
1988. }
1989. break;
1990. // True multiple arity operators
1991. case "aggregate":
1992. if (count($output) < 2)
1993. error("The {$arg} operator requires at least two arguments.", $linenum);
1994. $op1 = array_pop($output);
1995. $op2 = array_pop($output);
1996. if (!is_array($op2)) {
1997. array_push ($output, $op2);
1998. $op2 = $output;
1999. $output = array();
2000. }
2001. $result = array();
2002. if ($op1 instanceof Lambda) {
2003. foreach ($op2 as $key => $temp) {
2004. if (is_array($temp))
2005. $args = $temp;
2006. else
2007. $args = array($temp);
2008. $r = polish($op1->stack, $linenum, $args, array("key" => $key));
2009. if ($r) {
2010. array_push ($result, $r);
2011. }
2012. }
2013. array_push ($output, $result);
2014. }
2015. break;
2016. case "allequal":
2017. if (count($output) < 2)
2018. error("The {$arg} operator requires at least two arguments.", $linenum);
2019. $op1 = array_pop($output);
2020. if ((array)$op1 === $op1)
2021. array_push ($output, allequal($op1));
2022. else {
2023. array_push ($output, $op1);
2024. $temp = $output;
2025. unset ($output);
2026. $output[0] = allequal($temp);
2027. }
2028. break;
2029. case "allfalse":
2030. case "nonetrue":
2031. if (count($output) < 2)
2032. error("The {$arg} operator requires at least two arguments.", $linenum);
2033. $op1 = array_pop($output);
2034. if ($op1 instanceof Lambda) {
2035. $op2 = array_pop($output);
2036. $result = true;
2037. foreach ($op2 as $key => $temp) {
2038. if (is_array($temp))
2039. $args = $temp;
2040. else
2041. $args = array($temp);
2042. $r = polish($op1->stack, $linenum, $args, array("key" => $key));
2043. if ($r) {
2044. $result = false;
2045. break;
2046. }
2047. }
2048. array_push ($output, $result);
2049. }
2050. elseif ((array)$op1 === $op1)
2051. array_push ($output, allfalse($op1));
2052. else {
2053. array_push ($output, $op1);
2054. $temp = $output;
2055. unset ($output);
2056. $output[0] = allfalse($temp);
2057. }
2058. break;
2059. case "alltrue":
2060. if (count($output) < 2)
2061. error("The {$arg} operator requires at least two arguments.", $linenum);
2062. $op1 = array_pop($output);
2063. if ($op1 instanceof Lambda) {
2064. $op2 = array_pop($output);
2065. $result = true;
2066. foreach ($op2 as $key => $temp) {
2067. if (is_array($temp))
2068. $args = $temp;
2069. else
2070. $args = array($temp);
2071. $r = polish($op1->stack, $linenum, $args, array("key" => $key));
2072. if (!$r) {
2073. $result = false;
2074. break;
2075. }
2076. }
2077. array_push ($output, $result);
2078. }
2079. elseif ((array)$op1 === $op1)
2080. array_push ($output, alltrue($op1));
2081. else {
2082. array_push ($output, $op1);
2083. $temp = $output;
2084. unset ($output);
2085. $output[0] = alltrue($temp);
2086. }
2087. break;
2088. case "anyfalse":
2089. if (count($output) < 2)
2090. error("The {$arg} operator requires at least two arguments.", $linenum);
2091. $op1 = array_pop($output);
2092. if ($op1 instanceof Lambda) {
2093. $op2 = array_pop($output);
2094. $result = false;
2095. foreach ($op2 as $key => $temp) {
2096. if (is_array($temp))
2097. $args = $temp;
2098. else
2099. $args = array($temp);
2100. $r = polish($op1->stack, $linenum, $args, array("key" => $key));
2101. if (!$r) {
2102. $result = true;
2103. break;
2104. }
2105. }
2106. array_push ($output, $result);
2107. }
2108. elseif ((array)$op1 === $op1)
2109. array_push ($output, anyfalse($op1));
2110. else {
2111. array_push ($output, $op1);
2112. $temp = $output;
2113. unset ($output);
2114. $output[0] = anyfalse($temp);
2115. }
2116. break;
2117. case "anytrue": case "any":
2118. if (count($output) < 2)
2119. error("The {$arg} operator requires at least two arguments.", $linenum);
2120. $op1 = array_pop($output);
2121. if ($op1 instanceof Lambda) {
2122. $op2 = array_pop($output);
2123. // print_r ($op1);
2124. // print_r ($op2);
2125. $result = false;
2126. foreach ($op2 as $key => $temp) {
2127. if (is_array($temp))
2128. $args = $temp;
2129. else
2130. $args = array($temp);
2131. $r = polish($op1->stack, $linenum, $args, array("key" => $key));
2132. if ($r) {
2133. $result = $r;
2134. break;
2135. }
2136. }
2137. array_push ($output, $result);
2138. }
2139. elseif ((array)$op1 === $op1) {
2140. echo "Array";
2141. array_push ($output, anytrue($op1));
2142. }
2143. else {
2144. array_push ($output, $op1);
2145. $temp = $output;
2146. unset ($output);
2147. $output[0] = anytrue($temp);
2148. }
2149. break;
2150. case "andsum":
2151. if (count($output) < 1)
2152. error("The {$arg} operator requires at least one argument.", $linenum);
2153. $op1 = array_pop($output);
2154. if ((array)$op1 === $op1)
2155. array_push ($output, and_sum($op1));
2156. else {
2157. array_push ($output, $op1);
2158. $temp = $output;
2159. unset ($output);
2160. $output[0] = and_sum($temp);
2161. }
2162. break;
2163. case "values":
2164. case "array":
2165. $op1 = array_pop($output);
2166. if ($op1 === NULL) {
2167. $output[0] = $output = array();
2168. }
2169. elseif ($op1 instanceof Lambda) {
2170. $op2 = array_pop($output);
2171. if (!is_array($op2)) {
2172. array_push ($output, $op2);
2173. $op2 = $output;
2174. $output = array();
2175. }
2176. $result = array();
2177. foreach ($op2 as $key => $val) {
2178. $args = array($key);
2179. if (is_array($val)) {
2180. foreach ($val as $v) {
2181. $args[] = $v;
2182. }
2183. }
2184. else
2185. $args[] = $val;
2186. $args = array($key, $val);
2187. array_push ($result, polish($op1->stack, $linenum, $args));
2188. }
2189. array_push ($output, $result);
2190. }
2191. elseif (($arg == "values") && is_array($op1)) {
2192. array_push ($output, array_values($op1));
2193. }
2194. else {
2195. array_push ($output, $op1);
2196. $newarray = array_reverse($output);
2197. unset($output);
2198. $output[0] = $newarray;
2199. }
2200. break;
2201. /*
2202. case "array":
2203. if (count($output) == 1)
2204. $newarray = explode(" ", $output[0]);
2205. else
2206. $newarray = array_reverse($output);
2207. // debug2("newarray", $newarray);
2208. unset($output);
2209. $output[0] = $newarray;
2210. break;
2211. */
2212. case "assoc":
2213. $newarray = array();
2214. while (count($output) > 1) {
2215. $key = array_pop($output);
2216. $val = array_pop($output);
2217. $newarray[$key] = $val;
2218. }
2219. unset($output);
2220. $output[0] = $newarray;
2221. break;
2222. case "checkapath":
2223. if (count($output) < 2)
2224. error("The {$arg} operator requires at least two arguments.", $linenum);
2225. $op1 = array_pop($output);
2226. $op2 = array_pop($output);
2227. $f = $filenum[$op1]; $r = $ranknum[$op1];
2228. if (($f === false) || ($r === false)) {
2229. array_push ($output, false);
2230. break;
2231. }
2232. $path = array_pop($output);
2233. if (!is_array($path)) {
2234. $output[] = $path;
2235. $path = $output;
2236. unset ($output);
2237. }
2238. if (count($path) & 1)
2239. error ("The checkapath operator requires an even number of operands.", $linenum);
2240. while (count($path)) {
2241. $f += array_pop($path);
2242. $r += array_pop($path);
2243. $c = $file[$f] . $rank[$r];
2244. if (!isset($space[$c]) || ($space[$c] != "@"))
2245. break;
2246. }
2247. if (count($path) > 0)
2248. $output[] = false;
2249. else
2250. $output[] = ($c == $op2);
2251. break;
2252. case "checkpath":
2253. if (count($output) < 2)
2254. error("The {$arg} operator requires at least two arguments.", $linenum);
2255. $op1 = array_pop($output);
2256. $op2 = array_pop($output);
2257. $f1 = get_filenum($op1); $r1 = get_ranknum($op1);
2258. $f2 = get_filenum($op2); $r2 = get_ranknum($op2);
2259. $fmove = $f2 - $f1;
2260. $rmove = $r2 - $r1;
2261. $fd = ($fmove >= 0) ? 1 : -1;
2262. $rd = ($rmove >= 0) ? 1 : -1;
2263. $temp = $output;
2264. $f = $f1;
2265. $r = $r1;
2266. while (count($output) > 1) {
2267. $op3 = abs(array_pop($output));
2268. $op4 = abs(array_pop($output));
2269. $f += $op3*$fd;
2270. $r += $op4*$rd;
2271. $c = get_file($f) . get_rank($r);
2272. if (!isset($space[$c]) || ($space[$c] != "@"))
2273. break;
2274. }
2275. if (($c == $op2) && empty($output)) {
2276. unset ($output);
2277. unset ($temp);
2278. $output[0] = true;
2279. }
2280. else {
2281. $f = $f1;
2282. $r = $r1;
2283. while (count($temp) > 1) {
2284. $op3 = abs(array_pop($temp));
2285. $op4 = abs(array_pop($temp));
2286. $f += $op4*$fd;
2287. $r += $op3*$rd;
2288. $c = get_file($f) . get_rank($r);
2289. if (!isset($space[$c]) || ($space[$c] != "@"))
2290. break;
2291. }
2292. if (empty($temp) && ($c == $op2)) {
2293. $output[0] = true;
2294. }
2295. else {
2296. unset ($output);
2297. $output[0]= false;
2298. }
2299. unset ($temp);
2300. }
2301. break;
2302. case "filter":
2303. if (count($output) < 2)
2304. error("The {$arg} operator requires at least two arguments.", $linenum);
2305. $op1 = array_pop($output);
2306. $op2 = array_pop($output);
2307. if (!is_array($op2)) {
2308. array_push ($output, $op2);
2309. $op2 = $output;
2310. $output = array();
2311. }
2312. $result = array();
2313. if ($op1 instanceof Lambda) {
2314. foreach ($op2 as $key => $val) {
2315. $args = array($key);
2316. if (is_array($val)) {
2317. foreach ($val as $v) {
2318. $args[] = $v;
2319. }
2320. }
2321. else
2322. $args[] = $val;
2323. $args = array($key, $val);
2324. $r = polish($op1->stack, $linenum, $args);
2325. if ($r) {
2326. $result[$key] = $val;
2327. }
2328. }
2329. array_push ($output, $result);
2330. }
2331. break;
2332. case "findpiece":
2333. if (count($output) < 1)
2334. error("The {$arg} operator requires at least two arguments.", $linenum);
2335. $op1 = array_pop($output);
2336. $op2 = array_pop($output);
2337. $op3 = array_pop($output);
2338. if ($op2 === NULL)
2339. array_push ($output, findpiece($op1, array_keys($space)));
2340. elseif ((array)$op2 === $op2)
2341. array_push ($output, findpiece($op1, $op2));
2342. elseif (isset($op3) && (is_array($op3))) {
2343. array_push ($output, findpiece($op1, $op3, $op2));
2344. }
2345. elseif (($op2 == "first") || ($op2 == "last")) {
2346. if (isset($op3))
2347. array_push ($output, $op3);
2348. $temp = array_reverse($output);
2349. unset ($output);
2350. $output[0] = findpiece($op1, $temp, $op2);
2351. }
2352. else {
2353. if (isset($op2) !== NULL)
2354. array_push ($output, $op2);
2355. $temp = array_reverse($output);
2356. unset ($output);
2357. $output[0] = findpiece($op1, $temp, "first");
2358. }
2359. break;
2360. case "fn":
2361. if (count($output) < 1)
2362. error("The {$arg} operator requires at least one arguments.", $linenum);
2363. $op1 = array_pop($output);
2364. if ($op1 instanceof Lambda)
2365. $fn = $op1->stack;
2366. elseif (is_array($op1))
2367. $fn = $op1;
2368. elseif (str_contains($op1 ?? "", " "))
2369. $fn = explode(" ", $op1);
2370. elseif (isset($functions[$op1])) {
2371. $fn = $functions[$op1];
2372. // $sub[$scope] = $op1;
2373. }
2374. else
2375. error ("The function '{$op1}' has not been defined. Its arguments are " . implode(" ", array_reverse($output)), $linenum);
2376. if (empty($fn))
2377. error ("The <B>fn</B> built-in function has not been given a valid function name or lambda function.", $linenum);
2378. $maxargs = 0;
2379. $max = count($fn);
2380. for ($i = 0; $i < $max; $i++) {
2381. if (array_key_exists($i, $fn) && !empty($fn[$i]) && ($fn[$i][0] == "#")) {
2382. $n = substr($fn[$i], 1);
2383. if (ctype_digit($n))
2384. $maxargs = max($maxargs, $n+1);
2385. }
2386. }
2387. if ($maxargs > 0) {
2388. if ($maxargs > count($output))
2389. error ("Function {$op1} requires more arguments than have been passed to it.", $linenum);
2390. for ($i = 0; $i < $maxargs; $i++)
2391. $args[$i] = array_pop($output);
2392. // // debug2 ("Entering", $op1);
2393. }
2394. else {
2395. $args = array_reverse($output);
2396. $output = array();
2397. }
2398. $temp = polish($fn, $linenum, $args);
2399. array_push ($output, $temp);
2400. // // debug2 ("Exited from", $op1);
2401. break;
2402. case "intersection":
2403. if (count($output) < 2)
2404. error("The {$arg} operator requires at least two arguments.", $linenum);
2405. $op1 = array_pop($output);
2406. $op2 = array_pop($output);
2407. if (!is_array($op1))
2408. die ("The first argument to intersection must be an array");
2409. if (!is_array($op2)) {
2410. array_push($output, $op2);
2411. $op2 = $output;
2412. $output = array();
2413. }
2414. array_push ($output, array_intersect($op1, $op2));
2415. break;
2416. case "isort":
2417. if (count($output) < 1)
2418. error("The {$arg} operator requires at least two arguments.", $linenum);
2419. $op1 = array_pop($output);
2420. if (is_array($op1)) {
2421. sort($op1, SORT_NATURAL | SORT_FLAG_CASE);
2422. array_push ($output, $op1);
2423. }
2424. else {
2425. array_push($output, $op1);
2426. $op1 = $output;
2427. unset($output);
2428. sort($op1, SORT_NATURAL | SORT_FLAG_CASE);
2429. $output[0] = $op1;
2430. }
2431. break;
2432. case "list":
2433. $op1 = array_pop($output);
2434. if ((array)$op1 === $op1)
2435. array_push ($output, implode(" ", $op1));
2436. else {
2437. array_push ($output, $op1);
2438. $temp = array_reverse($output);
2439. unset ($output);
2440. $output[0] = implode(" ", $temp);
2441. }
2442. break;
2443. case "logleap":
2444. // Determines whether a logical leap from one space to another is
2445. // possible through any of the directions provided.
2446. if (count($output) < 2)
2447. error("The {$arg} operator requires at least two arguments.", $linenum);
2448. $op1 = array_pop($output);
2449. $op2 = array_pop($output);
2450. do {
2451. $op3 = array_pop($output);
2452. if (is_array($op3))
2453. $ns = logleap($op1, $op2, $op3);
2454. elseif (isset($map[$op1][$op3]))
2455. $ns = $map[$op1][$op3];
2456. else {
2457. $ns = false;
2458. }
2459. } while (($ns != $op2) && (count($output) > 0));
2460. unset ($output);
2461. $output[0] = !empty($ns) && ($ns == $op2);
2462. break;
2463. case "logleaps":
2464. // Returns array of spaces that may be reached through single leaps in any
2465. // of the directions provided.
2466. if (count($output) < 2)
2467. error("The {$arg} operator requires at least two arguments.", $linenum);
2468. $op1 = array_pop($output);
2469. $tmp = array();
2470. while (count($output) > 0) {
2471. $op2 = array_pop($output);
2472. if (is_array($op2)) {
2473. $cc = $op1;
2474. for ($i = 0; $i < count($op2); $i++) {
2475. if (array_key_exists ($cc, $map) && is_array($map[$cc]) && array_key_exists($i, $op2) && array_key_exists($op2[$i], $map[$cc]))
2476. $cc = $map[$cc][$op2[$i]];
2477. else
2478. break;
2479. }
2480. if ($i == count($op2))
2481. array_push ($tmp, $cc);
2482. }
2483. elseif (array_key_exists ($op1, $map) && is_array($map[$op1]) && array_key_exists($op2, $map[$op1]))
2484. array_push ($tmp, $map[$op1][$op2]);
2485. }
2486. unset ($output);
2487. $output[0] = $tmp;
2488. break;
2489. case "lograys":
2490. /*
2491. if (count($output) < 2)
2492. error("The {$arg} operator requires at least two arguments.", $linenum);
2493. $op1 = array_pop($output);
2494. $allrays = array();
2495. while (count($output) > 0) {
2496. $ray = array();
2497. $op2 = array_pop($output);
2498. $cc = $op1;
2499. if (is_array($op2)) {
2500. foreach ($op2 as $d) {
2501. if (array_key_exists($d, $map[$cc])) {
2502. $cc = $map[$cc][$d];
2503. if ($cc == $op1)
2504. break;
2505. array_push ($ray, $cc);
2506. }
2507. else
2508. break;
2509. }
2510. $op2 = $d;
2511. }
2512. if (array_key_exists($cc, $map)) {
2513. while (array_key_exists($op2, $map[$cc])) {
2514. $cc = $map[$cc][$op2];
2515. if (($cc == $op1) || in_array($cc, $ray))
2516. break;
2517. array_push ($ray, $cc);
2518. }
2519. }
2520. $allrays = array_merge($allrays, $ray);
2521. }
2522. unset ($output);
2523. $output[0] = array_unique($allrays);
2524. break;
2525. case "lograise": // copy of lograys for testing
2526. */
2527. if (count($output) < 2)
2528. error("The {$arg} operator requires at least two arguments.", $linenum);
2529. $op1 = array_pop($output);
2530. $allrays = array();
2531. foreach ($output as $op2) {
2532. $ray = lograys($op1, $op2);
2533. $allrays = array_merge($ray, $allrays);
2534. }
2535. unset ($output);
2536. $output[0] = array_unique($allrays);
2537. break;
2538. case "logride":
2539. if (count($output) < 2)
2540. error("The {$arg} operator requires at least two arguments.", $linenum);
2541. $op1 = array_pop($output);
2542. $op2 = array_pop($output);
2543. do {
2544. $op3 = array_pop($output);
2545. if (is_array($op3))
2546. $ns = logride($op1, $op2, $op3);
2547. else
2548. $ns = logride($op1, $op2, array($op3));
2549. } while (($ns != $op1) && ($ns != $op2) && (count($output) > 0));
2550. unset ($output);
2551. $output[0] = ($ns == $op2);
2552. break;
2553. case "match":
2554. if (count($output) < 2)
2555. error("The {$arg} operator requires at least two arguments.", $linenum);
2556. $op1 = array_pop($output);
2557. $op2 = array_pop($output);
2558. // if op2 is not an array, make it one matching the remaining arguments
2559. if ((array)$op2 !== $op2) {
2560. array_push ($output, $op2);
2561. $op2 = $output;
2562. unset ($output);
2563. }
2564. if ((array)$op1 === $op1)
2565. $output[] = count(array_intersect($op1, $op2));
2566. else
2567. $output[] = in_array($op1, $op2);
2568. break;
2569. case "mates":
2570. if (count($output) < 2)
2571. error("The {$arg} operator requires at least two arguments.", $linenum);
2572. $newarray = array();
2573. while (count($output) > 1) {
2574. $key = array_pop($output);
2575. $val = array_pop($output);
2576. $newarray[$key] = $val;
2577. $newarray[$val] = $key;
2578. }
2579. unset($output);
2580. $output[0] = $newarray;
2581. break;
2582. case "mergeall":
2583. if (count($output) < 2)
2584. $output = $output[0];
2585. $newarray = $strays = array();
2586. foreach ($output as $val) {
2587. if ($val === (array)$val)
2588. $newarray[] = $val;
2589. elseif ($val)
2590. $strays[] = $val;
2591. }
2592. if (count($strays) > 0)
2593. $newarray[] = $strays;
2594. unset($output);
2595. $output[0] = array_unique(array_merge(...$newarray));
2596. break;
2597. case "poleride":
2598. if (count($output) < 3)
2599. error("The {$arg} operator requires at least 3 arguments.", $linenum);
2600. $op1 = array_pop($output);
2601. $op2 = array_pop($output);
2602. $op3 = array_pop($output);
2603. if (is_array($op3)) {
2604. do {
2605. if (count($op3) == 4)
2606. $bool = poleride($op1, $op2, $op3[0], $op3[1], $op3[2], $op3[3]);
2607. else
2608. error("poleride requires four directions to work", $linenum);
2609. if ($bool == true)
2610. break;
2611. } while ($op3 = array_pop($output));
2612. }
2613. elseif (count($output) >= 3) {
2614. $op4 = array_pop($output);
2615. $op5 = array_pop($output);
2616. $op6 = array_pop($output);
2617. $bool = poleride($op1, $op2, $op3, $op4, $op5, $op6);
2618. }
2619. unset ($output);
2620. $output[0] = $bool;
2621. break;
2622. case "sort":
2623. if (count($output) < 1)
2624. error("The {$arg} operator requires at least one argument.", $linenum);
2625. $op1 = array_pop($output);
2626. if (is_array($op1)) {
2627. sort($op1);
2628. array_push ($output, $op1);
2629. }
2630. else {
2631. array_push($output, $op1);
2632. $op1 = $output;
2633. unset($output);
2634. sort($op1);
2635. $output[0] = $op1;
2636. }
2637. break;
2638. case "sub":
2639. if (count($output) < 1)
2640. error("The {$arg} operator requires at least one argument.", $linenum);
2641. $gosub = array_pop($output);
2642. $subargs = array_reverse($output);
2643. unset($output);
2644. $output[0] = runsubroutine($gosub, $subargs, $linenum);
2645. break;
2646. case "sum":
2647. if (count($output) < 1)
2648. error("The {$arg} operator requires at least one argument.", $linenum);
2649. $op1 = array_pop($output);
2650. if ($op1 instanceof Lambda) {
2651. $op2 = array_pop($output);
2652. $result = 0;
2653. foreach ($op2 as $temp) {
2654. if (is_array($temp))
2655. $args = $temp;
2656. else
2657. $args = array($temp);
2658. $result += polish($op1->stack, $linenum, $args);
2659. }
2660. array_push ($output, $result);
2661. }
2662. elseif ((array)$op1 === $op1)
2663. array_push ($output, array_sum($op1));
2664. else {
2665. array_push ($output, $op1);
2666. $temp = $output;
2667. unset ($output);
2668. $output[0] = array_sum($temp);
2669. }
2670. break;
2671. case "orsum":
2672. if (count($output) < 1)
2673. error("The {$arg} operator requires at least one argument.", $linenum);
2674. $op1 = array_pop($output);
2675. if ((array)$op1 === $op1)
2676. array_push ($output, or_sum($op1));
2677. else {
2678. array_push ($output, $op1);
2679. $temp = $output;
2680. unset ($output);
2681. $output[0] = or_sum($temp);
2682. }
2683. break;
2684. case "windingrays":
2685. if (count($output) < 2)
2686. error("The {$arg} operator requires at least two arguments.", $linenum);
2687. $op1 = array_pop($output);
2688. $f1 = $filenum[$op1]; $r1 = $ranknum[$op1];
2689. $hstep = $vstep = $tmp = array();
2690. if (empty($output))
2691. error ("windingrays requires arguments for the directions of the move.", $linenum);
2692. while (!empty($output)) {
2693. $hstep[] = abs(array_pop($output));
2694. if (empty($output))
2695. error ("windingrays requires an even number of arguments.", $linenum);
2696. $vstep[] = abs(array_pop($output));
2697. }
2698. $n = count($hstep);
2699. $nc = "";
2700. for ($fd = -1; $fd < 2; $fd += 2) {
2701. for ($rd = -1; $rd < 2; $rd +=2) {
2702. $f = $f1;
2703. $r = $r1;
2704. do {
2705. $oc = $nc;
2706. for ($i = 0; $i < $n; $i++) {
2707. $f += $hstep[$i] * $fd;
2708. $r += $vstep[$i] * $rd;
2709. if (!isset($file[$f]) || !isset($rank[$r]))
2710. break;
2711. $nc = $file[$f] . $rank[$r];
2712. if (empty($space[$nc]) || ($space[$nc] == "-"))
2713. break;
2714. else
2715. array_push ($tmp, $nc);
2716. }
2717. } while (($oc != $nc) && !empty($space[$nc]) && ($space[$nc] != "-"));
2718. }
2719. }
2720. $tmp = array_unique($tmp);
2721. unset ($output);
2722. $output[0] = $tmp;
2723. break;
2724. case "windingride":
2725. if (count($output) < 2)
2726. error("The {$arg} operator requires at least two arguments.", $linenum);
2727. $op1 = array_pop($output);
2728. $op2 = array_pop($output);
2729. $f1 = $filenum[$op1]; $r1 = $ranknum[$op1];
2730. $f2 = $filenum[$op2]; $r2 = $ranknum[$op2];
2731. $fmove = $f2 - $f1;
2732. $rmove = $r2 - $r1;
2733. $fd = ($fmove >= 0) ? 1 : -1;
2734. $rd = ($rmove >= 0) ? 1 : -1;
2735. $hstep = $vstep = array();
2736. if (empty($output))
2737. error ("windingride requires arguments for the directions of the move.", $linenum);
2738. while (!empty($output)) {
2739. $hstep[] = abs(array_pop($output));
2740. if (empty($output))
2741. error ("windingride requires an even number of arguments.", $linenum);
2742. $vstep[] = abs(array_pop($output));
2743. }
2744. print_r($hstep);
2745. print_r($vstep);
2746. $n = count($hstep);
2747. $f = $f1;
2748. $r = $r1;
2749. $nc = "";
2750. do {
2751. $oc = $nc;
2752. for ($i = 0; $i < $n; $i++) {
2753. $f += $hstep[$i] * $fd;
2754. $r += $vstep[$i] * $rd;
2755. if (!isset($file[$f]) || !isset($rank[$r]))
2756. break;
2757. $nc = $file[$f] . $rank[$r];
2758. if (($nc == $op2) || empty($space[$nc]) || ($space[$nc] != "@"))
2759. break;
2760. }
2761. if ($nc == $op1)
2762. error ("windingride buggy", $linenum);
2763. // echo "<P STYLE=\"display:block\">{$nc}</P>";
2764. } while (($oc != $nc) && ($nc != $op2) && !empty($space[$nc]) && ($space[$nc] == "@"));
2765. unset ($output);
2766. $output[0] = ($nc == $op2);
2767. break;
2768. default:
2769. array_push ($output, $arg);
2770. break;
2771. }
2772. }
2773. }
2774. $cnt = count($output);
2775. $retval = ($cnt > 1) ? $output : ($cnt ? array_pop($output) : false);
2776. // debug2 ("retval", $retval);
2777. if ($scope == $higherscope)
2778. unsetlocals ($scope, --$scope);
2779. return $retval;
2780. }
2781.
2782. function parse_coord($coord) {
2783. global $filenum, $ranknum;
2784.
2785. return array($filenum[$op1], $ranknum[$op1]);
2786. /*
2787. $lastlen = 0;
2788. foreach ($file as $fkey => $fval) {
2789. $len = strlen($fval);
2790. if ($len != $lastlen) {
2791. $left = substr($coord, 0, $len);
2792. $rest = substr($coord, $len);
2793. }
2794. if ($left == $fval) {
2795. foreach ($rank as $rkey => $rval) {
2796. if ($rest == $rval)
2797. return array ($fkey, $rkey);
2798. }
2799. }
2800. }
2801.
2802. return array(false, false);
2803. */
2804. }
2805.
2806. function sgn ($n) {
2807. return ($n < 0) ? -1 : ($n ? 1 : 0);
2808. }
2809.
2810. function checknsteps ($f1, $r1, $f2, $r2, $steps, $any) {
2811. global $file, $rank, $space;
2812.
2813. if (!isset($file[$f1]) || !isset($rank[$r1]) || !isset($file[$f2]) || !isset($rank[$r2]))
2814.
2815. if ($steps < 1) // Path has stopped. Did we make it?
2816. return (($f1 == $f2) && ($r1 == $r2));
2817.
2818. // If any number of steps up to n is allowed,
2819. // check if we have made it already.
2820. if ($any && ($f1 == $f2) && ($r1 == $r2))
2821. return true;
2822.
2823. // Verify that initial file and rank are real
2824. if (!isset($file[$f1]) || !isset($rank[$r1]))
2825. return false;
2826.
2827. $c = $file[$f1] . $rank[$r1];
2828. if (!isset($space[$c]) || ($space[$c] != "@"))
2829. return false; // Path blocked
2830.
2831. $f = abs($f1 - $f2);
2832. $r = abs($r1 - $r2);
2833.
2834. if (($f > $steps) || ($r > $steps))
2835. return false; // Too far away
2836.
2837. if (($steps & 1) && ($f <= 1) && ($r <= 1))
2838. return true; // Success! Destination is one step away.
2839.
2840. $steps--;
2841.
2842. return checknsteps($f1 - 1, $r1 - 1, $f2, $r2, $steps, $any)
2843. || checknsteps($f1 - 1, $r1, $f2, $r2, $steps, $any)
2844. || checknsteps($f1 - 1, $r1 + 1, $f2, $r2, $steps, $any)
2845. || checknsteps($f1, $r1 - 1, $f2, $r2, $steps, $any)
2846. || checknsteps($f1, $r1 + 1, $f2, $r2, $steps, $any)
2847. || checknsteps($f1 + 1, $r1 - 1, $f2, $r2, $steps, $any)
2848. || checknsteps($f1 + 1, $r1, $f2, $r2, $steps, $any)
2849. || checknsteps($f1 + 1, $r1 + 1, $f2, $r2, $steps, $any);
2850. }
2851.
2852. function allequal ($arr) {
2853. $op = array_pop($arr);
2854. while (isset($arr[0])) {
2855. if (array_pop($arr) != $op)
2856. return false;
2857. }
2858. return true;
2859. }
2860.
2861. function matchstr ($arr) {
2862. $op = array_pop($arr);
2863. while (isset($arr[0])) {
2864. if (array_pop($arr) == $op)
2865. return true;
2866. }
2867. return false;
2868. }
2869.
2870. function nomatchstr ($arr) {
2871. $op = array_pop($arr);
2872. while (isset($arr[0])) {
2873. if (array_pop($arr) == $op)
2874. return false;
2875. }
2876. return true;
2877. }
2878.
2879. function allfalse ($arr) {
2880. while (isset($arr[0])) {
2881. if (array_pop($arr))
2882. return false;
2883. }
2884. return true;
2885. }
2886.
2887. function alltrue ($arr) {
2888. while (isset($arr[0])) {
2889. if (!array_pop($arr))
2890. return false;
2891. }
2892. return true;
2893. }
2894.
2895. function anyfalse ($arr) {
2896. while (isset($arr[0])) {
2897. if (!array_pop($arr))
2898. return true;
2899. }
2900. return false;
2901. }
2902.
2903. function anytrue ($arr) {
2904. while (isset($arr[0])) {
2905. if (array_pop($arr))
2906. return true;
2907. }
2908. return false;
2909. }
2910.
2911. function gcd($m, $n) {
2912. $d = $m;
2913. $r = $n;
2914.
2915. while ($r != 0) {
2916. $m = $d;
2917. $d = $r;
2918. $r = $m % $r;
2919. }
2920. return $d;
2921. }
2922.
2923. // Used for Hostage Chess.
2924. // Indicates most valuable piece that may be dropped.
2925. // Used with code for checking possible moves.
2926.
2927. function best2drop () {
2928. global $starpath, $piecevals, $firstplayer, $space;
2929.
2930. $bestdrop = "";
2931. for ($i = 0; $i < count($starpath[$firstplayer]); $i++) {
2932. if (($piecevals[$starpath[$firstplayer][$i]] ?? 0) > ($piecevals[$bestdrop] ?? 0))
2933. $bestdrop = $starpath[$firstplayer][$i];
2934. }
2935. if ($bestdrop == "")
2936. return false;
2937. return $bestdrop;
2938. }
2939.
2940. // Used for Hostage Chess.
2941. // Indicates most valuable hostage that may be freed.
2942. // Used with code for checking possible moves.
2943.
2944. function best2free () {
2945. global $prison, $piecevals, $firstplayer, $space;
2946.
2947. $capital = 0;
2948. for ($i = 0; $i < count($prison[$firstplayer]); $i++) {
2949. $piece = $space[$prison[$firstplayer][$i]] ?? "";
2950. $capital = max($piecevals[$piece] ?? 0, $capital);
2951. }
2952. if ($capital == 0)
2953. return false;
2954.
2955. $bestbuy = "";
2956. for ($i = 0; $i < count($prison[!$firstplayer]); $i++) {
2957. $piece = $space[$prison[!$firstplayer][$i]];
2958. if (($piecevals[$piece] ?? 0) == $capital)
2959. return $piece;
2960. elseif (($piecevals[$piece] ?? 0) < $capital)
2961. $bestbuy = (($piecevals[$piece] ?? 0) > ($piecevals[$bestbuy] ?? 0)) ? $piece : $bestbuy;
2962. }
2963. if ($bestbuy == "")
2964. return false;
2965. return $bestbuy;
2966. }
2967.
2968. function function_literal ($ra) {
2969. $max = count($ra);
2970. for ($i = 0; $i < $max; $i++) {
2971. if (is_array($ra[$i]))
2972. $ra[$i] = array_literal($ra[$i]);
2973. elseif (strstr($ra[$i], " "))
2974. $ra[$i] = '"' . $ra[$i] . '"';
2975. }
2976. return implode(" ", $ra);
2977. }
2978.
2979. function array_literal ($ra) {
2980. $max = count($ra);
2981. for ($i = 0; $i < $max; $i++) {
2982. if (is_array($ra[$i]))
2983. $ra[$i] = array_literal($ra[$i]);
2984. }
2985. return "(" . implode(" ", $ra) . ")";
2986. }
2987.
2988. function logleap ($from, $to, $ra) {
2989. global $map, $space;
2990.
2991. $ns = $from;
2992. if (!array_key_exists($ns, $space))
2993. error("The first argument to logleap does not match any space on the board.", $GLOBALS["linenum"]);
2994. for ($i = 0; $i < count($ra); $i++) {
2995. if (($i > 0) && (($space[$ns] ?? "") != '@'))
2996. break;
2997. $dir = $ra[$i];
2998. $temp = false;
2999. if (is_array($dir)) {
3000. if (($temp = logleap($from, $to, $dir)) == $to)
3001. return $temp;
3002. }
3003. elseif (isset($map[$ns][$dir]))
3004. $ns = $map[$ns][$dir];
3005. else
3006. $ns = false;
3007. }
3008. if (($temp == false) && ($i < count($ra)))
3009. return false;
3010. return $temp ? $temp : $ns;
3011. }
3012.
3013. function logride ($from, $to, $ra) {
3014. global $map, $space;
3015. if (!is_array($ra))
3016. $ra = array($ra);
3017. $ns = $from;
3018. $counter = 0;
3019. do {
3020. $cnt = count($ra);
3021. for ($i = 0; $i < $cnt; $i++) {
3022. $dir = $ra[$i];
3023. $temp = false;
3024. if (is_array($dir)) {
3025. if (($temp = logride($ns, $to, $dir)) == $to)
3026. return $temp;
3027. }
3028. elseif (!array_key_exists($ns, $map) || !array_key_exists($dir, $map[$ns]))
3029. break 2;
3030. elseif ($ns == $map[$ns][$dir])
3031. break 2;
3032. else
3033. $ns = $map[$ns][$dir];
3034. if (($ns == $from) || ($ns == $to) || ($space[$ns] != '@'))
3035. break 2;
3036. if ($counter++ > 1000) {
3037. error_log("logride {$from} {$to} " . implode(" ", $ra));
3038. error_log ("ns is '{$ns}, space[ns] is {$space[$ns]}'");
3039. if ($counter > 1003) {
3040. echo "<PRE>";
3041. print_r($map);
3042. echo "</PRE>";
3043. exit();
3044. }
3045. }
3046. }
3047. } while (!is_array($ra[$cnt-1]) && ($ns != $to) && ($ns != $from));
3048. return ($ns == $to) ? $to : false;
3049. }
3050.
3051. function lograys ($from, $ra) {
3052. global $map, $space;
3053. if (!is_array($ra))
3054. $ra = array($ra);
3055. $legal = array();
3056. $counter = 0;
3057. $ns = $from;
3058. do {
3059. $cnt = count($ra);
3060. for ($i = 0; $i < $cnt; $i++) {
3061. $dir = $ra[$i];
3062. if (is_array($dir)) {
3063. $legal = array_merge($legal, lograys($ns, $dir));
3064. }
3065. else {
3066. if (!array_key_exists($ns, $map) || !array_key_exists($dir, $map[$ns]))
3067. break 2;
3068. $ns = $map[$ns][$dir];
3069. $legal[] = $ns;
3070. if ($counter++ > 100) {
3071. error_log("lograys {$from} " . implode(" ", $ra));
3072. error_log ("ns is '{$ns}, space[ns] is {$space[$ns]}'");
3073. if ($counter > 1003) {
3074. echo "<PRE>";
3075. print_r($map);
3076. echo "</PRE>";
3077. exit();
3078. }
3079. }
3080. }
3081. }
3082. } while (!is_array($ra[$cnt-1]) && ($ns != $from));
3083. return $legal;
3084. }
3085.
3086. function poleride ($from, $to, $dir1, $dir2, $dir3, $dir4) {
3087. global $map, $space, $rankname, $linenum;
3088. $ns = $from;
3089. $cnt = 0;
3090. $max = count($space)*2;
3091. do {
3092. // Normal board movement until it reaches a pole
3093. while (array_key_exists($dir1, $map[$ns])) {
3094. $cnt++;
3095. $ns = $map[$ns][$dir1];
3096. if ($ns == $to)
3097. return true;
3098. if (($ns == $from) || ($space[$ns] != '@'))
3099. return false;
3100. if ($cnt > $max)
3101. error ("Infinite Loop in poleride", $linenum);
3102. };
3103. // Single step in dir2 to cross the pole
3104. // If it didn't skip the previous loop, it is already by this pole.
3105. // If it went through the previous loop, it was brought to this pole.
3106. if (array_key_exists($dir2, $map[$ns])) {
3107. $cnt++;
3108. $ns = $map[$ns][$dir2];
3109. if ($ns == $to)
3110. return true;
3111. if (($ns == $from) || ($space[$ns] != '@'))
3112. return false;
3113. }
3114. else // So if it is not by this pole at this point, there is an error.
3115. return false;
3116. // Changes direction to move away from the pole it just crossed
3117. while (array_key_exists($dir3, $map[$ns])) {
3118. $cnt++;
3119. $ns = $map[$ns][$dir3];
3120. if ($ns == $to)
3121. return true;
3122. if (($ns == $from) || ($space[$ns] != '@'))
3123. return false;
3124. if ($cnt > $max)
3125. error ("Infinite Loop in poleride", $linenum);
3126. };
3127. // Single step in dir4 to cross the other pole
3128. if (array_key_exists($dir4, $map[$ns])) {
3129. $cnt++;
3130. $ns = $map[$ns][$dir4];
3131. if ($ns == $to)
3132. return true;
3133. if (($ns == $from) || ($space[$ns] != '@'))
3134. return false;
3135. }
3136. else
3137. return false;
3138. // Loop back in case the move initially skipped the first loop, or in case the move
3139. // path is more complicated than a simple non-intersecting, non-overlapping circuit.
3140. } while ($cnt < $max); // This is to prevent an infinite loop.
3141. }
3142.
3143. function fencode($w = 0) {
3144. global $space, $excode;
3145. $fen = ""; $cnt = 0; $total = 0;
3146. if (!is_array($space))
3147. return false;
3148. reset ($space);
3149. reset ($excode);
3150. foreach ($excode as $key => $val) {
3151. if ((($total > 0) && ($w > 0)) && (($total % $w) == 0)) {
3152. $fen .= "/";
3153. }
3154. $total++;
3155. if (key($space) == "")
3156. continue;
3157. $sp = current($space);
3158. if (($val == "-") && ($sp != "-")) {
3159. if ($cnt > 0) {
3160. $fen .= $cnt;
3161. $cnt = 0;
3162. }
3163. $fen .= "-";
3164. continue;
3165. }
3166. if ($sp == "@") {
3167. $cnt++;
3168. if (($w > 0) && (($total % $w) == 0)) {
3169. $fen .= $cnt;
3170. $cnt = 0;
3171. }
3172. }
3173. else {
3174. if ($cnt > 0) {
3175. $fen .= $cnt;
3176. $cnt = 0;
3177. }
3178. if (strlen($sp ?? "") == 1)
3179. $fen .= $sp;
3180. else
3181. $fen .= "{" . $sp . "}";
3182. }
3183. next ($space);
3184. }
3185. if ($cnt > 0)
3186. $fen .= $cnt;
3187. return $fen;
3188. }
3189.
3190. function boardflags() {
3191. global $space, $flag;
3192. // reset ($space);
3193. // reset ($flag);
3194. $onflags = array();
3195.
3196. if (empty($flag))
3197. return false;
3198. foreach ($flag as $key => $val) {
3199. if ($val && isset($space[$key]))
3200. $onflags[] = $key;
3201. }
3202. sort ($onflags);
3203. return "," . implode(",", $onflags);
3204. }
3205.
3206. function and_sum ($a) {
3207. $s = $a[0];
3208. foreach ($a as $v) {
3209. $s &= $v;
3210. }
3211. return $s;
3212. }
3213.
3214. function or_sum ($a) {
3215. $s = (int)$a[0];
3216. foreach ($a as $v) {
3217. $s = (int)$s | (int)$v;
3218. }
3219. return (int)$s;
3220. }
3221.
3222. // Wrapper functions used with array_filter
3223.
3224. function notlower ($s) {
3225. return !ctype_lower($s);
3226. }
3227.
3228. function notupper ($s) {
3229. return !ctype_upper($s);
3230. }
3231.
3232. /*
3233. function systemvar ($name) {
3234. if (preg_match("/^(answered|board|capturedpieces|code|columns|debug|dest|firstplayer|lastcaptured|lastmoved|legalmoves|maxmln|maxmove|mln|movelist|moves|named|noerrorcheck|orientation|origin|originalpieces|piecekeys|piecevals|prevcaptured|prevmoved|prevdest|prevorigin|prison|scope|showoutput|side|space|sub|starpath|submit)$/", $name))
3235. return $GLOBALS[$name];
3236. elseif (preg_match("/^(capturedpieces|originalpieces|piecekeys|piecevals|prison|starpath|sub)\./", $name))
3237. return getvar($GLOBALS, $name);
3238. else switch ($name) {
3239. case "old":
3240. return $lastcaptured;
3241. break;
3242. case "moved":
3243. return $lastmoved;
3244. case "prevsub":
3245. return prevsub();
3246. break;
3247. case "subname":
3248. return $sub[$scope];
3249. break;
3250. }
3251. }
3252. */
3253. function prevsub () {
3254. global $sub, $scope, $ifhead;
3255.
3256. $i = $scope;
3257. while (($ifhead[$i] != "sub") && ($ifhead[$i] != "main"))
3258. $i--;
3259. return $sub[$i];
3260. }
3261.
3262. ?>