重绘五子棋棋盘需先绘制界面,继承JFrame的属性和方法并调整界面大小。要加入的功能都设置绑定按钮存在最初界面。并让按钮分别绑上监听器。
public class GoUI extends JFrame
{
public void showUI()
{
setTitle("五子棋");
setSize(1100,850);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(null);
JButton btn1=new JButton("开始游戏");
btn1.setBounds(875,100,100,35);
JButton btn2=new JButton("悔棋");
btn2.setBounds(875,150,100,35);
JButton btn3=new JButton("回放");
btn3.setBounds(875,200,100,35);
JButton btn4=new JButton("AI下棋");
btn4.setBounds(875,250,100,35);
add(btn1);
add(btn2);
add(btn3);
add(btn4);
ButtonGroup Group = new ButtonGroup ();
setVisible(true);
GoListener goListener=new GoListener();
addMouseListener(goListener);
btn1.addActionListener(goListener);
btn2.addActionListener(goListener);
btn3.addActionListener(goListener);
btn4.addActionListener(goListener);
Graphics g=getGraphics();
goListener.g=g;
goListener.ui=this;
}
public static void main(String[] args)
{
GoUI goUI=new GoUI();
goUI.showUI();
}
}
然后在paint绘制方法中绘制画布与棋盘,防止其消失。优先将具体不变的数字用参数代替,不仅善于调用,也更方便观察。
public void paint (Graphics g)
{
count++;
System.out.println("paint"+count);
Color color=new Color(128,164,128);
g.setColor(color);
g.fillRect(0,0,getWidth(),getHeight());
int X=50,Y=75,SIZE=50,ROWS=14,COLS=14;
g.setColor(Color.ORANGE);
for (int i=0;i<=15;i++)
{
g.drawLine(X,Y+i*SIZE,X+COLS*SIZE,Y+i*SIZE);
g.drawLine(X+i*SIZE,Y,X+i*SIZE,Y+ROWS*SIZE);
}
g.setColor(Color.red);
g.drawRect(X-25,Y-25,SIZE*COLS+SIZE,SIZE*ROWS+SIZE);
}
在paint绘制方法中也绘制棋子,遇到空指针直接跳过。
for (int i = 0; i < goListener.Sto.length; i++)
{
StorageChess sc = goListener.Sto[i];
if(sc!=null)
{
g.setColor(sc.color==1?Color.BLACK:Color.WHITE);
int x = sc.X;
int y = sc.Y;
int c=x*50+50-25;
int r=y*50+75-25;
g.fillOval(c,r,50,50);
}
}
监听器与鼠标的点击、按钮、鼠标位置相绑。其中设置悔棋时,利用index(在本代码中为落下的棋子数(从0开始计数))调整落下的棋子。
public class GoListener implements MouseListener, ActionListener
{
Graphics g;
int chessFlag=0;
@Override
public void actionPerformed(ActionEvent e)
{
System.out.println("按钮被点击了");
String btnStr=e.getActionCommand();
JButton btn=(JButton)e.getSource();
if (btnStr.equals("开始游戏"))
{
chessFlag=1;
btn.setText("结束游戏");
}
else if(btnStr.equals("结束游戏"))
{
chessFlag=0;
btn.setText("开始游戏");
}
else if (btnStr.equals("悔棋"))
{
if (index<=0)
{
System.out.println("无法悔棋");
JOptionPane.showMessageDialog(null,"无法悔棋");
return;
}
else if (chessFlag != 0)
{
chessFlag = (chessFlag % 2) + 1;
Sto[--index]=null;
}
}
}
public void mouseClicked(MouseEvent e)
{
System.out.println("鼠标按下");
if (chessFlag==0)
{
System.out.println("游戏未开始");
JOptionPane.showMessageDialog(null,"游戏未开始");
return;
}
int x=e.getX();
int y=e.getY();
System.out.println("x="+x+"y="+y);
int c=(x-50+25)/50;
int r=(y-75+25)/50;
System.out.println("c="+c+"r="+r);
if (c<0||c>15||r<0||r>15)
{
System.out.println("此处无法落子");
JOptionPane.showMessageDialog(null,"此处无法落子");
return;
}
回放功能与悔棋类似,(这里默认回放后本局结束不再下棋),清空二维数组,再根据一维数组的数据重新依次落子。为防止棋子过多运算速度过快而卡住,最好设置一休眠函数。
else if (btnStr.equals("回放"))
{
chessFlag=0;
chessarr=new int[15][15];
ui.repaint();
System.out.println("回放");
JOptionPane.showMessageDialog(null,"回放");
for (int i=0;i<index;i++)
{
try
{
Thread.sleep(500);
}
catch(InterruptedException ex)
{
throw new RuntimeException(ex);
}
StorageChess storage=Sto[i];
chessarr[storage.X][storage.Y]= storage.color;
g.setColor(storage.color==1?Color.BLACK:Color.WHITE);
int chessX= storage.X*50+50;
int chessY= storage.Y*50+75;
g.fillOval(chessX-25,chessY-25,50,50);
g.setColor(Color.red);
g.drawString((i+1)+"",chessX,chessY);
}
}
而AI下棋是将二维数组中储存的棋子传入其类中进行判定,判定方法是根据棋子所在位置八个方向上的棋子情况设置分数相加再进行比较。下棋时判定下在分数最高的一处。
else if (btnStr.equals("AI下棋"))
{
int[] aiPoints=AISet.aiPlay(chessarr,chessFlag);
StorageChess storageChess = new StorageChess();
storageChess.X=aiPoints[0];
storageChess.Y=aiPoints[1];
storageChess.serialNember=index;
storageChess.color=chessFlag;
chessarr[storageChess.X][storageChess.Y]=chessFlag;
Sto[index++]=storageChess;
g.setColor(chessFlag==1?Color.BLACK:Color.WHITE);
g.fillOval(storageChess.X*50+50-25, storageChess.Y*50+75-25, 50,50);
chessFlag=chessFlag%2+1;
PdWin.Pdwin(chessarr);
}
//单独创建一个类,利于封装与调用
public class AISet {
static HashMap<String, Integer> codeMap = new HashMap<>();
static int[][] codeArr = new int[15][15];
static {
codeMap.put("010", 50);
codeMap.put("0110", 250);
codeMap.put("01110", 1000);
codeMap.put("011110", 5000);
codeMap.put("020", 50);
codeMap.put("0220", 250);
codeMap.put("02220", 1000);
codeMap.put("022220", 5000);
codeMap.put("01", 30);
codeMap.put("011", 150);
codeMap.put("0111", 700);
codeMap.put("01111", 5000);
codeMap.put("02", 30);
codeMap.put("022", 150);
codeMap.put("0222", 700);
codeMap.put("02222", 5000);
}
public static int[] aiPlay(int[][] chessArr,int chessFlag) {
for (int i = 0; i < chessArr.length; i++) {
for (int j = 0; j < chessArr[i].length; j++) {
int cnum = chessArr[i][j];
//在这里判定该处还未下棋
if (cnum == 0) {
toRight(chessArr, i, j);
toLeft(chessArr, i, j);
toUp(chessArr, i, j);
toDown(chessArr, i, j);
toRightDown(chessArr, i, j);
toLeftUp(chessArr, i, j);
toRightUp(chessArr, i, j);
toLeftDown(chessArr, i, j);
}
}
}
int tempi = 7,tempj=7;
for (int i = 0; i < codeArr.length; i++){
for (int j = 0; j < codeArr[i].length; j++){
if (chessArr[i][j]==0){
tempi=i;
tempj=j;
}
}
}
for (int i = 0; i < codeArr.length; i++) {
for (int j = 0; j < codeArr[i].length; j++) {
if (chessArr[i][j]==0) {
if (codeArr[i][j] > codeArr[tempi][tempj]) {
tempi = i;
tempj = j;
}
}
}
}
chessArr[tempi][tempj]=chessFlag;
System.out.println(tempi+","+tempj);
return new int[]{tempi,tempj};
}
private static void toRight(int[][] chessArr, int r, int c) {
String codeStr = "0";
if (c == 14) {
return;
}
if (chessArr[r][c+1]==0) {
return;
}
codeStr+=chessArr[r][c+1]+"";
for (int i = c+2; i <= 14; i++) {
if (chessArr[r][i ] == 0) {
codeStr += "0";
break;
} else if (chessArr[r][i ] == chessArr[r][i-1]) {
codeStr += chessArr[r][c + 1] + "";
} else {
break;
}
}
Integer code = codeMap.get(codeStr);
if(code==null){
return;
}
codeArr[r][c] += code;
}
private static void toLeft(int[][] chessArr, int r, int c) {
String codeStr = "0";
if (c == 0) {
return;
}
if (chessArr[r][c-1]==0) {
return;
}
codeStr+=chessArr[r][c-1]+"";
for (int i = c-2; i >=0; i--) {
if (chessArr[r][i ] == 0) {
codeStr += "0";
break;
} else if (chessArr[r][i ] == chessArr[r][i+1]) {
codeStr += chessArr[r][c - 1] + "";
} else {
break;
}
}
Integer code = codeMap.get(codeStr);
if(code==null){
return;
}
codeArr[r][c] += code;
}
private static void toDown(int[][] chessArr, int r, int c) {
String codeStr = "0";
if (r == 14) {
return;
}
if (chessArr[r+1][c]==0) {
return;
}
codeStr+=chessArr[r+1][c]+"";
for (int i = r+2; i <= 14; i++) {
if (chessArr[i][c ] == 0) {
codeStr += "0";
break;
} else if (chessArr[i][c ] == chessArr[i-1][c]) {
codeStr += chessArr[r+1][c ] + "";
} else {
break;
}
}
Integer code = codeMap.get(codeStr);
if(code==null){
return;
}
codeArr[r][c] += code;
}
private static void toUp(int[][] chessArr, int r, int c) {
String codeStr = "0";
if (r == 0) {
return;
}
if (chessArr[r-1][c]==0) {
return;
}
codeStr+=chessArr[r-1][c]+"";
for (int i = r-2; i >=0; i--) {
if (chessArr[i][c ] == 0) {
codeStr += "0";
break;
} else if (chessArr[i][c ] == chessArr[i+1][c]) {
codeStr += chessArr[r-1][c] + "";
} else {
break;
}
}
Integer code = codeMap.get(codeStr);
if(code==null){
return;
}
codeArr[r][c] += code;
}
private static void toRightDown(int[][] chessArr, int r, int c) {
String codeStr = "0";
if (r==14||c==14){
return;
}
if (chessArr[r+1][c+1]==0) {
return;
}
codeStr+=chessArr[r+1][c+1];
for (int i = 2; i <= 14-r&&i<=14-c; i++) {
if (chessArr[i+r][c +i ] == 0) {
codeStr += "0";
break;
} else if (chessArr[i+r][c +i] == chessArr[i-1+r][c+i-1]) {
codeStr += chessArr[r+1][c+1 ] + "";
} else {
break;
}
}
Integer code = codeMap.get(codeStr);
if(code==null){
return;
}
codeArr[r][c] += code;
}
private static void toLeftUp(int[][] chessArr, int r, int c) {
String codeStr = "0";
if (r==0||c==0){
return;
}
if (chessArr[r-1][c-1]==0) {
return;
}
codeStr+=chessArr[r-1][c-1];
for (int i = 2; i <= r&&i<=c; i++) {
if (chessArr[r-i][c -i ] == 0) {
codeStr += "0";
break;
} else if (chessArr[r-i+1][c -i+1] == chessArr[r-i][c-i]) {
codeStr += chessArr[r-1][c-1 ] + "";
} else {
break;
}
}
Integer code = codeMap.get(codeStr);
if(code==null){
return;
}
codeArr[r][c] += code;
}
private static void toRightUp(int[][] chessArr, int r, int c) {
String codeStr = "0";
if (r==0||c==14){
return;
}
if (chessArr[r-1][c+1]==0) {
return;
}
codeStr+=chessArr[r-1][c+1];
for (int i = 2; i <= r&&i<=14-c; i++) {
if (chessArr[r-i][c +i ] == 0) {
codeStr += "0";
break;
} else if (chessArr[r-i][c +i] == chessArr[r-i+1][c+i-1]) {
codeStr += chessArr[r-1][c+1 ] + "";
} else {
break;
}
}
Integer code = codeMap.get(codeStr);
if(code==null){
return;
}
codeArr[r][c] += code;
}
private static void toLeftDown(int[][] chessArr, int r, int c) {
String codeStr = "0";
if (r==14||c==0){
return;
}
if (chessArr[r+1][c-1]==0) {
return;
}
codeStr+=chessArr[r+1][c-1];
for (int i = 2; i <= 14-r&&i<=c; i++) {
if (chessArr[i+r][c-i ] == 0) {
codeStr += "0";
break;
} else if (chessArr[i+r][c -i] == chessArr[i-1+r][c-i+1]) {
codeStr += chessArr[r+1][c-1 ] + "";
} else {
break;
}
}
Integer code = codeMap.get(codeStr);
if(code==null){
return;
}
codeArr[r][c] += code;
}
}
在落在棋盘外与正常落子外还有一种情况为重复落子,可将已落的棋子存入数组(存储其序号、位置、颜色),在判定棋子落入棋盘后再通过比较是否存在一组位置与当前落子位置相同判断是否为重新落子,遇到空指针直接跳过。
for (int a = 0; a <= index; a++)
{
StorageChess storageChess=Sto[a];
if (storageChess!=null)
{
if (c == (storageChess.X) && r == (storageChess.Y))
{
System.out.println("此处已落子");
JOptionPane.showMessageDialog(null, "此处已落子");
return;
}
}
}
可设置一个参数来控制是否开始落子和棋子颜色。
if (chessFlag==1)
{
g.setColor(Color.BLACK);
chessFlag=2;
}
else if (chessFlag==2)
{
g.setColor(Color.WHITE);
chessFlag=1;
}
}
并利用计算机整数除法忽略余数的特点修饰校正落子点。
int chessX=c*50+50-25;
int chessY=r*50+75-25;
g.fillOval(chessX,chessY,50,50);
可再引入二维数组用于储存棋子,先建造一个二维数组对应棋盘上的格子,在每次落子时在每个对应的数上进行修改,再根据五子棋规则进行判断胜负。其中为更为清晰适合再创建一个类再进行调用,其中只需在落子与点击AI下棋后判断胜负,所以只需在这两处后加入调用判断即可。
import javax.swing.*;
public class PdWin {
public static void Pdwin(int [][]chessarr) {
for (int a = 0; a <= 10; a++) {
for (int b = 0; b <= 10; b++) {
if (chessarr[a][b] != 0) {
if (chessarr[a + 1][b] == chessarr[a][b] && chessarr[a + 2][b] == chessarr[a][b] && chessarr[a + 3][b] == chessarr[a][b] && chessarr[a + 4][b] == chessarr[a][b]) {
if (chessarr[a][b] == 1) {
System.out.println("黑棋方胜利");
JOptionPane.showMessageDialog(null, "黑棋方胜利");
} else {
System.out.println("白棋方胜利");
JOptionPane.showMessageDialog(null, "白棋方胜利");
}
}
if (chessarr[a][b + 1] == chessarr[a][b] && chessarr[a][b + 2] == chessarr[a][b] && chessarr[a][b + 3] == chessarr[a][b] && chessarr[a][b + 4] == chessarr[a][b]) {
if (chessarr[a][b] == 1) {
System.out.println("黑棋方胜利");
JOptionPane.showMessageDialog(null, "黑棋方胜利");
} else {
System.out.println("白棋方胜利");
JOptionPane.showMessageDialog(null, "白棋方胜利");
}
}
if (chessarr[a + 1][b + 1] == chessarr[a][b] && chessarr[a + 2][b + 2] == chessarr[a][b] && chessarr[a + 3][b + 3] == chessarr[a][b] && chessarr[a + 4][b + 4] == chessarr[a][b]) {
if (chessarr[a][b] == 1) {
System.out.println("黑棋方胜利");
JOptionPane.showMessageDialog(null, "黑棋方胜利");
} else {
System.out.println("白棋方胜利");
JOptionPane.showMessageDialog(null, "白棋方胜利");
}
}
}
}
}
for (int a = 4; a <= 14; a++) {
for (int b = 0; b <= 10; b++) {
if (chessarr[a][b] != 0) {
if (chessarr[a - 1][b + 1] == chessarr[a][b] && chessarr[a - 2][b + 2] == chessarr[a][b] && chessarr[a - 3][b + 3] == chessarr[a][b] && chessarr[a - 4][b + 4] == chessarr[a][b]) {
if (chessarr[a][b] == 1) {
System.out.println("黑棋方胜利");
JOptionPane.showMessageDialog(null, "黑棋方胜利");
} else {
System.out.println("白棋方胜利");
JOptionPane.showMessageDialog(null, "白棋方胜利");
}
}
}
}
}
}
}
附:在添加重绘等代码可使得五子棋自动刷新。
//GoUI类中放入重绘前后皆可。
goListener.ui=this;
//加入监听器中
public GoUI ui;
//放在监听器最后
ui.repaint();