1 !***************************************************************************
3 !** Reverzi: Yet Another Abuse of the Z-Machine
5 !** Reversi for the Z-Machine by John Menichelli
7 !***************************************************************************
9 !***************************************************************************
11 !** Reverzi can be inserted into other games, possibly as an Easter egg.
12 !** To start the game, call PlayRev();
14 !** I've given all of the identifiers in this code a "rev_" prefix, to
15 !** separate them from identifiers in the main game.
17 !** The code uses 8 global variables and 192 bytes of array space.
19 !** This source code is in the public domain.
21 !***************************************************************************
23 !***************************************************************************
25 !** The board in internally represented as follows:
28 !** 8 9 10 11 12 13 14 15
29 !** 16 17 18 19 20 21 22 23
30 !** 24 25 26 27 28 29 30 31
31 !** 32 33 34 35 36 37 38 39
32 !** 40 41 42 43 44 45 46 47
33 !** 48 49 50 51 52 53 54 55
34 !** 56 57 58 59 60 61 62 63
36 !***************************************************************************
38 !***************************************************************************
40 !** Arrays and Variables
42 !***************************************************************************
57 !***************************************************************************
61 !***************************************************************************
64 if (side == 1) return 2; return 1;
67 [ PosAdjoins pos side retval x y;
73 if (rev_b->(pos-1) == side) retval = 1;
77 if (rev_b->(pos+1) == side) retval = 1;
81 if (rev_b->(pos-8) == side) retval = 1;
85 if (rev_b->(pos+8) == side) retval = 1;
88 if ((x > 0) && (y > 0)) {
89 if (rev_b->(pos-9) == side) retval = 1;
92 if ((x < 7) && (y > 0)) {
93 if (rev_b->(pos-7) == side) retval = 1;
96 if ((x > 0) && (y < 7)) {
97 if (rev_b->(pos+7) == side) retval = 1;
100 if ((x < 7) && (y < 7)) {
101 if (rev_b->(pos+9) == side) retval = 1;
111 for(loop=0: loop<64: loop++)
113 if (rev_b->loop == 1) rev_black++;
114 if (rev_b->loop == 2) rev_white++;
150 if (rev_playside == 1)
157 for(i = 0: i < 64: i++)
160 rev_b->27 = 1; ! Black
161 rev_b->28 = 2; ! White
162 rev_b->35 = 2; ! White
163 rev_b->36 = 1; ! Black
169 @set_cursor -1 0; ! Turn off cursor
170 for (i = 1 : i <= 13 : ++i) {
175 print "R E V E R Z I";
186 print "[Spc] Enter move";
188 print "[C]hange sides";
203 [ LineCaptured side pos offset stop capture cont
204 count lpos loop other retval;
207 other = OtherSide(side);
211 for (lpos=pos+offset: (lpos >= 0 && lpos <= 63 && cont == 1): lpos=lpos+offset)
213 if (rev_b->lpos == 0) cont = 0;
215 if (rev_b->lpos == other) count++;
217 if (rev_b->lpos == side && cont ~= 0)
220 if (capture == 1 && count > 0)
222 for (loop = pos: loop ~= lpos: loop = loop + offset)
227 if (lpos == stop) cont = 0;
232 [ PiecesCaptured side pos capture x y captured minnw minne minsw minse;
253 if ((7 - x) < (7 - y))
260 captured = captured +
261 linecaptured (side, pos, -1, pos-x, capture);
266 captured = captured +
267 linecaptured (side, pos, 1, pos+7-x, capture);
272 captured = captured +
273 linecaptured(side, pos, -8, pos-(y*8), capture);
278 captured = captured +
279 linecaptured(side, pos, 8, pos+((7-y)*8), capture);
282 if ((x > 0) && (y > 0))
284 captured = captured +
285 linecaptured(side, pos, -9, pos-(minnw*9), capture);
288 if ((x > 0) && (y < 7))
290 captured = captured +
291 linecaptured(side, pos, 7, pos+(minsw*7), capture);
294 if ((x < 7) && (y > 0))
296 captured = captured +
297 linecaptured(side, pos, -7, pos-(minne*7), capture);
300 if ((x < 7) && (y < 7))
302 captured = captured +
303 linecaptured(side, pos, 9, pos+(minse*9), capture);
308 [ IsValid side pos other retval adjoins;
310 if (pos > -1 && pos < 64)
312 other = OtherSide(side);
315 adjoins = PosAdjoins(pos, other);
318 if (PiecesCaptured(side, pos, 0) > 0) retval = 1;
324 ! The "guts" of the program - selects moves for the computer.
325 ! Also checks to see if the player has any valid moves
327 [ GetMove side loop max move;
331 ! If a corner is empty, avoid adjacent squares unless there is no other
332 ! choice. Refer to diagram at the beginning of this file for details.
334 for (loop = 0: loop < 64: loop++)
339 if (IsValid(side, 1)) rev_d->1 = 1;
340 if (IsValid(side, 8)) rev_d->8 = 1;
341 if (IsValid(side, 9)) rev_d->9 = 1;
346 if (IsValid(side, 6)) rev_d->6 = 1;
347 if (IsValid(side, 14)) rev_d->14 = 1;
348 if (IsValid(side, 15)) rev_d->15 = 1;
353 if (IsValid(side, 48)) rev_d->48 = 1;
354 if (IsValid(side, 49)) rev_d->49 = 1;
355 if (IsValid(side, 57)) rev_d->57 = 1;
360 if (IsValid(side, 54)) rev_d->54 = 1;
361 if (IsValid(side, 55)) rev_d->55 = 1;
362 if (IsValid(side, 62)) rev_d->62 = 1;
365 ! Corner moves have priority
367 if(IsValid(side, 0)) move = 0;
369 if(IsValid(side, 7)) move = 7;
371 if(IsValid(side, 56)) move = 56;
373 if(IsValid(side, 63)) move = 63;
380 for (loop = 0: loop < 64: loop++)
382 if (IsValid(side, loop))
384 rev_c->loop = PiecesCaptured(side, loop, 0);
385 if (rev_c->loop > max)
390 if (rev_c->loop == max && random(10) > 5)
400 ! Now we have two arrays: rev_c contains the number of pieces that would
401 ! be captured if that move was played, while rev_d contains those moves
402 ! that should be avoided.
404 ! First, eliminate moves adjacent to the corners
406 for (loop = 0: loop < 64: loop++)
407 if (rev_d->loop == 1 && rev_c->loop > 0) rev_c->loop = 0;
409 ! Next, check to see if any valid moves are left
411 max = 0; ! Re-use max
412 for (loop = 0: loop < 64: loop++)
413 if (rev_c->loop > 0) max++;
415 ! If a not-adajcent-to-the-corner move exists, make it
420 for (loop = 0: loop < 64: loop++)
422 if (rev_c->loop > max)
427 if (rev_c->loop == max && random(10) > 5)
439 move = GetMove(rev_compside);
442 rev_b->move = rev_compside;
443 PiecesCaptured(rev_compside, move, 1);
450 if (rev_black + rev_white == 64) return;
454 print "[No allowable moves - skipping turn]";
461 [ GetPlayerMove pos valid k cur_x cur_y a move;
463 move = GetMove(rev_playside);
470 print "[You have no allowable moves - skipping turn]";
481 @set_cursor cur_y cur_x;
485 while (valid == 0 && rev_skipmove == 0)
498 if (k == 'c' || k == 'C')
500 rev_compside = rev_playside;
501 rev_playside = OtherSide(rev_playside);
503 if (rev_compside == 1) ! Computer = black
511 if (k == 'h' || k == 'H')
517 print "Black (X) moves first.^^
519 To make a legal move, your piece must be placed next to a
520 piece of the opposite color. The move is legal if
521 somewhere on the column/row/diagonal in the direction of
522 the opposite piece is one of your own pieces. All opposite
523 pieces in this direction are then captured by you and will
524 change to your color.^^
526 If your piece is placed next to several pieces of the
527 opposite color then you capture those pieces also.^^
529 If you have no possible moves you will be forced to pass
530 your turn. To manually pass simply press ~P~. Two
531 consecutive passes (one by you and one by the computer
534 If the computer cannot make a move it will display a
535 message. You continue to make your moves as normal.^^
537 The game is over when all fields are occupied or when no
538 side can make a legal move. The winner of the game is the
539 one with the most pieces when the game is over.^^";
542 print "Controls: Use the arrow keys to move the cursor (the ~?~)
543 around the board. When the ~?~ is where you want to place
544 your piece, press the space bar. You can also use the ~W~,
545 ~A~, ~S~ and ~Z~ keys to move the cursor.^^
547 Most of the menu choices should be self-explanatory. ~C~
548 allows you to change sides. Press ~P~ to pass, ~Q~ to
549 quit and ~H~ to diplay this information. ~M~ changes the
550 game's mode between fast and slow. In ~slow~ mode, the
551 game will pause after you make a move, so that you can
552 see the results of your move. In ~fast~ mode, the computer
553 will make it's move immediately after you make yours, then
554 display the results.^^";
560 if (k == 'p' || k == 'P')
568 if (k == 'm' || k == 'M')
584 if (k == 'q' || k == 'Q')
589 print "Play again? (y/n) ";
592 if (a == 'n' || a == 'N') {
606 if (k == 'a' || k == 'A' || k == 131)
613 if (cur_x < 5) cur_x = 19;
618 if (k == 's' || k == 'S' || k == 132)
625 if (cur_x > 19) cur_x = 5;
630 if (k == 'w' || k == 'W' || k == 129)
637 if (cur_y < 3) cur_y = 10;
642 if (k == 'z' || k == 'Z' || k == 0 || k == 130)
649 if (cur_y > 10) cur_y = 3;
652 @set_cursor cur_y cur_x;
655 if (rev_play == 0) return;
656 if (rev_skipmove == 1) return;
657 if (IsValid(rev_playside, pos) == 1)
664 print "[Invalid move]";
668 if (rev_skipmove == 0) {
669 rev_b->pos = rev_playside;
670 PiecesCaptured(rev_playside, pos, 1);
677 rev_mode = 1; ! Fast (default)
686 while ((rev_black+rev_white < 64) &&
693 if (rev_play == 0) break;
699 print "[Press any key to continue]";
708 if (rev_play == 0) break;
714 if (rev_passes == 2) {
715 print "Two passes - game ends.";
718 if (rev_black > rev_white)
720 if (rev_playside == 1)
726 if (rev_white > rev_black)
728 if (rev_playside == 1)
734 if (rev_white == rev_black)
738 print " Play again? (y/n) ";
741 if (a == 'y' || a == 'Y') {
748 @set_cursor -2 0; ! Turn cursor on again
758 print "Reverzi, Version 1.0^
759 Reverzi is a port of Reversi to the Z-Machine^
760 Ported by John Menichelli, December 1999^^";
762 print "The original source code was written by Dave Derrick for handheld
763 PCs. I downloaded it from the OrbWorks web site
764 (www.orbworks.com/ceres.html) and converted it to Inform. The
765 original source was written in PocketC and was very easy to convert
766 to Inform; the most difficult part of the conversion was creating
769 print "Special thanks to Andrew Plotkin - some of the code for this
770 game - along with the idea of abusing the Z-Machine - was borrowed
771 from his game ~Freefall.~^^";