本项目使用的是JavaScript语言,用到了其中的jquery库的jquery-2.2.2.min版本,请自行网上下载,本文就不再给出。
(1)前端html文件
index.html
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8" /> 5 <meta name="viewport" content="initial-scale=1.0,user-scalable=no,maximum-scale=1,width=device-width"> 6 <title>人工智能五子棋</title> 7 <style type="text/css"> 8 body{ 9 margin: 0; 10 font-family: Microsoft Yahei; 11 text-align: center; 12 } 13 .timer{ 14 margin: 0 20px; 15 } 16 .rollback{ 17 width: 70px; 18 height: 30px; 19 margin: 20px; 20 } 21 .chessboard{ 22 width: 315px; 23 margin: 0 auto; 24 border-left: 1px solid #ccc; 25 border-top: 1px solid #ccc; 26 } 27 .chessboard .row{ 28 overflow: hidden; 29 } 30 .chessboard .tile{ 31 width: 20px; 32 height: 20px; 33 float: left; 34 border-right: 1px solid #ccc; 35 border-bottom: 1px solid #ccc; 36 text-align: center; 37 line-height: 20px; 38 } 39 .chessboard .tile.current{ 40 background-color: #ddd; 41 } 42 .chessboard .chess-max,.chessboard .chess-min{ 43 font-size: 20px; 44 cursor: pointer; 45 -webkit-user-select: none; 46 } 47 </style> 48 </head> 49 <body> 50 <div> 51 <span class="timer">游戏开始,请落子</span> 52 <button class="rollback">悔棋</button> 53 </div> 54 <div class="chessboard"></div> 55 <script type="text/javascript" src="jquery-2.2.2.min.js"></script> 56 <script type="text/javascript" src="fivechess.js"></script> 57 <script type="text/javascript" src="main.js"></script> 58 </body> 59 </html>
(2)后端五子棋游戏的实现
main.js
1 //棋盘 2 var chessboard = new Chessboard(15, 15); 3 var chessboardDom = $('.chessboard'); 4 //耗时和时钟 5 var t = 0, 6 tick; 7 //初始化棋盘dom 8 var initData = function() { 9 for (var i = 0; i < chessboard.row; i++) { 10 var rowDom = $('<div></div>').addClass('row'); 11 for (var j = 0; j < chessboard.column; j++) { 12 var tile = $('<div></div>').addClass('tile').data({ 13 row: i, 14 column: j 15 }); 16 rowDom.append(tile); 17 } 18 chessboardDom.append(rowDom); 19 } 20 }; 21 var initEvent = function() { 22 $('.tile').on('click', function() { 23 //如果下棋还未完结 24 if (!chessboard.isEnded()) { 25 var self = $(this); 26 //已经有棋子 27 if (self.is('.chess')) { 28 alert('请选择空余的格子下棋'); 29 } else { 30 var row = self.data('row'), 31 column = self.data('column'); 32 //人下棋 33 chessboard.put(row, column, Chessboard.MAX); 34 self.addClass('chess chess-max current').text('●'); 35 //第一次下棋开始计时 36 if (!tick) { 37 tick = setInterval(function() { 38 t++; 39 $('.timer').text('对局已经过' + t + '秒'); 40 }, 1000); 41 } 42 //人赢了,结束游戏 43 if (chessboard.isMaxWin()) { 44 chessboard.end(); 45 clearInterval(tick); 46 return alert('你用了' + t + '秒赢了人工智能'); 47 } 48 //没赢,但平手了 49 if (chessboard.isEnded()) { 50 clearInterval(tick); 51 return alert('你用了' + t + '秒和人工智能成为平手'); 52 } else { 53 setTimeout(function() { 54 //未分胜负,AI下棋 55 console.time('min'); 56 var res = min(chessboard, 2); 57 console.timeEnd('min'); 58 //AI下棋 59 chessboard.put(res.row, res.column, Chessboard.MIN); 60 $('.current').removeClass('current'); 61 chessboardDom.find('.row').eq(res.row).find('.tile').eq(res.column).addClass('chess chess-min current').text('○'); 62 //AI赢了,结束游戏 63 if (chessboard.isMinWin()) { 64 chessboard.end(); 65 clearInterval(tick); 66 return alert('你被人工智能打败!'); 67 } 68 //没赢,但平手了,否则未分胜负,等待人继续下棋 69 if (chessboard.isEnded()) { 70 clearInterval(tick); 71 return alert('你用了' + t + '秒赢了人工智能'); 72 } 73 }, 200); 74 } 75 } 76 } 77 }); 78 //悔棋 79 $('.rollback').on('click', function() { 80 //倒退两步 81 var steps = chessboard.rollback(2); 82 //清空前两步的dom文本 83 steps.forEach(function(step) { 84 chessboardDom.find('.row').eq(step.row).find('.tile').eq(step.column).removeClass('chess chess-min chess-max current').text(''); 85 }); 86 //返回当前的下棋位置,并添加current类 87 var step = chessboard.current(); 88 if (step) { 89 chessboardDom.find('.row').eq(step.row).find('.tile').eq(step.column).addClass('current'); 90 } 91 }); 92 }; 93 initData(); 94 initEvent();
(2)算法的实现代码
fivechess.js
1 /** 2 * [Chessboard 棋盘] 3 * @param {[type]} row [description] 4 * @param {[type]} column [description] 5 */ 6 var Chessboard = function(row, column) { 7 this.data = []; 8 this.row = row; 9 this.column = column; 10 //赢法数组 11 this.wins = []; 12 //赢法数 13 this.count = 0; 14 //记录max每一种赢法的已经达成棋子数 15 this.maxWin = []; 16 //记录min每一种赢法的已经达成棋子数 17 this.minWin = []; 18 //初始化棋盘,顺便初始化赢法数组 19 for (var i = 0; i < row; i++) { 20 this.data[i] = []; 21 this.wins[i] = []; 22 for (var j = 0; j < column; j++) { 23 this.data[i][j] = Chessboard.NONE; 24 this.wins[i][j] = []; 25 } 26 } 27 //横向赢法 28 for (var i = 0; i < row; i++) { 29 for (var j = 0; j <= column - 5; j++) { 30 for (var k = 0; k < 5; k++) { 31 this.wins[i][j + k][this.count] = true; 32 } 33 this.count++; 34 } 35 } 36 //纵向赢法 37 for (var i = 0; i < column; i++) { 38 for (var j = 0; j <= row - 5; j++) { 39 for (var k = 0; k < 5; k++) { 40 this.wins[j + k][i][this.count] = true; 41 } 42 this.count++; 43 } 44 } 45 //右斜线的赢法 46 for (var i = 0; i <= row - 5; i++) { 47 for (var j = 0; j <= column - 5; j++) { 48 for (var k = 0; k < 5; k++) { 49 this.wins[i + k][j + k][this.count] = true; 50 } 51 this.count++; 52 } 53 } 54 //左斜线的赢法 55 for (var i = 0; i <= row - 5; i++) { 56 for (var j = column - 1; j >= 4; j--) { 57 for (var k = 0; k < 5; k++) { 58 this.wins[i + k][j - k][this.count] = true; 59 } 60 this.count++; 61 } 62 } 63 //初始化max和min每一种赢法的下子情况 64 for (var i = 0; i < this.count; i++) { 65 this.maxWin[i] = { 66 max: 0, 67 min: 0 68 }; 69 this.minWin[i] = { 70 min: 0, 71 max: 0 72 }; 73 } 74 //下棋记录堆栈 75 this.stack = []; 76 //游戏是否结束 77 this.is_ended = false; 78 }; 79 /** 80 * [toString 输出棋盘信息] 81 * @return {[type]} [description] 82 */ 83 Chessboard.prototype.toString = function() { 84 return this.data.map(function(data) { 85 return data.toString(); 86 }).join('\n'); 87 }; 88 /** 89 * 返回当前最新一步下的棋子 90 * @return {[type]} 91 */ 92 Chessboard.prototype.current = function() { 93 var l = this.stack.length; 94 if (l) { 95 return this.stack[l - 1]; 96 } 97 }; 98 /** 99 * [put 下棋] 100 * @param {[type]} row [行] 101 * @param {[type]} column [列] 102 * @param {[type]} type [人还是AI下棋] 103 * @return {[type]} [description] 104 */ 105 Chessboard.prototype.put = function(row, column, type) { 106 if (this.data[row][column] == Chessboard.NONE) { 107 this.data[row][column] = type; 108 //放进记录堆栈 109 this.stack.push({ 110 row: row, 111 column: column, 112 type: type 113 }); 114 //下棋之后对每一种赢法的下棋情况进行更新 115 for (var i = 0; i < this.count; i++) { 116 if (this.wins[row][column][i]) { 117 if (type == Chessboard.MAX) { 118 this.maxWin[i].max++; 119 this.minWin[i].max++; 120 } else { 121 this.minWin[i].min++; 122 this.maxWin[i].min++; 123 } 124 } 125 } 126 //如果下子满了则结束游戏 127 if (this.stack.length == this.row * this.column) { 128 this.end(); 129 } 130 } 131 return this; 132 }; 133 /** 134 * [rollback 悔棋] 135 * @param {[type]} n [后退n步] 136 * @return {[type]} [description] 137 */ 138 Chessboard.prototype.rollback = function(n) { 139 //记录后退的n步走法 140 var steps = []; 141 n = n || 1; 142 for (var i = 0; i < n; i++) { 143 var step = this.stack.pop(); 144 if (step) { 145 steps.push(step); 146 var row = step.row, 147 column = step.column, 148 type = step.type; 149 //置空格点 150 this.data[row][column] = Chessboard.NONE; 151 //更新每一种赢法的下子情况 152 for (var j = 0; j < this.count; j++) { 153 if (this.wins[row][column][j]) { 154 if (type == Chessboard.MAX) { 155 this.maxWin[j].max--; 156 this.minWin[j].max--; 157 } else { 158 this.minWin[j].min--; 159 this.maxWin[j].min--; 160 } 161 } 162 } 163 } 164 } 165 this.is_ended = false; 166 return steps; 167 }; 168 /** 169 * 获取当前点附近考虑的下棋位置 170 * @param {[p这个点]} 171 * @return {[type]} 172 */ 173 Chessboard.prototype.getNearPoints = function(p) { 174 var points = [], 175 row, column; 176 for (var i = -2; i <= 2; i++) { 177 //右下角 178 row = p.row + i; 179 column = p.column + i; 180 if (this.isValid(row, column)) { 181 points.push({ 182 row: row, 183 column: column 184 }); 185 } 186 //左上角 187 row = p.row - i; 188 column = p.column + i; 189 if (this.isValid(row, column)) { 190 points.push({ 191 row: row, 192 column: column 193 }); 194 } 195 //行 196 row = p.row; 197 column = p.column - i; 198 if (this.isValid(row, column)) { 199 points.push({ 200 row: row, 201 column: column 202 }); 203 } 204 //列 205 row = p.row - i; 206 column = p.column; 207 if (this.isValid(row, column)) { 208 points.push({ 209 row: row, 210 column: column 211 }); 212 } 213 } 214 return points; 215 }; 216 //该位置是否合法 217 Chessboard.prototype.isValid = function(row, column) { 218 return row >= 0 && row < this.row && column >= 0 && column < this.column && this.data[row][column] == Chessboard.NONE; 219 }; 220 /** 221 * [availableSteps 获取可走的位置] 222 * @return {[type]} [description] 223 */ 224 Chessboard.prototype.availableSteps = function() { 225 var availableSteps = [], 226 row = this.row, 227 column = this.column, 228 stackLen = this.stack.length, 229 centerRow = Math.floor((row - 1) / 2), 230 centerColumn = Math.floor((column - 1) / 2); 231 if (!stackLen || (stackLen == 1 && this.data[centerRow][centerColumn] == Chessboard.NONE)) { 232 availableSteps.push({ 233 row: centerRow, 234 column: centerColumn 235 }); 236 return availableSteps; 237 } else { 238 if (stackLen == 1) { 239 var nextRow = centerRow + (Math.random() < 0.5 ? -1 : 1), 240 nextColumn = centerColumn + (Math.random() < 0.5 ? -1 : 1); 241 availableSteps.push({ 242 row: nextRow, 243 column: nextColumn 244 }); 245 return availableSteps; 246 } else { 247 var hash = {}; 248 this.stack.forEach(function(p) { 249 nearPoints = this.getNearPoints(p); 250 nearPoints.forEach(function(nearPoint) { 251 var row = nearPoint.row, 252 column = nearPoint.column; 253 if (!hash[row + '#' + column]) { 254 availableSteps.push(nearPoint); 255 hash[row + '#' + column] = true; 256 } 257 }); 258 }.bind(this)); 259 return availableSteps; 260 } 261 } 262 return availableSteps; 263 }; 264 Chessboard.prototype.analyseMax = function(data, type) { 265 switch (type) { 266 case Chessboard.FIVE_TYPE: 267 return ~data.indexOf('11111') ? 1 : 0; 268 case Chessboard.SFOUR_TYPE: 269 if (~data.indexOf('011110')) { 270 return 1; 271 } 272 return 0; 273 case Chessboard.FOUR_TYPE: 274 var c = 0; 275 var res1 = data.match(/211110/g); 276 var res2 = data.match(/011112/g); 277 var res3 = data.match(/10111/g); 278 var res4 = data.match(/11011/g); 279 var res5 = data.match(/11101/g); 280 c += (res1 ? res1.length : 0); 281 c += (res2 ? res2.length : 0); 282 c += (res3 ? res3.length : 0); 283 c += (res4 ? res4.length : 0); 284 c += (res5 ? res5.length : 0); 285 return c; 286 case Chessboard.STHREE_TYPE: 287 var c = 0; 288 var res1 = data.match(/01110/g); 289 var res2 = data.match(/011010/g); 290 var res3 = data.match(/010110/g); 291 c += (res1 ? res1.length : 0); 292 c += (res2 ? res2.length : 0); 293 c += (res3 ? res3.length : 0); 294 return c; 295 case Chessboard.THREE_TYPE: 296 var c = 0; 297 var res1 = data.match(/211100/g); 298 var res2 = data.match(/001112/g); 299 var res3 = data.match(/211010/g); 300 var res4 = data.match(/010112/g); 301 var res5 = data.match(/210110/g); 302 var res6 = data.match(/011012/g); 303 var res7 = data.match(/10011/g); 304 var res8 = data.match(/11001/g); 305 var res9 = data.match(/10101/g); 306 var res10 = data.match(/2011102/g); 307 c += (res1 ? res1.length : 0); 308 c += (res2 ? res2.length : 0); 309 c += (res3 ? res3.length : 0); 310 c += (res4 ? res4.length : 0); 311 c += (res5 ? res5.length : 0); 312 c += (res6 ? res6.length : 0); 313 c += (res7 ? res7.length : 0); 314 c += (res8 ? res8.length : 0); 315 c += (res9 ? res9.length : 0); 316 c += (res10 ? res10.length : 0); 317 return c; 318 case Chessboard.STWO_TYPE: 319 var c = 0; 320 var res1 = data.match(/001100/g); 321 var res2 = data.match(/01010/g); 322 var res3 = data.match(/010010/g); 323 c += (res1 ? res1.length : 0); 324 c += (res2 ? res2.length : 0); 325 c += (res3 ? res3.length : 0); 326 return c; 327 case Chessboard.TWO_TYPE: 328 var c = 0; 329 var res1 = data.match(/001100/g); 330 var res2 = data.match(/01010/g); 331 var res3 = data.match(/010010/g); 332 c += (res1 ? res1.length : 0); 333 c += (res2 ? res2.length : 0); 334 c += (res3 ? res3.length : 0); 335 return c; 336 default: 337 return 0; 338 } 339 }; 340 Chessboard.prototype.analyseMin = function(data, type) { 341 switch (type) { 342 case Chessboard.FIVE_TYPE: 343 return ~data.indexOf('22222') ? 1 : 0; 344 case Chessboard.SFOUR_TYPE: 345 if (~data.indexOf('022220')) { 346 return 1; 347 } 348 return 0; 349 case Chessboard.FOUR_TYPE: 350 var c = 0; 351 var res1 = data.match(/122220/g); 352 var res2 = data.match(/022221/g); 353 var res3 = data.match(/20222/g); 354 var res4 = data.match(/22022/g); 355 var res5 = data.match(/22202/g); 356 c += (res1 ? res1.length : 0); 357 c += (res2 ? res2.length : 0); 358 c += (res3 ? res3.length : 0); 359 c += (res4 ? res4.length : 0); 360 c += (res5 ? res5.length : 0); 361 return c; 362 case Chessboard.STHREE_TYPE: 363 var c = 0; 364 var res1 = data.match(/02220/g); 365 var res2 = data.match(/022020/g); 366 var res3 = data.match(/020220/g); 367 c += (res1 ? res1.length : 0); 368 c += (res2 ? res2.length : 0); 369 c += (res3 ? res3.length : 0); 370 return c; 371 case Chessboard.THREE_TYPE: 372 var c = 0; 373 var res1 = data.match(/122200/g); 374 var res2 = data.match(/002221/g); 375 var res3 = data.match(/122020/g); 376 var res4 = data.match(/020221/g); 377 var res5 = data.match(/120220/g); 378 var res6 = data.match(/022021/g); 379 var res7 = data.match(/20022/g); 380 var res8 = data.match(/22002/g); 381 var res9 = data.match(/20202/g); 382 var res10 = data.match(/1022201/g); 383 c += (res1 ? res1.length : 0); 384 c += (res2 ? res2.length : 0); 385 c += (res3 ? res3.length : 0); 386 c += (res4 ? res4.length : 0); 387 c += (res5 ? res5.length : 0); 388 c += (res6 ? res6.length : 0); 389 c += (res7 ? res7.length : 0); 390 c += (res8 ? res8.length : 0); 391 c += (res9 ? res9.length : 0); 392 c += (res10 ? res10.length : 0); 393 return c; 394 case Chessboard.STWO_TYPE: 395 var c = 0; 396 var res1 = data.match(/002200/g); 397 var res2 = data.match(/02020/g); 398 var res3 = data.match(/020020/g); 399 c += (res1 ? res1.length : 0); 400 c += (res2 ? res2.length : 0); 401 c += (res3 ? res3.length : 0); 402 return c; 403 case Chessboard.TWO_TYPE: 404 var c = 0; 405 var res1 = data.match(/001100/g); 406 var res2 = data.match(/01010/g); 407 var res3 = data.match(/010010/g); 408 c += (res1 ? res1.length : 0); 409 c += (res2 ? res2.length : 0); 410 c += (res3 ? res3.length : 0); 411 return c; 412 default: 413 return 0; 414 } 415 }; 416 /** 417 * [evaluate 计算当前棋盘的估值] 418 * @return {[type]} [description] 419 */ 420 Chessboard.prototype.evaluate = function() { 421 var maxW = minW = 0; 422 var maxGroup = { 423 "5": 0, 424 "4": 0, 425 "3": 0, 426 "2": 0, 427 "1": 0 428 }, 429 minGroup = { 430 "5": 0, 431 "4": 0, 432 "3": 0, 433 "2": 0, 434 "1": 0 435 }; 436 for (var i = 0; i < this.count; i++) { 437 if (this.maxWin[i].max == 5 && !this.maxWin[i].min) { 438 return Chessboard.MAX_VALUE; 439 } 440 if (this.minWin[i].min == 5 && !this.minWin[i].max) { 441 return Chessboard.MIN_VALUE; 442 } 443 if (this.maxWin[i].max == 4 && !this.maxWin[i].min) { 444 maxGroup[4]++; 445 } 446 if (this.minWin[i].min == 4 && !this.minWin[i].max) { 447 minGroup[4]++; 448 } 449 if (this.maxWin[i].max == 3 && !this.maxWin[i].min) { 450 maxGroup[3]++; 451 } 452 if (this.minWin[i].min == 3 && !this.minWin[i].max) { 453 minGroup[3]++; 454 } 455 if (this.maxWin[i].max == 2 && !this.maxWin[i].min) { 456 maxGroup[2]++; 457 } 458 if (this.minWin[i].min == 2 && !this.minWin[i].max) { 459 minGroup[2]++; 460 } 461 if (this.maxWin[i].max == 1 && !this.maxWin[i].min) { 462 maxGroup[1]++; 463 } 464 if (this.minWin[i].min == 1 && !this.minWin[i].max) { 465 minGroup[1]++; 466 } 467 } 468 maxW = maxGroup[4] * Chessboard.FOUR_W + maxGroup[3] * Chessboard.THREE_W + maxGroup[2] * Chessboard.TWO_W + maxGroup[1] * Chessboard.ONE_W; 469 minW = minGroup[4] * Chessboard.FOUR_W + minGroup[3] * Chessboard.THREE_W + minGroup[2] * Chessboard.TWO_W + minGroup[1] * Chessboard.ONE_W; 470 return maxW - minW; 471 }; 472 /** 473 * [isMaxWin 人是否赢了] 474 * @return {Boolean} [description] 475 */ 476 Chessboard.prototype.isMaxWin = function() { 477 var w = this.evaluate(); 478 return w == Chessboard.MAX_VALUE ? true : false; 479 }; 480 /** 481 * [isMinWin AI是否赢了] 482 * @return {Boolean} [description] 483 */ 484 Chessboard.prototype.isMinWin = function() { 485 var w = this.evaluate(); 486 return w == Chessboard.MIN_VALUE ? true : false; 487 }; 488 /** 489 * [end 结束游戏] 490 * @return {[type]} [description] 491 */ 492 Chessboard.prototype.end = function() { 493 this.is_ended = true; 494 return this; 495 }; 496 /** 497 * [isEnded 游戏是否结束] 498 * @return {Boolean} [description] 499 */ 500 Chessboard.prototype.isEnded = function() { 501 return this.is_ended; 502 }; 503 /** 504 * [max max下棋] 505 * @param {[type]} currentChessboard [当前棋盘] 506 * @param {[type]} depth [考虑深度] 507 * @return {[type]} [description] 508 */ 509 var max = function(currentChessboard, depth, beta) { 510 //记录优势值,应该下棋的位置 511 var row, column, alpha = -Infinity; 512 //什么都不下,直接返回当前棋盘评估值 513 if (depth == 0) { 514 alpha = currentChessboard.evaluate(); 515 return { 516 w: alpha 517 }; 518 } else { 519 //获取每一步可以走的方案 520 var steps = currentChessboard.availableSteps(); 521 // console.log('搜索MAX' + steps.length + '个棋局'); 522 if (steps.length) { 523 //对于每一种走法 524 for (var i = 0, l = steps.length; i < l; i++) { 525 var step = steps[i]; 526 //下棋 527 currentChessboard.put(step.row, step.column, Chessboard.MAX); 528 //如果已经赢了,则直接下棋,不再考虑对方下棋 529 if (currentChessboard.isMaxWin()) { 530 alpha = Chessboard.MAX_VALUE; 531 row = step.row; 532 column = step.column; 533 //退回上一步下棋 534 currentChessboard.rollback(); 535 break; 536 } else { 537 //考虑对方depth-1步下棋之后的优势值,如果对方没棋可下了,则返回当前棋盘估值 538 var res = min(currentChessboard, depth - 1) || { 539 w: currentChessboard.evaluate() 540 }; 541 //退回上一步下棋 542 currentChessboard.rollback(); 543 if (res.w > alpha) { 544 //选择最大优势的走法 545 alpha = res.w; 546 row = step.row; 547 column = step.column; 548 } 549 //如果人可以获得更好的走法,则AI必然不会选择这一步走法,所以不用再考虑人的其他走法 550 if (alpha >= beta) { 551 // console.log('MAX节点' + l + '个棋局,剪掉了' + (l - 1 - i) + '个MIN棋局'); 552 break; 553 } 554 } 555 556 } 557 return { 558 w: alpha, 559 row: row, 560 column: column 561 }; 562 } 563 } 564 }; 565 /** 566 * [min min下棋] 567 * @param {[type]} currentChessboard [当前棋盘] 568 * @param {[type]} depth [考虑深度] 569 * @return {[type]} [权重和当前推荐下棋的位置] 570 */ 571 var min = function(currentChessboard, depth, alpha) { 572 var row, column, beta = Infinity; 573 if (depth == 0) { 574 beta = currentChessboard.evaluate(); 575 return { 576 w: beta 577 }; 578 } else { 579 //获取每一步可以走的方案 580 var steps = currentChessboard.availableSteps(); 581 // console.log('搜索MIN' + steps.length + '个棋局'); 582 if (steps.length) { 583 //对于每一种走法 584 for (var i = 0, l = steps.length; i < l; i++) { 585 var step = steps[i]; 586 //下棋 587 currentChessboard.put(step.row, step.column, Chessboard.MIN); 588 //如果已经赢了,则直接下棋,不再考虑对方下棋 589 if (currentChessboard.isMinWin()) { 590 beta = Chessboard.MIN_VALUE; 591 row = step.row; 592 column = step.column; 593 //退回上一步下棋 594 currentChessboard.rollback(); 595 break; 596 } else { 597 //考虑对方depth-1步下棋之后的优势值,如果对方没棋可下了,则返回当前棋盘估值 598 var res = max(currentChessboard, depth - 1, beta) || { 599 w: currentChessboard.evaluate() 600 }; 601 //退回上一步下棋 602 currentChessboard.rollback(); 603 if (res.w < beta) { 604 //选择最大优势的走法 605 beta = res.w; 606 row = step.row; 607 column = step.column; 608 } 609 //如果AI可以获得更好的走法,则人必然不会选择这一步走法,所以不用再考虑AI的其他走法 610 if (beta <= alpha) { 611 // console.log('MIN节点' + l + '个棋局,剪掉了' + (l - 1 - i) + '个MAX棋局'); 612 break; 613 } 614 } 615 } 616 return { 617 w: beta, 618 row: row, 619 column: column 620 }; 621 } 622 } 623 }; 624 Chessboard.NONE = 0; 625 Chessboard.MAX = 1; 626 Chessboard.MIN = 2; 627 Chessboard.FIVE_TYPE = 1; 628 Chessboard.SFOUR_TYPE = 2; 629 Chessboard.FOUR_TYPE = 3; 630 Chessboard.STHREE_TYPE = 4; 631 Chessboard.THREE_TYPE = 5; 632 Chessboard.STWO_TYPE = 6; 633 Chessboard.TWO_TYPE = 7; 634 Chessboard.MAX_VALUE = 100000; 635 Chessboard.MIN_VALUE = -100000; 636 Chessboard.FIVE_W = 100000; 637 Chessboard.SFOUR_W = 10000; 638 Chessboard.FOUR_W = 5000; 639 Chessboard.STHREE_W = 2000; 640 Chessboard.THREE_W = 1000; 641 Chessboard.STWO_W = 500; 642 Chessboard.TWO_W = 200; 643 Chessboard.ONE_W = 10;
标签:return,游戏,人工智能,Chessboard,五子棋,length,var,data,row From: https://www.cnblogs.com/yenaibo/p/17134970.html