一.实现效果:
二.程序描述:
同一台电脑上,分为黑,白两方进行对弈,双方轮流落子,当某一方的棋子能够横,竖,斜练成五颗同色棋子的时候,判定该方获胜
允许最近落子一方点击悔棋,撤销最近落下的一颗子,重新落子。
三.程序环境:
编辑软件:记事本或者Vistual Code 等允许能够编辑Html文件的编辑器即可。
编辑语言:Html,Js或者jQuery,Css,Vue(可有可无)。
核心技术:Js,Html Canvas。
编程插件:jQuery.js,Vue.js(可有可无,没有的话,需要改写一点代码)
四.程序代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>开始游戏</title>
<link rel="stylesheet" href="../css/game.css">
<script src="../js/jquery-3.4.1.js"></script>
<script src="../js/vue.js"></script>
<style>
*{
margin:0;
padding:0;
font-size:14px;
font-family: '微软雅黑';
}
body{
background: rgb(244, 245, 247);
/* background:rgb(78, 70, 46); */
}
#app{
display: flex;
height: 100vh;
width: 100%;
}
.main{
margin: auto;
}
.tips{
font-weight: bold;
}
#side2{
display: none;
}
#mycanvas{
display: block;
box-shadow: -2px -2px 2px #F3F2F2,5px 5px 5px #6F6767;
background: rgb(253, 222, 154);
/* background: rgb(163, 143, 86); */
/* width:450px;
height: 450px; */
}
.hint,.btn{
height: 10vh;
line-height: 10vh;
}
.btn{
text-align: right;
}
.btn input{
padding:3px 10px;
border-radius: 5px;
background: rgb(113, 181, 245);
color:white;
border:none;
cursor: pointer;
}
</style>
</head>
<body>
<div id="app">
<div class="main">
<p class="hint">
<span class="tips">落子方:</span>
<canvas id="side" width="30px" height="30px">你的浏览器不支持 canvas,请升级你的浏览器。</canvas>
<canvas id="side2" width="30px" height="30px">你的浏览器不支持 canvas,请升级你的浏览器。</canvas>
</p>
<p>
<canvas @click="fill" id="mycanvas" width="450px" height="450px">你的浏览器不支持 canvas,请升级你的浏览器。</canvas>
</p>
<p class="btn">
<input type="button" @click="repentance" value="悔棋">
</p>
</div>
</div>
<script>
new Vue({
el:'#app',
data(){
return{
me:true, //true 为黑棋,false为白棋
chessBox:[], //棋局情况
chess:"", //div对象
context:"", //棋局画布
x:-1, //悔棋清理x坐标
y:-1, //悔棋清理y坐标
i:-1, //预选落子位置x坐标
j:-1, //预选落子位置y坐标
}
},
mounted(){
// var chess = document.getElementById("mycanvas");
// var context = chess.getContext('2d');
this.chess = document.getElementById("mycanvas");
this.context = this.chess.getContext('2d');
//描绘落子方棋 黑棋 白棋
var side = document.getElementById("side");
var cont = side.getContext('2d');
var bg = cont.createRadialGradient(15,15,13,15,15,0);
bg.addColorStop(0,'#0a0a0a');
bg.addColorStop(1,'#636766');
cont.fillStyle = bg;
cont.arc(15,15,13,0,2*Math.PI);
cont.fill();
var side2 = document.getElementById("side2");
var cont2 = side2.getContext('2d');
var bg2 = cont2.createRadialGradient(15,15,13,15,15,0);
bg2.addColorStop(0,'#D1D1D1');
bg2.addColorStop(1,'#F9F9F9');
cont2.fillStyle = bg2;
cont2.arc(15,15,13,0,2*Math.PI);
cont2.fill();
//初始化棋盘
for(var i = 0;i< 15;i++){
this.chessBox[i] = [];
for(var j = 0;j< 15;j++){
this.chessBox[i][j] = -1;
}
}
console.log(this.chessBox);
//规划棋盘网格线
for(var i = 0;i< 15;i++){
// context.strokeStyle="#D6D1D1";
this.context.strokeStyle="rgb(163, 143, 86)";
this.context.moveTo(15+i*30,15);
this.context.lineTo(15+i*30,435);
this.context.stroke();
this.context.moveTo(15,15+i*30);
this.context.lineTo(435,15+i*30);
this.context.stroke();
}
//绘制棋盘中的五个点
var round = this.context.createRadialGradient(74,74,5,74,74,40);
round.addColorStop(0,"rgb(163, 143, 86)");
this.context.fillStyle = round;
this.context.beginPath();
this.context.arc(15+3*30,15+3*30,5,0,2*Math.PI);
this.context.arc(15+3*30,15+11*30,5,0,2*Math.PI);
this.context.fill();
this.context.beginPath();
this.context.arc(15+7*30,15+7*30,5,0,2*Math.PI);
this.context.fill();
this.context.beginPath();
this.context.arc(15+11*30,15+3*30,5,0,2*Math.PI);
this.context.arc(15+11*30,15+11*30,5,0,2*Math.PI);
this.context.fill();
},
methods:{
//落子操作,画棋子
oneStep(i,j,k){
this.chess = document.getElementById("mycanvas");
this.context = this.chess.getContext('2d');
this.context.beginPath();
this.context.arc(15+i*30,15+j*30,13,0,2*Math.PI);
var g = this.context.createRadialGradient(15+i*30,15+j*30,13,15+i*30,15+j*30,0);
if(k){
g.addColorStop(0,'#0a0a0a');
g.addColorStop(1,'#636766');
}else{
g.addColorStop(0,'#D1D1D1');
g.addColorStop(1,'#F9F9F9');
}
this.context.fillStyle = g;
this.context.fill();
this.context.closePath();
},
//获取落子,加入到数组
fill:function(event){
var x = event.offsetX;
var y = event.offsetY;
var i = Math.floor(x/30);
var j = Math.floor(y/30);
//预选落子位置
if(this.chessBox[i][j] == -1){
//清理之前的预选落子位置
if((this.i != i || this.j != j) && this.i != -1 || this.j != -1){
this.chessBox[this.i][this.j] = -1;
//擦拭预选框
this.context.clearRect((this.i) * 30, (this.j) * 30, 30, 30);
//重绘网格线
this.context.beginPath();
// this.context.strokeStyle="rgb(163, 143, 86)";
this.context.strokeStyle="rgb(78, 70, 46)";
this.context.moveTo(15+this.i*30 , this.j*30);
this.context.lineTo(15+this.i*30 , this.j*30 + 30);
this.context.moveTo(this.i*30, this.j*30+15);
this.context.lineTo((this.i+1)*30 , this.j*30+15);
this.context.stroke();
//如果是在五个棋盘点的位置,重绘棋盘点
if(this.i == 3 && this.j == 3){
var round = this.context.createRadialGradient(74,74,5,74,74,40);
round.addColorStop(0,"rgb(163, 143, 86)");
this.context.fillStyle = round;
this.context.beginPath();
this.context.arc(15+3*30,15+3*30,5,0,2*Math.PI);
this.context.fill();
}else if(this.i == 3 && this.j == 11){
var round = this.context.createRadialGradient(74,74,5,74,74,40);
round.addColorStop(0,"rgb(163, 143, 86)");
this.context.fillStyle = round;
this.context.beginPath();
this.context.arc(15+3*30,15+11*30,5,0,2*Math.PI);
this.context.fill();
}else if(this.i == 7 && this.j == 7){
var round = this.context.createRadialGradient(74,74,5,74,74,40);
round.addColorStop(0,"rgb(163, 143, 86)");
this.context.fillStyle = round;
this.context.beginPath();
this.context.arc(15+7*30,15+7*30,5,0,2*Math.PI);
this.context.fill();
}else if(this.i == 11 && this.j == 3){
var round = this.context.createRadialGradient(74,74,5,74,74,40);
round.addColorStop(0,"rgb(163, 143, 86)");
this.context.fillStyle = round;
this.context.beginPath();
this.context.arc(15+11*30,15+3*30,5,0,2*Math.PI);
this.context.fill();
}else if(this.i == 11 && this.j == 11){
var round = this.context.createRadialGradient(74,74,5,74,74,40);
round.addColorStop(0,"rgb(163, 143, 86)");
this.context.fillStyle = round;
this.context.beginPath();
this.context.arc(15+11*30,15+11*30,5,0,2*Math.PI);
this.context.fill();
}
}
//赋值宇轩落子位置
this.i = i;
this.j = j;
this.chessBox[i][j] = 0;
//画预选框
var round = this.context.createRadialGradient(74,74,5,74,74,40);
round.addColorStop(0,"red");
round.addColorStop(1,"red");
this.context.fillStyle = round;
//描绘预选样式
this.context.strokeStyle="red";
this.context.beginPath();
this.context.arc(15+i*30,15+j*30,4,0 ,2*Math.PI);
this.context.stroke();
this.context.fill();
this.context.beginPath();
this.context.arc(15+i*30,15+j*30,10,0.8*Math.PI ,1.2*Math.PI);
this.context.stroke();
this.context.beginPath();
this.context.arc(15+i*30,15+j*30,10,1.3*Math.PI ,1.7*Math.PI);
this.context.stroke();
this.context.beginPath();
this.context.arc(15+i*30,15+j*30,10,1.8*Math.PI ,2.2*Math.PI);
this.context.stroke();
this.context.beginPath();
this.context.arc(15+i*30,15+j*30,10,2.3*Math.PI ,2.7*Math.PI);
this.context.stroke();
return;
}
//再次点击预选位置,正式落子
if(this.chessBox[i][j] == 0){
this.$options.methods.oneStep(i,j,this.me);
if(this.me){
this.chessBox[i][j] = 1;
}else{
this.chessBox[i][j] = 2;
}
//赋值最近的落子坐标
this.x = i;
this.y = j;
//正式落子,清理预选落子坐标
this.i = -1;
this.j = -1;
//判断是否胜利
if(this.$options.methods.transverseWin(i,j,this.chessBox)
|| this.$options.methods.longitudinalWin(i,j,this.chessBox)
|| this.$options.methods.southeastWin(i,j,this.chessBox)
||this.$options.methods.southwestWin(i,j,this.chessBox)){
// console.log(this.me);
if(this.me){
alert('黑棋获胜!');
}else{
alert('白棋获胜!');
}
}
// this.$options.methods.transverseWin(i,j,this.chessBox);
// this.$options.methods.longitudinalWin(i,j,this.chessBox);
// this.$options.methods.southeastWin(i,j,this.chessBox);
// this.$options.methods.southwestWin(i,j,this.chessBox);
//切换落子方
this.me=!this.me;
//切换落子方提示
if(this.me){
$('#side2').css('display','none');
$('#side').css('display','inline');
}else{
$('#side').css('display','none');
$('#side2').css('display','inline');
}
}
},
//横向胜利
transverseWin(i,j,chessBox){
var min = i - 4 < 0 ? 0 : i - 4;
var max = i + 4 > 14 ? 14 : i + 4;
var count = 1;
for(var index = min;index < max;index++){
if(chessBox[index][j] <= -1){
continue;
}
if(chessBox[index][j]==chessBox[index+1][j]){
count++;
}else{
count = 1;
}
if(count == 5){
return true;
}
}
},
//纵向胜利
longitudinalWin(i,j,chessBox){
var min = j - 4 < 0 ? 0 : j - 4;
var max = j + 4 > 14 ? 14 : j + 4;
var count = 1;
for(var index = min;index < max;index++){
if(chessBox[i][index] <= -1){
continue;
}
if(chessBox[i][index]==chessBox[i][index+1]){
count++;
}else{
count = 1;
}
if(count == 5){
return true;
}
}
},
//东南获胜
southeastWin(i,j,chessBox){
var count = 1;
for(var index = 0; index < 14 ;index++){
for(var jndex = 0;jndex < 14;jndex++){
if(chessBox[index][jndex] == -1){
continue;
}
if(chessBox[index][jndex] == chessBox[index+1][jndex+1] && (j - i)==(jndex - index)){
count++;
// console.log(index + ' ' + jndex + ' ' + count);
}
if(count==5){
return true;
}
}
}
},
//西南获胜
southwestWin(i,j,chessBox){
var count = 1;
for(var index = 14; index > 0 ;index--){
for(var jndex = 0;jndex < 14;jndex++){
if(chessBox[index][jndex] == -1){
continue;
}
if(chessBox[index][jndex] == chessBox[index-1][jndex+1] && (j + i)==(jndex + index)){
count++;
// console.log(index + ' ' + jndex + ' ' + count);
}
if(count==5){
return true;
}
}
}
},
//悔棋
repentance(){
// console.log(this.x + ' ' + this.y);
if(this.x == -1 || this.y == -1){
return;
}
//擦拭棋子
this.context.clearRect((this.x) * 30, (this.y) * 30, 30, 30);
//重绘网格线
this.context.beginPath();
// this.context.strokeStyle="rgb(163, 143, 86)";
this.context.strokeStyle="rgb(78, 70, 46)";
this.context.moveTo(15+this.x*30 , this.y*30);
this.context.lineTo(15+this.x*30 , this.y*30 + 30);
this.context.moveTo(this.x*30, this.y*30+15);
this.context.lineTo((this.x+1)*30 , this.y*30+15);
this.context.stroke();
//如果是在五个棋盘点的位置,重绘棋盘点
if(this.x == 3 && this.y == 3){
var round = this.context.createRadialGradient(74,74,5,74,74,40);
round.addColorStop(0,"rgb(163, 143, 86)");
this.context.fillStyle = round;
this.context.beginPath();
this.context.arc(15+3*30,15+3*30,5,0,2*Math.PI);
this.context.fill();
}else if(this.x == 3 && this.y == 11){
var round = this.context.createRadialGradient(74,74,5,74,74,40);
round.addColorStop(0,"rgb(163, 143, 86)");
this.context.fillStyle = round;
this.context.beginPath();
this.context.arc(15+3*30,15+11*30,5,0,2*Math.PI);
this.context.fill();
}else if(this.x == 7 && this.y == 7){
var round = this.context.createRadialGradient(74,74,5,74,74,40);
round.addColorStop(0,"rgb(163, 143, 86)");
this.context.fillStyle = round;
this.context.beginPath();
this.context.arc(15+7*30,15+7*30,5,0,2*Math.PI);
this.context.fill();
}else if(this.x == 11 && this.y == 3){
var round = this.context.createRadialGradient(74,74,5,74,74,40);
round.addColorStop(0,"rgb(163, 143, 86)");
this.context.fillStyle = round;
this.context.beginPath();
this.context.arc(15+11*30,15+3*30,5,0,2*Math.PI);
this.context.fill();
}else if(this.x == 11 && this.y == 11){
var round = this.context.createRadialGradient(74,74,5,74,74,40);
round.addColorStop(0,"rgb(163, 143, 86)");
this.context.fillStyle = round;
this.context.beginPath();
this.context.arc(15+11*30,15+11*30,5,0,2*Math.PI);
this.context.fill();
}
//将棋盘棋子数据去除
this.chessBox[this.x][this.y] = 0;
//切换落子
this.me = !this.me;
//切换落子方提示
if(this.me){
$('#side2').css('display','none');
$('#side').css('display','inline');
}else{
$('#side').css('display','none');
$('#side2').css('display','inline');
}
//清理悔棋坐标
this.x = -1;
this.y = -1;
},
}
})
</script>
</body>
</html>
五.学习链接:
CSDN-黄瓜炒鸡蛋儿的博客
六.留言:
单机版五子棋还是差点意思,网络版五子棋,正在紧张制作中,敬请期待。。。