【前端】AI五子棋游戏186行

2024-04-18 16:04

本文主要是介绍【前端】AI五子棋游戏186行,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

这个来源于网上,不过代码改了不少,减少了些代码便于学习。 

<!DOCTYPE html>
<html><body><h3>AI五子棋游戏</h3><canvas id="chess" width="450px" height="450px"></canvas><script>var chressBord = []; //棋盘			var wins = [];  //存放所有5个棋子在一条线上所有可能性,第一维存放y, 第二维存放x,第三维存放当前的可能性编号var count = 0; //赢法总数量var myWin = []; //我们赢法的统计数组var computerWin = []; //计算机赢法的统计数组var chess = document.getElementById("chess");var context = chess.getContext('2d');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++){myWin[i] = 0; //这个数组很精髓,记录下棋后我方每一个位置在每种赢法的得分computerWin[i] = 0;}chess.onclick = function(e) // 我,下棋{var i = Math.floor(e.offsetX / 30);var j = Math.floor(e.offsetY / 30);if(chressBord[i][j] == 0){MoveStep(i,j,"red", 1, myWin);computerAI();}         }// 计算机下棋,找玩家最容易赢的位置或者电脑最容易赢的位置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++){						for(var k = 0; k < count; k++) //遍历到i,j这个坐标时,计算谁的得分更高{if(chressBord[i][j] != 0 || !wins[i][j][k]) //当前i,j坐标还没落子continue;switch(myWin[k]){case 1: myScore[i][j] += 200; break;case 2: myScore[i][j] += 400; break;case 3: myScore[i][j] += 2000; break;case 4: myScore[i][j] += 10000; break;}switch(computerWin[k]){case 1: computerScore[i][j] += 220; break;case 2: computerScore[i][j] += 420; break;case 3: computerScore[i][j] += 2100; break;case 4: computerScore[i][j] += 20000; break;}}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]) //如果电脑在i,j落子的分数比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;    }}}}MoveStep(u,v,"blue", 2, computerWin);}var CheckWin = function(i, j, Role, WinArray){			for(var k = 0; k < count; k++)if(wins[i][j][k]) // 将可能赢的情况都加1{WinArray[k]++;if(WinArray[k] >= 5)alert(Role + ': 恭喜,你赢了!')}}//绘画棋盘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();}}drawChessBoard(); // 画棋盘var MoveStep = function(i,j,Role, ID, WinArray) //落子{context.beginPath();context.arc(15 + i * 30, 15 + j * 30, 13, 0, 2 * Math.PI);// 画圆context.closePath();    context.fillStyle = Role;context.fill(); //填充颜色chressBord[i][j] = ID; //玩家ID棋盘位置占位CheckWin(i,j,Role, WinArray);  //判断是否获胜,这里也很精髓,递归思想}</script></body>
</html>

附原来的代码:

<!DOCTYPE html>
<html><head><meta charset="utf-8" /><title>AI五子棋游戏</title><style type='text/css'>canvas {display: block;margin: 50px auto;box-shadow: -2px -2px 2px #efefef, 5px 5px 5px #b9b9b9;cursor: pointer;}.btn-wrap { display: flex; flex-direction: row; justify-content:center;}.btn-wrap div { margin: 0 10px;}div>span {display: inline-block;padding: 10px 20px;color: #fff;background-color: #EE82EE;border-radius: 5px;cursor: pointer;}div.unable span { background: #D6D6D4; color: #adacaa;}#result-wrap {text-align: center;}</style></head><body><h3 id="result-wrap">AI五子棋</h3><canvas id="chess" width="450px" height="450px"></canvas><div class="btn-wrap"><div id='restart' class="restart"><span>重新开始</span></div><div id='goback' class="goback unable"><span>悔棋</span></div><div id='return' class="return unable"><span>撤销悔棋</span></div></div><script type="text/javascript" charset="utf-8">var over = false;var me = true; //我var _nowi = 0, _nowj = 0; //记录自己下棋的坐标var _compi = 0, _compj = 0; //记录计算机当前下棋的坐标var _myWin = [], _compWin = []; //记录我,计算机赢的情况var backAble = false, returnAble = false; var resultTxt = document.getElementById('result-wrap');var chressBord = [];//棋盘for(var i = 0; i < 15; i++){chressBord[i] = [];for(var j = 0; j < 15; j++){chressBord[i][j] = 0;}}//赢法的统计数组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++;}}// debugger;for(var i = 0; i < count; i++){myWin[i] = 0;_myWin[i] = 0;computerWin[i] = 0;_compWin[i] = 0;}var chess = document.getElementById("chess");var context = chess.getContext('2d');context.strokeStyle = '#bfbfbf'; //边框颜色var backbtn = document.getElementById("goback");var returnbtn = document.getElementById("return");window.onload = function(){drawChessBoard(); // 画棋盘}document.getElementById("restart").onclick = function(){window.location.reload();}// 我,下棋chess.onclick = function(e){if(over){return;}if(!me){return;}// 悔棋功能可用backbtn.className = backbtn.className.replace( new RegExp( "(\\s|^)unable(\\s|$)" )," " ); var x = e.offsetX;var y = e.offsetY;var i = Math.floor(x / 30);var j = Math.floor(y / 30);_nowi = i;_nowj = j;if(chressBord[i][j] == 0){oneStep(i,j,me);chressBord[i][j] = 1; //我,已占位置        for(var k = 0; k < count; k++){ // 将可能赢的情况都加1if(wins[i][j][k]){// debugger;myWin[k]++;_compWin[k] = computerWin[k];computerWin[k] = 6;//这个位置对方不可能赢了if(myWin[k] == 5){// window.alert('你赢了');resultTxt.innerHTML = '恭喜,你赢了!';over = true;}}}if(!over){me = !me;computerAI();}}         }// 悔棋backbtn.onclick = function(e){if(!backAble) { return;}over = false;me = true;// resultTxt.innerHTML = 'o(╯□╰)o,悔棋中';// 撤销悔棋功能可用returnbtn.className = returnbtn.className.replace( new RegExp( "(\\s|^)unable(\\s|$)" )," " ); // 我,悔棋chressBord[_nowi][_nowj] = 0; //我,已占位置 还原minusStep(_nowi, _nowj); //销毁棋子                                  for(var k = 0; k < count; k++){ // 将可能赢的情况都减1if(wins[_nowi][_nowj][k]){myWin[k]--;computerWin[k] = _compWin[k];//这个位置对方可能赢}}// 计算机相应的悔棋chressBord[_compi][_compj] = 0; //计算机,已占位置 还原minusStep(_compi, _compj); //销毁棋子                                  for(var k = 0; k < count; k++){ // 将可能赢的情况都减1if(wins[_compi][_compj][k]){computerWin[k]--;myWin[k] = _myWin[i];//这个位置对方可能赢}}resultTxt.innerHTML = '--益智五子棋--';returnAble = true;backAble = false;}// 撤销悔棋returnbtn.onclick = function(e){if(!returnAble) { return; }// 我,撤销悔棋chressBord[_nowi][_nowj] = 1; //我,已占位置 oneStep(_nowi,_nowj,me);                              for(var k = 0; k < count; k++){ if(wins[_nowi][_nowj][k]){myWin[k]++;_compWin[k] = computerWin[k];computerWin[k] = 6;//这个位置对方不可能赢}if(myWin[k] == 5){resultTxt.innerHTML = '恭喜,你赢了!';over = true;}}// 计算机撤销相应的悔棋chressBord[_compi][_compj] = 2; //计算机,已占位置   oneStep(_compi,_compj,false);                               for(var k = 0; k < count; k++){ // 将可能赢的情况都减1if(wins[_compi][_compj][k]){computerWin[k]++;_myWin[k] = myWin[k];myWin[k] = 6;//这个位置对方不可能赢}if(computerWin[k] == 5){resultTxt.innerHTML = 'o(╯□╰)o,计算机赢了,继续加油哦!';over = true;}}returnbtn.className += ' '+ 'unable';returnAble = false;backAble = true;}// 计算机下棋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 = 'o(╯□╰)o,计算机赢了,继续加油哦!';over = true;}}}if(!over){me = !me;}backAble = true;returnAble = false;var hasClass = new RegExp('unable').test(' ' + returnbtn.className + ' ');if(!hasClass) {returnbtn.className += ' ' + 'unable';}}//绘画棋盘var drawChessBoard = function() {for(var i = 0; i < 15; i++){context.moveTo(15 + i * 30 , 15);context.lineTo(15 + i * 30 , 435);context.stroke();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();}//销毁棋子var minusStep = function(i,j) {//擦除该圆context.clearRect((i) * 30, (j) * 30, 30, 30);// 重画该圆周围的格子context.beginPath();context.moveTo(15+i*30 , j*30);context.lineTo(15+i*30 , j*30 + 30);context.moveTo(i*30, j*30+15);context.lineTo((i+1)*30 , j*30+15);context.stroke();}</script></body>
</html>

这篇关于【前端】AI五子棋游戏186行的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/915235

相关文章

Python开发文字版随机事件游戏的项目实例

《Python开发文字版随机事件游戏的项目实例》随机事件游戏是一种通过生成不可预测的事件来增强游戏体验的类型,在这篇博文中,我们将使用Python开发一款文字版随机事件游戏,通过这个项目,读者不仅能够... 目录项目概述2.1 游戏概念2.2 游戏特色2.3 目标玩家群体技术选择与环境准备3.1 开发环境3

HTML5中的Microdata与历史记录管理详解

《HTML5中的Microdata与历史记录管理详解》Microdata作为HTML5新增的一个特性,它允许开发者在HTML文档中添加更多的语义信息,以便于搜索引擎和浏览器更好地理解页面内容,本文将探... 目录html5中的Mijscrodata与历史记录管理背景简介html5中的Microdata使用M

html5的响应式布局的方法示例详解

《html5的响应式布局的方法示例详解》:本文主要介绍了HTML5中使用媒体查询和Flexbox进行响应式布局的方法,简要介绍了CSSGrid布局的基础知识和如何实现自动换行的网格布局,详细内容请阅读本文,希望能对你有所帮助... 一 使用媒体查询响应式布局        使用的参数@media这是常用的

HTML5表格语法格式详解

《HTML5表格语法格式详解》在HTML语法中,表格主要通过table、tr和td3个标签构成,本文通过实例代码讲解HTML5表格语法格式,感兴趣的朋友一起看看吧... 目录一、表格1.表格语法格式2.表格属性 3.例子二、不规则表格1.跨行2.跨列3.例子一、表格在html语法中,表格主要通过< tab

Vue3组件中getCurrentInstance()获取App实例,但是返回null的解决方案

《Vue3组件中getCurrentInstance()获取App实例,但是返回null的解决方案》:本文主要介绍Vue3组件中getCurrentInstance()获取App实例,但是返回nu... 目录vue3组件中getCurrentInstajavascriptnce()获取App实例,但是返回n

JS+HTML实现在线图片水印添加工具

《JS+HTML实现在线图片水印添加工具》在社交媒体和内容创作日益频繁的今天,如何保护原创内容、展示品牌身份成了一个不得不面对的问题,本文将实现一个完全基于HTML+CSS构建的现代化图片水印在线工具... 目录概述功能亮点使用方法技术解析延伸思考运行效果项目源码下载总结概述在社交媒体和内容创作日益频繁的

前端CSS Grid 布局示例详解

《前端CSSGrid布局示例详解》CSSGrid是一种二维布局系统,可以同时控制行和列,相比Flex(一维布局),更适合用在整体页面布局或复杂模块结构中,:本文主要介绍前端CSSGri... 目录css Grid 布局详解(通俗易懂版)一、概述二、基础概念三、创建 Grid 容器四、定义网格行和列五、设置行

前端下载文件时如何后端返回的文件流一些常见方法

《前端下载文件时如何后端返回的文件流一些常见方法》:本文主要介绍前端下载文件时如何后端返回的文件流一些常见方法,包括使用Blob和URL.createObjectURL创建下载链接,以及处理带有C... 目录1. 使用 Blob 和 URL.createObjectURL 创建下载链接例子:使用 Blob

Vuex Actions多参数传递的解决方案

《VuexActions多参数传递的解决方案》在Vuex中,actions的设计默认只支持单个参数传递,这有时会限制我们的使用场景,下面我将详细介绍几种处理多参数传递的解决方案,从基础到高级,... 目录一、对象封装法(推荐)二、参数解构法三、柯里化函数法四、Payload 工厂函数五、TypeScript

Vue3使用router,params传参为空问题

《Vue3使用router,params传参为空问题》:本文主要介绍Vue3使用router,params传参为空问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录vue3使用China编程router,params传参为空1.使用query方式传参2.使用 Histo