js实现五子棋人机对战源码
indexhtml
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>五子棋</title> 6 <meta name="viewport" content="width=device-width"> <!-- 适应移动屏幕 --> 7 <link rel="stylesheet" type="text/css" href="style.css"> 8 </head> 9 <body> 10 <h1>五子棋人机对战版</h1> 11 12 <canvas id="chess" width="450px" height="450px"> 13 </canvas> 14 <div id="restart"> 15 <span>重新开始</span> 16 </div> 17 <!-- <script type="text/javascript" src="script.js"></script> --> <!-- 未封装版本 --> 18 <script type="text/javascript" src="gobang.js"></script> <!-- 封装版本 --> 19 </body> 20 </html>
style.css
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 h1{ 2 text-align: center; 3 margin-top: 5%; 4 } 5 #restart{ 6 display: block; 7 margin: 20px auto; 8 width: 100px; 9 padding: 10px 10px; 10 background-color: #8f7a66; 11 text-align: center; 12 font-size: 24px; 13 color: white; 14 border-radius: 10px; 15 text-decoration: none; 16 } 17 #restart:hover { 18 background-color: #9f8b77; 19 } 20 canvas { 21 margin: 0 auto; 22 display: block; 23 -moz-box-shadow: -2px -2px 2px #EFEFEF, 5px 5px 5px #b9b9b9; 24 -webkit-box-shadow: -2px -2px 2px #EFEFEF, 5px 5px 5px #b9b9b9; 25 box-shadow: -2px -2px 2px #EFEFEF, 5px 5px 5px #b9b9b9; 26 }
scrit.js (未封装版本)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 //全局变量 2 var me = true; //黑棋先手 3 var over = false; //判断游戏是否结束 4 //棋盘落子情况初始化为空 5 var chessBoard = new Array(); 6 7 var init = function(){ 8 for (var i=0; i<15; i++) { 9 chessBoard[i] = []; 10 for(var j=0; j<15; j++){ 11 chessBoard[i][j] = 0; 12 } 13 } 14 } 15 16 //制作棋盘 17 var chess = document.getElementById('chess'); 18 var ctx = chess.getContext('2d'); 19 ctx.strokeStyle = "#000000"; 20 21 //载入背景图片 22 var logo = new Image(); 23 logo.src = "logo.jpg"; 24 logo.onload = function(){ 25 ctx.drawImage(logo,0,0,450,450); 26 drawChessBoard(); 27 init(); 28 } 29 30 var newgame = function(){ 31 location.reload(); 32 } 33 34 //绘制棋盘线 35 var drawChessBoard = function(){ 36 for(var i=0; i<15; i++){ 37 //画棋盘竖线 38 ctx.moveTo(15+i*30, 15); 39 ctx.lineTo(15+i*30, 435); 40 ctx.stroke(); 41 //画棋盘横线 42 ctx.moveTo(15, 15+i*30); 43 ctx.lineTo(435, 15+i*30); 44 ctx.stroke(); 45 } 46 } 47 48 //制作黑白棋子 49 var oneStep = function(i, j, me){ 50 //画圆 51 ctx.beginPath(); 52 ctx.arc(15 + i*30, 15 + j*30, 13, 0, 2 * Math.PI); 53 ctx.closePath(); 54 //渐变 55 var grd = ctx.createRadialGradient(15 + i*30 + 2, 15 + j*30 - 2, 13, 15 + i*30 + 2, 15 + j*30 - 2, 0); 56 if(me){ //黑棋 57 grd.addColorStop(0, "#0A0A0A"); 58 grd.addColorStop(1, "#636766"); 59 } 60 else{ //白棋 61 grd.addColorStop(0, "#D1D1D1"); 62 grd.addColorStop(1, "#F9F9F9"); 63 } 64 ctx.fillStyle = grd; 65 ctx.fill(); 66 } 67 68 //点击棋盘落子 69 chess.onclick = function(e){ 70 if(over){ 71 return ; 72 } 73 if(!me){ 74 return ; 75 } 76 var x = e.offsetX; 77 var y = e.offsetY; 78 var i = Math.floor(x / 30); 79 var j = Math.floor(y / 30); 80 if(chessBoard[i][j] == 0){ 81 oneStep(i, j, me); 82 chessBoard[i][j] = 1; //黑棋落子为1 83 84 for(var k=0; k<count; k++){ 85 if(wins[i][j][k]){ 86 myWin[k]++; 87 computerWin[k] = 6; //设置成比5大的数都不会加分 88 if(myWin[k] == 5){ 89 window.alert("You Win !"); 90 over = true; 91 } 92 } 93 } 94 if(!over){ 95 me = !me; 96 computerAI(); 97 } 98 } 99 } 100 //计算机下棋 101 var computerAI = function(){ 102 var myScore = []; 103 var computerScore = []; 104 var max = 0; 105 var u = 0, v = 0; 106 for(var i=0; i<15; i++){ 107 myScore[i] = []; 108 computerScore[i] =[]; 109 for(var j=0; j<15; j++){ 110 myScore[i][j] = 0; 111 computerScore[i][j] = 0; 112 } 113 } 114 for(var i=0; i<15; i++){ 115 for(var j=0; j<15; j++){ 116 if(chessBoard[i][j] == 0){ 117 for(var k=0; k<count; k++){ 118 if(wins[i][j][k]){ 119 if(myWin[k] == 1){ 120 myScore[i][j] += 200; 121 }else if(myWin[k] == 2){ 122 myScore[i][j] += 400; 123 }else if(myWin[k] == 3){ 124 myScore[i][j] += 2000; 125 }else if(myWin[k] == 4){ 126 myScore[i][j] += 10000; 127 } 128 129 if(computerWin[k] == 1){ 130 computerScore[i][j] += 220; 131 } 132 else if(computerWin[k] == 2){ 133 computerScore[i][j] += 420; 134 } 135 else if(computerWin[k] == 3){ 136 computerScore[i][j] += 2100; 137 } 138 else if(computerWin[k] == 4){ 139 computerScore[i][j] += 20000; 140 } 141 } 142 } 143 if(myScore[i][j] > max){ 144 max = myScore[i][j]; 145 u = i; 146 v = j; 147 } 148 else if(myScore[i][j] == max){ 149 if(computerScore[i][j] > computerScore[u][v]){ 150 u = i; 151 v = j; 152 } 153 } 154 155 if(computerScore[i][j] > max){ 156 max = computerScore[i][j]; 157 u = i; 158 v = j; 159 } 160 else if(computerScore[i][j] == max){ 161 if(myScore[i][j] > myScore[u][v]){ 162 u = i; 163 v = j; 164 } 165 } 166 } 167 } 168 } 169 oneStep(u, v, false); 170 chessBoard[u][v] = 2; 171 172 for(var k = 0; k < count; k++){ 173 if(wins[u][v][k]){ 174 computerWin[k]++; 175 myWin[k] = 6; 176 if(computerWin[k] == 5){ 177 window.alert("Computer Win !") 178 over = true; 179 } 180 } 181 } 182 if(!over){ 183 me = !me; 184 } 185 } 186 187 188 //更改鼠标指针样式 189 chess.onmousemove = function(e){ 190 chess.style.cursor = "default"; 191 var x = e.offsetX; 192 var y = e.offsetY; 193 for(var i=0; i<15; i++){ 194 for(var j=0; j<15; j++){ 195 var a = x - (15+i*30); 196 var b = y - (15+j*30); 197 var distance = Math.hypot(a, b); 198 var chessRange = Math.sqrt(25, 2); 199 //在交叉处半径为5的范围内,鼠标变成手指样式 200 if(distance < chessRange){ 201 chess.style.cursor = "pointer"; 202 } 203 } 204 } 205 } 206 207 208 //赢法数组 209 var wins = new Array(); 210 211 //定义赢法的三维数组 212 for(var i=0; i<15; i++){ 213 wins[i] = []; 214 for(var j=0; j<15; j++){ 215 wins[i][j] = []; 216 } 217 } 218 var count = 0; 219 220 //横线赢法 221 for(var i=0; i<15; i++){ 222 for(var j=0; j<11; j++){ 223 for(var k=0; k<5; k++){ 224 wins[i][j+k][count] = true; 225 } 226 count++; 227 } 228 } 229 230 //竖线赢法 231 for(var i=0; i<15; i++){ 232 for(var j=0; j<11; j++){ 233 for(var k=0; k<5; k++){ 234 wins[j+k][i][count] = true; 235 } 236 count++; 237 } 238 } 239 240 //斜线赢法 241 for(var i=0; i<11; i++){ 242 for(var j=0; j<11; j++){ 243 for(var k=0; k<5; k++){ 244 wins[i+k][j+k][count] = true; 245 } 246 count++; 247 } 248 } 249 250 //反斜线赢法 251 for(var i = 0; i < 11; i++){ 252 for(var j= 14; j > 3; j--){ 253 for(var k = 0; k < 5; k++){ 254 wins[i+k][j-k][count] = true; 255 } 256 count++; 257 } 258 } 259 console.log(count); 260 261 262 //赢法统计数组 263 var myWin = []; 264 var computerWin = []; 265 266 //赢法统计数组初始化 267 for(var i=0; i<count; i++){ 268 myWin[i] = 0; 269 computerWin[i] = 0; 270 }
gobang.js(函数封装版本)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 //gobang 封装实现 2 (function(){ 3 //定义变量 4 var chess = document.getElementById('chess'); //获取棋盘画布 5 var ctx = chess.getContext('2d'); //设置画布渲染 6 var logo = new Image(); //创建棋盘背景图像 7 var chessBoard = new Array(); //棋盘落子统计,用于存储棋盘格上是否有落子 8 var wins = []; //赢法数组 9 var count = 0; //赢法统计数组 10 var myWin = []; //玩家赢法统计 11 var computerWin = []; //计算机赢法统计 12 var me = true; //棋手标记 true为玩家下棋,false为电脑下棋 13 var over = false; //判断对局是否结束标记 true为结束,flase为未结束 14 15 var goBang = { 16 //入口 17 init: function(){ 18 var _this = this; //复制this对象 19 return (function(){ 20 //变量初始化 21 _this.initializa(); 22 //图片加载点 23 logo.onload = function(){ 24 //填充背景图片 25 ctx.drawImage(logo,0,0,450,450); 26 //绘制棋盘线 27 _this.drawChessBoard(); 28 // _this.oneStep(7,7,false); //测试oneStep函数 29 }; 30 31 //落子事件绑定 32 //点击棋盘落子 33 chess.onclick = function(e){ 34 //判断对局是否结束或是否轮到玩家下棋,对局结束或者不是玩家下棋就会跳出循环 35 if(over || me == false){ 36 return ; 37 } 38 //获取鼠标点击位置坐标,并转换为落点坐标 39 var x = e.offsetX, 40 y = e.offsetY; 41 var i = Math.floor(x / 30), 42 j = Math.floor(y / 30); 43 //判断当前落点是否已有棋子,如果没有则落子成功 44 if(chessBoard[i][j] == 0){ 45 _this.oneStep(i, j, me); //玩家落子 46 chessBoard[i][j] = 1; //玩家黑棋落子为1 47 for(var k=0; k<count; k++){ 48 if(wins[i][j][k]){ 49 myWin[k]++; 50 computerWin[k] = 999; //设置成比5大的数都不会加分 51 if(myWin[k] == 5){ 52 window.alert("You Win !"); 53 over = true; 54 } 55 } 56 } 57 //判断对局是否未结束,如果未结束将换成计算机下子 58 if(over == false){ 59 me = !me; 60 _this.computerAI(); //计算机落子 61 } 62 } 63 }; 64 65 //更改鼠标指针样式 66 chess.onmousemove = function(e){ 67 chess.style.cursor = "default"; 68 var x = e.offsetX; 69 var y = e.offsetY; 70 for(var i=0; i<15; i++){ 71 for(var j=0; j<15; j++){ 72 var a = x - (15+i*30); 73 var b = y - (15+j*30); 74 var distance = Math.hypot(a, b); 75 var chessRange = Math.sqrt(25, 2); 76 //在交叉处半径为5的范围内,鼠标变成手指样式 77 if(distance < chessRange){ 78 chess.style.cursor = "pointer"; 79 } 80 } 81 } 82 }; 83 84 })(); 85 }, 86 87 //变量&初始化&参数设置 88 initializa: function(){ 89 return (function(){ 90 //棋盘线条颜色 91 ctx.strokeStyle = "#000000"; //黑色 92 //载入背景图片 93 logo.src = "logo.jpg"; 94 //棋盘棋盘落子统计初始化(无落子) chessBoard 95 for (var i=0; i<15; i++) { 96 chessBoard[i] = []; 97 for(var j=0; j<15; j++){ 98 chessBoard[i][j] = 0; 99 } 100 } 101 //定义赢法的三维数组 wins 102 for(var i=0; i<15; i++){ 103 wins[i] = []; 104 for(var j=0; j<15; j++){ 105 wins[i][j] = []; 106 } 107 } 108 //赢法总类统计 共计572种 109 //横线赢法 110 for(var i=0; i<15; i++){ 111 for(var j=0; j<11; j++){ 112 for(var k=0; k<5; k++){ 113 wins[i][j+k][count] = true; 114 } 115 count++; 116 } 117 } 118 //竖线赢法 119 for(var i=0; i<15; i++){ 120 for(var j=0; j<11; j++){ 121 for(var k=0; k<5; k++){ 122 wins[j+k][i][count] = true; 123 } 124 count++; 125 } 126 } 127 //斜线赢法 128 for(var i=0; i<11; i++){ 129 for(var j=0; j<11; j++){ 130 for(var k=0; k<5; k++){ 131 wins[i+k][j+k][count] = true; 132 } 133 count++; 134 } 135 } 136 //反斜线赢法 137 for(var i = 0; i < 11; i++){ 138 for(var j= 14; j > 3; j--){ 139 for(var k = 0; k < 5; k++){ 140 wins[i+k][j-k][count] = true; 141 } 142 count++; 143 } 144 } 145 console.log(count); //赢法总类输出 146 //赢法统计数组初始化 147 for(var i=0; i<count; i++){ 148 myWin[i] = 0; 149 computerWin[i] = 0; 150 } 151 })(); 152 }, 153 154 //绘制棋盘 155 drawChessBoard: function(){ 156 return (function(){ 157 for(var i=0; i<15; i++){ 158 //画棋盘竖线 159 ctx.moveTo(15+i*30, 15); 160 ctx.lineTo(15+i*30, 435); 161 ctx.stroke(); 162 //画棋盘横线 163 ctx.moveTo(15, 15+i*30); 164 ctx.lineTo(435, 15+i*30); 165 ctx.stroke(); 166 } 167 })(); 168 }, 169 170 //绘制黑白棋子 171 oneStep: function(i, j, me){ 172 return (function(){ 173 //阴影 174 ctx.shadowOffsetX = 1.5; 175 ctx.shadowOffsetY = 2; 176 ctx.shadowBlur = 3; 177 ctx.shadowColor = '#333'; 178 //画圆 179 ctx.beginPath(); 180 ctx.arc(15 + i*30, 15 + j*30, 13, 0, 2 * Math.PI); 181 ctx.closePath(); 182 //渐变 183 var grd = ctx.createRadialGradient(15 + i*30 + 2, 15 + j*30 - 2, 13, 15 + i*30 + 2, 15 + j*30 - 2, 0); 184 if(me){ //黑棋 185 grd.addColorStop(0, "#0A0A0A"); 186 grd.addColorStop(1, "#636766"); 187 } 188 else{ //白棋 189 grd.addColorStop(0, "#D1D1D1"); 190 grd.addColorStop(1, "#F9F9F9"); 191 } 192 ctx.fillStyle = grd; 193 ctx.fill(); 194 })(); 195 }, 196 197 //计算机下棋 198 computerAI: function(){ 199 var that = this; //复制this对象 200 return (function(){ 201 //定义变量,分数统计数组和坐标存储变量 202 var myScore = [], 203 computerScore = []; 204 var max = 0, 205 u = 0, v = 0; 206 //分数统计初始化 207 for(var i=0; i<15; i++){ 208 myScore[i] = []; 209 computerScore[i] = []; 210 for(var j=0; j<15; j++){ 211 myScore[i][j] = 0; 212 computerScore[i][j] = 0; 213 } 214 } 215 //分数(权重)统计&计算,获取坐标 216 for(var i=0; i<15; i++){ 217 for(var j=0; j<15; j++){ 218 //判断当前位置是否没有落子 219 if(chessBoard[i][j] == 0){ 220 //根据赢法数组计算分数 221 for(var k=0; k<count; k++){ 222 //如果存在第K种赢法的可能性 223 if(wins[i][j][k]){ 224 if(myWin[k] == 1){ 225 myScore[i][j] += 200; 226 }else if(myWin[k] == 2){ 227 myScore[i][j] += 400; 228 }else if(myWin[k] == 3){ 229 myScore[i][j] += 2000; 230 }else if(myWin[k] == 4){ 231 myScore[i][j] += 10000; 232 } 233 234 if(computerWin[k] == 1){ 235 computerScore[i][j] += 220; 236 } 237 else if(computerWin[k] == 2){ 238 computerScore[i][j] += 420; 239 } 240 else if(computerWin[k] == 3){ 241 computerScore[i][j] += 2100; 242 } 243 else if(computerWin[k] == 4){ 244 computerScore[i][j] += 20000; 245 } 246 } 247 } 248 //通过判断获取最优的落子点 249 if(myScore[i][j] > max){ 250 max = myScore[i][j]; 251 u = i; 252 v = j; 253 }else if(myScore[i][j] == max){ 254 if(computerScore[i][j] > computerScore[u][v]){ 255 u = i; 256 v = j; 257 } 258 } 259 260 if(computerScore[i][j] > max){ 261 max = computerScore[i][j]; 262 u = i; 263 v = j; 264 }else if(computerScore[i][j] == max){ 265 if(myScore[i][j] > myScore[u][v]){ 266 u = i; 267 v = j; 268 } 269 } 270 } 271 } 272 } 273 that.oneStep(u, v, false); //计算机落子 274 chessBoard[u][v] = 2; ////玩家白棋落子为2 275 //判断当前落点是否已有棋子,如果没有则落子成功,如果有则后台提示 276 for(var k = 0; k < count; k++){ 277 if(wins[u][v][k]){ 278 computerWin[k]++; 279 myWin[k] = 999; 280 if(computerWin[k] == 5){ 281 window.alert("Computer Win !") 282 over = true; 283 } 284 } 285 } 286 if(over == false){ 287 me = !me; 288 } 289 })(); 290 }, 291 }; 292 293 //重新开始 294 document.getElementById('restart').onclick = function(){ 295 window.location.reload(); 296 } 297 //执行代码 298 goBang.init(); 299 300 })();
棋盘背景图
效果预览