/*
* Created on 2006-6-2
*
*/
package com.ftinternet;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.HashMap;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
/**
* @author *
* TODO To change the template for this generated type comment go to
* Window - Preferences - Java - Code Style - Code Templates
*/
class MineButton extends JButton {
private static final long serialVersionUID = -2004966127695755657L;
public static final int MINE_BUTTON_WIDTH = 220;
public static final boolean MINESTATUS_MINED = true;
public static final boolean MINESTATUS_ACTIVE = false;
private int XPos = 0;
private int YPos = 0;
public boolean MineStatus = MINESTATUS_ACTIVE;
private int MineCount = -1;
private boolean Suspected = false;
public MineButton(int XPos, int YPos) {
this.XPos = XPos;
this.YPos = YPos;
setSize(MINE_BUTTON_WIDTH, MINE_BUTTON_WIDTH);
SetSuspected(false);
}
public int GetXPos() { return XPos; }
public int GetYPos() { return YPos; }
public boolean IsSuspected()
{
return Suspected;
}
public void SetSuspected(boolean IsSuspect)
{
Suspected = IsSuspect;
if (!Suspected) setText(" ");
else setText("x");
}
public boolean IsMined() {
return MineStatus == MINESTATUS_MINED;
}
public void SetMine() {
MineStatus = MINESTATUS_MINED;
}
public void Reset() {
MineStatus = MINESTATUS_ACTIVE;
SetSuspected(false);
MineCount = -1;
setBackground(Color.lightGray);
setForeground(Color.black);
}
public void setMineCount(int mine) {
MineCount = mine;
setBackground(Color.white);
switch (MineCount)
{
case 1:
setForeground(Color.blue);
break;
case 2:
setForeground(Color.green);
break;
case 3:
setForeground(Color.darkGray);
break;
case 4:
setForeground(Color.cyan);
break;
case 5:
setForeground(Color.magenta);
break;
case 6:
setForeground(Color.orange);
break;
case 7:
setForeground(Color.red);
break;
}
}
public int getMineCount() { return MineCount; }
}
public class TestMine extends JFrame {
private static final long serialVersionUID = -3295523726245939815L;
private static Point[] AroundPoint = {
new Point(-1, -1), new Point(0, -1), new Point(1, -1),
new Point(-1, 0), new Point(1, 0),
new Point(-1, 1), new Point(0, 1), new Point(1, 1)
};
private HashMap<String, MineButton> MineList = new HashMap<String, MineButton>();
private int MineMapWidth = 0;
private int MineMapHeight = 0;
private int MineMapCount = 0;
private boolean GameActive = false;
JPanel pnlControl = new JPanel();
JPanel pnlView = new JPanel();
JLabel lbMineLeft = new JLabel("");
JLabel lbMineOver = new JLabel("Game Over");
private String GetMineCode(int width, int height)
{
return "M" + width + "-" + height;
}
private MineButton GetMineButton(int XPos, int YPos)
{
if (MineList.containsKey(GetMineCode(XPos, YPos)))
return (MineButton) MineList.get(GetMineCode(XPos, YPos));
else
return null;
}
private MineButton GetMineButton(int Index) {
return GetMineButton(Index % MineMapWidth, Index / MineMapWidth);
}
private void ResetMineMap()
{
for (int i = 0; i < MineMapWidth * MineMapHeight; i++)
GetMineButton(i).Reset();
}
private void InitMineMap()
{
Random rand = new Random();
int rCount = MineMapCount;
ResetMineMap();
while (rCount > 0)
{
int rPos = rand.nextInt(MineMapWidth * MineMapHeight);
MineButton mbTemp = GetMineButton(rPos);
if ((mbTemp == null) || mbTemp.IsMined()) continue;
mbTemp.SetMine();
rCount--;
}
lbMineLeft.setText("" + MineMapCount);
GameActive = true;
pnlView.setEnabled(true);
lbMineOver.setVisible(false);
}
private void GameOver(boolean Active)
{
GameActive = false;
pnlView.setEnabled(false);
if (Active) lbMineOver.setForeground(Color.green);
else lbMineOver.setForeground(Color.red);
lbMineOver.setVisible(true);
repaint();
}
/**
* 检查mbTemp1,mbTemp2是否相邻
* @param mbTemp1
* @param mbTemp2
* @return
*/
protected boolean IsNeighbor(MineButton mbTemp1, MineButton mbTemp2) {
return (mbTemp1 != null) && (mbTemp2 != null)
&& Math.abs(mbTemp1.GetXPos() - mbTemp2.GetXPos()) + Math.abs(mbTemp1.GetYPos() - mbTemp1.GetYPos()) == 1;
}
/**
* 检查mbTemp1是否在mbTemp2在周围
* @param mbTemp1
* @param mbTemp2
* @return
*/
protected boolean IsAround(MineButton mbTemp1, MineButton mbTemp2) {
return (mbTemp1 != null) && (mbTemp2 != null)
&& (Math.abs(mbTemp1.GetXPos() - mbTemp2.GetXPos()) < 2) && (Math.abs(mbTemp1.GetYPos() - mbTemp2.GetYPos()) < 2);
}
private boolean CheckPosition(int XPos, int YPos)
{
MineButton mbMine = GetMineButton(XPos, YPos);
return ((mbMine != null) && mbMine.IsMined());
}
private int GetMineAround(int XPos, int YPos)
{
int Mines = 0;
for (int i = 0; i < AroundPoint.length; i++)
if (CheckPosition(XPos + AroundPoint[i].x, YPos + AroundPoint[i].y)) Mines++;
return Mines;
}
/**
* 从(XPos, YPos)向周围扩展
* @param XPos
* @param YPos
*/
private void ExplorMine(int XPos, int YPos)
{
MineButton mbMine = GetMineButton(XPos, YPos);
if ((mbMine == null) || (mbMine.getMineCount() > -1) || mbMine.IsSuspected()) return;
mbMine.setMineCount(GetMineAround(XPos, YPos));
if (mbMine.getMineCount() > 0)
mbMine.setText("" + mbMine.getMineCount());
else {
for (int i = 0; i < AroundPoint.length; i++)
ExplorMine(XPos + AroundPoint[i].x, YPos + AroundPoint[i].y);
}
}
/**
* 统计点(XPos, YPos)周围的情况
* @param XPos
* @param YPos
* @return Point.x 周围的嫌疑个数,Point.y周围的未知个数
*/
private void CheckSuspectPosition(int XPos, int YPos, Point info)
{
MineButton mbTemp = GetMineButton(XPos, YPos);
if (mbTemp == null) return;
if (mbTemp.IsSuspected()) info.x++;
else if (mbTemp.getMineCount() < 0) info.y++;
}
private Point CalculatePositionAround(int XPos, int YPos)
{
Point around = new Point();
for (int i = 0; i < AroundPoint.length; i++)
CheckSuspectPosition(XPos + AroundPoint[i].x, YPos + AroundPoint[i].y, around);
return around;
}
/**
* 从(XPos, YPos)处展开周围所有未探测的点都被认为非雷
* @param XPos
* @param YPos
*/
private void FlashPosition(int XPos, int YPos)
{
MineButton mbTemp = GetMineButton(XPos, YPos);
if ((mbTemp == null) || mbTemp.IsSuspected()) return;
if (mbTemp.getMineCount() < 0) {
if (mbTemp.IsMined())
{
mbTemp.setText("x");
mbTemp.setBackground(Color.RED);
GameOver(false);
}
else
ExplorMine(XPos, YPos);
}
}
/**
* see also FlashPosition(int XPos, int YPos)
* @param mbSender
*/
private void FlashPositionAround(MineButton mbSender)
{
FlashPositionAround(mbSender.GetXPos(), mbSender.GetYPos());
}
private void FlashPositionAround(int XPos, int YPos)
{
for (int i = 0; i < AroundPoint.length; i++)
FlashPosition(XPos + AroundPoint[i].x, YPos + AroundPoint[i].y);
}
private void CalculatePosition(MineButton mbSender)
{
/**
* 计算(XPos, YPos) 附近雷的情况
*/
if (mbSender == null) return;
Point around = CalculatePositionAround(mbSender.GetXPos(), mbSender.GetYPos());
/** (XPos, YPos)周围雷已全部发现 */
if (around.x == mbSender.getMineCount())
FlashPositionAround(mbSender);
}
private boolean FindAllMine() {
int safemines = 0;
for (int i = 0; i < MineMapWidth * MineMapHeight; i++)
if (GetMineButton(i).getMineCount() > -1) safemines++;
return (safemines + MineMapCount) == MineMapWidth * MineMapHeight;
}
public TestMine() {
this(9, 9, 10);
}
public TestMine(int Width, int Height, int Mines) {
setDefaultCloseOperation(EXIT_ON_CLOSE);
MineMapWidth = Width < 9 ? 9 : Width;
MineMapHeight = Height < 9 ? 9 : Height;
MineMapCount = 2 * Mines > MineMapWidth * MineMapHeight
? MineMapWidth * MineMapHeight / 2
: Mines;
getContentPane().add(pnlControl, BorderLayout.NORTH);
pnlControl.setLayout(new FlowLayout(FlowLayout.LEFT, 30, 2));
JButton bRestart = new JButton("开 始");
pnlControl.add(lbMineLeft);
bRestart.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent ae) {
InitMineMap();
}
});
pnlControl.add(bRestart);
pnlControl.add(lbMineOver);
pnlView.setSize(MineButton.MINE_BUTTON_WIDTH * MineMapWidth, MineButton.MINE_BUTTON_WIDTH * MineMapHeight);
getContentPane().add(pnlView, BorderLayout.CENTER);
pnlView.setLayout(new GridLayout(MineMapHeight, MineMapWidth));
for (int h = 0; h < MineMapHeight; h++)
for (int w = 0; w < MineMapWidth; w++)
{
MineButton mbMine = new MineButton(w, h);
pnlView.add(mbMine);
MineList.put(GetMineCode(w, h), mbMine);
mbMine.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent ae) {
if (!GameActive) return;
MineButton mbSender = (MineButton) ae.getSource();
if (ae.getButton() == MouseEvent.BUTTON1) {
if (mbSender.IsSuspected()) return;
if (mbSender.getMineCount() != -1) {
CalculatePosition(mbSender);
}
else if (mbSender.IsMined()) {
mbSender.setText("x");
mbSender.setBackground(Color.RED);
GameOver(false);
return;
}
else
ExplorMine(mbSender.GetXPos(), mbSender.GetYPos());
}
if (ae.getButton() == MouseEvent.BUTTON3) {
if (mbSender.getMineCount() > -1) return;
mbSender.SetSuspected(!mbSender.IsSuspected());
if (mbSender.IsSuspected())
lbMineLeft.setText("" + (Integer.parseInt(lbMineLeft.getText()) - 1));
else
lbMineLeft.setText("" + (Integer.parseInt(lbMineLeft.getText()) + 1));
}
if (FindAllMine()) GameOver(true);
}
});
}
InitMineMap();
this.setTitle("扫雷:雷区----" + MineMapWidth + "x" + MineMapHeight + ":" + MineMapCount);
pack();
}
public static void main(String[] args) {
TestMine tm = new TestMine(9, 9, 10);
tm.setVisible(true);
}
}