您的位置:首页 > 编程语言 > Python开发

命令行2048

2015-07-27 10:28 615 查看

命令行2048

By 白熊花田(http://blog.csdn.net/whiterbear) 转载需注明出处,谢谢。

写了一个基于命令行的2048游戏,python写的,难度不是很大,关键是要理清游戏的逻辑。这篇博客将介绍下游戏实现的逻辑和简单的实现,以及美化游戏界面的细节。

先贴一张游戏运行的截图。



1 逻辑

介绍该游戏的逻辑。

1.1 游戏的逻辑

玩过2048的童鞋应该知道,该游戏是由4*4的方格组成,启动时方格里会随机出现两个数字,一般为2,偶尔也会出现4. 游戏在达到2048时显示胜利,当然也可以继续玩下去,在方格填满并且四个方向均无法移动时游戏失败。

1.2 移动的逻辑

可以通过上下左右进行方格数字的移动,以向左为例,当玩家选择向左时,每一行从最左边的数字开始,先(1)向左移动,如果该数字左边有0格,移动后位置数字的值从0变成该数字的值,一直到该行所有的数字均尝试了移动为止;(2)合并,如果该数字与其右边的数字等值且不等于0时,它自身值变为以前的2倍,其右边的值变为0,继续合并,直到该行的所有数字均尝试了该合并操作;(3)向左移动,规则同(1)。

以向左为例,可能会出现的情况有:

[0, 0, 0, 2] -> [2, 0, 0, 0]
[2, 2, 2, 0] -> [4, 2, 0, 0]
[2, 2, 2, 2] -> [4, 4, 0, 0]
[4, 2, 0, 2] -> [4, 4, 0, 0]


1.3 分数的逻辑

每次移动有合并时,游戏总分加上合并后该数字的数值。如某行从

[2, 2, 2, 2] -> [4, 4, 0, 0],出现了两次合并,则总分应该加上4+4分。

2 实现

介绍该游戏的编程实现细节。

2.1 方格的表示和显示

使用二维数组来表示游戏方格。

_SIZE = 4
cells = [[0]*_SIZE for _ in xrange(_SIZE)]


使用format来显示游戏方格。

for i in xrange(_SIZE):
print('{0:4} {1:4} {2:4} {3:4}'.format(cells[i][0], cells[i][1], cells[i][2], cells[i][3]))


2.2 初始化游戏方格

初始化游戏方格时,需要随机选择两个方格放置随机的数字(2或4)。

利用random模块,从[2]*9 + [4]中随机选择一个数值。在所有空的方格中随机选择一个方格,放入选择的数值,重复两次。

2.3 获得玩家输入

以asdw键分别代表左,下,左,上操作。使用raw_input获得玩家输入即可。

2.4 移动方格

获得到玩家输入的方向时,即可利用该方向移动方格。按照1.2中给定的移动的逻辑,在移动之前需要进行方格的位置移动,即在不进行合并操作的情况下进行数字移动,这样能够便于之后的合并操作。以向左为例:

for line in xrange(_SIZE):
# 从该行最左边开始
for row in xrange(0, _SIZE - 1, 1):
# 如果该方格为0值
if not cells[line][row]:
# 将其右边的方格值传递给它,即进行移动
cells[line][row] = cells[line][row + 1]
cells[line][row + 1] = 0


当然会出现一次操作不能使方格移动完整,即会出现[0, 0, 0, 2]->[0, 0, 2, 0]的情况,所以需要多移动几次才会变成[2, 0, 0, 0]。

在移动方格后,开始合并方格。以向左为例:

for line in xrange(_SIZE):
# 从该行最左边开始
for row in xrange(0, _SIZE - 1, 1):
# 如果该方格和其右边方格值相同,且两者都不为0时进行合并
if cells[line][row] == cells[line][row + 1] != 0:
# 合并,即它自身值变成之前的2倍,而它右边的方格值变成0
cells[line][row], cells[line][row + 1] = 2*cells[line][row], 0
# 分数加上合并后的方格值
score += cells[line][row]


然而,这种移动的方式会出现[2, 2, 2, 2]->[4, 0, 4, 0]的情况,而我们需要的是变成[4, 4, 0, 0]。所以,在这样移动后,我们仍需要调用上面的位置移动代码,进行方格值的移动达到我们要的结果。

2.5 运行游戏

有了上面的基础,该游戏就可以简单的运行起来了。

# 循环处理
while True:
# 显示游戏方格和分数
display()
# 接受玩家输入,并进行移动方格操作
operation()
# 选择空格区域添加一个随机分值
addCell()


然而,这样运行会出现游戏方格在玩家输入某方向上已经不能移动时,游戏仍然会选择空格区域添加随机分值,这样,我们需要判断玩家输入某方向后,该方向是否移动过,如果移动了,那么才可以添加分值。改进如下:

while True:
display()
# 必须使用深复制,否则两者变化会一致
old_cells = copy.deepcopy(cells)
operation()
# 如果方格有移动,则选择一个方格添加一个值
if old_cells != cells:
addCell()


使用了深复制,复制了一份移动之前的游戏方格状态,将该状态与玩家输入移动后的状态进行比较,如果两者不一致即说明移动成功了,可以添加方格。

游戏截图:



3 美化

介绍该游戏界面的美化。

3.1 添加颜色

前面的游戏运行所有分数都是以默认的黑色进行显示的,我们尝试着让不同的分值显示不同的颜色。在github上找到了一位大神的2048代码,他使用了colorama模块,然后他代码里的其他特性也被我用上了。利用了他的代码,我也将我的游戏添上了色彩。

colorama是一个能够让python在命令行中输出彩色字体的模块。安装很简单:pip install colorama。下面给出一个简单的使用范例。

from colorama import init, Fore, Style
# autoreset能够让变色效果只对当前输出有效果
init(autoreset=True)
# Fore.RED可以让后面的输出变为红色,Style.RESET_ALL能够清除变色效果
print(Fore.RED + 'color font' + Style.RESET_ALL + 'no color')

# 该段代码输出红色的‘color font’和默认黑色的‘no color’


使用colorama到游戏中。首先定义一个颜色字典,让每个数值都对应一个颜色。如:

COLORS = {
2:    Fore.GREEN,
4:    Fore.BLUE + Style.BRIGHT,
8:    Fore.CYAN,
...}


利用该字典,我们在每次显示游戏方格时,对每个数字进行变色处理。

# 获取给定的一个游戏方格值
cell = getCell(x, y)
# 如果值为0,则表示为一个点 .
if cell == 0:
return '  .'
# 如果是数字,那么默认每个数字占3个空格长度
# 在字典中找到该数值对应的颜色,修饰后恢复默认颜色(这样不会影响下一个数字输出的颜色)
else:
str_cell = '%3d' % cell
return str(COLORS.get(cell, Fore.GREEN) + str_cell + Style.RESET_ALL)


这样游戏的运行的效果如:



3.2 支持VIM键和箭头操作

作为程序员,还是有必要支持一下vim键的,另外,如果能够支持箭头,那么操作起来也会更方便(我好像暴露了)。利用termios模块(只在Unix下运行,Windows下请使用msvcrt),可以方便的获得键盘输入。学习一下termios模块,获取字母的大小写输入并不是难事,但是箭头的获取稍微麻烦点。你需要按照下面的方式来获取箭头输入:

k = __getKey()
if k == 27:
k = __getKey()
if k == 91:
k = __getKey()


其中__getKey()函数能够获取键盘输入,并返回输入的ascii码值。普通的键,比如‘A’,输入后得到65,而输入箭头时得到的k值等于27,接着再调用该方法,得到91,再调用一次,得到104或106或107或108,这四个值分别是输入左,下,上,右箭头。

3.3 支持刷新

通过前面的游戏界面,我们能看到每次玩家输入,游戏界面总是会在命令行重新绘制,增加了行数,降低了游戏的娱乐程度。所以我们使用清屏操作,每次输入后,清屏,然后在同样的位置绘制游戏界面,这样给玩家的感觉游戏时连贯的。另外,消除掉命令行的光标也有助于增加游戏体验。

清屏操作:

os.system('clear')


隐藏光标操作:

sys.stdout.write('\033[?25l')


显示光标操作:

sys.stdout.write('\033[?25h')


修改运行代码:

# 首先注册显示光标函数,这样游戏运行完成退出后能够运行该函数显示光标
atexit.register(showCursor)
# 隐藏光标
hideCursor()
while True:
# 每次循环先清屏,然后重新绘制游戏界面
clearScreen()
display()
old_cells = copy.deepcopy(cells)
operation()
if old_cells != cells:
addCell()


最后再贴一张运行截图:



代码链接:

github

csdn
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  python 命令行 游戏 2048