首页 > 脚本语言 > python > Python实例浅谈之八2048游戏(字符界面)
2015
07-24

Python实例浅谈之八2048游戏(字符界面)

一、简介

使用python完成2048的代码编写。
2048游戏规则:简单的移动方向键让数字叠加,并且获得这些数字每次叠加后的得分,当出现2048这个数字时游戏胜利。同时每次移动方向键时,都会在这个4*4的方格矩阵的空白区域随机产生一个数字2或者4,如果方格被数字填满了,那么就GameOver了。
实现思路:2048游戏的全部操作都是围绕着一个4*4的矩阵进行,每次从用户界面获取用户的操作(即移动方向),然后重新计算这个4*4矩阵的状态,最后刷新用户界面显示4*4矩阵的最新状态,不断的循环这个过程,直到出现2048或没有空白方块了,如下是一个处理流程示意图:
Python实例浅谈之八2048游戏(字符界面) - 第1张  | 大话运维Python实例浅谈之八2048游戏(字符界面) - 第2张  | 大话运维

二、运行图

 Python实例浅谈之八2048游戏(字符界面) - 第3张  | 大话运维
Python控制台程序,用字符(W/S/A/D)代表方向键的输入,以数字0代表空白方格。计算部分:以向左移动为例,4*4矩阵在接收到向左移动的指令后,应该将每行的数字向左叠加, 将一行的叠加操作定义为函数 handle(list, direction),其第一个参数用来存储4*4矩阵中的某一行(列),第二个参数表示移动的方向(上下左右)。 这样当左右移动方向键时,可以这样来计算矩阵:遍历矩阵的每行,并将每行的数字沿左或右进行叠加操作,for row in matrix:handle(row, direction)。对于上下移动方向键时,由于矩阵是按行存储的,不能直接处理矩阵中的列,可以通过变通采用上面的函数handle()。对于矩阵中每一列,先将其拷贝到一个列表中,然后调用handle()函数对该列表进行叠加处理,最后再将叠加后的新列表拷贝回原始矩阵中其所在的列,其逻辑上等同于下面的代码操作。

for col in matrix:handle(col, direction)。
handle(row, direction)函数的作用是沿指定方向叠加一行中的数字,请看下面几个例子:
Python实例浅谈之八2048游戏(字符界面) - 第4张  | 大话运维
实现handle函数是关键。仔细观察叠加的过程,其都是由两个子过程组成的:

(1) align(row, direction)沿direction方向对齐列表row中的数字,例如:
x = [0, 4, 0, 2]
align(x, ‘left’)  后 x = [4, 2, 0, 0]
在 align(x, ‘right’) 后 x = [0, 0, 4, 2]
(2) addSame(row, direction) 查找相同且相邻的数字。如果找到,将其中一个翻倍,另一个置0(如果direction是’left’将左侧翻倍,右侧置0,如果direction为’right’,将右侧翻倍,左侧置0),并返回True;否则,返回False。例如:
x = [2, 2, 2, 2]
addSame(x, ‘left’) 后 x = [4, 0, 2, 2]      返回 True
再 addSame(x, ‘left’) 后 x = [4, 0, 4, 0]   返回 True
再 addSame(x, ‘left’) 后 x = [4, 0, 4, 0]   返回 False
       有了上面两个子函数,应该不难实现。有了这两个子函数,函数handle()就很好实现了,如下:
handle(row, direction):
          align(row, direction)
          result = addSame(row, direction)
          while result == True:
                    align(row, direction)
                    result = addSame(row, direction)
     下面结合一个实际例子再来看看handle函数的处理过程:
x = [2, 4, 2, 2]
调用 handle(x, ‘right’),变量 x 变化过程:
align(x, ‘right’)          ->     [2, 4, 2, 2]
addSame(x, ‘right’)   ->     [2, 4, 0, 4]     ->     return True
align(x, ‘right’)          ->     [0, 2, 4, 4]
addSame(x, ‘right’)   ->     [0, 2, 0, 8]     ->     return True
align(x, ‘right’)          ->     [0, 0, 2, 8]
addSame(x, ‘right’)   ->     [0, 0, 2, 8]     ->     return False
最终得到的 x = [0, 0, 2, 8]

三、详解

(1)文件2048.py,运行:python 2048.py,运行环境linux python2.6.6。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
 
#! /usr/bin/python
 
import random
import sys
 
v = [[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0] ]
 
def display(v, score):
'''显示界面
'''
print '{0:4} {1:4} {2:4} {3:4}'.format(v[0][0], v[0][1], v[0][2], v[0][3])
print '{0:4} {1:4} {2:4} {3:4}'.format(v[1][0], v[1][1], v[1][2], v[1][3])
print '{0:4} {1:4} {2:4} {3:4}'.format(v[2][0], v[2][1], v[2][2], v[2][3])
print '{0:4} {1:4} {2:4} {3:4}'.format(v[3][0], v[3][1], v[3][2], v[3][3]), '    Total score: ', score
 
 
def init(v):
'''随机分布网格值
'''
for i in range(4):
v[i] = [random.choice([0, 0, 0, 2, 2, 4]) for x in v[i]]
 
def align(vList, direction):
'''对齐非零的数字
direction == 'left':向左对齐,例如[8,0,0,2]左对齐后[8,2,0,0]
direction == 'right':向右对齐,例如[8,0,0,2]右对齐后[0,0,8,2]
'''
 
# 移除列表中的0
for i in range(vList.count(0)):
vList.remove(0)
# 被移除的0
zeros = [0 for x in range(4 - len(vList))]
# 在非0数字的一侧补充0
if direction == 'left':
vList.extend(zeros)
else:
vList[:0] = zeros
 
def addSame(vList, direction):
'''在列表查找相同且相邻的数字相加, 找到符合条件的返回True,否则返回False,同时还返回增加的分数
direction == 'left':从右向左查找,找到相同且相邻的两个数字,左侧数字翻倍,右侧数字置0
direction == 'right':从左向右查找,找到相同且相邻的两个数字,右侧数字翻倍,左侧数字置0
'''
score = 0
if direction == 'left':
for i in [0, 1, 2]:
if vList[i] == vList[i+1] != 0:
vList[i] *= 2
vList[i+1] = 0
score += vList[i]
return {'bool':True, 'score':score}
else:
for i in [3, 2, 1]:
if vList[i] == vList[i-1] != 0:
vList[i-1] *= 2
vList[i] = 0
score += vList[i-1]
return {'bool':True, 'score':score}
return {'bool':False, 'score':score}
 
def handle(vList, direction):
'''处理一行(列)中的数据,得到最终的该行(列)的数字状态值, 返回得分
vList: 列表结构,存储了一行(列)中的数据
direction: 移动方向,向上和向左都使用方向'left',向右和向下都使用'right'
'''
totalScore = 0
align(vList, direction)
result = addSame(vList, direction)
while result['bool'] == True:
totalScore += result['score']
align(vList, direction)
result = addSame(vList, direction)
return totalScore
 
 
def operation(v):
'''根据移动方向重新计算矩阵状态值,并记录得分
'''
totalScore = 0
gameOver = False
direction = 'left'
op = raw_input('operator:')
if op in ['a', 'A']:    # 向左移动
direction = 'left'
for row in range(4):
totalScore += handle(v[row], direction)
elif op in ['d', 'D']# 向右移动
direction = 'right'
for row in range(4):
totalScore += handle(v[row], direction)
elif op in ['w', 'W']# 向上移动
direction = 'left'
for col in range(4):
# 将矩阵中一列复制到一个列表中然后处理
vList = [v[row][col] for row in range(4)]
totalScore += handle(vList, direction)
# 从处理后的列表中的数字覆盖原来矩阵中的值
for row in range(4):
v[row][col] = vList[row]
elif op in ['s', 'S']# 向下移动
direction = 'right'
for col in range(4):
# 同上
vList = [v[row][col] for row in range(4)]
totalScore += handle(vList, direction)
for row in range(4):
v[row][col] = vList[row]
else:
print('Invalid input, please enter a charactor in [W, S, A, D] or the lower')
return {'gameOver':gameOver, 'score':totalScore}
 
# 统计空白区域数目 N
N = 0
for q in v:
N += q.count(0)
# 不存在剩余的空白区域时,游戏结束
if N == 0:
gameOver = True
return {'gameOver':gameOver, 'score':totalScore}
 
# 按2和4出现的几率为3/1来产生随机数2和4
num = random.choice([2, 2, 2, 4])
# 产生随机数k,上一步产生的2或4将被填到第k个空白区域
k = random.randrange(1, N+1)
n = 0
for i in range(4):
for j in range(4):
if v[i][j] == 0:
n += 1
if n == k:
v[i][j] = num
break
 
return {'gameOver':gameOver, 'score':totalScore}
 
init(v)
score = 0
print 'Input:W(Up) S(Down) A(Left) D(Right), press <CR>.'
while True:
display(v, score)
result = operation(v)
if result['gameOver'] == True:
print 'Game Over, You failed!'
print 'Your total score:', score
sys.exit(1)
else:
score += result['score']
if score >= 2048:
print 'Game Over, You Win!!!'
print 'Your total score:', score
sys.exit(0)

(2)修改出现例如(4,4,8,0)这样的情况,得分不合理的情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
 
#!/usr/bin/python2
 
import random
import os, sys
 
 
v = [[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0]]
 
def display(v, score):
print "%4d  %4d %4d %4d"    %   (v[0][0], v[0][1], v[0][2], v[0][3])
print "%4d  %4d %4d %4d"    %   (v[1][0], v[1][1], v[1][2], v[1][3])
print "%4d  %4d %4d %4d"    %   (v[2][0], v[2][1], v[2][2], v[2][3])
print "%4d  %4d %4d %4d"    %   (v[3][0], v[3][1], v[3][2], v[3][3])
print "Total score: %d" % score
 
def init(v):
for i in range(4):
v[i] = [random.choice([0, 0, 0, 2, 2, 4]) for x in range(4)]
 
def align(vList, direction):
for i in range(vList.count(0)):
vList.remove(0)
zeros = [0 for x in range(4 - len(vList))]
if direction == 'left':
vList.extend(zeros)
else:
vList[:0] = zeros
 
def addSame(vList, direction):
score = 0
if direction == 'left':
for i in [0, 1, 2]:
align(vList, direction)
if vList[i] == vList[i+1] != 0:
vList[i] *= 2
vList[i+1] = 0
score += vList[i]
return {'bool':True, 'score':score}
else:
for i in [3, 2, 1]:
align(vList, direction)
if vList[i] == vList[i-1] != 0:
vList[i] *= 2
vList[i-1] = 0
score += vList[i]
return {'bool':True, 'score':score}
return {'bool':False, 'score':score}
 
def handle(vList, direction):
totalScore = 0
align(vList, direction)
result = addSame(vList, direction)
while result['bool'] == True:
totalScore += result['score']
align(vList, direction)
result = addSame(vList, direction)
return totalScore
 
def operation(v):
totalScore = 0
gameOver = False
direction = 'left'
op = raw_input('operator:')
if op in ['a','A']:
direction = 'left'
for row in range(4):
totalScore += handle(v[row], direction)
elif op in ['d','D']:
direction = 'right'
for row in range(4):
totalScore += handle(v[row], direction)
elif op in ['w', 'W']:
direction = 'left'
for col in range(4):
vList = [v[row][col] for row in range(4)]
totalScore += handle(vList, direction)
for row in range(4):
v[row][col] = vList[row]
elif op in ['s', 'S']:
direction = 'right'
for col in range(4):
vList = [v[row][col] for row in range(4)]
totalScore += handle(vList, direction)
for row in range(4):
v[row][col] = vList[row]
else:
print "Invalid input,please enter a charactor in [W,S,A,D] or the lower"
gameOver = True
return {'gameOver':gameOver,'score':totalScore}
 
N = 0
for q in v:
N += q.count(0)
 
if N == 0:
gameOver = True
return {'gameover':gameOver,'score':totalScore}
 
num = random.choice([2,2,2,4])
k = random.randrange(1, N+1)
n = 0
 
for i in range(4):
for j in range(4):
if v[i][j] == 0:
n += 1
if n == k:
v[i][j] = num
break
 
return {'gameOver':gameOver, 'score':totalScore}
 
 
init(v)
score = 0
print "Input:W(Up) S(Down) A(Left) D(Right), press <CR>."
while True:
os.system("clear")
display(v, score)
result = operation(v)
print result
if result['gameOver'] == True:
print "Game Over, You failed!"
print "Your total score %d" % (score)
sys.exit(1)
else:
score += result['score']
if score >= 2048:
print "Game Over, You Win!!!"
print "Your total score: %d" % (score)
sys.exit(0)

(3)linux使用ncurses库实现的2048 ai