import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import java.net.*;
import java.util.StringTokenizer;
public class ReversiBoard extends Canvas {
private static final int BLACK = -1;
private static final int WHITE = 1;
private static final int EMPTY = 0;
private static final int LAST_BLACK = -2;
private static final int LAST_WHITE = 2;
private static final int LEGAL_MOVE = 99;
private static final int SELECTED_MOVE = 98;
private static final int TABLE_BORDER = 10;
private int[][] pieces = new int[][] {
{ 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0},
};
private Socket socket;
private BufferedReader in;
private PrintWriter out;
private int hoverX = -1;
private int hoverY = -1;
private Label statusLabel;
private String host;
private int color;
private boolean aiMoving = false;
private int getSquareAtX(int x) {
if (x < TABLE_BORDER) {
return -1;
}
int square = (x - TABLE_BORDER) * 8 / (getSize().width - TABLE_BORDER * 2);
if (square > 7) {
return -1;
}
return square;
}
private int getSquareAtY(int y) {
if (y < TABLE_BORDER) {
return -1;
}
int square = (y - TABLE_BORDER) * 8 / (getSize().height - TABLE_BORDER * 2);
if (square > 7) {
return -1;
}
return square;
}
public ReversiBoard(Label statusLabel, String host) {
this.statusLabel = statusLabel;
this.host = host;
addMouseMotionListener(new MouseMotionAdapter() {
public void mouseMoved(MouseEvent e) {
int newHoverX = getSquareAtX(e.getX());
int newHoverY = getSquareAtY(e.getY());
if (newHoverX < 0 || newHoverY < 0 || pieces[newHoverY][newHoverX] != LEGAL_MOVE) {
newHoverX = -1;
newHoverY = -1;
}
if (hoverX != newHoverX || hoverY != newHoverY) {
int oldHoverX = hoverX;
int oldHoverY = hoverY;
hoverX = newHoverX;
hoverY = newHoverY;
repaintSquare(oldHoverX,oldHoverY);
repaintSquare(hoverX,hoverY);
}
}
});
addMouseListener(new MouseAdapter() {
public void mouseExited(MouseEvent e) {
if (hoverX != -1 || hoverY != -1) {
int oldHoverX = hoverX;
int oldHoverY = hoverY;
hoverX = -1;
hoverY = -1;
repaintSquare(oldHoverX,oldHoverY);
}
}
public void mouseClicked(MouseEvent e) {
synchronized(this) {
if (aiMoving) {
return;
}
}
int x = getSquareAtX(e.getX());
int y = getSquareAtY(e.getY());
if (x >= 0 && y >= 0) {
if (pieces[y][x] != 99) {
return;
}
int moveNum = 0;
for (int sy = 0; sy < 8; sy++) {
for (int sx = 0; sx < 8; sx++) {
if (pieces[sy][sx] == LAST_BLACK) {
pieces[sy][sx] = BLACK;
repaintSquare(sx,sy);
}
else if (pieces[sy][sx] == LAST_WHITE) {
pieces[sy][sx] = WHITE;
repaintSquare(sx,sy);
}
else if (pieces[sy][sx] == LEGAL_MOVE) {
moveNum++;
if (sy == y && sx == x) {
pieces[sy][sx] = SELECTED_MOVE;
hoverX = -1;
hoverY = -1;
out.println(moveNum);
repaintSquare(sx,sy);
doAI();
return;
}
}
}
}
}
}
});
}
public void clearBoard() {
for (int y = 0; y < 8; y++) {
for (int x = 0; x < 8; x++) {
pieces[y][x] = 0;
}
}
repaint();
}
public void connectAsColor(int color) throws IOException {
System.out.println("Got here");
synchronized(this) {
if (aiMoving) {
return;
}
}
this.color = color;
clearBoard();
if (socket != null) {
try {socket.close();} catch (IOException ex) {}
socket = null;
in = null;
out = null;
}
socket = new Socket(host,9000);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(),true);
StringBuffer sb = new StringBuffer();
while (true) {
int ch = in.read();
if (ch < 0) {
throw new EOFException();
}
sb.append((char) ch);
if (sb.toString().indexOf("Your choice: ") >= 0) {
out.println("999");
break;
}
}
doAI();
}
public boolean process(String s) {
System.out.println("Got Command: " + s);
StringTokenizer st = new StringTokenizer(s," ");
if (!st.hasMoreTokens()) {
return false;
}
String command = st.nextToken();
if (command.equals("CHOOSECOLOR")) {
out.println(color);
return false;
}
else if (command.equals("BOARDSTATE")) {
for (int y = 0; y < 8; y++) {
for (int x = 0; x < 8; x++) {
int newPiece = Integer.parseInt(st.nextToken());
if (newPiece != pieces[y][x]) {
pieces[y][x] = newPiece;
repaintSquare(x,y);
}
}
}
return false;
}
else if (command.equals("YOURMOVE")) {
statusLabel.setText("Your turn.");
statusLabel.setForeground(Color.red);
st.nextToken();
while (st.hasMoreTokens()) {
int y = Integer.parseInt(st.nextToken());
int x = Integer.parseInt(st.nextToken());
pieces[y - 1][x - 1] = LEGAL_MOVE;
}
return true;
}
else if (command.equals("NOMOVES")) {
statusLabel.setText("No available moves.");
statusLabel.setForeground(Color.blue);
return false;
}
else if (command.equals("GAMEOVER")) {
int black = Integer.parseInt(st.nextToken());
int white = Integer.parseInt(st.nextToken());
if (black > white) {
statusLabel.setText("Game over. Black wins " + black + " to " + white + ".");
}
else if (white > black) {
statusLabel.setText("Game over. White wins " + white + " to " + black + ".");
}
else {
statusLabel.setText("Game over. Tied at " + black + " discs.");
}
statusLabel.setForeground(Color.red);
out.println();
return true;
}
else return false;
}
public void repaintSquare(int x, int y) {
if (x < 0 || y < 0) {
return;
}
int width = getSize().width - TABLE_BORDER * 2;
int height = getSize().height - TABLE_BORDER * 2;
int px = TABLE_BORDER + x * width / 8;
int py = TABLE_BORDER + y * height / 8;
int pwidth = width / 8;
int pheight = height / 8;
repaint(px,py,pwidth,pheight);
}
public void paint(Graphics g) {
int x = 0;
int y = 0;
int width = getSize().width;
int height = getSize().height;
g.setColor(Color.black);
g.fillRect(x,y,width,height);
x += TABLE_BORDER;
y += TABLE_BORDER;
width -= TABLE_BORDER * 2;
height -= TABLE_BORDER * 2;
g.setColor(new Color(64,128,64));
g.fillRect(x,y,width,height);
g.setColor(new Color(99,157,109));
for (int i=0; i < 8; i++) {
g.drawLine(x,y + 1 + i * height / 8,x + width,y + 1 + i * height / 8);
g.drawLine(x + 1 + i * width / 8,y,x + 1 + i * width / 8,y + height);
}
for (int by = 0; by < 8; by++) {
for (int bx = 0; bx < 8; bx++) {
int piece = pieces[by][bx];
if (piece == EMPTY) {
continue;
}
int px = x + bx * width / 8;
int py = y + by * height / 8;
int pwidth = width / 8;
int pheight = height / 8;
if (piece == BLACK || piece == LAST_BLACK) { g.setColor(Color.black);
g.fillOval(px + 5,py + 5,pwidth - 10,pheight - 10);
g.setColor(Color.black);
g.drawOval(px + 5,py + 5,pwidth - 10,pheight - 10);
if (piece == LAST_BLACK) {
g.setColor(Color.white);
g.drawLine(px + pwidth / 2 - 3,
py + pheight / 2 - 3,
px + pwidth / 2 + 3,
py + pheight / 2 + 3
);
g.drawLine(px + pwidth / 2 + 3,
py + pheight / 2 - 3,
px + pwidth / 2 - 3,
py + pheight / 2 + 3
);
}
}
else if (piece == WHITE || piece == LAST_WHITE) { g.setColor(Color.white);
g.fillOval(px + 5,py + 5,pwidth - 10,pheight - 10);
g.setColor(Color.black);
g.drawOval(px + 5,py + 5,pwidth - 10,pheight - 10);
if (piece == LAST_WHITE) {
g.setColor(Color.black);
g.drawLine(px + pwidth / 2 - 3,
py + pheight / 2 - 3,
px + pwidth / 2 + 3,
py + pheight / 2 + 3
);
g.drawLine(px + pwidth / 2 + 3,
py + pheight / 2 - 3,
px + pwidth / 2 - 3,
py + pheight / 2 + 3
);
}
}
else if (piece == SELECTED_MOVE ||
(piece == LEGAL_MOVE && hoverX == bx && hoverY == by)) {
g.setColor(new Color(57,115,57));
g.fillRect(x + bx * width / 8,y + by * height / 8,pwidth + 1,pheight + 1);
g.setColor(new Color(45,90,45));
g.drawLine(x + bx * width / 8 + 1,
y + by * height / 8,
x + bx * width / 8 + 1,
y + (by + 1) * height / 8);
g.drawLine(x + bx * width / 8,
y + by * height / 8 + 1,
x + (bx + 1) * width / 8,
y + by * height / 8 + 1);
if (piece == SELECTED_MOVE) {
g.setColor(Color.white);
g.drawLine(px + pwidth / 2 - 3,
py + pheight / 2 - 3,
px + pwidth / 2 + 3,
py + pheight / 2 + 3
);
g.drawLine(px + pwidth / 2 + 3,
py + pheight / 2 - 3,
px + pwidth / 2 - 3,
py + pheight / 2 + 3
);
}
}
}
}
g.setColor(Color.black);
for (int i=0; i < 8; i++) {
g.drawLine(x,y + i * height / 8,x + width,y + i * height / 8);
g.drawLine(x + i * width / 8,y,x + i * width / 8,y + height);
}
}
public void update(Graphics g) {
paint(g);
}
public void doAI() {
new AIThread().start();
}
private class AIThread extends Thread {
public AIThread() {
synchronized(ReversiBoard.this) {
if (aiMoving) {
return;
}
aiMoving = true;
}
statusLabel.setText("Computer is thinking...");
statusLabel.setForeground(Color.black);
new Thread() {
public void run() {
waitForAI();
}
}.start();
}
private void waitForAI() {
try {
while (true) {
String line = in.readLine();
if (line == null) {
statusLabel.setText("Connection to server lost...");
statusLabel.setForeground(Color.red);
return;
}
if (process(line)) {
return;
}
}
}
catch (IOException ex) {
statusLabel.setText(ex.toString());
statusLabel.setForeground(Color.red);
}
finally {
aiMoving = false;
}
}
}
}