我们先玩一下2048游戏,看都有哪些特点需要完成
完成效果图:
现在开始编写游戏2048:
1.首先,画出棋盘
import random
def draw_sep():
print("+-----" * 4 + '+')
# 2. 画每一行的格子
def draw_one_row(row): # [0, 2, 0, 0] | | 2 | | |
print("".join([ '| %d '%(item) if item != 0 else '| ' for item in row ]) + '|')
# draw_one_row([0, 2, 0, 0])
# 3. 创建棋盘的数据, 默认情况下时4*4, 数值全为0;
field = [[0 for j in range(4)] for i in range(4)]
# print(field)
# [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
# 4. 开始游戏时, 棋盘数据会随机生成2或者4,
def random_create():
# field[0][2] = 2
while True:
firstIndex = random.choice(range(4))
secondIndex = random.choice(range(4))
# 随机生成索引值
if field[firstIndex][secondIndex] == 0:
value = random.choice([2, 4, 2, 2, 2]) # 让一开始游戏生成2的概率大
field[firstIndex][secondIndex] = value
break
def game():
random_create()
random_create()
# 随机生成两个数字2或4
print(field)
# 打印棋盘
for row in field:
draw_sep()
draw_one_row(row)
draw_sep()
if __name__ == '__main__':
game()
输出:
第一行列表就是field的内容
2.判断棋盘是否可以向左移动
判断棋盘是否可以向左移动?
1). 只要棋盘的任意一行可以向左移动, 就返回True;
目标: 如何判断棋盘的一行是否可以向左移动?
2). 只要这一行的任意两个元素可以向左移动, 则返回True;
目标: 如何两个元素可以向左移动?
# - 如果第一个数值为0, 第二个数值不为0, 则说明可以向左移动;
# - 如果第一个数值不为0, 第二个数值与第一个元素相等, 则说明可以向左移动;
首先,可以在python console,熟悉or any and all功能:
True or False or True
输出True
any([True, False, True])
输出True
True and False and True
输出False
all([True, False, True])
输出False
def is_row_left(row): # [0, 2,2,0]
# 任意两个元素可以向左移动?
def is_change(index): # index时索引值, [0,1,2,3]
# - 如果第一个数值为0, 第二个数值不为0, 则说明可以向左移动;
if row[index] == 0 and row[index + 1] != 0:
return True
# - 如果第一个数值不为0, 第二个数值与第一个元素相等, 则说明可以向左移动;
if row[index] != 0 and row[index + 1] == row[index]:
return True
return False
# 只要这一行的任意两个元素可以向左移动, 则返回True;
return any([is_change(index) for index in range(3)])
def is_move_left(field):
# 只要棋盘的任意一行可以向左移动, 就返回True;
return any([is_row_left(row) for row in field])
测试这段程序:
if __name__ == "__main__":
try:
assert is_move_left([[0, 0, 0, 0], [0, 2, 0, 0], [0, 0, 0, 0], [0, 0, 0, 4]]) == True, "棋盘向左移动失败"
assert is_row_left([2, 2, 2, 2]) == True, 'Error'
assert is_row_left([2, 4, 2, 4]) == False, 'Error'
except AssertionError as e:
print(e)
else:
print("测试用例完成.....")
输出:
测试用例完成.....
- 棋盘是否可以向左完成之后,可以延伸到判断棋盘是否可以向右,向下,向上。
可以画一个矩阵想一下:
是否向右:翻转以后是否可以向左移动
是否向上:转置->向左
是否向下:转置->向右
我们先来实现翻转和转置功能:
def invert(field):
"""矩阵反转"""
return [row[::-1] for row in field]
测试:
if __name__ == '__main__':
print(invert([[0, 0, 0, 0], [0, 2, 0, 0], [0, 0, 0, 0], [0, 0, 0, 4]]))
def transpose(field):
"""实现矩阵的转置"""
# zip: 实现转置
# *field对列表进行解包;
return list(zip(*field))
测试:
if __name__ == '__main__':
print(transpose([[0, 0, 1, 0], [0, 2, 0, 1], [0, 0, 0, 1], [0, 0, 0, 4]]))
输出:
zip的功能,就是实现转置,但是要先把列表解包。zip转置后,需要转换为列表形式输出,否则输出是一个对象。
转置和翻转会了接下来就来完成判断棋盘是否可以向右、向下、向上。
def is_move_right(field):
# 对棋盘的每一行元素进行反转;
invertField = invert(field)
return is_move_left(invertField)
def is_move_up(field):
# 对棋盘的每一行元素进行转置;
transposeField = transpose(field)
return is_move_left( transposeField)
def is_move_down(field):
# 判断能否向下移动, 也就是对于元素进行转置, 判断转置后的棋盘能否向右移动;
# 对棋盘的每一行元素进行反转;
transposeField = transpose(field)
return is_move_right(transposeField)
测试:
if __name__ == '__main__':
try:
assert is_move_right([[0, 0, 0, 0], [0, 2, 0, 0], [0, 0, 0, 0], [0, 0, 0, 4]]) == True, 'Error'
assert is_move_up([[0, 0, 0, 0], [0, 2, 0, 0], [0, 0, 0, 0], [0, 0, 0, 4]]) == True, 'Error'
assert is_move_down([[0, 0, 0, 0], [0, 2, 0, 0], [0, 0, 0, 0], [0, 0, 0, 4]]) == True, 'Error'
except AssertionError as e:
print(e)
else:
print('测试完成')
输出&