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 ...
随机推荐
- 授权指定ip访问mysql 服务器
授权指定ip访问访问 授权ROOT使用密码1234从应用服务器主机连接到mysql服务器 mysql> GRANT ALL PRIVILEGES ON *.* TO 'root'@'xxx. ...
- ps axu 参数说明
问题:1.ps axu 看到进程的time不清楚什么意思 ru: resin 31507 0.2 1.3 3569452 98340 ? Sl Jul28 7:11 / ...
- Android开发 ShapeDrawable详解
前言 ShapeDrawable一开始我以为它是对应xml文件属性里的shape的画图,后来发现我错了... 其实ShapeDrawable更像是一共自由度更大跟偏向与实现draw()方法的一共图像绘 ...
- 廖雪峰Java11多线程编程-3高级concurrent包-6ExecutorService
Java语言内置多线程支持: 创建线程需要操作系统资源(线程资源,栈空间) 频繁创建和销毁线程需要消耗大量时间 如果可以复用一个线程 线程池: 线程池维护若干个线程,处于等待状态 如果有新任务,就分配 ...
- ES6数组对象新增方法
1. Array.from() Array.from方法用于将两类对象转为真正的数组:类数组的对象( array-like object )和可遍历( iterable )的对象(包括 ES6 新增的 ...
- CreateProcess函数详解及示例
WIN32API函数CreateProcess用来创建一个新的进程和它的主线程,这个新进程运行指定的可执行文件. 函数原型: BOOL CreateProcess ( LPCTSTR lpApplic ...
- <scrapy爬虫>爬取腾讯社招信息
1.创建scrapy项目 dos窗口输入: scrapy startproject tencent cd tencent 2.编写item.py文件(相当于编写模板,需要爬取的数据在这里定义) # - ...
- css3 做border = 0.5px的细线
参考: https://blog.csdn.net/Tyro_java/article/details/52013531
- 2019-8-31-dotnet-如何在-Mock-模拟-Func-判断调用次数
title author date CreateTime categories dotnet 如何在 Mock 模拟 Func 判断调用次数 lindexi 2019-08-31 16:55:58 + ...
- ip-up脚本参数
pppoe连接建立后,系统自动调用/etc/ppp/ip-up脚本. 其参数如下面文件所示,第4个参数是系统获得的动态ip.#!/bin/bash## Script which handles the ...