
/**
* PARCHEESI
*
* @version 1.0b1 * @author Jason Bloomberg
*
* Java code copyright (c) 1997 Jason Bloomberg
* Parcheesi brand game copyright (c) Milton Bradley, Inc.
*
* This Java code is emailware. You may read it, use it, learn from it,
* or modify it, as long as you send email to wizard@rhodes.com. Let me
* know what you think, good or bad!
*
* This applet was my first Java project. Version 1 (what you see here) was
* completed in October 1997. Version 2, if I have the time and inclination,
* will be the multiplayer version.
*
* Since this was my first Java project, you'll notice that the code has grown
* organically; early code is very amateurish, while I got the idea as I went.
*
* Why Parcheesi? Well, if you're familiar with The Rhodes Arcade, you know that
* I like programming games to learn new technologies. I wanted a game that lent
* itself to Java, that is, one that wouldn't be easy to program in JavaScript.
*
* I also wanted a game that would let me work on all the fun Java stuff -- creating
* classes, using threads, messing with the AWT, and then working with streams
* and networking when I get around to the multiplayer version. And then I wanted
* a game that nobody had programmed in Java, so Parcheesi it was!
*
* I tried to comment the code -- over 2500 lines of it -- so that a new Java
* programmer could follow it and learn from it. So have fun!
*
*****/
import java.awt.*;
import java.applet.*;
import java.awt.image.*;
import java.net.*;
import java.util.*;
import java.applet.AudioClip;
public class Parcheesi extends Applet implements Runnable
{
/***********
*
* This program is organized in the following manner:
*
* Parcheesi class
* Thread methods
* Computer moves
* Initialization methods
* Init painting methods
* Gameplay methods
* Static methods
* Event methods
* Variables
* Flasher class
* Pawn class
* Die class
*
* Because Parcheesi is an applet, program control begins with the init ()
* method. From there, it processes events.
*
************/
///////////////////////////// THREAD METHODS /////////////////////////
public void run ()
{
boolean noMoreDice = false;
// the following loop keeps running until the game stops, usually
// because the player reloads or leaves the game
while (runner != null)
{
// System.out.println("RUN: " + j);
if (!pauseThread & !playAgain)
{
// gc means garbage collection; since Java garbage collection
// runs as a low priority thread, I was running out of memory
// until I forced the system to collect garbage
System.gc ();
if (readyToStart)
readyToStart = false;
else
if (gameTimer == 0 || readyToForce)
forceMove ();
else
if (noMoreDice || turnIsOver)
turn ();
else
handlePlayerTurn ();
// the timer keeps track of quarter seconds, updating the
// clock every four "ticks".
try
{
runner.sleep (250);
}
catch (InterruptedException e)
{
System.out.println("InterruptedException 1");
}
if (timerTick == 3)
{
timerTick = 0;
gameTimer -= 1;
repaintClock ();
}
else
timerTick++;
noMoreDice = true;
for (int i = 0; i < 4; i++)
noMoreDice = noMoreDice && diceArray[i].getValue () == 0;
}
}
readyToStart = true; // shouldn't get here
}
public void start ()
{
if (runner == null && readyToStart)
{
System.out.println("Starting PARCHEESI!");
runner = new Thread (this);
runner.setPriority(Thread.MIN_PRIORITY);
runner.start ();
}
}
public void stop ()
{
if (runner != null)
{
System.out.println("Error: PARCHEESI stopped!");
runner.stop ();
runner = null;
}
}
public void handlePlayerTurn ()
// handles case where user deselects a die or a pawn
{
if (selectedPawn != null)
{
repaintBoard ();
if (deselectPawn)
{
// System.out.println("run: deselecting pawn");
selectedPawn.setVisible ();
selectedPawn = null;
deselectPawn = false;
repaintBoard ();
}
else
if (selectedPawn.isSelected ())
selectedPawn.changeVisibility ();
}
if (selectedDie != null)
{
repaintDice ();
if (deselectDie)
{
// System.out.println("run: deselecting die") ;
selectedDie.setVisible ();
selectedDie = null;
deselectDie = false;
repaintDice ();
}
else
if (selectedDie.isSelected ())
selectedDie.changeVisibility ();
}
}
public void turn ()
// key method that proceeds through each turn and on to the next one
{
clearBlockades ();
if (doubletCount == 0 && !newGame)
{
currentPlayer = (currentPlayer + 1) % 4;
repaintBigPawn ();
repaintMessage (colorName[currentPlayer] + "'s turn!");
}
if (newGame)
{
repaintBigPawn ();
repaintMessage (colorName[currentPlayer] + " goes first!");
System.out.println(colorName[currentPlayer] + " goes first!");
newGame = false;
}
turnIsOver = false;
for (int i = 0; i < 4; i++)
diceArray[i].clear ();
repaintDice ();
System.gc ();
System.out.println("-------- " + colorName[currentPlayer] + " --------");
if (switchPlayerFlag > -1)
{
switchPlayer (switchPlayerFlag);
switchPlayerFlag = -1;
}
startBlockades ();
rollDice ();
if (turnIsOver)
try
{
runner.sleep (1500);
}
catch (InterruptedException e)
{
System.out.println("InterruptedException 9a");
}
gameTimer = maxTime;
repaintClock ();
readyToForce = players[currentPlayer] == 1;
}
public void clearBlockades ()
// Rule: you can't advance a blockade to create a new one. Therefore, I
// have to keep track of every blockade every pawn of the current player
// is in during a turn so that they can't create a blockade with pawns
// that were already in a blockade this turn. This method and the next
// keep track of that.
{
for (int i = 0; i < 100; i++)
for (int j = 0; j < 2; j++)
if (gameBoard[i][j] != null &&
gameBoard[i][j].getColor () == currentPlayer &&
!gameBoard[i][j].isHome () ) // not home
gameBoard[i][j].clearBlockade ();
}
public void startBlockades ()
{
for (int i = 0; i < 100; i++)
for (int j = 0; j < 2; j++)
if (gameBoard[i][j] != null &&
gameBoard[i][j].getColor () == currentPlayer &&
!gameBoard[i][j].isHome () && // not home
gameBoard[i][1 - j] != null && // a pawn is next door
gameBoard[i][1 - j].getColor () == currentPlayer)
Pawn.setBlockades (gameBoard[i][j], gameBoard[i][1 - j]);
}
public void switchPlayer (int thisPlayer)
// handles case when player clicks on smiley/computer icon
{
players[thisPlayer] = 1 - players[thisPlayer];
selectedPlayer = thisPlayer;
repaintPlayer ();
}
////////////////////////// COMPUTER MOVES ///////////////////////////
// I placed computer moves by the thread methods, because they run on the
// thread.
public void forceMove ()
// This method handles the case when player clicks on "Done with turn" or
// allows timer to expire, as well as when it's the computer's turn. Keep
// in mind that the computer uses the same strategy in either case.
{
if (turnIsOver)
finishTurn ();
else
{
if (players[currentPlayer] == 0)
{
repaintMessage ("Computer finishes your move.");
System.out.println("Computer finishes your move.");
}
readyToForce = false;
if (turnIsOver)
finishTurn();
else
{
deselectAll ();
pauseThread = true;
while (computerMove ())
{}
try
{
runner.sleep (700);
}
catch (InterruptedException e)
{
System.out.println("InterruptedException 2");
}
deselectAll ();
pauseThread = false;
if (!playAgain)
turn ();
}
}
}
public void finishTurn ()
{
deselectAll ();
try
{
runner.sleep (700);
}
catch (InterruptedException e)
{
System.out.println("InterruptedException 3");
}
turn ();
}
public void deselectAll ()
{
if (selectedPawn != null)
{
selectedPawn.setVisible ();
selectedPawn.deselect ();
deselectPawn = true;
}
if (selectedDie != null)
{
selectedDie.setVisible ();
selectedDie.deselect ();
deselectDie = true;
}
}
public boolean computerMove ()
// This method is the key to the computer's strategy. It tries to move
// pawns in accordance with the order of calls you see here.
{
if (computerEnter ())
return true;
if (computerCapture ())
return true;
if (computerHome ())
return true;
if (turnIsOver)
return false;
if (computerBlock ())
return true;
if (computerSafety ())
return true;
if (computerOpenEnter ())
return true;
if (computerDontPass ())
return true;
if (computerMoveOffWhite ())
return true;
if (computerMoves ())
return true;
computerCurses ();
return false;
}
public boolean computerEnter ()
// You must enter pawns if you can, so that is top priority
{
int dieSum = diceArray[0].getValue () + diceArray[1].getValue ();
if (dieSum == 5 || diceArray[0].getValue () == 5 || diceArray[1].getValue () == 5)
{
for (int i = 0; i < 4; i++)
if (myPawns[currentPlayer][i].isAtStart () &&
myPawns[currentPlayer][i].canMove (1) != null)
{
System.out.println ("Entering a pawn");
repaintDice ();
useBothDice = dieSum == 5;
if (useBothDice)
selectedDie = diceArray[0];
else
for (int j = 0; j < 4; j++)
if (diceArray[j].getValue () == 5)
selectedDie = diceArray[j];
movePawn (myPawns[currentPlayer][i], 1);
if (players[currentPlayer] == 1)
chat(currentPlayer, "Yes!!");
return true;
}
}
return false;
}
public boolean computerCapture ()
// Next, the computer tries to capture pawns
{
int thisValue = 0;
for (int i = 0; i < 4; i++) // pawns
for (int j = 0; j < 4; j++) // dice
if (diceArray[j].getValue () > 0 && // for a given die roll
!myPawns[currentPlayer][i].isAtStart () ) // not at Start
{
thisValue = adjustValue (diceArray[j].getValue ());
Pawn neighbor = myPawns[currentPlayer][i].canMove (thisValue);
if (neighbor != null)
if (neighbor.getColor () != currentPlayer)
{
repaintDice ();
System.out.println ("Capturing!");
selectedDie = diceArray[j];
movePawn (myPawns[currentPlayer][i], thisValue);
if (players[currentPlayer] == 1)
chat (currentPlayer, "Gotcha! Ha! Ha! Ha!");
return true;
}
}
return false;
}
public boolean computerHome ()
// Third, the computer tries to move a pawn Home
{
int thisValue = 0;
for (int i = 0; i < 4; i++) // pawns
for (int j = 0; j < 4; j++) // dice
if (diceArray[j].getValue () > 0) // for a given die roll
{
thisValue = adjustValue (diceArray[j].getValue ());
Pawn neighbor = myPawns[currentPlayer][i].canMove (thisValue);
if (neighbor != null &&
myPawns[currentPlayer][i].getPathPosition () + thisValue == 72)
{
repaintDice ();
System.out.println ("Going home!");
selectedDie = diceArray[j];
movePawn (myPawns[currentPlayer][i], thisValue);
if (players[currentPlayer] == 1)
chat (currentPlayer, "What a relief!");
return true;
}
}
return false;
}
public boolean computerBlock ()
// Next, computer tries to form a blockade
{
int thisValue = 0;
for (int i = 0; i < 4; i++) // pawns
for (int j = 0; j < 4; j++) // dice
if (diceArray[j].getValue () > 0 && // for a given die roll
!myPawns[currentPlayer][i].isAtStart () ) // not at Start
{
thisValue = adjustValue (diceArray[j].getValue ());
Pawn neighbor = myPawns[currentPlayer][i].canMove (thisValue);
if (neighbor != null)
if (neighbor != myPawns[currentPlayer][i] && neighbor.getColor () == currentPlayer)
{
repaintDice ();
System.out.println ("Creating a block.");
selectedDie = diceArray[j];
movePawn (myPawns[currentPlayer][i], thisValue);
if (players[currentPlayer] == 1)
chat (currentPlayer, "Take that!");
return true;
}
}
return false;
}
public boolean computerSafety ()
// Next, the computer tries to move a pawn to a safety square
{
int thisValue = 0;
for (int i = 0; i < 4; i++) // pawns
for (int j = 0; j < 4; j++) // dice
if (diceArray[j].getValue () > 0 && // for a given die roll
!myPawns[currentPlayer][i].isAtStart () ) // not at Start
{
thisValue = adjustValue (diceArray[j].getValue ());
Pawn neighbor = myPawns[currentPlayer][i].canMove (thisValue);
if (neighbor != null)
{
int newPath = myPawns[currentPlayer][i].getPathPosition () + thisValue;
int newPosition = Pawn.getPawnPath (currentPlayer, newPath);
if (newPath > 64 || isSafetySquare (Pawn.getPawnPath (currentPlayer, newPath) ))
{
for (int k = 0; k < 4; k++)
if (k != currentPlayer && isEnter (k, newPosition) && !allPawnsEntered (k) )
return false; // space is enter square of color with pawns in Start
repaintDice ();
System.out.println ("Entering safety square");
selectedDie = diceArray[j];
movePawn (myPawns[currentPlayer][i], thisValue);
if (players[currentPlayer] == 1)
chat (currentPlayer, "Ahhh.");
return true;
}
}
}
return false;
}
public boolean computerOpenEnter ()
// If there are still pawns to be entered, it's important not to block
// your own enter space!
{
int thisValue = 0;
for (int i = 0; i < 4; i++) // pawns
for (int j = 0; j < 4; j++) // dice
if (diceArray[j].getValue () > 0 && // for a given die roll
!myPawns[currentPlayer][i].isAtStart () ) // not at Start
{
thisValue = adjustValue (diceArray[j].getValue ());
Pawn thisPawn = myPawns[currentPlayer][i];
Pawn neighbor = thisPawn.canMove (thisValue);
if (neighbor != null)
if (thisPawn.getPathPosition () == 1 && // in Enter space
!allPawnsEntered (currentPlayer) && // still a pawn in Start
gameBoard[thisPawn.getPosition ()][1 - thisPawn.getSpace ()] != null)
// currently has a neighbor
{
repaintDice ();
System.out.println ("Moving off enter");
selectedDie = diceArray[j];
movePawn (thisPawn, thisValue);
return true;
}
}
return false;
}
public boolean computerDontPass ()
// I didn't want the computer to be terribly smart, but I wanted it to
// play a pretty good game. So I figured if it could move a pawn without
// passing an opponent's pawn, that pawn would be less likely to be
// captured. Works pretty well!
{
int thisValue = 0;
for (int i = 0; i < 4; i++) // pawns
for (int j = 0; j < 4; j++) // dice
if (diceArray[j].getValue () > 0 && // for a given die roll
!myPawns[currentPlayer][i].isAtStart () ) // not at Start
{
thisValue = adjustValue (diceArray[j].getValue ());
Pawn neighbor = myPawns[currentPlayer][i].canMove (thisValue);
if (neighbor != null)
if (myPawns[currentPlayer][i].wontPass (thisValue) )
{
repaintDice ();
System.out.println ("Moving without passing opponent's pawn");
selectedDie = diceArray[j];
movePawn (myPawns[currentPlayer][i], thisValue);
return true;
}
}
return false;
}
public boolean computerMoveOffWhite ()
// If all else fails, it's better not to move off of a safety square
{
int thisValue = 0;
for (int i = 0; i < 4; i++) // pawns
for (int j = 0; j < 4; j++) // dice
if (diceArray[j].getValue () > 0 && // for a given die roll
!myPawns[currentPlayer][i].isAtStart () ) // not at Start
{
thisValue = adjustValue (diceArray[j].getValue ());
Pawn thisPawn = myPawns[currentPlayer][i];
Pawn neighbor = thisPawn.canMove (thisValue);
if (neighbor != null && !isSafetySquare (thisPawn.getPosition () ))
if (neighbor == thisPawn || neighbor.getColor () != thisPawn.getColor () )
{
repaintDice ();
System.out.println ("Moving off white square, passing opponent's pawn");
selectedDie = diceArray[j];
movePawn (thisPawn, thisValue);
return true;
}
}
return false;
}
public boolean computerMoves ()
// No good moves left, so it moves what it can
{
int thisValue = 0;
for (int i = 0; i < 4; i++) // pawns
for (int j = 0; j < 4; j++) // dice
if (diceArray[j].getValue () > 0 && // for a given die roll
!myPawns[currentPlayer][i].isAtStart () ) // not at Start
{
thisValue = adjustValue (diceArray[j].getValue ());
Pawn neighbor = myPawns[currentPlayer][i].canMove (thisValue);
if (neighbor != null)
{
repaintDice ();
System.out.println ("Passing opponent's pawn");
selectedDie = diceArray[j];
movePawn (myPawns[currentPlayer][i], thisValue);
return true;
}
}
return false;
}
public void computerCurses ()
// Curses! There are dice that cannot be used!
{
for (int i = 0; i < 4; i++)
if (diceArray[i].getValue () > 0)
{
System.out.println ("Wasted dice!");
if (players[currentPlayer] == 1)
chat (currentPlayer, "Curses!");
break;
}
}
///////////////////////////// INITIALIZATION METHODS /////////////////////////
public void init()
// Game begins here! Start by drawing the screen.
{
setBackground (Color.white);
resize (bgW, bgH);
initGraphics ();
chatField = new TextField (24);
sendButton = new Button ("Start");
chatArea = new TextArea (6, 32);
doneButton = new Button ("Done with turn");
northPanel = new Panel ();
northPanel.setLayout (new FlowLayout(FlowLayout.CENTER));
northPanel.add (doneButton);
messagePanel = new Panel();
messagePanel.setLayout (new FlowLayout(FlowLayout.CENTER));
messagePanel.add (chatField);
messagePanel.add (sendButton);
cornerPanel = new Panel();
cornerPanel.setLayout(new BorderLayout());
cornerPanel.add ("North", northPanel);
cornerPanel.add ("Center", chatArea);
cornerPanel.add ("South", messagePanel);
blankPanel = new Panel ();
GridBagLayout gbl = new GridBagLayout();
setLayout (gbl);
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.NONE;
gbc.weightx = 100;
gbc.weighty = 100;
gbc.gridx = 1;
gbc.gridy = 1;
gbc.gridwidth = 1;
gbc.gridheight = 1;
gbc.anchor = GridBagConstraints.SOUTHEAST;
gbl.setConstraints (cornerPanel, gbc);
add (cornerPanel);
getMedia();
initGame ();
}
public void initGraphics ()
// How to you create an applet that updates different parts of the screen
// at different times -- efficiently? Maybe you need multiple graphics
// contexts!
{
bgImage = createImage (bgW, bgH);
bgG = bgImage.getGraphics ();
boardImage = createImage (boardW, boardH);
boardG = boardImage.getGraphics ();
diceImage = createImage (diceW, diceH);
diceG = diceImage.getGraphics ();
clockImage = createImage (clockW, clockH);
clockG = clockImage.getGraphics ();
messageImage = createImage (messageW, messageH);
messageG = messageImage.getGraphics ();
playerImage = createImage (playerW, playerH);
playerG = playerImage.getGraphics ();
activeImage = createImage (activeW, activeH);
activeG = activeImage.getGraphics ();
}
public void initGame()
{
for (int i = 0; i < 4; i++)
diceArray[i] = new Die (i, 0);
chatMessage = "";
chatText = "You!";
systemMessage = "Enter your name and click \"Start\" to begin!";
currentPlayer = (int) (Math.random() * 4);
for (int i = 0; i < 104; i++)
for (int j = 0; j < 4; j++)
p[i][j] = new Point (0, 0);
initBoard ();
// testPawns (); // testing only
initPawns ();
initPaint ();
quickPaint ();
gameTimer = maxTime;
repaintInit ();
for (int pawn0 = 0; pawn0 < 4; pawn0++)
for (int die0 = 0; die0 < 2; die0++)
for (int pawn1 = 0; pawn1 < 4; pawn1++)
for (int die1 = 0; die1 < 2; die1++)
for (int pawn2 = 0; pawn2 < 4; pawn2++)
for (int die2 = 0; die2 < 2; die2++)
for (int pawn3 = 0; pawn3 < 4; pawn3++)
for (int die3 = 0; die3 < 2; die3++)
moveArray[pawn0][die0][pawn1][die1][pawn2][die2][pawn3][die3] = false;
}
public void initAgain()
// the initialization that needs to be done when a game is finished
// and the player wants to play again
{
currentPlayer = (int) (Math.random() * 4);
gameTimer = maxTime;
timerTick = 3;
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
myPawns[i][j] = null;
for (int i = 0; i < 104; i++)
for (int j = 0; j < 4; j++)
gameBoard[i][j] = null;
initPawns ();
repaintInit ();
}
public void testPawns ()
// this method is only called when debugging -- it allows me
// to place the pawns anywhere I want. Essential for testing the
// end of the game!
{
// red
gameBoard[70][0] = new Pawn (0, 70, 0);
myPawns[0][0] = gameBoard[70][0];
gameBoard[72][1] = new Pawn (0, 72, 1);
myPawns[0][1] = gameBoard[72][1];
gameBoard[71][0] = new Pawn (0, 71, 0);
myPawns[0][2] = gameBoard[71][0];
gameBoard[73][1] = new Pawn (0, 73, 1);
myPawns[0][3] = gameBoard[73][1];
// green
gameBoard[78][0] = new Pawn (1, 78, 0);
myPawns[1][0] = gameBoard[78][0];
gameBoard[80][1] = new Pawn (1, 80, 1);
myPawns[1][1] = gameBoard[80][1];
gameBoard[79][0] = new Pawn (1, 79, 0);
myPawns[1][2] = gameBoard[79][0];
gameBoard[81][1] = new Pawn (1, 81, 1);
myPawns[1][3] = gameBoard[81][1];
// yellow
gameBoard[87][0] = new Pawn (2, 87, 0);
myPawns[2][0] = gameBoard[87][0];
gameBoard[89][1] = new Pawn (2, 89, 1);
myPawns[2][1] = gameBoard[89][1];
gameBoard[88][0] = new Pawn (2, 88, 0);
myPawns[2][2] = gameBoard[88][0];
gameBoard[90][1] = new Pawn (2, 90, 1);
myPawns[2][3] = gameBoard[90][1];
// blue
gameBoard[95][0] = new Pawn (3, 95, 0);
myPawns[3][0] = gameBoard[95][0];
gameBoard[97][1] = new Pawn (3, 97, 1);
myPawns[3][1] = gameBoard[97][1];
gameBoard[96][0] = new Pawn (3, 96, 0);
myPawns[3][2] = gameBoard[96][0];
gameBoard[98][1] = new Pawn (3, 98, 1);
myPawns[3][3] = gameBoard[98][1];
}
public void initPawns ()
// each pawn is kept in two places at all times: on the gameboard,
// and in the myPawns array. This allows me to index over the board
// or over every one of a player's pawns as needed. Since pawns
// are objects, the SAME pawn can be in both arrays! Remember, Java
// objects retain the best features of pointers.
{
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
myPawns[i][j] = null;
for (int i = 0; i < 104; i++)
for (int j = 0; j < 4; j++)
gameBoard[i][j] = null;
for (int i = 0; i < 4; i++) // color
for (int j = 0; j < 4; j++) // space
{
gameBoard[i + 100][j] = new Pawn (i, i + 100, j);
myPawns[i][j] = gameBoard[i + 100][j];
}
}
public void getMedia ()
// gets the gifs and the sound
{
MediaTracker tracker;
tracker = new MediaTracker (this);
tick = getAudioClip (getCodeBase(), "tick.au");
startcircle = getImage(getCodeBase(), "circle.gif");
tracker.addImage (startcircle, 0);
try
{
tracker.waitForID (0);
}
catch (InterruptedException e)
{
System.out.println("InterruptedException 4");
}
for (int i = 0; i < 9; i++)
{
diceImages [i] = getImage (getCodeBase(), "die" + i + ".gif");
tracker.addImage (diceImages [i], 1 + i);
try
{
tracker.waitForID (1 + i);
}
catch (InterruptedException e)
{
System.out.println("InterruptedException 5");
}
}
for (int i = 0; i < 4; i++)
{
pawnImages [i][0] = getImage (getCodeBase(), "pawn" + i + ".gif");
tracker.addImage (pawnImages [i][0], 10 + i);
try
{
tracker.waitForID (10 + i);
}
catch (InterruptedException e)
{
System.out.println("InterruptedException 6");
}
pawnImages [i][1] = getImage (getCodeBase(), "pawnm" + i + ".gif");
tracker.addImage (pawnImages [i][1], 10 + i);
try
{
tracker.waitForID (10 + i);
}
catch (InterruptedException e)
{
System.out.println("InterruptedException 6a");
}
pawnImages [i][2] = getImage (getCodeBase(), "pawnl" + i + ".gif");
tracker.addImage (pawnImages [i][2], 10 + i);
try
{
tracker.waitForID (10 + i);
}
catch (InterruptedException e)
{
System.out.println("InterruptedException 6b");
}
}
playerIcon[1] = getImage(getCodeBase(), "computer.gif");
tracker.addImage (playerIcon[1], 14);
try
{
tracker.waitForID (14);
}
catch (InterruptedException e)
{
System.out.println("InterruptedException 7");
}
playerIcon[0] = getImage(getCodeBase(), "face.gif");
tracker.addImage (playerIcon[0], 15);
try
{
tracker.waitForID (15);
}
catch (InterruptedException e)
{
System.out.println("InterruptedException 8");
}
}
public void initBoard ()
// This was a fun one to write. There are 104 places pawns can
// be on the board (allowing for separate Home spaces for each
// player). How does it know where they are on the board, and
// what order they are in? Thank god for the Point object!
{
for (int i = 4; i <= 11; i++)
p[i][0].x = 174;
for (int i = 47; i <= 54; i++)
p[i][0].x = 174;
for (int i = 13; i <= 20; i++)
p[i][0].x = 108;
for (int i = 38; i <= 45; i++)
p[i][0].x = 108;
p[12][0].x = 141;
p[46][0].x = 141;
for (int i = 76; i <= 82; i++)
p[i][0].x = 141;
for (int i = 92; i <= 98; i++)
p[i][0].x = 141;
for (int i = 0; i <= 3; i++)
p[i][0].y = 108;
for (int i = 21; i <= 28; i++)
p[i][0].y = 108;
for (int i = 64; i <= 67; i++)
p[i][0].y = 108;
for (int i = 30; i <= 37; i++)
p[i][0].y = 174;
for (int i = 55; i <= 62; i++)
p[i][0].y = 174;
p[29][0].y = 141;
p[63][0].y = 141;
for (int i = 68; i <= 79; i++)
p[i][0].y = 141;
for (int i = 84; i <= 90; i++)
p[i][0].y = 141;
for (int i = 4; i <= 10; i++)
p[i][0].y = 5 + (11 - i) * 13;
for (int i = 14; i <= 20; i++)
p[i][0].y = 5 + (i - 13) * 13;
for (int i = 11; i <= 13; i++)
p[i][0].y = 5;
for (int i = 4; i <= 10; i++)
p[i][0].y = 5 + (11 - i) * 13;
for (int i = 92; i <= 98; i++)
p[i][0].y = 5 + (i - 91) * 13;
for (int i = 48; i <= 54; i++)
p[i][0].y = 201 + (54 - i) * 13;
for (int i = 38; i <= 44; i++)
p[i][0].y = 201 + (i - 38) * 13;
for (int i = 45; i <= 47; i++)
p[i][0].y = 292;
for (int i = 76; i <= 82; i++)
p[i][0].y = 201 + (82 - i) * 13;
for (int i = 0; i <= 3; i++)
p[i][0].x = 201 + (3 - i) * 13;
for (int i = 65; i <= 67; i++)
p[i][0].x = 253 + (67 - i) * 13;
for (int i = 55; i <= 61; i++)
p[i][0].x = 201 + (i - 55) * 13;
for (int i = 62; i <= 64; i++)
p[i][0].x = 292;
for (int i = 68; i <= 74; i++)
p[i][0].x = 201 + (74 - i) * 13;
for (int i = 21; i <= 27; i++)
p[i][0].x = 5 + (28 - i) * 13;
for (int i = 31; i <= 37; i++)
p[i][0].x = 5 + (i - 30) * 13;
for (int i = 28; i <= 30; i++)
p[i][0].x = 5;
for (int i = 84; i <= 90; i++)
p[i][0].x = 5 + (i - 83) * 13;
p[75][0].x = 115; p[75][0].y = 115;
p[83][0].x = 115; p[83][0].y = 135;
p[91][0].x = 115; p[91][0].y = 155;
p[99][0].x = 115; p[99][0].y = 175;
p[100][0].x = 235; p[100][0].y = 49;
p[101][0].x = 235; p[101][0].y = 249;
p[102][0].x = 35; p[102][0].y = 249;
p[103][0].x = 35; p[103][0].y = 49;
for (int i = 0; i <= 3; i++)
incY (i);
for (int i = 21; i <= 37; i++)
incY (i);
for (int i = 55; i <= 74; i++)
incY (i);
for (int i = 84; i <= 90; i++)
incY (i);
for (int i = 4; i <= 20; i++)
incX (i);
for (int i = 38; i <= 54; i++)
incX (i);
for (int i = 76; i <= 82; i++)
incX (i);
for (int i = 92; i <= 98; i++)
incX (i);
incX (75);
incX (83);
incX (91);
incX (99);
for (int i = 100; i < 104; i++)
incX (i);
}
public void incY (int i)
{
for (int j = 1; j < 4; j++)
{
p[i][j].x = p[i][0].x;
p[i][j].y = p[i][0].y + j * 15;
}
}
public void incX (int i)
{
for (int j = 1; j < 4; j++)
{
p[i][j].y = p[i][0].y;
p[i][j].x = p[i][0].x + j * 15;
}
}
///////////////////////// INIT PAINTING METHODS //////////////////////////
// I grouped all the methods that act on graphics contexts together. Keep
// in mind that different methods work on different graphics contexts!
public void initPaint ()
{
drawCircles (boardG);
drawBoard (boardG);
boardG.dispose ();
}
public void drawCircles (Graphics g)
{
g.setColor (Color.white);
g.fillRect (0, 0, 305, 305);
g.drawImage (startcircle, 6, 6, this);
g.drawImage (startcircle, 205, 6, this);
g.drawImage (startcircle, 6, 205, this);
g.drawImage (startcircle, 205, 205, this);
}
public void drawBoard (Graphics g)
// Yes, I draw all the rectangles on the board one by one!
{
g.setColor (Color.black);
g.draw3DRect (5, 5, 300, 300, true);
g.setColor (Color.red);
g.fillRect (138, 18, 33, 7 * 13);
g.fillRect (138, 201, 33, 7 * 13);
g.fillRect (18, 138, 7 * 13, 33);
g.fillRect (201, 138, 7 * 13, 33);
g.setColor (lightBlue);
g.fillRect (138, 5, 33, 13);
g.fillRect (105, 5 + 4 * 13, 33, 13);
g.fillRect (171, 5 + 4 * 13, 33, 13);
g.fillRect (138, 292, 33, 13);
g.fillRect (105, 305 - 5 * 13, 33, 13);
g.fillRect (171, 305 - 5 * 13, 33, 13);
g.fillRect (5, 138, 13, 33);
g.fillRect (5 + 4 * 13, 105, 13, 33);
g.fillRect (5 + 4 * 13, 171, 13, 33);
g.fillRect (292, 138, 13, 33);
g.fillRect (305 - 5 * 13, 105, 13, 33);
g.fillRect (305 - 5 * 13, 171, 13, 33);
g.setColor(medBlue);
g.fillOval(115, 5 + 4 * 13, 13, 13);
Polygon bluePoly = new Polygon();
bluePoly.addPoint(5 + 100 + 33 + 10, 5 + 7 * 13);
bluePoly.addPoint(5 + 100 + 33 + 20, 5 + 7 * 13);
bluePoly.addPoint(5 + 100 + 33 + 15, 5 + 8 * 13);
bluePoly.addPoint(5 + 100 + 33 + 10, 5 + 7 * 13);
g.fillPolygon(bluePoly);
g.setColor(lightGreen);
g.fillOval(105 + 66 + 10, 305 - 5 * 13, 13, 13);
Polygon greenPoly = new Polygon();
greenPoly.addPoint(5 + 100 + 33 + 10, 305 - 7 * 13);
greenPoly.addPoint(5 + 100 + 33 + 20, 305 - 7 * 13);
greenPoly.addPoint(5 + 100 + 33 + 15, 305 - 8 * 13);
greenPoly.addPoint(5 + 100 + 33 + 10, 305 - 7 * 13);
g.fillPolygon(greenPoly);
g.setColor(lightYellow);
g.fillOval(5 + 4 * 13, 105 + 66 + 10, 13, 13);
Polygon yellowPoly = new Polygon();
yellowPoly.addPoint(5 + 7 * 13, 5 + 100 + 33 + 10);
yellowPoly.addPoint(5 + 7 * 13, 5 + 100 + 33 + 20);
yellowPoly.addPoint(5 + 8 * 13, 5 + 100 + 33 + 15);
yellowPoly.addPoint(5 + 7 * 13, 5 + 100 + 33 + 10);
g.fillPolygon(yellowPoly);
g.setColor(pink);
g.fillOval(305 - 5 * 13, 105 + 10, 13, 13);
Polygon pinkPoly = new Polygon();
pinkPoly.addPoint(305 - 7 * 13, 5 + 100 + 33 + 10);
pinkPoly.addPoint(305 - 7 * 13, 5 + 100 + 33 + 20);
pinkPoly.addPoint(305 - 8 * 13, 5 + 100 + 33 + 15);
pinkPoly.addPoint(305 - 7 * 13, 5 + 100 + 33 + 10);
g.fillPolygon(pinkPoly);
g.setColor (Color.black);
g.drawOval(115, 5 + 4 * 13, 13, 13);
g.drawOval(105 + 66 + 10, 305 - 5 * 13, 13, 13);
g.drawOval(5 + 4 * 13, 105 + 66 + 10, 13, 13);
g.drawOval(305 - 5 * 13, 105 + 10, 13, 13);
g.drawPolygon(bluePoly);
g.drawPolygon(greenPoly);
g.drawPolygon(yellowPoly);
g.drawPolygon(pinkPoly);
for (int i = 100; i < 199; i += 33)
for (int j = 0; j < 104; j += 13)
g.drawRect (i + 5, j + 5, 33, 13);
for (int i = 100; i < 199; i += 33)
for (int j = 196; j < 300; j += 13)
g.drawRect (i + 5, j + 5, 33, 13);
for (int i = 100; i < 199; i += 33)
for (int j = 0; j < 104; j += 13)
g.drawRect (j + 5, i + 5, 13, 33);
for (int i = 100; i < 199; i += 33)
for (int j = 196; j < 300; j += 13)
g.drawRect (j + 5, i + 5, 13, 33);
g.setFont (new Font ("Helvetica", Font.BOLD, 12));
g.drawString("HOME", 137, 160);
}
public void drawPawns (Graphics g)
{
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
drawPawn (myPawns[i][j], activeG);
}
public void drawPlayers (Graphics g)
// draws the players' names and icons
{
int x = 0;
int y = 0;
int xDel = 140;
int yDel = 30;
g.setFont (smallFont);
g.setColor (Color.white);
g.fillRect (0, 0, playerW, playerH);
g.setColor (Color.black);
g.drawImage (pawnImages[0][1], x, y, this);
g.drawImage (playerIcon[players[0]], x + 28, y, this);
g.drawString(playerName[0], x + 56, y + 16);
g.drawImage (pawnImages[1][1], x, y + yDel, this);
g.drawImage (playerIcon[players[1]], x + 28, y + yDel, this);
g.drawString(playerName[1], x + 56, y + yDel + 16);
g.drawImage (pawnImages[2][1], x + xDel, y, this);
g.drawImage (playerIcon[players[2]], x + xDel + 28, y, this);
g.drawString(playerName[2], x + xDel + 56, y + 16);
g.drawImage (pawnImages[3][1], x + xDel, y + yDel, this);
g.drawImage (playerIcon[players[3]], x + xDel + 28, y + yDel, this);
g.drawString(playerName[3], x + xDel + 56, y + yDel + 16);
}
////////////////////// REGULAR PAINTING METHODS /////////////////////
public void paint (Graphics g)
// I write every graphics context to the background image bgImage,
// so all paint has to do is draw it.
{
// System.out.println("In paint, x=" + clipX + " y=" + clipY + " w=" + clipW + " h=" + clipH);
g.drawImage (bgImage, bgX, bgY, this);
quickPaintFlag = false;
}
public void update (Graphics g)
// To improve speed, update only paints the rectangle that needs to be painted
{
g.clipRect (clipX, clipY, clipW, clipH);
paint (g);
}
public void repaintInit ()
// what I got to paint to start the game.
{
activeG.drawImage (boardImage, boardX, boardY, this);
drawClock (clockG);
drawPawns (activeG);
drawPlayers (playerG);
drawMessage (messageG);
bgG.setColor (Color.white);
bgG.fillRect (0, 0, bgW, bgH);
bgG.drawImage (messageImage, messageX, messageY, this);
bgG.drawImage (clockImage, clockX, clockY, this);
bgG.drawImage (activeImage, activeX, activeY, this);
bgG.drawImage (playerImage, playerX, playerY, this);
clipX = bgX;
clipY = bgY;
clipW = bgW;
clipH = bgH;
quickPaint ();
}
public void repaintDice ()
{
clipX = diceX;
clipY = diceY;
clipW = diceW;
clipH = diceH;
drawDice (diceG);
bgG.drawImage (diceImage, diceX, diceY, this);
quickPaint ();
}
public void repaintBoard ()
// The empty board is only drawn to boardImage once; this method
// puts the pawns on it and repaints it as a unit.
{
clipX = boardX;
clipY = boardY;
clipW = boardW;
clipH = boardH;
activeG.drawImage (boardImage, boardX, boardY, this);
drawPawns (activeG);
bgG.drawImage (activeImage, activeX, activeY, this);
quickPaint ();
}
public void repaintClock ()
{
clipX = clockX;
clipY = clockY;
clipW = clockW;
clipH = clockH;
drawClock (clockG);
bgG.drawImage (clockImage, clockX, clockY, this);
quickPaint ();
}
public void repaintMessage (String str)
{
clipX = messageX;
clipY = messageY;
clipW = messageW;
clipH = messageH;
systemMessage = str;
drawMessage (messageG);
bgG.drawImage (messageImage, messageX, messageY, this);
quickPaint ();
}
public void repaintBigPawn ()
{
clipX = bigPawnX;
clipY = bigPawnY;
clipW = bigPawnW;
clipH = bigPawnH;
drawBigPawn (bgG);
quickPaint ();
}
public void repaintPlayer ()
{
clipX = playerX;
clipY = playerY;
clipW = playerW;
clipH = playerH;
drawPlayers (playerG);
bgG.drawImage (playerImage, playerX, playerY, this);
quickPaint ();
}
public void quickPaint ()
// Most of the time, I want to draw pawns moving around the board.
// Because paint only schedules a screen redraw, I had the problem
// of pawns disappearing and jumping to their destination, instead of
// moving one square at a time. To solve this problem, quickpaint sets
// a flag, and waits until paint completes for the game to proceed.
// Therefore, even on the slowest computers, every pawn moves every
// square.
{
quickPaintFlag = true;
update (this.getGraphics ());
while (quickPaintFlag)
{
try
{
System.out.println("Waiting...");
Thread.sleep(10);
}
catch (InterruptedException e)
{
System.out.println("Interrupted Exception quickPaint");
}
}
}
public void drawPawn (Pawn currentPawn, Graphics g)
{
if (currentPawn.getVisible ())
{
int col = currentPawn.getColor();
int pos = currentPawn.getPosition();
int sp = currentPawn.getSpace();
g.drawImage (pawnImages[col][0], p[pos][sp].x, p[pos][sp].y, this);
}
}
public void drawBigPawn (Graphics g)
{
g.drawImage (pawnImages[currentPlayer][2], bigPawnX, bigPawnY, this);
}
public void drawClock (Graphics g)
{
g.setColor (Color.white);
g.fillRect (0, 0, clockW, clockH);
g.setColor (Color.black);
g.setFont (bigFont);
g.drawString("Time: " + gameTimer, 0, (int) clockH / 3 + 1);
}
public void drawDice (Graphics g)
{
// System.out.println("In drawdice, ready to draw dice");
g.setColor (Color.white);
g.fillRect (0, 0, diceW, diceH);
for (int i = 0; i < 4; i++)
if (diceArray[i].getVisible () && diceArray[i].getValue () > 0)
g.drawImage (diceImages[diceArray[i].getValue ()],
diceDelta * i, 0, this);
else
g.drawImage (diceImages[0], diceDelta * i, 0, this);
}
public void drawMessage (Graphics g)
{
g.setColor(Color.white);
g.fillRect (0, 0, messageW, messageH);
g.setColor(Color.black);
String str = Pawn.getMessage ();
if (!str.equals (""))
{
systemMessage = str;
Pawn.clearMessage ();
}
if (systemMessage.length () > 15)
g.setFont (smallFont);
else
g.setFont (bigFont);
g.drawString(systemMessage, 0, (int) messageH / 3 + 1);
}
////////////////////////// GAMEPLAY METHODS /////////////////////////////
public void checkMove ()
// This method applies when the (human) player attempts to move. The computer
// will never attempt an illegal move, but that can't be said about humans!
{
int dieSum = diceArray[0].getValue () + diceArray[1].getValue ();
if (selectedPawn != null && selectedDie != null)
{
if (selectedPawn.isAtStart ())
{
// System.out.println("Pawn at enter");
if (selectedDie.getValue () == 5)
makeMove (true);
else
if (dieSum == 5)
{
// System.out.println("must use both dice");
repaintMessage ("You must use both dice");
useBothDice = true;
makeMove (true);
}
else
pawnStuck ("You can't move that pawn!");
}
else
if ((dieSum == 5 || diceArray[0].getValue () == 5 ||
diceArray[1].getValue () == 5) &&
(gameBoard[Pawn.getPawnPath(currentPlayer, 1)][0] == null ||
gameBoard[Pawn.getPawnPath(currentPlayer, 1)][1] == null) &&
!allPawnsEntered (currentPlayer))
pawnStuck("You must enter a pawn with a 5 first!");
else
if (shouldCheckDoublets () && selectedDie.getValue () <= 6)
if (canMoveDoublets (selectedPawn, selectedDie.getValue ()) )
makeMove (false);
else
if (selectedPawn.canMove (selectedDie.getValue ()) != null)
// only illegal because of doublet rule
pawnStuck("Illegal move! Must move all doublets rolls.");
else
// illegal for another reason; following will fail
makeMove (false);
else
makeMove (false);
}
}
public void pawnStuck (String str)
{
// System.out.println("Pawn is stuck");
repaintMessage (str);
selectedPawn.select ();
deselectPawn = true;
}
public void makeMove (boolean entering)
// We know the selected pawn can move, so let's move it
{
// System.out.println("Making move");
gameTimer = maxTime;
repaintClock ();
selectedDie.setVisible ();
selectedPawn.setVisible ();
selectedPawn.select ();
selectedDie.select ();
pauseThread = true;
int numSpaces = adjustValue (selectedDie.getValue ());
if (entering)
numSpaces = 1;
movePawn (selectedPawn, numSpaces);
deselectPawn = true;
deselectDie = true;
pauseThread = false;
}
public int adjustValue (int val)
// handles bonus roll values of 10 and 20
{
int numSpaces = val;
if (numSpaces == 7)
numSpaces = 10;
if (numSpaces == 8)
numSpaces = 20;
return numSpaces;
}
public void movePawn (Pawn whichPawn, int numSpaces)
// The player's pawn may move, even if the move turns out to be illegal.
// If the move is blocked, say, the pawn will advance to the block,
// get bounced back, and the appropriate message will be displayed.
{
// System.out.println("Ready to move pawn");
int hasMoved = 0;
boolean success;
whichPawn.startPosition();
do
{
hasMoved++;
success = whichPawn.advancePawn(hasMoved == numSpaces);
repaintBoard ();
tick.play ();
try
{
Thread.sleep (300);
}
catch (InterruptedException e)
{
System.out.println("InterruptedException 9");
}
}
while (hasMoved < numSpaces && success);
if (success)
{
clearDie ();
if (!checkHome (whichPawn))
checkCapture (whichPawn);
for (int i = 0; i < 4; i++)
if (currentMove [i][0] == -1)
{
currentMove[i][0] = getPawnNum (whichPawn);
currentMove[i][1] = (dv[0] == numSpaces) ? 0 : 1;
break;
}
}
else
{
repaintMessage (systemMessage);
useBothDice = false;
whichPawn.returnPosition();
}
}
public void checkCapture (Pawn whichPawn)
// handles the capturing of pawns
{
int thisPosition = whichPawn.getPosition ();
int thisSpace = whichPawn.getSpace ();
int targetColor = -1;
if (gameBoard[thisPosition][1 - thisSpace] != null)
targetColor = gameBoard[thisPosition][1 - thisSpace].getColor ();
// System.out.println("pos: " + thisPosition + " sp: " + thisSpace + " col: " + targetColor);
if (thisPosition < 68) // not on Home paths
if (gameBoard[thisPosition][1 - thisSpace] != null &&
targetColor != currentPlayer)
{
repaintMessage (colorName[currentPlayer] + " captured " +
colorName[targetColor] + "'s pawn!");
gameBoard[thisPosition][1 - thisSpace].goStart ();
gameBoard[thisPosition][1 - thisSpace] = null;
int i = 0;
while (diceArray[i].getValue () != 0)
i++;
diceArray[i].setValue (8); // really means 20
repaintBoard ();
repaintDice ();
}
}
public boolean checkHome (Pawn whichPawn)
// Handles going home. Naturally, also handles the winning condition.
{
if (whichPawn.isHome ())
{
repaintMessage (colorName[currentPlayer] + " moves a pawn Home!");
if (whichPawn.getSpace () == 3)
{
repaintMessage (colorName[currentPlayer] + " WINS!! Click \"Start\" to play again.");
sendButton.setLabel ("Start");
System.out.println(colorName[currentPlayer] + " WINS!!");
playAgain = true;
pauseThread = true;
doubletCount = 0;
turnIsOver = true;
// stop ();
}
else
{
int i = 0;
while (diceArray[i].getValue () != 0)
i++;
diceArray[i].setValue (7); // really means 10
repaintDice ();
}
}
return whichPawn.isHome ();
}
public static boolean isSafetySquare (int thisPosition)
{
return thisPosition == 7 || thisPosition == 12 || thisPosition == 17 ||
thisPosition == 24 || thisPosition == 29 || thisPosition == 34 ||
thisPosition == 41 || thisPosition == 46 || thisPosition == 51 ||
thisPosition == 58 || thisPosition == 63 || thisPosition == 0;
}
public void clearDie()
// Dice aren't actually destroyed when they're used, their values are
// just set to zero. It's easier to index over all dice without getting
// null pointer errors this way.
{
if (useBothDice)
// Rule: if you can enter and you roll a five on both dice (for example,
// a 3 and a 2), you must use both dice to enter!
{
diceArray[0].clear ();
diceArray[1].clear ();
useBothDice = false;
}
else
if (selectedDie == null)
System.out.println("ERROR! Please don't click so quickly!");
else
selectedDie.clear ();
repaintDice ();
}
public void rollDice()
// Rolls both dice, handles doublets
{
// System.out.println("In rolldice, ready to paint");
allPawnsEnteredAtBeginning = allPawnsEntered (currentPlayer);
diceArray[0].rollDie ();
diceArray[1].rollDie ();
// diceArray[1].setValue (diceArray[0].getValue ()); // testing only
// System.out.println("** rolled " + diceArray[0].getValue () +
// " and " + diceArray[1].getValue ());
if (diceArray[0].getValue () == diceArray[1].getValue ())
{
repaintMessage ("Doublets!");
doubletCount++;
if (doubletCount == 3) // actual=3; testing=?
doubletsPenalty ();
else
if (allPawnsEnteredAtBeginning)
{
diceArray[2].setValue (7 - diceArray[0].getValue ());
diceArray[3].setValue (7 - diceArray[0].getValue ());
// Rule: if all your pawns are entered and you roll doublets,
// you must use all four dice or you can't use any!
if (!passDoublets ())
{
repaintMessage("Doublets! You can't move all 4 dice!");
turnIsOver = true;
}
}
}
else
doubletCount = 0;
repaintDice ();
if (players[currentPlayer] == 1)
try
{
Thread.sleep (1000);
}
catch (InterruptedException e)
{
System.out.println("InterruptedException 10");
}
}
public void doubletsPenalty ()
// Roll doublets three times ends your turn and sends a pawn to Start.
{
repaintMessage ("Doublets penalty!");
System.out.println("Doublets penalty!");
Pawn target = null;
int thePath = 0;
int test = 0;
for (int i = 0; i < 4; i++)
{
test = myPawns[currentPlayer][i].getPathPosition ();
if (test != 0 && test != 72 && test > thePath)
{
thePath = test;
target = myPawns[currentPlayer][i];
}
}
if (target != null)
{
target.goStart ();
repaintBoard ();
}
doubletCount = 0;
turnIsOver = true;
}
public boolean passDoublets ()
// This method and its associated methods took over a month to program!
// If all your pawns are entered and you roll doublets, you must move all
// four, if possible. Therefore, it is illegal to move a pawn that will
// prevent you from using all four dice. So I need to know if a move
// will create this situation. The best way? Calculate each and every
// possible move (all 1536 of them!) and designate which ones are legal.
// Now, all I have to do is look up a move to see if it's okay.
// This method uses all the tricks in the book to avoid extra processing.
// It still bogs down a slow computer!
{
/* System.out.println("In passDoublets: " +
myPawns[currentPlayer][0].getPosition () + "/" + myPawns[currentPlayer][0].getSpace () + " " +
myPawns[currentPlayer][1].getPosition () + "/" + myPawns[currentPlayer][1].getSpace () + " " +
myPawns[currentPlayer][2].getPosition () + "/" + myPawns[currentPlayer][2].getSpace () + " " +
myPawns[currentPlayer][3].getPosition () + "/" + myPawns[currentPlayer][3].getSpace ()); */
System.out.println("Checking for legal moves...");
int die2min, die2max, die3 = 0;
boolean move0, move1, move2, move3, canmove = false;
// int counter = 0;
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 2; j++)
currentMove[i][j] = -1;
myPawns[currentPlayer][i].initialize ();
}
dv[0] = diceArray[0].getValue ();
dv[1] = 7 - dv[0];
for (int pawn0 = 0; pawn0 < 4; pawn0++)
for (int die0 = 0; die0 < 2; die0++)
{
/* System.out.println("0: Trying to move pawn #" + pawn0 + " at " +
myPawns[currentPlayer][pawn0].getPosition () + " " + dv[die0] + " spaces"); */
move0 = myPawns[currentPlayer][pawn0].successMove (dv[die0], 0);
for (int pawn1 = 0; pawn1 < 4; pawn1++)
for (int die1 = 0; die1 < 2; die1++)
{
/* System.out.println("1: Trying to move pawn #" + pawn1 + " at " +
myPawns[currentPlayer][pawn1].getPosition () + " " + dv[die1] + " spaces"); */
move1 = (move0 || pawn1 != pawn0) ?
myPawns[currentPlayer][pawn1].successMove (dv[die1], 1) :
myPawns[currentPlayer][pawn1].failMove (1);
if (die0 == die1)
{
die2min = 1 - die0;
die2max = die2min + 1;
}
else
{
die2min = 0;
die2max = 2;
}
for (int pawn2 = 0; pawn2 < 4; pawn2++)
for (int die2 = die2min; die2 < die2max; die2++)
{
/* System.out.println("2: Trying to move pawn #" + pawn2 + " at " +
myPawns[currentPlayer][pawn2].getPosition () + " " + dv[die2] + " spaces"); */
move2 = (move1 || pawn2 != pawn1) ?
myPawns[currentPlayer][pawn2].successMove (dv[die2], 2) :
myPawns[currentPlayer][pawn2].failMove (2);
for (int pawn3 = 0; pawn3 < 4; pawn3++)
{
die3 = (die0 + die1 + die2 == 1) ? 1 : 0;
/* System.out.println("3: Trying to move pawn #" + pawn3 + " at " +
myPawns[currentPlayer][pawn3].getPosition () + " " + dv[die3] + " spaces"); */
move3 = (move2 || pawn2 != pawn1) ?
myPawns[currentPlayer][pawn3].successMove (dv[die3], 3) :
myPawns[currentPlayer][pawn3].failMove (3);
moveArray[pawn0][die0][pawn1][die1][pawn2][die2][pawn3][die3] =
move0 && move1 && move2 && move3;
if (moveArray[pawn0][die0][pawn1][die1][pawn2][die2][pawn3][die3])
canmove = true;
/* System.out.println(counter + ": Move? " +
moveArray[pawn0][die0][pawn1][die1][pawn2][die2][pawn3][die3]);
counter++; */
if (move3)
myPawns[currentPlayer][pawn3].restorePawn (3);
}
if (move2)
myPawns[currentPlayer][pawn2].restorePawn (2);
}
if (move1)
myPawns[currentPlayer][pawn1].restorePawn (1);
}
if (move0)
myPawns[currentPlayer][pawn0].restorePawn (0);
}
/* System.out.println("Leaving passDoublets: " + canmove + " " +
myPawns[currentPlayer][0].getPosition () + "/" + myPawns[currentPlayer][0].getSpace () + " " +
myPawns[currentPlayer][1].getPosition () + "/" + myPawns[currentPlayer][1].getSpace () + " " +
myPawns[currentPlayer][2].getPosition () + "/" + myPawns[currentPlayer][2].getSpace () + " " +
myPawns[currentPlayer][3].getPosition () + "/" + myPawns[currentPlayer][3].getSpace ()); */
if (!canmove)
System.out.println("Can't move all four doublets rolls!");
Pawn.clearMessage ();
return canmove;
}
public static boolean allPawnsEntered (int player)
// Are all the player's pawns entered?
{
int st = Pawn.getPawnPath(player, 0);
boolean okay = true;
for (int i = 0; i < 4; i++)
okay = okay && gameBoard[st][i] == null;
return okay;
}
public boolean isEnter (int player, int pos)
{
if (player == RED && pos == 0)
return true;
if (player == GREEN && pos == 51)
return true;
if (player == YELLOW && pos == 34)
return true;
if (player == BLUE && pos == 17)
return true;
return false;
}
////////////////////////// STATIC METHODS //////////////////////////
// These methods are for use by the other classes (namely, Flasher, Pawn,
// and Die). One tenet of object-oriented programming is never pass values
// between classes directly. Instead, call methods in other classes.
public static void setGameBoard (int pos, int sp, Pawn pn)
{
gameBoard[pos][sp] = pn;
}
public static Pawn getGameBoard (int pos, int sp)
{
return gameBoard[pos][sp];
}
public static Die getDiceArray (int i)
{
return diceArray[i];
}
public static Pawn getMyPawns (int i)
{
return myPawns[currentPlayer][i];
}
public static int getPawnNum (Pawn p)
{
for (int i = 0; i < 4; i++)
if (myPawns[currentPlayer][i] == p)
return i;
return -1;
}
public static boolean shouldCheckDoublets ()
{
return (doubletCount > 0 && allPawnsEnteredAtBeginning);
}
public static boolean canMoveDoublets (Pawn thisPawn, int numSpaces)
// Here's where I look up whether a pawn can make a doublets move
{
// System.out.println("In canMoveDoublets, Pawn:" + thisPawn.getPosition () + " #" + numSpaces);
int whichMove = 0;
for (int i = 0; i < 4; i++)
if (currentMove [i][0] > -1)
whichMove++;
int thisPawnNum = getPawnNum (thisPawn);
int thisDie = (dv[0] == numSpaces) ? 0 : 1;
if (whichMove == 0)
for (int pawn1 = 0; pawn1 < 4; pawn1++)
for (int die1 = 0; die1 < 2; die1++)
for (int pawn2 = 0; pawn2 < 4; pawn2++)
for (int die2 = 0; die2 < 2; die2++)
for (int pawn3 = 0; pawn3 < 4; pawn3++)
for (int die3 = 0; die3 < 2; die3++)
if (moveArray[thisPawnNum][thisDie][pawn1][die1][pawn2][die2][pawn3][die3])
return true;
if (whichMove == 1)
for (int pawn2 = 0; pawn2 < 4; pawn2++)
for (int die2 = 0; die2 < 2; die2++)
for (int pawn3 = 0; pawn3 < 4; pawn3++)
for (int die3 = 0; die3 < 2; die3++)
if (moveArray[currentMove[0][0]][currentMove[0][1]]
[thisPawnNum][thisDie][pawn2][die2][pawn3][die3])
return true;
if (whichMove == 2)
for (int pawn3 = 0; pawn3 < 4; pawn3++)
for (int die3 = 0; die3 < 2; die3++)
if (moveArray[currentMove[0][0]][currentMove[0][1]]
[currentMove[1][0]][currentMove[1][1]][thisPawnNum][thisDie][pawn3][die3])
return true;
if (whichMove == 3)
return true;
return false;
}
//////////////////////////// EVENT METHODS ////////////////////////////////
public boolean action (Event evt, Object arg)
// Click a button. Java 1.0.2 events work fine here.
{
if (arg.equals ("Chat!"))
{
clickSend ();
return true;
}
if (arg.equals ("Start"))
{
sendButton.setLabel ("Chat!");
clickSend ();
return true;
}
if (arg.equals ("Done with turn"))
{
readyToForce = true;
return true;
}
return super.action (evt, arg);
}
public void clickSend ()
// Let's chat!
{
chatMessage = chatField.getText();
chat (0, chatMessage);
if (newGame)
{
readyToStart = true;
if (chatMessage.length () > 12)
chatMessage = chatMessage.substring (0, 12);
playerName[0] = (chatMessage.length () == 0) ? "You" : chatMessage;
repaintPlayer ();
start ();
}
if (playAgain)
{
pauseThread = true;
playAgain = false;
initAgain ();
readyToStart = true;
newGame = true;
pauseThread = false;
}
chatField.setText ("");
}
public void chat (int player, String msg)
{
if (msg.length () > 30)
msg = msg.substring (0, 30);
if (msg.length () > 0)
chatArea.appendText (playerName[player] + ": " + msg + "\n");
}
public boolean mouseUp (Event evt, int x, int y)
// Most of mouseUp handles clicking on pawns and dice. We must
// handle selecting, deselecting, and making moves.
{
// System.out.println("x:" + x + " y: " + y);
// pauseThread indicates that a pawn is moving, so the player shouldn't
// be able to click anything on the board. The player can still chat, though!
if (!pauseThread)
{
// check for dice
for (int i = 0; i < 4; i++)
if (x >= diceX + i * diceDelta && x < diceX + i * diceDelta + 32
&& y > diceY && y < diceY + 32)
if (diceArray[i] != null && !deselectDie)
if (diceArray[i].isSelected ())
{
// System.out.println("deselecting die: " + i);
diceArray[i].select ();
deselectDie = true;
return true;
}
else
if (diceArray[i].getValue () != 0)
if (checkBonus (i))
{
if (selectedDie != null)
{
selectedDie.select ();
selectedDie.setVisible ();
}
// System.out.println("selecting die: " + i);
diceArray[i].select ();
selectedDie = diceArray[i];
checkMove ();
return true;
}
else
return true;
// check for pawn
if (x < 305 && y < 305)
for (int i = 0; i < 104; i++)
for (int j = 0; j < 4; j++)
if (x >= p[i][j].x && x < p[i][j].x + 12 &&
y >= p[i][j].y && y < p[i][j].y + 12)
if (gameBoard[i][j] != null & !deselectPawn)
if (gameBoard[i][j].isSelected ()) // this pawn is selected, so deselect it
{
// System.out.println("deselecting pawn: " + i + ":" + j);
gameBoard[i][j].select ();
deselectPawn = true;
return true;
}
else
if (gameBoard[i][j].getColor () == currentPlayer) // can only select your pawn
{
if (selectedPawn != null) // another pawn is selected, so deselect it
{
selectedPawn.select ();
selectedPawn.setVisible ();
}
// System.out.println("selecting pawn: " + i + ":" + j);
gameBoard[i][j].select (); // select this pawn
selectedPawn = gameBoard[i][j];
// selectedPawn.reportBlockades (); // debug only
checkMove ();
return true;
}
}
// check for player icon
if (x >= 368 && x < 368 + 24 && y >= 115 && y < 115 + 24)
switchPlayerFlag = 0;
if (x >= 368 && x < 368 + 24 && y >= 145 && y < 145 + 24)
switchPlayerFlag = 1;
if (x >= 508 && x < 508 + 24 && y >= 115 && y < 115 + 24)
switchPlayerFlag = 2;
if (x >= 508 && x < 508 + 24 && y >= 145 && y < 145 + 24)
switchPlayerFlag = 3;
return false;
}
public boolean checkBonus (int thisDie)
{
if (diceArray[thisDie].getValue () > 6)
for (int i = 0; i < 4; i++)
if (thisDie != i && diceArray[i].getValue () > 0 && diceArray[i].getValue () <= 6)
{
repaintMessage("You can only use Bonuses at the end of your turn!");
return false;
}
return true;
}
public boolean handleEvent(Event evt)
// This method only applies if you are using an applet viewer. It enables the
// close window box.
{
if (evt.id == Event.WINDOW_DESTROY)
System.exit(0);
return super.handleEvent(evt);
}
////////////////////////////// VARIABLES ///////////////////////////////
// General variables
public Thread runner;
// GUI variables
private Image boardImage, messageImage, clockImage, diceImage,
playerImage, bgImage, activeImage, thisImage;
Graphics boardG, messageG, clockG, diceG, playerG, bgG, activeG;
private Image startcircle, face, computer;
private Panel cornerPanel, messagePanel, northPanel, blankPanel;
private TextField chatField;
private Button sendButton, doneButton, leaveButton;
private TextArea chatArea;
int clipX = 0;
int clipY = 0;
int clipW = 600;
int clipH = 360;
boolean quickPaintFlag = false;
int selectedPlayer = -1;
String [] playerName = {"You", "Larry", "Curly", "Moe"};
int [] players = {0, 1, 1, 1};
Image [] playerIcon = new Image [2];
boolean newGame = true;
boolean readyToStart = false;
int timerTick = 0;
boolean pauseThread = false;
boolean playAgain = false;
int switchPlayerFlag = -1;
boolean tickFlag = false;
static boolean allPawnsEnteredAtBeginning = false;
private AudioClip tick;
private Color lightBlue = new Color(0x99ffff);
private Color medBlue = new Color(0x66ccff);
private Color pink = new Color(0xff9999);
private Color lightYellow = new Color(0xffff00);
private Color lightGreen = new Color(0x00cc66);
private final int bgX = 0;
private final int bgY = 0;
private final int bgW = 600;
private final int bgH = 360;
private final int diceX = 360;
private final int diceY = 70;
private final int diceW = 278;
private final int diceH = 32;
private final int boardX = 0;
private final int boardY = 0;
private final int boardW = 306;
private final int boardH = 306;
private final int activeX = 0;
private final int activeY = 0;
private final int activeW = 306;
private final int activeH = 306;
private final int clockX = 450;
private final int clockY = 20;
private final int clockW = 130;
private final int clockH = 48;
private final int messageX = 5;
private final int messageY = 340;
private final int messageW = 300;
private final int messageH = 48;
private final int bigPawnX = 325;
private final int bigPawnY = 5;
private final int bigPawnW = 48;
private final int bigPawnH = 48;
private final int playerX = 340;
private final int playerY = 115;
private final int playerW = 250;
private final int playerH = 54;
private final int diceDelta = 50;
private Pawn selectedPawn = null;
private Die selectedDie = null;
private boolean deselectPawn = false;
private boolean deselectDie = false;
private boolean useBothDice = false;
// pawn color/player name designators
private final int RED = 0;
private final int GREEN = 1;
private final int YELLOW = 2;
private final int BLUE = 3;
String [] colorName = {"Red", "Green", "Yellow", "Blue"};
// core game variables
String systemMessage;
public static Die [] diceArray = new Die [4];
private String chatMessage;
private String chatText;
Image [] diceImages = new Image [9];
Image [][] pawnImages = new Image [4][3];
final Font bigFont = new Font ("Helvetica", Font.BOLD, 24);
final Font smallFont = new Font ("Helvetica", Font.BOLD, 12);
private static int currentPlayer;
private int gameTimer;
final int maxTime = 10;
Point [][] p = new Point [104][4]; // [position][space]
public static Pawn [][] gameBoard = new Pawn [104][4]; // contains the pawns
private Pawn currentPawn;
public static Pawn [][] myPawns = new Pawn [4][4];
public static Pawn [][] backup = new Pawn [5][4];
public static int [] dv = new int [2];
public static boolean [][][][][][][][] moveArray = new boolean [4][2][4][2][4][2][4][2];
public static int [][] currentMove = new int [4][2];
boolean turnIsOver = false;
public static int doubletCount = 0;
boolean readyToForce = false;
}
///////////////////////FLASHER CLASS /////////////////////
// Since pawns and dice all flash, and can all be selected and deselected,
// it made sense to have them both extend the same class. This was a good
// exercise in object-oriented programming, as well!
class Flasher extends Object
{
public Flasher ()
{
}
public void changeVisibility ()
{
// System.out.println("flasher: flash");
isVisible = !isVisible;
}
public void setVisible ()
{
isVisible = true;
}
public boolean getVisible ()
{
return isVisible;
}
public void select ()
{
selected = !selected;
}
public void deselect ()
{
selected = false;
}
public boolean isSelected ()
{
return selected;
}
public boolean isVisible = true;
public boolean selected = false;
}
//////////////////////// PAWN CLASS ///////////////////////
class Pawn extends Flasher
{
public Pawn (int c, int p, int s)
{
super ();
color = c;
pawnPosition = p;
spacePosition = s;
for (int i = 0; i < 3; i++)
blockades[i] = null;
}
//////////////// PUBLIC METHODS /////////////////////////////
public boolean advancePawn (boolean lastPosition)
// "this" pawn moves one space at a time, but it might have to
// jump back to its starting point, if the move is illegal.
// lastPosition indicates that the pawn is moving to its
// destination space
{
// System.out.println("Color: " + color + " Pos: " + pawnPosition + " Sp: " + spacePosition);
// System.out.println(pawnPath[0][0]);
int path = this.getPathPosition ();
if (path == 72) // already home!
{
newMessage = "You must enter Home with an exact die roll!";
return false;
}
int oldPosition = pawnPath[color][path];
path++;
int numSpaces = (path == 72) ? 4 : 2;
int newPosition = pawnPath[color][path];
boolean isBlocked = true;
for (int i = 0; i < numSpaces; i++)
if (Parcheesi.getGameBoard(newPosition, i) == null) // found an empty space
{
isBlocked = false;
if (!lastPosition)
{
pawnPosition = newPosition;
Parcheesi.setGameBoard (newPosition, i, this);
Parcheesi.setGameBoard (oldPosition, spacePosition, null);
spacePosition = i;
return true;
}
if (checkSafetySquare (newPosition, 1 - i) &&
checkBlockades (newPosition, 1 - i) )
{
pawnPosition = newPosition;
Parcheesi.setGameBoard (newPosition, i, this);
Parcheesi.setGameBoard (oldPosition, spacePosition, null);
spacePosition = i;
return true;
}
}
if (isBlocked)
newMessage = "That space is blocked!";
return false; // space is full or blocked, or move is invalid
}
private boolean checkSafetySquare (int newPosition, int occupiedSpace)
/* space is a safety square with another color pawn
and this pawn is not entering */
{
if (occupiedSpace < 0) // only happens at home
return true;
if (Parcheesi.isSafetySquare (newPosition))
if( Parcheesi.getGameBoard (newPosition, occupiedSpace) != null &&
// space is truly occupied
Parcheesi.getGameBoard(newPosition, occupiedSpace).getColor () != color &&
// pawn in space isn't same color as this pawn
newPosition != pawnPath[color][1])
// space isn't this pawn's ENTER space
{
newMessage = "You can't enter an occupied safety square!";
return false;
}
return true;
}
public boolean checkBlockades (int newPosition, int occupiedSpace)
// If a pawn is trying to form a blockade, we must check that it is a
// legal blockade; if it is, then we must record that each pawn is in
// a blockade with the other.
{
if (occupiedSpace < 0) // only happens at home
return true;
// System.out.println("Checking blockade " + newPosition + "/" + occupiedSpace);
Pawn targetPawn = Parcheesi.getGameBoard (newPosition, occupiedSpace);
/* if (targetPawn == null)
System.out.println("targetPawn is null");
else
System.out.println("targetPawn color= " + targetPawn.getColor () ); */
if(targetPawn != null &&
// space is truly occupied
targetPawn.getColor () == color &&
// pawn in space is same color as this pawn
!targetPawn.isHome () )
{
// System.out.println("Checking blockade");
// first, see if new blockade is legal
for (int i = 0; i < 3; i++)
if (this.blockades[i] != null )
if (this.blockades[i].equals (targetPawn) )
{
// System.out.println("Bad Blockade");
newMessage = "You can't move a blockade forward!";
return false;
}
// second, identify new blockade
setBlockades (this, targetPawn);
setBlockades (targetPawn, this);
}
return true;
}
public static String getMessage ()
{
return newMessage;
}
public static void clearMessage ()
{
newMessage = "";
}
public static void setBlockades (Pawn thisPawn, Pawn targetPawn)
{
/* System.out.println("In setBlockades: " + thisPawn.getPosition () + "/" +
thisPawn.getSpace () + " & " + targetPawn.getPosition () + "/" +
targetPawn.getSpace () ); */
int j = 0;
while (thisPawn.blockades[j] != null)
j++;
thisPawn.blockades[j] = targetPawn;
// System.out.println("Setting blockade at: " + targetPawn.getPosition ());
}
public void clearBlockade ()
{
for (int i = 0; i < 3; i++)
this.blockades[i] = null;
}
// The following group of methods allow different classes to obtain
// information about "this" pawn
public static int getPawnPath (int player, int path)
// pawnPath is a static array that contains the spaces that each of
// the four players must follow. Remember, each player starts and
// ends in a different place, so we need to know the order of the
// spaces for each player.
{
return pawnPath[player][path];
}
public int getPathPosition ()
{
for (int i = 0; i < 73; i++)
if (pawnPath[color][i] == pawnPosition)
return i;
System.out.println("ERROR: Path position not found");
return -1;
}
public int getColor ()
{
return color;
}
public int getPosition ()
{
return pawnPosition;
}
public int getSpace ()
{
return spacePosition;
}
public Pawn getBlockade (int i)
{
if (blockades[i] == null)
return null;
return (blockades[i]);
}
public void clearOneBlockade (int i)
{
blockades[i] = null;
}
public void initialize ()
// In order to calculate the possible moves in the case of doublets,
// we need to keep track of the pawns that might have been captured,
// so that we can put them back.
{
for (int i = 0; i < 4; i++)
prisoners[i] = null;
}
public void restorePawn (int move)
// Here's how we put pawns back after calculating possible moves in
// the case of doublets.
{
/* System.out.println(move + ": restorePawn from " + pawnPosition + "/" +
spacePosition + " to " + initialPosition[move] + "/" + initialSpace[move]); */
int finalPosition = pawnPosition;
int finalSpace = spacePosition;
// first, put this pawn back
Parcheesi.setGameBoard (pawnPosition, spacePosition, null);
pawnPosition = initialPosition[move];
spacePosition = initialSpace[move];
Parcheesi.setGameBoard (pawnPosition, spacePosition, this);
// second, undo just set blockade
for (int i = 0; i < 3; i++)
if (blockades[i] != null)
if (blockades[i].getPosition () == finalPosition)
// this is now in blockade with blockades[i]
{
for (int j = 0; j < 3; j++)
if (blockades[i].getBlockade (j) == this)
blockades[i].clearOneBlockade (j);
blockades[i] = null;
}
// third, replace captured pawn
if (prisoners[move] != null)
{
Parcheesi.setGameBoard (finalPosition, 1 - finalSpace, prisoners[move]);
prisoners[move] = null;
}
/* System.out.println(move + ": restorePawn completed at " + pawnPosition + "/" +
spacePosition); */
}
public void startPosition()
// startPosition and returnPosition allow a pawn that is trying to make
// an illegal move to return to its starting point.
{
currentPosition = pawnPosition;
currentSpace = spacePosition;
}
public void returnPosition()
{
Parcheesi.setGameBoard (pawnPosition, spacePosition, null);
// System.out.println(pawnPosition + "/" + spacePosition + " is null; new = " +
// currentPosition + "/" + currentSpace);
pawnPosition = currentPosition;
spacePosition = currentSpace;
Parcheesi.setGameBoard (pawnPosition, spacePosition, this);
}
public boolean isAtStart ()
{
return (pawnPosition > 99);
}
public boolean isHome ()
{
// if (pawnPath[color][72] == pawnPosition)
// System.out.println("is home");
return pawnPath[color][72] == pawnPosition;
}
public void reportBlockades ()
// This method is called for debugging only
{
for (int i = 0; i < 3; i++)
if (blockades[i] == null)
System.out.println("blockade # " + i + " is null");
else
System.out.println("blockade #" + i + ": " +
blockades[i].getPosition () + "/" + blockades[i].getSpace ());
}
public void goStart ()
{
int startPosition = pawnPath[this.getColor ()][0];
for (int i = 0; i < 4; i++)
if (Parcheesi.getGameBoard (startPosition, i) == null)
{
Parcheesi.setGameBoard (pawnPosition, spacePosition, null);
pawnPosition = startPosition;
spacePosition = i;
Parcheesi.setGameBoard (pawnPosition, spacePosition, this);
}
}
public void setBlockade (int i, Pawn blocker)
{
blockades[i] = blocker;
}
public boolean successMove (int testvalue, int move)
// This method "pretends" to move a pawn for the case of doublets. It works
// like advancePawn, except the player doesn't see the pawn move.
{
initialPosition[move] = pawnPosition;
initialSpace[move] = spacePosition;
if (this.isHome ())
return false;
int hasMoved = 0;
this.startPosition ();
boolean success;
do
{
hasMoved++;
success = this.advancePawn (hasMoved == testvalue);
}
while (hasMoved < testvalue && success);
if (success)
{
if (!this.isHome ())
this.checkDoubletsCapture (move);
}
else
this.returnPosition ();
return success;
}
public boolean failMove (int move)
{
initialPosition[move] = pawnPosition;
initialSpace[move] = spacePosition;
return false;
}
public void checkDoubletsCapture (int move)
// If a "fake" move results in a "fake" capture, we must keep
// track of the captured pawns -- the "prisoners."
{
int targetColor = -1;
Pawn targetPawn = Parcheesi.getGameBoard (pawnPosition, 1 - spacePosition);
if (targetPawn == null)
return;
targetColor = targetPawn.getColor ();
if (pawnPosition < 68) // not on Home paths
if (targetColor != color)
{
prisoners[move] = targetPawn;
Parcheesi.setGameBoard(pawnPosition, 1 - spacePosition, null);
}
}
public Pawn canMove (int numSpaces)
// The computer will never make an illegal move. This method determines
// whether a move is legal. It returns null if the move is illegal;
// returns "this" pawn if the destination space was empty; returns
// "this" pawn's new neighbor if "this" pawn is moving into a blockade.
{
// System.out.println("In canMove, numSpaces=" + numSpaces);
// numSpaces must be adjusted first!
Pawn neighbor = this;
if (numSpaces > 6)
{
for (int i = 0; i < 4; i++)
if (Parcheesi.getDiceArray (i).getValue () <= 6 &&
Parcheesi.getDiceArray (i).getValue () > 0)
return null; // can't use bonus die till end of turn
}
else
if (Parcheesi.shouldCheckDoublets ())
if (!Parcheesi.canMoveDoublets (this, numSpaces))
{
// System.out.println ("Can't use remaining Doublets rolls!");
return null; // can't use all four Doublets rolls
}
int myPath = this.getPathPosition ();
int newPath = myPath + numSpaces;
if (newPath > 72) // can't move past Home
return null;
int target = pawnPosition;
for (int j = myPath + 1; j <= newPath; j++)
{
target = pawnPath[color][j];
if (Parcheesi.getGameBoard (target, 0) != null &&
Parcheesi.getGameBoard (target, 1) != null && j != 72)
{ // can't be blocked at Home
// System.out.println("Blocked: roll=" + numSpaces + " at position=" + target);
return null; // pawn is blocked;
}
}
target = pawnPath[color][newPath];
if (Parcheesi.getGameBoard (target, 0) != null)
neighbor = Parcheesi.getGameBoard (target, 0);
if (Parcheesi.getGameBoard (target, 1) != null)
neighbor = Parcheesi.getGameBoard (target, 1);
if (Parcheesi.isSafetySquare (target) && !isAtStart ())
{ // can only move onto occupied safety square if entering
if (Parcheesi.getGameBoard (target, 0) != null)
if (neighbor.getColor () != color)
return null; // pawn of another color on safety space
if (Parcheesi.getGameBoard (target, 1) != null)
if (neighbor.getColor () != color)
return null; // pawn of another color on safety space
}
if (neighbor != this)
if (neighbor.getColor () == color)
for (int k = 0; k < 3; k++)
if (this.blockades[k] == neighbor)
return null; // illegal blockade
/*
if (neighbor == this)
System.out.println("Can move: " + numSpaces + ". No neighbor");
else
System.out.println("Can move: " + numSpaces + ". Neighbor is " + neighbor.getColor ());
*/
return neighbor;
}
public boolean wontPass (int numSpaces)
// If the computer move calls for moving a pawn that won't pass
// an opponent's pawn, this method determines this.
{
int startPath = this.getPathPosition ();
if (startPath + numSpaces > 64) // entering Home path (even if it'll pass)
return true;
int pos = 0;
for (int i = startPath + 1; i <= startPath + numSpaces; i++)
{
pos = pawnPath[color][i];
if (Parcheesi.getGameBoard (pos, 0) != null)
if (Parcheesi.getGameBoard (pos, 0).getColor () != color)
return false;
if (Parcheesi.getGameBoard (pos, 1) != null)
if (Parcheesi.getGameBoard (pos, 1).getColor () != color)
return false;
}
return true;
}
public static void initPaths ()
// Here is where we define which spaces form each player's path from
// Start to Home.
{
int i, j;
int RED = 0;
int GREEN = 1;
int YELLOW = 2;
int BLUE = 3;
pawnPath[RED][0] = 100;
for (i = 1; i <= 64; i++)
pawnPath[RED][i] = i - 1;
for (i = 65; i <= 72; i++)
pawnPath[RED][i] = i + 3;
pawnPath[GREEN][0] = 101;
for (i = 1; i <= 17; i++)
pawnPath[GREEN][i] = i + 50;
for (i = 18; i <= 64; i++)
pawnPath[GREEN][i] = i - 18;
for (i = 65; i <= 72; i++)
pawnPath[GREEN][i] = i + 11;
pawnPath[YELLOW][0] = 102;
for (i = 1; i <= 34; i++)
pawnPath[YELLOW][i] = i + 33;
for (i = 35; i <= 64; i++)
pawnPath[YELLOW][i] = i - 35;
for (i = 65; i <= 72; i++)
pawnPath[YELLOW][i] = i + 19;
pawnPath[BLUE][0] = 103;
for (i = 1; i <= 51; i++)
pawnPath[BLUE][i] = i + 16;
for (i = 52; i <= 64; i++)
pawnPath[BLUE][i] = i - 52;
for (i = 65; i <= 72; i++)
pawnPath[BLUE][i] = i + 27;
}
/////////////////////////// VARIABLES /////////////////////////////
private int color, pawnPosition, spacePosition;
private int currentPosition;
private int currentSpace;
private static int [][] pawnPath = new int [4][73]; // [color][path position]
static
{
initPaths();
}
public static String newMessage = "";
Pawn [] blockades = new Pawn [3];
// passDoublets variables
Pawn [] prisoners = new Pawn [4];
int [] initialPosition = new int [4];
int [] initialSpace = new int [4];
// pawn color/player name designators
private static int RED = 0;
private static int GREEN = 1;
private static int YELLOW = 2;
private static int BLUE = 3;
}
//////////////////////////// DIE CLASS /////////////////////////////////////
class Die extends Flasher
{
public Die (int d, int v)
{
super ();
die = d;
value = v;
}
////////////////////////// PUBLIC METHODS //////////////////////////////////
// There's not much to the dice! Remember, they inherit from Flasher, too.
public void rollDie()
{
value = (int)(Math.random () * 6) + 1;
}
public int getValue ()
{
return value;
}
public void setValue (int val)
{
value = val;
}
public void clear ()
{
value = 0;
}
private int die, value;
}
![]() |
![]() |
![]() |
![]() |