Wednesday, February 8, 2017

This code will draw the window - given by prof

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class TTT3DWindow extends JFrame {
 
  //Instance variables that are set once only, in the constructor
  private JPanel wholeWindow; //The drawing area (the whole area of the window)
  private TTTBoard3D board;   //The reference to the TTTBoard3D object controlling the game
  private Font messageFont;   //The Font to use for the messages at the bottom
  private int boardSize;      //The board size - an n by n by n board

  //These constants control the size and shape of the graphical board
  //Change ONLY these values to adjust the board appearance.
  private static int MESSAGE_HEIGHT = 40; //Height of message area at the bottom (pixels)
  private static int MARGIN = 10; //Margin on all sizes of the board (pixels)
  private static double GAP = 0.3; //Size of the gap between levels as a portion of one ROW height
  private static double ASPECT_RATIO = 2.0; //Width of levels as a multiple of height
  private static double SLANT = 0.7; //Offset of top of level relative to bottom, as portion of width
 
  //Instance variables which change as the window is resized.
  //These are recalculated every time the window is redrawn.
  private int width, height; //Total size of the drawing area of the window
  private int colWidth;      //Width (pixels) of one square or one column
  private int rowSlant;      //Offset (pixels) of top of one square/row from its bottom
  private int rowHeight;     //Height (pixels) of one square or one row
  private int leftEdge;      //Coordinate of the left edge of the board (bottom left of each level)
  private int topEdge;       //Coordinate of the top edge of the board
  private int gapSize;       //The actual size of the gap between levels in pixels
 
  //==============================================================================
  //Constructor
  public TTT3DWindow(int w, int h, int n) {
    messageFont = new Font("Helvetica",Font.PLAIN,24);
    boardSize = n;
    board = new TTTBoard3D(n);
    setTitle("3D Tic-tac-toe");
    setSize(w,h);
    wholeWindow = new graphicsPanel();
    add(wholeWindow);
    wholeWindow.addMouseListener(new HandleMouse());
    setVisible(true);
  }//TTT3DWindow constructor

  //==============================================================================
  //Instance methods

  private void calculateSizes(int w, int h){
    //Realculates all of the instance variables for the current window size.
    width = w;
    height = h;
    int n = boardSize; //Just to keep the formulae smaller
    rowHeight = (int)((height-2*MARGIN-MESSAGE_HEIGHT)/(n*n+GAP*(n-1)));
    gapSize = (height-2*MARGIN-MESSAGE_HEIGHT-(n*n*rowHeight))/(n-1);
    rowSlant = (int)(rowHeight*SLANT);
    colWidth = (int)(rowHeight*ASPECT_RATIO);
    topEdge = MARGIN; //This is just for readability later
    leftEdge = width/2-(n*colWidth+n*rowSlant)/2;
  }
 
  public void drawBoard(Graphics g){
    //Draw the whole board, in the given graphics environment (window)
    //Make one Coordinate then change it using the 3 loops
    Coordinate c = new Coordinate(0,0,0);
    for(c.level=0; c.level<boardSize; c.level++)
      for(c.row=0; c.row<boardSize; c.row++)
        for(c.column=0; c.column<boardSize; c.column++)
          //Draw that one square. Get the colour from the board.
          drawSquare(c.level,c.row,c.column,board.getSquareColor(c),g);
  }

  private void drawSquare(int level, int row, int col, Color c, Graphics g){
    //Draw one particular "square". What's tricky is that it's really
    //a parallelogram so the coordinates of all four corners must be found.
    //First,get the coordinate of the bottom left:
    int x = getX(row,col);
    int y = getY(level,row);
    //Calculate the others based on that.
    int[] xCoords = {x,x+colWidth,x+colWidth+rowSlant,x+rowSlant};
    int[] yCoords = {y,y,y-rowHeight,y-rowHeight};
    //Now fill in that area, and draw a border around it, too.
    g.setColor(c);
    g.fillPolygon(xCoords,yCoords,4);
    g.setColor(Color.black);
    g.drawPolygon(xCoords,yCoords,4);
  }
 
  private int getX(int row, int col){
    //Get the X coordinate of the left edge of any row and column.
    //All levels have the same X coordinate so that is not needed.
    return leftEdge+col*colWidth+row*rowSlant;
  }
 
  private int getY(int level, int row){
    //Get the Y coordinate of the bottom edge of any level and row.
    //All columns have the same Y coordinate so that is not needed.
    return (topEdge+boardSize*rowHeight)
           +(boardSize-1-level)*(gapSize+boardSize*rowHeight)
           -row*rowHeight;
  }

  private void drawMessageArea(Graphics g){
    //Draw the message (as supplied by the board) at the bottom
    //of the window
    g.setColor(new Color(255,255,200));
    g.fillRect(0,height-MESSAGE_HEIGHT,width,MESSAGE_HEIGHT);
    g.setColor(Color.black);
    g.setFont(messageFont);
    g.drawString(board.getMessage(),MARGIN,height-12);
  }
 

  private Coordinate findClickCoordinate(int x, int y){
    /* Convert the mouse position (x,y) into a (level,row,column)
     * Coordinate, if possible. Return null if the mouse is
     * not within a valid "square" on the board.
     * This gets rather long and tricky because the "squares" are
     * drawn as parallelograms to make the board look "3D".
     */
    //Is it within the entire board vertically?
    if(y<=getY(0,0) && y>=getY(boardSize-1,boardSize)){
      //Convert y to a level and a row
      int level = (getY(0,0)-y)/(boardSize*rowHeight+gapSize);
      int row = (getY(level,0)-y)/rowHeight;
      //Is it in a valid row (and not in the "gap" between levels)?
      if(row<boardSize){
        //Is it within the entire board horizontally, for that row?
        if(x>=getX(row,0) && x<=getX(row+1,boardSize)){
          //This gets tricky because the "squares" are parallelograms
          //How far above the base of the row is the click?
          int yOffset = getY(level,row)-y;
          //How far to the right are the x coordinates shifted at that place?
          int xOffset = yOffset*rowSlant/rowHeight;
          //Where does the left edge intersect that particular y coordinate?
          int xLeft = getX(row,0)+xOffset;
          //Is it within the boundaries of the board at that specific Y coordinate?
          if(x>=xLeft && x<xLeft+boardSize*colWidth){
            //IT'S VALID! FINALLY!
            //Find the column number, return the coordinates
            int col = (x-xLeft)/colWidth;
            return new Coordinate(level,row,col);
          }//within the board at the specific Y
        }//within board horizontally
      }//valid row
    }//within board vertically
    //The default is null if any of the above didn't work
    return null;
  }//findClickCoordinate()
 
  private class graphicsPanel extends JPanel {
    public void paintComponent(Graphics g){
      /* This is where all the drawing commands go.
       * Whenever the window needs to be drawn, or redrawn,
       * this method will automatically be called.
       */

      //Find out the size of the available area, then
      //recalculate the sizes and positions for the board
      Rectangle r = g.getClipBounds();
      calculateSizes(r.width,r.height);
      
      //Draw the board once it's known how to draw it.
      drawMessageArea(g);
      drawBoard(g);
     
     }//paintComponent method
  }//private inner class graphicsPanel
 
  private class HandleMouse implements MouseListener {
    //The five standard methods are required. I don't want these ones:
    public void mousePressed(MouseEvent e){ /*Do nothing */ }
    public void mouseReleased(MouseEvent e){ /*Do nothing */ }
    public void mouseEntered(MouseEvent e){ /*Do nothing */ }
    public void mouseExited(MouseEvent e){ /*Do nothing */ }
   
    //The only one we really want to pay attention to
    public void mouseClicked(MouseEvent e){
      Coordinate c = findClickCoordinate(e.getX(),e.getY());
      if(c!=null){
        board.handleClick(c); //Update the game board
        repaint(); //And force it to be redrawn
      }
    }//mouseClicked
    
  }//private inner class HandleMouse
  
}//class TTT3DWindow

No comments:

Post a Comment