Friday 31 March 2017

Scrabblet: The Source Code - Java Tutorials ( Page 4 of 6 )

moveToTray( )
The moveToTray( ) method is just a simple convenience to compute the screen position of a letter in a given tray slot.

    private void moveToTray(Letter l, int i) {
      int x = lm + (lw + lt) * i;
      int y = tm + ah - 2 * lt;
      l.move(x, y);
    }

dropOnTray( )
The dropOnTray( ) method is used whenever we drop a letter over the tray area or off the board anywhere. This allows us to shuffle the contents of the tray as well as simply return tiles from the board.

    private void dropOnTray(Letter l, int x) {
      unplay(l); // unhook where we were.

      // find out what slot this letter WAS in.
      int oldx = 0;
      for (int i = 0 ; i < 7 ; i++) {
        if (tray[i] == l) {
          oldx = i;
          break;
        }
      }

      // if the slot we dropped on was empty,
      // find the rightmost occupied slot.
      if (tray[x] == null) {
        for (int i = 6 ; i >= 0 ; i--) {
          if (tray[i] != null) {
            x = i;
            break;
          }
        }
      }
      // if the slot we dropped on was from a tile already
      // played on the board, just swap slots with it.
      if (tray[x].recall() != null) {
        tray[oldx] = tray[x];
      } else {
        // we are just rearranging a tile already on the tray.
        if (oldx < x) { // shuffle left.
          for (int i = oldx ; i < x ; i++) {
            tray[i] = tray[i+1];
            if (tray[i].recall() == null)
              moveToTray(tray[i], i);
          }
        } else { // shuffle right.
          for (int i = oldx ; i > x ; i--) {
            tray[i] = tray[i-1];
            if (tray[i].recall() == null)
              moveToTray(tray[i], i);
          }
        }
      }
      tray[x] = l;
      moveToTray(l, x);
    }

getLetter( )
getLetter( ) is a simple read-only wrapper on the board array.

    Letter getLetter(int x, int y) {
      return board[y][x];
    }

moveLetter( )
The moveLetter( ) method handles the cases where we want to move tiles to board positions or set them on the tray. If the x,y position is out of range for the board, then the tray is used. When a letter is moved to the board, it must be a blank slot, otherwise the letter is sent back to the value stored in orig.

    void moveLetter(Letter l, int x, int y) {
      if (y > 14 || x > 14 || y < 0 || x < 0) {
        // if we are off the board.
        if (x > 6)
          x = 6;
        if (x < 0)
          x = 0;
        dropOnTray(l, x);
      } else {
        if (board[y][x] != null) {
          x = orig.x;
          y = orig.y;
        } else {
          here.x = x;
          here.y = y;
          unplay(l);
          board[y][x] = l;
          l.remember(here);

          // turn it back into pixels
          x = lm + (lw + lt) * x;
          y = tm + (lh + lt) * y;
        }
        l.move(x, y);
      }
    }

checksize( )
This method has a misleading name. checksize( ) does a lot more than verify the size of the applet, but it is convenient to do this kind of initialization once, when we confirm the size of the applet. This method contains the drawing code for the main board pattern. It paints all of the squares, including the colors and the bonus score text.

    private Color bg = new Color(175, 185, 175);
    private Color w3 = new Color(255, 50, 100);
    private Color w2 = new Color(255, 200, 200);
    private Color l3 = new Color(75, 75, 255);
    private Color l2 = new Color(150, 200, 255);
    private Color tiles[][] = {
      {w3, bg, bg, l2, bg, bg, bg, w3},
      {bg, w2, bg, bg, bg, l3, bg, bg},
      {bg, bg, w2, bg, bg, bg, l2, bg},
      {l2, bg, bg, w2, bg, bg, bg, l2},
      {bg, bg, bg, bg, w2, bg, bg, bg},
      {bg, l3, bg, bg, bg, l3, bg, bg},
      {bg, bg, l2, bg, bg, bg, l2, bg},
      {w3, bg, bg, l2, bg, bg, bg, w2}
    };

    private Dimension checksize() {
      Dimension d = getSize();
      int w = d.width;
      int h = d.height;

      if (w < 1 || h < 1)
        return d;
      if ((offscreen == null) ||
        (w != offscreensize.width) ||
        (h != offscreensize.height)) {
        System.out.println("updating board: " + w + " x " + h + 
                           "\r");

        offscreen = createImage(w, h);
        offscreensize = d;
        offGraphics = offscreen.getGraphics();
        offscreen2 = createImage(w, h);
        offGraphics2 = offscreen2.getGraphics();

        offGraphics.setColor(Color.white);
        offGraphics.fillRect(0,0,w,h);

        // lt is the thickness of the white lines between tiles.
        // gaps is the sum of all the whitespace.
        // lw, lh are the dimensions of the tiles.
        // aw, ah are the dimensions of the entire board
        // lm, tm are the left and top margin to center aw, ah in 
                                                       the applet.

        lt = 1 + w / 400;
        int gaps = lt * 20;

        lw = (w - gaps) / 15;
        lh = (h - gaps - lt * 2) / 16; // compensating for tray 
                                                         height;
        aw = lw * 15 + gaps;
        ah = lh * 15 + gaps;
        lm = (w - aw) / 2 + lt;
        tm = (h - ah - (lt * 2 + lh)) / 2 + lt;
        offGraphics.setColor(Color.black);
        offGraphics.fillRect(lm,tm,aw-2*lt,ah-2*lt);
        lm += lt;
        tm += lt;
        offGraphics.setColor(Color.white);
        offGraphics.fillRect(lm,tm,aw-4*lt,ah-4*lt);
        lm += lt;
        tm += lt;
        int sfh = (lh > 30) ? lh / 4 : lh / 2;
        Font font = new Font("SansSerif", Font.PLAIN, sfh);
        offGraphics.setFont(font);
        for (int j = 0, y = tm; j < 15; j++, y += lh + lt) {
          for (int i = 0, x = lm; i < 15; i++, x += lw + lt) {
            Color c = tiles[j < 8 ? j : 14 - j][i < 8 ? i : 14 - i];
            offGraphics.setColor(c);
            offGraphics.fillRect(x, y, lw, lh);
            offGraphics.setColor(Color.black);
            if (lh > 30) {
              String td = (c == w2 || c == l2) ? "DOUBLE" :
                          (c == w3 || c == l3) ? "TRIPLE" : null;
              String wl = (c == l2 || c == l3) ? "LETTER" :
                          (c == w2 || c == w3) ? "WORD" : null;
              if (td != null) {
                center(offGraphics, td, x, y + 2 + sfh, lw);
                center(offGraphics, wl, x, y + 2 * (2 + sfh), lw);
                center(offGraphics, "SCORE", x, y + 3 * (2 + sfh),
                                                              lw);
              }
            } else {
              String td = (c == w2 || c == l2) ? "2" :
                          (c == w3 || c == l3) ? "3" : null;
              String wl = (c == l2 || c == l3) ? "L" :
                          (c == w2 || c == w3) ? "W" : null;
              if (td != null) {
                center(offGraphics, td + wl, x,
                  y + (lh - sfh) * 4 / 10 + sfh, lw);
              }
            }
          }
        }
        Color c = new Color(255, 255, 200);
        offGraphics.setColor(c);
        offGraphics.fillRect(lm, tm + ah - 3 * lt, 7 * (lw + lt), 
                             lh + 2 * lt);

        Letter.resize(lw, lh);

        // if we already have some letters, place them.
        for (int i = 0; i < 7; i++) {
          if (tray[i] != null) {
            moveToTray(tray[i], i);
          }
        }
        paintScore();
      }
      return d;
    }

center( )
center( ) is a convenience routine that checksize( ) uses to center the “Double Letter Score” text.

    private void center(Graphics g, String s, int x, int y, int w) {
      x += (w - g.getFontMetrics().stringWidth(s)) / 2;
      g.drawString(s, x, y);
    }

paintScore( )
The paintScore( ) method paints the two players’ scores or just the one score in single-player mode.

    private void paintScore() {
      int x = lm + (lw + lt) * 7 + lm;
      int y = tm + ah - 3 * lt;
      int h = lh + 2 * lt;
      Font font = new Font("TimesRoman", Font.PLAIN, h/2);
      offGraphics.setFont(font);
      FontMetrics fm = offGraphics.getFontMetrics();

      offGraphics.setColor(Color.white);
      offGraphics.fillRect(x, y, aw, h);
      offGraphics.setColor(Color.black);
      if (others_name == null) {
        int y0 = (h - fm.getHeight()) / 2 + fm.getAscent();
        offGraphics.drawString("Score: " + total_score, x, y + y0);
      } else {
        h/=2;
        int y0 = (h - fm.getHeight()) / 2 + fm.getAscent();
        offGraphics.drawString(name + ": " + total_score, x, y +
                               y0);
        offGraphics.drawString(others_name + ": " + others_score,
                               x, y + h + y0);
      }
    }

    private int x0, y0, w0, h0;

selectLetter( )
The selectLetter( ) method checks the mouse position to see if the cursor is over a letter. If so, it stores that in pick and computes how far the mouse was from the upper-left corner of the letter, which is stored in dx, dy. It also remembers the original position of this letter in orig.

    private void selectLetter(int x, int y) {
      pick = LetterHit(x, y);
      if(pick != null) {
        dx = pick.x - x;
        dy = pick.y - y;
        orig.x = pick.x;
        orig.y = pick.y;
      }
      repaint();
    }

dropLetter( )
In dropLetter( ), the user has dropped the letter if he or she was carrying one. It determines which square on the board the letter was over when it was dropped. It then calls moveLetter( ) to attempt to move the letter to that square.

    private void dropLetter(int x, int y) {
      if(pick != null) {
        // find the center of the tile
        x += dx + lw / 2;
        y += dy + lh / 2;
        // find the tile index
        x = (x - lm) / (lw + lt);
        y = (y - tm) / (lh + lt);

        moveLetter(pick, x, y);

        pick = null;
        repaint();
      }
    }

No comments:

Post a Comment