服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - Java实现简单的五子棋游戏示例代码

Java实现简单的五子棋游戏示例代码

2022-12-13 17:06错过了时间 Java教程

这篇文章主要为大家介绍了如何利用Java语言实现简单的五子棋游戏,文中的示例代码讲解详细,对我们学习Java游戏开发有一定帮助,需要的可以参考一下

项目结构

这个是在网上找的资源,出处记不得了,记录一下。程序的总体结构,很简单的:

Java实现简单的五子棋游戏示例代码

核心代码

代码如下:

ArrComparator.java类

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import java.util.Comparator;
 
/**
 * 排序 Comparator
 */
class ArrComparator implements Comparator<Object> {
    int column = 2;
 
    int sortOrder = -1; // 递减
 
    public ArrComparator() {
    }
    public int compare(Object a, Object b) {
        if (a instanceof int[]) {
            return sortOrder * (((int[]) a)[column] - ((int[]) b)[column]);
        }
        throw new IllegalArgumentException("param a,b must int[].");
    }
}

ChessMap.java类

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
import javax.swing.*;
 
import java.awt.*;
import java.awt.event.*;
import java.net.URL;
@SuppressWarnings("serial")
public class ChessMap extends JFrame {
    private ImageIcon map;              //棋盘背景位图
    private ImageIcon blackchess;       //黑子位图
    private ImageIcon whitechess;       //白子位图
    private ChessPanel cp;              //棋盘
    private JPanel east;
    private JPanel west;
    private static final int FINAL_WIDTH = 450;
    private static final int FINAL_HEIGHT = 500;
    //以下为下拉菜单
    private JMenuBar menubar;          
    private JMenu[] menu={new JMenu("开始"),new JMenu("设置"),new JMenu("帮助")};
    private JMenuItem[] menuitem1={new JMenuItem("重新开始"),new JMenuItem("悔棋"),new JMenuItem("退出")};
    private JMenuItem[] menuitem2={new JMenuItem("禁手选择"),new JMenuItem("人机博弈"),new JMenuItem("人人对弈")};
    private JMenuItem[] menuitem3={new JMenuItem("规则"),new JMenuItem("关于")};
    private boolean haveai=true;        //人与人下还是人与电脑下,true与电脑下
    Mouseclicked mouseclicked=new Mouseclicked();
    MouseMoved mousemoved=new MouseMoved();
    Menuitemclicked menuclicked=new Menuitemclicked();
    
    //构造函数
    public ChessMap(){
        //改变系统默认字体
        Font font = new Font("Dialog", Font.PLAIN, 12);
        java.util.Enumeration keys = UIManager.getDefaults().keys();
        while (keys.hasMoreElements()) {
            Object key = keys.nextElement();
            Object value = UIManager.get(key);
            if (value instanceof javax.swing.plaf.FontUIResource) {
                UIManager.put(key, font);
            }
        }
        setTitle("五子棋 ");
        setSize(FINAL_WIDTH,FINAL_HEIGHT);
        setResizable(false);
        init();
        setLocation(Toolkit.getDefaultToolkit().getScreenSize().width / 2
                - FINAL_WIDTH / 2, Toolkit.getDefaultToolkit()
                .getScreenSize().height
                / 2 - FINAL_HEIGHT / 2);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        cp.reset();
        setVisible(true);
    }
    
    //初始化与默认值
    public void init()
    {
        
        map=new ImageIcon(getClass().getResource("bg.jpg"));
        blackchess=new ImageIcon(getClass().getResource("blackchess.gif"));
        whitechess=new ImageIcon(getClass().getResource("whitechess.gif"));
        cp=new ChessPanel(map,blackchess,whitechess);
        menubar=new JMenuBar();
        menuitem1[0].setActionCommand("Restart");
        menuitem1[1].setActionCommand("Rollback");
        menuitem1[2].setActionCommand("Exit");
        menuitem2[0].setActionCommand("Forbid");
        menuitem2[1].setActionCommand("Robot");
        menuitem2[2].setActionCommand("Human");
        menuitem3[0].setActionCommand("Rule");
        menuitem3[1].setActionCommand("About");
        for(int i=0;i<3;i++)
            menu[0].add(menuitem1[i]);
        for(int i=0;i<3;i++)
            menu[1].add(menuitem2[i]);
        for(int i=0;i<2;i++)
            menu[2].add(menuitem3[i]);
        for(int i=0;i<3;i++)
            menubar.add(menu[i]);
        Container p = getContentPane();
        setJMenuBar(menubar);
        east = new JPanel();
        west = new JPanel();
        p.add(east, "East");
        p.add(west, "West");
        p.add(cp, "Center");
        cp.addMouseListener(mouseclicked);
        cp.addMouseMotionListener(mousemoved);
        menuitem1[0].addActionListener(menuclicked);
        menuitem1[1].addActionListener(menuclicked);
        menuitem1[2].addActionListener(menuclicked);
        menuitem2[0].addActionListener(menuclicked);
        menuitem2[1].addActionListener(menuclicked);
        menuitem2[2].addActionListener(menuclicked);
        menuitem3[0].addActionListener(menuclicked);
        menuitem3[1].addActionListener(menuclicked);
    
    }
    class Mouseclicked extends MouseAdapter     //判断鼠标左击并通知棋盘和电脑
    {
        public void mouseClicked(MouseEvent e)
        {
          if(cp.win==false){
                if(haveai){           //和电脑博弈
                          Point p1=new Point();
                          p1=cp.getPoint(e.getX(),e.getY());
                          int x=p1.x;
                          int y=p1.y;
                          // 如果该位置已经放置棋子
                          System.out.println("x="+x+",y="+y);
                          if (cp.isChessOn[x][y] != 2)
                                     return;
                          // 玩家为黑棋,考虑禁手
                          if( cp.able_flag && cp.bw == 0) {
                                 int type = cp.getType(x,y,cp.bw);
                                 String str = null;
                                 switch(type){
                                 case 20:
                                       str = "黑长连禁手!请选择其它位置下棋!";
                                       break;
                                 case 21:
                                       str = "黑四四禁手!请选择其它位置下棋!";
                                       break;
                                 case 22:
                                       str = "黑三三禁手!请选择其它位置下棋!";
                                       break;
                                 default : break;
                                 }
                                 if(str != null) {
                                        JOptionPane.showMessageDialog(null,str);
                                         return;
                                 }
                          }
                          boolean flag=cp.haveWin(x, y, cp.bw);
                          cp.update( x, y );
                          cp.putVoice();  //落子声音
                          // 第一步棋,需初始化设置边界值
                         if( cp.chess_num == 1){ 
                         if(x-1>=0)
                                  cp.x_min = x-1;
                         if(x-1<=15)
                                  cp.x_max = x+1;
                         if(y-1>=0)
                                  cp.y_min = y-1;
                         if(y-1<=15)
                                  cp.y_max = y+1;
                  }
                 else
                    cp.resetMaxMin(x,y);
                 if (flag) {
                     cp.wined(1 - cp.bw);
                     return;
                 }
                 cp.putOne(cp.bw);
            }else{                                        //和人博弈
                Point p1=new Point();
                p1=cp.getPoint(e.getX(),e.getY());
                int x=p1.x;
                int y=p1.y;
                 // 如果该位置已经放置棋子
                System.out.println("x="+x+",y="+y);
                 if (cp.isChessOn[x][y] != 2)
                             return;
                 // 玩家为黑棋,考虑禁手
                 if( cp.able_flag && cp.bw == 0) {
                       int type = cp.getType(x,y,cp.bw);
                       String str = null;
                       switch(type){
                       case 20:
                           str = "黑长连禁手!请选择其它位置下棋!";
                           break;
                       case 21:
                           str = "黑四四禁手!请选择其它位置下棋!";
                           break;
                       case 22:
                           str = "黑三三禁手!请选择其它位置下棋!";
                           break;
                       default : break;
                       }
                       if(str != null) {
                               JOptionPane.showMessageDialog(null,str);
                               return;
                       }
               }
                boolean flag=cp.haveWin(x, y, cp.bw);
                cp.update( x, y );
                cp.putVoice();  //落子声音
                cp.repaint();
              // 第一步棋,需初始化设置边界值
              if( cp.chess_num == 1){ 
                if(x-1>=0)
                    cp.x_min = x-1;
                  if(x-1<=15)
                    cp.x_max = x+1;
                  if(y-1>=0)
                    cp.y_min = y-1;
                  if(y-1<=15)
                    cp.y_max = y+1;
              }
              else
                cp.resetMaxMin(x,y);
              if (flag) {
                  cp.wined(1 - cp.bw);
                  return;
              }
            }
        }
        }
    }
    class MouseMoved implements MouseMotionListener     //调试用,获得鼠标位置
    {
        public void mouseMoved(MouseEvent e)
        {
            cp.showMousePos(e.getPoint());
        }
        public void mouseDragged(MouseEvent e)
        {}
    }
    class Menuitemclicked implements ActionListener     //菜单消息处理
    {
        public void actionPerformed(ActionEvent e)
        {
            JMenuItem target = (JMenuItem)e.getSource();
            String actionCommand = target.getActionCommand();
            if(actionCommand.equals("Restart")){        //重开一局
               cp.reset(); 
               if(cp.sbw==cp.WHITE_ONE)
                   cp.update(7, 7);
               //player=cp.BLACK_ONE;
            }
            if(actionCommand.equals("Rollback")){       //悔棋
                if(cp.win) {
                    JOptionPane.showMessageDialog(null,"棋局已经结束,不能悔棋!请重新开始新的棋局!");
                    return;
                }
                // 当前轮到玩家下棋,取消两步  否则,取消一步
                if(cp.chess_num >= 2 && cp.bw == cp.sbw){
                    cp.isChessOn[cp.pre[cp.chess_num-1][0]][cp.pre[cp.chess_num-1][1]] = 2;
                    cp.isChessOn[cp.pre[cp.chess_num-2][0]][cp.pre[cp.chess_num-2][1]] = 2;
                    cp.chess_num -= 2;
                    cp.repaint();
                }
                else if(cp.chess_num >= 1 && cp.bw == 1-cp.sbw){
                    cp.isChessOn[cp.pre[cp.chess_num-1][0]][cp.pre[cp.chess_num-1][1]] = 2;
                    cp.chess_num --;
                    cp.repaint();
                }
            }
            else if(actionCommand.equals("Exit")){      //退出
                System.exit(1);
            }
            else if(actionCommand.equals("Forbid")){     //禁手选择
                Object[] options = { "无禁手", "有禁手" };
                int sel = JOptionPane.showOptionDialog(
                        null, "你的选择:", "禁手选择",
                        JOptionPane.DEFAULT_OPTION,
                        JOptionPane.QUESTION_MESSAGE, null,
                        options, options[0]);
                if(sel==1){
                        cp.able_flag=true;
                        System.out.println("有禁手");
                }else{
                        cp.able_flag=false;
                        System.out.println("无禁手");
                }
            }
            else if(actionCommand.equals("Robot")){            //人机博弈
                haveai=true;
                Object[] options = { "人类先手", "机器先手" };
                int sel = JOptionPane.showOptionDialog(
                        null, "你的选择:", "先手选择",
                        JOptionPane.DEFAULT_OPTION,
                        JOptionPane.QUESTION_MESSAGE, null,
                        options, options[0]);
                if(sel==1){       //机器先手
                        cp.sbw=cp.WHITE_ONE;
                        cp.update(7, 7);
                        System.out.println("机器先手");
                        
                }else{             //人先手
                        //player=cp.BLACK_ONE;
                        cp.sbw=cp.BLACK_ONE;
                        System.out.println("人先手");
                }
            }
            else if(actionCommand.equals("Human")){         //人人博弈
                haveai=false;  
                cp.setHumanhuman(true);
            }else if(actionCommand.equals("Rule")){          //规则
                JOptionPane.showConfirmDialog(null,
                "1、无禁手:" +"\n"+
                "   黑白双方依次落子,任一方先在棋盘上形成连续的五个(含五个以上)棋子的一方为胜。" +"\n"+
                "2、有禁手:(走禁手就输,禁手不能落子)" +"\n"+
                "   鉴于无禁手规则黑棋必胜,人们不断采用一些方法限制黑棋先行的优势,以平衡黑白双方的形式。" +"\n"+
                "   于是针对黑棋的各种禁手逐渐形成。" +"\n"+
                "   禁手主要分为以下几类:" +"\n"+
                "   (1)黑长连禁手:连成六个以上连续相同的棋子。" +"\n"+
                "   (2)黑三三禁手:两个以上的活三。" + "\n"+
                "   (3)黑四四禁手:两个以上的四。" + "\n"+
                "   禁手是针对黑棋而言的,白棋没有任何禁手。" ,"规则",JOptionPane.CLOSED_OPTION,JOptionPane.INFORMATION_MESSAGE);
            }
            else if(actionCommand.equals("About")){         //版权与帮助
                JOptionPane.showConfirmDialog(null,"团队成员:\n" +"自行添加","关于",JOptionPane.CLOSED_OPTION,JOptionPane.INFORMATION_MESSAGE);  
            }
        }
 
    }
  public static void main(String[] args) {
        new ChessMap();
  }
}

ChessPanel.java类

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
import javax.sound.sampled.AudioInputStream;
import javax.swing.*;
import java.applet.AudioClip;
import java.awt.*;
import java.net.URL;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Random;
 
@SuppressWarnings("serial")
public class ChessPanel extends JPanel{
    private ImageIcon map;                  //棋盘背景位图
    private ImageIcon blackchess;           //黑子位图
    private ImageIcon whitechess;           //白子位图
    public int isChessOn [][];              //棋局
    protected boolean win = false;          // 是否已经分出胜负
    protected int win_bw;                   // 胜利棋色
    protected int deep = 3, weight = 7;    // 搜索的深度以及广度
    public int drawn_num = 110;           // 和棋步数
    int chess_num = 0;                      // 总落子数目
    public int[][] pre = new int[drawn_num + 1][2];    // 记录下棋点的x,y坐标   最多 (drawn_num + 1) 个
    public int sbw = 0;                          //玩家棋色黑色0,白色1
    public int bw = 0;                           // 当前应该下的棋色  0:黑色(默认), 1:白色
      // 边界值,用于速度优化
    protected int x_max = 15, x_min = 0;
    protected int y_max = 15, y_min = 0;
    protected boolean able_flag = true;       // 是否选择禁手标志 0:无禁手  1:有禁手(默认
    private int h;                          //棋子长
    private int w;                          //棋子宽
    private int insx;                       //插入棋子的位置
    private int insy;
    private Point mousePoint;               //鼠标当前位置
    private int winer;                      //获胜方
    private boolean humanhuman=false;       //是否是人人对弈
    private int plast=0;                    //走了几步了,
    public int BLACK_ONE;                   //0表黑子
    public int WHITE_ONE;                   //1表白子
    public int NONE_ONE;                    //2表无子
    public int N;                           //棋盘边长
 
    //-------声音
     String[] choics = { "put.wav", "win.wav","lost.wav" }; //声音文件名数组
     URL file1 = getClass().getResource(choics[0]); //落子声音文件
     URL file2 = getClass().getResource(choics[1]); //获胜声音文件
     URL file3 = getClass().getResource(choics[2]); //失败声音文件
     AudioClip soundPut = java.applet.Applet.newAudioClip(file1); //落子声音剪辑对象
     AudioClip soundWin = java.applet.Applet.newAudioClip(file2); //获胜声音剪辑对象
     AudioClip soundLost = java.applet.Applet.newAudioClip(file3); //失败声音剪辑对象
    
    public ChessPanel(){}
    public ChessPanel(ImageIcon r_map,ImageIcon r_blackchess,ImageIcon r_whitechess) {
        
        N=15;
        map=new ImageIcon();
        blackchess=new ImageIcon();
        whitechess=new ImageIcon();
        map=r_map;
        blackchess=r_blackchess;
        whitechess=r_whitechess;
        NONE_ONE=2;
        BLACK_ONE=0;
        WHITE_ONE=1;
        winer=NONE_ONE;
        isChessOn=new int[N][N];
        h=blackchess.getIconHeight()*(N-1);
        w=blackchess.getIconWidth()*(N-1);
        insx=0;
        insy=0;
        mousePoint=new Point();
        
    }
    
    public void reset(){                            //重开一局
        winer=NONE_ONE;
        for(int i=0;i<N;i++)
            for(int j=0;j<N;j++){
                isChessOn[i][j]=NONE_ONE;
            }
        chess_num = 0
        win = false;
        win_bw=2;
        bw = 0;
        x_max = 15; x_min = 0;
        y_max = 15;y_min = 0;
        repaint();
    }
    public void showMousePos(Point p){              //调试用,显示鼠标位置
        int cw;
        cw=h/N;
        mousePoint.x=p.x/cw;
        mousePoint.y=p.y/cw;
        repaint();
    }
    public Point getPoint(int x,int y){
        int cw;
        insx=x;
        insy=y;
        cw=h/N;
      Point r=new Point(x/cw,y/cw);
      return r;
    }
  public void gameOver(int r_winer){            //游戏胜负已分
    winer=r_winer;
  }
  public void paint(Graphics g){                //整体布局
    super.paint(g);
    paintChessMap(g);
    paintChess(g);
    if(winer==BLACK_ONE){
        g.drawString(new String("游戏结束!黑棋获胜!"),500,200);
        
    }
    else if(winer==WHITE_ONE){
        g.drawString(new String("游戏结束!白棋获胜!"),500,200);
    }
  }
  private void paintChessMap(Graphics g){       //画棋盘
    map.paintIcon(this,g,10,10);
    int j;
    g.setColor(Color.BLACK);
    for(j=0;j<N;j++){                            //画线
        g.drawLine(h/N/2,h/N*j+h/N/2,w-w/N+(N%2)*(h/N/2),h/N*j+h/N/2);
        g.drawLine(w/N*j+h/N/2,h/N/2,w/N*j+h/N/2,h-h/N+(N%2)*(h/N/2));
    }
    g.fillRect(w/N*7+h/N/2-3,h/N*7+h/N/2-3,6,6);//画5个黑方块
    g.fillRect(w/N*3+h/N/2-3,h/N*3+h/N/2-3,6,6);
    g.fillRect(w/N*11+h/N/2-3,h/N*3+h/N/2-3,6,6);
    g.fillRect(w/N*3+h/N/2-3,h/N*11+h/N/2-3,6,6);
    g.fillRect(w/N*11+h/N/2-3,h/N*11+h/N/2-3,6,6);
  }
  private void paintChess(Graphics g){          //画棋子
        int i,j;
        for(i=0;i<N;i++)
            for(j=0;j<N;j++){
                if(isChessOn[i][j]==BLACK_ONE){
                    blackchess.paintIcon(this,g,w/N*i,h/N*j);
                }
                else if(isChessOn[i][j]==WHITE_ONE){
                    whitechess.paintIcon(this,g,w/N*i,h/N*j);
                }  
            }
  }
  //-------------------------------下棋声音设置-------------------------------------------------
  
  //落子声音
  public void putVoice(){
        soundPut.play();    
  }
  //获胜声音
  public void winVoice(){
       soundWin.play();
  }
  //失败声音
  public void lostVoice(){
      soundLost.play();
  }
  
   //----------------------电脑下棋-------------------------------//
  public void  putOne(int bwf ) {  //bwf 棋色 0:黑色 1:白色
      int x, y, mx = -100000000;
      x = y = -1;
      // 搜索最优下棋点
      int[][] bests = getBests( bwf );
      for (int k = 0; k < bests.length; k++) {
          int i = bests[k][0];
          int j = bests[k][1];
          // 有成5,则直接下子,并退出循环..没有,则思考对方情况
          if (getType(i, j, bwf) == 1) {
              x = i;
              y = j;
              break;
          }
          if (getType(i, j,1 - bwf) == 1) {
              x = i;
              y = j;
              break;
          }
          // 预存当前边界值
          int temp1=x_min,temp2=x_max,temp3=y_min,temp4=y_max;
          // 预设己方下棋,并更新边界值
          isChessOn[i][j] = bwf;
          resetMaxMin(i,j);
          // 预测未来
          int t = findMin(-100000000, 100000000, deep);
          // 还原预设下棋位置以及边界值
          isChessOn[i][j] = 2;
          x_min=temp1;
          x_max=temp2;
          y_min=temp3;
          y_max=temp4;
          // 差距小于1000,50%概率随机选取
          //System.out.println("外       :" + i + "," + j + "  mx:" + mx + "  t:" + t);
          if (t - mx > 1000 || Math.abs(t - mx)<1000 && randomTest(3)) {
              x = i;
              y = j;
              mx = t;
              //System.out.println(i + "," + j + "  mx:" + mx + "  t:" + t);
          }
         
      }
      System.out.println("x="+x+",y="+y);
     // addChess(x,y,(bwf+1)%2,true);
     // repaint();
      int step=0;
        step++;
        System.out.println("step "+step+":-----------------------------------------------");
        for(int i=0;i<15;i++,System.out.print("\n"))
            for(int j=0;j<15;j++)
                {
                    if(isChessOn[j][i]!=2)System.out.print(isChessOn[j][i]);
                    else    System.out.print(isChessOn[j][i]);
                }  
    // 判断是否已分胜负
    boolean flag = haveWin(x, y, bwf);
       //记录
      update( x, y );
      repaint();
      // 重设边界值
      resetMaxMin(x,y);
     //  胜负已分
      if (flag)
          wined(bwf);
      if (!flag && chess_num >= drawn_num) {
          win = true;
          String str = drawn_num + "步没分胜负,判和棋!";
          JOptionPane.showMessageDialog(null,str);
          return;
      }
         
  }
  
  //---------搜索当前搜索状态极大值--------------------------------//
  //alpha 祖先节点得到的当前最小最大值,用于alpha 剪枝
  //beta  祖先节点得到的当前最大最小值,用于beta 剪枝。
  //step  还要搜索的步数
  //return 当前搜索子树极大值
  protected int findMax(int alpha, int beta, int step) {
    int max = alpha;
      if (step == 0) {
          return evaluate();
      }
      int[][] rt = getBests(1 - sbw);
      for (int i = 0; i < rt.length; i++) {
          int x = rt[i][0];
        int y = rt[i][1];
        if (getType(x, y, 1 - sbw) == 1)   //电脑可取胜
            return 100 * ( getMark(1) + step*1000 );
          isChessOn[x][y] = 1 - sbw;
          // 预存当前边界值
          int temp1=x_min,temp2=x_max,temp3=y_min,temp4=y_max;
          resetMaxMin(x,y);
          int t = findMin(max, beta, step - 1);
          isChessOn[x][y] = 2;
          // 还原预设边界值
          x_min=temp1;
          x_max=temp2;
          y_min=temp3;
          y_max=temp4;
          if (t > max)
            max = t;
          //beta 剪枝
          if (max >= beta)
              return max;
      }
      return max;
  }
  
 
   //-----------------------搜索当前搜索状态极小值---------------------------------//
   //alpha 祖先节点得到的当前最小最大值,用于alpha 剪枝
  //beta  祖先节点得到的当前最大最小值,用于beta 剪枝
  //step  还要搜索的步数
 //return 当前搜索子树极小值。
  protected int findMin(int alpha, int beta, int step) {
    int min = beta;
      if (step == 0) {
          return evaluate();
      }
      int[][] rt = getBests(sbw);
      for (int i = 0; i < rt.length; i++) {
          int x = rt[i][0];
          int y = rt[i][1];
          int type = getType(x, y, sbw);
          if (type == 1)                                    //玩家成5
              return -100 * ( getMark(1) + step*1000 );
          // 预存当前边界值
          int temp1=x_min,temp2=x_max,temp3=y_min,temp4=y_max;
          isChessOn[x][y] = sbw;
          resetMaxMin(x,y);
          int t = findMax( alpha, min, step - 1 );
          isChessOn[x][y] = 2;
          // 还原预设边界值
          x_min=temp1;
          x_max=temp2;
          y_min=temp3;
          y_max=temp4;
          if (t < min)
            min = t;
          //alpha 剪枝
          if (min <= alpha) {
              return min;
          }
      }
      return min;
  }
 
 
   //-----------------选取局部最优的几个落子点作为下一次扩展的节点---------//
   //bwf 棋色 0:黑棋 1:白棋
   //return 选出来的节点坐标
  private int[][] getBests(int bwf) {
 
      int i_min=(x_min==0 ? x_min:x_min-1);
      int j_min=(y_min==0 ? y_min:y_min-1);
      int i_max=(x_max==15 ? x_max:x_max+1);
      int j_max=(y_max==15 ? y_max:y_max+1);
      int n = 0;
      int type_1,type_2;
      int[][] rt = new int[(i_max-i_min) * (j_max-j_min)][3];
      for ( int i = i_min; i < i_max; i++)
        for (int j = j_min; j < j_max; j++)
            if (isChessOn[i][j] == 2) {
                  type_1 = getType(i, j, bwf);
                  type_2 = getType(i, j, 1 - bwf);
                  if(able_flag && bwf==0 && (type_1 == 20 || type_1 == 21 || type_1 == 22)) // 禁手棋位置,不记录
                    continue;
                  rt[n][0] = i;
                  rt[n][1] = j;
                  rt[n][2] = getMark(type_1) + getMark(type_2);
                  n++;
      }
      // 对二维数组排序
      Arrays.sort(rt, new ArrComparator());
      int size = weight > n? n:weight;
      int[][] bests = new int[size][3];
      System.arraycopy(rt, 0, bests, 0, size);
      return bests;
  }
 
   //----------------------------计算指定方位上的棋型-------------------//
   // x,y 方向线基准一点。
   //ex,ey 指定方向步进向量。
   // k 棋子颜色,0:黑色,1:白色
   // 该方向上的棋子数目 以及 活度
  private int[] count(int x, int y, int ex, int ey, int bwf) {
    // 该方向没意义,返回0
      if( !makesense(x, y, ex, ey, bwf))
          return new int[] {0, 1};
      
      // 正方向 以及 反方向棋子个数
    int rt_1 = 1,rt_2 = 1;
    // 总棋子个数
    int rt = 1;
    // 正方向 以及 反方向连子的活度
      int ok_1 = 0,ok_2 =0;
      // 总活度
      int ok = 0;
      // 连子中间有无空格
      boolean flag_mid1 =false,flag_mid2 = false;
      // 连子中间空格的位置
      int flag_i1 = 1,flag_i2 = 1;
      
      if (isChessOn[x][y] != 2) {
          throw new IllegalArgumentException("position x,y must be empty!..");
      }
      int i;
      // 往正方向搜索
      for (i = 1; x + i * ex < 15 && x + i * ex >= 0 && y + i * ey < 15 && y + i * ey >= 0; i++) {
          if (isChessOn[x + i * ex][y + i * ey] == bwf)
              rt_1++;
        // 位置为空,若中空标志为false,则记为中空并继续搜索  否则,break
          else if(isChessOn[x + i * ex][y + i * ey] == 2) {
                if(!flag_mid1) {
                    flag_mid1 = true;
                    flag_i1 = i;
                }
                else
                    break;
            }
          // 位置为对方棋子
          else   
            break;
      }
      // 计算正方向活度,,
      // 最后一个位置不超过边界
      if (x + i * ex < 15 && x + i * ex >= 0 && y + i * ey < 15 && y + i * ey >= 0) {
        // 最后一个位置为空位 +1活
        if( isChessOn[x + i * ex][y + i * ey] == 2) {
            ok_1++;
            // 若是在尾部检测到连续的空格而退出搜索,则不算有中空
              if(rt_1 == flag_i1)
                flag_mid1 = false;
              // 若中空的位置在4以下 且 棋子数>=4,则这一边的4非活
              if(flag_mid1 && rt_1 > 3 && flag_i1 < 4) {
                ok_1--;
              }
        }
        // 最后一个位置不是空格,且搜索了2步以上,若前一个是空格,  则不算中空,且为活的边
        else if( isChessOn[x + i * ex][y + i * ey] != bwf && i >= 2)
            if(isChessOn[x + (i-1) * ex][y + (i-1) * ey] == 2) {
                ok_1++;
                flag_mid1 = false;
            }
      }
      // 最后一个位置是边界  搜索了2步以上,且前一个是空格,  则不算中空,且为活的边
      else if(i >= 2 && isChessOn[x + (i-1) * ex][y + (i-1) * ey] == 2) {
        ok_1++;
        flag_mid1 = false;
      }
      
      // 往反方向搜索       
      for (i = 1; x - i * ex >= 0 && x - i * ex < 15 && y - i * ey >= 0 && y - i * ey < 15; i++) {
          if (isChessOn[x - i * ex][y - i * ey] == bwf)
              rt_2++;
          else if(isChessOn[x - i * ex][y - i * ey] == 2) {
                if(!flag_mid2) {
                    flag_mid2 = true;
                    flag_i2 = i;
                }
                else
                    break;
            }
          else
              break;
      }
      // 计算反方向活度
      if (x - i * ex < 15 && x - i * ex >= 0 && y - i * ey < 15 && y - i * ey >= 0) {
        if( isChessOn[x - i * ex][y - i * ey] == 2) {
            ok_2++;
            if(rt_2 == flag_i2)
                flag_mid2 = false;
            if(flag_mid2 && rt_2 > 3 && flag_i2 < 4) {
                ok_2--;
              }
        }
        else if( isChessOn[x - i * ex][y - i * ey] != bwf && i >= 2 )
            if(isChessOn[x - (i-1) * ex][y - (i-1) * ey] == 2) {
                ok_2++;
                flag_mid2 = false;
            }
      }
      else if(i >= 2 && isChessOn[x - (i-1) * ex][y - (i-1) * ey] == 2) {
        ok_2++;
        flag_mid2 = false;
      }
      
      //------------------分析棋子类型
      // 两边都没中空,直接合成
      if( !flag_mid1 && !flag_mid2 ) {
        rt = rt_1 + rt_2 - 1;
        ok = ok_1 + ok_2;
        return new int[] {rt, ok};
      }
      // 两边都有中空
      else if( flag_mid1 && flag_mid2 ){
        int temp = flag_i1 + flag_i2 - 1;
        // 判断中间的纯连子数,在5以上,直接返回;  为4,返回活4; 
        if(temp >= 5)
            return new int[] {temp, 2};
        if(temp == 4)
            return new int[] {temp, 2};
        // 先看有没死4,再看有没活3,剩下只能是死3
        if(rt_1 + flag_i2 - 1 >= 4 || rt_2 + flag_i1 - 1 >= 4)
            return new int[] {4, 1};
        if(rt_1+flag_i2-1 == 3 && ok_1 > 0 || rt_2+flag_i1-1 == 3 && ok_2 > 0)
            return new int[] {3, 2};
        return new int[] {3, 1};
      }
      // 有一边有中空
      else {
        // 总棋子数少于5,直接合成
        if( rt_1 + rt_2 - 1 < 5 )
            return new int[] {rt_1 + rt_2 - 1, ok_1 + ok_2};
        // 多于5,先找成5,再找活4,剩下的只能是死4
        else {
            if(flag_mid1 && rt_2 + flag_i1 - 1 >= 5)
                return new int[] {rt_2 + flag_i1 - 1, ok_2 + 1};
            if(flag_mid2 && rt_1 + flag_i2 - 1 >= 5)
                return new int[] {rt_1 + flag_i2 - 1, ok_1 + 1};
            
            if(flag_mid1 && (rt_2 + flag_i1 - 1 == 4 && ok_2 == 1 || flag_i1 == 4) )
                return new int[] {4, 2};
            if(flag_mid2 && (rt_1 + flag_i2 - 1 == 4 && ok_1 == 1 || flag_i2 == 4) )
                return new int[] {4, 2};
            
            return new int[] {4, 1};
        }
      }
  }
 
   //----------------------------判断指定方向下棋是否有意义,即最大可能的棋子数是否 >=5-------------------------------//
   // x,y 评估的基准点
   // ex,ey 方向向量
   // k 棋色
   // true:有意义 false:没意义
  private Boolean makesense(int x, int y, int ex, int ey, int bwf) {
 
      int rt = 1;
      for (int i = 1; x + i * ex < 15 && x + i * ex >= 0 && y + i * ey < 15 && y + i * ey >= 0 && rt < 5; i++)
          if (isChessOn[x + i * ex][y + i * ey] != 1 - bwf)
              rt++;
          else
              break;
 
      for (int i = 1; x - i * ex >= 0 && x - i * ex < 15 && y - i * ey >= 0 && y - i * ey < 15 && rt < 5; i++)
          if (isChessOn[x - i * ex][y - i * ey] != 1 - bwf)
              rt++;
          else
              break;
      return (rt >= 5);
  }
 
   //------------------------------------ 棋型判别-------------------------------------//
   // x,y 落子位置
   // bwf 棋色  0:黑子,1:白子
   // 对应的棋型: 棋型代码对应如下:
   //             1:成5
   //             2:成活4或者是双死4或者是死4活3
   //             3:成双活3
   //             4:成死3活3
   //             5:成死4
   //             6:单活3
   //             7:成双活2
  //             8:成死3
   //            9:成死2活2
   //            10:成活2
   //             11:成死2
   //             12: 其他
   //             20: 长连禁手
   //             21: 双四禁手
   //            22: 双活三禁手
 
  protected int getType(int x, int y, int bwf) {
    if (isChessOn[x][y] != 2)
          return -1;
    int[][] types = new int[4][2];
    types[0] = count(x, y, 0, 1, bwf);   // 竖直
      types[1] = count(x, y, 1, 0, bwf);   // 横向
      types[2] = count(x, y, -1, 1, bwf);  // 斜上
      types[3] = count(x, y, 1, 1, bwf);   // 斜下
      // 各种棋型的方向的数目
      int longfive = 0;
      int five_OR_more = 0;
      int four_died = 0, four_live = 0;
      int three_died = 0, three_live = 0;
      int two_died  = 0, two_live = 0;
      // 各方向上棋型的判别
      for (int k = 0; k < 4; k++) {
        if (types[k][0] > 5) { 
            longfive++;              // 长连
            five_OR_more++;
        }
        else if (types[k][0] == 5)
            five_OR_more++;          // 成5
          else if (types[k][0] == 4 && types[k][1] == 2)
            four_live++;             // 活4
          else if (types[k][0] == 4 && types[k][1] != 2)
            four_died++;             // 死4
          else if (types[k][0] == 3 && types[k][1] == 2)
            three_live ++;           // 活3
          else if (types[k][0] == 3 && types[k][1] != 2)
            three_died++;            // 死3
          else if (types[k][0] == 2 && types[k][1] == 2)
            two_live++;              // 活2
          else if (types[k][0] == 2 && types[k][1] != 2)
            two_died++;              // 死2
          else
              ;
      }
      // 总棋型的判别
      if(bwf == 0 && able_flag) {       // 黑棋且选择有禁手
        if (longfive != 0)              // 长连禁手
            return 20;
        if (four_live + four_died >=2// 双4禁手
            return 21;
        if (three_live  >=2)         // 双活三禁手
            return 22;
      }
      if (five_OR_more != 0)
          return 1;   // 成5
      if (four_live != 0 || four_died >= 2 || four_died != 0 && three_live  != 0)
          return 2;   // 成活4或者是双死4或者是死4活3
      if (three_live  >= 2)
          return 3;   // 成双活3
      if (three_died != 0 && three_live  != 0)
          return 4;   // 成死3活3
      if (four_died != 0)
          return 5;   // 成死4
      if (three_live  != 0)
          return 6;   // 单活3
      if (two_live >= 2)
          return 7;   // 成双活2
      if (three_died != 0)
          return 8;   // 成死3
      if (two_live != 0 && two_died != 0)
          return 9;   // 成死2活2
      if (two_live != 0)
          return 10// 成活2
      if (two_died != 0)
          return 11// 成死2
      return 12;
  }
 
   //--------------------------对当前棋面进行打分------------------------------------------------------------//
 
  protected int evaluate() {
    int rt = 0, mt_c = 1, mt_m = 1;
    if(bw == sbw)
        mt_m = 2;
    else
        mt_c = 2;
    int i_min=(x_min==0 ? x_min:x_min-1);
      int j_min=(y_min==0 ? y_min:y_min-1);
      int i_max=(x_max==15 ? x_max:x_max+1);
      int j_max=(y_max==15 ? y_max:y_max+1);
      for (int i = i_min; i < i_max; i++)
          for (int j = j_min; j < j_max; j++)
              if (isChessOn[i][j] == 2) {
                // 电脑棋面分数
                  int type = getType(i, j, 1 - sbw );
                  if(type == 1)      // 棋型1,棋型2以及棋型3,加权.  防止"4个双活3"的局分大于"1个双四"之类的错误出现
                    rt += 30 * mt_c * getMark(type);
                  else if(type == 2)                   
                    rt += 10 * mt_c * getMark(type);
                  else if(type == 3)
                    rt += 3 * mt_c * getMark(type);
                  else
                    rt += mt_c * getMark(type);
                  // 玩家棋面分数
                  type = getType(i, j, sbw );
                  if(type == 1)
                    rt -= 30 * mt_m * getMark(type);
                  else if(type == 2)                   
                    rt -= 10 * mt_m * getMark(type);
                  else if(type == 3)
                    rt -= 3 * mt_m * getMark(type);
                  else
                    rt -= mt_m * getMark(type);
              }
      return rt;
  }
 
   //--------------------------------下棋后,更新信息-----------------------------//
  void update(int x,int y) {
    isChessOn[x][y] = bw;
      bw = 1 - bw;
      pre[chess_num][0] = x;
      pre[chess_num][1] = y;
      chess_num++;
  }
  
   //-------------------------------------- 下棋后,重设边界值------------------------------//
   // x 当前下棋位置的x坐标
   // y 当前下棋位置的y坐标
 
  public void resetMaxMin(int x,int y){
        if(x-1>=0)
        x_min = (x_min<x-1 ? x_min:x-1);
      if(x+1<=15)
        x_max = (x_max>x+1 ? x_max:x+1);
      if(y-1>=0)
        y_min = (y_min<y-1 ? y_min:y-1);
      if(y+1<=15)
        y_max = (y_max>y+1 ? y_max:y+1);
  
  }
  
 
   //------------------------------------------对分数相同的落子点,随机选取-------------------//
   //   kt 随机因子 值越小,被选取的概率越大
   //  return 是否选择该位置
 
  private boolean randomTest(int kt) {
      Random rm = new Random();
      return rm.nextInt() % kt == 0;
  }
 
 
   //------------------------------------- 不同棋型对应分数---------------------------------
   // k 棋型代号
   //return 对应分数
  private int getMark(int k) {
      switch (k) {
      case 1:                  
          return 100000;
      case 2:                  
          return 30000;
      case 3:
          return 5000;
      case 4:
          return 1000;
      case 5:
          return 500;
      case 6:
          return 200;
      case 7:
          return 100;
      case 8:
          return 50;
      case 9:
          return 10;
      case 10:
          return 5;
      case 11:
          return 3;
      case 12:
          return 2;
      default:                     //禁手棋型
          return 0;
      }
  }
 
   //--------------------------------------- 判断是否已分出胜负---------------------------------------------
   // x 落子点x坐标    y 落子点y坐标
   // bwf 棋色 0:黑色 1:白色
   // return true:分出胜负 false:未分出胜负
 
  public boolean haveWin(int x, int y, int bwf) {
      boolean flag = false;
      if (count(x, y, 1, 0, bwf)[0] >= 5)
          flag = true;
      if (!flag && count(x, y, 0, 1, bwf)[0] >= 5)
          flag = true;
      if (!flag && count(x, y, 1, 0, bwf)[0] >= 5)
          flag = true;
      if (!flag && count(x, y, 1, -1, bwf)[0] >= 5)
          flag = true;
      if (!flag && count(x, y, 1, 1, bwf)[0] >= 5)
          flag = true;
      // 测试用,激活此行代码,不会有输赢..   flag = false;
      return flag;
  }
 
  public void wined(int bw) {
      boolean hh=getHumanhuman();
      if(!hh){           //不是人人对弈
           win = true;
           win_bw = bw;
           String str = (bw == sbw ? "恭喜!你赢了!" : "电脑赢了,你还要继续努力啊!");
           if(bw==sbw)
                winVoice();
           else
                lostVoice();
           JOptionPane.showMessageDialog(null,str);
      }
      else{             //人人对弈
          win = true;
          win_bw = bw;
          String str = (bw == BLACK_ONE ? "恭喜!黑棋获胜!" : "恭喜!白棋获胜!");
          winVoice();
          JOptionPane.showMessageDialog(null,str);
      }
  }
public void setHumanhuman(boolean humanhuman) {
    this.humanhuman = humanhuman;
}
public boolean getHumanhuman() {
    return humanhuman;
}
}

效果图展示

运行截图:

Java实现简单的五子棋游戏示例代码

看了这么多,是不是没看懂,这里给出链接,剩下的就靠大家努力啦!

以上就是Java实现简单的五子棋游戏示例代码的详细内容,更多关于Java五子棋的资料请关注服务器之家其它相关文章!

原文链接:https://blog.csdn.net/Code__rookie/article/details/103505531

延伸 · 阅读

精彩推荐