2.2 Python“主函数”标志: if __name__ == "__main__"
3.1 减少重复,边查找就边正好把查找的空位的位置传入白板中
一.源代码
#打印棋盘
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()函数
- 翻译:范围
- 菜鸟教程 Python range() 函数用法 http://www.runoob.com/python/python-func-range.html
- python range() 函数可创建一个整数列表,一般用在 for 循环中。
- 菜鸟教程 Python for循环 http://www.runoob.com/python3/python3-loop.html
- Python for循环可以遍历任何序列的项目,如一个列表或者一个字符串。
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()
- x[::-1] 用到切片的知识
- ? 廖雪峰网站——切片https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431756919644a792ee4ead724ef7afab3f7f771b04f5000
- 第一个代码块是矩阵右转
- 第二个代码块表示左转相当于右转三次
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
- 如果两个if都满足了,程序在哪里终止?是否return一个值后函数就结束了不再执行后面的内容了?还是后面的return会把前面的return推翻?
-
答案:https://blog.youkuaiyun.com/lanchunhui/article/details/51586868这篇对return的理解很好的解释了这个问题
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学习路线
- 哔哩哔哩视频——自己敲代码——记录博客
- 视频网站:https://www.bilibili.com/video/av35223933?from=search&seid=16856379516999773770
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!
- What if someone provides a file with a name like
"; rm -rf /? If the host machine runs the Python process as a privileged user, that could delete all of the files on the machine. That’s bad. - 转自 https://www.kevinlondon.com/2015/07/26/dangerous-python-functions.html
本文详细介绍了使用Python实现2048游戏的过程,涵盖了源代码、关键知识点如解包、主函数、PyCharm快捷键、range()函数等。在算法与逻辑部分,讲解了减少重复、填补随机数的逻辑以及矩阵旋转等操作。同时,文章还讨论了函数return、循环break的疑问,并总结了学习路线和反思,包括对基础不牢固的反思和未来的学习计划。此外,还提及了Notepad的快捷键和编写代码时需要注意的安全问题。

1万+

被折叠的 条评论
为什么被折叠?



