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 ...
随机推荐
- JConsole&VisualVM监控总结
简介JConsole(以下写作jconsole),VisualVM(以下写作jvisualvm ) 都是比较好的JVM调优工具,且都为JDK自带,可在命令行直接启动. 监控示例Server端(需要监控 ...
- 关于Windows10企业版的激活方法
今天打开Excel在使用的时候,突然弹出弹窗,说我的激活即将过期什么的,让我转到设置进行激活. 第一个想到的办法就是更换产品密钥,在网上找了不少产品密钥,密钥有效,但是需要连接企业激活什么的,因为我是 ...
- leetcode-77-组合-字典序
题目描述: 第一次提交: class Solution: def combine(self, n: int, k: int) -> List[List[int]]: res = [] def b ...
- 【JZOJ2288】【BZOJ1898】【luoguP2579】沼泽鳄鱼
description 潘塔纳尔沼泽地号称世界上最大的一块湿地,它地位于巴西中部马托格罗索州的南部地区.每当雨季来临,这里碧波荡漾.生机盎然,引来不少游客. 为了让游玩更有情趣,人们在池塘的中央建设了 ...
- ubuntu下apache服务器操作方法小结,具有参考借鉴价值
这篇文章主要介绍了ubuntu下apache服务器操作方法小结,非常不错,具有参考借鉴价值,需要的朋友可以参考下(http://www.0831jl.com)Linux系统为Ubuntu 一.Star ...
- Spring Cache 简介
org.springframework.cache; org.springframework.cache.Cache org.springframework.cache.CacheManager 依赖 ...
- 0901NOIP模拟测试赛后总结
突然想学迪哥列一下分数线搞清楚自己和别人的差距. rank1- 5- 6-分. 差距很大啊.尤其是和某kyh.大家都开玩笑说天皇是个变态.但是事实摆在这儿,同样坐在机房这么长的时间,人家又AK了. 我 ...
- 模拟——1031D
/* dp[i][j]表示到[i,j]的权值 cnt[i,j]表示到[i,j]还可以使用的修改的次数 cnt[i,j]=max(cnt[i-1,j],cnt[i,j-1]) 如果mp[i,j]!='a ...
- java 获取本机所有IP地址
import java.net.Inet6Address; import java.net.InetAddress; import java.net.NetworkInterface; import ...
- CPU中的主要的寄存器
寄存器 名为寄存器的存储电路. 8种16位寄存器 AX accumulator 累加寄存器 CX counter 计数寄存器 DX data 数据寄存器 BX base 基址寄存器 SP stack ...