1 Star 0 Fork 1

jia/h5五子棋

forked from Object/h5五子棋 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
index.html 9.55 KB
一键复制 编辑 原始数据 按行查看 历史
Object 提交于 2021-08-04 17:29 . AI优化
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>五子棋</title>
</head>
<body>
<!--棋盘层-->
<canvas id="gobangBase" width="1200px" height="800px" style="position: absolute;"></canvas>
<!--棋子层-->
<canvas id="gobangPice" width="1200px" height="800px" style="position: absolute;"></canvas>
<!--交互层-->
<canvas id="gobangActi" width="1200px" height="800px" style="position: absolute;"></canvas>
</body>
<script>
//游戏基本架构
var gbb = gobangBase.getContext("2d");
var gbp = gobangPice.getContext("2d");
var gba = gobangActi.getContext("2d");
var gbm = [];
var isEnd = 0;
var pices = [2, [],
[]
];
//玩家使用的棋子
var player = 2;
function isEmpty(x, y) {
//判断该位置是否有棋子
return isEnd == 0 && gbm[x] && gbm[x][y] == 0;
}
function trans(X) {
//坐标转换为像素坐标
return 25 + 50 * X;
}
function toX(P) {
//像素坐标转换为坐标
return Math.round((P - 25) / 50);
}
function drawBase() {
//绘制棋盘
//画线
for (let i = 0; i < 16; i++) {
gbb.moveTo(25, trans(i));
gbb.lineTo(775, trans(i));
gbb.moveTo(trans(i), 25);
gbb.lineTo(trans(i), 775);
//小黑点
if (i == 7 || i == 3 || i == 12) {
gbb.fillRect(trans(i) - 5, trans(i) - 5, 10, 10);
if (i != 7) {
gbb.fillRect(trans(i) - 5, trans(15 - i) - 5, 10, 10);
}
}
}
gbb.stroke();
//初始化棋盘数组
var row = [];
for (let i = 0; i < 16; i++) {
row.push(0);
}
for (let i = 0; i < 16; i++) {
gbm.push([].concat(row));
}
}
drawBase();
var old = [0, 0];
gobangActi.onmousemove = (e) => {
//棋盘内移动时,绘制定位光标
let x = toX(e.clientX);
let y = toX(e.clientY);
if (isEnd == 0) {
gba.clearRect(trans(old[0]) - 15, trans(old[1]) - 15, 30, 30);
}
if (isEmpty(x, y)) {
gba.strokeRect(trans(x) - 10, trans(y) - 10, 20, 20);
old = [x, y];
}
}
gobangActi.onclick = (e) => {
if (pices[0] == player) {
let x = toX(e.clientX);
let y = toX(e.clientY);
drawPice(x, y, pices[0]);
setTimeout(() => {
gbAi(gbm, pices, player == 1 ? 2 : 1, drawPice);
}, 10);
}
}
function drawPice(x, y, pice) {
//绘制棋子
if (isEmpty(x, y)) {
gba.clearRect(trans(old[0]) - 15, trans(old[1]) - 15, 30, 30);
let p = pice == 1 ? 2 : 1;
let len = pices[p].length - 1;
if (len > -1) {
gba.clearRect(trans(pices[p][len][0]) - 30, trans(pices[p][len][1]) - 30, 60, 60);
}
gbp.fillStyle = "#000";
gbp.beginPath();
gbp.arc(trans(x), trans(y), 20, 0, 2 * Math.PI);
gbp.fill();
//白棋
if (pice == 1) {
gbp.fillStyle = "#FFF";
gbp.beginPath();
gbp.arc(trans(x), trans(y), 18, 0, 2 * Math.PI);
gbp.fill();
}
gbm[x][y] = pice;
pices[pice].push([x, y]);
gba.strokeRect(trans(x) - 25, trans(y) - 25, 50, 50);
pices[0] = pice == 1 ? 2 : 1;
checkWin(x, y);
}
}
function drawWin(x1, y1, x2, y2) {
//游戏结束
let s = 1;
let e = 2;
if (x1 == x2) {
if (y1 > y2) {
s = 0;
e = 1;
}
} else if (y1 == y2) {
if (x1 > x2) {
s = 1.5;
e = 0.5;
} else {
s = 0.5;
e = 1.5;
}
} else if (x1 > x2) {
if (y1 > y2) {
s = 1.75;
e = 0.75;
} else {
s = 1.25;
e = 0.25;
}
} else {
if (y1 > y2) {
s = 0.25;
e = 1.25;
} else {
s = 0.75;
e = 1.75;
}
}
let p = pices[0] == 1 ? 2 : 1;
let len = pices[p].length - 1;
if (len > -1) {
gba.clearRect(trans(pices[p][len][0]) - 30, trans(pices[p][len][1]) - 30, 60, 60);
}
gba.lineWidth = 3;
gba.strokeStyle = "#F00";
gba.beginPath();
gba.arc(trans(x1), trans(y1), 22, s * Math.PI, e * Math.PI);
gba.arc(trans(x2), trans(y2), 22, e * Math.PI, s * Math.PI);
gba.arc(trans(x1), trans(y1), 22, s * Math.PI, s * Math.PI);
gba.stroke();
gba.strokeStyle = "#000";
isEnd = 1;
gba.lineWidth = 1;
playWin();
}
function playWin() {
//播放结果动画
let start = 0;
let w = 60;
let h = 10;
gba.clearRect(trans(old[0]) - 15, trans(old[1]) - 15, 30, 30);
let loop = () => {
start += 1;
let x = 1000 - (w / 2 + start);
let y = 125 - (h + start) / 2;
gba.fillStyle = "#000";
gba.fillRect(x, y, w + start * 2, h + start);
gba.fillStyle = "#FFF";
gba.fillRect(x + 3, y + 3, (w - 6) + start * 2, (h - 6) + start);
if (start < 100) {
setTimeout(function() {
loop();
}, 10);
} else {
gba.font = "45px Arial";
if (pices[0] == 2) {
gba.strokeText("白棋获胜", x + 36, y + 70);
} else {
gba.strokeText("黑棋获胜", x + 36, y + 70);
}
}
}
loop();
}
function checkWin(x, y) {
//游戏结束检测
let p = gbm[x][y];
let count = 0;
let e = [x, y];
//水平检测
//左
let res = counter(gbm,p,x,y,-1,0,0,4);
if(res[0] == 4){
drawWin(x,y,res[1],res[2]);
return;
}
e = [res[1],res[2]];
count = res[0];
//右
res = counter(gbm,p,x,y,1,0,0,4);
if((res[0] + count) >= 4){
drawWin(e[0],e[1],res[1] - (res[0] + count - 4),res[2]);
return;
}
//垂直检测
//上
res = counter(gbm,p,x,y,0,-1,0,4);
if(res[0] == 4){
drawWin(x,y,res[1],res[2]);
return;
}
e = [res[1],res[2]];
count = res[0];
//下
res = counter(gbm,p,x,y,0,1,0,4);
if((res[0] + count) >= 4){
drawWin(x,y,res[1] ,res[2] + (res[0] + count - 4));
return;
}
//撇
//右上
res = counter(gbm,p,x,y,1,-1,0,4);
if(res[0] == 4){
drawWin(x,y,res[1],res[2]);
return;
}
e = [res[1],res[2]];
count = res[0];
//左下
res = counter(gbm,p,x,y,-1,1,0,4);
if((res[0] + count) >= 4){
drawWin(x,y,res[1] + (res[0] + count - 4) ,res[2] - (res[0] + count - 4));
return;
}
//捺
//左上
res = counter(gbm,p,x,y,-1,-1,0,4);
if(res[0] == 4){
drawWin(x,y,res[1],res[2]);
return;
}
e = [res[1],res[2]];
count = res[0];
//右下
res = counter(gbm,p,x,y,1,1,0,4);
if((res[0] + count) >= 4){
drawWin(x,y,res[1] - (res[0] + count - 4) ,res[2] - (res[0] + count - 4));
return;
}
}
function counter(m,t,x,y,xw,yw,z,c){
//方向计数器 m 地图数组 t 目标值 x,y 起点坐标 xw,yw 坐标前进方向 z 允许空格数 c 检测格数
let count = 0;
let ex = -1;
let ey = -1;
let end = -1;
for(let i = 1; i <= c; i++ ){
ex = x+xw*i;
ey = y+yw*i;
if(m[x+xw*i]){
let n = m[x+xw*i][y+yw*i];
end = n;
if(n == t){
count++;
}else if( n == 0 && z > 0){
z--;
}else{
ex = x+xw*(i-1);
ey = y+yw*(i-1);
break;
}
}else{
ex = x+xw*(i-1);
ey = y+yw*(i-1);
break;
}
}
return [count,ex,ey,end];
}
</script>
<script>
//五子棋AI
function gbAi(map, prices, act, fun) {
if (prices[0] == act) {
let other = act == 1 ? 2 : 1;
let leno = prices[other].length;
//在对手落子周围评估得分
let res = {
x: 7,
y: 7,
max: 0,
step:3
};
let s1 = {};
let s2 = {};
if (leno > 0) {
let price = prices[other];
for(let i in price){
let p = price[i];
let s3 = sea4area(map, p, other, res);
for(let k in s3){
s1[k] = s3[k];
}
}
}
for (let i in prices[act]) {
let s3 = sea4area(map, prices[act][i], act, res);
for(let k in s3){
s2[k] = s3[k];
}
}
for(let k in s1){
if(s2[k]){
s2[k] += s1[k] * 0.8;
}else{
s2[k] = s1[k]
}
}
let maxs = [];
for(let k in s2){
if(s2[k] > res.max){
res.max = s2[k];
let pxy = k.split(",");
res.x = parseInt(pxy[0]);
res.y = parseInt(pxy[1]);
maxs = [[res.x,res.y]]
}else if(s2[k] == res.max){
maxs.push([res.x,res.y]);
}
}
if(maxs.length > 1){
let chose = parseInt(maxs.length * Math.random());
res.x = maxs[chose][0];
res.y = maxs[chose][1]
}
fun(res.x, res.y, act);
}
}
//计算位置周围得分最大值
function sea4area(map, p, act, res) {
let x = res.x;
let y = res.y;
let max = res.max;
let ws = [
[1,0],
[-1,0],
[0,1],
[0,-1],
[1,1],
[1,-1],
[-1,-1],
[-1,1]
];
let scs = {};
for (let i = 1; i < res.step; i++){
for(let k in ws){
let w = ws[k];
let wx = p[0] + i * w[0];
let wy = p[1] + i * w[1];
if (map[wx] && map[wx][wy] == 0) {
let score = defen(wx, wy, map, act);
scs[[wx,wy].join(",")]=score;
}
}
}
res.x = x;
res.y = y;
res.max = max;
return scs;
}
//计算位置得分
function defen(x, y, map, act) {
//水平检测
let count = 0;
let config = [
[[-1,0,1],[1,0,0]],
[[-1,0,0],[1,0,1]],
[[0,-1,1],[0,1,0]],
[[0,-1,0],[0,1,1]],
[[-1,-1,1],[1,1,0]],
[[-1,-1,0],[1,1,1]],
[[-1,1,1],[1,-1,0]],
[[-1,1,0],[1,-1,1]]
];
for(let i in config){
let c = config[i];
let res = counter(map,act,x,y,c[0][0],c[0][1],c[0][2],5);
let num = res[0];
let none = 0;
if(res[3]==0){
none+=6;
}
res = counter(map,act,x,y,c[1][0],c[1][1],c[1][2],5);
num += res[0];
if(res[3]==0){
none+=6;
}
count+=10**num;
count+=none**num;
}
return count;
}
// setInterval(()=>{gbAi(gbm, pices, pices[0], drawPice);},10);
</script>
</html>
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/jia-code/gobang.git
[email protected]:jia-code/gobang.git
jia-code
gobang
h5五子棋
master

搜索帮助