注:此代码需要在shell下运行
import curses
from itertools import chain
from random import choice, randint
# 创建一个游戏类
class Gamefiled(object):
# 游戏文件的属性
def __init__(self, width=4, height=4, win_value=2048):
self.width = width
self.height = height
self.win_value = win_value
self.score1 = 0
self.score2 = 0
self.file1 = []
self.file2 = []
# 创建数据文件函数<以列表的方式保存>
def recreate_file(self):
self.file1 = [[0 for i in range(self.width)]for j in range(self.height)]
self.file2 = [[0 for i in range(self.width)]for j in range(self.height)]
self.create_random(self.file1)
self.create_random(self.file1)
self.create_random(self.file2)
self.create_random(self.file2)
# 在列表中随即生成数的函数
def create_random(self, filed):
while True:
i, j = choice(range(self.width)), choice(range(self.height))
if filed[i][j] == 0:
filed[i][j] = 4 if randint(1, 100) > 90 else 2
break
# 按格式画棋盘
def draw(self, stdscr):
def draw_sep():
line = '+' + '----+' * self.width
stdscr.addstr(line + '\n')
def draw_row(row): # [2,0,2,0]
draw_one_row = "".join(['|{:^4}'.format(num)
if num != 0 else '| ' for num in row]) + '|'
stdscr.addstr(draw_one_row + '\n')
stdscr.clear() # 清屏
# 打印分数
stdscr.addstr('Player1_Score:' + str(self.score1) + '\n')
# 画棋盘
for row in self.file1:
draw_sep()
draw_row(row)
draw_sep()
stdscr.addstr('Player2_Score:' + str(self.score2) + '\n')
for row in self.file2:
draw_sep()
draw_row(row)
draw_sep()
if self.is_win():
if self.score1 > self.score2:
stdscr.addstr('Palyer1 Win!' + '\n\n')
elif self.score2 > self.score1:
stdscr.addstr('Palyer2 Win!' + '\n\n')
else:
stdscr.addstr('DogFall!' + '\n')
stdscr.addstr('1P:Up Down Left Right\n2P:W A S D\n(R)Restart(Q)Exit\n')
# 定义判断输赢的函数<chain将多个列表内的值链成一个新列表>
def is_win(self):
return max(chain(*self.file1)) >= self.win_value or \
max(chain(*self.file2)) >= self.win_value or (not any([self.move_possible(direction) for direction in [
'Up', 'Down', 'Right', 'Left']])) and (not any([self.move_possible1(direction)
for direction in ['Up1', 'Down1', 'Right1', 'Left1']]))
@staticmethod
def invert(filed):
return [row[::-1] for row in filed]
@staticmethod
def transpose(filed):
return [list(row) for row in zip(*filed)] # zip完成数组的置换
# 定义判断是否可以移动的函数
def move_possible(self, direction):
def leftrow_move_possible(row):
def is_move(i):
if row[i] == 0 and row[i + 1] != 0:
return True
if row[i] == row[i + 1] != 0:
return True
return False
return any([is_move(i) for i in range(len(row) - 1)])
possible = {}
possible['Left'] = lambda filed: any([leftrow_move_possible(row) for row in filed])
possible['Right'] = lambda filed: possible['Left'](self.invert(filed))
possible['Up'] = lambda filed: possible['Left'](self.transpose(filed))
possible['Down'] = lambda filed: possible['Right'](self.transpose(filed))
if direction in possible:
return possible[direction](self.file1)
else:
return False
def move_possible1(self, direction):
def leftrow_move_possible(row):
def is_move(i):
if row[i] == 0 and row[i + 1] != 0:
return True
if row[i] == row[i + 1] != 0:
return True
return False
return any([is_move(i) for i in range(len(row) - 1)])
possible = {}
possible['Left1'] = lambda filed: any([leftrow_move_possible(row) for row in filed])
possible['Right1'] = lambda filed: possible['Left1'](self.invert(filed))
possible['Up1'] = lambda filed: possible['Left1'](self.transpose(filed))
possible['Down1'] = lambda filed: possible['Right1'](self.transpose(filed))
if direction in possible:
return possible[direction](self.file2)
else:
return False
# 定义移动函数
def move(self, direction):
def leftrow_move(row): # 一行的移动
def tight(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): # 合并
for i in range(len(row) - 1):
if row[i] == row[i + 1]:
row[i] *= 2
row[i + 1] = 0
self.score1 += row[i]
return row
return tight(merge(tight(row)))
def leftrow_move1(row): # 一行的移动
def tight(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): # 合并
for i in range(len(row) - 1):
if row[i] == row[i + 1]:
row[i] *= 2
row[i + 1] = 0
self.score2 += row[i]
return row
return tight(merge(tight(row)))
moves = {}
moves['Left'] = lambda filed: [leftrow_move(row) for row in filed]
moves['Right'] = lambda filed: self.invert([leftrow_move(row) for row in self.invert(filed)])
moves['Up'] = lambda filed: self.transpose([leftrow_move(row) for row in self.transpose(filed)])
moves['Down'] = lambda filed: self.transpose(moves['Right'](self.transpose(filed)))
moves1 = {}
moves1['Left1'] = lambda filed: [leftrow_move1(row) for row in filed]
moves1['Right1'] = lambda filed: self.invert([leftrow_move1(row) for row in self.invert(filed)])
moves1['Up1'] = lambda filed: self.transpose([leftrow_move1(row) for row in self.transpose(filed)])
moves1['Down1'] = lambda filed: self.transpose(moves1['Right1'](self.transpose(filed)))
# 判断是否可移动
if self.move_possible(direction):
self.file1 = moves[direction](self.file1)
self.create_random(self.file1)
return True
elif self.move_possible1(direction):
self.file2 = moves1[direction](self.file2)
self.create_random(self.file2)
return True
else:
return False
# 定义捕获用户操作的函数
def get_action(stdscr):
action = stdscr.getch()
if action == curses.KEY_UP:
return 'Up'
if action == curses.KEY_DOWN:
return 'Down'
if action == curses.KEY_LEFT:
return 'Left'
if action == curses.KEY_RIGHT:
return 'Right'
if action == ord('w'):
return 'Up1'
if action == ord('s'):
return 'Down1'
if action == ord('a'):
return 'Left1'
if action == ord('d'):
return 'Right1'
if action == ord('r'):
return 'Restart'
if action == ord('q'):
return 'Exit'
# 主函数
def main(stdscr):
# 调用游戏类
def init(): # 初始化函数,创建数据并返回开始玩游戏的函数
game_filed.recreate_file()
return 'Game'
def game(): # 游戏内函数
game_filed.draw(stdscr) # 画棋盘
action = get_action(stdscr) # 获取用户操作
if action == 'Restart': # 重置游戏
return 'Init'
if action == 'Exit':
return 'Exit'
if game_filed.move(action): # 其他操作让其移动
# 每次移动后判断输或者赢
if game_filed.is_win():
return 'Win'
return 'Game' # 再次返回游戏函数
def not_game(): # 定义游戏外函数
game_filed.draw(stdscr) # 画棋盘
while 1:
action = get_action(stdscr)
if action == 'Restart': # 重置游戏
return 'Init'
if action == 'Exit': # 退出
return 'Exit'
status_filed = {'Init': init,
'Game': game,
'Win': not_game,
'GameOver': not_game
}
game_filed = Gamefiled(win_value=2048)
status = 'Init'
while status != "Exit":
status = status_filed[status]()
curses.wrapper(main)