python代码⽰例200⾏-200⾏python代码实现2048游戏
创建游戏⽂件 2048.py
⾸先导⼊需要的包:
import curses
from random import randrange, choice
from collections import defaultdict
主逻辑
⽤户⾏为
所有的有效输⼊都可以转换为"上,下,左,右,游戏重置,退出"这六种⾏为,⽤ actions 表⽰
actions = ['Up', 'Left', 'Down', 'Right', 'Restart', 'Exit']
有效输⼊键是最常见的 W(上),A(左),S(下),D(右),R(重置),Q(退出),这⾥要考虑到⼤写键开启的情况,获得有效键值列表:
letter_codes = [ord(ch) for ch in 'WASDRQwasdrq']
将输⼊与⾏为进⾏关联:
actionsdict = dict(zip(lettercodes, actions * 2))
状态机
处理游戏主逻辑的时候我们会⽤到⼀种⼗分常⽤的技术:状态机,或者更准确的说是有限状态机(FSM)
你会发现 2048 游戏很容易就能分解成⼏种状态的转换。
state 存储当前状态, state_actions 这个词典变量作为状态转换的规则,它的 key 是状态,value 是返回下⼀个状态的函数:
Init: init()
Game: game()
Win: lambda: not_game('Win')
Gameover: lambda: not_game('Gameover')
Exit: 退出循环
状态机会不断循环,直到达到 Exit 终结状态结束程序。
下⾯是经过提取的主逻辑的代码,会在后⾯进⾏补全:
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 = state_actions[state]()
⽤户输⼊处理
阻塞+循环,直到获得⽤户有效输⼊才返回对应⾏为:
python新手代码示例def get_user_action(keyboard):
char = "N"
while char not in actions_dict:
char = h()
return actions_dict[char]
矩阵转置与矩阵逆转
加⼊这两个操作可以⼤⼤节省我们的代码量,减少重复劳动,看到后⾯就知道了。
矩阵转置:
def transpose(field):
return [list(row) for row in zip(*field)]
矩阵逆转(不是逆矩阵):
def invert(field):
return [row[::-1] for row in field]
创建棋盘
初始化棋盘的参数,可以指定棋盘的⾼和宽以及游戏胜利条件,默认是最经典的 4×4~2048。class GameField(object):
def __init__(self, height=4, width=4, win=2048):
self.height = height #⾼
self.width = width #宽
self.win_value = 2048 #过关分数
self.score = 0 #当前分数
self.highscore = 0 #最⾼分
棋盘操作
随机⽣成⼀个 2 或者 4
def spawn(self):
new_element = 4 if randrange(100) > 89 else 2
(i,j) = choice([(i,j) for i in range(self.width) for j in range(self.height) if self.field[i][j] == 0]) self.field[i][j] = new_element
#### 重置棋盘
def reset(self):
if self.score > self.highscore:
self.highscore = self.score
self.score = 0
self.field = [[0 for i in range(self.width)] for j in range(self.height)]
self.spawn()
self.spawn()
#### ⼀⾏向左合并
(注:这⼀操作是在 move 内定义的,拆出来是为了⽅便阅读)
def move_row_left(row):
def tighten(row): # 把零散的⾮零单元挤到⼀块
new_row = [i for i in row if i != 0]
new_row += [0 for i in range(len(row) - len(new_row))]
return new_row
def merge(row): # 对邻近元素进⾏合并
pair = False
new_row = []
for i in range(len(row)):
if pair:
new_row.append(2 * row[i])
self.score += 2 * row[i]
pair = False
else:
if i + 1 < len(row) and row[i] == row[i + 1]:
pair = True
new_row.append(0)
else:
new_row.append(row[i])
assert len(new_row) == len(row)
return new_row
#先挤到⼀块再合并再挤到⼀块
return tighten(merge(tighten(row)))
棋盘⾛⼀步
通过对矩阵进⾏转置与逆转,可以直接从左移得到其余三个⽅向的移动操作
def move(self, direction):
def move_row_left(row):
#⼀⾏向左合并
moves = {}
moves['Left'] = lambda field: [move_row_left(row) for row in field]
moves['Right'] = lambda field: invert(moves['Left'](invert(field)))
moves['Up'] = lambda field: transpose(moves['Left'](transpose(field))) moves['Down'] = lambda field: transpose(moves['Right'](transpose(field))) if direction in moves:
ve_is_possible(direction):
self.field = moves[direction](self.field)
self.spawn()
return True
else:
return False
判断输赢
def is_win(self):
return any(any(i >= self.win_value for i in row) for row in self.field)
def is_gameover(self):
return not ve_is_possible(move) for move in actions)
#### 判断能否移动
def move_is_possible(self, direction):
defrow_is_left_movable(row):
def change(i):
if row[i] == 0 and row[i + 1] != 0: # 可以移动
return True
if row[i] != 0 and row[i + 1] == row[i]: # 可以合并
return True
return False
return any(change(i) for i in range(len(row) - 1))
check = {}
check['Left'] = lambda field: any(row_is_left_movable(row) for row in field) check['Right'] = lambda field: check['Left'](invert(field))
check['Up'] = lambda field: check['Left'](transpose(field))
check['Down'] = lambda field: check['Right'](transpose(field))
if direction in check:
return check[direction](self.field)
else:
return False
绘制游戏界⾯
def draw(self, screen):
help_string1 = '(W)Up (S)Down (A)Left (D)Right'
help_string2 = ' (R)Restart (Q)Exit'
gameover_string = ' GAME OVER'
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论