五子棋人机对战设计与实践

这款五子棋小游戏是我五六年前在培训学习JAVA的时候花了一整个下午时间即兴写出来的,功能很简单,实现了五子棋的电脑对战,主要就是为了研究下电脑下棋算法,所以其他的功能和细节都没考虑,比如电脑最后的落子点我是直接用图片标示出来的,最好是另建一个线程来闪烁最后落子点,还有智能等级也是可以调节的,偏重于防守和进攻都可以修改代码中权值的设定来实现的,有兴趣的朋友可以在此基础上扩展一下。因为没有写谁先下棋的功能,可以模拟下电脑先下子,只需要你在边角上先下一子就可以了,相比下来,电脑先下的话,电脑赢的几率更大点,一共用到了三张图片,都在附件中。

 



 下面是全部的代码,写了一些注释,希望能对你阅读代码起到一点帮助

 

Java代码 

  1. import java.awt.*;   
  2. import java.awt.event.*;   
  3. import java.net.URL;   
  4.   
  5. import javax.swing.*;   
  6. public class GobangGame {   
  7.     public static void main(String[] args) {   
  8.         GameF game = new GameF();   
  9.         game.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);   
  10.         game.show();   
  11.     }   
  12. }   
  13. class GameF extends JFrame {   
  14.     public GameF() {   
  15.         Container contentPane = getContentPane();   
  16.         final Panel panel = new Panel();   
  17.         panel.setBackground(new Color(255, 182, 147));   
  18.         contentPane.setBackground(new Color(255, 182, 147));   
  19.         contentPane.add(panel);   
  20.         setSize(560, 560);   
  21.         setTitle("杨雷的五子棋游戏 版本1.0");   
  22.         setResizable(false);   
  23.         panel.setCursor(new Cursor(Cursor.HAND_CURSOR));   
  24.         JMenuBar menuBar=new JMenuBar();   
  25.         JMenu menu=new JMenu("选项");   
  26.         JMenuItem menuStart=new JMenuItem("开始游戏");   
  27.         menuStart.addActionListener(new ActionListener(){   
  28.            public void actionPerformed(ActionEvent e){   
  29.               panel.ResetGame();   
  30.               panel.repaint();   
  31.            }   
  32.         });   
  33.         JMenuItem menuExit =new JMenuItem("退出");   
  34.         menuExit.addActionListener(new ActionListener(){   
  35.             public void actionPerformed(ActionEvent e){   
  36.                   System.exit(0);   
  37.             }   
  38.          });   
  39.         menuBar.add(menu);   
  40.         menu.add(menuStart);   
  41.         menu.add(menuExit);   
  42.         this.setJMenuBar(menuBar);   
  43.       }   
  44. }   
  45. class Panel extends JPanel {   
  46.     private URL blackImgURL = GobangGame.class.getResource("black.gif");   
  47.     private ImageIcon black=new ImageIcon(blackImgURL);   
  48.     private URL whiteImgURL = GobangGame.class.getResource("white.gif");   
  49.     private ImageIcon white=new ImageIcon(whiteImgURL);   
  50.     private URL currentImgURL = GobangGame.class.getResource("current.gif");   
  51.     private ImageIcon current=new ImageIcon(currentImgURL);   
  52.     private int i, j, k, m, n, icount;   
  53.     private int[][] board = new int [16][16];   
  54.     private boolean[][][] ptable = new boolean[16][16][672];   
  55.     private boolean[][][] ctable = new boolean[16][16][672];   
  56.     private int[][] cgrades = new int[16][16];   
  57.     private int[][] pgrades = new int[16][16];   
  58.     private int cgrade,pgrade;   
  59.     private int[][] win = new int[2][672];   
  60.     private int oldx,oldy;   
  61.     private int bout=1;   
  62.     private int pcount,ccount;   
  63.     private boolean player,computer,over,pwin,cwin,tie,start;   
  64.     private int mat,nat,mde,nde;   
  65.     public Panel(){   
  66.         addMouseListener(new Xiazi());   
  67.         this.ResetGame();   
  68.      }   
  69.      public void paintComponent(Graphics g) {   
  70.         super.paintComponent(g);   
  71.         for (int i = 0; i < 16; i++)   
  72.             for (int j = 0; j < 16; j++){   
  73.                 g.drawLine(50, 50 + j * 30, 500, 50 + j * 30);   
  74.             }   
  75.         for (int i = 0; i < 16; i++)   
  76.             for (int j = 0; j < 16; j++){   
  77.                 g.drawLine(50 + j * 30, 50, 50 + j * 30, 500);   
  78.             }   
  79.         for (int i = 0; i < 16; i++){   
  80.             String number = Integer.toString(i);   
  81.             g.drawString(number, 46 + 30 * i, 45);   
  82.         }   
  83.         for (int i = 1; i < 16; i++){   
  84.             String number = Integer.toString(i);   
  85.             g.drawString(number, 33, 53 + 30 * i);   
  86.         }   
  87.        updatePaint(g);   
  88.     }   
  89.     class Xiazi extends MouseAdapter{   
  90.         public void mouseClicked(MouseEvent e){   
  91.             if(!over)   
  92.             {   
  93.                 oldx = e.getX();   
  94.                 oldy = e.getY();    
  95.                 mouseClick();   
  96.                 repaint();   
  97.             }   
  98.         }   
  99.      }   
  100. //      游戏初始化   
  101.         public void ResetGame()   
  102.         {    
  103.             //初始化棋盘   
  104.             for(i=0;i<16;i++)   
  105.                 for(j=0;j<16;j++)   
  106.                 {   
  107.                     this.pgrades[i][j] = 0;   
  108.                     this.cgrades[i][j] = 0;   
  109.                     this.board[i][j] = 2;   
  110.                 }   
  111.             //遍历所有的五连子可能情况的权值   
  112.             //横   
  113.             for(i=0;i<16;i++)   
  114.                 for(j=0;j<12;j++){   
  115.                     for(k=0;k<5;k++){   
  116.                         this.ptable[j+k][i][icount] = true;   
  117.                         this.ctable[j+k][i][icount] = true;   
  118.                     }   
  119.                     icount++;   
  120.                 }   
  121.             //竖   
  122.             for(i=0;i<16;i++)   
  123.                 for(j=0;j<12;j++){   
  124.                     for(k=0;k<5;k++){   
  125.                         this.ptable[i][j+k][icount] = true;   
  126.                         this.ctable[i][j+k][icount] = true;   
  127.                     }   
  128.                     icount++;   
  129.                 }   
  130.             //右斜   
  131.             for(i=0;i<12;i++)   
  132.                 for(j=0;j<12;j++){   
  133.                     for(k=0;k<5;k++){   
  134.                         this.ptable[j+k][i+k][icount] = true;   
  135.                         this.ctable[j+k][i+k][icount] = true;   
  136.                     }   
  137.                     icount++;   
  138.                 }   
  139.             //左斜   
  140.             for(i=0;i<12;i++)   
  141.                 for(j=15;j>=4;j--){   
  142.                     for(k=0;k<5;k++){   
  143.                         this.ptable[j-k][i+k][icount] = true;   
  144.                         this.ctable[j-k][i+k][icount] = true;   
  145.                     }   
  146.                     icount++;   
  147.                 }   
  148.             for(i=0;i<=1;i++)  //初始化黑子白子上的每个权值上的连子数   
  149.                 for(j=0;j<672;j++)   
  150.                     this.win[i][j] = 0;   
  151.             this.player = true;   
  152.             this.icount = 0;   
  153.             this.ccount = 0;   
  154.             this.pcount = 0;   
  155.             this.start = true;   
  156.             this.over = false;   
  157.             this.pwin = false;   
  158.             this.cwin = false;   
  159.             this.tie = false;   
  160.             this.bout=1;   
  161.         }   
  162.     public void ComTurn(){     //找出电脑(白子)最佳落子点   
  163.            for(i=0;i<=15;i++)     //遍历棋盘上的所有坐标   
  164.                 for(j=0;j<=15;j++){      
  165.                     this.pgrades[i][j]=0;  //该坐标的黑子奖励积分清零   
  166.                     if(this.board[i][j] == 2)  //在还没下棋子的地方遍历   
  167.                         for(k=0;k<672;k++)    //遍历该棋盘可落子点上的黑子所有权值的连子情况,并给该落子点加上相应奖励分   
  168.                             if(this.ptable[i][j][k]){   
  169.                                 switch(this.win[0][k]){      
  170.                                     case 1: //一连子   
  171.                                         this.pgrades[i][j]+=5;   
  172.                                         break;   
  173.                                     case 2: //两连子   
  174.                                         this.pgrades[i][j]+=50;   
  175.                                         break;   
  176.                                     case 3: //三连子   
  177.                                         this.pgrades[i][j]+=180;   
  178.                                         break;   
  179.                                     case 4: //四连子   
  180.                                         this.pgrades[i][j]+=400;   
  181.                                         break;   
  182.                                 }   
  183.                             }   
  184.                     this.cgrades[i][j]=0;//该坐标的白子的奖励积分清零   
  185.                     if(this.board[i][j] == 2)  //在还没下棋子的地方遍历   
  186.                         for(k=0;k<672;k++)     //遍历该棋盘可落子点上的白子所有权值的连子情况,并给该落子点加上相应奖励分   
  187.                             if(this.ctable[i][j][k]){   
  188.                                 switch(this.win[1][k]){     
  189.                                     case 1:  //一连子   
  190.                                         this.cgrades[i][j]+=5;   
  191.                                         break;   
  192.                                     case 2:  //两连子   
  193.                                         this.cgrades[i][j]+=52;   
  194.                                         break;   
  195.                                     case 3: //三连子   
  196.                                         this.cgrades[i][j]+=100;   
  197.                                         break;   
  198.                                     case 4:  //四连子   
  199.                                         this.cgrades[i][j]+=400;   
  200.                                         break;   
  201.                                 }   
  202.                             }   
  203.                 }   
  204.             if(this.start){      //开始时白子落子坐标   
  205.                 if(this.board[4][4]==2){   
  206.                     m = 4;   
  207.                     n = 4;   
  208.                 }else{   
  209.                     m = 5;   
  210.                     n = 5;   
  211.                 }   
  212.                 this.start = false;   
  213.             }else{   
  214.                 for(i=0;i<16;i++)   
  215.                     for(j=0;j<16;j++)   
  216.                         if(this.board[i][j] == 2){  //找出棋盘上可落子点的黑子白子的各自最大权值,找出各自的最佳落子点   
  217.                             if(this.cgrades[i][j]>=this.cgrade){   
  218.                                 this.cgrade = this.cgrades[i][j];      
  219.                                 this.mat = i;   
  220.                                 this.nat = j;   
  221.                             }   
  222.                             if(this.pgrades[i][j]>=this.pgrade){   
  223.                                 this.pgrade = this.pgrades[i][j];      
  224.                                 this.mde = i;   
  225.                                 this.nde = j;   
  226.                             }   
  227.                         }   
  228.                 if(this.cgrade>=this.pgrade){   //如果白子的最佳落子点的权值比黑子的最佳落子点权值大,则电脑的最佳落子点为白子的最佳落子点,否则相反   
  229.                     m = mat;   
  230.                     n = nat;   
  231.                 }else{   
  232.                     m = mde;   
  233.                     n = nde;   
  234.                 }   
  235.             }   
  236.             this.cgrade = 0;           
  237.             this.pgrade = 0;   
  238.             this.board[m][n] = 1;  //电脑下子位置      
  239.             ccount++;   
  240.             if((ccount == 50) && (pcount == 50))  //平局判断   
  241.             {   
  242.                 this.tie = true;   
  243.                 this.over = true;   
  244.             }   
  245.             for(i=0;i<672;i++){   
  246.                 if(this.ctable[m][n][i] && this.win[1][i] != 7)   
  247.                     this.win[1][i]++;     //给白子的所有五连子可能的加载当前连子数   
  248.                 if(this.ptable[m][n][i]){   
  249.                     this.ptable[m][n][i] = false;   
  250.                     this.win[0][i]=7;   
  251.                 }   
  252.             }   
  253.             this.player = true;     //该人落子   
  254.             this.computer = false;  //电脑落子结束   
  255.         }    
  256.     public void mouseClick(){   
  257.         if(!this.over)   
  258.             if(this.player){   
  259.                 if(this.oldx<520 && this.oldy<520) {   
  260.                     int m1=m,n1=n;   
  261.                     m = (oldx-33)/30;   
  262.                     n = (oldy-33)/30;   
  263.                     if(this.board[m][n] == 2){      
  264.                         this.bout++;   
  265.                         this.board[m][n] = 0;      
  266.                         pcount++;   
  267.                         if((ccount == 50) && (pcount == 50)){   
  268.                             this.tie = true;   
  269.                             this.over = true;   
  270.                         }   
  271.                         for(i=0;i<672;i++){   
  272.                             if(this.ptable[m][n][i] && this.win[0][i] != 7)   
  273.                                 this.win[0][i]++;     //给黑子的所有五连子可能的加载当前连子数   
  274.                             if(this.ctable[m][n][i]){   
  275.                                 this.ctable[m][n][i] = false;   
  276.                                 this.win[1][i]=7;   
  277.                             }   
  278.                         }   
  279.                         this.player = false;         
  280.                         this.computer = true;   
  281.                     }else{   
  282.                          m=m1;n=n1;   
  283.                     }   
  284.                 }   
  285.             }   
  286.       }   
  287.      public void updatePaint(Graphics g){   
  288.         if(!this.over){   //如果是轮到电脑下    
  289.             if(this.computer)   
  290.                 this.ComTurn();  //得到最佳下子点        
  291.             //遍历当前棋盘上的五连子情况,判断输赢   
  292.             for(i=0;i<=1;i++)   
  293.                 for(j=0;j<672;j++){      
  294.                     if(this.win[i][j] == 5)   
  295.                         if(i==0){                //人赢   
  296.                             this.pwin = true;   
  297.                             this.over = true;    //游戏结束   
  298.                             break;   
  299.                         }else{   
  300.                             this.cwin = true;    //电脑赢   
  301.                             this.over = true;   
  302.                             break;   
  303.                         }   
  304.                     if(this.over)               //一遇到五连子退出棋盘遍历   
  305.                         break;   
  306.                 }   
  307.              g.setFont(new Font("华文行楷",0,20));   
  308.              g.setColor(Color.RED);   
  309.             //画出当前棋盘所有棋子   
  310.             for(i=0;i<=15;i++)   
  311.                 for(j=0;j<=15;j++){   //如果board元素值为0,则该坐标处为黑子   
  312.                     if(this.board[i][j] == 0){   
  313.                          g.drawImage(black.getImage(),i*30+31,j*30+31,black.getImage().getWidth(black.getImageObserver())-3,black.getImage().getHeight(black.getImageObserver())-3, black.getImageObserver());   
  314.                     }   
  315.                     //如果board元素值为1,则该坐标处为白子   
  316.                     if(this.board[i][j] == 1){   
  317.                          g.drawImage(white.getImage(),i*30+31,j*30+31,white.getImage().getWidth(white.getImageObserver())-3,white.getImage().getHeight(white.getImageObserver())-3, white.getImageObserver());   
  318.                     }   
  319.                 }   
  320.             //画出白子(电脑)当前所下子,便于辨认   
  321.             if(this.board[m][n]!=2)   
  322.                 g.drawImage(current.getImage(),m*30+31,n*30+31,current.getImage().getWidth(current.getImageObserver())-4,current.getImage().getHeight(current.getImageObserver())-4, current.getImageObserver());   
  323.             //判断输赢情况   
  324.             //人赢   
  325.             if(this.pwin)   
  326.                 g.drawString("您太厉害了!再来一次请重新开始游戏..",20,200);   
  327.             //电脑赢   
  328.             if(this.cwin)   
  329.                 g.drawString("很遗憾,你输了!再来一次请重新开始游戏..",84,190);   
  330.             //平局   
  331.             if(this.tie)   
  332.                 g.drawString("不分胜负!再来一次请重新开始游戏..",80,200);   
  333.         g.dispose();   
  334.      }   
  335.   }    
  336. }  

 

posted @ 2012-03-28 15:23  天宫之神  阅读(326)  评论(3编辑  收藏  举报