本文是在200 行 Python 代码实现 2048的功能基础上进行的拓展功能开发

具体增加功能如下:

1.增加支持方向键
2.达到胜利分数值可以选择继续游戏或者结束游戏
3.在控制台输出不同的颜色
4.连接sqlite,将最高成绩存入其中,每次启动游戏时读取

完整代码如下:

#-*- coding:utf-8 -*-import curses
from random import randrange, choice # generate and place new tile
from collections import defaultdict
from itertools import chain
import sqlite3
from colorama import initinit(autoreset=True)#有效健值列表
letter_codes = [ord(ch) for ch in 'WASDRQYwasdrqy']
#print(letter_codes)#打印结果为WASDRQwasdrq对应的ascii码
letter_list=[259,260,258,261,10,27,121]#上左下右EscEnterY键对应的ascii码,通过get_user_action中的char来获取
letter_codes=letter_codes+letter_list#用户行为
actions = ['Up', 'Left', 'Down', 'Right', 'Restart', 'Exit','Continue']
#将输入与行为进行关联
actions_dict = dict(zip(letter_codes, actions * 3))#sqlite数据库操作,读取最高分数
class sqliteOperate():def __init__(self):self.conn=sqlite3.connect('2048.db')def select(self):score=self.conn.execute("select SCORE from HighScore")for row in score:return row[0]def update(self,score):self.conn.execute("update HighScore set SCORE ={0} where ID=1".format(score))self.conn.commit()self.conn.close() sqliteoperate=sqliteOperate()
Highscore=sqliteoperate.select()#用户输入处理
def get_user_action(keyboard):    char = "N"#阻塞+循环,直到获得用户有效输入才返回对应行为while char not in actions_dict:    char = keyboard.getch()#从控制台读取一个字符,但不显示在屏幕上
#         print(char)#通过这里打印对应按键的数字找到上下左右等按键的对应的ascii码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]#创建棋盘
class GameField(object):def __init__(self, height=4, width=4, win=8):self.height=height #高self.width=width  #宽self.win_value=8   #过关分数self.score=0   #当前分数self.highscore=Highscore  #从数据库获取最高分self.reset()   #棋盘重置##重置棋盘def reset(self):if self.score > self.highscore:self.highscore = self.scoresqliteoperate.update(self.highscore) self.score = 0        self.field = [[0 for i in range(self.width)] for j in range(self.height)]#创建一个4*4值全为0的二维数组self.spawn()#棋盘上初始状态显示2个数字,随机生成两个数字,调两次spawn方法self.spawn()def move(self, direction):#一行向左合并   def move_row_left(row):def tighten(row): #squeese non-zero elements together#把零散的非零单元挤到一块,先打印出非零的元素,然后在后面空白位置补0new_row = [i for i in row if i != 0]new_row += [0 for i in range(len(row) - len(new_row))]return new_rowdef merge(row):#对邻近元素进行合并pair = Falsenew_row = []for i in range(len(row)):if pair:new_row.append(2 * row[i])self.score += 2 * row[i]pair = Falseelse:if i + 1 < len(row) and row[i] == row[i + 1]:pair = Truenew_row.append(0)else:new_row.append(row[i])assert len(new_row) == len(row)#assert断言是声明其布尔值必须为真的判定,如果发生异常就说明表达示为假return new_row#先挤到一块再合并再挤到一起return tighten(merge(tighten(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:if self.move_is_possible(direction):self.field = moves[direction](self.field)self.spawn()return Trueelse:return Falsedef is_win(self):#any(x)判断x对象是否为空对象,如果都为空、0、false,则返回false,如果不都为空、0、false,则返回true#遍历每个元素查看是否大于win_value
#         return any(any(i >= self.win_value for i in row) for row in self.field)#找出当前二维数组中的最大值与win_value比较#chain把二维数组转化成序列
#         print(max(chain(*self.field)),self.win_value)return max(chain(*self.field))>=self.win_valuedef is_gameover(self):#所有的行都不能移动则游戏结束return not any(self.move_is_possible(move) for move in actions)def draw(self, screen):
#         init(autoreset=True)help_string1 = '(↑)Up(↓)Down(←)Left(→)Right'help_string2 = '   (Enter)Restart (Esc)Exit'help_string3 = '(Enter)Restart(Y)Continue(Esc)Exit'gameover_string = '           GAME OVER'win_string = '          YOU WIN!'           def set_color():#设置颜色#使用颜色首先需要调用这个方法curses.start_color()    #文字和背景色设置,设置了三个color pair,分别为1,2,3curses.init_pair(1,curses.COLOR_YELLOW,curses.COLOR_BLACK)curses.init_pair(2,curses.COLOR_GREEN,curses.COLOR_BLACK)curses.init_pair(3,curses.COLOR_RED,curses.COLOR_BLACK)def cast(string):#绘制字符串
#             screen.addstr(string+ '\n')     set_color()screen.addstr(string+ '\n',curses.color_pair(1))def cast2(string):#绘制字符串 ,成功时显示绿色的提示语
#             curses.start_color()set_color()screen.addstr(string+ '\n',curses.color_pair(2))def cast3(string):#将分数和最高分显示为红色
#             curses.start_color()set_color()screen.addstr(string+ '\n',curses.color_pair(3))def draw_hor_separator():#绘制分割线
#             line = '+' + ('+------' * self.width + '+')[1:]line =  ('+------' * self.width + '+')separator = defaultdict(lambda: line)#创建一个字典,默认值为lineif not hasattr(draw_hor_separator, "counter"):#hasattr判断draw_hor_separator对象中是否存在counter属性,有为True,没有Falsedraw_hor_separator.counter = 0cast(separator[draw_hor_separator.counter])draw_hor_separator.counter += 1def draw_row(row):#绘制包含数字的行#^是居中显式,<是左对齐,>是右对齐,冒号后面有一个空格,意思是空格填充#如果单元格中数字大于0,则将该数字格式化为居中显示,否者仅打印斜杠和空格cast(''.join('|{: ^5} '.format(num) if num > 0 else '|      ' for num in row) + '|')screen.clear()cast3('SCORE: ' + str(self.score))#绘制当前分数cast3('HIGHSCORE: ' + str(self.highscore))#绘制当前最高分数
#         if 0 != self.highscore:#绘制最高分
#             cast('HIGHSCORE: ' + str(self.highscore))for row in self.field:#遍历二维数组绘制4*4棋盘draw_hor_separator()draw_row(row)draw_hor_separator()if self.is_win():cast2(win_string)cast(help_string3)else:if self.is_gameover():cast(gameover_string)else:cast(help_string1)cast(help_string2)def spawn(self):new_element = 4 if randrange(100) > 89 else 2#9:1的比例生成2或4#通过choice随机选择一个未被占领的位置来放置new_element(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_elementdef move_is_possible(self, direction):def row_is_left_movable(row): def change(i): # true if there'll be change in i-th tileif row[i] == 0 and row[i + 1] != 0: # Movereturn Trueif row[i] != 0 and row[i + 1] == row[i]: # Mergereturn Truereturn Falsereturn 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 Falsedef main(stdscr):#stdscr由curses传入,主要用于命令行的操作def init():#重置游戏棋盘game_field.reset()return 'Game'def not_game(state):#胜利或失败的状态#画出 GameOver 或者 Win 的界面game_field.draw(stdscr)#读取用户输入得到action,判断是重启游戏还是结束游戏action = get_user_action(stdscr)responses = defaultdict(lambda: state) #默认是当前状态,没有行为就会一直在当前界面循环responses['Restart'], responses['Exit'],responses['Continue'] = 'Init', 'Exit','Continue' #对应不同的行为转换到不同的状态return responses[action]def game():#画出当前棋盘状态game_field.draw(stdscr)#读取用户输入得到actionaction = get_user_action(stdscr)if action == 'Restart':return 'Init'if action == 'Exit':return 'Exit'if game_field.move(action): # move successfulif game_field.is_win():if action=='Continue':return 'Continue'else:return 'Win'if game_field.is_gameover():return 'Gameover'return 'Game'    def game_suc():#画出游戏成功后当前棋盘状态game_field.draw(stdscr)#读取用户输入得到actionaction = get_user_action(stdscr)if action == 'Restart':return 'Init'if action == 'Exit':return 'Exit'if game_field.move(action): # move successful            return 'GameSuc'return 'GameSuc'def game_continue():#达到胜利分数值选择继续游戏game_field.draw(stdscr)
#         #读取用户输入得到actionaction = get_user_action(stdscr)if game_field.move(action): # move successfulif game_field.is_gameover():return 'Gameover'else: return 'GameSuc'return 'GameSuc'state_actions = {'Init': init,'Win': lambda: not_game('Win'),'Gameover': lambda: not_game('Gameover'),'Game': game,'Continue':game_continue,'GameSuc':game_suc            }curses.use_default_colors()# 设置终结状态最大数值为 8game_field = GameField(win=8)state = 'Init'#状态机开始循环while state != 'Exit':state = state_actions[state]()#curses库提供了控制字符屏幕的独立于终端的方法
#不能用任何IDE来运行有curses包的python文件,否则提示Redirection is not supported.
curses.wrapper(main) #初始化curses

运行结果

初始化页面:

胜利页面:

用面向对象方法重构代码

#-*- coding:utf-8 -*-import curses
from random import randrange, choice # generate and place new tile
from collections import defaultdict
from itertools import chain
import sqlite3
from colorama import initclass Action():#有效健值列表letter_codes = [ord(ch) for ch in 'WASDRQYwasdrqy']#print(letter_codes)#打印结果为WASDRQwasdrq对应的ascii码letter_list=[259,260,258,261,10,27,121]#上左下右EscEnterY键对应的ascii码,通过get_user_action中的char来获取letter_codes=letter_codes+letter_list#用户行为actions = ['Up', 'Left', 'Down', 'Right', 'Restart', 'Exit','Continue']#将输入与行为进行关联actions_dict = dict(zip(letter_codes, actions * 3))def __init__(self):pass#用户输入处理def get_user_action(self,keyboard):    char = "N"#阻塞+循环,直到获得用户有效输入才返回对应行为while char not in self.actions_dict:    char = keyboard.getch()#从控制台读取一个字符,但不显示在屏幕上#         print(char)#通过这里打印对应按键的数字找到上下左右等按键的对应的ascii码return self.actions_dict[char]#sqlite数据库操作,读取最高分数
class sqliteOperate():def __init__(self):self.conn=sqlite3.connect('2048.db')def select(self):score=self.conn.execute("select SCORE from HighScore")for row in score:return row[0]def update(self,score):self.conn.execute("update HighScore set SCORE ={0} where ID=1".format(score))self.conn.commit()self.conn.close() #创建棋盘
class GameField(object):def __init__(self, height=4, width=4,win=0):self.height=height #高self.width=width  #宽self.win_value=win  #过关分数self.score=0   #当前分数self.highscore=Highscore  #从数据库获取最高分self.reset()   #棋盘重置self.action=Action()#如果该方法没有引用对象的资源,可以采用静态方法,并且不需要传入self@staticmethod#矩阵转置,行和列的转换def transpose(field):return [list(row) for row in zip(*field)]@staticmethod#矩阵逆转,每行倒着排列def invert(field):return [row[::-1] for row in field]#重置棋盘def reset(self):if self.score > self.highscore:self.highscore = self.scoresqliteoperate.update(self.highscore) #更新数据库中的最高分self.score = 0        self.field = [[0 for i in range(self.width)] for j in range(self.height)]#创建一个4*4值全为0的二维数组self.spawn()#棋盘上初始状态显示2个数字,随机生成两个数字,调两次spawn方法self.spawn()def spawn(self):new_element = 4 if randrange(100) > 89 else 2#9:1的比例生成2或4#通过choice随机选择一个未被占领的位置来放置new_element(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_elementdef move(self, direction):#一行向左合并   def move_row_left(row):def tighten(row): #squeese non-zero elements together#把零散的非零单元挤到一块,先打印出非零的元素,然后在后面空白位置补0new_row = [i for i in row if i != 0]new_row += [0 for i in range(len(row) - len(new_row))]return new_rowdef merge(row):#对邻近元素进行合并pair = Falsenew_row = []for i in range(len(row)):if pair:new_row.append(2 * row[i])self.score += 2 * row[i]pair = Falseelse:if i + 1 < len(row) and row[i] == row[i + 1]:pair = Truenew_row.append(0)else:new_row.append(row[i])assert len(new_row) == len(row)#assert断言是声明其布尔值必须为真的判定,如果发生异常就说明表达示为假return new_row#先挤到一块再合并再挤到一起return tighten(merge(tighten(row)))moves = {}moves['Left']  = lambda field:                              \[move_row_left(row) for row in field]moves['Right'] = lambda field:                              \self.invert(moves['Left'](self.invert(field)))moves['Up']    = lambda field:                              \self.transpose(moves['Left'](self.transpose(field)))moves['Down']  = lambda field:                              \self.transpose(moves['Right'](self.transpose(field)))if direction in moves:if self.move_is_possible(direction):self.field = moves[direction](self.field)self.spawn()return Trueelse:return Falsedef move_is_possible(self, direction):def row_is_left_movable(row): def change(i): # true if there'll be change in i-th tileif row[i] == 0 and row[i + 1] != 0: # Movereturn Trueif row[i] != 0 and row[i + 1] == row[i]: # Mergereturn Truereturn Falsereturn 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'](self.invert(field))check['Up']    = lambda field:                              \check['Left'](self.transpose(field))check['Down']  = lambda field:                              \check['Right'](self.transpose(field))if direction in check:return check[direction](self.field)else:return False       def is_win(self):#any(x)判断x对象是否为空对象,如果都为空、0、false,则返回false,如果不都为空、0、false,则返回true#遍历每个元素查看是否大于win_value
#         return any(any(i >= self.win_value for i in row) for row in self.field)#找出当前二维数组中的最大值与win_value比较#chain把二维数组转化成序列
#         print(max(chain(*self.field)),self.win_value)return max(chain(*self.field))>=self.win_value        def is_gameover(self):#所有的行都不能移动则游戏结束return not any(self.move_is_possible(move) for move in self.action.actions)def draw(self, screen):     def set_color():#设置颜色#使用颜色首先需要调用这个方法curses.start_color()    #文字和背景色设置,设置了三个color pair,分别为1,2,3curses.init_pair(1,curses.COLOR_YELLOW,curses.COLOR_BLACK)curses.init_pair(2,curses.COLOR_GREEN,curses.COLOR_BLACK)curses.init_pair(3,curses.COLOR_RED,curses.COLOR_BLACK)def cast(string):#绘制字符串
#             screen.addstr(string+ '\n')     set_color()screen.addstr(string+ '\n',curses.color_pair(1))def cast2(string):#绘制字符串 ,成功时显示绿色的提示语     set_color()screen.addstr(string+ '\n',curses.color_pair(2))def cast3(string):#将分数和最高分显示为红色   set_color()screen.addstr(string+ '\n',curses.color_pair(3))def draw_row(row):#绘制包含数字的行#^是居中显式,<是左对齐,>是右对齐,冒号后面有一个空格,意思是空格填充#如果单元格中数字大于0,则将该数字格式化为居中显示,否者仅打印斜杠和空格cast(''.join('|{: ^5} '.format(num) if num > 0 else '|      ' for num in row) + '|')help_string1 = '(↑)Up(↓)Down(←)Left(→)Right'help_string2 = '   (Enter)Restart (Esc)Exit'help_string3 = '(Enter)Restart(Y)Continue(Esc)Exit'gameover_string = '           GAME OVER'win_string = '          YOU WIN!'      screen.clear()cast3('SCORE: ' + str(self.score))#绘制当前分数cast3('HIGHSCORE: ' + str(self.highscore))#绘制当前最高分数for row in self.field:cast('+------' * self.width + '+')draw_row(row)cast('+------' * self.width + '+')        if self.is_win():cast2(win_string)cast(help_string3)else:if self.is_gameover():cast(gameover_string)else:cast(help_string1)cast(help_string2)def main(stdscr):#stdscr由curses传入,主要用于命令行的操作def init():#重置游戏棋盘game_field.reset()return 'Game'def not_game(state):#胜利或失败的状态#画出 GameOver 或者 Win 的界面game_field.draw(stdscr)#读取用户输入得到action,判断是重启游戏还是结束游戏action = actionoperate.get_user_action(stdscr)responses = defaultdict(lambda: state) #默认是当前状态,没有行为就会一直在当前界面循环responses['Restart'], responses['Exit'],responses['Continue'] = 'Init', 'Exit','Continue' #对应不同的行为转换到不同的状态return responses[action]def game():#画出当前棋盘状态game_field.draw(stdscr)#读取用户输入得到actionaction = actionoperate.get_user_action(stdscr)if action == 'Restart':return 'Init'if action == 'Exit':return 'Exit'if game_field.move(action): # move successfulif game_field.is_win():if action=='Continue':return 'Continue'else:return 'Win'if game_field.is_gameover():return 'Gameover'return 'Game'    def game_suc():#画出游戏成功后当前棋盘状态game_field.draw(stdscr)#读取用户输入得到actionaction = actionoperate.get_user_action(stdscr)if action == 'Restart':return 'Init'if action == 'Exit':return 'Exit'if game_field.move(action): # move successful            return 'GameSuc'return 'GameSuc'def game_continue():#达到胜利分数值选择继续游戏game_field.draw(stdscr)
#         #读取用户输入得到actionaction = actionoperate.get_user_action(stdscr)if game_field.move(action): # move successfulif game_field.is_gameover():return 'Gameover'else: return 'GameSuc'return 'GameSuc'state_actions = {'Init': init,'Win': lambda: not_game('Win'),'Gameover': lambda: not_game('Gameover'),'Game': game,'Continue':game_continue,'GameSuc':game_suc            }#     curses.use_default_colors()# 设置终结状态最大数值为 8game_field = GameField(win=8)actionoperate=Action()state = 'Init'#状态机开始循环while state != 'Exit':state = state_actions[state]()sqliteoperate=sqliteOperate()
Highscore=sqliteoperate.select()
#curses库提供了控制字符屏幕的独立于终端的方法
#不能用任何IDE来运行有curses包的python文件,否则提示Redirection is not supported.
curses.wrapper(main) #初始化curses

Python代码实现2048-功能拓展相关推荐

  1. Python实战2 - 200行Python代码实现2048(控制台)

    Python实战系列用于记录实战项目中的思路,代码实现,出现的问题与解决方案以及可行的改进方向 本文为第2篇–200行Python代码实现2048 一.分析与函数设计 1.1 游戏玩法 2048这款游 ...

  2. python200行代码小游戏_200 行python 代码实现 2048 游戏

    创建游戏文件 2048.py 首先导入需要的包: import curses from random import randrange, choice from collections import ...

  3. python200行代码_200行Python代码实现2048

    200行Python代码实现2048 一.实验说明 1. 环境登录 无需密码自动登录,系统用户名shiyanlou 2. 环境介绍 本实验环境采用带桌面的Ubuntu Linux环境,实验中会用到桌面 ...

  4. python执行效果_使用tqdm显示Python代码执行进度功能

    在使用Python执行一些比较耗时的操作时,为了方便观察进度,通常使用进度条的方式来可视化呈现.Python中的tqdm就是用来实现此功能的. 先来看看tqdm的进度条效果: tqdm的基本用法 tq ...

  5. python游戏代码五子棋_用20行Python代码实现2048小游戏,你会吗?

    前些天在b站上看到有个大佬用c写了一个2048小游戏,我便一下来了兴趣.心想着,我貌似也能用Python来整一波,话不多说,直接开搞. 2048的游戏规则: 2048游戏总共有16个格子,初始时会有两 ...

  6. python秒表游戏代码_用20行Python代码实现2048小游戏,你会吗?

    前些天在b站上看到有个大佬用c写了一个2048小游戏,我便一下来了兴趣.心想着,我貌似也能用Python来整一波,话不多说,直接开搞. 2048的游戏规则: 2048游戏总共有16个格子,初始时会有两 ...

  7. python代码200行左右_200行Python代码实现2048

    import curses from random import randrange,chioce from collections import defaultdict actions=['Up', ...

  8. 详解200行Python代码实现控制台版2048【总有一款坑适合你】【超详细】

    跟着实验楼学习了2048的Python实现,先丢个地址 200行Python代码实现2048 我接触Python时间不长,只了解一些基本的语法和容器,在学习的过程中遇到不少问题,这里做一个记录. cu ...

  9. python调用计算器卡死_Python+tkinter使用40行代码实现计算器功能

    本文实例为大家分享了40行Python代码实现计算器功能,供大家参考,具体内容如下 偶尔用脚本写点东西也是不错的. 效果图 代码 from tkinter import * reset=True de ...

最新文章

  1. [日推荐]『保养汽车』爱车的专职管家
  2. 以咨询顾问为我终生职业(转)
  3. 使用js实现时钟效果
  4. linux php应用多台服务器架构,Nginx+PHP-FPM在两台服务器实现
  5. 浅析ASP.NET页面缓存的几点体会
  6. 脚本启动Tomcat
  7. 【Pytorch】Pytorch的自动混合精度(AMP)
  8. CreateThread用法详解
  9. C#基础4:函数+ref和out参数
  10. 深度学习之卷积神经网络CNN及tensorflow代码实现示例详细介绍(转载)
  11. 【z变换】2. z变换的性质
  12. 谷歌浏览器打不开网页
  13. java 出路 xls_java读取excel之xlsl超大文件
  14. 技术博客对找工作有帮助吗?
  15. 思维模型 波士顿矩阵
  16. 社区中无法创建帖子chatter
  17. P205-下载xkcd漫画
  18. HDU4324 - Triangle LOVE 拓补排序
  19. 818打响,家电第一渠道苏宁下一步目标是什么?
  20. Java读取hdfs文件权限问题

热门文章

  1. CXM百科 | 那些年我们做过的问卷题——评分量表题
  2. 净空法师:同修净土与般若
  3. 个人收藏的Java网站【偷偷收藏】
  4. 【记录一次nginx转发 80端口无效】
  5. 北航软件测试与质量管理,北航软件学院质量与测试专业.doc
  6. KLAY 2000-SAN-2-W-HT
  7. 优信拍集团php面试题_【优信拍PHP高级工程师面试】不错,主管眼光很犀利,而且不扯皮。-看准网...
  8. Android 预装APK
  9. JAVA通过拦截器实现IP黑名单
  10. 明翰Java教学系列之认识Java篇V1.3(持续更新)