跟着实验楼学习了2048的Python实现,先丢个地址 200行Python代码实现2048
我接触Python时间不长,只了解一些基本的语法和容器,在学习的过程中遇到不少问题,这里做一个记录。
curses库(windows系统)
本来想着在搞明白之前先运行代码看看效果,结果光这里的报错就折腾了我好半天。查了下才知道curses库不支持windows系统,需要使用一个 unofficial curses来代替Python自带的curses库,也就是whl包。unofficial curses ←这里下载,如果显示404,换谷歌浏览器!!!我当时用的是qq浏览器,404到怀疑人生= = 下载完以后,在Terminal中先用cd进入到刚下载的位置(最好改下默认保存路径,把它下载到2048的项目文件夹),输入pip install+带后缀的文件名,回车,大部分人到这一步就完事了。
但我可不是一般人,我是踩雷大师。
说一说不同报错的解决方案吧。
1.not a supported wheel on this platform
多半是版本下错了。链接中有好多版本,可以根据自己Python的版本和系统来确定。如果还是报错的话,开一个Python文件运行这段话检查下信息。
import pip
print(pip.pep425tags.get_supported())
如果显示 module 'pip' has no attribute 'pep425tags',改成这个
import pip._internal
print(pip._internal.pep425tags.get_supported())
以下是我的输出。现在可以根据元组组合挑选对应版本了。比如说我就应该下载 curses-2.2+utf8-cp36-cp36m-win_amd64.whl
[('cp36', 'cp36m', 'win_amd64'), ('cp36', 'none', 'win_amd64'), ('py3', 'none', 'win_amd64'), ('cp36', 'none', 'any'), ('cp3', 'none', 'any'), ('py36', 'none', 'any'), ('py3', 'none', 'any'), ('py35', 'none', 'any'), ('py34', 'none', 'any'), ('py33', 'none', 'any'), ('py32', 'none', 'any'), ('py31', 'none', 'any'), ('py30', 'none', 'any')]
2. You should consider upgrading via the 'python -m pip install --upgrade pip' command.
pip的时候可能会遇到的错误,提示你升级pip。直接按它说的,输入python-m pip install --upgrade pip回车就好了。
回车后如果显示Requirement already up-to-date: (一段路径),那就根据提供的路径找到这个文件删除后再升级。
到这,终于可以开始进入正题了!!!
导入需要的包
import curses
from random import randrange, choice
from collections import defaultdict
对引入的包做一个简单的了解吧~
curses是一个图形函数库,用于实现终端无关的控制台输出以及输入处理,可以在终端内绘制简单的图形用户界面。
randrange()函数,从给定的范围返回随机项。
choice()函数,返回一个列表,元组或字符串的随机项。
# 如果直接import random使用时就需要写成random.choice/randrange
from random import randrange, choice
# 输出[0,100)之间的随机数
print(randrange(0,100))
# 随机输出1,2,3,4的其中一项,同理qwerty
print(choice([1,2,3,4]),choice('qwerty'))
defaultdict,dict的一个子类,重写了部分方法,使得查询错误时会调用工厂函数产生对应工厂类的对象。也就是有一个默认值保证查询出错时程序不会报错(不严谨解释)
from collections import defaultdict
test = [('x',5),('y',4),('z',6),('x',6)]
testDict = defaultdict(list)
for x,y in test:
testDict[x].append(y)
print(list(testDict.items()))
# 输出[('x', [5, 6]), ('y', [4]), ('z', [6])]
print(testDict['w'])
# 没有报错,而是输出了[]
主逻辑
借用下实验楼的图。
经过分析,会发现其实就两种状态。游戏中和不在游戏中。其中,不在游戏中包括赢和输两个分支。按功能来看,需要初始化(赢/输/开始新的一局)和退出游戏。由此可以先得出以下的框架(具体内容等会儿填充):
def main(stdscr):
def init():
# 重置游戏棋盘
return 'Game'
def not_game(state):
# 画出 GameOver 或者 Win 的界面
# 读取用户输入得到action,判断是重启游戏还是结束游戏
responses = defaultdict(lambda: state) # 默认是当前状态,没有行为就会一直在当前界面循环
responses['Restart'], responses['Exit'] = 'Init', 'Exit' # 对应不同的行为转换到不同的状态
return responses[action]
def game():
# 画出当前棋盘状态
# 读取用户输入得到action
if action == 'Restart':
return 'Init'
if action == 'Exit':
return 'Exit'
# if 成功移动了一步:
if 游戏胜利了:
return 'Win'
if 游戏失败了:
return 'Gameover'
return 'Game'
state_actions = {
'Init': init,
'Win': lambda: not_game('Win'),
'Gameover': lambda: not_game('Gameover'),
'Game': game
}
state = 'Init'
# 状态机开始循环
while state != 'Exit':
# 末尾的():state_actions中以函数名作为字典值
state = state_actions[state]()
两个点。
1.def main(stdscr)里的stdscr
curses使用两个数据结构映射终端屏幕,stdscr和curscr。stdscr是“标准屏幕”(逻辑屏幕),在curses函数库产生输出时就刷新,是默认输出窗口(用户不会看到该内容)。curscr是“当前屏幕”(物理屏幕),在调用refresh函数是,函数库会将curscr刷新为stdscr的样子。
2.lambda函数和state = state_actions[state]() 末尾的括号
匿名函数。创建语法是:lambda parameters:ex