前情回顾

前面我们已经完成了对棋盘的建模,接下来是暴力求解程序的核心部分,即枚举算法。Python编程资料点击免费获取

算法实现

要想让程序不断地试错每一种走法,需要设计一种枚举算法。第一颗棋子落定后,第二步对应的几种走法又各自对应若干种第三步的走法,因此,固定第一颗棋子,则在这个棋盘上,所有走法构成了一棵树。第一颗棋子的位置有16个选择,考虑对称关系,可以略去重复项,只剩4个特异的起点。因此,整个游戏的所有走法可以用一个含4棵树的森林来表示。而枚举算法的目的则是试图在所有叶子结点中找到完成游戏的那几个结点。

接下来,我们让算法从根结点开始,逐步探索、完善这棵树。

基本操作

首先,我们需要一些基本操作。

为了表示棋盘状态(哪些格子为空,哪些格子有棋子),我们定义一个占用列表,为了方便起见,同时维护一个未占用列表。初试化两个列表如下:

NodesOccupied = []
NodesUnoccupied = list(range(15))
复制代码

获取棋子n在当前棋盘中的所有走法,输入为棋子序号n,该操作会遍历NodesUnoccupied,得到该棋子所有的走法,即下一步占用哪两个格子:

def getRoads(n):options_all = list(combinations(NodesUnoccupied, 2))options = []for option in options_all:if isSameRow(n, option[0], option[1]) is True\and ((n < option[0] and n < option[1]) or (n > option[0] and n > option[1])):options.append(option)return options
复制代码

执行某一种走法,输入为(n, n1, n2),分别为棋子序号n、接下来要占用的两个位置n1和n2。该操作用于更新NodesOccupiedNodesUnoccupied,并记录该走法,用于最后程序输出。当然,这一步有可能是错误的,如果出现这种情况,后面会有别的操作来将其弹出列表。

def action(n, n1, n2):NodesOccupied += [n1, n2]NodesOccupied.remove(n)NodesUnoccupied.append(n)NodesUnoccupied.remove(n1)NodesUnoccupied.remove(n2)temp_unoccupied = NodesUnoccupied[:]solution.append([[n, n1, n2], temp_unoccupied])
复制代码

回退。如果程序发现不能再往下走了,即运行到叶子结点,而此时又没有达到完成游戏的条件,则说明这条路不正确,最起码在最后的若干步不正确。这时,需要回退到上一个做选择的位置。回退机制需要我们有一个栈来记录每一个做选择(有路可走)的地方,因此,我定义了一个safe_stack。而回退操作则依赖于这个安全状态栈来完成,回退时需要刷新NodesOccupiedNodesUnoccupied,并弹出action列表的最后一步,因为这不是正确的走法。

def get_back():NodesOccupied = safe_stack[-1][0][:]NodesUnoccupied = []for i in range(15):if i not in NodesOccupied:NodesUnoccupied.append(i)solution.pop()
复制代码

主函数

定义完基本操作后,我们开始实现主函数。

主函数的逻辑很简单,即依赖安全状态栈不断循环,直到棋盘中只剩一个空格时退出循环。

代码如下:

def main():# 一共有四棵树,简单起见直接分四次执行。startPoints = [0, 1, 3, 4]# for startPoint in startPoints:startPoint = startPoints[0]NodesOccupied.append(startPoint)NodesUnoccupied.remove(startPoint)isAction = 1while len(NodesUnoccupied) > 1:if isAction:temp_Occupied = NodesOccupied[:]safe_stack.append([temp_Occupied, []])for node in temp_Occupied:options = getRoads(node)for option in options:safe_stack[-1][1].append([node] + list(option))if len(safe_stack[-1][1]):action(safe_stack[-1][1][0][0], safe_stack[-1][1][0][1], safe_stack[-1][1][0][2])isAction = 1else:if len(safe_stack) > 1:safe_stack.pop()safe_stack[-1][1].pop(0)get_back()isAction = 0else:print('Fail.\n')breakprint('Success.\n')for each in solution:print(f'remove {each[0][0]}, append {each[0][1:]}, NodesUnoccupied: {each[1]}')
复制代码

至此,暴力求解程序已经完成,它会将自己摸索出来的第一种解法打印出来:

Success.remove 0, append [1, 3], NodesUnoccupied: [2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0]
remove 1, append [4, 8], NodesUnoccupied: [2, 5, 6, 7, 9, 10, 11, 12, 13, 14, 0, 1]
remove 3, append [6, 10], NodesUnoccupied: [2, 5, 7, 9, 11, 12, 13, 14, 0, 1, 3]
remove 4, append [7, 11], NodesUnoccupied: [2, 5, 9, 12, 13, 14, 0, 1, 3, 4]
remove 6, append [1, 3], NodesUnoccupied: [0, 2, 4, 5, 9, 12, 13, 14, 6]
remove 7, append [2, 4], NodesUnoccupied: [0, 5, 9, 12, 13, 14, 6, 7]
remove 8, append [6, 7], NodesUnoccupied: [0, 5, 9, 12, 13, 14, 8]
remove 11, append [12, 13], NodesUnoccupied: [0, 5, 9, 14, 8, 11]
remove 2, append [5, 9], NodesUnoccupied: [0, 14, 8, 11, 2]
remove 5, append [0, 2], NodesUnoccupied: [14, 8, 11, 5]
remove 12, append [8, 5], NodesUnoccupied: [14, 11, 12]
remove 13, append [11, 12], NodesUnoccupied: [14, 13]
remove 12, append [14, 13], NodesUnoccupied: [12]
复制代码

remove 0, append [1, 3]就表示移动0,占用13NodesUnoccupied即当前还有哪些格子没有被占。按照程序给出的攻略,最终只剩一个空格,游戏完成。

项目代码:Yuezih-Playground/Hopscotch (github.com)

被智商检测器侮辱之后,我直接怒开PyCharm(下)相关推荐

  1. ​人工智能是如何成为“智商检测器”的?

    在5G没有取代4G之前,也许一切有关AI未来的畅想都只是空谈.可残酷的现实是,5G的成本难题让各大科技自媒体的乐观估计"5G已来"成为无法广泛商用的延迟满足. 2020年9月8日, ...

  2. 我服了!一些比较恶心的代码片段

    点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:硬刚一周,3W字总结,一年的经验告诉你如何准备校招! 个人原创100W+访问量博客:点击前往,查看更多 1.下面 ...

  3. 一些恶心的代码片段,你看了就知道!

    点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达今日推荐:2020年7月程序员工资统计,平均14357元,又跌了,扎心个人原创100W+访问量博客:点击前往,查看更多 1. ...

  4. 一些让人恶心的代码片段

    素材整理自网路 1.下面一段代码将注释和代码混在了一起,不认真看还真不知道. 高亮显示后: 2.看到这种多层嵌套恶心到头大 3.据说某俄国特工经过九死一生偷到了NASA的太空火箭发射程序的源代码的最后 ...

  5. 一些比较恶心的代码片段

    1.下面一段代码将注释和代码混在了一起,不认真看还真不知道. 高亮显示后: 2.看到这种多层嵌套恶心到头大. 3.据说某俄国特工经过九死一生偷到了NASA的太空火箭发射程序的源代码的最后一页,代码是: ...

  6. YOLOv4-5D:一种高效的自动驾驶物体检测器

    点击上方"3D视觉工坊",选择"星标" 干货第一时间送达 作者丨CY 来源丨 当交通遇上机器学习 1. 文章信息 本次介绍的文章是2021年3月份发表在IEEE ...

  7. 谷歌开源EfficientDet:实现新SOTA,又快又准的目标检测器

    关注上方"深度学习技术前沿",选择"星标公众号", 资源干货,第一时间送达! 来源:机器之心@微信公众号 什么检测器能够兼顾准确率和模型效率?如何才能实现? 去 ...

  8. 深度学习阅读导航 | 15 YOLOv4:最佳速度与精确度的目标检测器

    写在前面:大家好!我是[AI 菌],一枚爱弹吉他的程序员.我热爱AI.热爱分享.热爱开源! 这博客是我对学习的一点总结与记录.如果您也对 深度学习.机器视觉.算法.Python.C++ 感兴趣,可以关 ...

  9. 【2019-总结】初中毕业暑假集训No.6

    目录 前言 题目解析 一.Hindex 分析 代码 二.Telefoni 分析 代码 三.Turnir 题目 分析 考试瞎搞代码 AC代码 四.Savrsen 题目 分析 考试瞎搞-暴力超时-过1/4 ...

最新文章

  1. constructor
  2. linux rmi端口,RMI 两个端口 - 差不多先生的个人空间 - OSCHINA - 中文开源技术交流社区...
  3. 【CF1020C】Election【贪心】
  4. 南京林业大学计算机专业分数线,2021南京林业大学录取分数线_历年各专业分数线(2017-2020),各省投档线_一品高考网...
  5. python代码中使用pip安装文件
  6. 23. Linux 主机上的用户信息传递
  7. 江苏大学毕业论文答辩PPT模板
  8. 【斯科德C200立式访客机】
  9. 人工智能项目商业价值,主要体现在哪几个方面?
  10. 车载以太网第二弹 | 测试之实锤-IOP测试实践
  11. php strtotime技巧,获取前几天、前几周、后几天、后几周,本月开始和本月结束时间
  12. 〖Python 数据库开发实战 - Python与MySQL交互篇⑫〗- 项目实战- 实现新闻管理模块
  13. uniapp小程序文字与语音互相转化
  14. C语言程序设计第五版谭浩强 第七章答案
  15. jQuery Marquee
  16. 深度学习经典卷积神经网络之VGGNet
  17. Python是什么?Python基础教程400集大型视频,全套完整视频赠送给大家
  18. java——java介绍
  19. 文本自动换行样式word-break: break-all
  20. matlab求解代数等式,2008-2009学年线性代数试卷A及答案

热门文章

  1. Beta冲刺-星期四
  2. mount_nfs: can't mount /data from x.x.x.x onto /Users/caicloud/nfs1: Operation not permitted
  3. Linux内核块设备总结(一)
  4. 向量叉乘的右手螺旋定则
  5. android消息发送字符串,android - 从Android客户端通过HTTP在HL7消息中发送base64字符串时遇到错误 - 堆栈内存溢出...
  6. pixel 6手机连接wifi,网络受限
  7. linux卸载informatica,Informatica在linux下安装搭建
  8. Android开发之svn命令行以及cornerston教程
  9. 前端测试框架Jest——语法篇
  10. 【每日笔记】:layui表单checkbox设为必选