首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

建模!用python玩转积木安放问题

上了佩恩教授的AI人工智能课,小八对生活中一些看似神奇莫测的技术有了新的认识,比如人脸识别,它就是利用了OpenCV库的神经网络(NN)来训练电脑学习人脸模型。但电脑如何学习呢?在NN中,我们可以在神经元中给电脑一些输入,然后将每个神经元依次汇拢到传感器中。大家有认识算法的,一定想起了图与树。没错!在每个神经元到传感器的路径中,都有一定的权值,叫‘Weight’(这可不是体重!)。将每个输入依次乘以每个权值并求和,存入到传感器中,再由显示器输出。

那么问题来了,小八还是没有解释清楚电脑的学习原理。其实很简单,在你给了输入之后,让电脑产生随机的权值并得到输出,你再给电脑纠正,告诉他正确答案,电脑就会调整权值。如果你的例子多了,电脑的处理精度就会越高。比如,你输入一个数,想要让电脑返回那个数的平方,你就得教他:

输入1,得到1;

输入2,得到4;

输入3,得到9……

慢慢地,电脑的NN就会发现你在让他求一个数的平方(这不是简单地使用平方根!)

是不是被吓到了!那么还有更恐怖的,小八使用NN让电脑学会了求阶乘,

做找规律的题不在话下。。。

给大家介绍完NN的工作机制,小八开始进入正题(其实刚介绍的知识和后面要讲的没什么太大关系)。不知大家有没有玩过“智慧金字塔”,就是在一个有限的棋盘内,放置多种形状的积木(当然,每一种积木只有一个),使其平铺在棋盘上,不重叠也不出界。小八已经体会过了题目的烧脑和可怕,所以便灵感乍现地想请python来帮忙。规则简洁明了,但想要转化为python能够理解的思维方式就不容易了。计算机的世界里,只有一堆比特,在这儿可没有什么积木的存在。因此,在逻辑运算之前,如何构建表达方式是一个不可避免的难题。希望大家先思考思考~~~

时间到!小八可以先剧透一下——这个难题已经被我攻克了,而最初的思想就是:建模!

那什么是建模呢?扩充开来就是‘构建模型’,这有点类似软件架构师所做的事情。实际上,它就是一个思维线图和基础,把大量现实中纷繁复杂的数据转化或移入一个预先设计好的模型框架,并为后来的逻辑在模型中运转提供了可能。上一课,我们刚学了列表,它可以储存一系列的值,包括它本身。那么,我们可不可以将堆砌积木的现实问题,变成列表运算的编程问题呢?

这其实是完全可能的,想象一下:棋盘中所有空着的地方标注为0,不同种类积木的实体部分分别标注为1、2、3……等等,这已经是一个好的开端!

小八废话少说,先上程序谍照:

(注:由于时间紧迫,小八只添加了两种积木和一个较小的棋盘,但要扩展种类,用现有的函数是完全可以做到的)

(请自行忽略最上方的一长段注释)

接下来的内容就简单介绍,不再详细讲解了。我们在开头定义了一个new_board(),它的用处和名字一样,就是设定一个新的棋盘,简单来说,就是一旦发生积木安放失败或错误,它会在第一时间清除棋盘推倒重来。

spin()这个函数非常巧妙,它很聪明的模拟了积木方向的改变——比如原来的积木是[[1,2,3],

[4,5,6]] (注意只有两层)

通过spin之后变为:

[[3,6],

[2,5],

[1,4]]

这似乎是把原来的积木逆时针旋转了一下!我们运用spin,已经可以创建积木的4种不同方向。

下面是一段冗长的、繁琐的函数lay_block(),你能猜出它的用处吗?哈哈,恰如其名,这正是用于模拟安放积木的代码。为了遍历积木列表组的每一项,我们使用了两个for in循环,i是行数,j是列数。为了算出积木在棋盘中的具体位置,我们需要将积木块里的i,j两个index分别加上棋盘中的格点位置来得到。

(比如积木的某一格点的位置为(1,0)也就是在第二行的第一个,注意,python调用索引值总是现实的个数减一的,而你想以积木的左上角为顶点,在(0,0)处画,所以这个格点的真实位置是(1+0,0+0)=(1,0),没错,这是对的!)关于棋盘位置的具体数据,小八在开头已经用sites包括了。

为了判断积木是否出界,只要调用try except引诱出IndexError就行了,但要判断是否重合,就不太方便了,简要概括就是如果积木顶点和棋盘顶点都不为0(也就是你试图把积木实体部分放在棋盘上已经放有积木的地方),就将skip设为True。

接下来在函数run()主体部分,也就是写了一连串的循环,来得到两种积木各自的10个位置、4个方向……对了,积木是可以翻转的,我们将用reverse()把积木列表组倒序。如果python一旦检测到skip为True,也就是安放积木出现了问题,就将此方案continue掉,换句话说,就是跳入下一个循环,放弃掉老的进度。不过在这儿有一个巧妙的地方,即如果第一个积木就安放错误,那第二个积木根本就不用考虑直接跳过了。

只有当两个积木都安放成功,skip仍为False时,这才是一个可行的方案,小八用print()将答案打印在idle上。

在程序的最后,感谢__name__ == '__main__'使得只有当程序是非导入的情况下在执行run()。

[4]

[4, 4]

[4, 2, 2]

[4, 2, 2, 2]

[2]

[2, 2]

[2, 2, 4]

[4, 4, 4, 4]

电脑算对了!这的确是只有两种方案,而电脑都考虑到了!

而且,以这样模块化的编程习惯,今后要扩充棋盘或积木或更多功能,将会变得非常方便。

这一期,我们学了不少知识,当有人问你:《小八的游戏天空》都介绍些什么?你一定要回答:我可学到了建模呢!

不管你懂没懂,别人总会觉得你是一个掌握了特殊技能的人。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180813G1SM6L00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券