python实现2048游戏项目

本文详细介绍了使用Python实现2048游戏的过程,涵盖了源代码、关键知识点如解包、主函数、PyCharm快捷键、range()函数等。在算法与逻辑部分,讲解了减少重复、填补随机数的逻辑以及矩阵旋转等操作。同时,文章还讨论了函数return、循环break的疑问,并总结了学习路线和反思,包括对基础不牢固的反思和未来的学习计划。此外,还提及了Notepad的快捷键和编写代码时需要注意的安全问题。

 

目录 

一.源代码

二.知识记录

2.1 解包的知识

2.2 Python“主函数”标志: if __name__ == "__main__"

2.3 pytcharm 快捷键

2.4.Python3 range()函数

2.5 退出程序

2.6 传入表格的每一行,“解包”,

2.7 Python缩进格式很严格 

2.8 关于空和空格

三.算法/逻辑

3.1 减少重复,边查找就边正好把查找的空位的位置传入白板中 

3.2 填补一个随机数逻辑

3.3 存放空位坐标的表格的应用

3.4 关于左移操作的函数

3.5 矩阵旋转,关于将左移操作用于下,上,右移

3.6 [2,2,2]=>[4,2] 前后元素比较的算法

四.疑问

4.1 函数 return

4.2 循环 break

五.总结

5.1学习路线

5.2反思

六.拓展

6.1.notepad 快捷键

6.2 写代码一个危险例子


 

一.源代码

#打印棋盘
import random 

class Game():
    def __init__(self):
        self.score = 0
        self.list = [
            ['','','',''],
            ['','','',''],
            ['','','',''],
            ['','','','']
        ]
        #白板 存储坐标
        self.whiteBoard = []
    def restart(self):
        self.list = [
            ['','','',''],
            ['','','',''],
            ['','','',''],
            ['','','','']
        ]
        while True:
            t1 = [random.randrange(len(self.list)),random.randrange(len(self.list[0]))]
            t2 = [random.randrange(len(self.list)),random.randrange(len(self.list[0]))]
            if t1!= t2:
                break
        self.list[t1[0]][t1[1]] = random.randrange(2, 5, 2)
        self.list[t2[0]][t2[1]] = random.randrange(2, 5, 2)
        self.print_board()
  
                    
    def print_board(self):
        print("""
score:{}
+-----+-----+-----+-----+
|{:^5}+{:^5}+{:^5}+{:^5}+
+-----+-----+-----+-----+
|{:^5}+{:^5}+{:^5}+{:^5}+
+-----+-----+-----+-----+
|{:^5}+{:^5}+{:^5}+{:^5}+
+-----+-----+-----+-----+
|{:^5}+{:^5}+{:^5}+{:^5}+
+-----+-----+-----+-----+
w(up), s(down), a(left), d(right)
q(quit), r(restart)
""".format(self.score, *self.list[0],
                       *self.list[1],
                       *self.list[2],
                       *self.list[3]))
                       
    #判断输/赢/继续游戏
    def state(self):
        flag = 2
        for x in range(len(self.list)):
            for y in range(len(self.list[x])):
                if self.list[x][y] == 2048:
                    flag = 1 #win
                    break
                
                if self.list[x][y] == "":
                    self.whiteBoard.append([x,y])
                    flag = 0 #continue 
        
        return flag
        
    def left(self):
        #删除空格(2, ,2, )=>(2,2, , )(4, , , )
        #传入表格每一行 [2," ",2," "]
        for i in range(len(self.list)):
            temp=[]
            new_row=[]
            #遍历这行的每个元素,并把非空值传出
            for item in self.list[i]:
                if item:
                    temp.append(item)

            #得到一个temp[2,2]
            if len(temp) <1:
                continue
            
            elif len(temp) <2:
                new_row.append(temp[0])
                
            else:
                Flag = True
                for j in range(len(temp)):
                    if Flag:
                        if j+1<len(temp) and temp[j] == temp[j+1]:
                            new_row.append(temp[j]*2)
                            Flag = False
                        else:
                            new_row.append(temp[j])
                    else:
                        Flag = True        
                #得到new_row [4]
            y = len(self.list)-(len(new_row))
            #填补空格
            for x in range(y):
                new_row.append("")
            #传入表格当前行 [2," ",2," "]=>[4," "," "," "]
            self.list[i] = new_row
        
    def turn_right(self):
        self.list = [list(x[::-1])for x in zip(*self.list)]       
     
    def turn_left(self):
        for i in range(3):
            self.turn_right()  
   
        
    # 随机填补一个随机数    
    def add_randNumber(self):
        p = self.whiteBoard.pop(random.randrange(len(self.whiteBoard)))
        #再随机值
        self.list[p[0]][p[1]] = random.randrange(2, 5, 2)   
        
        self.print_board()       
    
    #开始游戏 
    def start_game(self):
    
        self.restart()
        
        #开始游戏,输入指令
        while True:
            code = input("请输入指令>>>:")
            #向上?
            if code == "w":
                self.turn_left()
                self.left()
                self.turn_right()
                
            #向下? 
            elif code == "s":
                self.turn_right()
                self.left()
                self.turn_left()
              
            #向左? 
            elif code == "a":
                self.left()
                
                
            #向右?     
            elif code == "d":
                self.turn_left()
                self.turn_left()
                self.left()
                self.turn_right()
                self.turn_right()
            
            
            #退出
            elif code == "q":
                exit("退出")
            
            #重启        
            elif code == "r":  
                self.restart()
                
            #输入有误
            else:
                print("请输入正确的指令!")
                
            #判断是否赢了,打印赢了 pass跳出这个游戏状态
            #判断是否输了,打印输了 pass跳出这个游戏状态 
            
            if self.state() == 1:
                print("You win!")
                break
                
            if self.state() == 2:
                print("You fail!")
                break
                
            self.add_randNumber()
if __name__ ==  "__main__":
    game = Game()
    game.start_game()

二.知识记录

2.1 解包的知识

  • 在十六个空格处都填上2048的方法 *[2048 for x in range(16)]
  • 理解: *[ ]是解包的意思,解的是一个临时列表,临时创建并循环传入16次 for x in range(16),每次都是2048,就在前面加上2048
  • 代码:
 print("""
        score:{}
        +-----+-----+-----+-----+
        |{:^5}+{:^5}+{:^5}+{:^5}+
        +-----+-----+-----+-----+
        |{:^5}+{:^5}+{:^5}+{:^5}+
        +-----+-----+-----+-----+
        |{:^5}+{:^5}+{:^5}+{:^5}+
        +-----+-----+-----+-----+
        |{:^5}+{:^5}+{:^5}+{:^5}+
        +-----+-----+-----+-----+
        w(up), s(down), a(left), d(right)
        q(quit), r(restart)
        """.format(self.score, *[2048 for x in range(16)])
  • 同理,解包表格:
""".format(self.score, *self.list[0],
                       *self.list[1],
                       *self.list[2],
                       *self.list[3]))

2.2 Python“主函数”标志: if __name__ == "__main__"

if __name__ ==  "__main__":
    game = Game()
    game.start_game()
  • 相当于Java中的主程序入口,程序开始的地方

2.3 pytcharm 快捷键

  • ctrl + ←
  • 含义:跳到函数定义的地方

2.4.Python3 range()函数

2.5 退出程序

 if input("code") == "q":
     exit("退出")
                
  • 结果:1.退出2.显示字符“exit”

2.6 传入表格的每一行,“解包”,

  • 错误写法:*(self.list[0])
print("""
        score:{}
        +-----+-----+-----+-----+
        |{^5} +{^5} +{^5} +{^5} +
        +-----+-----+-----+-----+
        |{^5} +{^5} +{^5} +{^5} +
        +-----+-----+-----+-----+
        |{^5} +{^5} +{^5} +{^5} +
        +-----+-----+-----+-----+
        |{^5} +{^5} +{^5} +{^5} +
        +-----+-----+-----+-----+
        w(up), s(down), a(left), d(right)
        q(quit), r(restart)
        """.format(self.score, 
                    *self.list[0],
                    *self.list[1],
                    *self.list[2],
                    *self.list[3]))

2.7 Python缩进格式很严格 

  • 图中错误:第八行,莫名缩进,报错: unexpected indent

2.8 关于空和空格

if item:
if item != "":
if item != " ":

  • 前两个一个意思,第三个是看那个值是不是空,空格也算一个值

 

 

三.算法/逻辑

3.1 减少重复,边查找就边正好把查找的空位的位置传入白板中 

  • 可用于循环查找数据库等等
def is_win(self):
        self.list = []
        for x in len(self.list):
            for y in len(self.list[x])):
                if self.list[x][y] == 2048:
                    return True #win
                if self.list[x][y] == "":
                    self.list.append((x,y))
                    
        return False #continu

 

3.2 填补一个随机数逻辑

# 随机填补一个随机数    
    def add_randNumber(self):
        if self.whiteBoard:
        #先随机位置,并且删除
            p = self.whiteBoard.pop(random.randrange(len(self.whiteBoard)))
            #再随机值
            self.list[p[0]][p[1]] = random.randrange(2, 5, 2)   
            self.print_board() 
  • pop()函数删除掉某位置的函数,并且返回那个位置
  • p[0] p[1]就是指删掉的位置
  • random.range(2, 5, 2)从2开始,不包括5,步长为2

 

3.3 存放空位坐标的表格的应用

def add_whiteBoard(self):
        for x in range(len(self.list)):
            for y in range(len(self.list[0])):
                self.whiteBoard.append([x,y])
  • 错误:犯了一个大的逻辑错误,空格位是不断变化的,所以必须每轮操作完都要遍历一次,然后把white_board重置,而我写的是一开始white_board把所有的位置传进去,从此以后就一直在删除元素,不会再添加,这不符合游戏逻辑。
  • 改正:在判断赢了或输了的时候会遍历元素,尤其是输了的时候我们会寻找空位,一旦找到一个空位,我们就加到white_board里面

 

3.4 关于左移操作的函数

  • 代码
def left(self):
        #删除空格(2, ,2, )=>(2,2, , )(4, , , )
        #传入表格每一行 [2," ",2," "]
        for i in range(len(self.list)):
            temp=[]
            new_row=[]
            #遍历这行的每个元素,并把非空值传出
            for item in self.list[i]:
                if item:
                    temp.append(item)
            
            Flag = True
            #得到一个temp[2,2]
            for j in range(len(temp)):
                if Flag:
                    if temp[j] == temp[j+1]:
                        new_row.append(temp[j]*2)
                        Flag = False
                    else:
                        new_row.append(temp[j])
                else:
                    Flag = True        
            #得到new_row [4]
            y = len(self.list)-(len(new_row))
            #填补空格
            for x in range(y):
                new_row.append(" ")
            #传入表格当前行 [2," ",2," "]=>[4," "," "," "]
            self.list[i] = new_row
def move_left(self):
    for i in range(len(self.board_list)):
        self.board_list[i] = self.row_left_oper(self.board_list[i])
  • 思路:第一个是我自己写的,用了一个函数实现了传入一个list,变成左移后的list,第二个是大佬用的方法的框架,他把每一行的处理作为一个函数,然后再建立一个函数传入每一行,再处理
  • 反思1:关于left操作,第二个这样定义函数比较清晰,不要一来就把一个函数写死,每个函数最好专注一个功能,也容易改错。
  • 反思2:我们只需要专注一行,最后再设计这样一个函数,把每一行传进去,处理一遍,得到新的list 而我的写法是用一个函数,一开始就传入一个list,然后再分别拆分,再分别处理,再替换list,显得比较乱

 

3.5 矩阵旋转,关于将左移操作用于下,上,右移

self.list = [list(x[::-1])for x in zip(*self.list)]
def turn_right(self):
        self.list = [list(x[::-1])for x in zip(*self.list)]       
     
def turn_left(self)
        for i in range(3):
            self.turn_right()  

3.6 [2,2,2]=>[4,2] 前后元素比较的算法

for j in range(len(temp)):
    if Flag:
        if j+1<len(temp) and temp[j] == temp[j+1]:
            new_row.append(temp[j]*2)
            Flag = False
        else:
            new_row.append(temp[j])
    else:
        Flag = True        
  • 注意1:第一行是range(len(temp))而不是range(len(temp)-1) 
  • 注意2:没有加 j+1<len(temp) ,出现 index out of range 数组越界
  • 解释:因为我们要输出最后一个元素,但是按照我们的循环,必须当j是指向最后一个元素,才可能输出它,所以像注意1说的我们在一开始是for j in range(len(temp)):而不是for j in range(len(temp)-1):;但是当j真的指向最后一个元素,它就必须和j+1这个元素比较,但显然j已经是最后一个元素,j+1不存在,所以这里返回了一个错误 index out of range,数组越界。所以我们在最后要加上一个if j+1<len(temp) and temp[j] == temp[j+1]: ,如果j+1=len(temp),它就会进入else模块,直接输出j对应元素,而不用与下一个元素比较

 

 

四.疑问

4.1 函数 return

  • 代码:
 def state(self):
        for x in range(len(self.list)):
            for y in range(len(self.list[x])):
                if self.list[x][y] == 2048:
                    return "W"  #win
                if self.list[x][y] == "":
                    return "C"  #fail 
        return "F"  #continue 

4.2 循环 break

def state(self):
        flag = 2
        for x in range(len(self.list)):
            for y in range(len(self.list[x])):
                if self.list[x][y] == 2048:
                    flag = 1 #win
                    break
                
                if self.list[x][y] == "":
                    self.whiteBoard.append([x,y])
                    flag = 0 #continue 
        
        return flag
  • break到底跳出哪个循环?

五.总结

5.1学习路线

5.2反思

  • 欠缺的基础:
  • 不会设置断点,for循环等基础知识不牢固,list tuple的用法,类与对象的知识等
  • 未来:
  • 算法——牛客网刷题,经典算法书,Leecode刷题
  • 读书——每次做完两到三个项目可以读一些书,巩固基础 详见https://blog.youkuaiyun.com/Programmer_ch/article/details/89294550或网站收藏夹——电子书
  • 多做项目——有功力大涨的赶jio 

  • 路漫漫其修远兮 吾将上下而求索 加油

六.拓展

6.1.notepad 快捷键

Ctrl-Q添加/删除注释
Ctrl-Shift-Q区块添加/删除注释
Ctrl-D   复制当前行至下方,或者复制选中区域至其后
Shift-Tab (selection of one or more full lines)    删除位置之前的Tab

 

6.2 写代码一个危险例子

  • A dangerous example
  • Let’s say we want to write a function to transcode a user-specified video file into a different format. We ask the user where to find the file on disk and then run it through ffmpeg to transcode it. What could go wrong?
import subprocess

def transcode_file():
    filename = raw_input('Please provide the path for the file to transcode: ')
    command = 'ffmpeg -i "{source}" output_file.mpg'.format(source=filename)
    subprocess.call(command, shell=True)  # a bad idea!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值