CSS3实现五子棋Web小游戏,Canvas画布和DOM两种实现,并且具有悔棋和撤销悔棋功能。

用Canvas实现五子棋的思路:

1、点击棋盘,获取坐标x,y,计算出棋子的二维数组坐标i和j,

2、棋子的实现,先arc一个圆,再填充渐变色。

3、下完一步棋后切换画笔和角色。

4、赢法算法的实现:计算出整个15*15的棋盘有多少种赢法,定义一个win[]三维数组,数组的初始化如下。

//赢法数组

var wins = [];
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++;
}
}

tip:win数组表达的是某个坐标的棋子有多少种赢法线条(本例中有15*11*5),并且有赢法线条的编号。这在后面下完棋后,需要判断该棋子是否在某个赢法线条上,然后让blackWin[k]数组+1,等blackWin[k]==5时就赢了

for (var k = 0; k < count; k++) {
if (wins[i][j][k]) {
blackWin[k]++;

if (blackWin[k] == 5) {
over = true;
$("#info").text("黑子已胜!再来一盘!");
break;
}

}

}

用DOM实现五子棋小游戏的思路:

1、先把所有棋子的坑用td填充,那么就有15*15个坑,给每个td加上id=i-j

2、每次点击棋盘的时候,获取该td的id,然后解析出来坐标i和j

3、判断赢法算法同上

悔棋的实现:

1、消除棋子:如果是DOM实现,则将td的backgroundImage=none;如果是Canvas实现,则用context.clearRec(x,y,width,height),清除画布中某个棋子区域

2、去除blackWin[k]数组的标记,逆向减法

for (var k = 0; k < count; k++) {
if (wins[i][j][k]) {
blackWin[k]--;
}
}

3、将切换的角色切换回来,me=!me

撤销悔棋的实现:

1、画棋子:如果是DOM实现,则将td的backgroundImage=url(black.png);如果是Canvas实现,则先arc圆,再填充渐变色

2、赢法数组统计

for (var k = 0; k < count; k++) {
if (wins[i][j][k]) {
blackWin[k]++;
}
}

总结:

这样,五子棋的实现原理脉络大概清楚了,最后再贴上完整代码,不用谢。

//DOM实现

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>五子棋</title>
<style>

div#chess {
display: flex;
width: 450px;
height: 450px;
padding: 0px;
display: block;
margin: 50px auto 0px auto;
box-shadow: -2px -2px 2px #efefef, 5px 5px 5px #b9b9b9;
background-image: url(bg.png);
align-items: center;
justify-content:center;
}
div.chessArea {
display: block;
width: 480px;
height: 450px;
padding: 0px;
}
.chessArea table {
border-collapse: collapse;
position:relative;
}

.chessAreaItem {
width: 30px;
height: 30px;
box-sizing: border-box;
margin: 0px;
top: 0px;
bottom: 0px;

}
.info {
width:450px;
height:30px;
color:red;
font-size:15px;
padding-left:20px;
margin:0px auto;
line-height:30px;
box-sizing:border-box;
}
.buttonGroup {
width: 500px;
margin: 20px auto;
display: flex;
justify-content: space-around;
}

.buttonGroup div:hover {
cursor: pointer;
}

.restart {
text-align: center;
background-color: #45c01a;
border-radius: 5px;
}

.revert, .removeRevert {
text-align: center;
background-color: #b9b9b9;
border-radius: 5px;
}

.restart > span, .revert > span, .removeRevert > span {
display: inline-block;
padding: 10px 20px;
color: #fff;
}
</style>
<script src="http://cdn.static.runoob.com/libs/jquery/1.10.2/jquery.min.js"></script>
</head>
<body>
<div id="chess" class="chess" style="display:flex;">
<div class="chessArea"></div>
</div>
<div class="info" id="info"></div>
<div class="buttonGroup">
<div id=‘restart‘ class="restart">
<span>重新开始</span>
</div>

<div id=‘revert‘ class="revert" onclick="revert()">
<span>悔棋</span>
</div>
<div id=‘removeRevert‘ class="removeRevert" onclick="removeRevert()">
<span>撤销悔棋</span>
</div>
</div>

</body>
</html>

<script>
var over = false;
var me = true; //我

var chressBord = [];//棋盘
for (var i = 0; i < 15; i++) {
chressBord[i] = [];
for (var j = 0; j < 15; j++) {
chressBord[i][j] = 0;
}
}

//赢法的统计数组
var blackWin = [];
var whiteWin = [];

//赢法数组
var wins = [];
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++;
}
}

for (var i = 0; i < count; i++) {
blackWin[i] = 0;
whiteWin[i] = 0;
}

function isLightBackground(id, isLight) {
var $this = document.getElementById(id);
if (isLight) {
$this.style.backgroundColor = "#45c01a";
} else {
$this.style.backgroundColor = "#b9b9b9";
}

}

function drawChess(id,me) {
if (me) {
$("#" + id).css("backgroundImage", "url(black.png)");
} else {
$("#" + id).css("backgroundImage", "url(white.png)");
}
}

function removeChess(id) {
$("#" + id).css("backgroundImage", "none");
}

var i, j;
var id;
function chessAreaItemClick(aid) {
id = aid;
if (over) {
return;
}
drawChess(id,me);
i = id.split(‘-‘)[0];
j = id.split(‘-‘)[1];
if (me) {
if (chressBord[i][j] == 0) {
chressBord[i][j] = 1;//黑子
debugger;
for (var k = 0; k < count; k++) {
if (wins[i][j][k]) {
blackWin[k]++;
whiteWin[k] = 6;//这个位置对方不可能赢了
if (blackWin[k] == 5) {
over = true;
isLightBackground(‘revert‘, false);
isLightBackground(‘removeRevert‘, false);
$("#info").text("黑子已胜!再来一盘!");
break;
}
}
}

}
} else {
if (chressBord[i][j] == 0) {
chressBord[i][j] = 2;//白子
for (var k = 0; k < count; k++) {
if (wins[i][j][k]) {
whiteWin[k]++;
blackWin[k] = 6;
if (whiteWin[k] == 5) {
over = true;
isLightBackground(‘revert‘, false);
isLightBackground(‘removeRevert‘, false);
$("#info").text("白子已胜!再来一盘!");
break;
}
}
}
}
}
if (!over) {
me = !me;
//悔棋的样式点亮
isLightBackground(‘revert‘, true);
}

}

var revertFlag = false;
//悔棋事件
function revert() {
if (!over && !revertFlag) {
removeChess(id);
chressBord[i][j] = 0;
if (!me) {
for (var k = 0; k < count; k++) {
if (wins[i][j][k]) {
blackWin[k]--;
}
}
} else {
for (var k = 0; k < count; k++) {
if (wins[i][j][k]) {
whiteWin[k]--;
}
}
}
me = !me;
revertFlag = true;
//撤销悔棋的样式点亮,悔棋样式disabled
isLightBackground(‘revert‘, false);
isLightBackground(‘removeRevert‘, true);
}
}

//撤销悔棋事件
function removeRevert() {
if (!over && revertFlag) {
if (me) {
if (chressBord[i][j] == 0) {
drawChess(id,me);
chressBord[i][j] = 1;//黑子
for (var k = 0; k < count; k++) {
if (wins[i][j][k]) {
blackWin[k]++;
}
}

}
} else {
if (chressBord[i][j] == 0) {
drawChess(id, me);
chressBord[i][j] = 2;//白子
for (var k = 0; k < count; k++) {
if (wins[i][j][k]) {
whiteWin[k]++;
}
}
}
}
if (!over) {
me = !me;
}
revertFlag = false;

//悔棋的样式点亮,撤销悔棋样式disabled
isLightBackground(‘revert‘, true);
isLightBackground(‘removeRevert‘, false);
}
}

//重新开始
document.getElementById("restart").onclick = function () {
window.location.reload();
}

//画所有的棋子
function initChess() {
var $chessArea = document.getElementById("chessArea");
$tbody = $(".chessArea").append(‘<table cellspacing="0px"><tbody></tbody></table>‘);
for (var i = 0; i < 15; i++) {
var $tr = $tbody.append(‘<tr></tr>‘);
for (var j = 0; j < 15; j++) {
$tr.append(‘<td class="chessAreaItem" id=‘ + i +‘-‘+ j + ‘ onclick="chessAreaItemClick(id)"></td>‘);
}
}
}
initChess();

</script>

//Canvas实现

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>五子棋</title>
<style>
canvas {
display: block;
margin: 50px auto;
box-shadow: -2px -2px 2px #efefef, 5px 5px 5px #b9b9b9;
background-image: url(bg.png);
}

.buttonGroup {
width: 500px;
margin: 50px auto;
display: flex;
justify-content: space-around;
}

.buttonGroup div:hover {
cursor: pointer;
}

.restart {
text-align: center;
background-color: #45c01a;
border-radius: 5px;
}

.revert, .removeRevert {
text-align: center;
background-color: #b9b9b9;
border-radius: 5px;
}

.restart > span, .revert > span, .removeRevert > span {
display: inline-block;
padding: 10px 20px;
color: #fff;

}
</style>
</head>
<body>
<canvas id="chess" width="450px" height="450px"></canvas>
<div class="buttonGroup">
<div id=‘restart‘ class="restart">
<span>重新开始</span>
</div>

<div id=‘revert‘ class="revert" onclick="revert()">
<span>悔棋</span>
</div>
<div id=‘removeRevert‘ class="removeRevert" onclick="removeRevert()">
<span>撤销悔棋</span>
</div>
</div>

</body>
</html>

<script>
var over = false;
var me = true; //我

var chressBord = [];//棋盘
for (var i = 0; i < 15; i++) {
chressBord[i] = [];
for (var j = 0; j < 15; j++) {
chressBord[i][j] = 0;
}
}

//赢法的统计数组
var blackWin = [];
var whiteWin = [];

//赢法数组
var wins = [];
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++;
}
}

for (var i = 0; i < count; i++) {
blackWin[i] = 0;
whiteWin[i] = 0;
}

var chess = document.getElementById("chess");
var context = chess.getContext(‘2d‘);
context.strokeStyle = ‘#bfbfbf‘; //边框颜色

//绘画棋盘
//var drawChessBoard = function () {

// for (var i = 0; i < 15; i++) {
// context.moveTo(15 + i * 30, 15);
// context.lineTo(15 + i * 30, 435);
// context.stroke();
// context.moveTo(15, 15 + i * 30);
// context.lineTo(435, 15 + i * 30);
// context.stroke();
// }
//}
//drawChessBoard();
function isLightBackground(id, isLight) {
var $this = document.getElementById(id);
if (isLight) {
$this.style.backgroundColor = "#45c01a";
} else {
$this.style.backgroundColor = "#b9b9b9";
}

}
var i, j;
chess.onclick = function (e) {
if (over) {
return;
}
var x = e.offsetX;
var y = e.offsetY;
i = Math.floor(x / 30);
j = Math.floor(y / 30);
if (me) {
if (chressBord[i][j] == 0) {
oneStep(i, j, true);
chressBord[i][j] = 1;//黑子
for (var k = 0; k < count; k++) {
if (wins[i][j][k]) {

blackWin[k]++;
whiteWin[k] = 6;//这个位置对方不可能赢了
if (blackWin[k] == 5) {
window.alert(‘黑子赢了‘);
over = true;
isLightBackground(‘revert‘,false);
isLightBackground(‘removeRevert‘,false);
break;
}
}
}

}
} else {
if (chressBord[i][j] == 0) {
oneStep(i, j, false);
chressBord[i][j] = 2;//白子
for (var k = 0; k < count; k++) {
if (wins[i][j][k]) {
whiteWin[k]++;
blackWin[k] = 6;
if (whiteWin[k] == 5) {
window.alert(‘白子赢了‘);
over = true;
isLightBackground(‘revert‘, false);
isLightBackground(‘removeRevert‘, false);
break;
}
}
}
}
}
if (!over) {
me = !me;
//悔棋的样式点亮
isLightBackground(‘revert‘, true);
}

}

var revertFlag = false;
//悔棋事件
function revert() {
if (!over && !revertFlag) {
context.clearRect(i * 30, j * 30, 30, 30);
chressBord[i][j] = 0;
if (!me) {
for (var k = 0; k < count; k++) {
if (wins[i][j][k]) {
blackWin[k]--;
}
}
} else {
for (var k = 0; k < count; k++) {
if (wins[i][j][k]) {
whiteWin[k]--;
}
}
}
me = !me;
revertFlag = true;
//撤销悔棋的样式点亮,悔棋样式disabled
isLightBackground(‘revert‘, false);
isLightBackground(‘removeRevert‘, true);
}
}

//撤销悔棋事件
function removeRevert() {
if (!over&&revertFlag) {
if (me) {
if (chressBord[i][j] == 0) {
oneStep(i, j, true);
chressBord[i][j] = 1;//黑子
for (var k = 0; k < count; k++) {
if (wins[i][j][k]) {
blackWin[k]++;
}
}

}
} else {
if (chressBord[i][j] == 0) {
oneStep(i, j, false);
chressBord[i][j] = 2;//白子
for (var k = 0; k < count; k++) {
if (wins[i][j][k]) {
whiteWin[k]++;
}
}
}
}
if (!over) {
me = !me;
}
revertFlag = false;

//悔棋的样式点亮,撤销悔棋样式disabled
isLightBackground(‘revert‘, true);
isLightBackground(‘removeRevert‘, false);
}
}

//画棋子
var oneStep = function (i, j, me) {
context.beginPath();
context.arc(15 + i * 30, 15 + j * 30, 13, 0, 2 * Math.PI);//画圆
context.closePath();
//渐变
var gradient = context.createRadialGradient(15 + i * 30 + 2, 15 + j * 30 - 2, 13, 15 + i * 30 + 2, 15 + j * 30 - 2, 0);

if (me) {
gradient.addColorStop(0, ‘#0a0a0a‘);
gradient.addColorStop(1, ‘#636766‘);
} else {
gradient.addColorStop(0, ‘#d1d1d1‘);
gradient.addColorStop(1, ‘#f9f9f9‘);
}
context.fillStyle = gradient;
context.fill();
return true;
}

document.getElementById("restart").onclick = function () {
window.location.reload();
}

</script>

时间: 2024-10-15 15:56:48

CSS3实现五子棋Web小游戏,Canvas画布和DOM两种实现,并且具有悔棋和撤销悔棋功能。的相关文章

CSS3 常用属性(三)-- 用户界面、文字、两种盒模型

用户界面--column 关于用户界面,我们先了解一下在块元素中写文字时,浏览器中的呈现情况,这个其实很明显,所有的文本内容会在块元素内从左到右一个个字排列,排满后,从上到下一排排渲染--然而,有些时候,页面需求的呈现方式是,类似于报纸似得,将一段文本内容,分成多列布局显示. 用户界面使用的示例如下: .font{ width:300px; height:300px; border:1px solid #000; margin:0px auto; column-count:3; /* 定义数量

Web API之认证(Authentication)两种实现方式【二】(十三)

前言 上一节我们详细讲解了认证及其基本信息,这一节我们通过两种不同方式来实现认证,并且分析如何合理的利用这两种方式,文中涉及到的基础知识,请参看上一篇文中,就不再废叙述废话. 序言 对于所谓的认证说到底就是安全问题,在Web API中有多种方式来实现安全,[accepted]方式来处理基于IIS的安全(通过上节提到的WindowsIdentity依赖于HttpContext和IIS认证)或者在Web API里通过使用Web API中的消息处理机制,但是如果我们想应用程序运行在IIS之外此时Win

ASP.NET Web API接受AngualrJS的QueryString的两种方式

ASP.NET Web API如何接受来自AngualrJS的QueryString呢?本篇体验两种方式. 第一种方式:http://localhost:49705/api/products?search=GDN 这种方式是QueryString原生的格式. 首先,把当前的域名和端口号放到一个自定义的module中去. 1 (function () { 2 "use strict"; 3 4 angular.module("custommodule", ["

[转]Web APi之认证(Authentication)两种实现方式【二】(十三)

本文转自:http://www.cnblogs.com/CreateMyself/p/4857799.html 前言 上一节我们详细讲解了认证及其基本信息,这一节我们通过两种不同方式来实现认证,并且分析如何合理的利用这两种方式,文中涉及到的基础知识,请参看上一篇文中,就不再叙述废话. 序言 对于所谓的认证说到底就是安全问题,在Web API中有多种方式来实现安全,[accepted]方式来处理基于IIS的安全(通过上节提到的WindowsIdentity依赖于HttpContext和IIS认证)

velocity merge作为工具类从web上下文和jar加载模板的两种常见情形

很多时候,处于各种便利性或折衷或者通用性亦或是限制的原因,会借助于模板生成结果,在此介绍两种使用velocity merge的情形,第一种是和spring mvc一样,将模板放在velocityConfigurer属性指定的路径下,如: <bean id="velocityConfigurer" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer"> <pr

IOC容器在web容器中初始化——(一)两种配置方式

参考文章http://blog.csdn.net/liuganggao/article/details/44083817,http://blog.csdn.net/u013185616/article/details/52186184. 最近在研究IOC容器在web容器中初始化的过程.阅读了源码,参照了很多文章,在这里记录一下. 使用的web容器为tomcat7.spring的jar包为4.3.7.RELEASE版本. 我们可以通过web.xml配置文件web容器中声明spring容器.有以下两

我的web小游戏【持续更新中】

在谷歌浏览器中实测无问题.. 五子棋(双人对战):http://1.waymongame.sinaapp.com/wuziqi/wuziqi2.html 贪吃蛇:http://1.waymongame.sinaapp.com/tanchishe/tanchishe.html

powershell的一个小游戏,看看能写几种方式出来

今天在powershell.org看见了这个月的小测试,要求很简单,给出一个csv文件,里面有一列叫做machinename,都是计算机的名字,所有的计算机都可以远程执行powershell 2.0以上的版本,读取这个文本,然后输出一个新的csv文件,包括两列,machinename和osversion http://powershell.org/wp/2015/09/05/september-2015-scripting-games-puzzle/ 豆子想了想,大概写了4种方式都可以做到这一点

小部分ajax的控制,两种实现状态,两段js(纯属自己做给自己看的)

<div class="houseList" ><div class="one111_" id="one111_"> <h3>一/二</h3> <ul class="list"> <li > <span class="fleft">一:</span><!--EOT;$sel = $_viewer->p