标签:
最近在研究AI贪吃蛇,昨天写了一天代码实在头昏脑涨,想起之前在慕课网上看到一个关于五子棋AI的视频,加起来也就一个钟头,所以今天抽了点时间学习了一下,逻辑还是很简单的,但是如果自己想肯定是一时半会想不出这么好的方法,也对自己的学习以及最近对AI贪吃蛇的思考有所启发,还是很有收获的(为数不多觉得还可以的视频教程)。
关于具体的思路,视频讲的很清楚,也可以找到观看,就不一一分析了。主要是记录一下代码(因为视频没源码下载),以及自己的感想。
文件结构(sublime 截图)
index.html代码
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="utf-8"> 5 <title>五子棋</title> 6 <link rel="stylesheet" type="text/css" href="css/style.css"> 7 </head> 8 <body> 9 <canvas id="chess" width="450px" height="450px"></canvas> 10 <script type="text/javascript" src="js/script.js"></script> 11 </body> 12 </html> 13 <!--UI 14 *canvas 绘制直线 15 *设置画笔颜色 16 *canvas画圆 17 *填充渐变色 18 --> 19 <!--AI 20 *赢法数组,三维 21 *每一种赢法的统计数组,一位数组 22 *如何判断胜负 23 -->
style.css代码
1 canvas{ 2 display: block; 3 margin: 50px auto; 4 box-shadow: -2px -2px 2px 2px #EFEFEF, 5px 5px 5px #B9B9B9; 5 }
script.js代码
var chessBoard = []; var me = true; var over = false; //赢法数组 var wins = []; //赢法的统计数组 var myWin = []; var computerWin = []; for (var i = 0; i < 15; i++){ chessBoard[i] = []; for (var j = 0; j < 15; j++){ chessBoard[i][j] = 0; } } 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 < 11; i++){ for (var j = 0; j < 15; j++){ for (var k = 0; k < 5; k++){ wins[i+k][j][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++; } } //共 572 赢法 //初始化 for (var i = 0; i < count; i++){ myWin[i] = 0; computerWin[i] = 0; } var chess = document.getElementById(‘chess‘); var context = chess.getContext(‘2d‘); context.strokeStyle = "#AFAFAF"; var logo = new Image(); logo.src = "images/logo.png"; logo.onload = function() { context.drawImage(logo, 0, 0, 450, 450); drawChessBoard(); } var drawChessBoard = function() { 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(); } } var oneStep = function(i, j, me) { context.beginPath(); context.arc(15 + i*30, 15 + j*30, 13, 0, 2*Math.PI); context.closePath(); var gradient = context.createRadialGradient(15 + i*30 + 2, 15 + j*30 - 2, 13, 15 + i*30 + 2, 15 + j*30 - 2, 0); if (me){ gradient.addColorStop(0, "#0A0A0A"); gradient.addColorStop(1, "#636766"); } else { gradient.addColorStop(0, "#D1D1D1"); gradient.addColorStop(1, "#F9F9F9"); } context.fillStyle = gradient; context.fill(); } chess.onclick = function(e){ if (over){ return; } if (!me){ return; } var x = e.offsetX; var y = e.offsetY; var i = Math.floor(x / 30); var j = Math.floor(y / 30); if (0 == chessBoard[i][j]){ oneStep(i, j, me); chessBoard[i][j] = 1; //更新赢法统计数组 for (var k = 0; k < count; k++){ if (wins[i][j][k]){ myWin[k]++;//接近胜利 computerWin[k] = 6;//设置为异常值,因为最多加到5 if (5 == myWin[k]){ window.alert("You beat my stupid algorithm"); over = true; } } } if (!over){ computerAI(); me = !me; } } } var computerAI = function() { var myScore = []; var computerScore = []; var max = -1; 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; } } //evaluate for (var i = 0; i < 15; i++){ for (var j = 0; j < 15; j++){ if (0 == chessBoard[i][j]){//no chessman for (var k = 0; k <count; k++){ if (wins[i][j][k]){ if (1 == myWin[k]){ myScore[i][j] += 200; } else if (2 == myWin[k]){ myScore[i][j] += 400; } else if (3 == myWin[k]){ myScore[i][j] += 2000; } else if (4 == myWin[k]){ myScore[i][j] += 10000; } if (1 == computerWin[k]){ computerScore[i][j] += 3 20; } else if (2 == computerWin[k]){ computerScore[i][j] += 420; } else if (3 == computerWin[k]){ computerScore[i][j] += 4200; } else if (4 == computerWin[k]){ 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; } } } } } oneStep(u, v, false); chessBoard[u][v] = 2; //更新赢法统计数组 for (var k = 0; k < count; k++){ if (wins[u][v][k]){ computerWin[k]++;//接近胜利 myWin[k] = 6;//设置为异常值,因为最多加到5 if (5 == computerWin[k]){ window.alert("stupid guy"); over = true; } } } if (!over){ me = !me; } }
logo.png是我用自带的画图软件随便设计的
但是只要认真下,还是很容易就能赢,因为赢法数组(不懂看视频)打分还是自己随意设置的,肯定不是最科学的(这里我想是不是可以设计一套学习算法让程序自己优化打分的方案呢,可惜对这方面不是很了解,以后有机会试试),此外,这是一种很基础的AI,只考虑当前最优局势,相比什么高大上的蒙特卡洛树搜索弱爆了,所以遇到高手输是很正常的。比如
总结,AI看似高大上,但是其实际是对实际问题的高度抽象、模型化以及大量计算(正是计算机的优势)。如果能缜密地设计好编码思路,那么效率就会很高,比如昨天写的贪吃蛇,很多情况没想到,所以总是陷入困境,当代码量增加,逻辑结构变的复杂时,一定要事先规划,或者说,设计模式。自己要突破目前的瓶颈期可能要学习一下这方面的东西了!!!
此外,还利用Hbuilder生成了APP,首先是自己这么想了,然后还真找到办法实现了,所以创意,眼界,技术,同样重要。
小记。
标签:
原文地址:http://www.cnblogs.com/zhaoyu1995/p/5639101.html