// TT4DApplet.java
//so that I can invoke applet viewer on the source file
//<APPLET code="TT4DApplet.class" width=400 height=430></APPLET>
import java.awt.*;
import java.applet.*;
/**
*
* @author Sean Bridges
* @version 1.0.1
*
* The TT4DApplet allows you to play a game of 4D Tic Tac Toe.
*
* Applet size should be width = 400, height = 430.
*
*/
public class TT4DApplet extends Applet
{
//---------------------------------------
//class variables
final static String ABOUT = "4D Tic Tac Toe, created by Sean Bridges, www.oocities.org/sbridges.geo";
final static String L1 = "100%";
final static String L2 = "80%";
final static String L3 = "50%";
final static String L4 = "20%";
final static String L5 = "10%";
//---------------------------------------
//instance variables
private Button restart;
private Choice levels;
private ImagePanel imagePanel;
private AllPossibleMovesPlayer computer;
private AsynchronousPlayer human;
private TT4DBoard board;
private GameMaster gameMaster;
//---------------------------------------
//instance methods
//---------------------------------------
//applet methods
/** Initializes the applet TT4DApplet */
public void init()
{
System.out.println("TT4DApplet initializing");
System.out.println(ABOUT);
//if the init method is called more than once,
//then remove all will remove the components that were
//previously contained on the applet.
//Done mainly so that the appletviewer restart works.
removeAll();
//create the game
computer = new AllPossibleMovesPlayer( TT4DBoard.O_PLAYER_STRING, TT4DBoard.O_PLAYER_NUMBER);
human = new AsynchronousPlayer(TT4DBoard.X_PLAYER_STRING, TT4DBoard.X_PLAYER_NUMBER);
board = new TT4DBoard();
Player[] players = new Player[2];
players[0] = human;
players[1] = computer;
gameMaster = new GameMaster(board, players);
//lay out the components
this.setLayout(new BorderLayout());
//the control panel has the level drop down list and
//the restart button
Panel controlPanel = new Panel();
controlPanel.setLayout(new FlowLayout() );
restart = new Button("restart");
levels = new Choice();
levels.add(L1);
levels.add(L2);
levels.add(L3);
levels.add(L4);
levels.add(L5);
controlPanel.add(restart);
controlPanel.add(new Label(" Level"));
controlPanel.add(levels);
this.add(controlPanel, BorderLayout.SOUTH);
//the image panel draws the board.
imagePanel = new ImagePanel(gameMaster, board, computer, human);
this.add(imagePanel, BorderLayout.CENTER);
}
public void start()
{
System.out.println("TT4DApplet starting");
gameMaster.startGame();
this.repaint();
}
public void stop()
{
System.out.println("TT4DApplet stopping");
gameMaster.stopGame();
}
public String getAppletInfo()
{
return ABOUT;
}
//------------------------------------------------
//event processing
public boolean action (Event evt, Object arg)
{
if(arg.equals("restart"))
{
gameMaster.restartGame();
}
else if(evt.target.equals(levels))
{
if(levels.getSelectedItem() == L1)
{
computer.setFractionOfMovesTried(1.0f);
}
else if(levels.getSelectedItem() == L2)
{
computer.setFractionOfMovesTried(0.8f);
}
else if(levels.getSelectedItem() == L3)
{
computer.setFractionOfMovesTried(0.5f);
}
else if(levels.getSelectedItem() == L4)
{
computer.setFractionOfMovesTried(0.2f);
}
else if(levels.getSelectedItem() == L5)
{
computer.setFractionOfMovesTried(0.1f);
}
}
else
{
return super.action(evt,arg);
}
return true;
}
}//end class TT4DApplet
/**
* The image panel is responsible for drawing the game board.
*/
class ImagePanel extends Panel implements GameEventListener
{
//--------------------------------
//class variables
public final static int ORIGIN_X = 30;
public final static int ORIGIN_Y = 50;
public final static int SCORE_X = 20;
public final static int SCORE_Y = 30;
public final static int SCORE_WIDTH = 420;
public final static int SCORE_HEIGHT = 30;
public final static int BOX_HEIGHT = 30;
public final static int BOX_WIDTH = 30;
public final static int BOARD_WIDTH = 3 * BOX_HEIGHT;
public final static int BOARD_HEIGHT = 3 * BOX_WIDTH;
public final static int BOARD_VERTICAL_GAP = 30;
public final static int BOARD_HORIZONTAL_GAP = 30;
final static int X_OFFSET = 11;
final static int Y_OFFSET = 20;
final static Color LINE_COLOR = Color.black;
final static Color X_COLOR = Color.black;
final static Color O_COLOR = Color.blue;
final static Color EMPHASIS_COLOR = Color.red;
final static Color TEXT_COLOR = Color.black;
final static Font TOKEN_FONT = new Font("Serif", Font.PLAIN, 16);
final static Font SCORE_FONT = new Font("Serif", Font.PLAIN, 22);
//----------------------------------------
//instance variables
//drawing is done to a buffer offscreen so that the user doesnt see
//the screen flicker
private Image offscreenImage;
private Graphics offscreenGraphics;
private TT4DMove lastOMove;
private GameMaster game;
private Player computer;
private AsynchronousPlayer human;
private Board board;
//----------------------------------------
//constructors
ImagePanel(GameMaster aGame, Board aBoard, Player computer, AsynchronousPlayer human)
{
super();
game = aGame;
board = aBoard;
this.computer = computer;
this.human = human;
game.addListener(this);
}
//----------------------------------------
//instance methods
public void paint(Graphics g)
{
g.drawImage(offscreenImage,0,0, this);
}
public void update()
{
Graphics g = this.getGraphics();
g.drawImage(offscreenImage,0,0, this);
}
//----------------------------------------
//mouse interaction
/**
* If the user clicked on a square, find out where,
* and inform the appropiate player.
*/
public boolean mouseDown(java.awt.Event event, int mouseX, int mouseY)
{
for(int x = 0; x<3; x++)
{
for(int y = 0; y <3; y++ )
{
for(int z = 0; z <3; z++ )
{
for(int w = 0; w <3; w++ )
{
//check to see if the mouse was clicked in a box
int leftX = positionToX(x,w);
int topY = positionToY(y,z);
int rightX = leftX + BOX_WIDTH;
int bottomY = topY + BOX_HEIGHT;
if( ( mouseX > leftX && mouseX < rightX) &&
(mouseY > topY && mouseY < bottomY))
{
TT4DPoint p = new TT4DPoint(x,y,z,w);
TT4DMove m = new TT4DMove(human, p);
human.makeMove(m);
return true;
}
}//end for w
}//end for z
}//end for y
}//end for x
return true;
}
//----------------------------------------
//drawing
private void resetOffScreen()
{
offscreenImage = createImage(this.getSize().width, this.getSize().height);
offscreenGraphics = offscreenImage.getGraphics();
drawBoard();
drawScore();
update();
}
private int positionToX(int x, int w)
{
return ORIGIN_X +
(BOX_WIDTH * x) +
((BOARD_WIDTH + BOARD_VERTICAL_GAP) * w);
}
private int positionToY(int y, int z)
{
return ORIGIN_Y +
(BOX_HEIGHT * y) +
((BOARD_HEIGHT + BOARD_HORIZONTAL_GAP) * z);
}
/**
* Returns the top left corner x position of the point.
*/
private int pointToX(TT4DPoint p)
{
return positionToX(p.getX(), p.getW() );
}
/**
* Returns the top left corner y position of the point.
*/
private int pointToY(TT4DPoint p)
{
return positionToY(p.getY(), p.getZ() );
}
private void clearPoint(TT4DPoint p)
{
offscreenGraphics.clearRect(pointToX(p) + 1, pointToY(p) + 1, BOX_HEIGHT - 1, BOX_WIDTH -1);
}
/**
* Draw the given string at the given point. Draw to offscreen,
* must call update before it is visible.
*/
private void drawToken(TT4DPoint p, String s, Color c )
{
offscreenGraphics.setFont(TOKEN_FONT);
offscreenGraphics.setColor(c);
offscreenGraphics.drawString(s,pointToX(p) + X_OFFSET, pointToY(p) + Y_OFFSET);
}
/**
* Draws the board offscreen. Must call update before it is visible
*/
private void drawBoard()
{
offscreenGraphics.setColor(LINE_COLOR);
draw4dBoard(ORIGIN_X,ORIGIN_Y);
}
private void draw4dBoard(int x, int y)
{
draw3dBoard(x,y);
draw3dBoard(x + BOARD_WIDTH + BOARD_HORIZONTAL_GAP, y);
draw3dBoard(x + (2* (BOARD_WIDTH + BOARD_HORIZONTAL_GAP) ), y);
}
private void draw3dBoard(int x, int y)
{
draw2dBoard(x,y);
draw2dBoard(x, y + BOARD_HEIGHT + BOARD_VERTICAL_GAP);
draw2dBoard(x, y + (2* (BOARD_HEIGHT + BOARD_VERTICAL_GAP) ));
}
private void draw2dBoard(int x, int y)
{
//draw vertical lines
offscreenGraphics.drawLine(x + BOX_WIDTH,y,
x + BOX_WIDTH, y + (3 * BOX_HEIGHT) );
offscreenGraphics.drawLine(x + (2* BOX_WIDTH) ,y,
x + (2*BOX_WIDTH), y + (3 * BOX_HEIGHT) );
//draw horizontal lines
offscreenGraphics.drawLine(x, y + BOX_HEIGHT,
x + (3 * BOX_WIDTH), y + BOX_HEIGHT );
offscreenGraphics.drawLine(x ,y + (2 * BOX_HEIGHT),
x + (3*BOX_WIDTH), y + (2 * BOX_HEIGHT) );
}
/**
* Erases the old score and draws the new score offscreen.
* Must call update before it's seen.
*/
private void drawScore()
{
offscreenGraphics.clearRect(SCORE_X, SCORE_Y - SCORE_HEIGHT, SCORE_WIDTH, SCORE_HEIGHT);
BoardStats stats = board.getBoardStats();
offscreenGraphics.setFont(SCORE_FONT);
offscreenGraphics.setColor(TEXT_COLOR);
offscreenGraphics.drawString(
" X's Score " + stats.getScore(human) + " " +
"O's Score " + stats.getScore(computer), SCORE_X, SCORE_Y);
}
//-----------------------------------------------
//GameEventListenerMethods
/** The game has started.
*/
public void gameStarted()
{
lastOMove = null;
resetOffScreen();
}
/** The game has stopped
*/
public void gameStoped()
{//we just dont really care
}
/**
* The game has been restarted.
*/
public void gameRestarted()
{
lastOMove = null;
resetOffScreen();
}
/**
* A player has moved.
*/
public void moveMade(Move aMove)
{
TT4DMove move = (TT4DMove) aMove;
if(move.maker() == computer)
{
if(lastOMove != null)
{
//clear the highlited square, redraw the old token, draw the new one
this.clearPoint(lastOMove.getPoint() );
this.drawToken(lastOMove.getPoint(), lastOMove.maker().getName(), O_COLOR);
}
this.drawToken(move.getPoint(), move.maker().getName(), EMPHASIS_COLOR);
lastOMove = move;
}
else //x Moved
{
this.drawToken(move.getPoint(), move.maker().getName(), X_COLOR);
}
drawScore();
update();
}
}//end class ImagePanel