python 小游戏《2048》字符版非图形界面

参考链接: 闲谈2048小游戏和数组的旋转及翻转和转置

目录

2048 

一、方阵类

二、随机插入1或2

三、 合并和递增

四、 判断和移动

五、 键盘控制

完整源代码

玩法过程


2048 

上回说到2048小游戏中数组的各种旋转、翻转的方法,就是为代码编程作准备的;有了这些再就加上二维数组各行列上元素的合并、能否被合并的判断、成功失败的判断等等;以及再加上键盘按键的控制,小游戏就基本完成了。

一、方阵类

方阵就是高宽相同的矩阵,2048用方阵就行了,写代码也省事一点,方阵的类如下:

>>> from random import sample
>>> class Matrix:
...     def __init__(self, order=4):
...         self.order = order
...         self.matrix = self.new()
...     def __repr__(self):
...         m, n = [], len(str(2**max(sum(self.matrix,[]))))
...         for mat in self.matrix:
...             m.append(', '.join(f'{2**x if x else 0:>{n}}' for x in mat))
...         return '],\n ['.join(m).join(['[[',']]'])
...     def new(self):
...         n = self.order
...         m = sample([0]*(n*n-2)+sample([0,1,1],2),n*n)
...         return  [m[i*n:i*n+n] for i in range(n)]
... 
...     
>>> Matrix()
[[0, 0, 2, 0],
 [0, 0, 0, 0],
 [0, 0, 2, 0],
 [0, 0, 0, 0]]
>>> Matrix()
[[0, 0, 0, 0],
 [0, 0, 0, 0],
 [0, 0, 2, 0],
 [0, 0, 0, 0]]

在方阵中随机产生1~2个1,sample([0,1,1],2) 生成的1个还是2个,比例为2:1;

在__repr__方法中显示时,这些1作为2的指数,所以显示为2^1=2。

二、随机插入数字

    def insert(self):
        n = self.order
        m = [i for i,n in enumerate(sum(self.matrix,[])) if not n]
        if m:
            i = sample(m, 1)[0]
            self.matrix[i//n][i%n] = sum(sample([1,1,1,2],1))

或者:

    def insert(self):
        n = self.order
        m = [(i,j) for j in range(n) for i in range(n) if not self.matrix[i][j]]
        if m:
            i, j = sample(m, 1)[0]
            self.matrix[i][j] = sum(sample([1,1,1,2],1))

为加快数字的拼合速度,从5队开始,除了只插入1和2,可以考虑加入更大的数字:

self.matrix[i][j] = sum(sample([1,1,1,2]*3+([1,2,3,3]+[i for i in range(n+4,n,-1)] if n>4 else []),1))

如 n = 5 时,拟插入的各数字比例为:

>>> n = 5
>>> t = [1,1,1,2]*3+[1,2,3,3]+[i for i in range(n+4,n,-1)]
>>> for i in set(t):
...     print([i,t.count(i)/20])
... 
...     
[1, 0.5]
[2, 0.2]
[3, 0.1]
[6, 0.05]
[7, 0.05]
[8, 0.05]
[9, 0.05] 

三、 合并和递增

   ......     
   for i,array in enumerate(self.matrix):
            self.matrix[i] = Matrix.update(array)
    ......
    def update(array):
        split = lambda a: [_ for _ in a if _]+[_ for _ in a if not _]
        array = split(array)
        for i,a in enumerate(array):
            if i and a and a==array[i-1]:
                array[i-1] += 1
                array[i] = 0
        return split(array)

四、 判断和移动

略……写得有点复杂,可以到完整代码中阅读。

五、 键盘控制

引入keyboard库控制键盘,示例如下:

import keyboard  def keys0():  print("Left key pressed")  def keys1():  print("Right key pressed")  def keys2():  print("Up key pressed")  def keys3():  print("Down key pressed")  def restart():  print("Enter key pressed")  # 添加热键  
keyboard.add_hotkey('left', keys0)  
keyboard.add_hotkey('right', keys1)  
keyboard.add_hotkey('up', keys2)  
keyboard.add_hotkey('down', keys3)  
keyboard.add_hotkey('enter', restart)  # 等待用户按下esc键  
print("Waiting for ESC to exit...")  
keyboard.wait('esc')  # 在这里移除所有热键  
print("Removing all hotkeys...")  
keyboard.unhook_all_hotkeys()

Waiting for ESC to exit...
Left key pressed
Right key pressed
Up key pressed
Down key pressed
Enter key pressed
Removing all hotkeys...
>>> 

注:最后一行代码keyboard.unhook_all_hotkeys()很关键,一定都有否则即使按了ESC键退出程序,热键还是驻留在内存里,键盘还会响应keyboard.add_hotkey()添加的热键。


完整源代码

import keyboard
from random import sampleclass Matrix:def __init__(self, order=4):self.over = Falseself.order = orderself.matrix = self.new()self.victory = Falsedef __repr__(self):m, n = [], len(str(2**max(sum(self.matrix,[]))))for mat in self.matrix:m.append(', '.join(f'{2**x if x else 0:>{n}}' for x in mat))return '],\n ['.join(m).join(['[[',']]'])def new(self):n = self.orderm = sample([0]*(n*n-2)+sample([0,1,1],2),n*n)return  [m[i*n:i*n+n] for i in range(n)]def show(self):if self.over or self.victory:print('Enter to restart...')else:print(self)print()def insert(self):n = self.orderm = [(i,j) for j in range(n) for i in range(n) if not self.matrix[i][j]]if m:i, j = sample(m, 1)[0]self.matrix[i][j] = sum(sample([1,1,1,2],1))def full(self):return all(sum(self.matrix,[]))def move(self, direction=0):if self.over or self.victory: returndirection %= 4if direction == 0:  #leftif self.cannotmove(0): returnelif direction == 1:  #rightif self.cannotmove(1): returnself.matrix = self.flipH()elif direction == 2:  #upif self.cannotmove(2): returnself.matrix = self.rotL()elif direction == 3:  #downif self.cannotmove(3): returnself.matrix = self.rotR()for i,array in enumerate(self.matrix):self.matrix[i] = Matrix.update(array)if direction == 1:self.matrix = self.flipH()elif direction == 2:self.matrix = self.rotR()elif direction == 3:self.matrix = self.rotL()indexmax = max(sum(self.matrix,[]))if self.order==2 and indexmax==4 or self.order==3 and indexmax==7 or indexmax==self.order+7:self.victory = Trueprint(self)print('Win! Enter to restart...')returnself.insert()self.over = self.cannotmove()if self.over:print(self)print('Gave over!')def cannotmove(self, direction = 4):m, n = self.matrix, self.rotR()p, q = self.rotL(), self.flipH()if direction==0:return all(n[0]) and Matrix.cannotupdate(m)elif direction==1:return all(n[-1]) and Matrix.cannotupdate(q)elif direction==2:return all(m[0]) and Matrix.cannotupdate(n)elif direction==3:return all(m[-1]) and Matrix.cannotupdate(p)else:return (self.full() and self.cannotmove(0) and self.cannotmove(1)and self.cannotmove(2) and self.cannotmove(3))def cannotupdate(matrix):return all([m==Matrix.update(m) for m in matrix])def update(array):split = lambda a: [_ for _ in a if _]+[_ for _ in a if not _]array = split(array)for i,a in enumerate(array):if i and a and a==array[i-1]:array[i-1] += 1array[i] = 0return split(array)def flipH(self):m, n = self.matrix, self.orderreturn [[m[i][n-j-1] for j in range(n)] for i in range(n)]def flipV(self):m, n = self.matrix, self.orderreturn [[m[n-j-1][i] for i in range(n)] for j in range(n)]def rotL(self):m, n = self.matrix, self.orderreturn [[m[j][n-i-1] for j in range(n)] for i in range(n)]def rotR(self):m, n = self.matrix, self.orderreturn [[m[n-j-1][i] for j in range(n)] for i in range(n)]def move(i):mat.move(i)mat.show()
def keys0():  move(0)
def keys1():  move(1)
def keys2():  move(2)
def keys3():  move(3)
def restart():global matif mat.victory:mat.order += 1mat = Matrix(mat.order)mat.show()if mat.over:if mat.order>3:mat.order -= 1mat = Matrix(mat.order)mat.show()if __name__ == '__main__':print("《2048小游戏》")print("上下左右前头控制方向,按ESC退出...") mat = Matrix(2)mat.show()keyboard.add_hotkey('left', keys0)keyboard.add_hotkey('right', keys1) keyboard.add_hotkey('up', keys2)keyboard.add_hotkey('down', keys3)keyboard.add_hotkey('enter', restart)keyboard.wait('esc')  # 等待用户按下esc键退出print('bye!')keyboard.unhook_all_hotkeys()  # 退出后移除所有热键

玩法过程

《2048小游戏》
上下左右前头控制方向,按ESC退出...
[[0, 0],
 [0, 2]]

[[0, 0],
 [2, 2]]

[[0, 4],
 [0, 4]]

[[0, 2],
 [0, 8]]

[[2, 2],
 [8, 0]]

[[4, 2],
 [8, 0]]

[[4, 4],
 [8, 2]]

[[8, 2],
 [8, 2]]

[[ 0,  0],
 [16,  4]]
Win! Enter to restart...
Enter to restart...
[[0, 2, 0],
 [0, 0, 2],
 [0, 0, 0]]

[[0, 0, 0],
 [2, 0, 0],
 [0, 2, 2]]

[[4, 0, 0],
 [0, 0, 2],
 [0, 0, 4]]

[[0, 2, 0],
 [0, 0, 2],
 [4, 0, 4]]

[[0, 0, 2],
 [0, 0, 2],
 [4, 0, 8]]

[[0, 0, 2],
 [0, 2, 2],
 [0, 4, 8]]

[[0, 0, 0],
 [0, 2, 4],
 [2, 4, 8]]

[[2, 0, 0],
 [2, 4, 0],
 [2, 4, 8]]

[[2, 0, 0],
 [2, 0, 0],
 [4, 8, 8]]

[[ 0,  2,  2],
 [ 0,  0,  2],
 [ 0,  4, 16]]

[[ 0,  0,  0],
 [ 2,  2,  4],
 [ 0,  4, 16]]

[[ 0,  0,  0],
 [ 0,  4,  4],
 [ 4,  4, 16]]

[[ 2,  0,  0],
 [ 0,  0,  4],
 [ 4,  8, 16]]

[[ 2,  0,  0],
 [ 2,  0,  4],
 [ 4,  8, 16]]

[[ 2,  0,  0],
 [ 4,  0,  4],
 [ 4,  8, 16]]

[[ 0,  4,  0],
 [ 2,  0,  4],
 [ 8,  8, 16]]

[[ 0,  2,  4],
 [ 0,  2,  4],
 [ 0, 16, 16]]

[[ 2,  2,  4],
 [ 0,  2,  4],
 [ 0,  0, 32]]

[[ 0,  0,  0],
 [ 2,  0,  8],
 [ 2,  4, 32]]

[[ 0,  0,  0],
 [ 2,  0,  8],
 [ 4,  4, 32]]

[[ 0,  0,  2],
 [ 0,  2,  8],
 [ 0,  8, 32]]

[[ 0,  0,  2],
 [ 0,  2,  8],
 [ 2,  8, 32]]

[[ 2,  0,  4],
 [ 2,  8,  0],
 [ 2,  8, 32]]

[[ 0,  0,  2],
 [ 2,  0,  4],
 [ 4, 16, 32]]

[[ 2,  0,  2],
 [ 2,  4,  0],
 [ 4, 16, 32]]

[[ 0,  0,  4],
 [ 4,  4,  2],
 [ 4, 16, 32]]

[[ 2,  0,  4],
 [ 0,  4,  2],
 [ 8, 16, 32]]

[[ 2,  2,  4],
 [ 0,  4,  2],
 [ 8, 16, 32]]

[[ 0,  4,  4],
 [ 2,  4,  2],
 [ 8, 16, 32]]

[[ 2,  0,  4],
 [ 2,  8,  2],
 [ 8, 16, 32]]

[[ 0,  2,  4],
 [ 4,  8,  2],
 [ 8, 16, 32]]

[[ 2,  4,  2],
 [ 4,  8,  2],
 [ 8, 16, 32]]

[[ 2,  4,  2],
 [ 4,  8,  4],
 [ 8, 16, 32]]
Gave over!
Enter to restart...

注:二阶方阵玩出16就过关,三阶方阵玩出128就过关,四阶就要到2048才能过关,五阶则要到4096才过关,六阶以上类推。演示时玩到三阶方阵就over了,如果三阶方阵过关会自动升级到四阶方阵,以此类推。


本文完

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/718356.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第十六天-爬虫selenium库

目录 1.介绍 2.使用 selenium 1.安装 2.使用 1.测试打开网页,抓取雷速体育日职乙信息 2.通过xpath查找 3.输入文本框内容 send_keys 4.点击事件 click 5.获取网页源码: 6.获取cookies 7.seleniumt提供元素定位方式:8种 8.控制浏览…

Spring Security OAuth2如何自定义返回的 Token 信息

文章目录 Spring Security OAuth2如何自定义返回的 Token 信息定制不透明令牌的信息Springsecurity-oauth2之TokenEndPoint参考Spring Security OAuth2如何自定义返回的 Token 信息 Spring Boot+OAuth2,如何自定义返回的 Token 信息? 参考URL: https://www.jianshu.com/p/b7…

【Go】指针的声明和初始化

package mainimport "fmt"func main() {// 声明一个整数变量var num int 42// 声明一个指向整数的指针变量,并将其初始化为指向整数变量的地址var ptr *int &num// 打印整数变量的值和指针变量的值(即整数变量的地址)fmt.Pri…

2024第24届中国国际工业博览会新能源与智能网联汽车展电池制造展馆

2024第24届中国国际工业博览会新能源与智能网联汽车展电池制造展馆 时间:2024年9月24日-28日 地点:国家会展中心(上海) 主办单位:工业和信息化部、国家发展和改革委员会、科学技术部、商务部、中国科学院、中国工程…

【游记】GDOI2024

GDOI2024游记 老年退役选手。NOIP 218 分,GDOI 纯纯旅游。 Day -5 周日返校,开始停课。 开始攒 rp。 Day -4 模拟赛,犯困,啥也不会。 下午打球。 Day -3 模拟赛,不困,还是啥也不会。 下午打球。 …

CSS3单独制作移动端页面布局方式(流式布局、flex弹性布局)

目录 1. 流式布局(百分比布局)2. flex弹性布局(强烈推荐)2.1 介绍2.2 Flex容器常见属性2.2.1 flex-direction2.2.2 justify-content2.2.3 flex-wrap2.2.4 align-items2.2.5 align-content2.2.6 flex-flow 2.3 Flex项目常见属性2.3.1 flex2.3.2 align-self和order 1. 流式布局(百…

银河麒麟之Workstation安装

一、VMware Workstation简介 VMware Workstation是一款由VMware公司开发的虚拟化软件,它允许用户在一台物理计算机上运行多个操作系统,并在每个操作系统中运行多个虚拟机。VMware Workstation提供了一个可视化的用户界面,使用户可以轻松创建、…

程序环境和预处理(2)

文章目录 3.2.7 命名约定 3.3 #undef3.4 命令行定义3.5 条件编译3.6 文件包含3.6.1 头文件被包含的方式3.6.2 嵌套文件包含 4. 其他预处理指令 3.2.7 命名约定 一般来讲函数和宏的使用语法很相似,所以语言本身没法帮我们区分二者,那我们平时的一个习惯是…

linux条件判断之if-then

if..then是最常见的条件判断语句,简而言之,就是当符合某个条件判断的时候,就予以进行某项工作。 1.if-then格式 if-then格式1: if [ 条件判断表达式 ];then 当条件判断表达式成立时,需执行的命令 fi if-then格式2…

Redis安全加固策略:绑定Redis监听的IP地址 修改默认端口 禁用或者重命名高危命令

Redis安全加固策略:绑定Redis监听的IP地址 & 修改默认端口 & 禁用或者重命名高危命令 1.1 绑定Redis监听的IP地址1.2 修改默认端口1.3 禁用或者重命名高危命令1.4 附:redis配置文件详解(来源于网络) 💖The Beg…

驱动开发面试复习

创建字符设备 1 创建设备号 alloc_chrdev_region 2.创建cdev cdev_init 3.添加一个 cdev,完成字符设备注册到内核 cdev_add 4.创建类 class_create 5.创建设备 device_create 1.内核空间与用户空间数据 copy_from_user 和copy_to_user 俩个函数来完成。 copy_from_user 函数…

618快递准点到达,别忘了感谢它!

进入6月以来,全国快递日均业务量飞速上涨。 虽然618大促是电商的主场,但作为不可或缺的物流环节,为了这场年中大考,快递企业在此期间也使尽浑身解数,竞相比拼配送速度。那么,为了更快的时效,快递…

uniapp 的video播放如何实现小窗功能

在页面中使用<video>组件来展示视频&#xff0c;并设置好相应的属性和事件监听&#xff1a; <video src"video.mp4" play"onVideoPlay" pause"onVideoPause"></video>在页面的data中定义一个变量来表示是否开启小窗模式&#…

【Wio Terminal】使用WiFi(3)- Wi-F的高级使用

使用WiFi&#xff08;3&#xff09; Wi-F的高级使用HTTPClient 的使用HTTP GETHTTPs GETHTTP POSTWebServerHTTP Authentication Web ServerDNSServermDNSmDNS-SDWiFiManager Wi-F的高级使用 本节介绍了一些WiFi的高级库用法&#xff0c;如HTTPClient、DNSServer和WebServer库…

美国亚利桑那州立大学宣布与OpenAI建立合作伙伴关系!

美国亚利桑那州立大学 (Arizona State University) 在官网宣布—— 将与OpenAI建立合作伙伴关系&#xff01; 该校也成为了第一个与OpenAI合作的高等教育机构。 来源&#xff1a;亚利桑那州立大学官网 亚利桑那州立大学校长表示&#xff1a; “我们认识到人工智能系统将持续…

高并发IO底层原理浅析(四)

Java NIO中的Selector&#xff08;选择器&#xff09;是一个用于检测多个非阻塞通道&#xff08;Channel&#xff09;是否准备就绪进行读写操作的关键组件&#xff0c;它实现了I/O多路复用技术。在单个线程中&#xff0c;Selector可以监听和管理多个Channel上的事件&#xff0c…

Redis安全加固策略:配置文件权限设置 配置本地日志存储目录 连接超时时间限制

Redis安全加固策略&#xff1a;配置文件权限设置 & 配置本地日志存储目录 & 连接超时时间限制 1.1 配置文件权限设置1.2 配置本地日志存储目录1.3 连接超时时间限制 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 1.1 配置文件权限…

如何理解template<size_t N>?

template<size_t N> 是C中的模板参数&#xff0c;用于定一个非类型参数的值。它可以在编译时确定&#xff0c;并且可以在编译时进行计算和使用。 例如&#xff0c;我们可以定义一个模板函数&#xff0c;接受一个大小为N的数组作为参数&#xff1a; template<size_t …

Qt/事件分发器/事件过滤器

事件分发器 //事件分发器bool event(QEvent* e); //事件分发器&#xff1a;&#xff1a;用途 分发事件 bool MyLabel::event(QEvent* e) {if(e->type() QEvent::MouseButtonPress){//如果是鼠标摁下 拦截事件 不向下分发QMouseEvent* ev static_cast<QMouseEvent*>…

Qt-Qss 样式表属性大全

目录 前言 源码文件信息 QSS属性大全 1.控件常用的属性 2.控件常用属性值 3.控件常用状态 4.其他 前言 相信很大一部分开发者真的被Qt样式表的属性搞挺头痛的&#xff01; 一方面Qss的示例Demo太过简单&#xff0c; 另一方面&#xff0c;Qss的所有属性在Qt的官方文…