澳门永利m5900cc

澳门永利m5900cc

  • 鑱旂郴鎴戜滑鈥斿崐鏈堣皥缃 2019-07-16
  • 【江州天气】江州天气预报,一周、15天、30天江州天气预报查询 2019-07-16
  • 雄安新区:个人产权住房以共有产权房为主 2019-07-16
  • 吉林省委书记巴音朝鲁致信网友:共同构筑网上网下最大同心圆,集聚振兴发展最强正能量 2019-07-16
  • 1943年2月17日:赖传珠关于敌向盐阜区扫荡情况的报告 2019-07-16
  • 揪心悲剧!男孩身体伸出天窗 撞限高栏不幸身亡 2019-07-16
  • 台湾医师:电子烟危害多 2019-07-16
  • 【抚宁天气】抚宁天气预报,一周、15天、30天抚宁天气预报查询 2019-07-16
  • 《中国古典和谐政治理念与治国方略研究》简介 2019-07-16
  • 江苏通报少女被泼开水烫伤案:行凶者未实施开水灌喉 2019-07-16
  • 从未雨绸缪到枕戈待旦 2019-07-16
  • 2018反转新闻盘点:看清真相有多难? 2019-07-16
  • 2019女足世界杯:耐克助力中国女足全新球衣亮相巴黎 2019-07-16
  • 高洪波:当图书管理员“监守自盗” 和战友偷书看 2019-07-16
  • 2018年国家社科基金后期资助项目立项名单公布 2019-07-16
  • 登录 立即注册
    金钱:

    澳门永利m5900cc

    看了《最强大脑》,我决定做这个游戏 [复制链接]

    2018-7-28 23:00
    iOS雯Ping 阅读:602 评论:0 赞:1
    Tag:  爬虫大数据人工智能web前端

    澳门永利m5900cc www.alfanarrealestate.com 来源: C与Python实战 链接:

    https://mp.weixin.qq.com/s/CRUpNx6hmsGTu-Jr0hvuLw

    今年年初,新一季的《最强大脑》开播了,第一集选拔的时候大家做了一个数字游戏,名叫《数字华容道》,当时何猷君以二十几秒的成绩夺得该项目的冠军,来看一下当时的比赛:

    <iframe frameborder="0" width="677" height="380.8125" allow="autoplay; fullscreen" allowfullscreen="true" src="https://v.qq.com/txp/iframe/player.html?origin=https%3A%2F%2Fmp.weixin.qq.com&amp;vid=b0530dd3y1o&amp;autoplay=false&amp;full=true&amp;show1080p=false" style="margin: 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important;"></iframe>

    作为一个开发者,有一个学习的氛围跟一个交流圈子特别重要这是一个我的python交流群:831524055,不管你是小白还是大牛欢迎入驻 ,讨论技术, 大家一起交流学习成长!

    看了这个游戏之后我决定要写一个《数字华容道》的程序,过去了半年,我终于记起了这件事,今天就来实现。

    数字推盘游戏(n-puzzle)是一种智力游戏,常见的类型有十五数字推盘游戏和八数字推盘游戏等。十五数字推盘游戏的板上会有十五个方块和一个大小相当于一个方块的空位(供方块移动之用),当15个数字依次排序并且最后一个格子为空位即代表挑战成功。

    本文使用?PyQt5?进行设计与实现,PyQt5 是该程序的一个呈现方式,最重要的是算法,学会了算法,完全可以使用?PyGame?或者?Tkinter?实现。

    PyQt5安装:pip install PyQt5??

    本文使用环境:
    • 系统:Windows 10 ?64位

    • Python版本:3.6

    1、布局设计

    做一个简版的数字华容道,布局设计如图所示:

    <figure style="margin: 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; font-size: inherit; color: inherit; line-height: inherit;">![image.gif](https://upload-images.jianshu.io/upload_images/12650374-c5a06bbd1be796aa.gif?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    
    <figcaption style="margin: 10px 0px 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; line-height: inherit; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em;">简版数字华容道布局</figcaption>
    
    </figure>
    • 图中灰色的部分使用?QWidget?作为整个游戏的载体;

    • 黄色部分使用?QGridLayout?作为数字方块的布局;

    • 红色部分使用?QLabel?作为数字方块。

    2、算法设计

    如上图所示,本游戏共需要15个方块,每个方块代表一个数字。我们可以使用 一个二维 list?来存储方块上的数字。其实我们要创建一个?4x4?的 list 存储 0~15 各个数字,0 代表空的位置。

    2.1 创建并初始化数组

    创建数组的方法:

    • 创建一个长度为16的数组,并且在对应位置上保存着 0~15 ;

    • 打乱顺序

    import?random#?用来存放位置信息的二维数组blocks?=?[]#?产生随机数组,0?代表空的位置arr?=?range(16)numbers?=?random.sample(arr,?16)for?row?in?range(4):????blocks.append([])????for?column?in?range(4):????????blocks[row].append(numbers[row*4?+?column])#?打印结果for?i?in?range(4):????print(blocks[i])[out][2,?5,?7,?9][11,?8,?4,?12][6,?13,?10,?15][1,?14,?0,?3][Finished?in?0.1s]

    2.2 移动算法

    假如移动之前个数字位置如左图所示,那么当按下左箭头时,会变成如右图所示:

    <figure style="margin: 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; font-size: inherit; color: inherit; line-height: inherit;">
    
    <figcaption style="margin: 10px 0px 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; line-height: inherit; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em;">![image.gif](https://upload-images.jianshu.io/upload_images/12650374-751a552bfee366d3.gif?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    
    </figcaption>
    
    <figcaption style="margin: 10px 0px 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; line-height: inherit; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em;">左移</figcaption>
    
    </figure>

    可以看到?(1, 2)?和 ?(1, 3)?两个位置上的数字互换了,即 0 和 8 互换;如果右图所示再次按下左箭头,那么所有数字都不会改变,因为 数字 0 右边没有数了。

    总结一下:如果 数字 0 所在位置为 (row, column),并且?column≠3?那么按下左箭头之后,(row, column) 和 (row, column+1) 位置上的数组互换,同理可得:

    • 如果 数字 0 所在位置为 (row, column),并且?column≠0?那么按下右箭头之后,(row, column) 和 (row, column-1) 位置上的数组互换;

    • 如果 数字 0 所在位置为 (row, column),并且?row≠3?那么按下上箭头之后,(row, column) 和 (row+1, column) 位置上的数组互换;

    • 如果 数字 0 所在位置为 (row, column),并且?row≠0?那么按下下箭头之后,(row, column) 和 (row-1, column) 位置上的数组互换;

    将移动算法封装成一个函数如下:

    #?移动#?zero_row?代表数字0?所在二维数组的行下标,zero_column代表数字0?所在二维数组的列下标def?move(direction):????if(direction?==?'UP'):?#?上????????if?zero_row?!=?3:????????????blocks[zero_row][zero_column]?=?blocks[zero_row?+?1][zero_column]????????????blocks[zero_row?+?1][zero_column]?=?0????????????zero_row?+=?1????if(direction?==?'DOWN'):?#?下????????if?zero_row?!=?0:????????????blocks[zero_row][zero_column]?=?blocks[zero_row?-?1][zero_column]????????????blocks[zero_row?-?1][zero_column]?=?0????????????zero_row?-=?1????if(direction?==?'LEFT'):?#?左????????if?zero_column?!=?3:????????????blocks[zero_row][zero_column]?=?blocks[zero_row][zero_column?+?1]????????????blocks[zero_row][zero_column?+?1]?=?0????????????zero_column?+=?1????if(direction?==?'RIGHT'):?#?右????????if?zero_column?!=?0:????????????blocks[zero_row][zero_column]?=?blocks[zero_row][zero_column?-?1]????????????blocks[zero_row][zero_column?-?1]?=?0????????????zero_column?-=?1

    2.3 是否胜利检测算法

    检测是否胜利其实很简单:前15个位置分别对应,最后一个为0即为胜利?,不过为了避免不必要的计算,我们先检测最后一个是否为 0 ,如果不为0 前面的就不用比较了。具体代码实现如下:

    #?检测是否完成def?checkResult():????????#?先检测最右下角是否为0????????if?blocks[3][3]?!=?0:????????????return?False????????for?row?in?range(4):????????????for?column?in?range(4):????????????????#?运行到此处说名最右下角已经为0,pass即可????????????????if?row?==?3?and?column?==?3:????????????????????pass????????????????#?值是否对应????????????????elif?blocks[row][column]?!=?row?*?4?+?column?+?1:????????????????????return?False????????return?True

    3、实现

    下面讲解所有功能模块的实现。

    3.1 框架搭建

    创建?QWidget?作为整个游戏的载体:

    import?sysfrom?PyQt5.QtWidgets?import?QWidget,?QApplicationclass?NumberHuaRong(QWidget):????"""?华容道主体?"""????def?__init__(self):????????super().__init__()????????self.initUI()????def?initUI(self):????????#?设置宽和高????????self.setFixedSize(400,?400)????????#?设置标题????????self.setWindowTitle('数字华容道')????????#?设置背景颜色????????self.setStyleSheet("background-color:gray;")????????self.show()if?__name__?==?'__main__':????app?=?QApplication(sys.argv)????ex?=?NumberHuaRong()????sys.exit(app.exec_())

    运行结果如下图所示:

    <figure style="margin: 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; font-size: inherit; color: inherit; line-height: inherit; text-align: center;">![image.gif](https://upload-images.jianshu.io/upload_images/12650374-c10f06bfb82d6404.gif?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    
    <figcaption style="margin: 10px 0px 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; line-height: inherit; color: rgb(153, 153, 153); font-size: 0.7em;">框架运行结果</figcaption>
    
    </figure>

    3.2 数字方块实现

    前面已经提到,用一个二维数组来存放 0~16 个数字,最终我们要转换成一个数字方块,单独创建一个类:

    class?Block(QLabel):????"""?数字方块?"""????def?__init__(self,?number):????????super().__init__()????????self.number?=?number????????self.setFixedSize(80,?80)????????#?设置字体????????font?=?QFont()????????font.setPointSize(30)????????font.setBold(True)????????self.setFont(font)????????#?设置字体颜色????????pa?=?QPalette()????????pa.setColor(QPalette.WindowText,?Qt.white)????????self.setPalette(pa)????????#?设置文字位置????????self.setAlignment(Qt.AlignCenter)????????#?设置背景颜色\圆角和文本内容????????if?self.number?==?0:????????????self.setStyleSheet("background-color:white;border-radius:10px;")????????else:????????????self.setStyleSheet("background-color:red;border-radius:10px;")????????????self.setText(str(self.number))

    该类继承自?QLablel?,初始化需要传入一个参数?number?,number就是数字方块上显示的数字。

    3.3 将数字转换成方块添加到布局

    布局采用?QGridLayout?创建一个 4X4 的?self.gltMain,将16个 Block 添加到 self.gltMain:

    def?updatePanel(self):????for?row?in?range(4):????????for?column?in?range(4):????????????self.gltMain.addWidget(Block(self.blocks[row][column]),?row,?column)????self.setLayout(self.gltMain)

    3.4 初始化布局

    初始化布局包括随机数据的产生与将数字转换成方块添加到布局

    #?初始化布局????def?onInit(self):????????#?产生随机数组,0?代表空的位置????????arr?=?range(16)????????self.numbers?=?random.sample(arr,?16)????????#?将数字方块添加到布局????????for?row?in?range(4):????????????self.blocks.append([])????????????for?column?in?range(4):????????????????temp?=?self.numbers[row?*?4?+?column]????????????????if?temp?==?0:????????????????????self.zero_row?=?row????????????????????self.zero_column?=?column????????????????self.blocks[row].append(temp)????????????????self.gltMain.addWidget(Block(temp),?row,?column)

    3.5 按键检测

    QWidget 有一个?keyPressEvent?事件句柄,我们只需要重新实现该方法即可:

    #?检测按键def?keyPressEvent(self,?event):????key?=?event.key()????if(key?==?Qt.Key_Up?or?key?==?Qt.Key_W):????????self.move(Direction.UP)????if(key?==?Qt.Key_Down?or?key?==?Qt.Key_S):????????self.move(Direction.DOWN)????if(key?==?Qt.Key_Left?or?key?==?Qt.Key_A):????????self.move(Direction.LEFT)????if(key?==?Qt.Key_Right?or?key?==?Qt.Key_D):????????self.move(Direction.RIGHT)????self.updatePanel()????if?self.checkResult():????????if?QMessageBox.Ok?==?QMessageBox.information(self,?'挑战结果',?'恭喜您完成挑战!'):????????????self.onInit()

    按键检测到按键按下之后判断该键值是否为 “↑↓←→”或“WSAD”,并作出相应的移动(move),移动之后刷新布局(updatePannel),最后检测是否完成挑战(checkResult),如果完成挑战,弹出提示框。如果点击了?OK?按钮,游戏重新开始(onInit)。

    3.6 试玩测试

    至此,所有功能模块介绍完毕,不要着急看完整代码,我们先运行一下程序看是否还有 Bugs。

    玩了几局之后发现,并不是所有的局都能都还原,如下面这种情况:

    <figure style="margin: 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; font-size: inherit; color: inherit; line-height: inherit; text-align: center;">![image.gif](https://upload-images.jianshu.io/upload_images/12650374-1fbff437781d0850.gif?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    
    <figcaption style="margin: 10px 0px 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; line-height: inherit; color: rgb(153, 153, 153); font-size: 0.7em;">无法还原</figcaption>
    
    </figure>

    如图所示,14?和?15?方块位置反了,无论如何也还原不聊了,这种情况是随机出现的。到底是怎么回事呢?经过一番上网搜索,确实如果只有两个数字的位置反了,无论如何也还原不了的。那这是由什么造成的呢?还记得我们的二维数组是怎么产生的吧,随机的,也就是说可能会随机到无法还原的情况。

    如何避免这种情况呢?初始化数组时,所有的位置都是正确的数字,然后使用 move 进行移动打乱。

    3.7 改进完善

    由于前面已经将各个功能模块单独写成了方法,因此我们只需修改?onInit?方法即可。

    #?初始化布局def?onInit(self):????#?产生顺序数组????self.numbers?=?list(range(1,?16))????self.numbers.append(0)????#?将数字添加到二维数组????for?row?in?range(4):????????self.blocks.append([])????????for?column?in?range(4):????????????temp?=?self.numbers[row?*?4?+?column]????????????if?temp?==?0:????????????????self.zero_row?=?row????????????????self.zero_column?=?column????????????self.blocks[row].append(temp)????#?打乱数组????for?i?in?range(500):????????random_num?=?random.randint(0,?3)????????self.move(Direction(random_num))????self.updatePanel()

    先生成一个顺序数组,里面保存着[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0],然后转为二维数组 blocks,再后随即移动500次,最后添加到布局。

    4、完整代码

    import?sysimport?randomfrom?enum?import?IntEnumfrom?PyQt5.QtWidgets?import?QLabel,?QWidget,?QApplication,?QGridLayout,?QMessageBoxfrom?PyQt5.QtGui?import?QFont,?QPalettefrom?PyQt5.QtCore?import?Qt#?用枚举类表示方向class?Direction(IntEnum):????UP?=?0????DOWN?=?1????LEFT?=?2????RIGHT?=?3class?NumberHuaRong(QWidget):????"""?华容道主体?"""????def?__init__(self):????????super().__init__()????????self.blocks?=?[]????????self.zero_row?=?0????????self.zero_column?=?0????????self.gltMain?=?QGridLayout()????????self.initUI()????def?initUI(self):??????????????#?设置方块间隔????????self.gltMain.setSpacing(10)????????self.onInit()????????#?设置布局????????self.setLayout(self.gltMain)????????#?设置宽和高????????self.setFixedSize(400,?400)????????#?设置标题????????self.setWindowTitle('数字华容道')????????#?设置背景颜色????????self.setStyleSheet("background-color:gray;")????????self.show()????#?初始化布局????def?onInit(self):????????#?产生顺序数组????????self.numbers?=?list(range(1,?16))????????self.numbers.append(0)????????#?将数字添加到二维数组????????for?row?in?range(4):????????????self.blocks.append([])????????????for?column?in?range(4):????????????????temp?=?self.numbers[row?*?4?+?column]????????????????if?temp?==?0:????????????????????self.zero_row?=?row????????????????????self.zero_column?=?column????????????????self.blocks[row].append(temp)????????#?打乱数组????????for?i?in?range(500):????????????random_num?=?random.randint(0,?3)????????????self.move(Direction(random_num))????????self.updatePanel()????#?检测按键????def?keyPressEvent(self,?event):????????key?=?event.key()????????if(key?==?Qt.Key_Up?or?key?==?Qt.Key_W):????????????self.move(Direction.UP)????????if(key?==?Qt.Key_Down?or?key?==?Qt.Key_S):????????????self.move(Direction.DOWN)????????if(key?==?Qt.Key_Left?or?key?==?Qt.Key_A):????????????self.move(Direction.LEFT)????????if(key?==?Qt.Key_Right?or?key?==?Qt.Key_D):????????????self.move(Direction.RIGHT)????????self.updatePanel()????????if?self.checkResult():????????????if?QMessageBox.Ok?==?QMessageBox.information(self,?'挑战结果',?'恭喜您完成挑战!'):????????????????self.onInit()????#?方块移动算法????def?move(self,?direction):????????if(direction?==?Direction.UP):?#?上????????????if?self.zero_row?!=?3:????????????????self.blocks[self.zero_row][self.zero_column]?=?self.blocks[self.zero_row?+?1][self.zero_column]????????????????self.blocks[self.zero_row?+?1][self.zero_column]?=?0????????????????self.zero_row?+=?1????????if(direction?==?Direction.DOWN):?#?下????????????if?self.zero_row?!=?0:????????????????self.blocks[self.zero_row][self.zero_column]?=?self.blocks[self.zero_row?-?1][self.zero_column]????????????????self.blocks[self.zero_row?-?1][self.zero_column]?=?0????????????????self.zero_row?-=?1????????if(direction?==?Direction.LEFT):?#?左????????????if?self.zero_column?!=?3:????????????????self.blocks[self.zero_row][self.zero_column]?=?self.blocks[self.zero_row][self.zero_column?+?1]????????????????self.blocks[self.zero_row][self.zero_column?+?1]?=?0????????????????self.zero_column?+=?1????????if(direction?==?Direction.RIGHT):?#?右????????????if?self.zero_column?!=?0:????????????????self.blocks[self.zero_row][self.zero_column]?=?self.blocks[self.zero_row][self.zero_column?-?1]????????????????self.blocks[self.zero_row][self.zero_column?-?1]?=?0????????????????self.zero_column?-=?1????def?updatePanel(self):????????for?row?in?range(4):????????????for?column?in?range(4):????????????????self.gltMain.addWidget(Block(self.blocks[row][column]),?row,?column)????????self.setLayout(self.gltMain)????#?检测是否完成????def?checkResult(self):????????#?先检测最右下角是否为0????????if?self.blocks[3][3]?!=?0:????????????return?False????????for?row?in?range(4):????????????for?column?in?range(4):????????????????#?运行到此处说名最右下角已经为0,pass即可????????????????if?row?==?3?and?column?==?3:????????????????????pass????????????????#值是否对应????????????????elif?self.blocks[row][column]?!=?row?*?4?+?column?+?1:????????????????????return?False????????return?Trueclass?Block(QLabel):????"""?数字方块?"""????def?__init__(self,?number):????????super().__init__()????????self.number?=?number????????self.setFixedSize(80,?80)????????#?设置字体????????font?=?QFont()????????font.setPointSize(30)????????font.setBold(True)????????self.setFont(font)????????#?设置字体颜色????????pa?=?QPalette()????????pa.setColor(QPalette.WindowText,?Qt.white)????????self.setPalette(pa)????????#?设置文字位置????????self.setAlignment(Qt.AlignCenter)????????#?设置背景颜色\圆角和文本内容????????if?self.number?==?0:????????????self.setStyleSheet("background-color:white;border-radius:10px;")????????else:????????????self.setStyleSheet("background-color:red;border-radius:10px;")????????????self.setText(str(self.number))if?__name__?==?'__main__':????app?=?QApplication(sys.argv)????ex?=?NumberHuaRong()????sys.exit(app.exec_())

    5、总结

    在做的过程中遇到最大的坑就是随机数组导致无法还原。另外在做这个游戏的时候我已经找到还原规律了,这样在测试的时候可以做完完整测试,否则根本无法测试都挑战成功那一步。

    另外要对《最强大脑》做一下吐槽:这个项目设置的不太好,玩过的人会很快,没有玩过的找规律的时间就很长。我在手机上玩4X4的最快还原用了 33 秒,对于该节目的冠军(即便是玩过)很是敬仰。

    下面是本游戏的试玩视频:

    <iframe frameborder="0" width="677" height="380.8125" allow="autoplay; fullscreen" allowfullscreen="true" src="https://v.qq.com/txp/iframe/player.html?origin=https%3A%2F%2Fmp.weixin.qq.com&amp;vid=c1344uq0i30&amp;autoplay=false&amp;full=true&amp;show1080p=false" style="margin: 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important;"></iframe>

    由于文件较大,在公众号后台回复 “数字华容道” 即可获取本文所有代码,包括:算法、框架搭建、无法还原的完整代码和最终版的完整代码。

    image

    话不多说,资源共享,直接上图:

    还有很多包括视频我就不一一截图了,需要这些资料的可以先关注小编,转发评论,私信小编晓雯

    分享到:
    我来说两句
    facelist
    您需要登录后才可以评论 登录 | 立即注册
    所有评论(0)
    关闭

    每日头条

    通过邮件订阅最新 澳门永利m5900cc 信息
    上一条 /4 下一条
    联系我们
    关闭
    合作电话:
    13802416937
    Email:
    435399051@qq.com
    商务市场合作/投稿
    问题反馈及帮助
    联系我们

    广告投放| Github|申请友链|手机版|澳门永利m5900cc ( 澳门永利m5900cc )

    返回顶部