TicTacToe.java



/*
 *  @(#)TicTacToe.java    1.5 97/02/05
 *
 *  Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
 *
 *  Sun grants you ("Licensee") a non-exclusive, royalty free, license to use,
 *  modify and redistribute this software in source and binary code form,
 *  provided that i) this copyright notice and license appear on all copies of
 *  the software; and ii) Licensee does not utilize the software in a manner
 *  which is disparaging to Sun.
 *
 *  This software is provided "AS IS," without a warranty of any kind. ALL
 *  EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
 *  IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
 *  NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
 *  LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
 *  OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
 *  LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
 *  INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
 *  CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
 *  OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGES.
 *
 *  This software is not designed or intended for use in on-line control of
 *  aircraft, air traffic, aircraft navigation or aircraft communications; or in
 *  the design, construction, operation or maintenance of any nuclear
 *  facility. Licensee represents and warrants that it will not use or
 *  redistribute the Software for such purposes.
 */

import com.sap.ip.me.api.runtime.awt.AWTConfigurationUI;
import com.sap.ip.me.api.runtime.awt.AwtApplication;

import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.net.*;

/**
 *  A TicTacToe applet. A very simple, and mostly brain-dead implementation of
 *  your favorite game! <p>
 *
 *  In this game a position is represented by a white and black bitmask. A bit
 *  is set if a position is ocupied. There are 9 squares so there are 1<<9
 *  possible positions for each side. An array of 1<<9 booleans is created, it
 *  marks all the winning positions.
 *
 *@author      Arthur van Hoff
 *@created     14. Oktober 2002
 *@version     1.2, 13 Oct 1995
 *@modified    04/23/96 Jim Hagen : winning sounds
 *@modified    02/10/98 Mike McCloskey : added destroy()
 */

public class TicTacToe extends Applet implements MouseListener, AwtApplication {

  /**
   *  Description of the Field
   */
  public final static String homeMenuEntry = "home";

  /**
   *  The squares in order of importance...
   */
  final static int moves[] = {4, 0, 2, 6, 8, 1, 3, 5, 7};
  final static int DONE = (1 << 9) - 1;
  final static int OK = 0;
  final static int WIN = 1;
  final static int LOSE = 2;
  final static int STALEMATE = 3;

  /**
   *  The winning positions.
   */
  static boolean won[] = new boolean[1 << 9];
  /**
   *  White's current position. The computer is white.
   */
  int white;

  /**
   *  Black's current position. The user is black.
   */
  int black;

  /**
   *  Who goes first in the next game?
   */
  boolean first = true;

  /**
   *  The image for white.
   */
  Image notImage;

  /**
   *  The image for black.
   */
  Image crossImage;


  /**
   *  Initialize the applet. Resize and load images.
   */
  public void initApplication() {
    addMouseListener(this);

    /*
     *  Menu navMenu = new Menu("Nav");
     *  / menuBar.add(actionMenu);
     *  MenuItem menuItem;
     *  menuItem = new MenuItem("home");
     *  navMenu.add(menuItem);
     *  AWTConfigurationUI.setMenu(navMenu);
     */
  }


  /**
   *  Description of the Method
   */
  public void destroy() {
    removeMouseListener(this);
  }


  /**
   *  Paint it.
   *
   *@param  g  Description of the Parameter
   */
  public void paint(Graphics g) {
    Dimension d = getSize();
    g.setColor(Color.black);
    int xoff = d.width / 3;
    int yoff = d.height / 3;

    int xab = d.width / 12;
    int yab = d.height / 12;
    g.drawLine(xoff, 0, xoff, d.height);
    g.drawLine(2 * xoff, 0, 2 * xoff, d.height);
    g.drawLine(0, yoff, d.width, yoff);
    g.drawLine(0, 2 * yoff, d.width, 2 * yoff);

    int i = 0;
    for (int r = 0; r < 3; r++) {
      for (int c = 0; c < 3; c++, i++) {
        if ((white & (1 << i)) != 0) {
          g.drawOval(c * xoff + xab, r * yoff + yab, xoff - 2 * xab, yoff - 2 * yab);
        }
        else if ((black & (1 << i)) != 0) {
          g.drawLine(c * xoff + xab, r * yoff + yab, (c + 1) * xoff - xab, (r + 1) * yoff - yab);
          g.drawLine((c + 1) * xoff - xab, r * yoff + yab, c * xoff + xab, (r + 1) * yoff - yab);
        }
      }
    }
  }


  /**
   *  The user has clicked in the applet. Figure out where and see if a legal
   *  move is possible. If it is a legal move, respond with a legal move (if
   *  possible).
   *
   *@param  e  Description of the Parameter
   */
  public void mouseReleased(MouseEvent e) {

    int x = e.getX();
    int y = e.getY();

    switch (status()) {
      case WIN:
      case LOSE:
      case STALEMATE:
        white = black = 0;
        if (first) {
          white |= 1 << (int) (Math.random() * 9);
        }
        first = !first;
        repaint();
        return;
    }

    // Figure out the row/column
    Dimension d = getSize();
    int c = (x * 3) / d.width;
    int r = (y * 3) / d.height;
    if (yourMove(c + r * 3)) {
      repaint();

      switch (status()) {
        case WIN:
          break;
        case LOSE:
          break;
        case STALEMATE:
          break;
        default:
          if (myMove()) {
            repaint();
            switch (status()) {
              case WIN:
                break;
              case LOSE:
                break;
              case STALEMATE:
                break;
              default:
            }
          }
          else {
          }
      }
    }
    else {
    }
  }


  /**
   *  Description of the Method
   *
   *@param  e  Description of the Parameter
   */
  public void mousePressed(MouseEvent e) {
  }


  /**
   *  Description of the Method
   *
   *@param  e  Description of the Parameter
   */
  public void mouseClicked(MouseEvent e) {
  }


  /**
   *  Description of the Method
   *
   *@param  e  Description of the Parameter
   */
  public void mouseEntered(MouseEvent e) {
  }


  /**
   *  Description of the Method
   *
   *@param  e  Description of the Parameter
   */
  public void mouseExited(MouseEvent e) {
  }


  /**
   *  Gets the appletInfo attribute of the TicTacToe object
   *
   *@return    The appletInfo value
   */
  public String getAppletInfo() {
    return "TicTacToe by Arthur van Hoff";
  }


  /**
   *  Gets the rootPanel attribute of the TicTacToe object
   *
   *@return    The rootPanel value
   */
  public Panel getRootPanel() {
    return this;
  }


  /**
   *  Description of the Method
   */
  public void activateApplication() {
  }


  /**
   *  Description of the Method
   */
  public void deactivateApplication() {
  }


  /**
   *  Description of the Method
   */
  public void destroyApplication() {
  }


  /**
   *  Description of the Method
   *
   *@param  menuItem  Description of the Parameter
   */
  public void actionMenuItem(MenuItem menuItem) {
    if (homeMenuEntry.equals(menuItem.getLabel())) {
      AWTConfigurationUI.goHome();
    }
  }


  /**
   *  Gets the applicationName attribute of the TicTacToe object
   *
   *@return    The applicationName value
   */
  public String getApplicationName() {
    // return "TICTACTOE";
    return "DEMOAWTTTT";
  }


  /**
   *  Mark all positions with these bits set as winning.
   *
   *@param  pos  Description of the Parameter
   */
  static void isWon(int pos) {
    for (int i = 0; i < DONE; i++) {
      if ((i & pos) == pos) {
        won[i] = true;
      }
    }
  }


  /**
   *  Compute the best move for white.
   *
   *@param  white  Description of the Parameter
   *@param  black  Description of the Parameter
   *@return        t3he square to take
   */
  int bestMove(int white, int black) {
    int bestmove = -1;

    loop :
    for (int i = 0; i < 9; i++) {
      int mw = moves[i];
      if (((white & (1 << mw)) == 0) && ((black & (1 << mw)) == 0)) {
        int pw = white | (1 << mw);
        if (won[pw]) {
          // white wins, take it!
          return mw;
        }
        for (int mb = 0; mb < 9; mb++) {
          if (((pw & (1 << mb)) == 0) && ((black & (1 << mb)) == 0)) {
            int pb = black | (1 << mb);
            if (won[pb]) {
              // black wins, take another
              continue loop;
            }
          }
        }
        // Neither white nor black can win in one move, this will do.
        if (bestmove == -1) {
          bestmove = mw;
        }
      }
    }
    if (bestmove != -1) {
      return bestmove;
    }

    // No move is totally satisfactory, try the first one that is open
    for (int i = 0; i < 9; i++) {
      int mw = moves[i];
      if (((white & (1 << mw)) == 0) && ((black & (1 << mw)) == 0)) {
        return mw;
      }
    }

    // No more moves
    return -1;
  }


  /**
   *  User move.
   *
   *@param  m  Description of the Parameter
   *@return    true if legal
   */
  boolean yourMove(int m) {
    if ((m < 0) || (m > 8)) {
      return false;
    }
    if (((black | white) & (1 << m)) != 0) {
      return false;
    }
    black |= 1 << m;
    return true;
  }


  /**
   *  Computer move.
   *
   *@return    true if legal
   */
  boolean myMove() {
    if ((black | white) == DONE) {
      return false;
    }
    int best = bestMove(white, black);
    white |= 1 << best;
    return true;
  }


  /**
   *  Figure what the status of the game is.
   *
   *@return    Description of the Return Value
   */
  int status() {
    if (won[white]) {
      return WIN;
    }
    if (won[black]) {
      return LOSE;
    }
    if ((black | white) == DONE) {
      return STALEMATE;
    }
    return OK;
  }

  /**
   *  Initialize all winning positions.
   */
  static {
    isWon((1 << 0) | (1 << 1) | (1 << 2));
    isWon((1 << 3) | (1 << 4) | (1 << 5));
    isWon((1 << 6) | (1 << 7) | (1 << 8));
    isWon((1 << 0) | (1 << 3) | (1 << 6));
    isWon((1 << 1) | (1 << 4) | (1 << 7));
    isWon((1 << 2) | (1 << 5) | (1 << 8));
    isWon((1 << 0) | (1 << 4) | (1 << 8));
    isWon((1 << 2) | (1 << 4) | (1 << 6));
  }
}