前段时间很想做一个五子棋,就和我们老大讨论相关的算法与规则,了解过后,才发觉,原来一个五子棋的水也很深,这时我们老大建议我做个黑白棋先试试,然后就有了这么个东西。
废话不多说,效果图如下:
1、结构
功能采用html+css+jquery进行编写。
index.html页面用于存储页面布局与样式。
/images文件夹用于存储棋子图片。
/js文件夹用于存放功能js代码(/js/index.js)与jquery(jquery-1.8.3.min.js)
2、html页面(index.html)
css代码如下:
<style> .main { width: 340px; height: 340px; padding-top: 10px; padding-left: 10px; background-color: #f6f5f5; float:left; } .lattice { display: table-cell; vertical-align:middle; text-align:center; width: 40px; height: 40px; float: left; cursor:pointer; } .lattice span { height:100%; display:inline-block; vertical-align:middle; } .lattice img { vertical-align:middle; } .latticeLeft { border-left: 1px solid #b1b0b0; border-top: 1px solid #b1b0b0; } .latticeRight { border-right: 1px solid #b1b0b0; } .latticeBottom { border-bottom: 1px solid #b1b0b0; } style>
类样式(main)为棋盘样式,类样式(lattice)为格子样式,span与img的作用是控制图片居中,类样式(latticeLeft)为左边框样式,类样式(latticeRight)为右边框样式,类样式(latticeBottom)为底边框样式。
js引用代码如下:
<script src="js/jquery-1.8.3.min.js">script> <script src="js/index.js">script>
body代码如下:
<div class="main"> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft latticeRight"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft latticeRight"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft latticeRight"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src="images/black.png"/> div> <div class="lattice latticeLeft"> <span>span><img src="images/white.png" /> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft latticeRight"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src="images/white.png" /> div> <div class="lattice latticeLeft"> <span>span><img src="images/black.png"/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft latticeRight"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft latticeRight"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft"> <span>span><img src=""/> div> <div class="lattice latticeLeft latticeRight"> <span>span><img src=""/> div> <div class="lattice latticeLeft latticeBottom"> <span>span><img src=""/> div> <div class="lattice latticeLeft latticeBottom"> <span>span><img src=""/> div> <div class="lattice latticeLeft latticeBottom"> <span>span><img src=""/> div> <div class="lattice latticeLeft latticeBottom"> <span>span><img src=""/> div> <div class="lattice latticeLeft latticeBottom"> <span>span><img src=""/> div> <div class="lattice latticeLeft latticeBottom"> <span>span><img src=""/> div> <div class="lattice latticeLeft latticeBottom"> <span>span><img src=""/> div> <div class="lattice latticeLeft latticeRight latticeBottom"> <span>span><img src=""/> div> div> <div style="position:relative;left:20px;width:200px;height:100%;float:left;border:1px solid #808080;padding-left:10px;"> <br /> <br /> 等待落子:<label id="lblText">请点击开始label> <br /> <br /> 黑子:<label id="lblcurrent1Num">2label>子 <br /> <br /> 白子:<label id="lblcurrent2Num">2label>子 <br /> <br /> <button onclick="begin()">开始button> <button onclick="reset()">重置button> <br /><br /><br /> div>
html代码采用div进行布局,比较傻,其实可以使用js进行动态加载。
3、js部分(index.js)
通用变量部分,代码如下:
// 落子情况
var dataList = [
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 2, 0, 0, 0],
[0, 0, 0, 2, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
];// 1=黑棋 2=白棋
// 当前棋子
var current = 1;
// 当前黑子数
var current1Num = 2;
// 当前白子数
var current2Num = 2;
// 是否开始
var isBengin = false;
重置按钮事件,代码如下:
// 重置 function reset() { dataList = [ [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 2, 0, 0, 0], [0, 0, 0, 2, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], ]; var x = 0; var y = 0; var divList = document.getElementsByClassName("lattice"); for (var i = 0; i < divList.length; i++) { x = $(divList[i]).attr("data-x"); y = $(divList[i]).attr("data-y"); if (x !=undefined && y != undefined && parseInt(dataList[y][x]) == 1) { $($(divList[i])).find("img").attr("src", "images/black.png"); } else if (x != undefined && y != undefined && parseInt(dataList[y][x]) == 2) { $($(divList[i])).find("img").attr("src", "images/white.png"); } else { $($(divList[i])).find("img").attr("src", ""); } } isBengin = false; }
处理流程,初始化棋子落点数组》清空落点棋子,这里还应该重置黑子落子数与白子落子数,并清空settimeout事件,这里未进行处理。
开始按钮点击事件,代码如下:
function begin() {
isBengin = true;
$("#lblText").text("玩家");
}
落点初始化点击事件与落点坐标,代码如下:
function init() { var x = 0; var y = 0; var divList = document.getElementsByClassName("lattice"); for (var i = 0; i < divList.length; i++) { // 更新X轴值 if (x == 8) { x = 0; } // 更新Y轴值 if (x == 0 && i != 0) { y++; } $(divList[i]).attr("data-x", x); $(divList[i]).attr("data-y", y); $(divList[i]).attr("id", y + "_" + x); $(divList[i]).click(function () { if (!isBengin) { return; } // 验证当前位置是否有子 if ($(this).find("img").attr("src").length > 0) { return; } // 获取当前x和y var thisX = parseInt($(this).attr("data-x")); var thisY = parseInt($(this).attr("data-y")); var arr = checkLegal(thisX, thisY); // 验证是否可以落子 if (!checkIsLegal()) { current = current == 1 ? 2 : 1; $("#lblText").text("电脑"); setTimeout(function () { AILegal(); }, 2000); return; } // 验证是否合法 if (sumArray(arr) == 0) { return; } // 翻转棋子 var rearr = SumTurn(thisX, thisY, arr); Turn(rearr); if (current == 1) {// 黑棋 $(this).find("img").attr("src", "images/black.png"); dataList[thisY][thisX] = current; current = 2; } else {// 白棋 $(this).find("img").attr("src", "images/white.png"); dataList[thisY][thisX] = current; current = 1; } sumNum(); $("#lblText").text("电脑"); setTimeout(function () { AILegal(); }, 2000); }); x++; } }
校验是否可进行落子,代码如下:
// 验证落子是否合法 function checkLegal(x, y) { var result = new Array(); var isLegal = false; var isDuiFang = false; var i = y - 1; // 上 for (; i >= 0; i--) { if (dataList[i][x] == 0) { break; } if (dataList[i][x] != current) { isDuiFang = true; } if (isDuiFang && dataList[i][x] == current) { isLegal = true; break; } } if (isLegal) { result.push(1); } else { result.push(0); } // 下 isLegal = false; isDuiFang = false; i = y + 1; for (; i < 8; i++) { if (dataList[i][x] == 0) { break; } if (dataList[i][x] != current) { isDuiFang = true; } if (isDuiFang && dataList[i][x] == current) { isLegal = true; break; } } if (isLegal) { result.push(1); } else { result.push(0); } // 左 isLegal = false; isDuiFang = false; i = x - 1; for (; i >= 0; i--) { if (dataList[y][i] == 0) { break; } if (dataList[y][i] != current) { isDuiFang = true; } if (isDuiFang && dataList[y][i] == current) { isLegal = true; break; } } if (isLegal) { result.push(1); } else { result.push(0); } // 右 isLegal = false; isDuiFang = false; i = x + 1; for (; i < 8; i++) { if (dataList[y][i] == 0) { break; } if (dataList[y][i] != current) { isDuiFang = true; } if (isDuiFang && dataList[y][i] == current) { isLegal = true; break; } } if (isLegal) { result.push(1); } else { result.push(0); } // 左上 isLegal = false; isDuiFang = false; i = y - 1; var j = x - 1; for (; i >= 0 && j >= 0; i--, j--) { if (dataList[i][j] == 0) { break; } if (dataList[i][j] != current) { isDuiFang = true; } if (isDuiFang && dataList[i][j] == current) { isLegal = true; break; } } if (isLegal) { result.push(1); } else { result.push(0); } // 右上 isLegal = false; isDuiFang = false; i = y - 1; var j = x + 1; for (; i >= 0 && j < 8; i--, j++) { if (dataList[i][j] == 0) { break; } if (dataList[i][j] != current) { isDuiFang = true; } if (isDuiFang && dataList[i][j] == current) { isLegal = true; break; } } if (isLegal) { result.push(1); } else { result.push(0); } // 左下 isLegal = false; isDuiFang = false; i = y + 1; var j = x - 1; for (; i < 8 && j >= 0; i++, j--) { if (dataList[i][j] == 0) { break; } if (dataList[i][j] != current) { isDuiFang = true; } if (isDuiFang && dataList[i][j] == current) { isLegal = true; break; } } if (isLegal) { result.push(1); } else { result.push(0); } // 右下 isLegal = false; isDuiFang = false; i = y + 1; var j = x + 1; for (; i < 8 && j < 8; i++, j++) { if (dataList[i][j] == 0) { break; } if (dataList[i][j] != current) { isDuiFang = true; } if (isDuiFang && dataList[i][j] == current) { isLegal = true; break; } } if (isLegal) { result.push(1); } else { result.push(0); } return result; }
计算翻转位置,代码如下:
// 计算需要翻转位置 function SumTurn(x,y,arr) { var isDuiFang = false; var xArr = new Array(); var yArr = new Array(); var currentArr = new Array(); // 上 if (arr[0] == 1) { for (var i = y-1; i >= 0; i--) { if (dataList[i][x] == 0) { break; } if (dataList[i][x] != current) { xArr.push(x); yArr.push(i); if (current == 1) { currentArr.push(1); } else { currentArr.push(2); } isDuiFang = true; } if (isDuiFang && dataList[i][x] == current) { break; } } } // 下 isDuiFang = false; if (arr[1] == 1) { for (var i = y+1; i < 8; i++) { if (dataList[i][x] == 0) { break; } if (dataList[i][x] != current) { xArr.push(x); yArr.push(i); if (current == 1) { currentArr.push(1); } else { currentArr.push(2); } isDuiFang = true; } if (isDuiFang && dataList[i][x] == current) { break; } } } // 左 isDuiFang = false; if (arr[2] == 1) { for (var i = x-1; i >= 0; i--) { if (dataList[y][i] == 0) { break; } if (dataList[y][i] != current) { xArr.push(i); yArr.push(y); if (current == 1) { currentArr.push(1); } else { currentArr.push(2); } isDuiFang = true; } if (isDuiFang && dataList[y][i] == current) { break; } } } // 右 isDuiFang = false; if (arr[3] == 1) { for (var i = x+1; i < 8; i++) { if (dataList[y][i] == 0) { break; } if (dataList[y][i] != current) { xArr.push(i); yArr.push(y); if (current == 1) { currentArr.push(1); } else { currentArr.push(2); } isDuiFang = true; } if (isDuiFang && dataList[y][i] == current) { break; } } } // 左上 isDuiFang = false; if (arr[4] == 1) { for (var i = y-1, j = x-1; i >= 0 && j >= 0; i--, j--) { if (dataList[i][j] == 0) { break; } if (dataList[i][j] != current) { xArr.push(j); yArr.push(i); if (current == 1) { currentArr.push(1); } else { currentArr.push(2); } isDuiFang = true; } if (isDuiFang && dataList[i][j] == current) { break; } } } // 右上 isDuiFang = false; if (arr[5] == 1) { for (var i = y-1, j = x+1; i >= 0 && j < 8; i--, j++) { if (dataList[i][j] == 0) { break; } if (dataList[i][j] != current) { xArr.push(j); yArr.push(i); if (current == 1) { currentArr.push(1); } else { currentArr.push(2); } isDuiFang = true; } if (isDuiFang && dataList[i][j] == current) { break; } } } // 左下 isDuiFang = false; if (arr[6] == 1) { for (var i = y+1, j = x-1; i < 8 && j >= 0; i++, j--) { if (dataList[i][j] == 0) { break; } if (dataList[i][j] != current) { xArr.push(j); yArr.push(i); if (current == 1) { currentArr.push(1); } else { currentArr.push(2); } isDuiFang = true; } if (isDuiFang && dataList[i][j] == current) { break; } } } // 右下 isDuiFang = false; if (arr[7] == 1) { for (var i = y+1, j = x+1; i < 8 && j < 8; i++, j++) { if (dataList[i][j] == 0) { break; } if (dataList[i][j] != current) { xArr.push(j); yArr.push(i); if (current == 1) { currentArr.push(1); } else { currentArr.push(2); } isDuiFang = true; } if (isDuiFang && dataList[i][j] == current) { break; } } } var result = new Array(); result.push(xArr); result.push(yArr); result.push(currentArr); return result; }
翻转棋子,代码如下:
// 翻转棋子 function Turn(arr) { var xArr = arr[0]; var yArr = arr[1]; var currentArr = arr[2]; for (var n = 0; n < xArr.length; n++) { if (currentArr[n] == 1) { $("#" + yArr[n] + "_" + xArr[n]).find("img").attr("src", "images/black.png"); dataList[yArr[n]][xArr[n]] = 1; } else { $("#" + yArr[n] + "_" + xArr[n]).find("img").attr("src", "images/white.png"); dataList[yArr[n]][xArr[n]] = 2; } } }
计算数组合计,通用方法,代码如下:
// 计算数组合计
function sumArray(arr) {
var result = 0;
for (var i = 0; i < arr.length; i++) {
result += arr[i];
}
return result;
}
校验当前落子人是否可进行落子,代码如下:
// 验证当前需要落子人是否可以落子
function checkIsLegal() {
for (var i = 0; i < dataList.length; i++) {
for (var j = 0; j < dataList[i].length; j++) {
var arr = checkLegal(j, i);
// 验证是否合法
if (sumArray(arr) > 0) {
return true;
}
}
}
return false;
}
ai落子,代码如下:
// AI落子 function AILegal() { // 获取可以落子点 var xArr = new Array(); var yArr = new Array(); var lArr = new Array(); var WeightArr = new Array(); var resultArr = new Array(); // 初始化可以落子的位置 for (var i = 0; i < dataList.length; i++) { for (var j = 0; j < dataList[i].length; j++) { if (dataList[i][j] == 0) { var arr = checkLegal(j, i); // 验证是否合法 if (sumArray(arr) > 0) { xArr.push(j); yArr.push(i); lArr.push(arr); var result = SumTurn(j, i, arr); WeightArr.push(result[0].length); resultArr.push(result); } } } } // 计算权值最大 var i_t = -1; var sumWeight=0; for (var i = 0; i < WeightArr.length; i++) { if (sumWeight < WeightArr[i]) { i_t = i; sumWeight = WeightArr[i]; } } if (i_t >= 0) { Turn(resultArr[i_t]); // 验证是否可以落子 if (!checkIsLegal()) { current = current == 1 ? 2 : 1; $("#lblText").text("玩家"); } if (current == 1) {// 黑棋 $("#" + yArr[i_t] + "_" + xArr[i_t]).find("img").attr("src", "images/black.png"); dataList[yArr[i_t]][xArr[i_t]] = current; current = 2; } else {// 白棋 $("#" + yArr[i_t] + "_" + xArr[i_t]).find("img").attr("src", "images/white.png"); dataList[yArr[i_t]][xArr[i_t]] = current; current = 1; } sumNum(); $("#lblText").text("玩家"); } }
这里,只进行了初级ai,如果有兴趣,其实可以增加权值,比如说普通点权值为1,占边为5,有兴趣可以一起讨论一下。
计算并展示落子数:
function sumNum() { current1Num = 0; current2Num = 0; // 计算当前落子 for (var i = 0; i < dataList.length; i++) { for (var j = 0; j < dataList[i].length; j++) { if (parseInt(dataList[i][j]) == 1) { current1Num++; } else if (parseInt(dataList[i][j]) == 2) { current2Num++; } } } $("#lblcurrent1Num").text(current1Num); $("#lblcurrent2Num").text(current2Num); }
4、总结
一个练手的东西,无聊的时候研究研究还是挺有意思的,功能上有很多可以完善完善,算法上也有很多不足,有人要是有好的想法,欢迎讨论。
下载附件