运行效果(这是未分出胜负):
这是分出胜负:
源代码,把下边的代码放到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,y
y = (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();
}
}