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 commands, complete with line numbering and syntax highlighting. The commands can be found as cases in a long switch statement. You can find a particular command by searching for its name within double quotation marks, or you can browse through it to see what commands are available. Although I tried to keep commands in alphabetical order, it sometimes made sense to group related commands together. So, they are roughly, but not strictly, in alphabetical order. Note that this code is displayed here only for educational purposes, and it should not be copied or downloaded.
Copyright © Fergus Duniho, 2016.
1.
<?
2.
3. // Here is the main function for interpreting the main program and every subroutine
4. // of a GAME Code program.
5.
6. function runsubroutine ($subname, $subargs, $oldlinenum=-1) {
7. global $ai, $REALNAME, $allowed, $appendautorules, $background, $banned, $capturedpieces, $cardback, $cards, $cardsdir, $cases, $coded, $codelines, $color, $comments, $constants, $customsets, $debug, $deck, $dest, $discardpile, $drawncards, $exit, $file, $first, $firstplayer, $flag, $flipped, $functions, $gameover, $hand, $hand1, $hand2, $height, $jsvar, $label, $lastcaptured, $lastmoved, $legalmoves, $links, $map, $maxmove, $message, $mline, $mln, $move, $movelist, $movenum, $moves, $named, $noerrorcheck, $oldmovelist, $opponent, $origin, $password, $pastmoves, $pastmovesfield, $piecekeys, $pieces, $piecevals, $playedcards1, $playedcards2, $player, $players, $posdata, $prevcaptured, $prevdest, $prevmoved, $prevorigin, $prevpos, $prison, $rank, $ALIAS, $reminder, $reserved, $returnaliases, $scope, $side, $sidecnt, $space, $starpath, $startbackground, $startposition, $sub, $submit, $switchsides, $turn, $turnorder, $userid, $uservar, $width, $winner;
8.
9. if (!empty($exit)) {
10. return;
11. }
12.
13. static $includes = array();
14. static $returns = array();
15. static $ifhead = array();
16. static $condition = array();
17. static $store = array();
18. static $banlist = array();
19. static $ban = false;
20. static $echos = 0;
21.
22. if (empty($posdata) && !is_array($posdata)) {
23. $posdata = array();
24. $moveindex = 0;
25. }
26.
27. $maxlines = count($codelines);
28.
29. if ($subname == "main") {
30. $subscope = $scope = 0;
31. $sub = array();
32. $sub[$scope] = "main";
33. $ifhead[$scope] = "main";
34. $linenum = -1;
35. }
36. else {
37. $scope++;
38. $subscope = $scope;
39. $sub[$scope] = $subname;
40. $ifhead[$scope] = "sub";
41. if (!array_key_exists($subname, $label))
42. error ("{$subname} is not the name of any known subroutine in your program", $oldlinenum);
43. $linenum = $label[$subname];
44. $move = trim($codelines[$linenum]);
45. $args = parsemove($move);
46. $cnt = count($args);
47. if (!array_key_exists(1, $args) || ($subname != $args[1])) {
48. print_r ($args);
49. error ("Call to {$subname} subroutine got misrouted in <CODE>{$move}</CODE>.", $oldlinenum);
50. }
51. $uservar[$scope][$subname]["subargs"] = $subargs;
52. for ($i = 2; $i < $cnt; $i++) {
53. if (!array_key_exists($i-2, $subargs)) {
54. error ("A call to the subroutine <CODE>{$move}</CODE>, which is defined on line {$linenum}, is missing an argument.", $oldlinenum);
55. }
56. $uservar[$scope]["main"][$args[$i]] = $subargs[$i-2];
57. }
58. }
59.
60. foreach (array_keys($sub) as $key) {
61. if ($key > $scope)
62. unset($sub[$key]);
63. }
64. for ($linenum++; $linenum < $maxlines; $linenum++) {
65. $move = trim($codelines[$linenum]);
66. if (empty($move))
67. continue;
68.
69. $args = parsemove($move);
70. if ($debug || (DEBUG && (($player == "fergus") || ($player == "duniho") || empty($player)))) {
71. // printf ("%d [%d:%s]: %s<BR>", $linenum, $scope, $ifhead[$scope], $move);
72. printf ("%d [%s %d:%s]: %s<PRE>\n%s\n</PRE>", $linenum, $subname, $scope, $ifhead[$scope], $move, var_export($args));
73. }
74.
75. $cnt = count($args);
76. if (empty($cnt))
77. continue;
78.
79. // The eval command is evaluated before any other, because it can change what the command will be.
80. // It evaluates the expression that follows it, converts it into a line of code, and prepares it
81. // to be executed as through it were the original line of code.
82. if ($args[0] == "eval") {
83. $move = polish(array_slice($args, 1), $linenum);
84. if ((array)$move === $move)
85. $move = implode(" ", array_reverse($move));
86. if (empty($move))
87. continue;
88. $args = parsemove($move);
89. $cnt = count($args);
90. }
91.
92. // Evaluate player moves.
93. // No elseif, because previous block may change value of $args
94. $moveflag = false;
95. if ($args[0] == "MOVE:") {
96. $prevcaptured = $lastcaptured;
97. $prevmoved = $lastmoved;
98. $prevorigin = $origin;
99. $prevdest = $dest;
100. $named = $args[1]; // Initialize default value
101. $movecnt = isset($movecnt) ? $movecnt + 1 : 1;
102. $moveflag = true;
103. if (($maxmove > 0) && ($movecnt > $maxmove))
104. banned ("You may not enter more than {$maxmove} move primitives in a move in this game.");
105.
106. // Delete a space
107. if ($args[1] == "-") {
108. if (($subname == "main") && !empty($banned["deletions"]) && empty($allowed["deletions"][$movecnt]))
109. banned ("{$move} and other moves that delete a space with the hyphen operator are banned here.");
110. $dest = $args[2];
111. if ($dest[0] == "!" && !isset($ALIAS[$dest]) && ($submit!="Compose") && $coded)
112. badinput ("The exclamation mark at the beginning of coordinate $dest in <B>{$move}</B> indicates you may not enter it as part of a move.");
113. if (isset($space[$dest])) {
114. $lastcaptured = $space[$dest];
115. $space[$dest] = "-";
116. }
117. else
118. badinput ("You can't remove {$dest} with {$move}, because it is not a valid coordinate.");
119. }
120.
121. // when the command is a coordinate
122. elseif (isset($space[$args[1]])) {
123. if ($args[2] != "-") {
124. echo "<PRE>";
125. print_r ($args);
126. echo "</PRE>";
127. illegal ("The move <b>{$move}</b> ain't well-formed. {$args[1]} is a coordinate. So {$args[2]} should be a hyphen.");
128. }
129. if ($subname == "main") {
130. if (empty($args[3]) && !empty($banned["suicides"]) && empty($allowed["suicides"][$movecnt]))
131. banned ("{$move} and other suicide moves are banned here.");
132. elseif (!empty($banned["moves"]) && empty($allowed["moves"][$movecnt]))
133. banned ("{$move} and other moves from one space to another are banned here.");
134. elseif (!empty($banned["offboard"]) && empty($allowed["offboard"][$movecnt]) && isset($args[3]) && ($space[$args[3]] == "-"))
135. banned ("{$move} and other moves to an off-board space are banned here.");
136. elseif (!empty($banned["captures"]) && empty($allowed["captures"][$movecnt]) && (!isset($args[3]) || ($space[$args[3]] != "@")))
137. banned ("{$move} and other moves to occupied spaces are banned here.");
138. }
139. if (!empty($args[3]))
140. move ($args[1], $args[3]);
141. else {
142. $lastmoved = $lastcaptured = $space[$args[1]];
143. $space[$args[1]] = "@";
144. }
145. }
146.
147. // when the command places an empty space on a coordinate.
148. elseif (($args[1] == "@") && ($args[2] == "-") && isset($space[$args[3]])) {
149. if ($subname == "main") {
150. if (!empty($banned["suicides"]) && empty($allowed["suicides"][$movecnt]))
151. banned ("{$move} and other suicide moves are banned here.");
152. elseif (!empty($banned["offboard"]) && empty($allowed["offboard"][$movecnt]) && ($space[$args[3]] == "-"))
153. banned ("{$move} and other moves adding a new space to the board are banned here.");
154. }
155. $dest = $args[3];
156. if ($dest[0] == "!" && !isset($ALIAS[$dest]) && ($submit!="Compose") && $coded)
157. badinput ("The exclamation mark at the beginning of coordinate $dest in <B>{$move}</B> indicates you may not enter it as part of a move.");
158. $lastmoved = $lastcaptured = $space[$dest];
159. $space[$dest] = $args[1];
160. }
161.
162. // when the command is a piece
163. elseif (isset($pieces[$args[1]])) {
164. $named = $args[1];
165.
166. // full notation for move
167. if (isset($args[3]) && ($args[3] == "-")) {
168. if ($subname == "main") {
169. if (!empty($banned["moves"]) && empty($allowed["moves"][$movecnt]))
170. banned ("{$move} and other moves from one space to another are banned here.");
171. if (!empty($banned["offboard"]) && empty($allowed["offboard"][$movecnt]) && !empty($space[$args[3]]) && ($space[$args[3]] == "-"))
172. banned ("{$move} and other moves to an off-board space are banned here.");
173. if (!empty($banned["suicides"]) && empty($allowed["suicides"][$movecnt]) && empty($args[4]))
174. banned ("{$move} and other suicide moves are banned here.");
175. if (!empty($banned["captures"]) && empty($allowed["captures"][$movecnt]) && (empty($space[$args[4]]) || ($space[$args[4]] != "@")))
176. banned ("{$move} and other moves to occupied spaces are banned here.");
177. }
178. if (($args[1] == ($space[$args[2]] ?? "")) or ($noerrorcheck == "on")) {
179. if (array_key_exists(4, $args))
180. move ($args[2], $args[4]);
181. else {
182. // Suicide move
183. $lastmoved = $lastcaptured = $args[1];
184. $space[$args[2]] = "@";
185. }
186. }
187. else {
188. $a0 = $ALIAS[$args[1]] ?? $args[1];
189. $a1 = $ALIAS[$args[2]] ?? $args[2];
190. $p0 = $ALIAS[$space[$args[2]]] ?? $space[$args[2]];
191. if ($p0 == "@")
192. illegal ("There was no $a0 on $a1. It is an empty space.");
193. else
194. illegal ("There was no $a0 on $a1. The piece on $a1 is a $p0.");
195. }
196. }
197.
198. elseif ($args[2] == "-") {
199.
200. // promote or introduce piece
201. if (isset($space[$args[3]])) {
202. if ($subname == "main") {
203. if (!empty($banned["freedrops"]) && empty($allowed["freedrops"][$movecnt]) && ($space[$args[3]] == "@"))
204. banned ("{$move} and other moves dropping a new piece onto an empty spaces are banned here.");
205. elseif (!empty($banned["promotions"]) && empty($allowed["promotions"][$movecnt]) && ($args[3] == $dest))
206. banned ("{$move} and other promotions are banned here.");
207. elseif (!empty($banned["offboard"]) && empty($allowed["offboard"][$movecnt]) && ($space[$args[3]] == "-"))
208. banned ("{$move} and other moves dropping a piece onto a non-board space are banned here.");
209. elseif (!empty($banned["changes"]) && empty($allowed["changes"][$movecnt]) && ($args[3] != $dest) && ctype_alnum($space[$args[3]]))
210. banned ("{$move} and other moves changing the type of an arbitrary piece are banned here.");
211. }
212. if ($args[3] != $dest) {
213. $dest = $args[3];
214. $origin = false;
215. $lastcaptured = $space[$dest];
216. }
217. $space[$dest] = (isset($alias) && !empty($alias[$args[1]])) ? $alias[$args[1]] : $args[1];
218. }
219.
220. // exchange pieces ala Hostage Chess
221. elseif (isset($pieces[$args[3]]) && isset($prison) && isset($starpath)) {
222. if (($subname == "main") && !empty($banned["hostages"]) && empty($allowed["hostages"][$movecnt]))
223. banned ("{$move} and other moves for the exchange of hostages are banned here.");
224. if (isset($piecevals) && ($piecevals[$args[1]] < $piecevals[$args[3]]))
225. die ("<P>You may not release a {$args[1]} to rescue your {$args[3]}, because the {$args[1]} is not as valuable.");
226. if (($o1 = findpiece($args[3], $prison[!$firstplayer])) === false) {
227. die ("<P>Cannot find {$args[3]} in your opponent's prison.</P>");
228. }
229. if (($o2 = findpiece($args[1], $prison[$firstplayer])) === false)
230. die ("<P>Cannot find {$args[1]} in your prison.</P>");
231. if (($d1 = findpiece("@", $starpath[$firstplayer])) === false)
232. die ("<P>No vacancy. Your starpath is full.</P>");
233. if (($d2 = findpiece("@", $starpath[!$firstplayer])) === false)
234. die ("<P>No vacancy. Opponent's starpath is full.</P>");
235. $lastmoved = $space[$d1] = $space[$o1];
236. $space[$d2] = $space[$o2];
237. $lastcaptured = $space[$o1] = $space[$o2] = "@";
238. $dest = $d1; $origin = $o2;
239. }
240.
241. else {
242. print_r ($args);
243. print_r ($prison);
244. print_r ($starpath);
245. illegal ("Game Courier does not know what to do with this move: {$move}");
246. }
247. }
248.
249. // drop piece
250. elseif ($args[2] == "*") {
251. if (($subname == "main") && !empty($banned["drops"]) && empty($allowed["drops"][$movecnt]))
252. banned ("{$move} and other moves dropping a captured piece are banned here.");
253. $dest = $args[3];
254. if (empty($space[$dest]))
255. illegal ("The coordinate \"{$dest}\" is unknown in move: {$move}.");
256. $p = $args[1];
257. $origin = findpiece($p, $starpath[$firstplayer]);
258. if ($origin === false) {
259. echo "<PRE>";
260. print_r ($firstplayer);
261. print_r ($starpath);
262. print_r ($starpath[$firstplayer]);
263. echo "</PRE>";
264. illegal ("You have no $p to drop with the * operator for move: {$move}.");
265. }
266. $dest = trim($dest);
267. $lastcaptured = $space[$dest];
268. $lastmoved = $space[$dest] = $p;
269. $space[$origin] = "@";
270. }
271. else {
272. illegal ("The move <b>{$move}</b> is NOT well-formed.");
273. }
274. }
275. /*
276. elseif (($args[1] == "resign") || ($args[1] == "lost")) {
277. if (($submit == "Preview") || ($submit == "Send")) {
278. $GLOBALS["winner"] = $opponent;
279. if ($args[1] == "resign")
280. $message = sprintf("%s has resigned.", userid_name($player));
281. else
282. $message = sprintf("%s has accepted a loss.", userid_name($player));
283. }
284. else {
285. echo "<P>first is {$first}, side is {$side}, movenum is {$movenum}</P>";
286. $GLOBALS["status"] = sprintf("%s has won.", $side);
287. $winner = (($movenum & 1) ^ ($side != $first)) ? $opponent : $player;
288. $loser = ($winner == $player) ? $opponent : $player;
289. if ($args[1] == "resign")
290. $message = userid_name($loser) . " has resigned.";
291. else
292. $message = userid_name($loser) . " has accepted a loss.";
293. }
294. $GLOBALS["status"] = sprintf("%s has won.", userid_name($winner));
295. $gameover = true;
296. return;
297. }
298. elseif ($args[1] == "drawn") {
299. if (empty($submit) || ($submit == "Preview") || ($submit == "Send") || ($submit == "View") || ($submit == "Move")) {
300. $GLOBALS["status"] = "Drawn game.";
301. $GLOBALS["winner"] = "";
302. $GLOBALS["message"] = "The game is declared drawn.";
303. $gameover = true;
304. }
305. return;
306. }
307. */
308. elseif (($subname == "main") && !empty($banned[$args[1]])) {
309. banned ("The <b>{$args[1]}</b> command has been explicitly banned from user input on the part of the turn indexed {$movecnt}.");
310. }
311. elseif (($subname == "main") && !empty($banned["commands"]) && empty($allowed[$args[1]][$movecnt]) && ($args[1] != "resign") && ($args[1] != "lost") && ($args[1] != "drawn")) {
312. banned ("There is a global ban on commands in user input, and no exception has been made for the <b>{$args[1]}</b> command on the part of the turn indexed {$movecnt}.");
313. }
314. else {
315. $moveflag = false;
316. array_shift ($args);
317. }
318. }
319.
320. /*
321. if ((($sub == "main") && (!$ban xor in_array($args[0], $banlist))) ? $args[0] : "-") {
322. printf ("<PRE>");
323. print_r ($ban);
324. printf ("</PRE>");
325. if ($ban)
326. $errmessage = sprintf("All commands except these have been banned from the main level of the program: %s", implode(", ", $banlist));
327. else
328. $errmessage = sprintf("The <b>%s</b> command has been banned from the main level of the program.", $args[0]);
329. error ($errmessage, $linenum);
330. }
331. */
332.
333. // Commands
334. if ($moveflag) {
335. // Do nothing since the move was already handled.
336. }
337. elseif (isset($label[$args[0]])) { // Silent Gosub
338. // You may replace a command with a subroutine by the same name.
339. // This is useful for letting me add new commands without breaking
340. // code that silently calls subroutines by the same name. You may
341. // name a subroutine after a command if you want to change its behavior,
342. // but it is generally recommended that you don't.
343. setuservar("RESULT", runsubroutine ($args[0], array_slice($args, 1), $linenum));
344. if (!empty($exit))
345. return;
346. }
347. else
348. switch ($args[0]) {
349. case "MOVE:":
350. break;
351. case "add":
352. if (count($args) < 3) {
353. error("The <b>add</b> command requires at least two arguments.", $linenum);
354. }
355. elseif ($args[2] == "all") {
356. // Add same piece to all listed spaces
357. for ($i = 3; $i < $cnt; $i++)
358. $space[$args[$i]] = $args[1];
359. }
360. elseif ($args[2] == "any") {
361. // Add one piece to any listed space
362. $space[$args[mt_rand(3, $cnt-1)]] = $args[1];
363. }
364. else {
365. // Add each piece to singular listed space
366. for ($i = 1; $i < ($cnt - 1); $i += 2) {
367. $space[$args[$i+1]] = $args[$i];
368. }
369. }
370. break;
371. case "alias": // Set alias for piece or coordinate
372. for ($i = 1; $i < $cnt; $i += 2) {
373. if (($i + 1) < $cnt) {
374. // Sets realname of alias
375. $REALNAME[$args[$i]] = $args[$i+1];
376. // Sets alias used for realname
377. $ALIAS[$args[$i+1]] = $args[$i];
378. }
379. else
380. error("The last value passed to alias is unpaired", $linenum);
381. }
382. break;
383. case "allow": // Make exceptions to ban. See "ban"
384. for ($i = 1; $i < $cnt; $i += 2) {
385. if (!ctype_alpha($args[$i]) || !ctype_digit($args[$i+1] ?? ""))
386. error ("Invalid argument for <b>allow</b>. This command must be followed by keyword number pairs.", $linenum);
387. $allowed[$args[$i]][$args[$i+1]] = true;
388. }
389. break;
390. case "continuemove": // Allow multi-part move to be made with mouse/touch
391. case "redomove": // Allow player to redo illegal move
392. if ($submit == "Preview")
393. $submit = "";
394. $pastmovesfield = ($args[0] == "redomove") ? "" : $moves;
395. $movelist = $oldmovelist;
396. $movenum = max($movenum - 1, 0);
397. if (!$switchsides) {
398. $side = $turnorder[$movenum % $sidecnt];
399. }
400. else
401. $side = $turnorder[($sidecnt - 1) - ($movenum % $sidecnt)];
402. break;
403. case "appendmove": // Append value of expression to current move
404. $moves .= "; " . polish(array_slice($args, 1),$linenum);
405. $lastmove = trim($moves);
406. if (empty($oldmovelist))
407. $movelist = "{$turn}. {$lastmove}";
408. else
409. $movelist = $oldmovelist . "\n{$turn}. {$lastmove}";
410. $mline[count($mline)-1]->move = $lastmove;
411. if (!empty($comments)) {
412. $temp = trim($comments);
413. $temp = str_replace("\n", "\n// ", $temp);
414. $movelist .= "\n// $temp";
415. }
416. break;
417. case "rewritemove": // Rewrite current move with another move.
418. // Useful for standardizing notation.
419. $moves = polish(array_slice($args, 1),$linenum);
420. $lastmove = trim($moves);
421. if (empty($oldmovelist))
422. $movelist = "{$turn}. {$lastmove}";
423. else
424. $movelist = $oldmovelist . "\n{$turn}. {$lastmove}";
425. $mline[count($mline)-1]->move = $lastmove;
426. if (!empty($comments)) {
427. $temp = trim($comments);
428. $temp = str_replace("\n", "\n// ", $temp);
429. $movelist .= "\n// $temp";
430. }
431. break;
432. case "input": // Stores user input in a constant
433. if (isset($constants[$args[1]]))
434. break;
435. print_r($constants);
436. echo "<FORM NAME=\"move\" ACTION=\"play.php\" METHOD=POST>\n";
437. copyformdata ();
438. echo "<P><B>{$args[2]}</B></P>";
439. if ($cnt < 4) // User enters string
440. echo "<INPUT TYPE=\"text\" NAME=\"constants_{$args[1]}\" VALUE=\"\">\n";
441. elseif ($cnt == 4)
442. echo "<INPUT TYPE=\"checkbox\" NAME=\"constants_{$args[1]}\" VALUE=\"{$args[3]}\"> {$args[3]}\n";
443. else { // User is given multiple choices
444. for ($i = 3; $i < $cnt; $i++) {
445. echo "<DIV STYLE=\"float: left; border: solid black thin; margin: 1ex; padding: 1ex;\">";
446. // For an array, first element is value, rest is displayed as text
447. if ((array)($args[$i]) === $args[$i]) {
448. $car = $args[$i][0];
449. $cdr = $args[$i][1];
450. for ($j = 2; $j < count($args[$i]); $j++)
451. $cdr .= " {$args[$i][$j]}";
452. printf ("<INPUT TYPE=\"radio\" NAME=\"constants_%s\" VALUE=\"%s\"> %s\n", $args[1], $car, $cdr);
453. }
454. // For a piece label, the piece is displayed
455. elseif (isset($pieces[$args[$i]])) {
456. printf ("<INPUT TYPE=\"radio\" NAME=\"constants_%s\" VALUE=\"%s\">\n", $args[1], $args[$i]);
457. drawpiece($args[$i]);
458. }
459. // For a coordinate, its appropriately colored space
460. // is displayed with whatever piece is on it.
461. elseif (isset($space[$args[$i]])) {
462. printf ("<TABLE><TR><TD><INPUT TYPE=\"radio\" NAME=\"constants_%s\" VALUE=\"%s\"></TD><TD HEIGHT=%d WIDTH=%d ALIGN=CENTER VALIGN=MIDDLE BGCOLOR=%s\"><IMG SRC=\"%s%s\"></TD><TD>%s</TD></TR></TABLE>\n", $args[1], $args[$i], $height, $width, $color[$background[$args[$i]]], $GLOBALS["dir"], $pieces[$space[$args[$i]]], $args[$i]);
463. }
464. // Any other argument is used as a value and displayed as text
465. else
466. printf ("<INPUT TYPE=\"radio\" NAME=\"constants_%s\" VALUE=\"%s\"> %s\n", $args[1], $args[$i], $args[$i]);
467. echo "</DIV>";
468. }
469. }
470. if (empty($submit))
471. $submit = "Submit";
472. echo "<INPUT TYPE=\"submit\" NAME=\"submit\" VALUE=\"{$submit}\">\n";
473. if (($submit == "Preview") || ($submit == "Submit"))
474. hide ("userid", true);
475. $movelist = $oldmovelist;
476. $moves = "";
477. $movenum--;
478. hide ();
479. hide ("game settings", true);
480. echo "</FORM>";
481. exit ();
482. break;
483. case "ask":
484. // Asks a question with multiple answers.
485. // Appends move associated with chosen answer to current move.
486. if (!empty($moves)) {
487. echo "<FORM NAME=\"move\" ACTION=\"play.php\" METHOD=POST>\n";
488. copyformdata ();
489. echo "<P><B>{$args[1]}</B></P>";
490. for ($i = 2; $i < $cnt; $i += 2)
491. printf ("\n<INPUT TYPE=\"radio\" NAME=\"moves\" VALUE=\"{$moves}; %s\"%s> <B>%s:</B> <KBD>%s; %s</KBD><BR>\n", $args[$i+1], $i==2 ? " CHECKED" : "", $args[$i], $moves, $args[$i+1]);
492. // Is this next line needed? It may relate to the answered operator.
493. echo "<INPUT TYPE=\"hidden\" NAME=\"answered\" VALUE=true>";
494. echo "<INPUT TYPE=\"submit\" NAME=\"submit\" VALUE=\"{$submit}\">\n";
495. if ($submit == "Preview")
496. hide ("userid", true);
497. $movelist = $oldmovelist;
498. $moves = "";
499. $movenum--;
500. hide ();
501. hide ("game settings", true);
502. echo "</FORM>";
503. exit ();
504. }
505. break;
506. case "askpromote":
507. // Asks which piece to promote to, then updates current move.
508. // When promotion is optional, include the current piece in the options.
509. if (!empty($moves)) {
510. printf ("<FORM NAME=\"move\" ACTION=\"play.php\" METHOD=POST>\n");
511. copyformdata ();
512. echo "<P><B>Which piece will you promote to?</B></P>";
513. if (is_array($args[1])) {
514. foreach ($args[1] as $val) {
515. if ($val != $space[$dest]) {
516. printf ("<INPUT NAME=\"moves\" TYPE=\"radio\" VALUE=\"{$moves}; %s-dest\"> ", isset($ALIAS[$val]) ? $ALIAS[$val] : $val);
517. drawpiece ($val);
518. }
519. else {
520. printf ("<P><B>Decline Promotion:</B></P><INPUT NAME=\"moves\" TYPE=\"radio\" VALUE=\"{$moves}; skip\">");
521. drawpiece ($val);
522. }
523. }
524. }
525. else {
526. for ($i = 1; $i < $cnt; $i++) {
527. printf ("<INPUT TYPE=\"radio\" NAME=\"moves\" VALUE=\"{$moves}; %s-dest\"%s> ", !empty($ALIAS[$args[$i]]) ? $ALIAS[$args[$i]] : $args[$i], $i==1 ? " CHECKED" : "");
528. drawpiece ($args[$i]);
529. }
530. }
531. echo "<INPUT TYPE=\"hidden\" NAME=\"answered\" VALUE=true>";
532. echo "<INPUT TYPE=\"submit\" NAME=\"submit\" VALUE=\"{$submit}\">";
533. $movelist = $oldmovelist;
534. $moves = "";
535. $movenum--;
536. hide ();
537. hide ("game settings", true);
538. echo "</FORM>";
539. exit ();
540. }
541. break;
542. case "unallow": // Revokes exceptions to banning made by allow
543. for ($i = 1; $i < $cnt; $i += 2) {
544. if (!ctype_alpha($args[$i]) || !ctype_digit($args[$i+1]))
545. error ("Invalid argument for <b>unallow</b>. This command must be followed by keyword number pairs.", $linenum);
546. $allowed[$args[$i]][$args[$i+1]] = false;
547. }
548. break;
549. case "ban": // Bans types of moves or commands from being entered as moves
550. if ($cnt < 2)
551. error ("The <b>ban</b> command is missing required arguments.", $linenum);
552. for ($i = 1; $i < $cnt; $i++) {
553. if ($args[$i] == "none")
554. unset ($banned);
555. elseif ($args[$i] == "allmoves")
556. $banned["captures"] = $banned["changes"] = $banned["deletions"] = $banned["drops"] = $banned["freedrops"] = $banned["hostages"] = $banned["moves"] = $banned["offboard"] = $banned["promotions"] = $banned["suicides"] = true;
557. elseif ($args[$i] == "all")
558. $banned["commands"] = true;
559. else
560. $banned[$args[$i]] = true;
561. }
562. break;
563. case "calcset": // Performs the same logical or mathematical operation
564. // on each listed variable.
565. for ($i = 3; $i < $cnt; $i++) {
566. $temp = &refvar($args[$i]) ?? 0;
567. if (is_numeric($temp))
568. $temp = (int)$temp;
569. switch ($args[1]) {
570. case "|": case "or":
571. $temp |= $args[2];
572. break;
573. case "&": case "and":
574. $temp &= $args[2];
575. break;
576. case "^": case "xor":
577. $temp ^= $args[2];
578. break;
579. case "<<":
580. $temp <<= $args[2];
581. break;
582. case ">>":
583. $temp >>= $args[2];
584. break;
585. case "=":
586. $temp = $args[2];
587. break;
588. case "*":
589. $temp *= $args[2];
590. break;
591. case "/":
592. $temp /= $args[2];
593. break;
594. case "-":
595. $temp -= $args[2];
596. break;
597. case "+":
598. $temp += $args[2];
599. break;
600. case "&&":
601. $temp = ($temp && $args[2]);
602. break;
603. case "||":
604. $temp = ($temp || $args[2]);
605. break;
606. case "==":
607. $temp = ($temp == $args[2]);
608. break;
609. case "mod":
610. case "%":
611. $temp %= $args[2];
612. break;
613. default:
614. error ("The first argument of calcset is illegal: {$args[$i]}", $linenum);
615. break;
616. }
617. unset($temp);
618. }
619. break;
620. case "capture": // Captures pieces on all listed positions
621. // Sets $lastcaptured to last position in list.
622. if (isset($args[$cnt-1])) {
623. if (array_key_exists($args[$cnt-1], $space))
624. $lastcaptured = $space[$args[$cnt-1]];
625. for ($i = 1; $i < $cnt; $i++)
626. $space[$args[$i]] = '@';
627. }
628. else
629. error ("Expected argument for capture could not be found.", $linenum);
630. break;
631. case "change":
632. // Changes piece on coordinate to piece following its piece type in ranked list.
633. case "convert":
634. // Using list of pairs, finds the first pair whose first member matches the type
635. // of piece at coordinate and converts it to second member of same pair.
636. unset ($conversions);
637. $inc = ($args[0] == "change") ? 1 : 2;
638. for ($cnt--, $i = 2; $i < $cnt; $i += $inc)
639. $conversions[$args[$i]] = $args[$i+1];
640. $pos = $args[1];
641. if ($pos == "all") {
642. foreach ($space as $pos => $val) {
643. if (isset($conversions[$val]))
644. $space[$pos] = $conversions[$val];
645. }
646. }
647. elseif (array_key_exists($pos, $space) && isset($conversions[$space[$pos]]))
648. $space[$pos] = $conversions[$space[$pos]];
649. break;
650. case "clear": // Moves pieces to off-board area
651. // Useful for composing problems. NEEDS WORK.
652. if (empty($starpath[0])) {
653. $starpath[0] = array();
654. for ($x = 0; $x < $GLOBALS["cols"]; $x++) {
655. for ($y = 0; $y < $GLOBALS["rows"]; $y++) {
656. $c = $file[$x] . $rank[$y];
657. if (!ctype_alnum($c))
658. $starpath[0][] = $c;
659. }
660. }
661. }
662. if (empty($starpath[1])) {
663. $starpath[1] = array();
664. for ($x = $GLOBALS["cols"] - 1; $x >= 0; $x--) {
665. for ($y = $GLOBALS["rows"] - 1; $y >= 0; $y--) {
666. $c = $file[$x] . $rank[$y];
667. if (!ctype_alnum($c))
668. array_push($starpath[1], $c);
669. }
670. }
671. }
672. if (($cnt < 2) || (array_key_exists(1, $args) && ($args[1] == "board"))) {
673. foreach ($space as $sp => $p) {
674. if (($p != "@") && ($p != "-") && ($sp[0] != "!")) {
675. $space[$sp] = "@";
676. $nsp = ctype_lower($p) ? findpiece("@", $starpath[1]) : findpiece("@", $starpath[0]);
677. $space[$nsp] = $p;
678. }
679. }
680. }
681. else {
682. for ($i = 1; $i < $cnt; $i++) {
683. $p = $space[$args[$i]];
684. $nsp = ctype_lower($p) ? findpiece("@", $starpath[1]) : findpiece("@", $starpath[0]);
685. if ($nsp != false) {
686. $space[$args[$i]] = "@";
687. $space[$nsp] = $p;
688. }
689. }
690. }
691. break;
692. case "conserve":
693. error ("The conserve command has been removed.", $linenum);
694. break;
695. case "copy": // Copies content of one space to another
696. $space[$args[2]] = $space[$args[1]];
697. break;
698. case "copyflag": // Copies value of flag for first argument to flags named
699. // after remaining arguments
700. for ($i = 2; $i < $cnt; $i++)
701. $flag[$args[$i]] = $flag[$args[1]] ?? false;
702. break;
703. case "deal": // Shuffles a deck of cards and deals out specified number
704. // of cards to each player.
705. $deck = shufflearray(array_keys($cards));
706. $discardpile = array();
707. $hand1 = array();
708. $hand2 = array();
709. for ($i = 0; $i < $args[1]; $i++) {
710. $c = array_pop($deck);
711. $hand1[] = $c;
712. $drawncards[] = $c;
713. $c = array_pop($deck);
714. $hand2[] = $c;
715. $drawncards[] = $c;
716. }
717. break;
718. case "dec": // Decrements integer variable by one
719. $temp = &refvar($args[1]);
720. $temp--;
721. unset($temp);
722. break;
723. case "def": // Defines function
724. $functions[$args[1]] = array_slice($args, 2);
725. $tempflags = array();
726. $maxargs = 0;
727. $fn = $functions[$args[1]];
728. $mn = count($fn);
729. for ($i = 0; $i < $mn; $i++) {
730. // print_r($fn);
731. if (array_key_exists($i, $fn) && !empty($fn[$i]) && ($fn[$i][0] == "#")) {
732. $n = substr($fn[$i], 1);
733. if (ctype_digit($n)) {
734. $tempflags[$n] = true;
735. $maxargs = max($maxargs, $n);
736. }
737. }
738. }
739. if ($maxargs > count($tempflags)) {
740. $ct = count($tempflags);
741. print_r ($tempflags);
742. error ("Function {$args[0]} requires more arguments than it has placeholders for. maxargs: {$maxargs} tempflags: {$tempflags} count(tempflags): $ct", $linenum);
743. }
744. break;
745. case "copyfn": // Clones function to new function with new name
746. if (isset($functions[$args[1]]))
747. $functions[$args[2]] = $functions[$args[1]];
748. else
749. error ("The function {$args[1]} does not exist.", $linenum);
750. break;
751. case "empty": // Empties all spaces or listed spaces
752. if ($args[1] == "all") {
753. foreach ($space as $key => $val)
754. if ($val != '-')
755. $space[$key] = '@';
756. }
757. else {
758. for ($i = 1; $i < $cnt; $i++)
759. $space[$args[$i]] = '@';
760. }
761. break;
762. case "delete": // Removes listed spaces from board,
763. case "remove": // leaving behind non-space.
764. for ($i = 1; $i < $cnt; $i++)
765. $space[$args[$i]] = '-';
766. break;
767. case "end": // Main level command to mark natural end of program
768. // Inserted in right place automatically.
769. if ($subname != "main")
770. error ("Misplaced <b>end</b>.", $linenum);
771. case "exit":
772. $exit = true;
773. return;
774. break;
775. case "stop": // Forcibly exits subroutine.
776. // At main level, it forcibly exits the program.
777. return;
778. break;
779. case "die": // Forcibly exits program after printing message
780. echo ("</PRE><P STYLE=\"font-size: 2em; line-height: 1.2em;\">" . stripallslashes(join(" ", array_slice($args, 1))) . "</P><PRE>\n");
781. if (false && $_POST["olddefault"]) {
782. echo "<FORM ACTION=\"play.php\" METHOD=POST>";
783. $formvalues = json_decode(urldecode($_POST["olddefault"]));
784. foreach ($formvalues as $key => $val) {
785. if (is_array($val))
786. printf ("<INPUT TYPE='hidden' NAME='%s' VALUE='%s'>", $key, rawurlencode(serialize($val)));
787. else
788. printf ("<INPUT TYPE=\"hidden\" NAME=\"%s\" VALUE=\"%s\">", $key, rawurlencode($val));
789. }
790. if ($submit == "Move")
791. echo "<INPUT TYPE=\"submit\" NAME=\"submit\" VALUE=\"Move\">\n";
792. echo "</FORM>\n";
793. }
794.
795. if (!empty($submit))
796. echo ("<P><BIG>Use your browser's BACK button to go back to the previous page, then reload if necessary.</BIG></P>");
797. else
798. echo "<P><B>Since this is not a preview, something may have gone wrong with the code. For diagnostic purposes, this message was produced by calling the <B>die</B> command on line {$linenum}, and the last move played was</P> <P><BIG><B>{$mline[$mln]->turn}. {$mline[$mln]->move}</B></BIG></P>";
799. echo "<P>For general reference, here is the complete list of moves:</P><PRE>{$movelist}</PRE>";
800. $url = "https://www.chessvariants.com/play/pbm/play.php?game=" . urlencode($GLOBALS["game"]) . "&settings=" . urlencode($GLOBALS["settings"]) . "&submit=Edit";
801. echo "<p>If this is your settings file, you may edit it at <a href=\"{$url}\">{$url}</a></p>";
802. echo "<P>Here is a code listing:</P>";
803. listprog();
804. if (fpdip()) {
805. echo "<PRE>";
806. print_r($functions);
807. echo "</PRE>";
808. }
809.
810. exit();
811. break;
812. case "discard": // Places listed cards from player's hand into discard pile
813. if ($firstplayer)
814. $hand = &$hand1;
815. else
816. $hand = &$hand2;
817. for ($i = 1; $i < $cnt; $i++) {
818. if (empty($args[$i]))
819. continue;
820. if (in_array($args[$i], $hand)) {
821. $k = array_search($args[$i], $hand);
822. array_push($discardpile, $hand[$k]);
823. unset ($hand[$k]);
824. }
825. else {
826. echo "<PRE>";
827. print_r ($args[$i]);
828. print_r ($hand);
829. echo "</PRE>";
830. die ("<P>You can't discard a {$cards[$args[$i]]->alt}, because you don't have one in your hand. Go back and enter a legal move.</P>");
831. }
832. }
833. $hand = array_values($hand);
834. break;
835. case "displace": // discards continuing effect cards
836. for ($i = 1; $i < $cnt; $i++) {
837. if (in_array($args[$i], $displayedcards)) {
838. $k = array_search($args[$i], $displayedcards);
839. array_push($discardpile, $displayedcards[$k]);
840. unset ($displayedcards[$k]);
841. }
842. else
843. die ("<P>You can't displace a {$cards[$args[$i]]->alt}, because none is displayed.</P>");
844. }
845. $displayedcards = array_values($displayedcards);
846. break;
847. case "draw": // Draw specified number of cards
848. if ($firstplayer)
849. $hand = &$hand1;
850. else
851. $hand = &$hand2;
852. if (empty($args[1])) {
853. die ("<P>Use the <CODE>drawn</CODE> command if you wish to end a game in a draw. The draw command is for drawing cards from a deck.</P>");
854. }
855. elseif (!empty($args[2]) && ($args[2] == "discard")) { // Draw cards from discard pile
856. for ($i = 0; $i < $args[1]; $i++)
857. array_push($hand, array_pop($discardpile));
858. }
859. else {
860. for ($i = 0; $i < $args[1]; $i++) {
861. $c = array_pop($deck);
862. array_push($hand, $c);
863. array_push($drawncards, $c);
864. if (count($deck) == 0) {
865. $deck = shufflearray($discardpile);
866. $discardpile = array();
867. }
868. }
869. }
870. break;
871. case "drop": // Drops piece onto empty space(s) in list
872. case "replace": // Drops piece onto space(s) with or without specified piece
873. if ($args[0] == "drop") {
874. $trueflag = true;
875. $firstpos = 2;
876. $target = '@';
877. $p = $args[1];
878. }
879. elseif ($args[1] == "not") { // Drops on space(s) without specified piece
880. $trueflag = false;
881. $firstpos = 4;
882. $target = $args[2];
883. $p = $args[3];
884. }
885. else { // Drops on space(s) with specified piece
886. $trueflag = true;
887. $firstpos = 3;
888. $target = $args[1];
889. $p = $args[2];
890. }
891.
892. if (preg_match("/^(all|any|first|last|right|left)$/", $args[$firstpos])) {
893. $keyword = $args[$firstpos];
894. $firstpos++;
895. }
896. else
897. $keyword = "";
898.
899. if ((array)$args[$firstpos] === $args[$firstpos]) {
900. $temp = $args[$firstpos];
901. unset ($args);
902. $args = &$temp;
903. $firstpos = 0;
904. $cnt = count($args);
905. }
906. $j = 0;
907. $pos = array();
908. switch ($args[2]) {
909. case "first": // Selects first space matching criterion
910. for ($i = $firstpos; $i < $cnt; $i++) {
911. if (array_key_exists($args[$i], $space)) {
912. if (($space[$args[$i]] == $target) == $trueflag) {
913. $pos[$j++] = $args[$i];
914. break;
915. }
916. }
917. }
918. break;
919. case "last": // Selects last space matching criterion
920. for ($i = $cnt-1; $i >= $firstpos; $i--) {
921. if (array_key_exists($args[$i], $space)) {
922. if (($space[$args[$i]] == $target) == $trueflag) {
923. $pos[$j++] = $args[$i];
924. break;
925. }
926. }
927. }
928. break;
929. case "left": // Selects spaces to left not matching criterion
930. for ($i = $firstpos; $i < $cnt; $i++) {
931. if (array_key_exists($args[$i], $space)) {
932. if (($space[$args[$i]] != $target) == $trueflag)
933. break;
934. $pos[$j++] = $args[$i];
935. }
936. }
937. break;
938. case "right": // Selects spaces to right not matching criterion
939. for ($i = $cnt-1; $i >= $firstpos; $i--) {
940. if (array_key_exists($args[$i], $space)) {
941. if (($space[$args[$i]] != $target) == $trueflag)
942. break;
943. $pos[$j++] = $args[$i];
944. }
945. }
946. break;
947. default: // Selects every space matching criterion
948. for ($i = $firstpos; $i < $cnt; $i++) {
949. if (array_key_exists($args[$i], $space)) {
950. if (($space[$args[$i]] == $target) == $trueflag)
951. $pos[$j++] = $args[$i];
952. }
953. }
954. break;
955. }
956. if ((!isset($starpath[$firstplayer])) && ($p == $lastcaptured))
957. $starpath[$firstplayer] = array_slice($args, 2);
958. if ($keyword == "all") { // Drops piece on all selected spaces
959. for ($i = 0; $i < $j; $i++)
960. $space[$pos[$i]] = $p;
961. if (($j > 0) && array_key_exists($j-1, $pos))
962. $dest = $pos[$j-1];
963. }
964. elseif (count($pos) > 0) { // Drops piece on random space from selected spaces
965. if ($j < 2)
966. $poskey = 0;
967. else
968. $poskey = mt_rand(0, $j-1);
969. $dest = $pos[$poskey];
970. $space[$dest] = $p;
971. }
972. break;
973. case "dump": // Dumps array of all variables to output.
974. // Used for debugging.
975. echo "<PRE CLASS=\"dump\">";
976. if (empty($args[1]))
977. echo var_dump ($uservar);
978. elseif ($args[1] == "moves")
979. print_r ($mline);
980. elseif (fpdip() && ($args[1] == "globals"))
981. echo var_dump($GLOBALS);
982. else
983. echo var_dump($args[1]);
984. echo "</PRE>";
985. break;
986. case "echo": // Outputs text to screen. Used for debugging.
987. // if ($submit != "Play") { // Inoperative in play mode to prevent messages from moving board.
988. if (false and (++$echos > 64))
989. error ("The <b>echo</b> command may not be used more than 64 times in a program.", $linenum);
990. echo "<P>" . stripallslashes(join(" ", array_slice($args, 1))) . "</P>\n";
991. // }
992. break;
993. case "print": // Outputs value of expression to screen. Used for debugging.
994. if (false and (++$echos > 64))
995. error ("The <b>print</b> command may not be used more than 64 times in a program.", $linenum);
996. $t = polish(array_slice($args, 1),$linenum);
997. if (is_array($t)) {
998. echo "<PRE>";
999. print_r($t);
1000. echo "</PRE>";
1001. }
1002. else
1003. echo "<P>" . $t . "</P>";
1004. break;
1005. case "printr": // Outputs value of variable to screen. Used for debugging.
1006. if (is_string($args[1]) && (strpos($args[1], " ") === false)) {
1007. $printr = &refvar($args[1]);
1008. if (!isset($printr))
1009. $printr = $args[1];
1010. }
1011. else
1012. $printr = $args[1];
1013. echo "<PRE>";
1014. print_r ($printr);
1015. echo "</PRE>";
1016. unset ($printr);
1017. break;
1018. case "exchange": // NEEDS DOCUMENTATION
1019. switch ($args[1]) {
1020. case "hands": // Exchange two hands of cards
1021. $temp_array = $hand1;
1022. $hand1 = $hand2;
1023. $hand2 = $temp_array;
1024. if ($firstplayer)
1025. $hand = &$hand1;
1026. else
1027. $hand = &$hand2;
1028. $drawncards = array_merge($drawncards, $hand);
1029. break;
1030. default: // Prisoner exchange for Hostage Chess
1031. if (($o1 = findpiece($args[2], $prison[!$firstplayer])) === false)
1032. die ("<P>Cannot find {$args[2]}.</P>");
1033. if (($o2 = findpiece($args[3], $prison[$firstplayer])) === false)
1034. die ("<P>Cannot find {$args[3]}.</P>");
1035. if (($d1 = findpiece("@", $starpath[$firstplayer])) === false)
1036. die ("<P>No vacancy. Your starpath is full.</P>");
1037. if (($d2 = findpiece("@", $starpath[!$firstplayer])) === false)
1038. die ("<P>No vacancy. Opponent's starpath is full.</P>");
1039. $space[$d1] = $space[$o1];
1040. $space[$o1] = "@";
1041. $space[$d2] = $space[$o2];
1042. $space[$o2] = "@";
1043. break;
1044. }
1045. break;
1046. case "flip": // Flips the case of the piece label at each position.
1047. // For a two-player game that represents each side with a different
1048. // case, this changes the side of each piece.
1049. if (is_array($args[1])) {
1050. for ($i = 0; $i < count($args[1]); $i++) {
1051. if (array_key_exists($args[1][$i], $space))
1052. $space[$args[1][$i]] = flipcase($space[$args[1][$i]]);
1053. }
1054. }
1055. else {
1056. for ($i = 1; $i < $cnt; $i++) {
1057. if (array_key_exists($args[$i], $space))
1058. $space[$args[$i]] = flipcase($space[$args[$i]]);
1059. }
1060. }
1061. break;
1062. case "for": // An alias for foreach.
1063. case "foreach": // Loops through an array
1064. $scope++;
1065. $sub[$scope] = $subname;
1066. $ifhead[$scope] = "for";
1067. $label[$scope] = $linenum;
1068. $array[$scope] = polish(array_slice($args, 2),$linenum);
1069. if (!is_array($array[$scope]))
1070. error("The last expression is {$array[$scope]}. In for or foreach, it must evaluate to an array.", $linenum);
1071. if (count($array[$scope]) == 0) {
1072. $linenum = $links[$linenum];
1073. $scope--;
1074. }
1075. else {
1076. if ((array)$args[1] === $args[1]) {
1077. $forvar[$scope] = $args[1][1];
1078. $keyvar[$scope] = $args[1][0];
1079. }
1080. else
1081. $forvar[$scope] = $args[1];
1082. reset ($array[$scope]);
1083. if (isset($keyvar[$scope]))
1084. setuservar($keyvar[$scope], key($array[$scope]));
1085. $forval = current($array[$scope]);
1086. setuservar($forvar[$scope], $forval);
1087. $condition[$scope] = true;
1088. }
1089. break;
1090. case "next": // The closing part of a foreach loop
1091. if ($ifhead[$scope] != "for")
1092. error ("Misplaced next", $linenum);
1093. if (!is_array($array[$scope]))
1094. error ("Out of scope next", $linenum);
1095. $forval = next($array[$scope]);
1096. // After calling next, the key will not be 0
1097. // So only the end of the array should yield an empty value
1098. if (empty(key($array[$scope])))
1099. $scope--;
1100. else {
1101. if (isset($keyvar[$scope]))
1102. setuservar($keyvar[$scope], key($array[$scope]));
1103. setuservar($forvar[$scope], $forval);
1104. $linenum = $label[$scope];
1105. }
1106. break;
1107. case "redo": // Restart a loop without checking any conditions
1108. case "continue": // Goto the bottom condition of a loop
1109. for ($oldscope = $scope; $scope > 0; $scope--) {
1110. if (($ifhead[$scope] == "for") || ($ifhead[$scope] == "do"))
1111. break;
1112. }
1113. if (($ifhead[$scope] != "for") && ($ifhead[$scope] != "do"))
1114. error ("Misplaced {$args[0]}", $linenum);
1115. unsetlocals ($oldscope, $scope);
1116. if ($args[0] == "redo")
1117. $linenum = $label[$scope];
1118. else
1119. $linenum = $links[$label[$scope]] - 1;
1120. break;
1121. case "break": // Break out of innermost loop or switch statement
1122. for ($oldscope = $scope; $scope > 0; $scope--) {
1123. switch ($ifhead[$scope]) {
1124. case "for": case "do": case "switch":
1125. break 2;
1126. }
1127. }
1128. if ($scope == 0)
1129. error ("Misplaced {$args[0]}", $linenum);
1130. $linenum = $links[$label[$scope]];
1131. if (($ifhead[$scope] == "switch") && (isset($links[$linenum])))
1132. $linenum = $links[$linenum];
1133. unsetlocals ($oldscope, --$scope);
1134. break;
1135. // NEEDS DOCUMENATION
1136. case "give": // Give listed cards from your hand to other player
1137. if ($firstplayer) {
1138. $hand = &$hand1;
1139. $otherhand = &$hand2;
1140. }
1141. else {
1142. $hand = &$hand2;
1143. $otherhand = &$hand1;
1144. }
1145. for ($i = 1; $i < $cnt; $i++) {
1146. if (in_array($args[$i], $hand)) {
1147. $k = array_search($args[$i], $hand);
1148. array_push($otherhand, $hand[$k]);
1149. unset ($hand[$k]);
1150. }
1151. else
1152. die ("<P>You can't give away a {$cards[$args[$i]]->alt}, because you don't have one in your hand. Go back and enter a legal move.</P>");
1153. }
1154. $hand = array_values($hand);
1155. break;
1156. case "switch": // A computed goto with blocks of code for different cases
1157. $scope++;
1158. $sub[$scope] = $subname;
1159. $ifhead[$scope] = "switch";
1160. $label[$scope] = $linenum;
1161. $temp = polish(array_slice($args, 1),$linenum);
1162. if (isset($cases[$linenum][$temp]))
1163. $linenum = $cases[$linenum][$temp];
1164. elseif (isset($cases[$linenum]["default:"]))
1165. $linenum = $cases[$linenum]["default:"];
1166. else
1167. error ("Missing both default and case \"{$temp}\" in switch", $linenum);
1168. break;
1169. case "case": // Identifies a label in a switch statement
1170. case "default": // Identifies the code a switch statement runs by default when
1171. // there are no matching cases.
1172. break;
1173. case "endswitch": // The end of a switch statement
1174. if ($ifhead[$scope] != "switch")
1175. error ("Misplaced <b>{$args[0]}</b>.", $linenum);
1176. unsetlocals ($scope, --$scope);
1177. break;
1178. case "sub": // Indicates the start of a subroutine definition
1179. if (empty($args[1]))
1180. error ("Every subroutine requires a name.", $linenum);
1181. if (in_array($args[1], $reserved))
1182. error ("The name of <b>$args[1]</b> is a reserved keyword. It cannot be used as a subroutine name.", $linenum);
1183. if (isset($space[$args[1]]))
1184. error ("No subroutine may bear the same name as a coordinate.", $linenum);
1185. if (ctype_digit($args[1][0]))
1186. error ("No subroutine name may begin with a digit.", $linenum);
1187. $label[$args[1]] = $linenum;
1188. if (!isset($links[$linenum]))
1189. error ("Unknown error concerning the definition of subroutine {$args[1]}.", $linenum);
1190. $linenum = $links[$linenum];
1191. break;
1192. case "endsub": // Indicates the end of a subroutine definition
1193. if ($ifhead[$scope] == "sub")
1194. unsetlocals ($scope, --$scope);
1195. else
1196. error ("Misplaced endsub.", $linenum);
1197. return NULL;
1198. break;
1199. case "gosub": // Goes to the named subroutine
1200. $gosub = $args[1];
1201. $subargs = array_slice($args, 2);
1202. if (!isset($label[$gosub]))
1203. error ("gosub goes to unknown subroutine {$gosub}", $linenum);
1204. setuservar("RESULT", runsubroutine ($gosub, $subargs, $linenum));
1205. if (!empty($exit))
1206. return;
1207. break;
1208. case "moveindex": // NEEDS DOCUMENTATION. ADDED AUTOMATICALLY BETWEEN MOVES.
1209. $mln = $args[1]; // Sets index value for array of moves
1210. $firstplayer = (($mline[$mln]->movenum % $sidecnt) == 1);
1211. // $firstplayer = !$firstplayer; // Switches player
1212. // Something to do with cards. No effect on most games.
1213. if ($firstplayer)
1214. $playedcards1 = array();
1215. else
1216. $playedcards2 = array();
1217. $drawncards = array();
1218. $movecnt = 0; // Resets $movecnt
1219. $message = "";
1220. $posdata[$moveindex] = array();
1221. if ($moveindex == 0) {
1222. $prevpos = $posdata[$moveindex]["space"] = aliasedarray($space);
1223. }
1224. else {
1225. $thispos = aliasedarray($space);
1226. $posdata[$moveindex]["space"] = array_diff_assoc($thispos, $prevpos);
1227. $prevpos = $thispos;
1228. }
1229. if (isset($capturedpieces))
1230. $posdata[$moveindex]["captured"] = $capturedpieces;
1231. if (($moveindex == 0) || ($posdata[0]["background"] != $background))
1232. $posdata[$moveindex]["background"] = $background;
1233. if ($moveindex > 0) {
1234. $posdata[$moveindex]["dest"] = $dest;
1235. $posdata[$moveindex]["origin"] = $origin;
1236. }
1237. $moveindex++;
1238. break;
1239. case "endlib": // Indicates end of code from include file
1240. if ($scope != 0)
1241. error ("Misplaced endlib.", $linenum);
1242. $linenum = array_pop($returns);
1243. break;
1244. case "return": // Returns execution from a subroutine to where it left off
1245. // in the previous scope, returning any value of the expression as the value
1246. // of the subroutine call.
1247. if ($subscope == 0)
1248. error ("Misplaced return.", $linenum);
1249. $retval = polish(array_slice($args, 1),$linenum);
1250. unsetlocals ($scope, $scope = ($subscope - 1));
1251. return $retval;
1252. break;
1253. case "do": // Starts a loop. May include a while or until condition.
1254. $scope++;
1255. $sub[$scope] = $subname;
1256. $ifhead[$scope] = "do";
1257. if (empty($args[1]))
1258. $condition[$scope] = true;
1259. elseif ($args[1] == "while")
1260. $condition[$scope] = polish(array_slice($args, 2),$linenum);
1261. elseif ($args[1] == "until")
1262. $condition[$scope] = !polish(array_slice($args, 2),$linenum);
1263. else
1264. $condition[$scope] = true;
1265. $label[$scope] = $linenum;
1266. if (!$condition[$scope]) {
1267. $linenum = $links[$linenum];
1268. unsetlocals ($scope, --$scope);
1269. }
1270. break;
1271. case "loop": // Ends a loop. May include a while, until, or never condition.
1272. if ($ifhead[$scope] != "do")
1273. error ("Misplaced loop within scope of {$ifhead[$scope]} at scope $scope.", $linenum);
1274. if (empty($args[1]))
1275. $condition[$scope] = true;
1276. elseif ($args[1] == "while")
1277. $condition[$scope] = polish(array_slice($args, 2),$linenum);
1278. elseif ($args[1] == "until")
1279. $condition[$scope] = !polish(array_slice($args, 2),$linenum);
1280. elseif ($args[1] == "never")
1281. $condition[$scope] = false;
1282. else
1283. $condition[$scope] = true;
1284. if ($condition[$scope])
1285. $linenum = $label[$scope] - 1;
1286. else
1287. unsetlocals ($scope, $scope-1);
1288. $scope--;
1289. break;
1290. case "if": // Executes code in its block if condition is true.
1291. // May start an if-block series, consisting of
1292. // one if, multiple endifs, and one else.
1293. $scope++;
1294. $sub[$scope] = $subname;
1295. $ifhead[$scope] = "if";
1296. $condition[$scope] = false; // Pseudo-previous condition
1297. case "elseif": // Indicates code to run when no prior if or endif
1298. // was true but its own condition is true.
1299. if ($condition[$scope] == false) {
1300. $condition[$scope] = polish(array_slice($args, 1),$linenum);
1301. if (!$condition[$scope]) {
1302. $linenum = $links[$linenum] - 1;
1303. }
1304. }
1305. else {
1306. do {
1307. $linenum = $links[$linenum];
1308. } while (isset($links[$linenum]));
1309. $linenum--;
1310. }
1311. break;
1312. case "else": // Indicates code to run when the if-condition and any
1313. // prior elseif conditions were all false
1314. if (empty($ifhead[$scope]) || ($ifhead[$scope] != "if")) {
1315. $ifscp = $ifhead[$scope] ?? "";
1316. error ("Misplaced <b>else</b> within {$ifscp} scope {$scope}.", $linenum);
1317. }
1318. if ($condition[$scope] == true) {
1319. $linenum = ($links[$linenum] ?? 0) - 1;
1320. }
1321. break;
1322. case "endif": // Marks end of if-block series.
1323. // case "endifs": REMOVED ALIAS
1324. if (empty($ifhead[$scope]) || ($ifhead[$scope] != "if")) {
1325. print_r($ifhead);
1326. print_r($scope);
1327. $ifscp = $ifhead[$scope] ?? "";
1328. error ("Misplaced <b>{$args[0]}</b> within {$ifscp} scope {$scope}.", $linenum);
1329. }
1330. unsetlocals ($scope, --$scope);
1331. break;
1332. case "verify": // Returns value of false from subroutine unless condition is true
1333. $condition[$scope] = polish(array_slice($args, 1),$linenum);
1334. if (!$condition[$scope]) {
1335. unsetlocals ($scope, $scope = ($subscope - 1));
1336. return false;
1337. }
1338. break;
1339. case "inc": // Increments integer variable by one
1340. $temp = &refvar($args[1]);
1341. $temp++;
1342. unset ($temp);
1343. break;
1344. case "include": // Places code from include file after end of program,
1345. // runs it, and returns execution to next line after include.
1346. if (!empty($args[2]) && ($args[2] == "if") && !polish(array_slice($args, 3),$linenum))
1347. break;
1348. if ($ifhead[$scope] != "main") {
1349. printf ("<P>ifhead[$scope] is {$ifhead[$scope]}</P>");
1350. error ("The <b>include</b> command may not be used except at the main level.", $linenum);
1351. }
1352. if (ctype_digit($args[1][0]))
1353. error ("No include file may have a name beginning with a digit.", $linenum);
1354. if (array_search($args[1], $includes))
1355. break;
1356. array_push ($includes, $args[1]);
1357. if (substr($args[1], -4) != ".txt")
1358. $fname = $args[1] . ".txt";
1359. if ($args[1][0] == "/")
1360. $fname = CVP_ROOT . $args[1];
1361. else
1362. $fname = "includes/{$fname}";
1363. if ($fc = file_get_contents($fname)) {
1364. array_push ($returns, $linenum);
1365. $linenum = $maxlines;
1366. $fc = "lib {$args[1]};" . stripcomments($fc) . ";endlib;";
1367. $newlines = parseprog($fc);
1368. foreach ($newlines as $nl) {
1369. if (!empty($nl))
1370. $codelines[] = $nl;
1371. }
1372. $maxlines = count($codelines);
1373. setlinks ($linenum);
1374. }
1375. else
1376. die ("<P><B>Game Courier Error</B>: Could not include {$fname}</P>");
1377. break;
1378. /* case "kamikaze": // REMOVED
1379. if ($lastcaptured != "@")
1380. if ((empty($args[1]) || ($space[$dest]) == $args[1]))
1381. $space[$dest] = "@";
1382. break; */
1383. case "list": // Lists the program
1384. listprog();
1385. break;
1386. case "load": // Loads named deck of cards from server
1387. if ($args[1] == "cards") {
1388. $include_file = "cards/" . $args[2] . ".php";
1389. if (1) {
1390. include_once ($include_file);
1391. }
1392. }
1393. break;
1394. case "local": // Identifies a new variable as a dynamically indexed local variable
1395. for ($i = 1; $i < $cnt; $i++)
1396. if (!isset($uservar[$scope]["main"][$args[$i]]))
1397. $uservar[$scope]["main"][$args[$i]] = 0;
1398. break;
1399. case "my": // Identifies a new variable as both dynamically and lexically
1400. // indexed. Such a variable exists only in a single subroutine call.
1401. for ($i = 1; $i < $cnt; $i++)
1402. if (!isset($uservar[$scope][$sub[$scope]][$args[$i]]))
1403. $uservar[$scope][$sub[$scope]][$args[$i]] = 0;
1404. break;
1405. case "static": // Identifies variable as a lexically indexed variable that
1406. // retains its value between subroutine calls.
1407. if (!isset($uservar[0][$sub[$scope]][$args[1]]))
1408. $uservar[0][$sub[$scope]][$args[1]] = polish(array_slice($args, 2),$linenum);
1409. break;
1410. case "map": // Maps new logical direction(s) from existing relationships
1411. // between coordinates
1412. $rcnt = count($rank);
1413. $fcnt = count($file);
1414. if (is_numeric($args[2])) {
1415. for ($i = 1; $i < $cnt; $i+=3) {
1416. $direction = $args[$i];
1417. $y = $args[$i+1];
1418. $x = $args[$i+2];
1419. for ($r = 0; $r < $rcnt; $r++) {
1420. $rl = $rank[$r];
1421. if (isset($rank[$r + $x])) {
1422. $nr = $rank[$r + $x];
1423. for ($f = 0; $f < $fcnt; $f++) {
1424. $c = $file[$f] . $rl;
1425. if (isset($file[$f + $y])) {
1426. $n = $file[$f + $y] . $nr;
1427. if (isset($space[$n]) && ($space[$n] != '-'))
1428. $map[$c][$direction] = $n;
1429. }
1430. }
1431. }
1432. }
1433. }
1434. }
1435. elseif (is_array($args[2])) {
1436. for ($i = 1; $i < $cnt; $i+=2) {
1437. $direction = $args[$i];
1438. $directions = $args[$i+1];
1439. $jcnt = count($directions);
1440. foreach ($space as $c => $discard) {
1441. $n = $c;
1442. for ($j = 0; $j < $jcnt; $j++) {
1443. if (empty($map[$n]) || empty($map[$n][$directions[$j]])) {
1444. $n = "";
1445. break;
1446. }
1447. $n = $map[$n][$directions[$j]];
1448. }
1449. if (!empty($space[$n]) && ($space[$n] != '-'))
1450. $map[$c][$direction] = $n;
1451. }
1452. }
1453. }
1454. else {
1455. $direction = $args[1];
1456. for ($r = 0; $r < $rcnt; $r++) {
1457. $rl = $rank[$r];
1458. $nr = $rank[$r + $x];
1459. for ($f = 0; $f < $fcnt; $f++) {
1460. $c = $n = $file[$f] . $rl;
1461. for ($i = 2; $i < $cnt; $i++) {
1462. $n = $map[$n][$args[$i]];
1463. if (empty($n))
1464. break 2;
1465. }
1466. if (isset($space[$n]) && ($space[$n] != '-'))
1467. $map[$c][$direction] = $n;
1468. }
1469. }
1470. }
1471. break;
1472. case "link": // Adds individual links from one space to another to the map
1473. // for a specific logical direction.
1474. $direction = $args[1];
1475. for ($i = 2; $i < $cnt; $i++) {
1476. if (!is_array($args[$i]))
1477. error ("<P>Argument {$i}, {$args[$i]}, in link is not an array.</P>", $linenum);
1478. $subcnt = count($args[$i]) - 1;
1479. for ($j = 0; $j < $subcnt; $j++) {
1480. $map[$args[$i][$j]][$direction] = $args[$i][$j+1];
1481. }
1482. }
1483. /*
1484. echo "<PRE>";
1485. print_r($map);
1486. echo "</PRE>";
1487. */
1488. break;
1489. case "rlink": // Adds individual links from one space to another to the map
1490. // for a specific logical direction.
1491. $direction = $args[1];
1492. for ($i = 2; $i < $cnt; $i++) {
1493. if (!is_array($args[$i]))
1494. error ("<P>Argument {$i}, {$args[$i]}, in rlink is not an array.</P>", $linenum);
1495. $subcnt = count($args[$i]) - 1;
1496. for ($j = 0; $j < $subcnt; $j++) {
1497. $map[$args[$i][$j+1]][$direction] = $args[$i][$j];
1498. }
1499. }
1500. break;
1501. case "unlink": // CONTINUE;
1502. // Unlinks specific pairings of coordinates from map for specific direction.
1503. // map[from][dir] = to;
1504. // loop through arguments
1505. if (is_array($args[1]) || array_key_exists($args[1], $space) || (strpos("*", $args[1]) !== false)) {
1506. for ($i = 1; $i < $cnt; $i++) {
1507. // When coordinates are grouped together in an array, unlink them from each other
1508. $ai = $args[$i];
1509. if (empty($ai))
1510. continue;
1511. if (is_array($ai) && (count($ai) > 0)) {
1512. $temp = $ai;
1513. foreach ($ai as $f1) {
1514. if (!is_array($f1) && !ctype_alnum($f1))
1515. // $f1 = array_filter(array_keys($map), create_function('$v', "return fnmatch(\"$f1\",\$v);"));
1516. $f1 = array_filter(array_keys($map), function($v) use ($f1) {return fnmatch($f1,$v);});
1517. // When one array is nested within another, unlink the coordinates in the nested
1518. // array from whatever else is in the first array, but not from each other.
1519. if (is_array($f1)) {
1520. foreach ($f1 as $f2) {
1521. if (!ctype_alnum($f2))
1522. // $ra = array_filter(array_keys($map), create_function('$v', "return fnmatch(\"$f2\",\$v);"));
1523. $ra = array_filter(array_keys($map), function($v) use ($f2) {return fnmatch($f2,$v);});
1524. else
1525. $ra = array($f2);
1526. foreach ($ra as $f3) {
1527. reset ($map[$f3]);
1528. foreach ($map[$f3] as $d => $to) {
1529. reset ($temp);
1530. foreach ($temp as $v1) {
1531. if (!is_array($v1) && !ctype_alnum($v1))
1532. // $v1 = array_filter(array_keys($map), create_function('$v', "return fnmatch(\"$v1\",\$v);"));
1533. $v1 = array_filter(array_keys($map), function($v) use ($v1) {return fnmatch($v1,$v);});
1534. if (is_array($v1)) {
1535. if ($v1 == $f1)
1536. continue;
1537. foreach ($v1 as $v2) {
1538. if (($f3 != $v2) && fnmatch($v2,$to))
1539. unset ($map[$f3][$d]);
1540. }
1541. }
1542. elseif (fnmatch($v1,$to))
1543. unset ($map[$f3][$d]);
1544. }
1545. }
1546. }
1547. }
1548. }
1549. // Simple element appears in first array.
1550. else {
1551. reset ($map[$f1]);
1552. foreach ($map[$f1] as $d => $to) {
1553. reset ($temp);
1554. foreach ($temp as $v1) {
1555. if (is_array($v1)) {
1556. foreach ($v1 as $v2) {
1557. if (fnmatch($v2,$to))
1558. unset ($map[$f1][$d]);
1559. }
1560. }
1561. elseif (fnmatch($v1,$to))
1562. unset ($map[$f1][$d]);
1563. }
1564. }
1565. }
1566. }
1567. }
1568. // when a single coordinate appears, unlink it from everything
1569. elseif (!is_array($ai) && (isset($space[$ai]) || array_key_exists($ai, $space)))
1570. unlink_all ($ai);
1571. elseif (!is_array($ai) && !ctype_alnum($ai)) {
1572. // $ai = array_filter(array_keys($map), create_function('$v', "return fnmatch(\"$ai\",\$v);"));
1573. $ai = array_filter(array_keys($map), function($v) use ($ai) {return fnmatch($ai,$v);});
1574. foreach ($ai as $val)
1575. unlink_all ($val);
1576. }
1577. }
1578. }
1579. else {
1580. $direction = $args[1];
1581. for ($i = 2; $i < $cnt; $i++) {
1582. $ai = $args[$i];
1583. if (!is_array($ai)) {
1584. if (array_key_exists($ai, $map)) {
1585. if (isset($map[$ai][$direction])) {
1586. unset ($map[$ai][$direction]);
1587. }
1588. }
1589. elseif (strpos("*", $ai) !== false) {
1590. foreach ($map as $key => $val) {
1591. if (fnmatch ($ai, $key) && ($val == $direction)) {
1592. unset ($map[$key][$val]);
1593. }
1594. }
1595. }
1596. else {
1597. $direction = $ai;
1598. }
1599. }
1600. }
1601. }
1602. break;
1603. case "move": // Moves piece from one space to another
1604. if ($args[1] != $args[2]) {
1605. if (!array_key_exists($args[1], $space)) {
1606. printf ("<P>\count is %s</P>", count($args));
1607. fpdebug2("args", $args);
1608. error ("The first argument to the <B>move</B> command, {$args[1]}, is not a recognized coordinate.", $linenum);
1609. }
1610. if (!empty($args[2])) {
1611. $space[$args[2]] = $space[$args[1]];
1612. // $flag[$args[2]] = $flag[$args[1]];
1613. }
1614. $space[$args[1]] = "@";
1615. // $flag[$args[1]] = false;
1616. }
1617. break;
1618. case "pass": // Pass turn
1619. case "skip": // Skip expected portion of move, such as promotion,
1620. // showing that a move is not incomplete as is.
1621. break;
1622. case "place": // for playing continuing effect cards
1623. if ($firstplayer)
1624. $hand = &$hand1;
1625. else
1626. $hand = &$hand2;
1627. for ($i = 1; $i < $cnt; $i++) {
1628. $k = array_search($args[$i], $hand);
1629. if (in_array($args[$i], $hand)) {
1630. array_push($displayedcards, $hand[$k]);
1631. unset ($hand[$k]);
1632. }
1633. }
1634. $hand = array_values($hand);
1635. break;
1636. case "play": // Play cards from hand
1637. // Displays cards to opponent and moves them to discard pile
1638. if ($firstplayer) {
1639. $hand = &$hand1;
1640. $playedcards = &$playedcards1;
1641. }
1642. else {
1643. $hand = &$hand2;
1644. $playedcards = &$playedcards2;
1645. }
1646. for ($i = 1; $i < $cnt; $i++) {
1647. $k = array_search($args[$i], $hand);
1648. if (in_array($args[$i], $hand)) {
1649. array_push($discardpile, $hand[$k]);
1650. array_push($playedcards, $hand[$k]);
1651. unset ($hand[$k]);
1652. }
1653. else
1654. die ("<P>You can't play a {$cards[$args[$i]]->alt}, because you don't have one in your hand. Go back and enter a legal move.</P>");
1655. }
1656. $hand = array_values($hand);
1657. break;
1658. case "pop": // Pops off last value of array and copies it to variable.
1659. $temp = &refvar($args[1]);
1660. setuservar($args[2], array_pop($temp));
1661. unset($temp);
1662. break;
1663. case "push": // Pushes value of expression to end of array.
1664. $temp = &refvar($args[1]);
1665. if (isset($temp) && (!is_array($temp)))
1666. $temp = array($temp);
1667. $temp[] = polish(array_slice($args, 2),$linenum);
1668. unset($temp);
1669. // pushuservar($args[1], polish(array_slice($args, 2),$linenum));
1670. break;
1671. // "pushall" NEEDS DOCUMENTATION
1672. case "pushall": // Pushes all listed values to end of array in sequence
1673. $temp = &refvar($args[1]);
1674. for ($i = 2; $i < $cnt; $i++)
1675. $temp[] = $args[$i];
1676. unset($temp);
1677. break;
1678. // "stopwatch" NEEDS DOCUMENTATION
1679. case "stopwatch": // Used to time code. Useful for optimizing.
1680. if (array_key_exists(1, $args) && ($args[1] == "reset")) { // Starts stopwatch
1681. $watchstart = microtime(true);
1682. }
1683. else { // Outputs time passed
1684. $watchtime = microtime(true) - $watchstart;
1685. echo "<P>Elapsed time: {$watchtime} seconds</P>";
1686. }
1687. break;
1688. case "reserve": // Place pieces in reserve area, used by games like Chessgi and Shogi.
1689. echo "<PRE>";
1690. print_r ($args);
1691. if (($args[1] == "left") || ($args[1] == "second")) {
1692. $stpath = $starpath[false];
1693. $start = 2;
1694. }
1695. elseif (($args[1] == "right") || ($args[1] == "first")) {
1696. $stpath = $starpath[true];
1697. $start = 2;
1698. }
1699. else {
1700. $stpath = $starpath[true];
1701. $start = 1;
1702. }
1703. echo "{$start}<BR>";
1704. echo "{$cnt}<BR>";
1705. for ($i = $start; $i < $cnt; $i++) {
1706. echo $args[$i];
1707. $jcnt = 1;
1708. while (is_numeric($args[$i])) {
1709. echo "<P>$i is numeric.</P>";
1710. $jcnt = $args[$i];
1711. $i++;
1712. }
1713. if ($args[$i] == "")
1714. continue;
1715. for ($j = 0; $j < $jcnt; $j++) {
1716. foreach ($stpath as $k => $v) {
1717. if ($space[$v] == "@") {
1718. echo "<P>{$args[$i]} on $v</P>";
1719. $space[$v] = $args[$i];
1720. break;
1721. }
1722. }
1723. }
1724. }
1725. echo "</PRE>";
1726. break;
1727. case "resign": // User command to resign from game
1728. case "resigned": // Alias for resign
1729. case "resigns": // Alias for resign
1730. if (!$gameover || ($submit != "Fix")) {
1731. if (($submit == "Move") || ($submit == "Play")) {
1732. $GLOBALS["winner"] = ($side == $turnorder[0]) ? $turnorder[0] : $turnorder[1];
1733. $GLOBALS["status"] = sprintf("%s has won.", $GLOBALS["winner"]);
1734. $loser = ($winner == $turnorder[1]) ? $turnorder[0] : $turnorder[1];
1735. $losername = userid_name($loser);
1736. if (empty($losername))
1737. $losername = $loser;
1738. $message = "{$losername} has resigned.";
1739. }
1740. elseif (empty($player) || empty($opponent)) {
1741. $GLOBALS["winner"] = ($side == $turnorder[0]) ? $turnorder[0] : $turnorder[1];
1742. $GLOBALS["status"] = sprintf("%s has won.", $GLOBALS["winner"]);
1743. $loser = ($winner == $turnorder[1]) ? $turnorder[0] : $turnorder[1];
1744. $message = "{$loser} has resigned.";
1745. }
1746. else {
1747. if (($submit == "Preview") || ($submit == "Send")) {
1748. $GLOBALS["winner"] = $opponent;
1749. $GLOBALS["status"] = sprintf("%s has won.", userid_name($winner));
1750. }
1751. elseif (!empty($players)) {
1752. $ps = explode(" ", $players);
1753. $winner = ($mline[$mln]->movenum & 1) ? $ps[1] : $ps[0];
1754. }
1755. elseif (($mline[$mln]->movenum & 1) == ($movenum & 1)) {
1756. // Last player to move in entire game was the same as the player of this move,
1757. // and $player and $opponent values were swapped after completion of move.
1758. $winner = $player;
1759. }
1760. else {
1761. // Last player to move in entire game was not the same as the player of this move,
1762. // and $player and $opponent values were swapped after completion of move.
1763. $winner = $opponent;
1764. }
1765. $GLOBALS["status"] = sprintf("%s has won.", userid_name($winner));
1766. $loser = ($winner == $player) ? $opponent : $player;
1767. $losername = userid_name($loser);
1768. if (empty($losername))
1769. $losername = $loser;
1770. $message = "{$losername} has resigned.";
1771. }
1772. }
1773. $lastcaptured = $lastmoved = $dest = $origin = $prevcaptured = $prevmoved = $prevorigin = $prevdest = "";
1774. $gameover = $exit = true;
1775. return;
1776. break;
1777. case "lost": // Program command to indicate the current player has lost
1778. if (($submit == "Move") || ($submit == "Play")) {
1779. $GLOBALS["winner"] = ($side == $turnorder[0]) ? $turnorder[0] : $turnorder[1];
1780. $GLOBALS["status"] = sprintf("%s has won.", $GLOBALS["winner"]);
1781. }
1782. else {
1783. if (($submit == "Preview") || ($submit == "Send")) {
1784. $GLOBALS["winner"] = $opponent;
1785. $GLOBALS["status"] = sprintf("%s has won.", userid_name($winner));
1786. }
1787. elseif (!empty($players)) {
1788. $ps = explode(" ", $players);
1789. $winner = ($mline[$mln]->movenum & 1) ? $ps[1] : $ps[0];
1790. }
1791. elseif (($mline[$mln]->movenum & 1) == ($movenum & 1)) {
1792. // Last player to move in entire game was the same as the player of this move,
1793. // and $player and $opponent values were swapped after completion of move.
1794. $winner = $player;
1795. }
1796. else {
1797. // Last player to move in entire game was not the same as the player of this move,
1798. // and $player and $opponent values were swapped after completion of move.
1799. $winner = $opponent;
1800. }
1801. $GLOBALS["status"] = sprintf("%s has won.", userid_name($winner));
1802. }
1803. $gameover = $exit = true;
1804. return;
1805. break;
1806. case "won": // Indicates that current player has won
1807. if (($submit == "Move") || ($submit == "Play") || empty($GLOBALS["log"])) {
1808. $GLOBALS["winner"] = ($side != $turnorder[0]) ? $turnorder[0] : $turnorder[1];
1809. $GLOBALS["status"] = sprintf("%s has won.", $GLOBALS["winner"]);
1810. }
1811. else {
1812. if (($submit == "Preview") || ($submit == "Send")) {
1813. $GLOBALS["winner"] = $player;
1814. $GLOBALS["status"] = sprintf("%s has won.", userid_name($winner));
1815. }
1816. elseif (!empty($players)) {
1817. $ps = explode(" ", $players);
1818. $winner = ($mline[$mln]->movenum & 1) ? $ps[0] : $ps[1];
1819. }
1820. elseif (!empty($mline) && (($mline[$mln]->movenum & 1) == ($movenum & 1))) {
1821. // Last player to move in entire game was the same as the player of this move,
1822. // and $player and $opponent values were swapped after completion of move.
1823. $winner = $opponent;
1824. }
1825. else {
1826. // Last player to move in entire game was not the same as the player of this move,
1827. // and $player and $opponent values were swapped after completion of move.
1828. $winner = $player;
1829. }
1830. $GLOBALS["status"] = sprintf("%s has won.", userid_name($winner));
1831. }
1832. $gameover = $exit = true;
1833. return;
1834. break;
1835. case "drawn": // Indicates that the game has ended in a draw
1836. if (empty($submit) || ($submit == "Preview") || ($submit == "Send") || ($submit == "View") || ($submit == "Move")) {
1837. $GLOBALS["status"] = "Drawn game.";
1838. $GLOBALS["winner"] = "";
1839. if (empty($GLOBALS["message"]))
1840. $GLOBALS["message"] = "The game is declared drawn.";
1841. }
1842. $gameover = $exit = true;
1843. return;
1844. break;
1845. case "recolor": // Changes color index of space(s) on board
1846. $nc = polish(array_slice($args, 2),$linenum);
1847. if (is_array($args[1])) {
1848. foreach ($args[1] as $val)
1849. $background[$val] = $nc;
1850. }
1851. else
1852. $background[$args[1]] = $nc;
1853. break;
1854. case "reverse": // Reverses the order of the content of the listed coordinates
1855. $halfway = ceil($cnt/2);
1856. for ($i = 1; $i < $halfway; $i++) {
1857. $temp = $space[$args[$i]];
1858. $space[$args[$i]] = $space[$args[$cnt - $i]];
1859. $space[$args[$cnt - $i]] = $temp;
1860. }
1861. break;
1862. case "rotate": // Moves each piece in list of coordinates to next position,
1863. // and piece at last position to first position.
1864. if ($cnt > 2) {
1865. $temp = $space[$args[$cnt-1]];
1866. for ($i = $cnt-1; $i > 1; $i--)
1867. $space[$args[$i]] = $space[$args[$i-1]];
1868. $space[$args[1]] = $temp;
1869. }
1870. break;
1871. case "set": // Sets a named variable to value of expression
1872. if ($args[1] == "many") {
1873. for ($i = 2; $i < $cnt; $i += 2) {
1874. if (ctype_digit($args[$i][0]))
1875. error ("A variable name should not begin with a digit.", $linenum);
1876. if (array_key_exists($i+1, $args))
1877. setuservar($args[$i], $args[$i+1]);
1878. else
1879. error ("set many should be followed by an even number of arguments. No argument has been given for the variable called {$args[$i]}. If you were trying to use 'set many' with an expression, you can enclose it in {braces} or set it on its own line.", $linenum);
1880. }
1881. }
1882. elseif (empty($args[1])) {
1883. error ("A variable name should not be empty.", $linenum);
1884. }
1885. elseif (ctype_digit($args[1][0] ?? ""))
1886. error ("A variable name should not begin with a digit.", $linenum);
1887. else {
1888. setuservar($args[1], polish(array_slice($args, 2),$linenum));
1889. }
1890. break;
1891. case "setjsvar": // Passes value from GAME Code to a JavaScript variable
1892. $jsvar[$args[1]] = polish(array_slice($args, 2),$linenum);
1893. break;
1894. case "setlegal": // Records indicated move(s) to $legalmoves array,
1895. // which will be passed to the JavaScript legalMoves array.
1896. if (empty($legalmoves))
1897. $legalmoves = array();
1898. if (is_array($args[1])) {
1899. for ($i = 1; $i < $cnt; $i++) {
1900. if (is_array($args[$i])) {
1901. if (count($args[$i]) < 2) {
1902. print_r($args[$i]);
1903. error("setlegal: Array should include at least two coordinates.", $linenum);
1904. }
1905. $lm = compose_move($args[$i]);
1906. if (!in_array($lm, $legalmoves))
1907. $legalmoves[] = $lm;
1908. }
1909. else {
1910. badinput("setlegal: {$args[$i]} was expected to be an array, but it is not.");
1911. }
1912. }
1913. }
1914. elseif (strpos(trim($args[1]), " ") || (strpos($args[1], "-") !== false) || strpos($args[1], "*")) {
1915. for ($i = 1; $i < $cnt; $i++) {
1916. if (valid_move($args[$i]))
1917. $legalmoves[] = $args[$i];
1918. }
1919. }
1920. else {
1921. $k = 1;
1922. while ($k < $cnt) {
1923. if (!$space[$args[$k]] && !$pieces[$args[$k]] && ($args[$k] != "@")) {
1924. print_r ($space);
1925. badinput ("setlegal: {$args[$k]} is not a valid piece or coordinate.");
1926. }
1927. for ($i = $k+1; $i < $cnt; $i++) {
1928. if ((array)$args[$i] === $args[$i]) {
1929. $temp = polish($args[$i],$linenum);
1930. if ((array)$temp == $temp) {
1931. $tcnt = count($temp);
1932. for ($j = 0; $j < $tcnt; $j++) {
1933. if (!$space[$temp[$j]])
1934. badinput ("{$temp[$j]} is not a valid coordinate.");
1935. $lm = compose_move($args[$k], $temp[$j]);
1936. if (!in_array($lm, $legalmoves))
1937. $legalmoves[] = $lm;
1938. }
1939. }
1940. else {
1941. $lm = compose_move($args[$k], $temp);
1942. if (!in_array($lm, $legalmoves))
1943. $legalmoves[] = $lm;
1944. }
1945. break;
1946. }
1947. else {
1948. $lm = compose_move($args[$k], $args[$i]);
1949. if (!in_array($lm, $legalmoves))
1950. $legalmoves[] = $lm;
1951. }
1952. }
1953. $k = $i + 1;
1954. }
1955. }
1956. break;
1957. case "setelem": // Sets specific element of array variable
1958. if (ctype_digit($args[1][0]))
1959. error ("A variable name should not begin with a digit.", $linenum);
1960. setuservar ("{$args[1]}.{$args[2]}", polish(array_slice($args, 3),$linenum));
1961. break;
1962. case "setflag": // Turns on named boolean flags
1963. for ($i = 1; $i < $cnt; $i++)
1964. $flag[$args[$i]] = true;
1965. break;
1966. case "setglobal": case "setsystem":
1967. // Sets PHP variable used by Game Courier to value of expression
1968. switch ($args[1]) {
1969. case "answered":
1970. case "appendautorules":
1971. case "autorules":
1972. case "board":
1973. case "capturedpieces":
1974. case "code":
1975. case "columns":
1976. case "debug":
1977. case "dest":
1978. case "dir":
1979. case "groupsets":
1980. case "lastcaptured":
1981. case "lastmoved":
1982. case "map":
1983. case "maxmove":
1984. case "meetingpoint":
1985. case "movelist";
1986. case "moves":
1987. case "noerrorcheck":
1988. case "omitmoves":
1989. case "orientation":
1990. case "origin":
1991. case "originalpieces":
1992. case "piecekeys":
1993. case "pieces":
1994. case "piecevals":
1995. case "prison":
1996. case "secondfirst":
1997. case "selset":
1998. case "sets":
1999. case "showoutput":
2000. case "space";
2001. case "submit":
2002. $GLOBALS[$args[1]] = polish(array_slice($args, 2),$linenum);
2003. break;
2004. case "flipped":
2005. case "legalmoves":
2006. case "starpath":
2007. $GLOBALS[$args[1]] = polish(array_slice($args, 2),$linenum);
2008. break;
2009. default:
2010. if (preg_match("/^(capturedpieces|originalpieces|piecekeys|pieces|piecevals|prison|sets|starpath)\./", $args[1])) {
2011. list($ra,$lm) = explode(".", $args[1]);
2012. $GLOBALS[$ra][$lm] = polish(array_slice($args, 2), $linenum);
2013. }
2014. else {
2015. error ("You may not set \${$args[1]} with {$args[0]}.", $linenum);
2016. }
2017. break;
2018. }
2019. if (empty($customsets) && (($args[1] == "dir") || ($args[1] == "pieces"))) {
2020. $customSet["custom"][$args[1]] = $GLOBALS[$args[1]];
2021. if (is_array($customSet) && array_key_exists("dir", $customSet["custom"]) && array_key_exists("pieces", $customSet["custom"])) {
2022. $customsets = json_encode($customSet, JSON_PRETTY_PRINT);
2023. }
2024. }
2025. break;
2026. // Used because the keyword dest gets converted to the value of $dest
2027. case "setdest":
2028. $GLOBALS["dest"] = polish(array_slice($args, 1),$linenum);
2029. break;
2030. // Used because the keyword origin gets converted to the value of $origin
2031. case "setorigin":
2032. $GLOBALS["origin"] = polish(array_slice($args, 1),$linenum);
2033. break;
2034. // Sets reminder text, which is outputted to player
2035. // Like Say, but prints smaller and lower.
2036. case "remind":
2037. $reminder = stripallslashes(join(" ", array_slice($args, 1)));
2038. break;
2039. case "resetconst": // Changes the value of a constant to the value of expression
2040. if (!is_array($constants))
2041. $constants = array();
2042. $constants[$args[1]] = polish(array_slice($args, 2),$linenum);
2043. break;
2044. case "setconst": // Set new constant to value of expression
2045. if (!is_array($constants))
2046. $constants = array();
2047. if (!array_key_exists($args[1], $constants)) {
2048. $constants[$args[1]] = polish(array_slice($args, 2),$linenum);
2049. }
2050. break;
2051. case "unsetconst": // Deletes named constant
2052. if (isset($constants[$args[1]]))
2053. unset ($constants[$args[1]]);
2054. break;
2055. case "shift": // Shifts contents of each coordinate to next coordinate,
2056. // losing what is on last coordinate.
2057. for ($i = $cnt-1; $i > 1; $i--)
2058. $space[$args[$i]] = $space[$args[$i-1]];
2059. $space[$args[1]] = '@';
2060. break;
2061. case "shuffle": // Randomly shuffles contents of listed coordinates.
2062. if ($args[1] == "cards") {
2063. $deck = shufflearray($deck);
2064. }
2065. elseif (is_array($args[1])) {
2066. $tcnt = count($args[1]);
2067. for ($i = 0; $i < $tcnt; $i++) {
2068. $j = mt_rand(0, $cnt-1);
2069. $temp = $space[$args[1][$i]];
2070. $space[$args[1][$i]] = $space[$args[1][$j]];
2071. $space[$args[1][$j]] = $temp;
2072. }
2073. }
2074. else {
2075. for ($i = 1; $i < $cnt; $i++) {
2076. $j = mt_rand(1, $cnt-1);
2077. $temp = $space[$args[$i]];
2078. $space[$args[$i]] = $space[$args[$j]];
2079. $space[$args[$j]] = $temp;
2080. }
2081. }
2082. break;
2083. case "store": // Stores board configuration, color indexes, flags, and
2084. // information about last move.
2085. // Stores to name or to "last".
2086. $storage = empty($args[1]) ? "last" : $args[1];
2087. $store[$storage]["space"] = $space;
2088. $store[$storage]["flag"] = $flag;
2089. $store[$storage]["lastcaptured"] = $lastcaptured;
2090. $store[$storage]["lastmoved"] = $lastmoved;
2091. $store[$storage]["dest"] = $dest;
2092. $store[$storage]["origin"] = $origin;
2093. $store[$storage]["background"] = $background;
2094. $store[$storage]["prevcaptured"] = $prevcaptured;
2095. $store[$storage]["prevmoved"] = $prevmoved;
2096. $store[$storage]["prevorigin"] = $prevorigin;
2097. $store[$storage]["prevdest"] = $prevdest;
2098. break;
2099. case "restore": // Restores board config, etc., to last stored config.
2100. // Restores from name or from "last".
2101. $storage = empty($args[1]) ? "last" : $args[1];
2102. if (isset($store[$storage]))
2103. extract ($store[$storage]);
2104. break;
2105. case "run": // NEEDS DOCUMENTATION
2106. // Appears to restart program from beginning.
2107. unsetlocals ($scope, 0);
2108. $scope = 0;
2109. $space = $startposition;
2110. $linenum = 0;
2111. $flag = array();
2112. $lastcaptured = $lastmoved = $dest = $origin = $prevcaptured = $prevmoved = $prevorigin = $prevdest = "";
2113. $background = $startbackground;
2114. break;
2115. case "say": // Copy text to output for player to read.
2116. $message = stripallslashes(join(" ", array_slice($args, 1)));
2117. break;
2118. case "swap": // Swaps pieces on a pair of spaces.
2119. // Multiple pairs may be listed.
2120. for ($i = 1; $i < $cnt; $i += 2) {
2121. if (array_key_exists($i, $args) && array_key_exists($i+1, $args)) {
2122. $c1 = $args[$i]; $c2 = $args[$i+1];
2123. if (array_key_exists($c1, $space) && array_key_exists($c2, $space)) {
2124. $temp = $space[$c1];
2125. $space[$c1] = $space[$c2];
2126. $space[$c2] = $temp;
2127. }
2128. }
2129. elseif ($i <= 1) {
2130. echo "<P>\$i is {$i}</P>";
2131. print_r($args);
2132. illegal ("The <b>swap</b> command does not have enough arguments.", $linenum);
2133. }
2134. }
2135. break;
2136. case "take": // NEEDS DOCUMENATION
2137. // Take so many cards from opponent's hand
2138. if ($firstplayer) {
2139. $hand = &$hand1;
2140. $otherhand = &$hand2;
2141. }
2142. else {
2143. $hand = &$hand2;
2144. $otherhand = &$hand1;
2145. }
2146. for ($i = 0; $i < $args[1]; $i++) {
2147. $c = array_pop($otherhand);
2148. array_push($hand, $c);
2149. array_push($drawncards, $c);
2150. if (count($otherhand) == 0) {
2151. die ("Your opponent has only {$i} cards. You can't take {$args[1]}. Go back and take fewer.");
2152. }
2153. }
2154. break;
2155. case "unset": // Unsets variable
2156. // If multiple variables have the same name, it unsets the one with highest precedence.
2157. for ($i = 1; $i < $cnt; $i++)
2158. unsetuservar ($args[$i]);
2159. break;
2160. case "unsetflag": // Sets boolean flag to false
2161. for ($i = 1; $i < $cnt; $i++)
2162. $flag[$args[$i]] = false;
2163. break;
2164. /*
2165. case "write": // NEEDS DOCUMENTATION
2166. write_on_space ($args[1], polish(array_slice($args, 2),$linenum));
2167. break;
2168. */
2169. case "lib": // Marks beginning of code inserted from include file
2170. break;
2171. default:
2172. error ("<B>$move</B> is not a valid expression, because <B>{$args[0]}</B> is not a recognized piece, coordinate, command, or subroutine.", $linenum);
2173. }
2174. }
2175. return NULL;
2176. }
2177.
2178. // Gets the value of the most local variable whose name is given
2179.
2180. /*
2181. function getuservar($name) {
2182. global $scope, $uservar, $sub;
2183. for ($i = $scope; $sub[$scope] == $sub[$i]; $i--)
2184. if (isset($uservar[$i][$sub[$scope]]) && (isset($uservar[$i][$sub[$scope]][$name]) || array_key_exists($name, $uservar[$i][$sub[$scope]])))
2185. return $uservar[$i][$sub[$scope]][$name];
2186. if (isset($uservar[0][$sub[$scope]]) && (isset($uservar[0][$sub[$scope]][$name]) || array_key_exists($name, $uservar[0][$sub[$scope]])))
2187. return $uservar[0][$sub[$scope]][$name];
2188. for ($i = $scope; $i >= 0; $i--)
2189. if (isset($uservar[$i]["main"]) && (isset($uservar[$i]["main"][$name]) || array_key_exists($name, $uservar[$i]["main"])))
2190. return $uservar[$i]["main"][$name];
2191. return NULL;
2192. }
2193. */
2194.
2195. function &refvar($name) {
2196. global $scope, $uservar, $sub;
2197.
2198. // When array element is specified by including periods in name,
2199. // get top level array for purposes of determining scope of variable.
2200. if ($p = strpos($name, "."))
2201. $top = substr($name, 0, $p);
2202. else
2203. $top = $name;
2204. // covers my variables, as well as global variables when lexical scope is main.
2205. for ($i = $scope; ($i >= 0) && ($sub[$scope] == $sub[$i]); $i--) {
2206. if (isset($uservar[$i][$sub[$scope]]) && (isset($uservar[$i][$sub[$scope]][$top]) || array_key_exists($top, $uservar[$i][$sub[$scope]]))) {
2207. $array = &$uservar[$i][$sub[$scope]];
2208. goto ret;
2209. }
2210. }
2211. // covers static variables
2212. if (isset($uservar[0][$sub[$scope]]) && (isset($uservar[0][$sub[$scope]][$top]) || array_key_exists($top, $uservar[0][$sub[$scope]]))) {
2213. $array = &$uservar[0][$sub[$scope]];
2214. goto ret;
2215. }
2216. // covers local variables, as well as global variables within a subroutine
2217. for ($i = $scope; $i >= 0; $i--) {
2218. if (isset($uservar[$i]["main"]) && (isset($uservar[$i]["main"][$top]) || array_key_exists($top, $uservar[$i]["main"]))) {
2219. $array = &$uservar[$i]["main"];
2220. goto ret;
2221. }
2222. }
2223. $array = &$uservar[0]["main"];
2224. ret:
2225. if (!$p)
2226. return $array[$name];
2227. $subkeys = explode(".",$name);
2228. $penult = count($subkeys) - 1;
2229. for ($i = 0; $i < $penult; $i++) {
2230. $array = &$array[$subkeys[$i]];
2231. }
2232. return $array[$subkeys[$penult]];
2233. }
2234.
2235.
2236. function &parentarray (&$array, $name) {
2237. if ($p = strpos($name, ".")) {
2238. $subkeys = explode(".",$name);
2239. $penult = count($subkeys) - 1;
2240. for ($i = 0; $i < $penult; $i++) {
2241. $array = &$array[$subkeys[$i]];
2242. }
2243. }
2244. return $array;
2245. }
2246.
2247. function getvar (&$array, $name) {
2248. if ($p = strpos($name, ".")) {
2249. $subkeys = explode(".",$name);
2250. $penult = count($subkeys) - 1;
2251. for ($i = 0; $i < $penult; $i++) {
2252. $array = &$array[$subkeys[$i]];
2253. }
2254. return $array[$subkeys[$penult]];
2255. }
2256. return $array[$name];
2257. }
2258.
2259.
2260. function getuservar($name) {
2261. global $scope, $uservar, $sub;
2262.
2263. if (empty($name))
2264. return NULL;
2265. // When array element is specified by including periods in name,
2266. // get top level array for purposes of determining scope of variable.
2267. if ($p = strpos($name, "."))
2268. $top = substr($name, 0, $p);
2269. else
2270. $top = $name;
2271. if (array_key_exists($scope, $sub)) {
2272. // covers my variables, as well as global variables when lexical scope is main.
2273. for ($i = $scope; ($i >= 0) && ($sub[$scope] == $sub[$i]); $i--) {
2274. if (isset($uservar[$i][$sub[$scope]]) && (isset($uservar[$i][$sub[$scope]][$top]) || array_key_exists($top, $uservar[$i][$sub[$scope]]))) {
2275. $array = $uservar[$i][$sub[$scope]];
2276. goto ret;
2277. }
2278. }
2279. // covers static variables
2280. if (isset($uservar[0][$sub[$scope]]) && (isset($uservar[0][$sub[$scope]][$top]) || array_key_exists($top, $uservar[0][$sub[$scope]]))) {
2281. $array = $uservar[0][$sub[$scope]];
2282. goto ret;
2283. }
2284. }
2285. // covers local variables, as well as global variables within a subroutine
2286. for ($i = $scope; $i >= 0; $i--) {
2287. if (isset($uservar[$i]["main"]) && (isset($uservar[$i]["main"][$top]) || array_key_exists($top, $uservar[$i]["main"]))) {
2288. $array = $uservar[$i]["main"];
2289. goto ret;
2290. }
2291. }
2292. return NULL;
2293. ret:
2294. if (!$p)
2295. return $array[$name];
2296. $subkeys = explode(".",$name);
2297. $penult = count($subkeys) - 1;
2298. for ($i = 0; $i < $penult; $i++) {
2299. $array = &$array[$subkeys[$i]];
2300. }
2301. if (isset($array[$subkeys[$penult]]))
2302. return $array[$subkeys[$penult]];
2303. else
2304. return NULL;
2305. }
2306.
2307. function issetuservar($name) {
2308. global $scope, $uservar, $sub;
2309.
2310. // When array element is specified by including periods in name,
2311. // get top level array for purposes of determining scope of variable.
2312. if ($p = strpos($name, "."))
2313. $top = substr($name, 0, $p);
2314. else
2315. $top = $name;
2316. // covers my variables, as well as global variables when lexical scope is main.
2317. for ($i = $scope; ($i >= 0) && ($sub[$scope] == $sub[$i]); $i--) {
2318. if (isset($uservar[$i][$sub[$scope]]) && (isset($uservar[$i][$sub[$scope]][$top]) || array_key_exists($top, $uservar[$i][$sub[$scope]]))) {
2319. $array = &$uservar[$i][$sub[$scope]];
2320. goto ret;
2321. }
2322. }
2323. // covers static variables
2324. if (isset($uservar[0][$sub[$scope]]) && (isset($uservar[0][$sub[$scope]][$top]) || array_key_exists($top, $uservar[0][$sub[$scope]]))) {
2325. $array = &$uservar[0][$sub[$scope]];
2326. goto ret;
2327. }
2328. // covers local variables, as well as global variables within a subroutine
2329. for ($i = $scope; $i >= 0; $i--) {
2330. if (isset($uservar[$i]["main"]) && (isset($uservar[$i]["main"][$top]) || array_key_exists($top, $uservar[$i]["main"]))) {
2331. $array = &$uservar[$i]["main"];
2332. goto ret;
2333. }
2334. }
2335. $array = &$uservar[0]["main"];
2336. ret:
2337. if (!$p) {
2338. if (isset($array[$name]))
2339. return true;
2340. }
2341. $subkeys = explode(".",$name);
2342. $penult = count($subkeys) - 1;
2343. for ($i = 0; $i < $penult; $i++) {
2344. $array = &$array[$subkeys[$i]];
2345. }
2346. if (isset($array[$subkeys[$penult]]))
2347. return true;
2348. return false;
2349. }
2350.
2351. function getuserelem($name, $elem) {
2352. return getuservar("{$name}.{$elem}");
2353. /*
2354. global $scope, $uservar, $sub;
2355.
2356. for ($i = $scope; $sub[$scope] == $sub[$i]; $i--)
2357. if (isset($uservar[$i][$sub[$scope]][$name]) || (is_array($uservar[$i][$sub[$scope]]) && array_key_exists($name, $uservar[$i][$sub[$scope]])))
2358. return $uservar[$i][$sub[$scope]][$name][$elem];
2359. if (isset($uservar[0][$sub[$scope]][$name]) || (is_array($uservar[0][$sub[$scope]]) && array_key_exists($name, $uservar[0][$sub[$scope]])))
2360. return $uservar[0][$sub[$scope]][$name][$elem];
2361. for ($i = $scope; $i > 0; $i--)
2362. if (isset($uservar[$i]["main"][$name]) || (is_array($uservar[$i]["main"]) && array_key_exists($name, $uservar[$i]["main"])))
2363. return $uservar[$i]["main"][$name][$elem];
2364. return $uservar[0]["main"][$name][$elem];;
2365. */
2366. }
2367.
2368. // Sets the most local variable of the name used to val
2369.
2370. /*
2371. function setuservar ($name, $val) {
2372. global $scope, $uservar, $sub;
2373.
2374. for ($i = $scope; $sub[$scope] == $sub[$i]; $i--)
2375. if (isset($uservar[$i][$sub[$scope]]) && array_key_exists($name, $uservar[$i][$sub[$scope]])) {
2376. $uservar[$i][$sub[$scope]][$name] = $val;
2377. return;
2378. }
2379. if (isset($uservar[0][$sub[$scope]]) && array_key_exists($name, $uservar[0][$sub[$scope]])) {
2380. $uservar[0][$sub[$scope]][$name] = $val;
2381. return;
2382. }
2383. for ($i = $scope; $i > 0; $i--)
2384. if (isset($uservar[$i]["main"]) && array_key_exists($name, $uservar[$i]["main"])) {
2385. $uservar[$i]["main"][$name] = $val;
2386. return;
2387. }
2388. $uservar[0]["main"][$name] = $val;
2389. return;
2390. }
2391. */
2392.
2393. // Recursively set variable
2394.
2395. function setuservar ($name, $val) {
2396. global $scope, $uservar, $sub;
2397.
2398. if (($p = strpos($name, ".")) !== false)
2399. $base = substr($name, 0, $p);
2400. else
2401. $base = $name;
2402. for ($i = $scope; ($i >= 0) && ($sub[$scope] == $sub[$i]); $i--)
2403. if (isset($uservar[$i][$sub[$scope]]) && array_key_exists($base, $uservar[$i][$sub[$scope]])) {
2404. recsetvar($uservar[$i][$sub[$scope]],$name,$val);
2405. return;
2406. }
2407. if (isset($uservar[0][$sub[$scope]]) && array_key_exists($base, $uservar[0][$sub[$scope]])) {
2408. recsetvar($uservar[0][$sub[$scope]],$name,$val);
2409. return;
2410. }
2411. for ($i = $scope; $i > 0; $i--)
2412. if (isset($uservar[$i]["main"]) && array_key_exists($base, $uservar[$i]["main"])) {
2413. recsetvar($uservar[$i]["main"],$name,$val);
2414. return;
2415. }
2416. recsetvar ($uservar[0]["main"],$name,$val);
2417. return;
2418. }
2419.
2420. function recsetvar (&$array, $key, $val) {
2421. if (strpos($key, ".")) {
2422. $subkeys = explode(".", $key);
2423. $penult = count($subkeys) - 1;
2424. for ($i = 0; $i < $penult; $i++) {
2425. $array = &$array[$subkeys[$i]];
2426. if (!is_array($array))
2427. $array = array();
2428. }
2429. $array[$subkeys[$penult]] = $val;
2430. }
2431. else {
2432. if (!is_array($array))
2433. $array = array();
2434. $array[$key] = $val;
2435. }
2436. }
2437.
2438. function setuserelem ($name, $elem, $val) {
2439. setuservar ("{$name}.{$elem}", $val);
2440. /*
2441. global $scope, $uservar, $sub;
2442. // echo "<P>Testing new code for setelem command to allow multiple dimensions. Problems may arise.</P>";
2443. for ($i = $scope; $sub[$scope] == $sub[$i]; $i--)
2444. if (isset($uservar[$i][$sub[$scope]]) && array_key_exists($name, $uservar[$i][$sub[$scope]])) {
2445. $uservar[$i][$sub[$scope]][$name][$elem] = $val;
2446. // recsetvar($uservar[$i][$sub[$scope]][$name],$elem,$val);
2447. return;
2448. }
2449. if (isset($uservar[0][$sub[$scope]]) && array_key_exists($name, $uservar[0][$sub[$scope]])) {
2450. $uservar[0][$sub[$scope]][$name][$elem] = $val;
2451. // recsetvar($uservar[0][$sub[$scope]][$name], $elem, $val);
2452. return;
2453. }
2454. for ($i = $scope; $i > 0; $i--)
2455. if (isset($uservar[$i]["main"]) && array_key_exists($name, $uservar[$i]["main"])) {
2456. $uservar[$i]["main"][$name][$elem] = $val;
2457. // recsetvar($uservar[$i]["main"][$name], $elem, $val);
2458. return;
2459. }
2460. $uservar[0]["main"][$name][$elem] = $val;
2461. // recsetvar($uservar[0]["main"][$name], $elem, $val);
2462. return;
2463. */
2464. }
2465.
2466. /*
2467. function pushuservar ($name, $val) {
2468. global $scope, $uservar, $sub;
2469. for ($i = $scope; $sub[$scope] == $sub[$i]; $i--) {
2470. if (isset($uservar[$i][$sub[$scope]]) && array_key_exists($name, $uservar[$i][$sub[$scope]])) {
2471. $uservar[$i][$sub[$scope]][$name][] = $val;
2472. return;
2473. }
2474. }
2475. if (isset($uservar[0][$sub[$scope]]) && array_key_exists($name, $uservar[0][$sub[$scope]])) {
2476. $uservar[0][$sub[$scope]][$name][] = $val;
2477. return;
2478. }
2479. for ($i = $scope; $i > 0; $i--) {
2480. if (isset($uservar[$i]["main"]) && array_key_exists($name, $uservar[$i]["main"])) {
2481. $uservar[$i]["main"][$name][] = $val;
2482. return;
2483. }
2484. }
2485. $uservar[0]["main"][$name][] = $val;
2486. return 0;
2487. }
2488.
2489. function decuservar ($name) {
2490. global $scope, $uservar, $sub;
2491.
2492. for ($i = $scope; $sub[$scope] == $sub[$i]; $i--)
2493. if (isset($uservar[$i][$sub[$scope]]) && array_key_exists($name, $uservar[$i][$sub[$scope]])) {
2494. $uservar[$i][$sub[$scope]][$name]--;
2495. return;
2496. }
2497. if (isset($uservar[0][$sub[$scope]]) && array_key_exists($name, $uservar[0][$sub[$scope]])) {
2498. $uservar[0][$sub[$scope]][$name]--;
2499. return;
2500. }
2501. for ($i = $scope; $i > 0; $i--)
2502. if (isset($uservar[$i]["main"]) && array_key_exists($name, $uservar[$i]["main"])) {
2503. $uservar[$i]["main"][$name]--;
2504. return;
2505. }
2506. $uservar[0]["main"][$name]--;
2507. return;
2508. }
2509.
2510. function incuservar ($name) {
2511. global $scope, $uservar, $sub;
2512.
2513. for ($i = $scope; $sub[$scope] == $sub[$i]; $i--)
2514. if (isset($uservar[$i][$sub[$scope]]) && array_key_exists($name, $uservar[$i][$sub[$scope]])) {
2515. $uservar[$i][$sub[$scope]][$name]++;
2516. return;
2517. }
2518. if (isset($uservar[0][$sub[$scope]]) && array_key_exists($name, $uservar[0][$sub[$scope]])) {
2519. $uservar[0][$sub[$scope]][$name]++;
2520. return;
2521. }
2522. for ($i = $scope; $i > 0; $i--)
2523. if (isset($uservar[$i]["main"]) && array_key_exists($name, $uservar[$i]["main"])) {
2524. $uservar[$i]["main"][$name]++;
2525. return;
2526. }
2527. $uservar[0]["main"][$name]++;
2528. return;
2529. }
2530. */
2531.
2532. function unsetlocals ($old, $new) {
2533. for ($i = $new+1; $i <= $old; $i++)
2534. unset ($GLOBALS["uservar"][$i]);
2535. }
2536.
2537. function unsetuservar ($name) {
2538. global $scope, $uservar, $sub;
2539.
2540. // When array element is specified by including periods in name,
2541. // get top level array for purposes of determining scope of variable.
2542. if ($p = strpos($name, "."))
2543. $top = substr($name, 0, $p);
2544. else
2545. $top = $name;
2546. // covers my variables, as well as global variables when lexical scope is main.
2547. for ($i = $scope; $sub[$scope] == $sub[$i]; $i--) {
2548. if (isset($uservar[$i][$sub[$scope]]) && (isset($uservar[$i][$sub[$scope]][$top]) || array_key_exists($top, $uservar[$i][$sub[$scope]]))) {
2549. $array = &$uservar[$i][$sub[$scope]];
2550. goto ret;
2551. }
2552. }
2553. // covers static variables
2554. if (isset($uservar[0][$sub[$scope]]) && (isset($uservar[0][$sub[$scope]][$top]) || array_key_exists($top, $uservar[0][$sub[$scope]]))) {
2555. $array = &$uservar[0][$sub[$scope]];
2556. goto ret;
2557. }
2558. // covers local variables, as well as global variables within a subroutine
2559. for ($i = $scope; $i >= 0; $i--) {
2560. if (isset($uservar[$i]["main"]) && (isset($uservar[$i]["main"][$top]) || array_key_exists($top, $uservar[$i]["main"]))) {
2561. $array = &$uservar[$i]["main"];
2562. goto ret;
2563. }
2564. }
2565. $array = &$uservar[0]["main"];
2566. ret:
2567. if (!$p) {
2568. if (isset($array[$name]))
2569. unset ($array[$name]);
2570. }
2571. $subkeys = explode(".",$name);
2572. $penult = count($subkeys) - 1;
2573. for ($i = 0; $i < $penult; $i++) {
2574. $array = &$array[$subkeys[$i]];
2575. }
2576. if (isset($array[$subkeys[$penult]]))
2577. unset ($array[$subkeys[$penult]]);
2578. }
2579.
2580. function alias ($s) {
2581. global $space, $pieces, $REALNAME, $dest, $origin, $lastmoved, $lastcaptured;
2582.
2583. if (isset($REALNAME[$s]))
2584. return $REALNAME[$s];
2585. elseif (isset($space[$s]) || isset($pieces[$s]))
2586. return $s;
2587. elseif ($s == "old")
2588. return $lastcaptured;
2589. elseif ($s == "moved")
2590. return $lastmoved;
2591. elseif ($s == "origin")
2592. return $origin;
2593. elseif ($s == "dest")
2594. return $dest;
2595. elseif (ctype_alnum($s))
2596. return false;
2597. else
2598. return $s;
2599. }
2600.
2601. function parsemove ($line, $requireMOVE = true) {
2602. global $space, $pieces, $dest;
2603.
2604. if ($requireMOVE && strncmp($line, "MOVE: ", 6)) {
2605. return parseline($line);
2606. }
2607. $args = array();
2608. $args[0] = "MOVE:";
2609. $move = trim(substr($line, 6));
2610. $len = strlen($move);
2611. for ($i = 0; $i < $len; $i++) {
2612. if (($move[$i] == "*") || ($move[$i] == "-") || ($move[$i] == " "))
2613. break;
2614. }
2615. $args[] = $i ? substr($move, 0, $i) : $move[0];
2616. $move = $i ? substr($move, $i) : substr($move, 1);
2617. $move = trim($move);
2618. $args[1] = isset($args[1]) ? alias($args[1]) : "";
2619. if ($args[1] == "-") {
2620. if (!isset($space[$move]))
2621. illegal ("When the hyphen begins a move, it must be followed by a recognized coordinate in move: {$move}.");
2622. $args[] = alias($move);
2623. return $args;
2624. }
2625. if (isset($pieces[$args[1]]) || ($args[1] == "@")) {
2626. if (($move[0] == "*") || ($move[0] == "-")) {
2627. $args[2] = $move[0];
2628. $args[3] = alias(trim(substr($move, 1)));
2629. return $args;
2630. }
2631. else {
2632. $coords = explode("-", $move);
2633. if (count($coords) != 2)
2634. illegal ("The move <B>$move</B> is not Well-formed.");
2635. $args[2] = alias(trim($coords[0]));
2636. $args[3] = "-";
2637. if (!empty($coords[1]))
2638. $args[4] = alias(trim($coords[1]));
2639. return $args;
2640. }
2641. }
2642. if (($args[1] != "") && isset($space[$args[1]])) {
2643. if (empty($move))
2644. error_log("line in parsemove: {$line}");
2645. $args[2] = $move[0] ?? NULL;
2646. $temp = ltrim(substr($move, 1));
2647. $args[3] = empty($temp) ? NULL : alias($temp);
2648. return $args;
2649. }
2650.
2651. return parseline($line);
2652. }
2653.
2654. /*
2655.
2656. // Turned out to be a dead end.
2657.
2658. function preprocessline ($line) {
2659. $max = strlen($line);
2660. for ($i = 0; $i < $max; $i++) {
2661. if (($line[$i] == "#") && (($i == 0) || ($line{$h=($i-1)} == " ") || ($line[$h] == "(") || ($line[$h] == "#"))) {
2662. $j = $i + 1;
2663. if (($line[$j] == "#") || ctype_digit($line[$j]))
2664. continue;
2665. for ($k = $j; ($k < $max) && ($line[$k] != " ") && ($line[$k] != ")"); $k++);
2666. if ($k == $j)
2667. continue;
2668. $varname = substr($line, $j, $k-$j);
2669. if (($temp = getuservar($varname)) !== NULL) {
2670. if ((array)$temp !== $temp) {
2671. $line = substr_replace($line, $temp, $i, $k-$i);
2672. $i--;
2673. }
2674. $max = strlen($line);
2675. }
2676. }
2677. }
2678. return $line;
2679. }
2680.
2681. */
2682.
2683. function parseline ($line) {
2684. global $origin, $dest, $lastcaptured, $lastmoved, $flag, $constants, $linenum;
2685.
2686. $max = strlen($line);
2687. $n = 0;
2688.
2689. for ($i = 0; $i < $max; $i++) {
2690. if ($line[$i] == '{') {
2691. $start = $i+1;
2692. $parcnt = 1;
2693. for ($j = $start; $j < $max; $j++) {
2694. if ($line[$j] == '{')
2695. $parcnt++;
2696. if ($line[$j] == '}')
2697. $parcnt--;
2698. if ($parcnt == 0)
2699. break;
2700. }
2701. $values = parseline(substr($line, $start, $j - $start));
2702. // $line = substr($line, 0, $i) . implode(".", $values) . substr($line, $j+1);
2703. $val = polish($values, $linenum);
2704. if (is_array($val))
2705. $val = array2string($val);
2706. $line = substr($line, 0, $i) . $val . substr($line, $j+1);
2707. $i--;
2708. $max = strlen($line); // Recalculate when $line changes
2709. }
2710. }
2711.
2712. $max = strlen($line);
2713. for ($i = 0; $i < $max; $i++) {
2714. if (ctype_space($line[$i]))
2715. continue;
2716. if ($line[$i] == '"') {
2717. $start = $i+1;
2718. for ($i = $start; $i < $max; $i++) {
2719. if ($line[$i] == '"')
2720. break;
2721. }
2722. $args[$n++] = substr($line, $start, $i - $start);
2723. }
2724. /* elseif ($line[$i] == "'") {
2725. $start = $i+1;
2726. for ($i = $start; $i < $max; $i++) {
2727. if ($line[$i] == "'")
2728. break;
2729. }
2730. $args[$n++] = substr($line, $start, $i - $start);
2731. }
2732. */
2733. elseif ($line[$i] == '(') {
2734. $start = $i+1;
2735. $parcnt = 1;
2736. for ($i = $start; $i < $max; $i++) {
2737. if ($line[$i] == '(')
2738. $parcnt++;
2739. if ($line[$i] == ')')
2740. $parcnt--;
2741. if ($parcnt == 0)
2742. break;
2743. }
2744. $args[$n++] = parseline(substr($line, $start, $i - $start));
2745. }
2746. else {
2747. $start = $i;
2748. for (; $i < $max; $i++) {
2749. if (ctype_space($line[$i]))
2750. break;
2751. }
2752. $args[$n] = substr($line, $start, $i - $start);
2753. if ($args[0] != "def")
2754. $args[$n] = evalvar($args[$n]);
2755. $n++;
2756. /*
2757. $args[$n] = substr($line, $start, $i - $start);
2758. if ($args[$n][0] == "?") {
2759. $name = substr($args[$n], 1);
2760. $args[$n] = isset($flag[$name]) ? $flag[$name] : false;
2761. }
2762. elseif (($args[$n][0] == "#") && ($args[$n] != "#")) {
2763. $name = substr($args[$n], 1);
2764. if (($temp = getuservar($name)) !== NULL)
2765. $args[$n] = $temp;
2766. elseif (isset($constants) && (is_array($constants) && (isset($constants[$name]) || array_key_exists($name, $constants))))
2767. $args[$n] = $constants[$name];
2768. }
2769. elseif (($args[$n][0] == "@") && ($args[$n] != "@")) {
2770. $name = substr($args[$n], 1);
2771. if (isset($constants) && (is_array($constants) && (isset($constants[$name]) || array_key_exists($name, $constants))))
2772. $args[$n] = $constants[$name];
2773. }
2774. elseif (($args[$n][0] == "$") && ($args[$n] != "$")) {
2775. $name = substr($args[$n], 1);
2776. if ($name == "old")
2777. $args[$n] = $lastcaptured;
2778. elseif ($name == "moved")
2779. $args[$n] = $lastmoved;
2780. elseif (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|showoutput|side|space|starpath|submit)$/", $name))
2781. $args[$n] = $GLOBALS[$name];
2782. elseif (preg_match("/^(capturedpieces|originalpieces|piecekeys|piecevals|prison|starpath)\./", $name))
2783. $args[$n] = getvar($GLOBALS, $name);
2784. }
2785. elseif ($args[$n] == "old")
2786. $args[$n] = $lastcaptured;
2787. elseif ($args[$n] == "moved")
2788. $args[$n] = $lastmoved;
2789. elseif ($args[$n] == "origin")
2790. $args[$n] = $origin;
2791. elseif ($args[$n] == "dest")
2792. $args[$n] = $dest;
2793. $n++;
2794. }
2795. */
2796. }
2797. }
2798. return empty($args) ? array() : $args;
2799. }
2800.
2801. function evalvar ($var) {
2802. global $constants, $flag;
2803.
2804. // As in Lisp, a car is the first element of a list,
2805. // and cdr is the rest of the list. So, the code below
2806. // treats the string $var as a list of characters.
2807. $car = $var[0];
2808. $cdr = substr($var, 1);
2809. if (is_numeric($cdr))
2810. return $var;
2811. if (empty($cdr))
2812. return $car;
2813. if (strpos("@#$?", $cdr[0]) !== false)
2814. $cdr = evalvar($cdr); // Recursion
2815. switch ($car) {
2816. case "?":
2817. return isset($flag[$cdr]) ? $flag[$cdr] : false;
2818. break;
2819. case "#":
2820. if (($temp = getuservar($cdr)) !== NULL)
2821. return $temp;
2822. elseif (isset($constants) && (is_array($constants) && (isset($constants[$cdr]) || array_key_exists($cdr, $constants))))
2823. return $constants[$cdr];
2824. else
2825. return $var;
2826. break;
2827. case "@":
2828. if (isset($constants) && (is_array($constants) && (isset($constants[$cdr]) || array_key_exists($cdr, $constants))))
2829. return $constants[$cdr];
2830. else
2831. return $var;
2832. break;
2833. case "$":
2834. if ($cdr == "old")
2835. return $GLOBALS["lastcaptured"];
2836. elseif ($cdr == "moved")
2837. return $GLOBALS["lastmoved"];
2838. elseif (preg_match("/^(answered|board|capturedpieces|code|columns|debug|dest|dir|firstplayer|flipped|groupsets|lastcaptured|lastmoved|legalmoves|map|maxmln|maxmove|maxmoves|meetingpoint|mln|movelist|movenum|moves|named|noerrorcheck|oldmovelist|omitmoves|orientation|origin|originalpieces|piecekeys|pieces|piecemoves|piecevals|players|prevcaptured|prevmoved|prevdest|prevorigin|prison|rank|showoutput|selset|sets|side|space|starpath|status|submit|useerid)$/", $cdr))
2839. return isset($GLOBALS[$cdr]) ? $GLOBALS[$cdr] : "";
2840. elseif (preg_match("/^(capturedpieces|flipped|originalpieces|piecekeys|pieces|piecevals|prison|sets|starpath)\./", $cdr)) {
2841. list($ra,$ky) = explode(".", $cdr);
2842. if (isset($GLOBALS[$ra][$ky]))
2843. return $GLOBALS[$ra][$ky];
2844. elseif (isset($GLOBALS[$ra]))
2845. return getvar($GLOBALS[$ra], $ky);
2846. else
2847. return array();
2848. }
2849. else
2850. return $var;
2851. break;
2852. default:
2853. switch ($var) {
2854. case "old":
2855. return $GLOBALS["lastcaptured"];
2856. break;
2857. case "moved":
2858. return $GLOBALS["lastmoved"];
2859. break;
2860. case "origin":
2861. case "dest":
2862. return $GLOBALS[$var];
2863. break;
2864. default:
2865. return $var;
2866. break;
2867. }
2868. }
2869. }
2870.
2871. function move ($s, $d) {
2872. global $origin, $dest, $lastmoved, $lastcaptured, $space, $linenum, $ALIAS, $move;
2873.
2874. // Check whether $s is a known coordinate
2875. if (!array_key_exists($s, $space))
2876. illegal ("The coordinate {$s} is unknown in move: {$move}.");
2877.
2878. // Check whether $s is a known coordinate
2879. if (!empty($d) && empty($space[$d]))
2880. illegal ("The coordinate {$d} is unknown in move {$move}.");
2881. if (!empty($s[0]) && $s[0] == "!" && !isset($ALIAS[$s]) && (empty($submit) || ($submit!="Compose")) && !empty($coded))
2882. badinput ("The exclamation mark at the beginning of coordinate $s in <B>{$move}</B> indicates you may not enter it as part of a move.");
2883. if (!empty($d[0]) && $d[0] == "!" && !isset($ALIAS[$d]) && (empty($submit) || ($submit!="Compose")) && !empty($coded))
2884. badinput ("The exclamation mark at the beginning of coordinate $d in <B>{$move}</B> indicates you may not enter it as part of a move.");
2885. $lastcaptured = $space[$d] ?? ""; // saves for use with automation
2886. $space[$d] = $lastmoved = $space[$s]; // saves for use with automation
2887. $origin = $s; // saves for use with automation
2888. $dest = $d;
2889. if ($s != $d)
2890. $space[$s] = "@";
2891. return;
2892. }
2893.
2894. function unlink_all ($c) {
2895. global $map;
2896. unset($map[$c]);
2897. foreach ($map as $frm => $ra)
2898. foreach ($ra as $d => $v)
2899. if ($v == $c)
2900. unset ($map[$frm][$d]);
2901. }
2902.
2903. ?>