因为昨天失眠,一整宿没睡觉,让后不能上班睡觉不是,找个东西提神一下,刚好昨天写的小目标还都没做(咳咳)。所以就拿出来写一下。五子棋,应该很多朋友玩过,即双方棋子轮流执子,直到满足某一条直线上有五个已方棋子则已方获胜,反之亦然。那么重点就是要进行检测是否满足五个棋子这个命题了,其它的相对比较简单。
棋盘生成
不多说了,跟着描述走。首先,我去看了下五子棋的大小,是一个 15 * 15 的局面,可以选择用 table 和 ul 来布局,其它的当然也可以。不过总体来说用table 快捷方便一些,虽然我并不喜欢。所以代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<style>
table{border:1px solid #000;}
table tr>td{width:20px;height:20px;}
table tr:nth-child(2n - 1) td:nth-child(2n){border:1px solid #000;box-sizing:border-box;}
table tr:nth-child(2n) td:nth-child(2n - 1){border:1px solid #000;box-sizing:border-box;}
</style>
</head>
<body>
<table id="Checkerboard"> <!-- 棋盘 -->
</table>
</body>
</html>
<script>
function Checkerboard(obj = null){
var $this = this;
if(obj === null){
obj = document.getElementById('Checkerboard');
}
$this.obj = obj;
$this.xNum = 15; // 定义 横 向数量
$this.yNum = 15; // 定义 纵 向数量
$this.run = function(){ // 运行
var html = '<tbody>';
for(var i = 0;i < $this.yNum;i++){
html += '<tr>';
for(var ii = 0;ii < $this.xNum;ii++){
html += '<td>';
}
html += '</tr>';
}
html += '</tbody>';
$this.obj.innerHTML = html; // 写入 html
}
}
var obj = document.getElementById('Checkerboard'); // 对象目标
var board = new Checkerboard(obj);
board.run(); // 运行动作
</script>
刚开始是打算手写了,稍后想了一下,还是 js 生成快些。好了,棋盘布局就生成了,至于为什么是这个样子的,因为啊,我切图切失败了,所以就放弃了,心想,逻辑写出来了,那些样式问题还是交给各位大佬再改好些。
棋子生成
接下来是棋子问题了。棋子生成的思路很简单,一,给他们共同的类名 piece 表明它们是棋子,主要用来做后续标识使用。二,给双方各一个棋子类名,以区分两方轮流执子。三,点击棋盘,修改显示为已落子状态,并不可再落子。
具体代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<style>
table{border:1px solid #000;}
table tr>td{width:20px;height:20px;}
table tr:nth-child(2n - 1) td:nth-child(2n){border:1px solid #000;box-sizing:border-box;}
table tr:nth-child(2n) td:nth-child(2n - 1){border:1px solid #000;box-sizing:border-box;}
.piece{width:20px;height:20px;}
.red_piece{background:red;}
.blue_piece{background:blue;}
</style>
</head>
<body>
<ul>
<li>
<div class="piece red_piece"></div>
<p>这是红方</p>
</li>
<li>
<div class="piece blue_piece"></div>
<p>这是蓝方</p>
</li>
</ul>
<table id="Checkerboard"> <!-- 棋盘 -->
</table>
</body>
</html>
<script>
function Checkerboard(obj = null){
var $this = this;
if(obj === null){
obj = document.getElementById('Checkerboard');
}
$this.obj = obj;
$this.xNum = 15; // 定义 横 向数量
$this.yNum = 15; // 定义 纵 向数量
type = true; // 记录状态,当前用户
$this.run = function(){ // 运行
var html = '<tbody>';
for(var i = 0;i < $this.yNum;i++){
html += '<tr>';
for(var ii = 0;ii < $this.xNum;ii++){
html += '<td>';
}
html += '</tr>';
}
html += '</tbody>';
$this.obj.innerHTML = html; // 写入 html
var tbody = $this.obj.childNodes;
var tr = tbody[0].childNodes;
for(var i = 0;i < tr.length;i++){
var td = tr[i].childNodes;
tr[i].index = i; // 为元素添加索引
for(var ii = 0; ii < td.length;ii++){
td[ii].index = ii;
td[ii].onclick = function(){ // 点击事件
if(this.classList.contains('piece')){ // 判断点击对象是否棋子 类 piece
alert('个人领土神圣不可侵犯!');
}else{
var className;
if(type){
className = 'red_piece';
}else{
className = 'blue_piece';
}
this.classList.add('piece',className); // 为点击对象添加类型名
type = !type; // 修改用户
}
}
}
}
}
}
var obj = document.getElementById('Checkerboard'); // 对象目标
var board = new Checkerboard(obj);
board.run(); // 运行动作
</script>
执行点击动作,需要检测该位置是否已经落子。并且在每次成功落子后修改操作对象 type 作为一个标识进行记录使用用户是谁。主要是这两个点,其它其实也没什么。
获胜检测
下面就是主要的检测是否获胜的阶段了。
检测获胜的方式我是用毕竟笨的方式编写的,还有很多可优化的地方,但因为个人较懒就不想再进行修改了,如果有好的方案欢迎留言。
思路是,在每次落子之后都需要进行一次检测,检测是否获胜,即满足,在一条直线上有五个棋子。也就是四条线,八个方向。上,右上,右,右下,下,左下,左,左上 总共八个方向。我的逻辑就是每次分别检测以落子位子为中心的某条直线的两个方向,是否有五个棋子,如果有则获胜,如果没有则重新开始计算。
具体代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<style>
table{border:1px solid #000;}
table tr>td{width:20px;height:20px;}
table tr:nth-child(2n - 1) td:nth-child(2n){border:1px solid #000;box-sizing:border-box;}
table tr:nth-child(2n) td:nth-child(2n - 1){border:1px solid #000;box-sizing:border-box;}
.piece{width:20px;height:20px;}
.red_piece{background:red;}
.blue_piece{background:blue;}
</style>
</head>
<body>
<ul>
<li>
<div class="piece red_piece"></div>
<p>这是红方</p>
</li>
<li>
<div class="piece blue_piece"></div>
<p>这是蓝方</p>
</li>
</ul>
<table id="Checkerboard"> <!-- 棋盘 -->
</table>
</body>
</html>
<script>
function Checkerboard(obj = null){
var $this = this;
if(obj === null){
obj = document.getElementById('Checkerboard');
}
$this.obj = obj;
$this.xNum = 15; // 定义 横 向数量
$this.yNum = 15; // 定义 纵 向数量
type = true; // 记录状态,当前用户
$this.run = function(){ // 运行
var html = '<tbody>';
for(var i = 0;i < $this.yNum;i++){
html += '<tr>';
for(var ii = 0;ii < $this.xNum;ii++){
html += '<td>';
}
html += '</tr>';
}
html += '</tbody>';
$this.obj.innerHTML = html; // 写入 html
var tbody = $this.obj.childNodes;
var tr = tbody[0].childNodes;
for(var i = 0;i < tr.length;i++){
var td = tr[i].childNodes;
tr[i].index = i; // 为元素添加索引
for(var ii = 0; ii < td.length;ii++){
td[ii].index = ii;
td[ii].onclick = function(){ // 点击事件
if(this.classList.contains('piece')){ // 判断点击对象是否棋子 类 piece
alert('个人领土神圣不可侵犯!');
}else{
var className;
if(type){
className = 'red_piece';
}else{
className = 'blue_piece';
}
this.classList.add('piece',className); // 为点击对象添加类型名
type = !type; // 修改用户
terting(this,className);
}
}
}
}
}
var terting = function(obj,className){
// 开始检测是否条件成立,先进行竖列检测
// 向上报数
var num = 1; // 默认为 1,刚刚点下去的
var xIndex = obj.index;
var tr = obj.parentNode;
var yIndex = tr.index;
var tbody = tr.parentNode;
var win = function(){ // 胜利函数
if(num == 5){
var str = '';
switch(className){
case 'red_piece':
str = '红方胜利';
break;
case 'blue_piece':
str = '蓝方胜利';
break;
}
alert(str);
}
};
for(var i = yIndex - 1;i >= 0;i--){
var r = tbody.childNodes;
var d = r[i].childNodes;
if(d[xIndex].classList.contains(className)){
num++;
}else{
break; // 结束检测,上面没有符合的
}
win(); // 检测胜利
}
// 向下查找
for(var i = yIndex + 1;i < tbody.childNodes.length;i++){
var r = tbody.childNodes;
var d = r[i].childNodes;
if(d[xIndex].classList.contains(className)){
num++;
}else{
break;
}
win(); // 检测胜利
}
// 竖方向失败,则进行充值 num 值
num = 1;
// 左上斜线检测
var lx = xIndex; // 临时 td 索引
for(var i = yIndex - 1;i >= 0;i--){
lx--;
if(lx < 0){
break;
}
var r = tbody.childNodes;
var d = r[i].childNodes;
if(d[lx].classList.contains(className)){
num++;
}else{
break; // 结束检测,上面没有符合的
}
win(); // 检测胜利
}
// 右下斜线检测
lx = xIndex; // 临时 td 索引
for(var i = yIndex + 1;i < tbody.childNodes.length;i++){
lx++;
if(lx >= tr.childNodes.length){
break;
}
var r = tbody.childNodes;
var d = r[i].childNodes;
if(d[lx].classList.contains(className)){
num++;
}else{
break; // 结束检测,上面没有符合的
}
win(); // 检测胜利
}
// 重置 num
num = 1;
// 横向检测
for(var i = xIndex - 1;i >= 0;i--){
var r = tbody.childNodes;
var d = r[yIndex].childNodes;
if(d[i].classList.contains(className)){
num++;
}else{
break; // 结束检测,上面没有符合的
}
win(); // 检测胜利
}
for(var i = xIndex + 1;i < tr.childNodes.length;i++){
var r = tbody.childNodes;
var d = r[yIndex].childNodes;
if(d[i].classList.contains(className)){
num++;
}else{
break; // 结束检测,上面没有符合的
}
win(); // 检测胜利
}
// 重置 num
num = 1;
// 斜右上检测
lx = xIndex;
for(var i = yIndex - 1;i >= 0;i--){
lx++;
if(lx >= tr.childNodes.length){
break;
}
var r = tbody.childNodes;
var d = r[i].childNodes;
if(d[lx].classList.contains(className)){
num++;
}else{
break; // 结束检测,上面没有符合的
}
win(); // 检测胜利
}
// 斜左下检测
lx = xIndex;
for(var i = yIndex + 1;i < tbody.childNodes.length;i++){
lx--;
if(lx < 0){
break;
}
var r = tbody.childNodes;
var d = r[i].childNodes;
if(d[lx].classList.contains(className)){
num++;
}else{
break; // 结束检测,上面没有符合的
}
win(); // 检测胜利
}
// 检测结束,并没有获胜
}
}
var obj = document.getElementById('Checkerboard'); // 对象目标
var board = new Checkerboard(obj);
board.run(); // 运行动作
</script>