用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>