import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.util.*;
public class Chess extends JFrame{
Chessboard qipan=new Chessboard();//初始化外观
public Chess()
{
this.setTitle("围棋程序");//设置标题为“围棋程序”
this.setLayout(new BorderLayout());//设置布局管理器
this.setSize(qipan.getSize());//设置大小
this.add(qipan,"Center");//添加“棋盘”面板,并居中
this.setResizable(false);//设置窗体为不可调整大小
this.setLayout(new BorderLayout());//设置布局管理器
this.setSize(550,490);//设置错题大小
this.setVisible(true);//设置窗体的可见性为可见
}
public int getWidth()//取得宽度
{
return qipan.getWidth();
}
public int getHeight()//取得高度
{
return qipan.getHeight();
}
// 主函数,开始下棋程序
public static void main(String[] args){
Chess Igo=new Chess();
}
}
//棋盘类
class Chessboard extends JPanel {
// 默认的棋盘方格长度及数目
public static final int _gridLen = 22, _gridNum = 19;
/*
* 利用Vector保存所有已下的棋子,包括在棋盘上的所有棋子和被踢掉的,若某一次
* 落子没有造成踢子,包括所有被这个棋子提掉的棋子及这个棋子本身.
*
* Vector 类可以实现可增长的对象数组。与数组一样,它包含可以使用整数索引进行访问的组件。
* 但是,Vector 的大小可以根据需要增大或缩小,以适应创建 Vector 后进行添加或移除项的操作。
*/
private Vector chessman;
private int alreadyNum; // 已下数目
private int currentTurn; // 轮到谁下
private int gridNum, gridLen; // 方格长度及数目
private int chessmanLength; // 棋子的直径
private Chesspoint[][] map; // 在棋盘上的所有棋子
private Image offscreen;//用来绘制棋盘
private Graphics offg;//用来绘制方格和棋子
private int size; // 棋盘的宽度及高度
private int top = 13, left = 13; // 棋盘左边及上边的边距
//Point类表示 (x,y) 坐标空间中的位置的点,以整数精度指定。
private Point mouseLoc; // 鼠标的位置,即map数组中的下标
private ControlPanel controlPanel; // 控制面板
//获得控制板的距离
public int getWidth() {
return size + controlPanel.getWidth() + 35;
}
public int getHeight() {
return size;
}
//绘制棋盘外观
public Chessboard() {
gridNum = _gridNum;//方格数目为19
gridLen = _gridLen;//方格长度为22
chessmanLength = gridLen * 9 / 10;//棋子直径为22*9/10
size = 2 * left + gridNum * gridLen;//正方形棋盘边长为2*13+19*22
addMouseListener(new PutChess());//注册鼠标监听器,监听鼠标按下事件
addMouseMotionListener(new MML());//注册鼠标监听器,监听鼠标移动事件
setLayout(new BorderLayout());//设置布局模式
controlPanel = new ControlPanel();//创建控制面板
setSize(getWidth(), size);//设置宽度和大小
add(controlPanel, "West");//添加"控制面板",为"西"
startGame();//开始游戏
}
public void addNotify()
{
super.addNotify();//创建按钮的同位体。按钮的同位体允许应用程序更改按钮的外观。而不更改其功能。
offscreen = createImage(size, size);//创建一幅用于双缓冲的可在屏幕外绘制的图象
offg = offscreen.getGraphics();//为offscreen组件创建图形的上下文
}
public void paint(Graphics g) {
offg.setColor(new Color(180, 150, 100));//将颜色选取器的当前颜色设置为指定的 RGB 颜色。ǎ
offg.fillRect(0, 0, size, size);//(即设置画笔颜色)
//画出棋盘格子
offg.setColor(Color.black);//设置画笔颜色为黑色
for (int i = 0; i < gridNum + 1; i++) {
int x1 = left + i * gridLen;//13+i*22
int x2 = x1;
int y1 = top;//top=13(前面已定义)
int y2 = top + gridNum * gridLen;//13+i*22
offg.drawLine(x1, y1, x2, y2);//画竖线,在画布中心绘制直线(使用当前画笔颜色在(x1,y1)和(x2,y2)间画一条线段
x1 = left;
x2 = left + gridNum * gridLen;
y1 = top + i * gridLen;
y2 = y1;
offg.drawLine(x1, y1, x2, y2);//画横线,在画布中心绘制直线(使用当前画笔颜色在(x1,y1)和(x2,y2)间画一条线段
}//这是通过画线的方式将棋盘绘制出来
//画出棋子
for (int i = 0; i < gridNum + 1; i++)
for (int j = 0; j < gridNum + 1; j++) {
if (map[i][j] == null)//前面定义Chesspoint[][] map;即在棋盘上的所有棋子
continue;
offg.setColor(map[i][j].color == Chesspoint.black ? Color.black
: Color.white);//给棋子设置相应的颜色
offg.fillOval(left + i * gridLen - chessmanLength / 2, top + j
* gridLen - chessmanLength / 2, chessmanLength,
chessmanLength);//在指定区域绘制圆形
}
//画出鼠标的位置,即下一步将要下的位置
if (mouseLoc != null) {
offg.setColor(currentTurn == Chesspoint.black ? Color.gray
: new Color(200, 200, 250));//设置画笔颜色
offg.fillOval(left + mouseLoc.x * gridLen - chessmanLength / 2, top//应该是他少减一个数着具体的也没改好,这先用-3*_gridLen
+ mouseLoc.y * gridLen - chessmanLength / 2,
chessmanLength, chessmanLength);//使用当前颜色填充外接指定矩形框的椭圆。
}
//把画面一次性画出
g.drawImage(offscreen, 80, 0, this);
}
// 更新棋盘
public void update(Graphics g) {
paint(g);//绘制
}
//下棋子
//这是对鼠标按下事件的处理类,是内部类
class PutChess extends MouseAdapter { // 放一颗棋子
public void mousePressed(MouseEvent evt) {//鼠标按键在组件上按下时调用
int xoff = left / 2;
int yoff = top / 2;
//程序中的那个棋子与鼠标不对位的漏洞,很有可能是这里和下边鼠标事件,的X坐标出现了问题
int x = (evt.getX() - xoff-3*_gridLen) / gridLen;//getX()返回事件相对于源组件的水平 x 坐标。
//应该是少减一个数,具体的也没改好,这先用-3*_gridLen,位置大概也正确了
int y = (evt.getY() - yoff) / gridLen;//getY()返回事件相对于源组件的水平 y 坐标。
if (x < 0 || x > gridNum || y < 0 || y > gridNum)
return;//返回空
if (map[x][y] != null)
return;//在void函数中可以用一个不带值的return来结束程序
// *****************清除多余的棋子**********************
if (alreadyNum < chessman.size()) {
int size = chessman.size();
for (int i = size - 1; i >= alreadyNum; i--)
chessman.removeElementAt(i);//从此向量中移除i变量
}
// ****************************************************
Chesspoint qizi = new Chesspoint(x, y, currentTurn);
map[x][y] = qizi;
// ****************************************************
chessman.addElement(qizi);//将棋子添加到chessman中
alreadyNum++;//已下棋子数目自加
if (currentTurn == Chesspoint.black)
currentTurn = Chesspoint.white;
else
currentTurn = Chesspoint.black;
// **************判断在[x,y]落子后,是否可以提掉对方的子
tizi(x, y);
// ***************判断是否挤死了自己,若是则已落的子无效
if (allDead(qizi).size() != 0) {
map[x][y] = null;
repaint();//重绘此组件。
controlPanel.setMsg("挤死自己");//控制面板提示"挤死自己"
// ******************back**************
chessman.removeElement(qizi);//移除棋子
alreadyNum--;//已下棋子数目自减
if (currentTurn == Chesspoint.black)
currentTurn = Chesspoint.white;//轮到白子下
else
currentTurn = Chesspoint.black;//轮到黑子下
return;
}
mouseLoc = null;
// 更新控制面板
controlPanel.setLabel();
//更新标签
}
public void mouseExited(MouseEvent evt) {// 鼠标退出时,清除将要落子的位置
mouseLoc = null;
repaint();//重绘
}
}
private class MML extends MouseMotionAdapter {// 取得将要落子的位置
public void mouseMoved(MouseEvent evt) {
int xoff = left / 2;
int yoff = top / 2;
//这里也是上边说的棋子不对位的漏洞所对应的代码,这也放一个-3*_gridLen
int x = (evt.getX() - xoff-3*_gridLen) / gridLen;
int y = (evt.getY() - yoff) / gridLen;
if (x < 0 || x > gridNum || y < 0 || y > gridNum)
return;//在void函数中可以用一个不带值的return来结束程序
if (map[x][y] != null)
return;
mouseLoc = new Point(x, y);//鼠标位置为(x,y)
repaint();//重绘此组件。
}
}
//判断在[x,y]落子后,是否可以踢掉对方的子
//以下这两个数组是用来定位一下棋子四周的坐标
public static int[] xdir = { 0, 0, 1, -1 };
public static int[] ydir = { 1, -1, 0, 0 };
public void tizi(int x, int y) {
Chesspoint qizi;
if ((qizi = map[x][y]) == null)
return;
int color = qizi.color;
//取得棋子四周围的几个子
Vector v = around(qizi);
for (int l = 0; l < v.size(); l++) {
Chesspoint q = (Chesspoint) (v.elementAt(l));//elementAt()返回指定索引处的组件。
if (q.color == color)
continue;
//若颜色不同,取得和q连在一起的所有已死的子,
//若没有已死的子则返回一个空的Vector
Vector dead = allDead(q);
//移去所有已死的子
removeAll(dead);
//如果踢子,则保存所有被踢掉的棋子