!***************************************************************************
!**
!** Reverzi: Yet Another Abuse of the Z-Machine
!**
!** Reversi for the Z-Machine by John Menichelli
!**
!***************************************************************************
!***************************************************************************
!**
!** Reverzi can be inserted into other games, possibly as an Easter egg.
!** To start the game, call PlayRev();
!**
!** I've given all of the identifiers in this code a "rev_" prefix, to
!** separate them from identifiers in the main game.
!**
!** The code uses 8 global variables and 192 bytes of array space.
!**
!** This source code is in the public domain.
!**
!***************************************************************************
Global rev_black;
Global rev_white;
Global rev_play;
Global rev_playside;
Global rev_compside;
Global rev_skipmove;
Global rev_mode;
Global rev_passes;
if (rev_b->0 == 0)
{
if (IsValid(side, 1)) rev_d->1 = 1;
if (IsValid(side, 8)) rev_d->8 = 1;
if (IsValid(side, 9)) rev_d->9 = 1;
}
if (rev_b->7 == 0)
{
if (IsValid(side, 6)) rev_d->6 = 1;
if (IsValid(side, 14)) rev_d->14 = 1;
if (IsValid(side, 15)) rev_d->15 = 1;
}
if (rev_b->56 == 0)
{
if (IsValid(side, 48)) rev_d->48 = 1;
if (IsValid(side, 49)) rev_d->49 = 1;
if (IsValid(side, 57)) rev_d->57 = 1;
}
if (rev_b->63 == 0)
{
if (IsValid(side, 54)) rev_d->54 = 1;
if (IsValid(side, 55)) rev_d->55 = 1;
if (IsValid(side, 62)) rev_d->62 = 1;
}
! Corner moves have priority
if(IsValid(side, 0)) move = 0;
if(IsValid(side, 7)) move = 7;
if(IsValid(side, 56)) move = 56;
if(IsValid(side, 63)) move = 63;
if (move > -1)
return move;
else
{
for (loop = 0: loop < 64: loop++)
{
if (IsValid(side, loop))
{
rev_c->loop = PiecesCaptured(side, loop, 0);
if (rev_c->loop > max)
{
max = rev_c->loop;
move = loop;
}
if (rev_c->loop == max && random(10) > 5)
{
max = rev_c->loop;
move = loop;
}
}
else
rev_c->loop = 0;
}
! Now we have two arrays: rev_c contains the number of pieces that would
! be captured if that move was played, while rev_d contains those moves
! that should be avoided.
! First, eliminate moves adjacent to the corners
for (loop = 0: loop < 64: loop++)
if (rev_d->loop == 1 && rev_c->loop > 0) rev_c->loop = 0;
! Next, check to see if any valid moves are left
max = 0; ! Re-use max
for (loop = 0: loop < 64: loop++)
if (rev_c->loop > 0) max++;
! If a not-adajcent-to-the-corner move exists, make it
if (max > 0)
{
max = 0;
for (loop = 0: loop < 64: loop++)
{
if (rev_c->loop > max)
{
max = rev_c->loop;
move = loop;
}
if (rev_c->loop == max && random(10) > 5)
{
max = rev_c->loop;
move = loop;
}
}
}
}
return move;
];
! Change sides
if (k == 'c' || k == 'C')
{
rev_compside = rev_playside;
rev_playside = OtherSide(rev_playside);
InitGame();
if (rev_compside == 1) ! Computer = black
{
GetCompMove();
DrawBoard();
}
}
! Help
if (k == 'h' || k == 'H')
{
@set_window 0;
print "Rules:^^";
print "Black (X) moves first.^^
To make a legal move, your piece must be placed next to a
piece of the opposite color. The move is legal if
somewhere on the column/row/diagonal in the direction of
the opposite piece is one of your own pieces. All opposite
pieces in this direction are then captured by you and will
change to your color.^^
If your piece is placed next to several pieces of the
opposite color then you capture those pieces also.^^
If you have no possible moves you will be forced to pass
your turn. To manually pass simply press ~P~. Two
consecutive passes (one by you and one by the computer
will end the game.^^
If the computer cannot make a move it will display a
message. You continue to make your moves as normal.^^
The game is over when all fields are occupied or when no
side can make a legal move. The winner of the game is the
one with the most pieces when the game is over.^^";
print "Controls: Use the arrow keys to move the cursor (the ~?~)
around the board. When the ~?~ is where you want to place
your piece, press the space bar. You can also use the ~W~,
~A~, ~S~ and ~Z~ keys to move the cursor.^^
Most of the menu choices should be self-explanatory. ~C~
allows you to change sides. Press ~P~ to pass, ~Q~ to
quit and ~H~ to diplay this information. ~M~ changes the
game's mode between fast and slow. In ~slow~ mode, the
game will pause after you make a move, so that you can
see the results of your move. In ~fast~ mode, the computer
will make it's move immediately after you make yours, then
display the results.^^";
@set_window 1;
}
! Pass
if (k == 'p' || k == 'P')
{
rev_passes++;
rev_skipmove = 1;
break;
}
! Mode change
if (k == 'm' || k == 'M')
{
if (rev_mode == 0)
rev_mode = 1;
else
rev_mode = 0;
if (rev_passes == 2) {
print "Two passes - game ends.";
jump PlayAgain; }
if (rev_black > rev_white)
{
if (rev_playside == 1)
print "You win.";
else
print "I win.";
}
if (rev_white > rev_black)
{
if (rev_playside == 1)
print "I win.";
else
print "You win.";
}
if (rev_white == rev_black)
print "Drawn game.";
PlayAgain;
print " Play again? (y/n) ";
@read_char 1 -> a;
if (a == 'y' || a == 'Y') {
@set_cursor 12 1;
spaces (0->33) - 1;
jump Start; }
else
break;
}
@set_cursor -2 0; ! Turn cursor on again
@set_cursor 1 1;
@split_window 0;
@erase_window $ffff;
];
[ Main ;
PlayRev();
print "Reverzi, Version 1.0^
Reverzi is a port of Reversi to the Z-Machine^
Ported by John Menichelli, December 1999^^";
print "The original source code was written by Dave Derrick for handheld
PCs. I downloaded it from the OrbWorks web site
(www.orbworks.com/ceres.html) and converted it to Inform. The
original source was written in PocketC and was very easy to convert
to Inform; the most difficult part of the conversion was creating
the UI. ^^";
print "Special thanks to Andrew Plotkin - some of the code for this
game - along with the idea of abusing the Z-Machine - was borrowed
from his game ~Freefall.~^^";
];