大二期末,js老师布置实训任务中其中一项:五子棋。
先了解一下五子棋算法慨念吧。
五子棋应该大多数都玩过,人机或两人作战,各执黑白棋子,上下左右,左上,左下,右上,右下等方向若凑齐5颗连成线均为赢。
在网上各大博客中,都有谈到AI来实现算法,用三维数组,这里可以参考百度搜一下来看看。
现在,关键是如何利用这个三维数组,其实很多机器博弈其实就是在打分,再把棋子下到分高(或分低)的地方,比如下红色位置,如果没有棋子,应该 给一个较高分,因为在下一个白棋子就赢了,但是如果下了一个黑棋子,那么,上面的第一种赢法无论如何也不可能了,所以直接设置为零分。所以在设置两个一位数组,记录每种赢法的得分,再查找棋盘上哪些位置可以实现这种赢法,给这些位置加分,最后从所有位置中,找出分最高的落子即可。而且,一种赢法上的落子越多,就越接近获胜,所以分数应该越高。
// 计算机下棋
var computerAI = function() {
var myScore = [];
var computerScore = [];
var max = 0;
var u = 0,v = 0;
for(var i = 0; i < 15; i++) {
myScore[i] = [];
computerScore[i] = [];
for(var j = 0; j < 15; j++) {
myScore[i][j] = 0;
computerScore[i][j] = 0;
}
}
for(var i = 0; i < 15; i++) {
for(var j = 0; j < 15; j++) {
if(chressBord[i][j] == 0) {
for(var k = 0; k < count; k++) {
if(wins[i][j][k]) {
if(myWin[k] == 1) {
myScore[i][j] += 200;
} else if(myWin[k] == 2) {
myScore[i][j] += 400;
} else if(myWin[k] == 3) {
myScore[i][j] += 2000;
} else if(myWin[k] == 4) {
myScore[i][j] += 10000;
}
if(computerWin[k] == 1) {
computerScore[i][j] += 220;
} else if(computerWin[k] == 2) {
computerScore[i][j] += 420;
} else if(computerWin[k] == 3) {
computerScore[i][j] += 2100;
} else if(computerWin[k] == 4) {
computerScore[i][j] += 20000;
}
}
}
if(myScore[i][j] > max) {
max = myScore[i][j];
u = i;
v = j;
} else if(myScore[i][j] == max) {
if(computerScore[i][j] > computerScore[u][v]) {
u = i;
v = j;
}
}
if(computerScore[i][j] > max) {
max = computerScore[i][j];
u = i;
v = j;
} else if(computerScore[i][j] == max) {
if(myScore[i][j] > myScore[u][v]) {
u = i;
v = j;
}
}
}
}
}
_compi = u;
_compj = v;
oneStep(u, v, false);
chressBord[u][v] = 2;//计算机占据位置
for(var k = 0; k < count; k++) {
if(wins[u][v][k]) {
computerWin[k]++;
_myWin[k] = myWin[k];
myWin[k] = 6; //这个位置对方不可能赢了
if(computerWin[k] == 5) {
resultTxt.innerHTML = '遗憾,计算机赢了,继续加油哦!';
over = true;
}
}
}
if(!over) {
me = !me;
}
backAble = true;
returnAble = false;
var hasClass = new RegExp('unable').test(' ' + returnbtn.className + ' ');
if(!hasClass) {
returnbtn.className+=' '+'unable';
}
}
首先棋盘设定是15*15
赢的方式有572中赢法
//赢法的统计数组
var myWin = [];
var computerWin = [];
//赢法数组
var wins = [];
for(var i = 0; i < 15; i++) {
wins[i] = [];
for(var j = 0; j < 15; j++) {
wins[i][j] = [];
}
}
var count = 0; //赢法总数
//横线赢法
for(var i = 0; i < 15; i++) {
for(var j = 0; j < 11; j++) {
for(var k = 0; k < 5; k++) {
wins[i][j + k][count] = true;
}
count++;
}
}
//竖线赢法
for(var i = 0; i < 15; i++) {
for(var j = 0; j < 11; j++) {
for(var k = 0; k < 5; k++) {
wins[j + k][i][count] = true;
}
count++;
}
}
//正斜线赢法
for(var i = 0; i < 11; i++) {
for(var j = 0; j < 11; j++) {
for(var k = 0; k < 5; k++) {
wins[i + k][j + k][count] = true;
}
count++;
}
}
//反斜线赢法
for(var i = 0; i < 11; i++) {
for(var j = 14; j > 3; j--) {
for(var k = 0; k < 5; k++) {
wins[i + k][j - k][count] = true;
}
count++;
}
}
这是利用canvas的棋盘和AI算法来完成的五子棋游戏。
也有经典的算法来实现它。(看代码注释)
代码我贴上来吧:
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>五子棋title>
<script>
var n=15;
var winCount=5;
var isComputer;
var tbWidth=15*30+2;
var tbHeight=15*30+2;
var qipan=new Array(n);
window.onload=initBoard;
//画棋盘,并初始化数组
function initBoard() {
isComputer=true;
var table=document.createElement("table");
for(var i=0;ivar td=document.createElement("tr");
for(var j=0;j//每行有n列,n个单元格
var td=document.createElement("td");
//设置单元格的id,规则是前缀p加坐标i和j(此处坐标只是表示位置,不非用像素表示的坐标),编号从上往下,从左往右,i代表横坐标,j代表纵坐标
td.setAttribute("id","p"+j+"_"+i);
tr.appendChild(td);
}
table.appendChild(tr);
}
//设置表格的宽度和高度
table.style.width=tbWidth+"px";
table.style.height=tbHeight+"px";
var div=document.getElementsByTagName("div")[0]; //获取到放棋盘的div对象
div.innerHTML=""; //清空原来的内容
div.appendChild(table);
//设置div的位置
var left = (window.screen.availWidth-tbWidth)/2;
var top = (window.screen.availHeight-tbHeight)/2-50;
//设置div的宽度、高度和位置
div.style.width=tbWidth+"px";
div.style.height=tbHeight+"px";
div.style.left=left+"px";
div.style.top=top+"px";
//同时设置一个最后一个段落的位置
document.getElementsByTagName("p")[0].style.left=left+"px";
//初始化数组
for (var i=0;inew Array(n);
for(var j=0;j0;
}
}
//绑定每个单元格的单击时间
var tds=document.getElementsByTagName("td");
for(var i = 0;i//棋手走棋
}
//电脑走棋子
computer();
}
//棋手走棋
function user() {
//播放点击的声音
document.getElementById("dianji").play();
var id=this.id; //获取当前单元格的id
id=id.substr();
var i=id.split("_")[0]; //取出横向位置
var j=id.split("_")[0]; //取出纵向位置
if(qipan[i][j]==0) { //没有子可以下,否则不响应
this.style.background="url(img/white.jpg) no-repeat";
qipan[i][j]=2; //记录下的棋子,2表示白子,用户
checkWin(i,j); //判断胜负情况
computer(); //让计算机继续下
}
}
//计算机走棋,如果要让计算机更智能,需要设计算法,不是随机下
function computer() {
//每次计算机走之前都要判断还有位置走没有,如果已经没有位置可走,则平局
var next=false; //是否可以走下一步,初值为0;没有位置可以走了
for (var i=0;ifor (var j=0;jif(qipan[i][j]==0) {
next=true;
break;
}
}
}
if(!next) {
alert("平局");
location.reload(); //刷新页面,重新开始
}
var i=Math.floor(Math.random()*n) ; //floor向下取整数,获取一个0到n-1的随机数
var j=Math.floor(Math.random()*n);
//判断当前有棋子没有
while(qipan[i][j]!=0) {
//表示已经有子,重新产生一个位置
var i=Math.floor(Math.random()*n);
var j=Math.floor(Math.random()*n);
}
var td = document.getElementById("p"+i+"_"+j);
td.style.background="url(img/black.jpg) no-repeat";
document.getElementById("p"+preComputer[0]+"_"+preComputer[1]).className=""; //取消前一颗棋子设置的样式
td.className="cur"; //设置当前棋子为红色边框
preComputer[0]=i;
preComputer[1]=j;
qipan[i][j]=1; //记录下的棋子。1表示黑子,计算机
checkWin(i,j); //判断胜负情况
}
//获胜判断,x代表水平坐标,y代表垂直坐标
function checkWin(x,y) {
x=parseInt(x); //作数据类型转换
y=parseInt(y);
var total=0; //
//i 的取值范围0至n-1,j的取值范围0至n-1
var begin;
var end;
//判断水平方向,y不变
if(x-winCount+1<=0){
begin=0;
}else {
begin=x-winCount+1;
}
if(x+winCount-1>=n) {
end=n-1;
}else {
end=x+winCount-1;
}
for (var i = begin;i<=end;i++) {
//如果当前棋子是计算机统计的个数,如果是棋子是用户就统计2的个数
if (isComputer) {
if(qipan[i][y]==1){
total++;
if(total>=5) {
alert("计算机获胜!");
location.reload(); //刷新页面,重新开始
}
}else {
total=0; //重新计算
}
} else{
if(qipan[i][y] == 2) {
total++;
if(total >= 5) {
alert("选手获胜");
location.reload(); //刷新页面,重新开始
}
}else {
total=0; //重新计算
}
}
}
total=0; //重新设置为0
//判断垂直方向,x不变
if(y-winCount+1 <= 0) {
begin=0;
}else {
begin=y-winCount+1;
}if(y+winCount-1 >= n) {
end = n-1;
}else {
end=y+winCount-1;
}
for (var i = begin;i<=end;i++) {
//如果当前棋子是计算机统计的个数,如果是棋子是用户就统计2的个数
if(isComputer) {
if(qipan[x][i] == 1) {
total++;
if(total >= 5) {
alert("计算机获胜!");
location.reload();
}
}else {
total=0;
}
}else {
if(qipan[x][i] == 2) {
total++;
if(total >= 5) {
alert("选手获胜!");
location.reload();
}
}else {
total=0; //重新计算
}
}
}
total=0;
//左上角到右下角,x,y都要变
var tx=x; //保存当前棋子的x位置
var ty=y; //保存当前棋子的y位置
var xBegin,xEnd;
var yBegin,yEnd;
//确定开始位置,X往左移动,y往上移动
if(tx==0||ty==0) {
xBegin=tx;
yBegin=ty;
}else {
for(var i=0;i1;i++) { //5子连胜就循环4次
tx--;
ty--;
if(tx==0||ty==0) {
break;
}
xBegin=tx;
yBegin=ty;
}
}
//重新回到当前点击棋子的位置
tx=x;
ty=y;
//确认结束位置,x向右移动,y向下移动
if(tx==n-1 || ty==n-1){
xEnd=tx;
yEnd=ty;
}else {
for (var i=0;i1;i++) {
tx++;
ty++;
if(tx==n-1||ty==n-1)
break;
}
xEnd=tx;
yEnd=ty;
}
for (var i=xBegin,j=yBegin;i//如果。。
if(isComputer){
if(qipan[i][j]==1) {
total++;
if(total>=5) {
alert("计算机获胜");
location.reload();
}
}else {
if(qipan[x][i] == 2) {
total++;
if(total >= 5) {
alert("选手获胜!");
location.reload();
}
}else {
total=0; //重新计算
}
}
}
}
total=0;
tx=x;
ty=y;
if(tx==n-1 || ty==0) {
xBegin=tx;
yBegin=ty;
}else {
for (var i =0;i1;i++) {
tx++;
ty--;
if(tx==n-1 || ty ==0)
break;
}
xBegin=tx;
yBegin=ty;
}
tx=x;
ty=y;
if(tx==0||ty==n-1) {
xEnd=tx;
yEnd=ty;
}else{
for (var i=0;i1;i++) {
tx--;
ty++;
if(tx==0||ty==n-1)
break;
}
xEnd=tx;
yEnd=ty;
}
for(var i=xBegin,j=yBegin;i>=xEnd;i--,j++) {
if(isComputer) {
if(qipan[i][j]==1) {
total++;
if(total>=5){
alert("计算机获胜");
location.reload();
}
}else {
total=0;
}
}else{
if(qipan[i][j]==2){
total++;
if(total>=5){
alert("选手获胜");
location.reload();
}
}else{
total=0;
}
}
}
if(total<5) {
//没有人获胜
if(isComputer){
isComputer=false;
}else {
isComputer=true;
}
}
//制作背景音乐
function contronlMusic(){
var music=document.getElementById("backmusic");
if(music.paused){
music.play();
}else {
music.pause();
}
}
script>
<style>
body{
background: black;color: red;font-weight: bold;
}
table{
border-collapse: collapse;
}
td{
border: 2px solid black;height: 26px;width: 286px;background: #f89d1b;
}
div{
position: absolute;
}
.cur{
border: 2.2px solid red;
}
p{
position: absolute;bottom: 10px; color: orange;
}
style>
head>
<body>
<center>
<h2>五子棋对人机,计算机先下(黑子)h2>
<button onclick="contronlMusic();">播放/暂停button>
center>
<div>div>
<p>
初级版版-计算机智能极其低下
p>
<audio id="backmusic" autoplay="autoplay" loop="loop">
<source src="music.aac" type="audio/ogg">source>
你的浏览器不支持audio标签
audio>
<audio id="dianji">
<source src="beep.mp3" type="audio/ogg">source>
你的浏览器不支持audio标签
audio>
body>
html>
云盘也给一个吧:百度云盘
链接:https://pan.baidu.com/s/1o8gN5Ke 密码:y0k3
感谢大佬的指点:http://www.cnblogs.com/zhaoyu1995/p/5639101.html
http://blog.csdn.net/show_me_the_world/article/details/48884841