前情回顾

前面我们已经完成了对棋盘的建模,接下来是暴力求解程序的核心部分,即枚举算法。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. springboot整合Quartz实现动态配置定时任务
  2. JDBC 学习(一)
  3. 微信朋友圈技术之道:三个人的后台团队与每日十亿的发布量
  4. python调用函数传参时、有默认值的在中间 报错了_python的大坑:使用空列表作为默认参数,让我怀疑遇到了灵异代码...
  5. linux TCP/IP L2层数据包接收流程,eth_rxnetif_receive_skb处理流程
  6. Civil 3D 中使用COM API导入DEM数据创建曲面
  7. idea 配置jdk版本_JDK 11 安装过程(同时已安装了JDK 8)以及Intellij IDEA 配置
  8. 2-4:C++快速入门之函数重载
  9. Mysql数据库InnoDB存储引擎的隔离级别
  10. android开发先学什么,Android开发入门教程应该先学什么
  11. 动手实现图像双线性插值——实现图像resize
  12. idea出现Cannot find keymap “Windows copy的报错“
  13. 18.10.29 POJ 3987 Computer Virus on Planet Pandora(AC自动机+字符串处理)
  14. JAVA系列 IO流 知识结构整理 建立合理的知识框架逻辑 输入输出流 理顺你的思维架构Fileoutput inputStream FileWriter FIleReader结构整理
  15. IDEA中Tomcat乱码问题
  16. python二维数组随机取行,组成新的数组
  17. 为什么计算机编程以英语为主,为什么做编程都用英文,中文不行吗?听程序员解释完,总算明白了...
  18. Macbook M1 软件不兼容的解决办法
  19. 自学python有什么建议,想通过自学Python,朋友们有哪些提议吗?
  20. 微信小程序云开发实例 源码 部署详细流程[自带管理后台]

热门文章

  1. ubuntu linux通过rclone 挂载onedrive 到本地磁盘
  2. stm32+定时器PWM波+电机驱动+直流电机
  3. “终端有鸿蒙,云端有安超!” 鸿蒙落地,安超有什么新动作?
  4. 【Java设计模式】简单学装饰模式——来杯咖啡,先糖后奶
  5. GoogleNet、AleXNet、VGGNet、ResNet等总结
  6. 安装VUE过程中出现的4048错误
  7. npm install报错:4048
  8. 增长黑客AB-Test系统(三)——AB-Test Hash分流
  9. 优酷网页视频地址提取
  10. 赵小楼《天道》《遥远的救世主》深度解析(8)聪明如肖亚文借芮小丹攀缘丁元英到底图的是什么?