js实现五子棋人机对战源码
indexhtml
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>五子棋</title>
<meta name="viewport" content="width=device-width"> <!-- 适应移动屏幕 -->
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<h1>五子棋人机对战版</h1> <canvas id="chess" width="450px" height="450px">
</canvas>
<div id="restart">
<span>重新开始</span>
</div>
<!-- <script type="text/javascript" src="script.js"></script> --> <!-- 未封装版本 -->
<script type="text/javascript" src="gobang.js"></script> <!-- 封装版本 -->
</body>
</html>
style.css
h1{
text-align: center;
margin-top: 5%;
}
#restart{
display: block;
margin: 20px auto;
width: 100px;
padding: 10px 10px;
background-color: #8f7a66;
text-align: center;
font-size: 24px;
color: white;
border-radius: 10px;
text-decoration: none;
}
#restart:hover {
background-color: #9f8b77;
}
canvas {
margin: 0 auto;
display: block;
-moz-box-shadow: -2px -2px 2px #EFEFEF, 5px 5px 5px #b9b9b9;
-webkit-box-shadow: -2px -2px 2px #EFEFEF, 5px 5px 5px #b9b9b9;
box-shadow: -2px -2px 2px #EFEFEF, 5px 5px 5px #b9b9b9;
}
scrit.js (未封装版本)
//全局变量
var me = true; //黑棋先手
var over = false; //判断游戏是否结束
//棋盘落子情况初始化为空
var chessBoard = new Array(); var init = function(){
for (var i=0; i<15; i++) {
chessBoard[i] = [];
for(var j=0; j<15; j++){
chessBoard[i][j] = 0;
}
}
} //制作棋盘
var chess = document.getElementById('chess');
var ctx = chess.getContext('2d');
ctx.strokeStyle = "#000000"; //载入背景图片
var logo = new Image();
logo.src = "logo.jpg";
logo.onload = function(){
ctx.drawImage(logo,0,0,450,450);
drawChessBoard();
init();
} var newgame = function(){
location.reload();
} //绘制棋盘线
var drawChessBoard = function(){
for(var i=0; i<15; i++){
//画棋盘竖线
ctx.moveTo(15+i*30, 15);
ctx.lineTo(15+i*30, 435);
ctx.stroke();
//画棋盘横线
ctx.moveTo(15, 15+i*30);
ctx.lineTo(435, 15+i*30);
ctx.stroke();
}
} //制作黑白棋子
var oneStep = function(i, j, me){
//画圆
ctx.beginPath();
ctx.arc(15 + i*30, 15 + j*30, 13, 0, 2 * Math.PI);
ctx.closePath();
//渐变
var grd = ctx.createRadialGradient(15 + i*30 + 2, 15 + j*30 - 2, 13, 15 + i*30 + 2, 15 + j*30 - 2, 0);
if(me){ //黑棋
grd.addColorStop(0, "#0A0A0A");
grd.addColorStop(1, "#636766");
}
else{ //白棋
grd.addColorStop(0, "#D1D1D1");
grd.addColorStop(1, "#F9F9F9");
}
ctx.fillStyle = grd;
ctx.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(chessBoard[i][j] == 0){
oneStep(i, j, me);
chessBoard[i][j] = 1; //黑棋落子为1 for(var k=0; k<count; k++){
if(wins[i][j][k]){
myWin[k]++;
computerWin[k] = 6; //设置成比5大的数都不会加分
if(myWin[k] == 5){
window.alert("You Win !");
over = true;
}
}
}
if(!over){
me = !me;
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++){
if(chessBoard[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;
}
}
}
}
}
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;
if(computerWin[k] == 5){
window.alert("Computer Win !")
over = true;
}
}
}
if(!over){
me = !me;
}
} //更改鼠标指针样式
chess.onmousemove = function(e){
chess.style.cursor = "default";
var x = e.offsetX;
var y = e.offsetY;
for(var i=0; i<15; i++){
for(var j=0; j<15; j++){
var a = x - (15+i*30);
var b = y - (15+j*30);
var distance = Math.hypot(a, b);
var chessRange = Math.sqrt(25, 2);
//在交叉处半径为5的范围内,鼠标变成手指样式
if(distance < chessRange){
chess.style.cursor = "pointer";
}
}
}
} //赢法数组
var wins = new Array(); //定义赢法的三维数组
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++;
}
}
console.log(count); //赢法统计数组
var myWin = [];
var computerWin = []; //赢法统计数组初始化
for(var i=0; i<count; i++){
myWin[i] = 0;
computerWin[i] = 0;
}
gobang.js(函数封装版本)
//gobang 封装实现
(function(){
//定义变量
var chess = document.getElementById('chess'); //获取棋盘画布
var ctx = chess.getContext('2d'); //设置画布渲染
var logo = new Image(); //创建棋盘背景图像
var chessBoard = new Array(); //棋盘落子统计,用于存储棋盘格上是否有落子
var wins = []; //赢法数组
var count = 0; //赢法统计数组
var myWin = []; //玩家赢法统计
var computerWin = []; //计算机赢法统计
var me = true; //棋手标记 true为玩家下棋,false为电脑下棋
var over = false; //判断对局是否结束标记 true为结束,flase为未结束 var goBang = {
//入口
init: function(){
var _this = this; //复制this对象
return (function(){
//变量初始化
_this.initializa();
//图片加载点
logo.onload = function(){
//填充背景图片
ctx.drawImage(logo,0,0,450,450);
//绘制棋盘线
_this.drawChessBoard();
// _this.oneStep(7,7,false); //测试oneStep函数
}; //落子事件绑定
//点击棋盘落子
chess.onclick = function(e){
//判断对局是否结束或是否轮到玩家下棋,对局结束或者不是玩家下棋就会跳出循环
if(over || me == false){
return ;
}
//获取鼠标点击位置坐标,并转换为落点坐标
var x = e.offsetX,
y = e.offsetY;
var i = Math.floor(x / 30),
j = Math.floor(y / 30);
//判断当前落点是否已有棋子,如果没有则落子成功
if(chessBoard[i][j] == 0){
_this.oneStep(i, j, me); //玩家落子
chessBoard[i][j] = 1; //玩家黑棋落子为1
for(var k=0; k<count; k++){
if(wins[i][j][k]){
myWin[k]++;
computerWin[k] = 999; //设置成比5大的数都不会加分
if(myWin[k] == 5){
window.alert("You Win !");
over = true;
}
}
}
//判断对局是否未结束,如果未结束将换成计算机下子
if(over == false){
me = !me;
_this.computerAI(); //计算机落子
}
}
}; //更改鼠标指针样式
chess.onmousemove = function(e){
chess.style.cursor = "default";
var x = e.offsetX;
var y = e.offsetY;
for(var i=0; i<15; i++){
for(var j=0; j<15; j++){
var a = x - (15+i*30);
var b = y - (15+j*30);
var distance = Math.hypot(a, b);
var chessRange = Math.sqrt(25, 2);
//在交叉处半径为5的范围内,鼠标变成手指样式
if(distance < chessRange){
chess.style.cursor = "pointer";
}
}
}
}; })();
}, //变量&初始化&参数设置
initializa: function(){
return (function(){
//棋盘线条颜色
ctx.strokeStyle = "#000000"; //黑色
//载入背景图片
logo.src = "logo.jpg";
//棋盘棋盘落子统计初始化(无落子) chessBoard
for (var i=0; i<15; i++) {
chessBoard[i] = [];
for(var j=0; j<15; j++){
chessBoard[i][j] = 0;
}
}
//定义赢法的三维数组 wins
for(var i=0; i<15; i++){
wins[i] = [];
for(var j=0; j<15; j++){
wins[i][j] = [];
}
}
//赢法总类统计 共计572种
//横线赢法
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++;
}
}
console.log(count); //赢法总类输出
//赢法统计数组初始化
for(var i=0; i<count; i++){
myWin[i] = 0;
computerWin[i] = 0;
}
})();
}, //绘制棋盘
drawChessBoard: function(){
return (function(){
for(var i=0; i<15; i++){
//画棋盘竖线
ctx.moveTo(15+i*30, 15);
ctx.lineTo(15+i*30, 435);
ctx.stroke();
//画棋盘横线
ctx.moveTo(15, 15+i*30);
ctx.lineTo(435, 15+i*30);
ctx.stroke();
}
})();
}, //绘制黑白棋子
oneStep: function(i, j, me){
return (function(){
//阴影
ctx.shadowOffsetX = 1.5;
ctx.shadowOffsetY = 2;
ctx.shadowBlur = 3;
ctx.shadowColor = '#333';
//画圆
ctx.beginPath();
ctx.arc(15 + i*30, 15 + j*30, 13, 0, 2 * Math.PI);
ctx.closePath();
//渐变
var grd = ctx.createRadialGradient(15 + i*30 + 2, 15 + j*30 - 2, 13, 15 + i*30 + 2, 15 + j*30 - 2, 0);
if(me){ //黑棋
grd.addColorStop(0, "#0A0A0A");
grd.addColorStop(1, "#636766");
}
else{ //白棋
grd.addColorStop(0, "#D1D1D1");
grd.addColorStop(1, "#F9F9F9");
}
ctx.fillStyle = grd;
ctx.fill();
})();
}, //计算机下棋
computerAI: function(){
var that = this; //复制this对象
return (function(){
//定义变量,分数统计数组和坐标存储变量
var myScore = [],
computerScore = [];
var max = 0,
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(chessBoard[i][j] == 0){
//根据赢法数组计算分数
for(var k=0; k<count; k++){
//如果存在第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;
}
}
}
}
}
that.oneStep(u, v, false); //计算机落子
chessBoard[u][v] = 2; ////玩家白棋落子为2
//判断当前落点是否已有棋子,如果没有则落子成功,如果有则后台提示
for(var k = 0; k < count; k++){
if(wins[u][v][k]){
computerWin[k]++;
myWin[k] = 999;
if(computerWin[k] == 5){
window.alert("Computer Win !")
over = true;
}
}
}
if(over == false){
me = !me;
}
})();
},
}; //重新开始
document.getElementById('restart').onclick = function(){
window.location.reload();
}
//执行代码
goBang.init(); })();
棋盘背景图

效果预览

js实现五子棋人机对战源码的更多相关文章
- 【 js 模块加载 】【源码学习】深入学习模块化加载(node.js 模块源码)
文章提纲: 第一部分:介绍模块规范及之间区别 第二部分:以 node.js 实现模块化规范 源码,深入学习. 一.模块规范 说到模块化加载,就不得先说一说模块规范.模块规范是用来约束每个模块,让其必须 ...
- 完全自制的五子棋人机对战游戏(VC++实现)
五子棋工作文档 1说明: 这个程序在创建初期的时候是有一个写的比较乱的文档的,但是很可惜回学校的时候没有带回来……所以现在赶紧整理一下,不然再过一段时间就忘干净了. 最初这个程序是受老同学所托做的,一 ...
- RSA客户端js加密服务器C#解密(含源码)
国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html内部邀请码:C8E245J (不写邀请码,没有现金送)国内私 ...
- JS/Jquery版本的俄罗斯方块(附源码分析)
转载于http://blog.csdn.net/unionline/article/details/63250597 且后续更新于此 1.前言 写这个jQuery版本的小游戏的缘由在于我想通过从零到有 ...
- Pyhton实践项目之(一)五子棋人机对战
1 """五子棋之人机对战""" 2 3 import random 4 import sys 5 6 import pygame 7 im ...
- JS魔法堂: Native Promise Only源码剖析
一, 前言 深入学习Promise的朋友应该都看过<深入理解Promise五部曲>这一系列的文章, 以解除回调地狱之外的观点来剖析Promise更多的内涵,确实十分精彩. Part 1: ...
- 【js】 vue 2.5.1 源码学习(十二)模板编译
大体思路(十) 本节内容: 1. baseoptions 参数分析 2. options 参数分析 3. parse 编译器 4. parseHTNL 函数解析 // parse 解析 parser- ...
- JS如何禁止别人查看网站源码
四种查看路径: 查看效果:猛戳 1.直接按F12 2.Ctrl+Shift+I查看 3.鼠标点击右键查看 4.Ctrl+u=view-source:+url 把以上三种状态都屏蔽掉就可以了,docum ...
- 一个js变量以及其作用域的源码示例
今天遇到了一个问题,抽象出来的代码如下: var zoom=13; function setZoom(){ zoom=14; } function displayZoom(){ this.setZoo ...
随机推荐
- Linux 下 Nand Flash 调用关系
Nand Flash 设备添加时数据结构包含关系 struct mtd_partition partition_info[] --> struct s3c2410_nand_set ...
- [JZOJ3168] 【GDOI2013模拟3】踢足球
题目 描述 题目大意 有两个队伍,每个队伍各nnn人. 接到球的某个人会再下一刻随机地传给自己人.敌人和射门,射门有概率会中. 每次射门之后球权在对方111号选手. 某个队伍到了RRR分,或者总时间到 ...
- [JZOJ3171] 【GDOI2013模拟4】重心
题目 描述 题目大意 有一堆长为222的矩形,最下面的右端点横坐标为000. 每个矩形都有其固定的质量. 将这些矩形堆在一起,使得最右边的横坐标最大,并且满足它不会塌掉(满足物理学). 思考历程 首先 ...
- alias用于设置当前数据表的别名,
alias用于设置当前数据表的别名,便于使用其他的连贯操作例如join方法等. 示例: $Model = M('User'); $Model->alias('a')->join('__DE ...
- 基于MFC的实时可视化项目中视图刷新消息的严谨使用
在实时可视项目中,视图的实时刷新显示对软件的体验感来说非常重要,当算法的效率达到实时,比如一秒40帧,如果实时显示帧率更不上,则体验感将大大折扣,让用户感觉你的算法并没有40帧,当然最关键的是解决显示 ...
- mybatis 一对多和一对一写法注意事项
<resultMap id="ChartResultMap" type="com.qif.dsa.ucenter.planinfo.entity.ChartDate ...
- tty who 命令
#tty : 查看当前终端对应的终端的设备文件 #who : 查看当前系统登录的所有用户及其信息
- Spring MVC(七)--传递JSON参数
有时候参数的传递还需要更多的参数,比如一个获取用户信息的请求中既有用户ID等基本参数,还要求对查询结果进行分页,针对这种场景,一般都会将分页参数封装成一个对象,然后将它和基本参数一起传给控制器,为了控 ...
- day 47 前端基础之BOM和DOM
前端基础之BOM和DOM 前戏 到目前为止,我们已经学过了JavaScript的一些简单的语法.但是这些简单的语法,并没有和浏览器有任何交互. 也就是我们还不能制作一些我们经常看到的网页的一些 ...
- TCP重传机制的学习应用
1. TCP重传机制 TCP协议是一个可靠的协议.发送方每次发送一个数据包,需要等到ACK确认包再继续发送. 发出去的请求包在规定时间内没有收到ACK,不管是请求包丢失,还是ACK包丢失,还是网络延迟 ...