⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 board.java

📁 模仿windows的扫雷游戏 SWT编写的 需要log4j 1.2.4
💻 JAVA
字号:
package cn.pandaoen.game.minesweeper;

import org.apache.log4j.Logger;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;

import java.util.Random;

import cn.pandaoen.game.minesweeper.res.Resources;

public class Board extends Canvas implements Listener {

	// don't change the constant values
	static final int STATE_UNKNOWN = -1;
	static final int STATE_UNKNOWN_FLAG = 12;
	static final int STATE_UNKNOWN_QUESTION = 13;
	static final int STATE_MINE = 9;
	static final int STATE_EXPLOSION = 10;
	static final int STATE_WRONG = 11;

	private static final int INSET = 1;
	private final Logger logger = Logger.getLogger(Board.class);

	private int flagCount;
	private final Point boxSize;
	private int rows, columns, mineCount;
	private boolean[][] mines;
	private int[][] mineCounts;
	private int[][] states;
	private boolean isExploded;
	private boolean mouseBtn1Down;
	private boolean mouseBtn2Down;
	private int lastRow, lastColumn;
	private Color highlight;
	private Color light;
	private Color normal;
	private Color dark;
	private Color bg;
	private Image[] images = new Image[14];

	public Board(Composite parent, int style) {
		super(parent, style | SWT.NO_BACKGROUND | SWT.NO_FOCUS);

		for (int i = 0; i < 9; i++) {
			String name = i + ".gif"; //$NON-NLS-1$
			images[i] = Resources.res.getImage(name);
		}
		images[9] = Resources.res.getImage("mine.gif"); //$NON-NLS-1$
		images[10] = Resources.res.getImage("explosion.gif"); //$NON-NLS-1$
		images[11] = Resources.res.getImage("wrong.gif"); //$NON-NLS-1$
		images[12] = Resources.res.getImage("flag.gif"); //$NON-NLS-1$
		images[13] = Resources.res.getImage("question.gif"); //$NON-NLS-1$

		Rectangle bounds = images[0].getBounds();
		boxSize = new Point(bounds.width + INSET, bounds.height + INSET);
		Display display = getDisplay();
		highlight = display.getSystemColor(SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW);
		light = display.getSystemColor(SWT.COLOR_WIDGET_LIGHT_SHADOW);
		normal = display.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW);
		dark = display.getSystemColor(SWT.COLOR_WIDGET_DARK_SHADOW);
		bg = display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);

		addListener(SWT.Paint, this);
		addListener(SWT.MouseDown, this);
		addListener(SWT.MouseMove, this);
		addListener(SWT.MouseUp, this);
		addListener(SWT.Dispose, this);
	}

	public void setMinesAndSize(int mineCount, int rows, int columns) {
		logger.trace("Board " + mineCount + " " + rows + " " + columns); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
		checkWidget();

		this.mineCount = mineCount;
		this.rows = rows;
		this.columns = columns;

		mines = new boolean[rows][columns];
		states = new int[rows][columns];
		mineCounts = new int[rows][columns];

		reset();
		redraw();
	}

	public void reset() {
		checkWidget();

		for (int i = 0; i < rows; i++) {
			for (int j = 0; j < columns; j++) {
				states[i][j] = STATE_UNKNOWN;
				mines[i][j] = false;
				mineCounts[i][j] = -1;
			}
		}
		setEnabled(true);
		distributeMines();
		isExploded = false;
		flagCount = 0;
		lastRow = lastColumn = -1;
		
		redraw();
	}
	
	public void _showall() {
		GC gc = new GC(this);
		for(int i = 0; i < rows; i++) {
			for(int j = 0; j < columns; j++) {
				int s = states[i][j];
				if(mines[i][j])
					states[i][j] = STATE_MINE;
				else
					states[i][j] = getMineCount(i, j);
				drawItem(gc, i, j, boxSize.x, boxSize.y, false);
				states[i][j] = s;
			}
		}
		gc.dispose();
	}

	private void distributeMines() {
		int size = rows * columns;
		int[] indexs = new int[size];
		for (int i = 0; i < size; i++)
			indexs[i] = i;
		int count = mineCount;

		Random random = new Random();
		while (count-- > 0) {
			int rand = random.nextInt(size);
			int mineIndex = indexs[rand];
			indexs[rand] = indexs[--size];
			mines[mineIndex / columns][mineIndex % columns] = true;
		}
	}

	/**
	 * @return the number of mines
	 */
	public int getMineCount() {
		checkWidget();
		return mineCount;
	}

	public int getFlagCount() {
		checkWidget();
		return flagCount;
	}

	private int getMineCount(int r, int c) {
		if (mineCounts[r][c] == -1) {
			int count = 0;
			for (int i = r - 1; i <= r + 1; i++) {
				for (int j = c - 1; j <= c + 1; j++) {
					if (i != r || j != c) { // not (r, c)
						if (i >= 0 && i < rows && j >= 0 && j < columns) {
							if (mines[i][j])
								count++;
						}
					}
				}
			}
			mineCounts[r][c] = count;
		}

		return mineCounts[r][c];
	}

	private int getStateCount(int r, int c, int state) {
		int count = 0;
		for (int i = r - 1; i <= r + 1; i++) {
			for (int j = c - 1; j <= c + 1; j++) {
				if (i != r || j != c) { // not (r, c)
					if (i >= 0 && i < rows && j >= 0 && j < columns) {
						if (states[i][j] == state)
							count++;
					}
				}
			}
		}

		return count;
	}

	private boolean isUnknown(int state) {
		return state == STATE_UNKNOWN || state >= STATE_UNKNOWN_FLAG;
	}

	public boolean isExploded() {
		checkWidget();
		return isExploded;
	}

	public boolean isSwept() {
		checkWidget();
		int total = rows * columns;
		int numberOfKnown = 0;
		for (int i = 0; i < rows; i++) {
			for (int j = 0; j < columns; j++) {
				if (!isUnknown(states[i][j]))
					numberOfKnown++;
			}
		}

		boolean swept = numberOfKnown + mineCount == total;
		if (swept) {
			for (int i = 0; i < rows; i++) {
				for (int j = 0; j < columns; j++) {
					if (isUnknown(states[i][j]))
						states[i][j] = STATE_UNKNOWN_FLAG;
				}
			}
			redraw();
		}
		return swept;
	}

	/**
	 * @see #drawBox
	 */
	private void paint(Event event) {
		GC gc = event.gc;
		int boxWidth = boxSize.x;
		int boxHeight = boxSize.y;

		for (int i = 0; i < rows; i++) {
			for (int j = 0; j < columns; j++) {
				drawItem(gc, i, j, boxWidth, boxHeight, false);
			}
		}
	}

	private void drawItem(GC gc, int row, int column, int width, int height,
			boolean pressed) {
		if (row < 0 || row >= rows)
			return;
		if (column < 0 || column >= columns)
			return;

		int x = column * width;
		int y = row * height;

		gc.setBackground(bg);
		gc.fillRectangle(x, y, width, height);

		int state = states[row][column];
		if (state == STATE_UNKNOWN_FLAG)
			pressed = false;
		if (isUnknown(state)) {
			drawBox(gc, x, y, width, height, pressed);
		}
		if (state >= 0) {
			Image image = images[state];
			Rectangle rect = image.getBounds();
			int offsetX = Math.max(0, (width - rect.width) / 2);
			int offsetY = Math.max(0, (height - rect.height) / 2);
			gc.drawImage(image, x + offsetX, y + offsetY);
		}
	}

	private void drawBox(GC gc, int x, int y, int width, int height,
			boolean pressed) {
		Color topLeft = pressed ? dark : highlight;
		Color bottomRight = pressed ? highlight : dark;
		Color innerTopLeft = pressed ? normal : light;
		Color innerBottomRight = pressed ? light : normal;

		// draw top left line
		gc.setForeground(topLeft);
		gc.drawLine(x, y, x + width - 1, y);
		gc.drawLine(x, y, x, y + height - 1);
		gc.setForeground(innerTopLeft);
		gc.drawLine(x + 1, y + 1, x + width - 2, y + 1);
		gc.drawLine(x + 1, y + 1, x + 1, y + height - 2);

		// draw bottom right line
		gc.setForeground(bottomRight);
		gc.drawLine(x, y + height - 1, x + width - 1, y + height - 1);
		gc.drawLine(x + width - 1, y, x + width - 1, y + height - 1);
		gc.setForeground(innerBottomRight);
		gc.drawLine(x + 1, y + height - 2, x + width - 2, y + height - 2);
		gc.drawLine(x + width - 2, y + 1, x + width - 2, y + height - 2);
	}

	private void mouseBtn1Down(Event event) {
		int width = boxSize.x;
		int height = boxSize.y;
		int i = event.y / height;
		int j = event.x / width;
		mouseBtn1Down = true;
		GC gc = new GC(this);
		drawItem(gc, i, j, width, height, true);
		gc.dispose();

		lastRow = i;
		lastColumn = j;
	}

	private void mouseBtn2Down(Event event) {
		int width = boxSize.x;
		int height = boxSize.y;
		int i = event.y / height;
		int j = event.x / width;
		mouseBtn2Down = true;

		GC gc = new GC(this);
		draw9Boxes(gc, i, j, true);
		gc.dispose();

		lastRow = i;
		lastColumn = j;
	}

	private void draw9Boxes(GC gc, int r, int c, boolean pressed) {
		for (int i = r - 1; i <= r + 1; i++) {
			for (int j = c - 1; j <= c + 1; j++) {
				if (i >= 0 && i < rows && j >= 0 && j < columns) {
					drawItem(gc, i, j, boxSize.x, boxSize.y, pressed);
				}
			}
		}
	}

	private void mouseBtn3Down(Event event) {
		int r = event.y / boxSize.y;
		int c = event.x / boxSize.x;
		if (r >= 0 && r < rows & c >= 0 && c < columns) {
			int newState = states[r][c];
			if (states[r][c] == STATE_UNKNOWN)
				newState = STATE_UNKNOWN_FLAG;
			else if (states[r][c] == STATE_UNKNOWN_FLAG)
				newState = STATE_UNKNOWN_QUESTION;
			else if (states[r][c] == STATE_UNKNOWN_QUESTION)
				newState = STATE_UNKNOWN;

			if (newState != states[r][c]) {
				if (states[r][c] == STATE_UNKNOWN_FLAG)
					flagCount--;
				else if (newState == STATE_UNKNOWN_FLAG)
					flagCount++;
				states[r][c] = newState;
				GC gc = new GC(this);
				drawItem(gc, r, c, boxSize.x, boxSize.y, false);
				gc.dispose();
			}
		}
	}

	private void mouseMove(Event event) {
		if (!mouseBtn1Down && !mouseBtn2Down)
			return;

		int width = boxSize.x;
		int height = boxSize.y;
		int i = event.y / height;
		int j = event.x / width;
		if (i == lastRow && j == lastColumn)
			return;

		GC gc = new GC(this);
		if (lastRow != -1) {
			if (mouseBtn1Down)
				drawItem(gc, lastRow, lastColumn, width, height, false);
			else
				draw9Boxes(gc, lastRow, lastColumn, false);
			lastRow = lastColumn = -1;
		}

		if (i >= 0 && i < rows && j >= 0 && j < columns) {
			if (mouseBtn1Down)
				drawItem(gc, i, j, width, height, true);
			else
				draw9Boxes(gc, i, j, true);
			lastRow = i;
			lastColumn = j;
		}
		gc.dispose();
	}

	private void mouseBtn1Up(Event event) {
		if (lastRow != -1) {
			GC gc = new GC(this);
			drawItem(gc, lastRow, lastColumn, boxSize.x, boxSize.y, false);
			int state = states[lastRow][lastColumn];
			if (state == STATE_UNKNOWN || state == STATE_UNKNOWN_QUESTION) {
				sweep(gc, lastRow, lastColumn);
			}
			lastRow = lastColumn = -1;
			gc.dispose();
		}
		mouseBtn1Down = false;
	}

	private void mouseBtn2Up(Event event) {
		if (lastRow != -1) {
			GC gc = new GC(this);
			int state = states[lastRow][lastColumn];
			draw9Boxes(gc, lastRow, lastColumn, false);
			if (!isUnknown(state)) {
				int mineCount = getMineCount(lastRow, lastColumn);
				int flagCount = getStateCount(lastRow, lastColumn,
						STATE_UNKNOWN_FLAG);
				if (mineCount == flagCount) {
					sweepNeighbors(gc, lastRow, lastColumn);
				}
			}
			lastRow = lastColumn = -1;
			gc.dispose();
		}

		mouseBtn2Down = false;
	}

	// [(r, c) must be right indexs]
	private void sweep(GC gc, int r, int c) {
		if (mines[r][c]) {
			isExploded = true;
			setEnabled(false);
			states[r][c] = STATE_EXPLOSION;
			revealMines();
			redraw();
		} else {
			// (r, c) is swept
			int mineCount = getMineCount(r, c);
			if (mineCount > 0) {
				states[r][c] = mineCount;
				drawItem(gc, r, c, boxSize.x, boxSize.y, false);
			} else {
				recSweep(gc, r, c);
			}
		}
	}

	private void recSweep(GC gc, int r, int c) {
		if (mines[r][c]) {
			isExploded = true;
			setEnabled(false);
			states[r][c] = STATE_EXPLOSION;
			revealMines();
			redraw();
		} else {
			// (r, c) is swept
			int mineCount = getMineCount(r, c);
			int flagCount = getStateCount(r, c, STATE_UNKNOWN_FLAG);
			states[r][c] = mineCount;
			drawItem(gc, r, c, boxSize.x, boxSize.y, false);
			if (mineCount == flagCount) {
				sweepNeighbors(gc, r, c);
			}
		}

	}

	private void sweepNeighbors(GC gc, int r, int c) {
		for (int i = r - 1; i <= r + 1; i++) {
			for (int j = c - 1; j <= c + 1; j++) {
				if (i != r || j != c) { // not (r, c)
					if (i >= 0 && i < rows && j >= 0 && j < columns) {
						if (states[i][j] == STATE_UNKNOWN
								|| states[i][j] == STATE_UNKNOWN_QUESTION) {
							recSweep(gc, i, j);
						}
					}
				}
			}
		}
	}

	private void revealMines() {
		for (int i = 0; i < rows; i++) {
			for (int j = 0; j < columns; j++) {
				int state = states[i][j];
				if (state == STATE_UNKNOWN_FLAG) {
					if (!mines[i][j])
						states[i][j] = STATE_WRONG;
				} else if (isUnknown(state)) {
					if (mines[i][j])
						states[i][j] = STATE_MINE;
				}
			}
		}
	}

	/*
	 * @see org.eclipse.swt.widgets.Composite#computeSize(int, int, boolean)
	 */
	public Point computeSize(int wHint, int hHint, boolean changed) {
		checkWidget();

		int width = columns * boxSize.x;
		int height = rows * boxSize.y;
		Rectangle trim = computeTrim(0, 0, width, height);
		return new Point(trim.width, trim.height);
	}

	/*
	 * @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event)
	 */
	public void handleEvent(Event event) {
		switch (event.type) {
		case SWT.Paint:
			paint(event);
			break;
		case SWT.MouseDown:
			logger.trace("Mouse Button " + event.button + " pressed"); //$NON-NLS-1$ //$NON-NLS-2$
			if (event.button == 1)
				mouseBtn1Down(event);
			else if (event.button == 2)
				mouseBtn2Down(event);
			else if (event.button == 3)
				mouseBtn3Down(event);
			break;
		case SWT.MouseMove:
			mouseMove(event);
			break;
		case SWT.MouseUp:
			logger.trace("Mouse Button " + event.button + " released"); //$NON-NLS-1$ //$NON-NLS-2$
			if (event.button == 1)
				mouseBtn1Up(event);
			else if (event.button == 2)
				mouseBtn2Up(event);
			break;
		}
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -