运行效果(这是未分出胜负):
这是分出胜负:
源代码,把下边的代码放到1.html,然后用浏览器打开,就可以,然后刷新网页:
<!DOCTYPE html>
<html><body><h3>AI五子棋游戏,这个程序有个非常大的Bug,你找到了吗?doge</h3><canvas id="chess" width="450px" height="450px"></canvas><script>var chressBord = []; //棋盘当前落子后的记录,是否已经落子,是哪方落子 var wins = []; //存放所有5个棋子在一条线上所有可能性,第一维存放y, 第二维存放x,第三维存放当前的可能性编号var count = 0; //赢法总数量var blueWin = []; //我们赢法的统计数组var redWin = []; //计算机赢法的统计数组var chess = document.getElementById("chess");var context = chess.getContext('2d');var x = 0;var y = 0;for(var i = 0; i < 15; i++){chressBord[i] = [];wins[i] = [];for(var j = 0; j < 15; j++){chressBord[i][j] = 0;wins[i][j] = [];}}//横线赢法for(var i = 0; i < 15; i++)for(var j = 0; j < 11; j++,count++)for(var k = 0; k < 5; k++)wins[i][j+k][count] = true;//竖线赢法for(var i = 0; i < 15; i++)for(var j = 0; j < 11; j++,count++)for(var k = 0; k < 5; k++)wins[j+k][i][count] = true;//正斜线赢法for(var i = 0; i < 11; i++)for(var j = 0; j < 11; j++,count++)for(var k = 0; k < 5; k++)wins[i+k][j+k][count] = true;//反斜线赢法for(var i = 0; i < 11; i++) for(var j = 14; j > 3; j--,count++)for(var k = 0; k < 5; k++)wins[i+k][j-k][count] = true;for(var i = 0; i < count; i++){blueWin[i] = 0; //这个数组很精髓,记录下棋后每一个位置在每种赢法的得分redWin[i] = 0;}//程序运行入口function main() { var role = "red";//两个下棋的角色不断切换x = Math.floor(Math.random() * 15); //第一步随机x,y y = Math.floor(Math.random() * 15); for (i = 0; i < 225; i++){ if(chressBord[x][y] == 0) //computerAI计算后的x,y坐标还没有落子{ if (role == "red"){Move(x,y,role); //落子chressBord[x][y] = 1; //red玩家棋盘位置占位CheckWin(x,y,role, redWin); //计算落子后是否获胜,这里也很精髓,递归思想}else{Move(x,y,role); //落子chressBord[x][y] = 2; //blue玩家棋盘位置占位CheckWin(x,y,role, blueWin); //计算落子后是否获胜,这里也很精髓,递归思想}role = (role == "blue") ? "red" : "blue"; //落子后切换角色}computerAI(); //计算下一步落子的x,y坐标}}// 计算机下棋,找玩家最容易赢的位置或者电脑最容易赢的位置function computerAI(){var palyer1Score = []; //这两个数组存放的内容会不断变化,随着计算双方相互切换var palyer2Score = [];var max = 0;var u = 0, v = 0;for(var i = 0; i < 15; i++){palyer1Score[i] = [];palyer2Score[i] = [];for(var j = 0; j < 15; j++){palyer1Score[i][j] = 0;palyer2Score[i][j] = 0;}}//找落子赢的概率最大坐标for(var i = 0; i < 15; i++){for(var j = 0; j < 15; j++){ for(var k = 0; k < count; k++) //遍历到i,j这个坐标时,计算谁的得分更高{if(chressBord[i][j] != 0 || !wins[i][j][k]) //当前i,j坐标还没落子continue;switch(blueWin[k]){case 1: palyer1Score[i][j] += 200; break;case 2: palyer1Score[i][j] += 400; break;case 3: palyer1Score[i][j] += 2000; break;case 4: palyer1Score[i][j] += 10000; break;}switch(redWin[k]){case 1: palyer2Score[i][j] += 220; break;case 2: palyer2Score[i][j] += 420; break;case 3: palyer2Score[i][j] += 2100; break;case 4: palyer2Score[i][j] += 20000; break;}}if(palyer1Score[i][j] > max) //如果玩家落子的分数多,就替换{max = palyer1Score[i][j];u = i;v = j;}else if(palyer1Score[i][j] == max) //如果玩家落子的分数跟原来最多分数一样多{if(palyer2Score[i][j] > palyer2Score[u][v]) //如果电脑在i,j落子的分数比u,v的分数多,就替换{u = i;v = j; }}if(palyer2Score[i][j] > max) //如果电脑下棋新位置分数比原来的多,就替换{max = palyer2Score[i][j];u = i;v = j;}else if(palyer2Score[i][j] == max) //如果电脑下棋新位置分数跟原来的一样多{if(palyer1Score[i][j] > palyer1Score[u][v]) //如果玩家落子的分数多,就准备把玩家最好的位置占掉{u = i;v = j; }}}}x = u;y = v;}function Move(i,j,Role) //落子{context.beginPath();context.arc(15 + i * 30, 15 + j * 30, 13, 0, 2 * Math.PI);// 画圆context.closePath(); context.fillStyle = Role;context.fill(); //填充颜色 }function CheckWin(i, j, Role, WinArray){ for(var k = 0; k < count; k++)if(wins[i][j][k]) // 将可能赢的情况都加1{WinArray[k]++; //第k这个位置要注意,每一个k代表一种赢的可能性,并且前边的x,y代表第K种赢法x,y的坐标对,这个对于理解算法是否赢很重要if(WinArray[k] >= 5){alert(Role + ': 恭喜,你赢了!')throw new Error(Role + " player win!!");;}}} function drawChessBoard(){for(var i = 0; i < 15; i++){context.moveTo(15 + i * 30 , 15);context.lineTo(15 + i * 30 , 435);context.moveTo(15 , 15 + i * 30);context.lineTo(435 , 15 + i * 30);context.stroke();}}drawChessBoard(); // 画棋盘main();</script></body>
</html>
import javax.swing.*;
import java.awt.*;public class FiveInOne extends JFrame {static Graphics graphics;private final Image buffer; // 双缓冲图像private final Graphics bufferGraphics; // 双缓冲图像的绘图上下文int player;int[][] chessBoard;int[][][] wins;int count;int[] blueWin;int[] redWin;int x, y;Color c;FiveInOne(){setLayout(null);setSize(700, 900);setLocationRelativeTo(null);setVisible(true);graphics = getContentPane().getGraphics();buffer = createImage(700, 900);bufferGraphics = buffer.getGraphics();chessBoard = new int[15][15];wins = new int[15][15][573];blueWin = new int[573];redWin = new int[573];player = 1;c = new Color(255,0,0);bufferGraphics.setColor(new Color(0,0,0));drawchessBoard();System.out.println("count: " +String.valueOf(count));generateWinArray();main2();}void generateWinArray(){//横线赢法for(int i = 0; i < 15; i++)for(int j = 0; j < 11; j++,count++)for(int k = 0; k < 5; k++)wins[i][j+k][count] = 1;//竖线赢法for(int i = 0; i < 15; i++)for(int j = 0; j < 11; j++,count++)for(int k = 0; k < 5; k++)wins[j+k][i][count] = 1;//正斜线赢法for(int i = 0; i < 11; i++)for(int j = 0; j < 11; j++,count++)for(int k = 0; k < 5; k++)wins[i+k][j+k][count] = 1;//反斜线赢法for(int i = 0; i < 11; i++)for(int j = 14; j > 3; j--,count++)for(int k = 0; k < 5; k++)wins[i+k][j-k][count] = 1;}void main2(){String role = "red";//两个下棋的角色不断切换x = (int) Math.floor(Math.random() * 15); //第一步随机x,yy = (int) Math.floor(Math.random() * 15);for (int i = 0; i < 225; i++){if(chessBoard[x][y] == 0) //computerAI计算后的x,y坐标还没有落子{if (role.equals("red")){drawChess(x,y); //落子chessBoard[x][y] = 1; //red玩家棋盘位置占位CheckWin(x,y,role, redWin); //计算落子后是否获胜,这里也很精髓,递归思想}else{drawChess(x,y); //落子chessBoard[x][y] = 2; //blue玩家棋盘位置占位CheckWin(x,y,role, blueWin); //计算落子后是否获胜,这里也很精髓,递归思想}role = (role == "blue") ? "red" : "blue"; //落子后切换角色}computerAI(); //计算下一步落子的x,y坐标System.out.println("x: " + x + ", y: " + y);try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}}void computerAI(){int[][] palyer1Score = new int[15][15]; //这两个数组存放的内容会不断变化,随着计算双方相互切换int[][] palyer2Score = new int[15][15];int max = 0;int u = 0, v = 0;//找落子赢的概率最大坐标for(int i = 0; i < 15; i++){for(int j = 0; j < 15; j++){for(int k = 0; k < count; k++) //遍历到i,j这个坐标时,计算谁的得分更高{if(chessBoard[i][j] != 0 || 0 == wins[i][j][k]) //当前i,j坐标还没落子continue;switch(blueWin[k]){case 1: palyer1Score[i][j] += 200; break;case 2: palyer1Score[i][j] += 400; break;case 3: palyer1Score[i][j] += 2000; break;case 4: palyer1Score[i][j] += 10000; break;}switch(redWin[k]){case 1: palyer2Score[i][j] += 220; break;case 2: palyer2Score[i][j] += 420; break;case 3: palyer2Score[i][j] += 2100; break;case 4: palyer2Score[i][j] += 20000; break;}}if(palyer1Score[i][j] > max) //如果玩家落子的分数多,就替换{max = palyer1Score[i][j];u = i;v = j;}else if(palyer1Score[i][j] == max) //如果玩家落子的分数跟原来最多分数一样多{if(palyer2Score[i][j] > palyer2Score[u][v]) //如果电脑在i,j落子的分数比u,v的分数多,就替换{u = i;v = j;}}if(palyer2Score[i][j] > max) //如果电脑下棋新位置分数比原来的多,就替换{max = palyer2Score[i][j];u = i;v = j;}else if(palyer2Score[i][j] == max) //如果电脑下棋新位置分数跟原来的一样多{if(palyer1Score[i][j] > palyer1Score[u][v]) //如果玩家落子的分数多,就准备把玩家最好的位置占掉{u = i;v = j;}}}}x = u;y = v;}void CheckWin(int i, int j, String Role, int[] WinArray){for(int k = 0; k < count; k++)if(wins[i][j][k] == 1) // 将可能赢的情况都加1{WinArray[k]++; //第k这个位置要注意,每一个k代表一种赢的可能性,并且前边的x,y代表第K种赢法x,y的坐标对,这个对于理解算法是否赢很重要if(WinArray[k] >= 5){//alert(Role + ': 恭喜,你赢了!')System.out.println(Role + " player win!!");break;}}}void drawChess(int mouse_x, int mouse_y){mouse_x = 15 + mouse_x * 30; //把一个区域的点击放到一个点mouse_y = 15 + mouse_y * 30;if (player == 1){c = new Color(255,0,0);player = 2;}else{c = new Color(0,0,255);player = 1;}bufferGraphics.setColor(c);bufferGraphics.fillArc(mouse_x - 12, mouse_y - 38, 20, 20, 0, 360);graphics.drawImage(buffer, 0, 0, null);}void drawchessBoard(){for (int i = 0; i < 15; i++){bufferGraphics.drawLine(15 + i * 30, 15, 15 + i * 30, 435);bufferGraphics.drawLine(15, 15 + i * 30, 435, 15 + i * 30);}}//这个程序有个非常大的Bug,你找到了吗?public static void main(String[] args) {new FiveInOne();}
}