花了一个多星期才终于完善了我所有的五子棋。接下来给大家分享一款可以和朋友一起玩,闲暇时间陪你一起玩的居家旅行工具——五子棋。 (对了,我分享的不是游戏,而是游戏的制作方法)
一、制作接口
首先我们要做的就是打开你的(或者其他java编译软件,当然这些都是废话),然后我们开始制作五子棋的第一步:制作界面,制作方法接口相信没必要我多说,不知道怎么做接口的朋友可以看我之前的文章。代码直接附在这里:
public void showUI() {
// 窗体对象,JFrame默认是边框布局
JFrame jf = new JFrame();
jf.setTitle("五子棋1.0");
jf.setSize(800, 700);
// 设置退出进程的方法
jf.setDefaultCloseOperation(3);
// 设置居中显示
jf.setLocationRelativeTo(null);
GamePanel gp = new GamePanel(chessArray);
//设置棋盘背景色
gp.setBackground(new Color(139,139,122));
jf.add(gp,BorderLayout.CENTER);
//设置东边的属性
JPanel jp=new JPanel();
jp.setBackground(new Color(245,245,245));
jf.add(jp,BorderLayout.EAST);
//设置东边流式布局的属性
java.awt.FlowLayout fl=new java.awt.FlowLayout(5,5,60);
jp.setLayout(fl);
Dimension di=new Dimension(120,0);
jp.setPreferredSize(di);
//设置东边的按钮及按钮的属性
javax.swing.JButton jbu1=new javax.swing.JButton("开始游戏");
Dimension di1=new Dimension(100,60);
jbu1.setPreferredSize(di1);
jp.add(jbu1);
javax.swing.JButton jbu2=new javax.swing.JButton("人人对战");
Dimension di2=new Dimension(100,60);
jbu2.setPreferredSize(di2);
jp.add(jbu2);
javax.swing.JButton jbu3=new javax.swing.JButton("人机对战");
Dimension di3=new Dimension(100,60);
jbu3.setPreferredSize(di3);
jp.add(jbu3);
javax.swing.JButton jbu4=new javax.swing.JButton("悔棋");
Dimension di4=new Dimension(100,60);
jbu4.setPreferredSize(di4);
jp.add(jbu4);
javax.swing.JButton jbu5=new javax.swing.JButton("重新开始");
Dimension di5=new Dimension(100,60);
jbu5.setPreferredSize(di5);
jp.add(jbu5);
jf.setVisible(true);
顺便说一句,我们这里使用的不再是我们之前使用的流式布局。这里使用的布局就是布局,(即边框布局)。我们通常使用的默认是边框布局。评论也写了。虽然不是流式布局,但是我们可以将边框布局的block设置成我们想要的布局。我这里设置的是流布局。详情见代码。
二、创建按钮和监听器
界面完成后,我们要做的就是创建我们需要的按钮和按钮的监听器:
//设置按钮的动作监听器
jbu1.addActionListener(mouse);
jbu2.addActionListener(mouse);
jbu3.addActionListener(mouse);
jbu4.addActionListener(mouse);
jbu5.addActionListener(mouse);
然后在另一个类中创建一个监听方法:
public void mouseClicked(MouseEvent e) {
x1 = e.getX();
y1 = e.getY();
if (z == 1) {
rr();
}
if (z == 2) {
rj();
gameWin(xx, yy);
try {
Thread.sleep(350);
}catch(Exception ef) {}
a.ai();
gameWin(a.getmaxi(), a.getmaxj());
}
}
// 对设置的按钮进行功能实现
public int z;
public void actionPerformed(ActionEvent e) {
System.out.println("str" + e.getActionCommand());
if (e.getActionCommand().equals("开始游戏")) {
j.addMouseListener(this);
}
if (e.getActionCommand().equals("人人对战")) {
z = 1;
}
if (e.getActionCommand().equals("人机对战")) {
a = new AI(g, chessArray, j);
z = 2;
}
if (e.getActionCommand().equals("悔棋")) {
System.out.println("2");
for (int i = 0; i < LINE; i++) {
for (int j = 0; j < LINE; j++) {
chessArray[xx][yy] = 0;
count = 0;
}
}
j.repaint();
}
if (e.getActionCommand().equals("重新开始")) {
System.out.println("1");
// 调用repaint清空所有的棋子并使每个下过的点可以再下
for (int i = 0; i < LINE; i++) {
for (int j = 0; j < LINE; j++) {
chessArray[i][j] = 0;
count = 0;
}
}
j.repaint();
}
}
这里可以清楚的看到我设置的按钮和按钮方法的实现。因为我比较懒,先一起贴吧。之后游戏棋,我们将讨论按钮的功能实现。现在我只是告诉你创建一个监听器。 .
三、所有人对所有人
完成按键的监控,接下来我们将实现五子棋中最简单的可以让人娱乐的部分,也就是大家部分(和自己下棋,或者和朋友在同一台电脑下棋)。要完成大家的部分,我们首先要考虑的是如何搭建棋盘,如何让棋子落在棋盘线的交点上,如何让黑白交替出现。要做到这一点,我们首先要确定棋盘的宽度、高度和棋盘之间的间隔以及棋子的大小都是由你自己设定的。当然,为了让棋盘更加匀称美观,这些数据都是我亲测过的,大家也可以试试:
棋盘:
for(int i=0;i<LINE;i++){
g.drawLine(X, Y+i*SIZE, (LINE-1)*SIZE+X, Y+i*SIZE);
g.drawLine(X+i*SIZE, Y, X+i*SIZE, (LINE-1)*SIZE+Y);
}
控制棋盘的交点和黑白交替:
if ((x1 - X) % SIZE > SIZE / 2) {
xx = (x1 - X) / SIZE + 1;
} else {
xx = (x1 - X) / SIZE;
}
if ((y1 - Y) % SIZE > SIZE / 2) {
yy = (y1 - Y) / SIZE + 1;
} else {
yy = (y1 - Y) / SIZE;
}
// 控制棋子的黑白色交替出现
if (chessArray[xx][yy] == 0) {
if (count == 1) {
g.setColor(Color.WHITE);
chessArray[xx][yy] = 1;
count--;
} else {
g.setColor(Color.BLACK);
chessArray[xx][yy] = -1;
count++;
}
g.fillOval(xx * SIZE + X - CHESS / 2, yy * SIZE + Y - CHESS / 2,CHESS, CHESS);
}
做完这件事后,还要考虑输赢的情况。这也是大家最复杂的部分,未来人类和机器也会用到。整个五子棋的思路和精髓其实在于五子的判断:
// 判断黑棋和白棋的获胜方式
// 行
public int checkrow(int x, int y) {
int count1 = 0;// 存放连续的相同颜色的棋子数
for (int i = x + 1; i < 15; i++) {
if (chessArray[Math.abs(i)][y] == chessArray[x][y]) {
count1++;
System.out.println(count1);
} else {
break;
}
}
for (int i = x; i >= 0; i--) {
if (chessArray[Math.abs(i)][y] == chessArray[x][y]) {
count1++;
} else {
break;
}
}
return count1;
}
// 列
public int checkcolumn(int x, int y) {
int count1 = 0;// 存放连续的相同颜色的棋子数
for (int i = y + 1; i < 15; i++) {
if (chessArray[x][Math.abs(i)] == chessArray[x][y]) {
count1++;
} else {
break;
}
}
for (int i = y; i >= 0; i--) {
if (chessArray[x][Math.abs(i)] == chessArray[x][y]) {
count1++;
} else {
break;
}
}
return count1;
}
// 斜
public int checkinclined1(int x, int y) {
int count1 = 0;// 存放连续的相同颜色的棋子数
for (int i = x - 1, j = y - 1; i >= 0 && j >= 0; i--, j--) {
if (chessArray[i][j] == chessArray[x][y]) {
count1++;
System.out.println(count1);
} else {
break;
}
}
for (int i = x + 1, j = y + 1; i < LINE && j < LINE; i++, j++) {
if (chessArray[i][j] == chessArray[x][y]) {
count1++;
} else {
break;
}
}
return count1;
}
public int checkinclined2(int x, int y) {
int count1 = 0;
for (int i = x - 1, j = y + 1; i >= 0 && j < LINE; i--, j++) {
if (chessArray[i][j] == chessArray[x][y]) {
count1++;
} else {
break;
}
}
for (int i = x + 1, j = y - 1; i < LINE && j >= 0; i++, j--) {
if (chessArray[i][j] == chessArray[x][y]) {
count1++;
} else {
break;
}
}
return count1;
}
public void gameWin(int x,int y){
if(checkinclined1(x, y)>=4||checkinclined2(x,y)>=4||checkcolumn(x,y)>=5||checkrow(x,y)>=5){
if(chessArray[x][y] == -1){
hwin();
}else if(chessArray[x][y] == 1){
bwin();
}
}
}
这是判断五子棋胜负的一路。
完成大家判断走法、黑白交替、输赢的判断。相信大家已经对如何制作步步高供大家玩有一个基本的想法了。
四、人机大战
在完成了大家战斗的功能之后,接下来要做的就是我们简单的人工智能AI了。 AI在我们现在的生活中非常有名。相信大家一定对五子棋的AI很感兴趣吧,虽然五子棋的AI听起来很棒,但是并没有大家想象的那么复杂。我在这里没有使用任何特别强大的方法。我只是使用了一个哈希表并使用权重来让 AI 判断。达到我们简单人工智能的目的。首先我们需要创建一个权重表来存储不同棋子的权重,这里黑色是-1,白色是1:
HashMap<String, Integer> hm = new HashMap<String, Integer>();
public AI(Graphics g, int[][] chessArray, JPanel j) {
this.g = g;
this.chessArray = chessArray;
this.j = j; // 设置不同情况时的权值
hm.put("-1", 20);
hm.put("-1-1", 400);
hm.put("-1-1-1", 420);
hm.put("-1-1-1-1", 3000);
hm.put("-11", 4);
hm.put("-1-11", 40);
hm.put("-1-1-11", 400);
hm.put("-1-1-1-11", 10000);
hm.put("1-1-1-1-1", 10000);
hm.put("1", 8);
hm.put("11", 80);
hm.put("111", 1000);
hm.put("1111", 5000);
hm.put("1111-1", 5000);
hm.put("1111-1-1", 5000);
hm.put("1-1", 6);
hm.put("11-1", 60);
hm.put("111-1", 600);
hm.put("-11-1", 5);
hm.put("-111-1", 5);
hm.put("1-1-11", 5);
hm.put("1-11", 5);
}
这样,一个简单的权重表就完成了。事实上,这个重量表并不是很准确。可能有很多数值没有设置好,但作为一个简单的AI,还是可以和普通人一起玩的。建立哈希表并设置权重后,我们需要将需要的值存储在权重中。这里我们需要int类型,所以我们有如下代码来存储哈希表需要的数据:
public void ai() {
for (int i = 0; i < LINE; i++) {
for (int j = 0; j < LINE; j++) {
if (chessArray[i][j] == 0) {
String code = "";
int color = 0;
// 向右
for (int k = i + 1; k < 15; k++) {
if (chessArray[Math.abs(k)][j] == 0) {
break;
} else {
if (color == 0) { // 右边第一颗棋子
color = chessArray[Math.abs(k)][j]; // 保存颜色
code += chessArray[Math.abs(k)][j]; // 保存棋子相连情况
} else if (chessArray[Math.abs(k)][j] == color) {
code += chessArray[Math.abs(k)][j]; // 保存棋子相连情况
} else {
code += chessArray[Math.abs(k)][j]; // 保存棋子相连情况
break;
}
}
if (chessArray[i][j] != 0) {
chessValue[i][j] = 0;
}
}
Integer value = hm.get(code);
if (value != null) {
chessValue[i][j] += value;
}
if (value != null) {
chessValue[i][j] += value;
}
// 向左
code = "";
color = 0;
for (int k = i - 1; k >= 0; k--) {
if (chessArray[Math.abs(k)][j] == 0) {
break;
} else {
if (color == 0) { // 左边第一颗棋子
color = chessArray[Math.abs(k)][j]; // 保存颜色
code += chessArray[Math.abs(k)][j]; // 保存棋子相连情况
} else if (chessArray[Math.abs(k)][j] == color) {
code += chessArray[Math.abs(k)][j]; // 保存棋子相连情况
} else {
code += chessArray[Math.abs(k)][j]; // 保存棋子相连情况
break;
}
}
}
value = hm.get(code);
if (value != null) {
chessValue[i][j] += value;
}
if (chessArray[i][j] != 0) {
chessValue[i][j] = 0;
}
// 向上
code = "";
color = 0;
for (int k = j - 1; k >= 0; k--) {
if (chessArray[i][Math.abs(k)] == 0) {
break;
} else {
if (color == 0) { // 左边第一颗棋子
color = chessArray[i][Math.abs(k)]; // 保存颜色
code += chessArray[i][Math.abs(k)]; // 保存棋子相连情况
} else if (chessArray[i][Math.abs(k)] == color) {
code += chessArray[i][Math.abs(k)]; // 保存棋子相连情况
} else {
code += chessArray[i][Math.abs(k)]; // 保存棋子相连情况
break;
}
}
}
value = hm.get(code);
if (value != null) {
chessValue[i][j] += value;
}
if (chessArray[i][j] != 0) {
chessValue[i][j] = 0;
}
// 向下
code = "";
color = 0;
for (int k = j + 1; k < LINE; k++) {
if (chessArray[i][Math.abs(k)] == 0) {
break;
} else {
if (color == 0) { // 左边第一颗棋子
color = chessArray[i][Math.abs(k)]; // 保存颜色
code += chessArray[i][Math.abs(k)]; // 保存棋子相连情况
} else if (chessArray[i][Math.abs(k)] == color) {
code += chessArray[i][Math.abs(k)]; // 保存棋子相连情况
} else {
code += chessArray[i][Math.abs(k)]; // 保存棋子相连情况
break;
}
}
}
value = hm.get(code);
if (value != null) {
chessValue[i][j] += value;
}
if (chessArray[i][j] != 0) {
chessValue[i][j] = 0;
}
// 右下
code = "";
color = 0;
for (int k = i + 1, l = j + 1; k < LINE || l < LINE; k++, l++) {
if (chessArray[Math.abs(k)][Math.abs(l)] == 0) {
break;
} else {
if (color == 0) { // 左边第一颗棋子
color = chessArray[Math.abs(k)][Math.abs(l)]; // 保存颜色
code += chessArray[Math.abs(k)][Math.abs(l)]; // 保存棋子相连情况
} else if (chessArray[Math.abs(k)][Math.abs(l)] == color) {
code += chessArray[Math.abs(k)][Math.abs(l)]; // 保存棋子相连情况
} else {
code += chessArray[Math.abs(k)][Math.abs(l)]; // 保存棋子相连情况
break;
}
}
}
value = hm.get(code);
if (value != null) {
chessValue[i][j] += value;
}
if (chessArray[i][j] != 0) {
chessValue[i][j] = 0;
}
// 右上
code = "";
color = 0;
for (int k = i + 1, l = j - 1; k < LINE || l >= 0; k++, l--) {
if (chessArray[Math.abs(k)][Math.abs(l)] == 0) {
break;
} else {
if (color == 0) { // 左边第一颗棋子
color = chessArray[Math.abs(k)][Math.abs(l)]; // 保存颜色
code += chessArray[Math.abs(k)][Math.abs(l)]; // 保存棋子相连情况
} else if (chessArray[Math.abs(k)][Math.abs(l)] == color) {
code += chessArray[Math.abs(k)][Math.abs(l)]; // 保存棋子相连情况
} else {
code += chessArray[Math.abs(k)][Math.abs(l)]; // 保存棋子相连情况
break;
}
}
}
value = hm.get(code);
if (value != null) {
chessValue[i][j] += value;
}
if (chessArray[i][j] != 0) {
chessValue[i][j] = 0;
}
// 左上
code = "";
color = 0;
for (int k = i - 1, l = j - 1; k >= 0 || l >= 0; k--, l--) {
if (chessArray[Math.abs(k)][Math.abs(l)] == 0) {
break;
} else {
if (color == 0) { // 左边第一颗棋子
color = chessArray[Math.abs(k)][Math.abs(l)]; // 保存颜色
code += chessArray[Math.abs(k)][Math.abs(l)]; // 保存棋子相连情况
} else if (chessArray[Math.abs(k)][Math.abs(l)] == color) {
code += chessArray[Math.abs(k)][Math.abs(l)]; // 保存棋子相连情况
} else {
code += chessArray[Math.abs(k)][Math.abs(l)]; // 保存棋子相连情况
break;
}
}
}
value = hm.get(code);
if (value != null) {
chessValue[i][j] += value;
}
if (chessArray[i][j] != 0) {
chessValue[i][j] = 0;
}
// 左下
code = "";
color = 0;
for (int k = i - 1, l = j + 1; k >= 0 || l < LINE; k--, l++) {
if (chessArray[Math.abs(k)][Math.abs(l)] == 0) {
break;
} else {
if (color == 0) { // 左边第一颗棋子
color = chessArray[Math.abs(k)][Math.abs(l)]; // 保存颜色
code += chessArray[Math.abs(k)][Math.abs(l)]; // 保存棋子相连情况
} else if (chessArray[Math.abs(k)][Math.abs(l)] == color) {
code += chessArray[Math.abs(k)][Math.abs(l)]; // 保存棋子相连情况
} else {
code += chessArray[Math.abs(k)][Math.abs(l)]; // 保存棋子相连情况
break;
}
}
}
value = hm.get(code);
if (value != null) {
chessValue[i][j] += value;
}
if (chessArray[i][j] != 0) {
chessValue[i][j] = 0;
}
}
}
}
for (int j = 0; j < LINE; j++) {
for (int i = 0; i < LINE; i++) {
System.out.print(chessValue[i][j] + " ");
}
System.out.println();
}
for (int j = 0; j < LINE; j++) {
for (int i = 0; i < LINE; i++) {
System.out.print(chessArray[i][j] + " ");
}
System.out.println();
}
其实这个方法和之前判断五子连线的方法思路是一样的,所以我会说五子连线的思路其实就是五子棋的精髓。 (设置最后两个for循环,检查权重错误和颜色错误。)五子棋步法判断完成后,就要控制五子棋计算机的步法了。这里需要注意的是:每次我们下完棋和电脑下完棋后,都要判断输赢。这里我们需要用我上面写的语句来判断输赢,而且每走一步之后,我们都要将每一个点的权重清零。移动的点是彩色的,不能放在下面,代码如下:
// 判断权值最大的位置,并在该位置下棋。
int maxv = 0;
for (int i = 0; i < LINE; i++) {
for (int j = 0; j < LINE; j++) {
if (maxv < chessValue[i][j]) {
maxv = chessValue[i][j];
maxi = i;
maxj = j;
}
}
}
//画白棋
g.setColor(Color.WHITE);
g.fillOval(maxi * SIZE + X - CHESS / 2, maxj * SIZE + Y - CHESS / 2,CHESS, CHESS);
chessArray[maxi][maxj] = 1;
System.out.println("x" + maxi + "y" + maxj);
for (int i = 0; i < LINE; i++) {
for (int j = 0; j < LINE; j++) {
chessValue[i][j] = 0;
}
完成这些方法后,我们只需要调用监听类中的方法就可以了。
五、完成所有按钮功能并重绘
完成以上所有步骤后,我们就来到了我们步步高的最后一步,也就是步步高按钮功能的实现。我的五子棋按钮不多游戏棋,只有五个,每个都有不同的功能。 ,如果要实现这5个按钮的功能,可以先看看有没有想法:
其实看起来并不难,对吧?我们来看看:其实我们在开始游戏的时候,是想让鼠标在我们的棋盘上停止工作,所以我把面板的监听器放在了按钮的监听器里面。这样就达到了效果。人和人机要调用不同的方法,但是需要注意的是,每次调用一个下棋的方法,都要判断一次胜负,然后后悔重新开始。事实上,原理是相似的。 ,就是调用()方法重绘棋盘中的棋子,从而达到完美忏悔重启的目的,代码:
public int z;
public void actionPerformed(ActionEvent e) {
System.out.println("str" + e.getActionCommand());
if (e.getActionCommand().equals("开始游戏")) {
j.addMouseListener(this);
}
if (e.getActionCommand().equals("人人对战")) {
z = 1;
}
if (e.getActionCommand().equals("人机对战")) {
a = new AI(g, chessArray, j);
z = 2;
}
if (e.getActionCommand().equals("悔棋")) {
System.out.println("2");
for (int i = 0; i < LINE; i++) {
for (int j = 0; j < LINE; j++) {
chessArray[xx][yy] = 0;
count = 0;
}
}
j.repaint();
}
if (e.getActionCommand().equals("重新开始")) {
System.out.println("1");
// 调用repaint清空所有的棋子并使每个下过的点可以再下
for (int i = 0; i < LINE; i++) {
for (int j = 0; j < LINE; j++) {
chessArray[i][j] = 0;
count = 0;
}
}
j.repaint();
}
完成按钮功能的实现,然后重绘。其实之前我已经告诉过你,重绘其实就是调用paint方法,然后重绘我们要重绘的东西。这里我们要重绘的东西是棋盘和棋子,所以我们要重新创建一个类并在里面重绘:
public class GamePanel extends JPanel implements Config{
private int[][] chessArray;
public GamePanel(int[][] chessArray){
this.chessArray = chessArray;
}
public void paint(Graphics g){
super.paint(g);
//重绘棋盘
//硬编码
for(int i=0;i<LINE;i++){
g.drawLine(X, Y+i*SIZE, (LINE-1)*SIZE+X, Y+i*SIZE);
g.drawLine(X+i*SIZE, Y, X+i*SIZE, (LINE-1)*SIZE+Y);
}
paintChess(g);
}
/**
* 重绘棋子
* @param g
*/
public void paintChess(Graphics g){
for(int i=0;i<chessArray.length;i++){
for(int j=0;j<chessArray[i].length;j++){
if(chessArray[i][j] == 1){
g.setColor(Color.WHITE);
g.fillOval(i * SIZE + X - CHESS / 2, j * SIZE + Y - CHESS / 2, CHESS, CHESS);
}else if(chessArray[i][j] == -1){
g.setColor(Color.BLACK);
g.fillOval(i * SIZE + X - CHESS / 2, j * SIZE + Y - CHESS / 2, CHESS, CHESS);
}
}
}
}
}
顺便说一句,你可能会很困惑。我在每个类中都调用了一些大写的常量,比如LINE、X、Y等。其实这在java编程中是很重要的东西,它让我们改变编码更容易,我们称之为“硬编码”,在其实硬编码就是重新定义一个接口,把我们要使用的数据存储在接口中,这样以后需要修改代码的时候,会减少很多。工作量很大,我这里为每个类都继承了这样一个接口:
public interface Config {
public static final int X = 50;
public static final int Y = 40;
public static final int LINE = 15;
public static final int SIZE = 40;
public static final int CHESS = 30;
}
写到这里,我们的五子棋已经完成。相信大家已经了解了五子棋的制作方法,也有了自己制作一些小游戏的想法。如果您对我的五子棋有任何疑问或意见,可以评论与我讨论,我们下期再见! !