// 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