1. 程式人生 > >CSS3實現五子棋Web小遊戲,Canvas畫布和DOM兩種實現,並且具有悔棋和撤銷悔棋功能。

CSS3實現五子棋Web小遊戲,Canvas畫布和DOM兩種實現,並且具有悔棋和撤銷悔棋功能。

posit oct padding 角色 sar pac osi fse ech

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

CSS3實現五子棋Web小遊戲,Canvas畫布和DOM兩種實現,並且具有悔棋和撤銷悔棋功能。