Friday 31 March 2017

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

nameEntered( )
The nameEntered( ) method is called from actionPerformed( ) whenever ENTER is pressed in the original prompt for the user’s name. Any AWT components that might be in the way are removed, and then a new List object, idList, is created to store the names of the other players. The method also adds a button at the top named challenge, then notifies the server that we are here by calling setName( ).

  private void nameEntered(String s) {
    if (s.equals(""))
      return;
    name = s;
    if (ican != null)
      remove(ican);
    if (idList != null)
      remove(idList);
    if (challenge != null)
      remove(challenge);
    idList = new List(10, false);
    add("Center", idList);
    challenge = new Button("Challenge");
    challenge.addActionListener(this);
    add("North", challenge);
    validate();
    server.setName(name);
    showStatus("Wait for other players to arrive.");
    if (topPanel != null)
      remove(topPanel);
  }

wepick( ) and theypick( )
The methods wepick( ) and theypick( ) are simply used to start off the game by picking the seven tiles for each player. It is important that the caller do these in the right order on each side of the challenge, depending on who goes first. The call to bag.takeOut( ) gets a single letter permanently out of the shared bag. The call to board.addLetter( ) places the tile on our tray. For the other side, theypick( ) simply saves the letters in theirs.

  private void wepick() {
    for (int i = 0; i < 7; i++) {
      Letter l = bag.takeOut();
      board.addLetter(l);
    }
  }

  private void theypick() {
    for (int i = 0; i < 7; i++) {
      Letter l = bag.takeOut();
      theirs[i] = l;
    }
  }

start_Game( )
In single-player mode, start_Game( ) pops up the splash screen in a Frame window. It then creates a playing board, passing in no parameters to the constructor, which indicates single-player mode.

In head-to-head mode, we remove the selection list components and add the chat window to the applet. We then add the board and Done button to the applet. Next, we create the bag, and if it is ourturn, wepick( ) is first, then theypick( ). In the case where we don’t have the first turn, we disable the board and the Done button, and theypick( ) is first. We then force the board to repaint, which initializes it.

  private void start_Game(int seed) {
    if (single) {
      Frame popup = new Frame("Scrabblet");
      popup.setSize(400, 300);
      popup.add("Center", ican);
      popup.setResizable(false);
      popup.show();
      board = new Board();
      showStatus("no server found, playing solo");
      ourturn = true;
    } else {
      remove(idList);
      remove(challenge);
      board = new Board(name, others_name);
      chat = new TextField();
      chat.addActionListener(this);
      add("North", chat);
      showStatus("playing against " + others_name);
    }

    add("Center", board);
    done = new Button("Done");
    done.addActionListener(this);
    add("South", done);
    validate();

    bag = new Bag(seed);
    if (ourturn) {
      wepick();
      if (!single)
        theypick();
    } else {
      done.setEnabled(false);
      theypick();
      wepick();
    }
    board.repaint();
  }

challenge_them( )
The challenge_them( ) method is called when the challenge button is clicked. It simply takes the player you had selected in the idList and sends him or her a challenge( ) message. It removes the list and button to be ready for the game to start.

  private void challenge_them() {
    String s = idList.getSelectedItem();
    if (s == null) {
      showStatus("Choose a player from the list then press 
                 Challenge");
    } else {
      remove(challenge);
      remove(idList);
      String destid = s.substring(s.indexOf('(')+1,
                                  s.indexOf(')'));
      showStatus("challenging: " + destid);
      server.challenge(destid); // accept will get called if
                                // they accept.
      validate();
    }
  }

our_turn( )
When the Done button is clicked, our_turn( ) is called. First, it checks to see if we’ve placed tiles in valid locations by calling board.findwords( ) and storing the result in word. If word is null, then something is amiss with the tiles, and the method shows that in the status line. If word is ““, then it knows that there were no tiles in play at the time. In single-player mode, this is ignored. In competition mode, if we click Done twice in a row without any tiles in play, we will pass our turn to our opponent.

If you have played tiles and they are in legal positions, you have finished your turn, so ourturn( ) commits the letters to the board. Notice that commit( ) takes the server as a parameter. It will use this to tell the remote side about the position of each new letter. Then the method replaces the letters you used. In multiplayer mode, we disable ourselves and call server.turn( ) to tell the other player it is his or her turn.

  private void our_turn() {
    String word = board.findwords();
    if (word == null) {
      showStatus("Illegal letter positions");
    } else {
      if ("".equals(word)) {
        if (single)
          return;
        if (seen_pass) {
          done.setEnabled(false);
          server.turn("pass", 0);
          showStatus("You passed");
          seen_pass = false;
        } else {
          showStatus("Press done again to pass");
          seen_pass = true;
          return;
        }
      } else {
        seen_pass = false;
      }
      showStatus(word);
      board.commit(server);
      for (int i = 0; i < 7; i++) {
        if (board.getTray(i) == null) {
          Letter l = bag.takeOut();
          if (l == null)
            showStatus("No more letters");
          else
            board.addLetter(l);
        }
      }
      if (!single) {
        done.setEnabled(false);
        server.turn(word, board.getTurnScore());
      }
      board.repaint();
    }
  }

actionPerformed( )
The actionPerformed( ) method is used to grab input from the various components the applet uses. It handles the Challenge and Done buttons, as well as the name entry field and the chat entry field.

    public void actionPerformed(ActionEvent ae) {
      Object source = ae.getSource();
      if(source == chat) {
        server.chat(chat.getText());
        chat.setText("");
      }
      else if(source == challenge) {
        challenge_them();
      }
      else if(source == done) {
        our_turn();
      }
      else if(source == namefield) {
        TextComponent tc = (TextComponent)source;
        nameEntered(tc.getText());
      }
    }
  }

IntroCanvas.java
The IntroCanvas subclass of Canvas is very simple. It just overrides paint( ) to draw the name of the applet and a brief copyright notice. It creates some custom colors and fonts. The display strings are held in static variables simply for clarity.

  import java.awt.*;
  import java.awt.event.*;

  class IntroCanvas extends Canvas {
    private Color pink = new Color(255, 200, 200);
    private Color blue = new Color(150, 200, 255);
    private Color yellow = new Color(250, 220, 100);

    private int w, h;
    private int edge = 16;
    private static final String title = "Scrabblet";
    private static final String name =
                "Copyright 1999 - Patrick Naughton";
    private static final String book =
                "Chapter 32 from 'Java: The Complete Reference'";
    private Font namefont, titlefont, bookfont;

    IntroCanvas() {
      setBackground(yellow);
      titlefont = new Font("SansSerif", Font.BOLD, 58);
      namefont = new Font("SansSerif", Font.BOLD, 18);
      bookfont = new Font("SansSerif", Font.PLAIN, 12);
      addMouseListener(new MyMouseAdapter());
    }

d( )
The private method d( ) is a convenience method that paints centered text with an optional isometric offset. This is used to give the main title a highlight/shadow effect by drawing a white string up and to the left by 1, a black string down and to the right by 1, and then drawing the string one last time in pink, not offset at all.

    private void d(Graphics g, String s, Color c, Font f, int y,
                   int off) {
      g.setFont(f);
      FontMetrics fm = g.getFontMetrics();
      g.setColor(c);
      g.drawString(s, (w - fm.stringWidth(s)) / 2 + off, y + off);
    }

    public void paint(Graphics g) {
      Dimension d = getSize();
      w = d.width;
      h = d.height;
      g.setColor(blue);
      g.fill3DRect(edge, edge, w - 2 * edge, h - 2 * edge, true);
      d(g, title, Color.black, titlefont, h / 2, 1);
      d(g, title, Color.white, titlefont, h / 2, -1);
      d(g, title, pink, titlefont, h / 2, 0);
      d(g, name, Color.black, namefont, h * 3 / 4, 0);
      d(g, book, Color.black, bookfont, h * 7 / 8, 0);
    }

mousePressed( )
In the following code fragment, notice that MyMouseAdapter is an inner class that extends MouseAdapter. It overrides the mousePressed( ) method to cause this canvas’ parent to hide( ) if it is clicked on. This is only useful in single-player mode to dismiss the pop-up frame.

    class MyMouseAdapter extends MouseAdapter {
      public void mousePressed(MouseEvent me) {
        ((Frame)getParent()).setVisible(false);
      }
    }
  }

Board.java
The Board class encapsulates most of the game logic as well as the look and feel of the board. It is the biggest class in the game, weighing in at over 500 lines of code. There are several private variables that store the game state. The 15×15 array of Letter named board is used to store the tiles on each square of the board. The tray array holds the Letters that are currently on our tray. Remember that the Scrabblet applet class holds the seven Letters from our opponent. The Point objects orig and here are used to remember letter positions. The name and others_name variables are used simply to display names for the scoreboard. In single-player mode, both will be null. The two players’ scores are stored in total_score and others_score, while our last turn’s result is stored in turn_score. The two constructors set up the names of the players, or leave them blank in single-player mode.

  import java.awt.*;
  import java.awt.event.*;

  class Board extends Canvas {
    private Letter board[][] = new Letter[15][15];
    private Letter tray[] = new Letter[7];
    private Point orig = new Point(0,0);
    private Point here = new Point(0,0);
    private String name;
    private int total_score = 0;
    private int turn_score = 0;
    private int others_score = 0;
    private String others_name = null;

    Board(String our_name, String other_name) {
      name = our_name;
      others_name = other_name;
      addMouseListener(new MyMouseAdapter());
      addMouseMotionListener(new MyMouseMotionAdapter());
    }

    Board() {
      addMouseListener(new MyMouseAdapter());
      addMouseMotionListener(new MyMouseMotionAdapter());
    }

othersTurn( ), getTurnScore( ), and getTray( )
These three methods are used to control the access to several private variables. First, othersTurn( ) is called by the applet when the other player finishes a turn. It increments the player’s score and repaints that area of the board to reflect the change. The getTurnScore( ) method simply returns the saved last turn’s score, after making sure the scoreboard is painted with the correct value. The applet uses this method to pass the score to our opponent, where it will eventually call othersTurn( ) on the remote machine. The getTray( ) method simply provides a read-only access to the private tray array.

    void othersTurn(int score) {
      others_score += score;
      paintScore();
      repaint();
    }

    int getTurnScore() {
      paintScore();
      return turn_score;
    }

    Letter getTray(int i) {
      return tray[i];
    }

No comments:

Post a Comment