Friday 31 March 2017

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

hit( )
The hit( ) method returns true if the xp,yp pair passed in falls inside the bounds of this Letter.

    boolean hit(int xp, int yp) {
      return (xp >= x && xp < x + w && yp >= y && yp < y + h);
    }

validate( )
The validate( ) method is used to load the fonts to find out how big the letters are, to decide where to paint them. This information is cached in the private variables discussed earlier. The results of these calculations are used next in paint( ).

    private int font_ascent;
    void validate(Graphics g) {
      FontMetrics fm;
      if (h != lasth) {
        font = new Font("SansSerif", Font.BOLD, (int)(h * .6));
        g.setFont(font);
        fm = g.getFontMetrics();
        font_ascent = fm.getAscent();

        y0 = (h - font_ascent) * 4 / 10 + font_ascent;

        smfont = new Font("SansSerif", Font.BOLD, (int)(h * .3));
        g.setFont(smfont);
        fm = g.getFontMetrics();
        ys0 = y0 + fm.getAscent() / 2;
        lasth = h;
      }
      if (!valid) {
        valid = true;
        g.setFont(font);
        fm = g.getFontMetrics();
        w0 = fm.stringWidth(symbol);
        g.setFont(smfont);
        fm = g.getFontMetrics();
        ws0 = fm.stringWidth("" + points);
        int slop = w - (w0 + gap + ws0);
        x0 = slop / 2;
        if (x0 < 1)
          x0 = 1;
        xs0 = x0 + w0 + gap;
        if (points > 9)
          xs0--;
      }
    }

paint( )
The paint( ) method is called by the board. It passes in an integer, i, which is one of NORMAL, BRIGHT, or DIM from this class. That is used as an index into the colors array to select the base color. A sequence of rectangles is filled to create the appearance of a 3-D highlighted and shadowed button. If points is greater than zero, indicating a nonblank letter, then the main letter is drawn, and its point value is drawn next to it.

    void paint(Graphics g, int i) {
      Color c[] = colors[i];
      validate(g);
      g.setColor(c[NORMAL]);
      g.fillRect(x, y, w, h);
      g.setColor(c[BRIGHT]);
      g.fillRect(x, y, w - 1, 1);
      g.fillRect(x, y + 1, 1, h - 2);
      g.setColor(Color.black);
      g.fillRect(x, y + h - 1, w, 1);
      g.fillRect(x + w - 1, y, 1, h - 1);
      g.setColor(c[DIM]);
      g.fillRect(x + 1, y + h - 2, w - 2, 1);
      g.fillRect(x + w - 2, y + 1, 1, h - 3);
      g.setColor(Color.black);
      if (points > 0) {
        g.setFont(font);
        g.drawString(symbol, x + x0, y + y0);
        g.setFont(smfont);
        g.drawString("" + points, x + xs0, y + ys0);
      }
    }
  }


ServerConnection.java

The last class in the client side of this applet is ServerConnection, which encapsulates the communication with the server and our opponent. There are several variables declared at the beginning of the class. The socket port number to attach to on the server is 6564. CRLF is the Internet constant string representing end-of-line. The I/O streams from and to the server are in and out, respectively. The unique ID by which this connection is known on the server is stored in id. The ID that we are connected to as an opponent is stored in toid. The Scrabblet applet we are connecting for is scrabblet.

  import java.io.*;
  import java.net.*;
  import java.util.*;

  class ServerConnection implements Runnable {
    private static final int port = 6564;
    private static final String CRLF = "\r\n";
    private BufferedReader in;
    private PrintWriter out;
    private String id, toid = null;
    private Scrabblet scrabblet;

ServerConnection( )
The ServerConnection constructor takes the name of an Internet site to attach to and attempts to open a socket to the right port on that host. If that succeeds, it wraps an InputStreamReader and a BufferedReader around the input and a PrintWriter around the output. If the connection fails, an exception is thrown to the caller.

    public ServerConnection(Scrabblet sc, String site) throws
      IOException {
      scrabblet = sc;
      Socket server = new Socket(site, port);
      in = new BufferedReader(new
               InputStreamReader(server.getInputStream()));
      out = new PrintWriter(server.getOutputStream(), true);
    }

readline( )
The readline( ) method is merely a convenience function that converts the IOException from a readLine( ) into a simple null return.

    private String readline() {
      try {
        return in.readLine();
      } catch (IOException e) {
        return null;
      }
    }

setName( ) and delete( )
The setName( ) method tells the server to associate this name with us, and the delete( ) method is used to remove us from any lists the server is keeping.

    void setName(String s) {
      out.println("name " + s);
    }

    void delete() {
      out.println("delete " + id);
    }

setTo( ) and send( )
The setTo( ) method binds the ID of the opponent. Future send( ) calls will go to this player.

    void setTo(String to) {
      toid = to;
    }

    void send(String s) {
      if (toid != null)
        out.println("to " + toid + " " + s);
    }

challenge( ), accept( ), chat( ), move( ), turn( ), and quit( )
The following short methods send one-line messages from this client to the server, which will in turn send those messages on to our opponent. The challenge message is used to initiate starting a game, and accept is sent in response to a challenge. For each letter that moves, the move message is sent, and then the turn message is sent at the end of each turn. If the client quits or leaves the page with the applet on it, it sends the quit message.

    void challenge(String destid) {
      setTo(destid);
      send("challenge " + id);
    }

    void accept(String destid, int seed) {
      setTo(destid);
      send("accept " + id + " " + seed);
    }

    void chat(String s) {
      send("chat " + id + " " + s);
    }

    void move(String letter, int x, int y) {
      send("move " + letter + " " + x + " " + y);
    }

    void turn(String words, int score) {
      send("turn " + score + " " + words);
    }

    void quit() {
      send("quit " + id); // tell other player
      out.println("quit"); // unhook
    }

start( )
The next method simply starts the thread that manages the client side of the network.

    // reading from server...

    private Thread t;

    void start() {
      t = new Thread(this);
      t.start();
    }

Keywords
The static variables and static block shown here are used to initialize the keys Hashtable with a mapping between the strings in keystrings and their position in the array—for example, keys.get(“move”) == MOVE. The lookup( ) method takes care of unpacking the Integer objects into the right int, with –1 meaning the keyword was not found.

    private static final int ID = 1;
    private static final int ADD = 2;
    private static final int DELETE = 3;
    private static final int MOVE = 4;
    private static final int CHAT = 5;
    private static final int QUIT = 6;
    private static final int TURN = 7;
    private static final int ACCEPT = 8;
    private static final int CHALLENGE = 9;
    private static Hashtable keys = new Hashtable();
    private static String keystrings[] = {
      "", "id", "add", "delete", "move", "chat",
      "quit", "turn", "accept", "challenge"
    };
    static {
      for (int i = 0; i < keystrings.length; i++)
        keys.put(keystrings[i], new Integer(i));
    }

    private int lookup(String s) {
      Integer i = (Integer) keys.get(s);
      return i == null ? -1 : i.intValue();
    }

run( )
run( ) is the main loop of the game’s connection to the server. It goes into a blocking call to readline( ) that will return with a String whenever a line of text comes from the server. It uses a StringTokenizer to break the line into words. The switch statement dispatches us to the right code, based on the first word in the input line. Each of the keywords in the protocol parses the input line differently, and most of them make method calls back into the Scrabblet class to do their work.

    public void run() {
      String s;
      StringTokenizer st;
      while ((s = readline()) != null) {
        st = new StringTokenizer(s);
        String keyword = st.nextToken();
        switch (lookup(keyword)) {
        default:
          System.out.println("bogus keyword: " + keyword + "\r");
          break;
        case ID:
          id = st.nextToken();
          break;
        case ADD: {
            String id = st.nextToken();
            String hostname = st.nextToken();
            String name = st.nextToken(CRLF);
            scrabblet.add(id, hostname, name);
          }
          break;
        case DELETE:
          scrabblet.delete(st.nextToken());
          break;
        case MOVE: {
            String ch = st.nextToken();
            int x = Integer.parseInt(st.nextToken());
            int y = Integer.parseInt(st.nextToken());
            scrabblet.move(ch, x, y);
          }
          break;
        case CHAT: {
            String from = st.nextToken();
            scrabblet.chat(from, st.nextToken(CRLF));
          }
          break;
        case QUIT: {
            String from = st.nextToken();
            scrabblet.quit(from);
          }
          break;
        case TURN: {
            int score = Integer.parseInt(st.nextToken());
            scrabblet.turn(score, st.nextToken(CRLF));
          }
          break;
        case ACCEPT: {
            String from = st.nextToken();
            int seed = Integer.parseInt(st.nextToken());
            scrabblet.accept(from, seed);
          }
          break;
        case CHALLENGE: {
            String from = st.nextToken();
            scrabblet.challenge(from);
          }
          break;
        }
      }
    }
  }

No comments:

Post a Comment