home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 10
/
aminetcdnumber101996.iso
/
Aminet
/
comm
/
tcp
/
SlateGames.lha
/
reversi.rexx
< prev
Wrap
OS/2 REXX Batch file
|
1995-12-19
|
17KB
|
565 lines
/* Reversi for AmiSlate v1.0! */
/* This program should be run on a screen with at least 8 colors */
/* Get our host's name--always given as first argument when run from Amislate */
parse arg CommandPort ActiveString
if (length(CommandPort) == 0) then do
say ""
say "Usage: rx reversi.rexx <REXXPORTNAME>"
say " (REXXPORTNAME is usually AMISLATE)"
say ""
say "Or run from the Rexx menu within AmiSlate."
say ""
exit 0
end
/* Send all commands to this host */
address (CommandPort)
options results
lock ON
/* See if we're connected */
GetRemoteStateAttrs stem rstateattrs.
if (rstateattrs.mode > -1) then do
/* Parse command line argument to see if we've been activated by
a remote request or a local user */
check = upper(left(ActiveString,3))
if (upper(left(ActiveString,3)) ~= 'RE') then
GlobData.localplayer = 1
else
GlobData.localplayer = -1
end
else do
GlobData.localplayer = 0 /* i.e. we're both players */
end
if (GlobData.localplayer > 0) then do
call SetStatus("Requesting game from remote user... please wait.")
RemoteRexxCommand '"'||"Would you like to play Reversi?"||'"' "slaterexx:reversi.rexx"
waitevent stem handshake. MESSAGE
if (handshake.message == 0) then
do
call SetStatus("Reversi Game Refused")
lock off
exit 0
end
end
call SetStatus("Beginning Reversi...")
call ResetGameState
call SetGlobalData
if (GlobData.localplayer >= 0) then call DrawBoard
call NextTurn
call HandleEvents
lock OFF
exit 0
/* Global Data structure:
GlobData.Xspace.[step] (int) : horizontal pixel offsets to the center of each coord (0-16)
GlobData.XSize (int) : total width of each element
GlobData.Yspace.[step] (int) : vertical pixel offsets to the center of each coord (0-16)
GlobData.YSize (int) : total height of each element
(board state)
GlobData.board.[0..8].[0..8] : two-dimensional board array
(game state)
GlobData.turn : whose turn it is
GlobData.localplayer : which player is on local machine; 0 if both are
(color info)
GlobData.PieceColor.[playernum] : color of pieces for this player
*/
/* --------------------------------------------------------------- */
/* procedure HandleEvents */
/* --------------------------------------------------------------- */
HandleEvents: procedure expose GlobData. AMessage.
AMessage.TIMEOUT = 1 /* No events occurred in specified time period */
AMessage.MESSAGE = 2 /* Message recieved from remote Amiga */
AMessage.MOUSEDOWN = 4 /* Left mouse button press in drawing area */
AMessage.MOUSEUP = 8 /* Left mouse button release in drawing area */
AMessage.RESIZE = 16 /* Window was resized--time to redraw screen? */
AMessage.QUIT = 32 /* AmiSlate is shutting down */
AMessage.CONNECT = 64 /* Connection established */
AMessage.DISCONNECT = 128 /* Connection broken */
AMessage.TOOLSELECT = 256 /* Tool Selected */
AMessage.COLORSELECT = 512 /* Palette Color selected */
AMessage.KEYPRESS = 1024 /* Key pressed */
AMessage.MOUSEMOVE = 2048 /* Mouse was moved */
do while(1)
waitevent stem event. RESIZE MOUSEDOWN MOUSEUP TOOLSELECT MESSAGE DISCONNECT
if (event.type == AMessage.QUIT) then exit 0
if (event.type == AMessage.DISCONNECT) then do
call SetStatus("Connection broken--both players now local.")
GlobData.localplayer = 0
end
if (event.type == AMessage.MESSAGE) then do
parse var event.message rx ry
call PlaceMove((rx+0), (ry+0), 0) /* update our internals--the (+0) forces the vars back into numeric format */
call NextTurn
end
if (event.type == AMessage.RESIZE) then do
if ((GlobData.localplayer == GlobData.turn)|(GlobData.localplayer == 0)) then do
cturn = GlobData.turn
call SetGlobalData
call DrawBoard
call ColorBorder(GlobData.PieceColor.cturn)
call SetStatus("_LAST")
end
else do
/* else just update our internal vars */
call SetGlobalData
call SetStatus("_LAST")
end
end
if ((event.type == AMessage.MOUSEDOWN)&((GlobData.turn = GlobData.localplayer)|(GlobData.localplayer == 0))) then do
whatclickedx = ChopRange(trunc((event.x-GlobData.BORDER_H)/(GlobData.XSize)),0,7)
whatclickedy = ChopRange(trunc((event.y-GlobData.BORDER_V)/(GlobData.YSize)),0,7)
if (MoveOkay(whatclickedx, whatclickedy) == 1) then do
call PlaceMove(whatclickedx, whatclickedy, 1)
if (localplayer ~= 0) then call TransmitMove(whatclickedx, whatclickedy)
call NextTurn
end
end
end
return 1
/* --------------------------------------------------------------- */
/* procedure NextTurn */
/* */
/* --------------------------------------------------------------- */
NextTurn: procedure expose GlobData.
/* Swap turns */
GlobData.turn = -GlobData.turn
negone = -1
player.1 = "Player 1"
player.negone = "Player 2"
cturn = GlobData.turn
call SetStatus("Just a sec...")
if (GlobData.turn == GlobData.localplayer) then call ColorBorder(0)
/* Check to see if the new player has a move available */
if (CanMove() == 0) then do
call SetStatus("Sorry, " || player.cturn || ", but you must forfeit your turn.")
call Delay(100)
call NextTurn /* recursive! :) */
return 1
end
/* local game code */
if (Globdata.localplayer == 0) then do
call SetStatus(player.cturn || ", it's your turn to place a stone.")
call ColorBorder(GlobData.PieceColor.cturn)
return 1
end
/* two machine game code */
if (GlobData.turn == GlobData.localplayer) then do
call SetStatus(player.cturn || ", it's your turn to place a stone.")
call ColorBorder(GlobData.PieceColor.cturn)
end
else call SetStatus("Wait for other player to move.")
return 1
/* --------------------------------------------------------------- */
/* procedure ColorBorder */
/* */
/* Colors the border the color indicated in the param */
/* */
/* --------------------------------------------------------------- */
ColorBorder: procedure expose GlobData.
parse arg color
SetFPen color
/* Fill each side of the border with a square */
/* rely on AmiSlate's clipping to deal with extra material */
square 0 0 10000 (GlobData.YSpace.0)-1 FILL
square 0 0 (GlobData.XSpace.0)-1 10000 FILL
square (GlobData.XSpace.8)+1 0 10000 10000 FILL
square 0 (GlobData.YSpace.8)+1 10000 10000 FILL
return 1
/* --------------------------------------------------------------- */
/* procedure CanMove */
/* */
/* Returns 1 if there is a move available for the current player */
/* else 0 */
/* */
/* --------------------------------------------------------------- */
CanMove: procedure expose GlobData.
num1 = 0
num2 = 0
negone = -1
do i = 0 to 7
do j = 0 to 7
if (GlobData.board.i.j == 1) then
num1 = num1 + 1
else
if (GlobData.board.i.j == -1) then num2 = num2 + 1
if (MoveOkay(i,j) == 1) then return 1
end
end
/* If we got here there must not be an available move. */
/* If it's because the board is filled, then the game is over! */
if ((num1 + num2) == 64) then do
if (num1 > num2) then do
call ColorBorder(GlobData.PieceColor.1)
call GameWon("Player 1")
end
else if (num1 < num2) then do
call ColorBorder(GlobData.PieceColor.negone)
call GameWon("Player 2")
end
else do
call ColorBorder(0)
call GameWon("Tie")
end
end
/* If it's because one of the players has no pieces left, then
the game is also over! */
if (num1 == 0) then do
call ColorBorder(GlobData.PieceColor.negone)
call GameWon("Player 2")
end
if (num2 == 0) then do
call ColorBorder(GlobData.PieceColor.1)
call GameWon("Player 1")
end
/* otherwise there just wasn't a move available */
return 0
/* --------------------------------------------------------------- */
/* procedure GameWon */
/* */
/* displays a message saying who won, based on the arg, and exits. */
/* */
/* --------------------------------------------------------------- */
GameWon: procedure
parse arg winner
if (winner == "Tie") then winstring = "The game ends in a tie."
else winstring = winner || " has won the game!"
EasyRequest "Winner!" '"'||winstring||'"' "Okay"
call SetStatus("Game over. Rerun script to play again.")
lock off
exit 0
/* --------------------------------------------------------------- */
/* procedure PlaceMove */
/* */
/* does a move by placing a piece at (x,y) and turning over all */
/* appropriate pieces */
/* */
/* --------------------------------------------------------------- */
PlaceMove: procedure expose GlobData.
parse arg x,y, draw
GlobData.board.x.y = GlobData.turn
if (draw == 1) then call DrawPiece(x,y, draw)
if (BracketAvailable(x,y,-1,-1)) then call DrawBracket(x,y,-1,-1, draw)
if (BracketAvailable(x,y,0,-1)) then call DrawBracket(x,y,0,-1, draw)
if (BracketAvailable(x,y,1,-1)) then call DrawBracket(x,y,1,-1, draw)
if (BracketAvailable(x,y,1,0)) then call DrawBracket(x,y,1,0, draw)
if (BracketAvailable(x,y,1,1)) then call DrawBracket(x,y,1,1, draw)
if (BracketAvailable(x,y,0,1)) then call DrawBracket(x,y,0,1, draw)
if (BracketAvailable(x,y,-1,1)) then call DrawBracket(x,y,-1,1, draw)
if (BracketAvailable(x,y,-1,0)) then call DrawBracket(x,y,-1,0, draw)
return 1
/* --------------------------------------------------------------- */
/* procedure MoveOkay */
/* */
/* returns 1 if move is acceptable, or -1 if it is illegal. */
/* */
/* --------------------------------------------------------------- */
MoveOkay: procedure expose GlobData.
parse arg x, y
negone = -1
/* first rule: you can only place a stone where there isn't one */
if (GlobData.board.x.y ~= 0) then return 0
/* The only other rule: there must be a "bracket pair" in a direction */
/* Try north first */
if (BracketAvailable(x,y,0,-1) == 1) then return 1
if (BracketAvailable(x,y,0,1) == 1) then return 1
if (BracketAvailable(x,y,-1,0) == 1) then return 1
if (BracketAvailable(x,y,1,0) == 1) then return 1
if (BracketAvailable(x,y,-1,-1) == 1) then return 1
if (BracketAvailable(x,y,1,-1) == 1) then return 1
if (BracketAvailable(x,y,-1,1) == 1) then return 1
if (BracketAvailable(x,y,1,1) == 1) then return 1
/* No move available */
return 0
/* --------------------------------------------------------------- */
/* procedure BracketAvailable */
/* */
/* Searches for an "us-them[...-them]-us" pattern in the direction */
/* indicated by dx and dy. */
/* */
/* --------------------------------------------------------------- */
BracketAvailable: procedure expose GlobData.
parse arg x,y,dx,dy
/* default */
BFoundMiddle = 0
/* move off of the square-in-question... */
x = x + dx
y = y + dy
do while ((x>=0)&(y>=0)&(x<=7)&(y<=7))
/* We hit a blank--no end on our bracket */
if (GlobData.board.x.y == 0) then return 0
/* We hit our own piece--okay iff we saw theirs beforehand */
if (GlobData.board.x.y == GlobData.turn) then return BFoundMiddle
/* We hit their piece--make a note of it */
if (GlobData.board.x.y == -GlobData.turn) then BFoundMiddle = 1
/* advance to next square */
x = x + dx
y = y + dy
end
/* Nope, ran off board */
return 0
/* --------------------------------------------------------------- */
/* procedure DrawBracket */
/* */
/* Flips the counters for all of the other side's pieces in the */
/* given bracket. */
/* */
/* --------------------------------------------------------------- */
DrawBracket: procedure expose GlobData.
parse arg x,y,dx,dy,draw
/* move off of the square-in-question... */
x = x + dx
y = y + dy
do while ((x>=0)&(y>=0)&(x<=7)&(y<=7))
/* We hit our own piece--we're all done */
if (GlobData.board.x.y == GlobData.turn) then return 1
/* We hit their piece--flip it! */
if (GlobData.board.x.y == -GlobData.turn) then do
GlobData.board.x.y = GlobData.turn
if (draw == 1) then call DrawPiece(x,y,draw)
end
/* advance to next square */
x = x + dx
y = y + dy
end
/* Nope, ran off board */
return 0
/* --------------------------------------------------------------- */
/* procedure ResetGameState */
/* --------------------------------------------------------------- */
ResetGameState: procedure expose GlobData.
negone = -1;
GlobData.turn = -1;
/* first clear the board */
do i = 0 to 7
do j = 0 to 7
GlobData.board.i.j = 0
end
end
/* then add in initial pieces */
GlobData.board.3.3 = 1
GlobData.board.4.4 = 1
GlobData.board.4.3 = -1
GlobData.board.3.4 = -1
return 1
/* --------------------------------------------------------------- */
/* procedure SetGlobalData */
/* --------------------------------------------------------------- */
SetGlobalData: procedure expose GlobData.
negone = -1
/* constants */
GlobData.BORDER_H = 5
GlobData.BORDER_V = 10
/* Check to see whether we are connected */
GetWindowAttrs stem winattrs.
BoardWidth = winattrs.width - 58 - (GlobData.BORDER_H*2)
BoardHeight= winattrs.height - 55 - (GlobData.BORDER_V*2)
/* Set up offsets */
DO i=0 to 8
GlobData.Xspace.i = trunc(BoardWidth * i / 8) + GlobData.BORDER_H
GlobData.Yspace.i = trunc(BoardHeight * i / 8) + GlobData.BORDER_V
end
GlobData.XSize = trunc(BoardWidth / 8)
GlobData.YSize = trunc(BoardHeight / 8)
if (winattrs.depth < 2) then do
EasyRequest Reversi_Error '"'||"You need at least a 4-color screen to play Reversi!"||'"' '"'||"Abort Reversi"||'"'
call SetStatus("Reversi game exited.")
lock off
exit 0
end
GlobData.PieceColor.1 = 2
GlobData.PieceColor.negone = 3
return 1
/* --------------------------------------------------------------- */
/* procedure DrawBoard */
/* --------------------------------------------------------------- */
DrawBoard: procedure expose GlobData.
SetFColor 0 0 0 /* Get a black pen */
Clear
SetWindowTitle '"' || "Hang on, drawing the board..." || '"'
SetFPen 1
do i = 0 to 8
line GlobData.XSpace.i GlobData.YSpace.0 GlobData.XSpace.i GlobData.YSpace.8
line GlobData.XSpace.0 GlobData.YSpace.i GlobData.XSpace.8 GlobData.YSpace.i
end
do i = 0 to 7
do j = 0 to 7
if (GlobData.Board.i.j ~= 0) then call DrawPiece(i,j)
end
end
call SetStatus("_LAST")
return 1
/* Draws the piece listed at coords xc, yc */
DrawPiece: procedure expose GlobData.
parse arg xc, yc
piece = GlobData.board.xc.yc
if (piece == 0) then return 0
/* Draw the piece in the square on the LOWER RIGHT of this intersection */
cx = MidwayBetween(xc,xc+1,X)
cy = MidwayBetween(yc,yc+1,Y)
SetFPen GlobData.PieceColor.piece
circle cx cy trunc(GlobData.XSize/3) trunc(GlobData.YSize/3) FILL
SetFPen 1
circle cx cy trunc(GlobData.XSize/3) trunc(GlobData.YSize/3)
return 1
SetStatus: procedure
parse arg newstatus
if (newstatus == "_LAST") then do
SetWindowTitle '"' || getclip("PrevString") || '"'
end
else do
call setclip("PrevString",newstatus)
SetWindowTitle '"' || newstatus || '"'
end
return 1
/* Returns the point midway between two coords */
MidWayBetween: procedure expose GlobData.
parse arg left, right, XorY
if (XorY = X) then
return trunc((GlobData.XSpace.left + GlobData.XSpace.right)/2)
else
return trunc((GlobData.YSpace.left + GlobData.YSpace.right)/2)
ChopRange: procedure
parse arg myval, lo, hi
if (myval < lo) then return lo
if (myval > hi) then return hi
return myval
/* --------------------------------------------------------------- */
/* procedure CheckForWin */
/* --------------------------------------------------------------- */
CheckForWin: procedure expose GlobData.
winner = nobody
negone = -1
if (GlobData.exited.1 == 15) then winner = "Player 1"
else if (GlobData.exited.negone == 15) then winner = "Player 2"
/* nobody one yet */
if (winner == nobody) then return 1
EasyRequest "Winner!" '"'||winner||" has won the game!"||'"' "Okay"
call SetStatus("Game Over. Rerun the script to play again.")
lock off
exit
return 0
/* Transmit our move to our opponent */
TransmitMove: procedure
parse arg x, y
sstring = '"' || x || " " || y || '"'
sendmessage sstring
return 1