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 ...
随机推荐
- unity3d入门 Demo 学习记录
闲来学习一下 unity3d 的Demo,记录如下. 官方 Demo,名字为 Roll-A-Ball,如图 场景比较简单,包含地面.玩家精灵.主摄像机.墙壁.可拾取的方块.分数为示 text.平行光源 ...
- error in ./src/pages/login.vue?vue&type=style&index=0&lang=less&
vue-cli3创建less工程,npm run serve 无法运行 bug解决方法: rm -rf node-modules 修改package.json为 "less": & ...
- 01.MyBatis快速入门
1.下载jar包 Mybatis包+数据库驱动包 https://github.com/mybatis/mybatis-3/releases 2.新建Java工程并导入jar包 3.创建数据库与表 C ...
- fiddler抓包工具遇到的问题-------502报错
遇到的问题: 打开浏览器,输入本机的虚拟机地址的bugfree,出现无法连接的提示,具体是: [Fiddler] The connection to '192.168.211.128' failed. ...
- 廖雪峰Java15JDBC编程-2SQL入门-1SQL介绍
1.SQL:结构化查询语言 Structured Query Language 针对关系数据库设计 各种数据库基本一致 允许用户通过SQL查询数据而不关心数据库底层存储结构 1.1 SQL使用: 可以 ...
- itextPDF使用笔记
最近在做报表打印,使用的是itextPDF,第一次用到它,简单做个笔记.主要涉及到字体设置,文字处理操作,表格及单元格设置,绘制一些图形 IText中有三个处理text的类com.lowagie.te ...
- java使用stream流批量读取并合并文件,避免File相关类导致单文件过大造成的内存溢出。
import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.F ...
- 使用Ajax在HTML页面中局部刷新页面(左边菜单右边页面)
转载自:https://blog.csdn.net/Cenmen_17714/article/details/80969008 index.html <a href="javascri ...
- 上传本地项目到码云(gitee)
1.码云上创建一个项目比如zhirong 2.本地创建一个文件夹F:\workspace\zhirong-items,进入zhirong-items打开git bash 3.执行git init ,这 ...
- Redis学习笔记01-分布式锁
1.分布式锁的定义与理解 在并发任务中,当对数据执行修改和删除时为了防止多个任务同时拿到数据而产生的混乱,这时就要用到分布式锁来限制程序的并发执行. Redis分布式锁本质上要实现的目标就是在Redi ...