上一章:前端人工智能:前端AI研发之算法
第一节我们在人工智能 vs 人的比较中,使用了围棋的人工智能阿尔法狗作为例子。那么在接下来,我们也来完成一个棋类的人工智能游戏 - 五子棋。
在完成人工智能游戏 - 五子棋的研发期间,相信你不仅能打开自己对于前端人工智能世界的新大门,还能从中学到一些前端的相关知识。而五子棋也是我国受众非常广的益智游戏之一,同时它也是人工智能领域的重要研究对象,许多围棋和五子棋的人机大战都成为了人工智能领域的重要里程碑。
五子棋是一种两人对弈的棋类游戏,游戏的目标是在棋盘上先把自己的五个棋子连成一条线,即横线、竖线或斜线。玩家轮流在棋盘上落子,每次只能下一颗棋子。当一方落子后,另一方需要在下一步前判断是否需要阻止对方连成五子,或者自己连成五子。如果一方连成了五子,则游戏结束,该方获胜。
当我们明确我们要做的东西后,我们就得考虑清楚我们的技术栈。第一种方案就是使用 DOM 文档对象模型,第二种方案就是利用 DOM 的其中一个元素 - canvas 画布去写。那么我们使用哪个去写呢?那当然选择canvas了,因为使用 canvas 绘制五子棋棋盘的线条可以使得整个游戏更加立体、美观、真实,同时也提高了用户的交互性和沉浸感。
什么是 canvas
那么什么是 canvas 呢?大家可以简单理解为就是前端用 JavaScript 去画画的一个画布。它有几个特性,接下来我们一起来看看:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<canvas></canvas>
</body>
</html>
在上面的 HTML 文件中,我们定义了一个 canvas 标签,那么接下来打开这个HTML文件看看现在是什么效果
我们可以看到页面一片空白,根本分不出哪块是 canvas。这时候可能就有同学会说了:
“你都没加背景颜色,当然看不见啦!”
那好,我现在利用标签选择器,来给 body 加个背景颜色
<style>
body {
background-color: #000;
}
</style>
那这个时候我来问下大家,现在的页面应该是什么样子的?
在面试中,每当问到这个问题,许多前端求职者都会回答我说:
“页面是黑色的,然后 canvas 标签那一块是白色的。”
是这样的吗?我们一起来看一下
我们可以看到,页面全是黑色的。这也是很多同学会忽略的一个点,那就是 canvas 默认的颜色是透明的,并不是白色。那这个时候可能又有同学会说了:
“那有没有可能是因为你没给 canvas 设置宽高,所以看不见它的背景颜色。”
哎,好杠精!但这个时候我得回答你,canvas 是有默认宽高的,并不需要设置:
我们在浏览器的页面审查中可以看到 canvas 的默认宽高是 300X150,这也是 canvas 里最容易让人忽略的一个点。
那我们在简单了解完 canvas 后,接下来我们就使用它来制作我们的棋盘吧!
开始画画
我相信大家应该都见过别人画画,因为就算没吃过猪肉,应该也见过猪跑。所以画画的第一步,那就是拿好我们的画板。转为程序的角度就是我们要给 canvas 设置一个 id
,并利用 JavaScript 去获取,方便后续去操控它:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<canvas id="canvas"></canvas>
</body>
<script type="text/javascript">
var canvas = document.getElementById("canvas");
</script>
</html>
那么我们还得确定,首先我们做的是 2D 的画。3D 的画我们得用 WebGL,这东西不在我们这门课程的学习范畴内,当然你们想学的话我也可以出。跑偏了跑偏了,所以说,第一步我们得给它定义一个叫context
的东西,然后跟它说一声 :
“兄弟,我要用你画一幅2D的画。”
<script type="text/javascript">
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
</script>
其实context
这个兄弟还有其他很多方法,我跟它商量过了,凭我的面子它愿意让大家 console.log 打印它一下看看它的“家底”。那我们就勉为其难地看看,给它点面子:
从上面我们可以看到,context
为我们提供了很多的方法,足以让我们在网页中利用程序去绘制出一幅完整的画。那我们先不去深入剖析这个兄弟,毕竟刚认识,再继续下去就不礼貌了。
那我们做五子棋,肯定得有棋盘对吧,我们先看看棋盘的样子:
由上图我们可以看出来,棋盘是 15*15 的盘面。那大家觉得,我们画棋盘是画线、画方块还是画圆呢?
那肯定是画线比较好了,通过线的横向纵向排步,就可以很快地实现一个棋盘。那 canvas 怎么画线呢?
使用canvas画线
我们先给 canvas 设置个背景颜色,方便稍后进行分辨:
<style type="text/css">
body {
background: #000;
}
canvas {
background: #fff
}
</style>
用 canvas 去画画其实跟我们日常生活中的画画基本是一模一样的,但是我们需要使用 JavaScript 去告诉它应该怎么去画。那这个时候我要请大家去思考一件事情,那就是我们日常生活中画画,应该怎么去画?
第一步:我们是不是得做准备,准备好画板和思考我们要画什么;
第二步:准备好了,那我们肯定就是直接开始画了;
第三步:画完了,我们收起画笔,然后欣赏我们所作的画。
那么我们使用 canvas 去画呢,基本也跟上面的步骤一样。我们先把 canvas 的画布先调整大点,这里大家也可以注意一下,就是 canvas 画布的大小,是可以直接通过标签属性去设置的:
<canvas id="canvas" width=800 height=800 ></canvas>
那么我们就按照上面的步骤,首先我们要跟context
这个哥们说一声我们要开始画了。begin
在英文里是开始的意思,path
是路径的意思,那么顾名思义我们要跟context
说的就是:
“兄dei,我们要开始画画了。”
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
context.beginPath()
然后我们需要使用moveTo
去告诉它,我们是从哪个点开始画的,moveTo
接收两个值,分别是x轴的坐标值跟y轴的坐标值:
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
context.beginPath()
// 起点
context.moveTo(30,30)
起始点有了,接下来我们来画个终点,终点就是lineTo
,意思是要画到哪个点,同样也是接收x轴的坐标值跟y轴的坐标值:
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
context.beginPath()
// 起点
context.moveTo(30,30)
// 终点
context.lineTo(130,130)
这个时候你再去看画布,哎,奇怪了,是不是什么也没看到,然后控制台也没报错。别急,因为我们只是完成了前两步,我们不是还有第三步吗。那就是我们还要收笔,然后才能去欣赏我们所作的画:
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
context.beginPath()
// 起点
context.moveTo(30,30)
// 终点
context.lineTo(130,130)
// 收笔
context.stroke()
这时候我们再保存代码,去刷新一下页面,你就可以看到我们已经画出来了:
所以其实利用 JavaScript 去画画并没有我们想得那么难,关键是你得找到去把代码语言转换成我们方便记忆和理解的方法。那这个时候比如说我们觉得这支笔不好看,黑不溜秋的,我们想换支颜色鲜艳点的笔,那该怎么办呢?那你跟我说没用呀,得跟context
大兄弟说呀:
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
context.beginPath()
// 换笔
context.strokeStyle = 'red'
context.moveTo(30,30)
context.lineTo(130,130)
context.stroke()
style
是样式的意思,所以上面代码的意思就是我们跟context
借了一支红色的笔,这时候你保存代码刷新页面就可以看到我们画的线就变成红色的了。
那我们来做个简单的小总结:
第一步:准备开始画,context.beginPath()
第二步:假如你想换个画笔,context.strokeStyle
第三步:画,context.moveTo(x,y)
、context.lineTo(x,y)
第四步:收笔,context.stroke()
本站中,我们对 canvas进行了一个简单的入门。千万不要觉得简单而不以为然, canvas 将在我们后续去做人工智能游戏 - 五子棋中承担相当重要的作用。
而当我们知道该怎么使用 canvas 去绘制五子棋棋盘的线条后,那接下来我们还需要去做什么呢?那肯定还得有棋子对吧。那么在下一节中,我们将去体验如何使用 canvas 去绘制黑白棋子,并且我们还会使用 canvas 的高阶属性去实现一些效果。
而我们本次的课程也是从易到难,给大家一个一直往上攀登摸索的过程。实践出真知,很多细节都隐藏在我们的实战当中,也请大家不要忽略任何看起来很简单的东西,一字一行地一起跟着我实现功能,体验细节。