1. canvas是块级元素吗??

2. css3 box-shadow属性

语法:box-shadow: h-shadow v-shadow blur spread color inset;

注释:box-shadow 向框添加一个或多个阴影。该属性是由逗号分隔的阴影列表,每个阴影由 2-4 个长度值、可选的颜色值以及可选的 inset 关键词来规定。省略长度的值是 0。

 
描述
h-shadow 必需;水平阴影的位置;允许负值。
v-shadow 必需;垂直阴影的位置;允许负值。
blur 可选;模糊距离。
spread 可选;阴影的尺寸。
color 可选;阴影的颜色。
inset 可选;将外部阴影(outset)改为内部阴影。

3.

代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>五子棋</title>
<link rel="stylesheet" type="text/css" href="css/style.css">
</head>
<body>
<canvas id="chess" width="450px" height="450px"></canvas>
<script type="text/javascript" src="js/sc.js"></script>>
</body>
</html>

CSS

canvas{
display: block;
margin: 50px auto;
box-shadow: -2px -2px 2px #EFEFEF, 5px 5px 5px #B9B9B9;
}

js部分:

1)双人轮流下棋(赢需要人为判断)

//定义二维数组存储棋盘上落子的情况
var chessBoard = [];
var me = true; //代表黑子 for(var i=0; i<15; i++){
chessBoard[i] = [];
for(var j=0; j<15; j++){
chessBoard[i][j] = 0; //代表没有落子,空的
}
} var chess = document.getElementById('chess');
var context = chess.getContext('2d'); context.strokeStyle = "#BFBFBF"; var logo = new Image();
logo.src = "images/deer.png";
//图片加载完成后调用drawImage()
logo.onload = function() {
context.drawImage(logo, 0, 0, 450, 450);
drawChessBoard(); //保证棋盘在水印图片的上层
} /*canvas为450px*450px,棋盘内边距留白15px,每行每列均为15条线,14个方格,每个方格30px*/
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();
}
} //i,j代表棋子在棋盘的索引,而me(Boolean)表示走的是黑棋还是白棋
var oneStep = function(i, j, me) {
context.beginPath();
//可以画扇型,圆心,半径,扇型的起止弧度和终止弧度
context.arc(15 + i*30, 15 + j*30, 13, 0, 2 * Math.PI);
context.closePath();
//6个参数
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"); //0、1代表百分比
gradient.addColorStop(1, "#636766")
} else{
gradient.addColorStop(0, "#D1D1D1");
gradient.addColorStop(1, "#F9F9F9")
}
context.fillStyle = gradient;
context.fill(); //用于填充
} chess.onclick = function(e) {
//相对与canvas左上角计算的坐标
var x = e.offsetX;
var y = e.offsetY;
var i = Math.floor(x / 30);
var j = Math.floor(y / 30);
if(chessBoard[i][j] == 0) {
oneStep(i, j, me)
if(me) {
chessBoard[i][j] = 1;
} else {
chessBoard[i][j] = 2;
}
me = !me;
} }

2)人机模式

window.onload=function(){
var me=true;
var over=false;//表示棋局有没有结束 //定义二维数组存储棋盘上落子的情况
var chessBord=[];
//初始化chessBord数组
for(var i=0; i<15;i++){
chessBord[i]=[];
for(var j=0;j<15;j++){
chessBord[i][j]=0; //代表没有落子,空的
}
} //赢法数组(三维数组)
var wins=[];
//赢法的统计数组(一维数组)
var myWin=[];
var computerWin=[];
//初始化3维赢法数组
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++){
//wins[0][0][0] = true;
//wins[0][1][0] = true;
//wins[0][2][0] = true;
//wins[0][3][0] = true;
//wins[0][4][0] = true; //wins[0][1][1] = true;
//wins[0][2][1] = true;
//wins[0][3][1] = true;
//wins[0][4][1] = true;
//wins[0][5][1] = true;
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++;
}
} console.log(count);
//初始化赢法的统计数组
for(var i=0; i<count; i++){
myWin[i]=0;
computerWin[i]=0;
} /**/
var chess=document.getElementById('chess');
var context=chess.getContext('2d'); context.strokeStyle="#BFBFBF";
var logo=new Image();
logo.src="data:images/deer.png";
/**/
logo.onload=function(){
context.drawImage(logo,0,0,450,450);
drawChessBoard();
/**/ }
/**/
function drawChessBoard (){
for(var i=0; i<15; i++){
context.moveTo(15+i*30,15);
context.lineTo(15+i*30,430);
context.stroke();
context.moveTo(15,15+i*30);
context.lineTo(435,15+i*30);
context.stroke();
}
} /**//*定义onesStep函数来绘制棋子*/
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();//填充
} /**/
chess.onclick=function(e){
//棋局结束
if(over){
return;
}
if(!me){
return;
}
var x=e.offsetX;
var y=e.offsetY;
var i=Math.floor(x/30);
var j=Math.floor(y/30);
if(chessBord[i][j]==0){
oneStep(i,j,me);
chessBord[i][j]=1;
for(var k=0;k<count;k++){
if(wins[i][j][k]){
myWin[k]++; //向着胜利前进一步
computerWin[k]=6; //黑棋落子,白棋在k种赢法下不成立,异常数据,不可能大于5
if(myWin[k]==5){
window.alert("你赢了");
over=true;
}
}
}
if(!over){
me=!me;
computerAI();
}
}
} //定义computerAI函数
var computerAI=function(){
var myScore=[]; //计算我方得分(二维数组)
var computerScore=[]; //计算计算机得分(二维数组)
var max=0; //保存最高分数
var u=0, v=0; //保存最高分数的点的坐标 for(var i=0;i<15;i++){
myScore[i]=[];
computerScore[i]=[];
for(var j=0;j<15;j++){
myScore[i][j]=0;
computerScore[i][j]=0;
}
} for(var i=0;i<15;i++){
for(var j=0; j<15;j++){
if(chessBord[i][j]==0){
//如果i,j出现在多种赢法上,会进行累加
for(var k=0; k<count;k++){
if(wins[i][j][k]){
if(myWin[k]==1){
myScore[i][j]+=200;
} else if(myWin[k]==2){
myScore[i][j]+=400;
} else if(myWin[k]==3){
myScore[i][j]+=2000;
} else if(myWin[k]==4){
myScore[i][j]+=10000;
}
if(computerWin[k]==1){
computerScore[i][j]+=200;
} else if(computerWin[k]==2){
computerScore[i][j]+=400;
} else if(computerWin[k]==3){
computerScore[i][j]+=2000;
} else if(computerWin[k]==4){
computerScore[i][j]+=10000;
}
}
}
if(myScore[i][j]>max){
max=myScore[i][j];
u=i;
v=j;
} else if(myScore[i][j]==max){
if(computerScore[i][j]>computerScore[u][v]){
u=i;
v=j;
}
}
if(computerScore[i][j]>max){
max=computerScore[i][j];
u=i;
v=j;
} else if(computerScore[i][j]==max){
if(myScore[i][j]>myScore[u][v]){
u=i;
v=j;
}
}
}
}
}
oneStep(u,v,false);
chessBord[u][v]=2;
//
for(var k=0;k<count;k++){
if(wins[u][v][k]){
computerWin[k]++;
myWin[k]=6;
if(computerWin[k]==5){
setTimeout(function(){
window.alert("计算机赢了");},0.5);
over=true;
}
}
}
if(!over){
me=!me; }
}
}

注:此AI算法侧重于防守;

几个小问题:

1)Chrome浏览器中,在落下第五个棋子(赢),会先弹出‘赢了’的对话框,用setTimeout改进;

后续改进:

1)添加悔棋功能 

如果是要悔棋的功能的话可以用一个变量存储上次落子坐标,重新绘制背景以及坐标位置的十字;

2)添加重置功能

3)落子得分的计算

4)重复部分的封装 

  

 

  

Mooc--五子棋(js)小结的更多相关文章

  1. 【微信小程序项目实践总结】30分钟从陌生到熟悉 web app 、native app、hybrid app比较 30分钟ES6从陌生到熟悉 【原创】浅谈内存泄露 HTML5 五子棋 - JS/Canvas 游戏 meta 详解,html5 meta 标签日常设置 C#中回滚TransactionScope的使用方法和原理

    [微信小程序项目实践总结]30分钟从陌生到熟悉 前言 我们之前对小程序做了基本学习: 1. 微信小程序开发07-列表页面怎么做 2. 微信小程序开发06-一个业务页面的完成 3. 微信小程序开发05- ...

  2. CSS&JS小结

    回顾:html: 作用:展示 文件标签: <html> <head> <title></title> </head> <body> ...

  3. 五子棋js

    http://www.jb51.net/article/35993.htm <!DOCTYPE html> <html> <head> <meta http- ...

  4. HTML5 五子棋 - JS/Canvas 游戏

    背景介绍 因为之前用c#的winform中的gdi+,java图形包做过五子棋,所以做这个逻辑思路也就驾轻就熟,然而最近想温故html5的canvas绘图功能(公司一般不用这些),所以做了个五子棋,当 ...

  5. node.js小结 2

    下载node安装npm什么的就不说了 入门总结 http://www.cnblogs.com/Darren_code/archive/2011/10/31/nodejs.html 进入node_HOM ...

  6. 使用Webdriver执行JS小结

    首先,我们使用如下方式初始化driver: WebDriver driver = new FirefoxDriver(); JavascriptExecutor jse = (JavascriptEx ...

  7. js小结

    1,浏览器对json支持的方法: JSON.parse(jsonstr);将string转为json的对象. JSON.stringify(jsonobj);将json对象转为string. 2,js ...

  8. 百度地图js小结

    1.获取javascript API 服务方法,首先申请密钥(ak),才可成功载入APIJS文件. 用法例如以下: <script type="text/javascript" ...

  9. 小程序app.js小结

    小程序app.js app.js import { ApiUrl } from 'utils/apiurl.js'; import { httpReq } from 'utils/http.js'; ...

  10. js 小结

    <script type="text/javascript"> var hotalAddJs = { makeSubmitDataHandler: function ( ...

随机推荐

  1. [jzoj 5178] [NOIP2017提高组模拟6.28] So many prefix? 解题报告(KMP+DP)

    题目链接: https://jzoj.net/senior/#main/show/5178 题目: 题解: 我们定义$f[pos]$表示以位置pos为后缀的字符串对答案的贡献,答案就是$\sum_{i ...

  2. 访问Storm ui界面,出现Nimbus Summary或Supervisor Summary时有时无的问题解决(图文详解)

    不多说,直接上干货! 前期博客 apache-storm-0.9.6.tar.gz的集群搭建(3节点)(图文详解) apache-storm-1.0.2.tar.gz的集群搭建(3节点)(图文详解)( ...

  3. (转载)Android之有效防止按钮多次重复点击的方法(必看篇)

    为了防止测试妹子或者用户频繁点击某个按钮,导致程序在短时间内进行多次数据提交or数据处理,那到时候就比较坑了~ 那么如何有效避免这种情况的发生呢? 我的想法是,判断用户点击按钮间隔时间,如果间隔时间太 ...

  4. Linux下查看mysql错误日志

    1.进入 mysql 安装目录 进入 data 目录(该目录存储的是数据库的数据) cd  /usr/local/mysql ll 进入 mysql 目录 ,发现 文件后缀 .err,即是mysql ...

  5. jquery根据接口返回的值来设置asp:CheckBoxList的选中值

    接口返回一个json的值,然后通过jquery来选中asp:CheckBoxList相应选中的值 <asp:CheckBoxList runat="server" Repea ...

  6. SGU 180 Inversions【树状数组】

    题意:求逆序数 和POJ那题求逆序数的一样,不过这题离散化之后,要去一下重,然后要开到long long #include<iostream> #include<cstdio> ...

  7. UVa 12545 Bits Equalizer【贪心】

    题意:给出两个等长的字符串,0可以变成1,?可以变成0和1,可以任意交换s中任意两个字符的位置,问从s变成t至少需要多少次操作 先可以画个草图 发现需要考虑的就是 1---0 0---1 ?---0 ...

  8. ActiveMQ学习笔记(7)----ActiveMQ支持的传输协议

    1. 连接到ActiveMQ Connector: Active提供的,用来实现连接通讯的功能,包括:client-to-broker,broker-to-broker.ActiveMQ允许客户端使用 ...

  9. nginx.conf.default

    [root@web03 conf]# vim nginx.conf.default #user nobody;worker_processes 1; #error_log logs/error.log ...

  10. Vue2.0父子组件间事件派发机制

    从vue1.x过来的都知道,在vue2.0中,父子组件间事件通信的$dispatch和$broadcase被移除了.官方考虑是基于组件树结构的事件流方式实在是让人难以理解,并且在组件结构扩展的过程中会 ...