📄 board.java
字号:
/*******************************************************************************
* Copyright (c) 2004 Berthold Daum.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* Berthold Daum
*******************************************************************************
* Hex-7
* Version 2.0
* www.mazeworks.com
*
* Copyright (c) 2002 David Herzog
* All Rights Reserved.
*******************************************************************************/
package com.bdaum.Hex.game;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Display;
/*******************************************************************************
* BOARD ****** controls board status, rules of the game, tests for win by
* either side
*/
public final class Board implements PaintListener, MouseListener {
static final int SW = 1, SE = 2, E = 3, NE = 4, NW = 5, W = 6, SW_B = 7,
S_B = 8, SE_B = 9, NE_B = 10, N_B = 11, NW_B = 12;
private boolean visited[][] = new boolean[Game.SIZE][Game.SIZE];
private int stack[] = new int[25], stackPtr = 0;
private int cells[][] = new int[Game.SIZE][Game.SIZE];
private Canvas canvas;
private Game game;
private Display display;
private Color white, black, gray, green, cyan;
// Constructor
public Board(Canvas canvas, Game game) {
this.game = game;
this.canvas = canvas;
display = canvas.getDisplay();
white = display.getSystemColor(SWT.COLOR_WHITE);
black = display.getSystemColor(SWT.COLOR_BLACK);
gray = display.getSystemColor(SWT.COLOR_GRAY);
green = display.getSystemColor(SWT.COLOR_DARK_GREEN);
cyan = display.getSystemColor(SWT.COLOR_DARK_CYAN);
canvas.addPaintListener(this);
canvas.addMouseListener(this);
}
boolean isEmpty(int i, int j) {
return (cells[i][j] == Game.EMPTY);
}
boolean isEmpty(Point h) {
return (cells[h.x][h.y] == Game.EMPTY);
}
boolean isWhite(int i, int j) {
return (cells[i][j] == Game.WHITE);
}
boolean isBlack(int i, int j) {
return (cells[i][j] == Game.BLACK);
}
boolean isColor(int i, int j, int color) {
return (cells[i][j] == color);
}
int getHex(int i, int j) {
return cells[i][j];
}
void setEmpty(int i, int j) {
cells[i][j] = Game.EMPTY;
}
void setEmpty(Point h) {
cells[h.x][h.y] = Game.EMPTY;
}
public boolean setHex(int i, int j, int color) {
if ((i >= 0) && (i < Game.SIZE) && (j >= 0) && (j < Game.SIZE)
&& (isEmpty(i, j))) {
cells[i][j] = color;
return true;
} else
return false;
}
public boolean setHex(Point p, int color) {
return setHex(p.x, p.y, color);
}
// make the piece blink for computer move
void computerMove(Point p, int color) {
if (setHex(p, color) && (game.getPly() != 1)) {
draw();
game.sleep(400);
setEmpty(p);
draw();
game.sleep(400);
setHex(p, color);
}
}
boolean isVisited(int i, int j) {
return visited[i][j];
}
void setVisited(int i, int j, boolean v) {
visited[i][j] = v;
}
void clearVisited() {
for (int i = 0; i < Game.SIZE; i++)
for (int j = 0; j < Game.SIZE; j++)
visited[i][j] = false;
}
// main routine to check for win
public boolean isWin(int color) {
clearVisited();
if (color == Game.WHITE)
return isWinWhite();
else
return isWinBlack();
}
private boolean isWinWhite() {
int x = 0, y = 0;
for (int i = 0; i < Game.SIZE; i++) {
if ((cells[i][0] == Game.WHITE) && (!visited[i][0])) {
x = i;
y = 0;
stackPtr = 0;
visited[x][y] = true;
if (isWinDFS(x, y, Game.WHITE))
return true;
}
}
return false;
}
private boolean isWinBlack() {
int x = 0, y = 0;
for (int j = 0; j < Game.SIZE; j++) {
if ((cells[0][j] == Game.BLACK) && (!visited[0][j])) {
x = 0;
y = j;
stackPtr = 0;
visited[x][y] = true;
if (isWinDFS(x, y, Game.BLACK))
return true;
}
}
return false;
}
private boolean isWinDFS(int x, int y, int color) {
int direction = 0;
while (true) {
// look for a link
direction = scanLinks(x, y, color);
if (direction != 0) {
// found - make it current
stack[stackPtr++] = direction;
switch (direction) {
case SW:
y++;
break;
case SE:
x++;
y++;
break;
case E:
x++;
break;
case NE:
y--;
break;
case NW:
x--;
y--;
break;
case W:
x--;
break;
}
// check for win
if (color == Game.WHITE) {
if (y == Game.SIZE - 1)
return true;
} else if (x == Game.SIZE - 1)
return true;
visited[x][y] = true;
} else {
// no path, try next start point
if (stackPtr == 0)
return false;
// at end of path, back up
direction = stack[--stackPtr];
switch (direction) {
case SW:
y--;
break;
case SE:
x--;
y--;
break;
case E:
x--;
break;
case NE:
y++;
break;
case NW:
x++;
y++;
break;
case W:
x++;
break;
}
}
}
}
int scanLinks(int x, int y, int color) {
int dir = 0;
// search for unvisited links
if ((isLinkSW(x, y, color)) && (!visited[x][y + 1]))
dir = SW;
else if ((isLinkSE(x, y, color)) && (!visited[x + 1][y + 1]))
dir = SE;
else if ((isLinkE(x, y, color)) && (!visited[x + 1][y]))
dir = E;
else if ((isLinkNE(x, y, color)) && (!visited[x][y - 1]))
dir = NE;
else if ((isLinkNW(x, y, color)) && (!visited[x - 1][y - 1]))
dir = NW;
else if ((isLinkW(x, y, color)) && (!visited[x - 1][y]))
dir = W;
return dir;
}
// links
boolean isLinkSW(int i, int j, int color) {
if ((j < Game.SIZE - 1) && (isColor(i, j + 1, color)))
return true;
else
return false;
}
boolean isLinkSE(int i, int j, int color) {
if ((i < Game.SIZE - 1) && (j < Game.SIZE - 1)
&& (isColor(i + 1, j + 1, color)))
return true;
else
return false;
}
boolean isLinkE(int i, int j, int color) {
if ((i < Game.SIZE - 1) && (isColor(i + 1, j, color)))
return true;
else
return false;
}
boolean isLinkNE(int i, int j, int color) {
if ((j > 0) && (isColor(i, j - 1, color)))
return true;
else
return false;
}
boolean isLinkNW(int i, int j, int color) {
if ((i > 0) && (j > 0) && (isColor(i - 1, j - 1, color)))
return true;
else
return false;
}
boolean isLinkW(int i, int j, int color) {
if ((i > 0) && (isColor(i - 1, j, color)))
return true;
else
return false;
}
// Bridge methods are used by static evaluator
int scanBridges(int x, int y, int color) {
int dir = 0;
// search for unvisited bridges
if ((isBridgeSW(x, y, color)) && (!visited[x - 1][y + 1]))
dir = SW_B;
else if ((isBridgeS(x, y, color)) && (!visited[x + 1][y + 2]))
dir = S_B;
else if ((isBridgeSE(x, y, color)) && (!visited[x + 2][y + 1]))
dir = SE_B;
else if ((isBridgeNE(x, y, color)) && (!visited[x + 1][y - 1]))
dir = NE_B;
else if ((isBridgeN(x, y, color)) && (!visited[x - 1][y - 2]))
dir = N_B;
else if ((isBridgeNW(x, y, color)) && (!visited[x - 2][y - 1]))
dir = NW_B;
return dir;
}
// bridges
boolean isBridgeSW(int i, int j, int color) {
if ((i > 0) && (j < Game.SIZE - 1) && (isColor(i - 1, j + 1, color))
&& (isEmpty(i - 1, j)) && (isEmpty(i, j + 1)))
return true;
else
return false;
}
boolean isBridgeS(int i, int j, int color) {
if ((i < Game.SIZE - 1) && (j < Game.SIZE - 2)
&& (isColor(i + 1, j + 2, color)) && (isEmpty(i, j + 1))
&& (isEmpty(i + 1, j + 1)))
return true;
else
return false;
}
boolean isBridgeSE(int i, int j, int color) {
if ((i < Game.SIZE - 2) && (j < Game.SIZE - 1)
&& (isColor(i + 2, j + 1, color)) && (isEmpty(i + 1, j))
&& (isEmpty(i + 1, j + 1)))
return true;
else
return false;
}
boolean isBridgeNE(int i, int j, int color) {
if ((i < Game.SIZE - 1) && (j > 0) && (isColor(i + 1, j - 1, color))
&& (isEmpty(i + 1, j)) && (isEmpty(i, j - 1)))
return true;
else
return false;
}
boolean isBridgeN(int i, int j, int color) {
if ((i > 0) && (j > 1) && (isColor(i - 1, j - 2, color))
&& (isEmpty(i, j - 1)) && (isEmpty(i - 1, j - 1)))
return true;
else
return false;
}
boolean isBridgeNW(int i, int j, int color) {
if ((i > 1) && (j > 0) && (isColor(i - 2, j - 1, color))
&& (isEmpty(i - 1, j)) && (isEmpty(i - 1, j - 1)))
return true;
else
return false;
}
/**
* Redraw game board
*/
public void draw() {
canvas.getDisplay().syncExec(new Runnable() {
public void run() {
// Signal partial redraw
canvas.redraw(1, 1, 10000, 10000, false);
}
});
}
// Edge length of a hexagon (= outer radius)
private static final int OUTER_RAD = 30;
// Inner radius of a hexagon
private static final int INNER_RAD = (int) (Math.sqrt(0.75d) * OUTER_RAD);
// Outline of a hexagon
private static final int[] CELL = new int[] { -OUTER_RAD, 0,
-OUTER_RAD / 2, -INNER_RAD, OUTER_RAD / 2, -INNER_RAD, OUTER_RAD,
0, OUTER_RAD / 2, INNER_RAD, -OUTER_RAD / 2, INNER_RAD };
// Horizontal distance between cells
private static final int XDIST = OUTER_RAD * 3 / 2;
// Horizontal offset of the game board
private static final int XOFF = Game.SIZE * OUTER_RAD + 150;
// Vertical offset of the game board
private static final int YOFF = 100;
// Horizontal border width of game board
private static final int XMARGIN = 20;
// Vertical border width of game board
private static final int YMARGIN = 15;
// Radius of a game button
private static final int BUTTON_RAD = OUTER_RAD / 2;
// Corner positions of the game board
private static final Point TOP = hexToPixel(0, 0);
private static final Point BOTTOM = hexToPixel(Game.SIZE, Game.SIZE);
private static final Point RIGHT = hexToPixel(Game.SIZE, 0);
private static final Point LEFT = hexToPixel(0, Game.SIZE);
// Outlines of the game board edges
private static final int[] WHITEBORDER = new int[] { LEFT.x - XMARGIN,
LEFT.y - INNER_RAD, RIGHT.x + XMARGIN, RIGHT.y - INNER_RAD, TOP.x,
TOP.y - YMARGIN - INNER_RAD, BOTTOM.x,
BOTTOM.y + YMARGIN - INNER_RAD };
private static final int[] BLACKBORDER = new int[] { LEFT.x - XMARGIN,
LEFT.y - INNER_RAD, TOP.x, TOP.y - YMARGIN - INNER_RAD, BOTTOM.x,
BOTTOM.y + YMARGIN - INNER_RAD, RIGHT.x + XMARGIN,
RIGHT.y - INNER_RAD };
/**
* Convert rows and columns into pixel values
*
* @param i -
* row
* @param j -
* column
* @return - (x,y)-coordinate
*/
private static Point hexToPixel(int i, int j) {
return new Point(((i - j) * XDIST) + XOFF, ((i + j) * INNER_RAD) + YOFF);
}
/**
* Draw Canvas
*
* @param e -
* Event object
*/
public void paintControl(PaintEvent e) {
GC gc = e.gc;
if (e.x != 1 || e.y != 1) {
// Draw background
gc.setBackground(gray);
gc.fillRectangle(canvas.getClientArea());
// Draw game board edges
gc.setBackground(white);
gc.fillPolygon(WHITEBORDER);
gc.setBackground(black);
gc.fillPolygon(BLACKBORDER);
}
// Draw all hexagon cells
for (int i = 0; i < Game.SIZE; i++)
for (int j = 0; j < Game.SIZE; j++)
drawCellWithButton(gc, i, j, cells[i][j]);
}
/**
* Draw single cell
*
* @param gc -
* Graphic Context
* @param i -
* Row
* @param j -
* Column
* @param buttonColor -
* Color of game button
*/
private void drawCellWithButton(GC gc, int i, int j, int buttonColor) {
Point p = hexToPixel(i, j);
if (i == Game.SIZE / 2 && j == Game.SIZE / 2)
drawCell(gc, p.x, p.y, cyan, black);
else
drawCell(gc, p.x, p.y, green, black);
switch (buttonColor) {
case Game.BLACK:
drawButton(gc, p.x, p.y, black, white);
break;
case Game.WHITE:
drawButton(gc, p.x, p.y, white, black);
break;
}
}
/**
* Draw cell background
*
* @param gc -
* Graphic Context
* @param x -
* X-offset
* @param y -
* Y-offset
* @param cellColor -
* fill color
* @param outlineColor -
* outline color
*/
private void drawCell(GC gc, int x, int y, Color cellColor,
Color outlineColor) {
int[] points = new int[CELL.length];
for (int k = 0; k < CELL.length; k += 2) {
points[k] = x + CELL[k];
points[k + 1] = y + CELL[k + 1];
}
gc.setBackground(cellColor);
gc.setForeground(outlineColor);
gc.fillPolygon(points);
gc.drawPolygon(points);
}
/**
* Draw game button
*
* @param gc -
* Graphic Context
* @param x -
* X-offset
* @param y -
* Y-offset
* @param bgColor -
* fill color
* @param fgColor -
* outline color
*/
private void drawButton(GC gc, int x, int y, Color bgColor, Color fgColor) {
gc.setBackground(bgColor);
gc.fillOval(x - BUTTON_RAD, y - BUTTON_RAD, 2 * BUTTON_RAD,
2 * BUTTON_RAD);
gc.setForeground(fgColor);
gc.drawOval(x - BUTTON_RAD, y - BUTTON_RAD, 2 * BUTTON_RAD,
2 * BUTTON_RAD);
}
/**
* Doppelklick. Wird ignoriert.
*
* @param e -
* Mausereignis
*/
public void mouseDoubleClick(MouseEvent e) {
}
/*
* Mouse button pressed
*
* @param e - Event object
*/
public void mouseDown(MouseEvent e) {
Point p = pixelToHex(e.x, e.y);
game.selectHex(p.x, p.y);
}
/**
* Convert pixels into row and column
*
* @param x -
* X-offset
* @param y -
* Y-offset
* @return - (row, column)-tuple
*/
private static Point pixelToHex(int x, int y) {
int dist2 = INNER_RAD * INNER_RAD;
for (int i = 0; i < Game.SIZE; i++) {
for (int j = 0; j < Game.SIZE; j++) {
Point p = hexToPixel(i, j);
int dx = p.x - x;
int dy = p.y - y;
if (dx * dx + dy * dy < dist2)
return new Point(i, j);
}
}
return new Point(-1, -1);
}
/*
* Maustaste losgelassen. Wird ignoriert.
*
* @param e - Mausereignis
*/
public void mouseUp(MouseEvent e) {
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -