基础单人版:
设计思路:
游戏分为<初始化init><游戏中game><胜利win><失败gameover>四个状态;
main函数中主要有init函数,game函数和not_game函数,函数的返回值作为字典的key值,
函数作为value值生成字典,循环捕获key值,通过key值的变化来调用函数,使整个程序循环运转!
1).init函数
初始化创建数据的函数,在捕获用户操作restart时返回此函数,函数返回值为key值game,去进行游戏操作
2).game函数
该函数主要分为,画表格(将初始化的数据按一定格式画出来),不湖欧用户操作进行移动,移动完进行结束
游戏条件(胜利|失败)判断,不满足条件返回key值game,继续进行游戏操作,满足则返回key值win|gameover
进行游戏外设置(重置|退出)操作
3).not_game函数
主要进行游戏结束用户选择操作,捕获用户操作,restart返回key值init,重新游戏。exit退出游戏
代码:
mport 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.score = 0 self.high_score = 0 self.file = [] # 创建数据文件函数<以列表的方式保存> def recreate_file(self): if self.score > self.high_score: self.high_score = self.score self.score = 0 self.file = [[0 for i in range(self.width)] for j in range(self.height)] self.create_random() self.create_random() # 在列表中随即生成数的函数 def create_random(self): while True: i, j = choice(range(self.width)), choice(range(self.height)) if self.file[i][j] == 0: self.file[i][j] = 4 if randint(1, 100) > 90 else 2 break # 按格式画棋盘 def draw(self, stdscr): stdscr.clear() # 清屏 # 打印分数 stdscr.addstr('Score:' + str(self.score) + '\nHighScore:' + str(self.high_score) + '\n\n') # 画棋盘 for row in self.file: stdscr.addstr('+' + '----+' * self.width + '\n') stdscr.addstr(''.join(['|{:^4}'.format(num) if num != 0 else '| ' for num in row]) + '|' + '\n') stdscr.addstr("+" + '----+' * self.width + '\n') if self.is_win(): stdscr.addstr('You win!' + '\n') if self.is_gameover(): stdscr.addstr('Game Over!' + '\n') # 画提示信息 stdscr.addstr('\n\n\n\nUp Down Left Right\n(R)Restart (Q)Exit') # 定义判断输赢的函数<chain将多个列表内的值链成一个新列表> def is_win(self): return max(chain(*self.file)) >= self.win_value def is_gameover(self): return not any([self.move_possible(direction) for direction in ['Up', 'Down', 'Right', 'Left']]) @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.file) 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.score += 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))) # 判断是否可移动 if self.move_possible(direction): self.file = moves[direction](self.file) self.create_random() 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('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' if game_filed.is_gameover(): return 'GameOver' 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=32) status = 'Init' while status != "Exit": status = status_filed[status]() curses.wrapper(main)
胜利数值为32时:
按R重置后:
胜利数值为2048的游戏失败案例:
按R重置并保存其最高分:
双人即时PK版:
设计思路大体同2048基础版,主要在其用户操作的捕获和棋盘的构建和规划略有差异。
双人PK,胜利条件为:一方先到达指定胜利条件,两均为达到则比较分数
代码:
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') elif self.score2 > self.score1: stdscr.addstr('Palyer2 Win!' + '\n') else: stdscr.addstr('DogFall!' + '\n') stdscr.addstr('1P:WASD\t2P:UpDownLeftRight\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('r'): return 'Restart' if action == ord('q'): return 'Exit' if action == ord('w'): return 'Up1' if action == ord('s'): return 'Down1' if action == ord('a'): return 'Left1' if action == ord('d'): return 'Right1' # 主函数 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=32) status = 'Init' while status != "Exit": status = status_filed[status]() curses.wrapper(main)
胜利条件为32 时一方先达到32获胜:
胜利条件为2048时均为达到2048比较分数高的获胜:
***THE END***