1 Star 0 Fork 0

CodingNinja/py2048

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
py2048.py 7.65 KB
一键复制 编辑 原始数据 按行查看 历史
CodingNinja 提交于 2018-04-09 21:53 +08:00 . 更新 py2048.py
import curses
from collections import defaultdict
from random import choice, random
# 定义按键映射
ACTIONS = ['Up', 'Left', 'Down', 'Right', 'Restart', 'Exit']
LETTER_CODES = [ord(ch) for ch in 'WASDRQwasdrq']
ACTION_MAP = dict(zip(LETTER_CODES, ACTIONS * 2))
# 获取用户输入
def get_user_action(keyboard):
char = '-1'
while char not in ACTION_MAP:
char = keyboard.getch()
return ACTION_MAP[char]
# 转置矩阵
def transpose(grid):
return [list(row) for row in zip(*grid)]
# 反转矩阵
def invert(grid):
return [row[::-1] for row in grid]
# 定义游戏类
class Game(object):
def __init__(self, rows=4, cols=4, win=2048, start_tiles=2, keep_playing=True):
self.rows = rows
self.cols = cols
self.win = win
self.keep_playing = keep_playing
self._grid = [[]]
self._start_tiles = start_tiles
self._score = 0
self._best_score = 0
self._won_flag = False
self.reset()
# 随机填充一个瓦片
def _add_random_tile(self, pr_2=0.9):
tile = 2 if random() < pr_2 else 4
(r, c) = choice([(r, c)
for r in range(self.rows)
for c in range(self.cols)
if self._grid[r][c] == 0])
self._grid[r][c] = tile
# 判断是否可移动
def can_move(self, direction):
# 判断能否向左移动
def can_move_left(row):
# 判断能否移动一步
def can_move_one_step(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(can_move_one_step(i) for i in range(len(row) - 1))
# 将所有判断转化为判断能否向左移动
check = {}
check['Left'] = lambda grid: any(can_move_left(row) for row in grid)
check['Right'] = lambda grid: check['Left'](invert(grid))
check['Up'] = lambda grid: check['Left'](transpose(grid))
check['Down'] = lambda grid: check['Right'](transpose(grid))
if direction in check:
return check[direction](self._grid)
else:
return False
# 移动操作
def move(self, direction):
# 将一行向左移动
def move_left(row):
# 收紧一行
def tighten(row):
new_row = [i for i in row if i != 0]
new_row += [0 for _ 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])
return new_row
return tighten(merge(tighten(row)))
# 将所有操作转化为向左移动的操作
moves = {}
moves['Left'] = lambda grid: [move_left(row) for row in grid]
moves['Right'] = lambda grid: invert(moves['Left'](invert(grid)))
moves['Up'] = lambda grid: transpose(moves['Left'](transpose(grid)))
moves['Down'] = lambda grid: transpose(moves['Right'](transpose(grid)))
if direction in moves:
if self.can_move(direction):
self._grid = moves[direction](self._grid)
self._add_random_tile()
return True
else:
return False
# 判断游戏是否获胜
def has_won(self):
return any(any(i >= self.win for i in row) for row in self._grid)
# 判断游戏是否结束
def is_game_over(self):
return not any(self.can_move(move) for move in ACTIONS)
# 绘图
def draw(self, screen):
help_tips1 = "(W)Up (A)Left (S)Down (D)Right"
tips_width = len(help_tips1)
help_tips2 = "(R)Restart (Q)Exit".center(tips_width)
game_over_tips = "GAME OVER!".center(tips_width)
game_intro = "Join the numbers and get to the {self.win} tile!".format(
self=self)
score_tips = "SCORE: {} BEST: {}".format(
self._score, self._best_score)
win_tips = "YOU WIN!".center(tips_width)
won_tips = "YOU WON!".center(tips_width)
# 向屏幕添加一段字符串
def cast(string):
screen.addstr(string + '\n')
# 绘制水平分割线
def draw_hor_sep():
line = '+' + ('+------' * self.cols + '+')[1:]
separator = defaultdict(lambda: line)
if not hasattr(draw_hor_sep, "counter"):
draw_hor_sep.counter = 0
cast(separator[draw_hor_sep.counter])
draw_hor_sep.counter += 1
# 绘制行
def draw_row(row):
cast(''.join('|{: ^5} '.format(num)
if num > 0 else '| ' for num in row) + '|')
screen.clear()
cast(game_intro)
cast(score_tips)
for row in self._grid:
draw_hor_sep()
draw_row(row)
draw_hor_sep()
if self.has_won():
if self.keep_playing and self._won_flag:
cast(won_tips)
else:
cast(win_tips)
self._won_flag = True
else:
if self.is_game_over():
cast(game_over_tips)
else:
cast(help_tips1)
cast(help_tips2)
# 重置游戏
def reset(self, clear_best=False):
if clear_best:
self._best_score = 0
elif self._score > self._best_score:
self._best_score = self._score
self.score = 0
self._grid = [[0 for _ in range(self.cols)]
for _ in range(self.rows)]
for _ in range(self._start_tiles):
self._add_random_tile()
# 主函数
def main(stdscr):
# 初始化状态
def init():
game.reset()
return 'Game'
# 结果状态
def final(state):
game.draw(stdscr)
if game.keep_playing:
return 'Game'
action = get_user_action(stdscr)
responses = defaultdict(lambda: state)
responses['Restart'], responses['Exit'] = 'Init', 'Exit'
return responses[action]
# 游戏逻辑状态
def game_logic():
game.draw(stdscr)
action = get_user_action(stdscr)
if action == 'Restart':
return 'Init'
if action == 'Exit':
return 'Exit'
if game.move(action):
if game.is_game_over():
return 'GameOver'
if game.has_won():
return 'Win'
return 'Game'
# 定义状态,游戏在状态间转移
state_actions = {
'Init': init,
'Win': lambda: final('Win'),
'GameOver': lambda: final('GameOver'),
'Game': game_logic
}
curses.use_default_colors()
game = Game()
state = 'Init'
# 状态循环
while state != 'Exit':
state = state_actions[state]()
if __name__ == '__main__':
curses.wrapper(main)
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Python
1
https://gitee.com/CodingNinja/py2048.git
git@gitee.com:CodingNinja/py2048.git
CodingNinja
py2048
py2048
master

搜索帮助