我初学python,有不对之处望大家指教。转载请征得同意。

  我在网络上也找了一些2048游戏代码的讲解,但都不是特别详细。所以我希望能够尽量详细的讲解。同时,有的地方我也不懂,希望大家能帮助补充。我会随时更新以方便后来者。

  当然,需要一定的python基础再看此实例。

  1. #-*- coding:utf-8 -*-
  2.  
  3. import curses
  4. from random import randrange, choice
  5. from collections import defaultdict
  6. # 引入3个扩展包
  7.  
  8. letter_codes = [ord(ch) for ch in 'WASDRQwasdrq']
  9. actions = ['Up', 'Left', 'Down', 'Right', 'Restart', 'Exit']
  10. actions_dict = dict(zip(letter_codes, actions * 2))
  11. # 创建我们将要用的键盘输入字典,这个字典将在后边通过第18行的
  12. # keyboard.getch()
  13. # 而这个方法被封装成一个函数,调用函数以实现该方法。
  14.  
  15. def get_user_action(keyboard):
  16. char = "N"
  17. while char not in actions_dict:
  18. char = keyboard.getch()
  19. return actions_dict[char]
  20. # 键盘输入以匹配字典的方法
  21.  
  22. def transpose(field):
  23. return [list(row) for row in zip(*field)]
  24. # 矩阵转置,
  25. # 这是一个数学方法,如望详细了解,请先了解矩阵
  26. # 对于初学者,比较推荐暂时忽略。
  27.  
  28. def invert(field):
  29. return [row[::-1] for row in field]
  30. # 矩阵逆转,同上
  31.  
  32. class GameField(object):
  33. def __init__(self, height=4, width=4, win=2048):
  34. self.height = height
  35. self.width = width
  36. self.win_value = 2048
  37. self.score = 0
  38. self.highscore = 0
  39. self.reset()
  40. # 定义类的__init__方法,为初始化方法
  41.  
  42. def reset(self):
  43. if self.score > self.highscore:
  44. self.highscore = self.score
  45. self.score = 0
  46. self.field = [[0 for i in range(self.width)] for j in range(self.height)]
  47. self.spawn()
  48. self.spawn()
  49. # 重置方法,虽然命名为reset,但是初始化也同样使用该方法。
  50. # 如果你觉得命名为set更合适,请改为set。
  51. # 这个方法中使用了spawn()函数,这个函数放在了后边,
  52. # spawn()函数的功能是生成新的数字,reset()需要生成两次。
  53.  
  54. def move(self, direction):
  55. # 最重要的3个函数之一
  56. def move_row_left(row):
  57. def tighten(row):
  58. new_row = [i for i in row if i != 0]
  59. new_row += [0 for i in range(len(row) - len(new_row))]
  60. return new_row
  61.  
  62. def merge(row):
  63. pair = False
  64. new_row = []
  65. for i in range(len(row)):
  66. if pair:
  67. new_row.append(2 * row[i])
  68. self.score += 2 * row[i]
  69. pair = False
  70. else:
  71. if i + 1 < len(row) and row[i] == row[i + 1]:
  72. pair = True
  73. new_row.append(0)
  74. else:
  75. new_row.append(row[i])
  76. assert len(new_row) == len(row)
  77. return new_row
  78. return tighten(merge(tighten(row)))
  79. #这里可以有不同的写法,就是tighten一次,merge一次。在merge的时候没必要加0了。
  80. # 欢迎大家把好的方法发给我,谢谢。http://www.cnblogs.com/danjawwi/
  81. # def merge(row):
  82. # pair = False
  83. # new_row = []
  84. # for i in range(len(row)):
  85. # if pair:
  86. # new_row.append(2 * row[i])
  87. # self.score += 2 * row[i]
  88. # pair = False
  89. # else:
  90. # if i + 1 < len(row) and row[i] == row[i + 1]:
  91. # pair = True
  92. # else:
  93. # new_row.append(row[i])
  94. # new_row += [0 for j in range(len(row) - len(new_row))]
  95. # return new_row
  96. #
  97. # return merge(tighten(row))
  98.  
  99. moves = {}
  100. moves['Left'] = lambda field: \
  101. [move_row_left(row) for row in field]
  102. moves['Right'] = lambda field: \
  103. invert(moves['Left'](invert(field)))
  104. moves['Up'] = lambda field: \
  105. transpose(moves['Left'](transpose(field)))
  106. moves['Down'] = lambda field: \
  107. transpose(moves['Right'](transpose(field)))
  108. # 这里把row的迭代放在了方法外边,在对应字典值这里实现了。也可以放在方法里边
  109.  
  110. if direction in moves:
  111. if self.move_is_possible(direction):
  112. self.field = moves[direction](self.field)
  113. self.spawn()
  114. return True
  115. else:
  116. return False
  117.  
  118. def is_win(self):
  119. return any(any(i >= self.win_value for i in row) for row in self.field)
  120. #判断是否赢
  121.  
  122. def is_gameover(self):
  123. return not any(self.move_is_possible(move) for move in actions)
  124. # 判断是否输
  125.  
  126. def draw(self, screen):
  127. # 最重要的3个函数之一
  128. help_string1 = '(W)Up (S)Down (A)Left (D)Right'
  129. help_string2 = ' (R)Restart (Q)Exit'
  130. gameover_string = ' GAME OVER'
  131. win_string = ' YOU WIN!'
  132. def cast(string):
  133. screen.addstr(string + '\n')
  134.  
  135. def draw_hor_separator():
  136. line = '+' + ('+------' * self.width + '+')[1:]
  137. #不明白为什么这里要这样写
  138. #直接line = '+------' * self.width + '+' 不行吗?
  139. #http://www.cnblogs.com/danjawwi/
  140.  
  141. separator = defaultdict(lambda: line)
  142. if not hasattr(draw_hor_separator, "counter"):
  143. draw_hor_separator.counter = 0
  144. cast(separator[draw_hor_separator.counter])
  145. draw_hor_separator.counter += 1
  146. #这里我也不明白,直接根据self.height输出不就行了?
  147.  
  148. def draw_row(row):
  149. cast(''.join('|{: ^5} '.format(num) if num > 0 else '| ' for num in row) + '|')
  150. #用到了join 和 format这两种方法。
  151. screen.clear()
  152. cast('SCORE: ' + str(self.score))
  153. if 0 != self.highscore:
  154. cast('HGHSCORE: ' + str(self.highscore))
  155. for row in self.field:
  156. draw_hor_separator()
  157. draw_row(row)
  158. draw_hor_separator()
  159. if self.is_win():
  160. cast(win_string)
  161. else:
  162. if self.is_gameover():
  163. cast(gameover_string)
  164. else:
  165. cast(help_string1)
  166. cast(help_string2)
  167.  
  168. def spawn(self):
  169. new_element = 4 if randrange(100) > 89 else 2
  170. (i,j) = choice([(i,j) for i in range(self.width) for j in range(self.height) if self.field[i][j] == 0])
  171. self.field[i][j] = new_element
  172. #迭代器既可以根据层级来进行迭代,也可以在同层中迭代两次
  173.  
  174. def move_is_possible(self, direction):
  175. # 最重要的3个函数之一
  176. def row_is_left_movable(row):
  177. def change(i):
  178. if row[i] == 0 and row[i + 1] != 0:
  179. # 这里是不是在说None != 0 ?
  180. return True
  181. if row[i] != 0 and row[i + 1] == row[i]:
  182. return True
  183. return False
  184. return any(change(i) for i in range(len(row) - 1))
  185.  
  186. check = {}
  187. check['Left'] = lambda field: \
  188. any(row_is_left_movable(row) for row in field)
  189.  
  190. check['Right'] = lambda field: \
  191. check['Left'](invert(field))
  192.  
  193. check['Up'] = lambda field: \
  194. check['Left'](transpose(field))
  195.  
  196. check['Down'] = lambda field: \
  197. check['Right'](transpose(field))
  198.  
  199. if direction in check:
  200. return check[direction](self.field)
  201. else:
  202. return False
  203.  
  204. def main(stdscr):
  205. def init():
  206. game_field.reset()
  207. return 'Game'
  208.  
  209. def not_game(state):
  210. game_field.draw(stdscr)
  211. action = get_user_action(stdscr)
  212. responses = defaultdict(lambda: state)
  213. responses['Restart'], responses['Exit'] = 'Init', 'Exit'
  214. return responses[action]
  215.  
  216. def game():
  217. game_field.draw(stdscr)
  218. action = get_user_action(stdscr)
  219.  
  220. if action == 'Restart':
  221. return 'Init'
  222. if action == 'Exit':
  223. return 'Exit'
  224. if game_field.move(action):
  225. if game_field.is_win():
  226. return 'Win'
  227. if game_field.is_gameover():
  228. return 'Gameover'
  229. return 'Game'
  230.  
  231. state_actions = {
  232. 'Init': init,
  233. 'Win': lambda: not_game('Win'),
  234. 'Gameover': lambda: not_game('Gameover'),
  235. 'Game': game
  236. }
  237.  
  238. curses.use_default_colors()
  239. game_field = GameField(win=32)
  240.  
  241. state = 'Init'
  242.  
  243. while state != 'Exit':
  244. state = state_actions[state]()
  245.  
  246. curses.wrapper(main)

[python] python实现2048游戏,及代码解析。的更多相关文章

  1. Python中sort和sorted函数代码解析

    Python中sort和sorted函数代码解析 本文研究的主要是Python中sort和sorted函数的相关内容,具体如下. 一.sort函数 sort函数是序列的内部函数 函数原型: L.sor ...

  2. 「Python实用秘技08」一行代码解析地址信息

    本文完整示例代码及文件已上传至我的Github仓库https://github.com/CNFeffery/PythonPracticalSkills 这是我的系列文章「Python实用秘技」的第8期 ...

  3. 用Python做2048游戏 网易云课堂配套实验课。通过GUI来体验编程的乐趣。

    第1节 认识wxpython 第2节 画几个形状 第3节 再做个计算器 第4节 最后实现个2048游戏 实验1-认识wxpython 一.实验说明 1. 环境登录 无需密码自动登录,系统用户名shiy ...

  4. 通过游戏学python 3.6 第一季 第九章 实例项目 猜数字游戏--核心代码--猜测次数--随机函数和屏蔽错误代码--优化代码及注释--简单账号密码登陆--账号的注册查询和密码的找回修改--锁定账号--锁定次数--菜单功能'menufile

      通过游戏学python 3.6 第一季 第九章 实例项目 猜数字游戏--核心代码--猜测次数--随机函数和屏蔽错误代码--优化代码及注释--简单账号密码登陆--账号的注册查询和密码的找回修改--锁 ...

  5. 通过游戏学python 3.6 第一季 第八章 实例项目 猜数字游戏--核心代码--猜测次数--随机函数和屏蔽错误代码--优化代码及注释--简单账号密码登陆--账号的注册查询和密码的找回修改--锁定账号--锁定次数

    通过游戏学python 3.6 第一季 第八章 实例项目 猜数字游戏--核心代码--猜测次数--随机函数和屏蔽错误代码--优化代码及注释--简单账号密码登陆--账号的注册查询和密码的找回修改--锁定账 ...

  6. 通过游戏学python 3.6 第一季 第三章 实例项目 猜数字游戏--核心代码--猜测次数--随机函数和屏蔽错误代码 可复制直接使用 娱乐 可封装 函数

       猜数字游戏--核心代码--猜测次数--随机函数和屏蔽错误代码   #猜数字--核心代码--猜测次数--随机函数和屏蔽错误代码 import random secrst = random.rand ...

  7. 通过游戏学python 3.6 第一季 第二章 实例项目 猜数字游戏--核心代码--猜测次数 可复制直接使用 娱乐 可封装 函数

      猜数字游戏--核心代码--猜测次数   #猜数字--核心代码--猜测次数 number=33 amount=3 count=0 while count<=amount: conversion ...

  8. python 2048游戏控制器

    2048游戏控制器 1 evaluate 要用程序来处理就得对现实的问题进行量化,用数字来表示.在2048游戏中,我们的输入是一个棋局,让我们输出一个移动方向,这样我们需要对棋局进行量化,即我们要评估 ...

  9. Python之字符串小代码解析

    本篇只是拿一段代码来对python中的字符串的一些使用做解释,来让大家更加了解python Python 3.4.0 (v3.4.0:04f714765c13, Mar 16 2014, 19:25: ...

随机推荐

  1. linux内核调试技巧之addr2line

    addr2line工具是一个可以将指令的地址和可执行影像转换为文件名,函数名和源代码行数的工具.这在内核执行过程中出现崩溃时,可用于快速定位出出错的位置,进而找出代码的bug. 用法 addr2lin ...

  2. NGUI的localPosition和Position之间的关系

    假设有子节点为child, 父节点为parent, 且都是Transform类型. 则: child.localPosition = (child.position - parent.position ...

  3. JNI支持C++与C的区别

    1. C++的代码后缀是".cpp" 2. 在JNI.h 文件中有两套代码.一套是支持c的, 一套是支持JNI的. JNI.h地址:mac ▸ 用户 ▸ douj ▸ Docume ...

  4. su with hyphen and without - su带横杠和不带横杠

    The difference between "-" and "no hyphen" is that the latter keeps your existin ...

  5. ie8用ajax访问不能每次都刷新的问题

    最近发现,用ajax访问后台,用ie8访问,第一次可以正常返回值,后面就一直不会执行后台,总是返回第一次访问的结果. 用ie9,ie10等都没问题,chrome,等浏览器也没有问题. 测试后发现,是i ...

  6. 查看SQLServer最耗资源时间的SQL语句

    执行最慢的SQL语句 SELECT (total_elapsed_time / execution_count)/1000 N'平均时间ms' ,total_elapsed_time/1000 N'总 ...

  7. Chrome 没有注册类

    妈蛋这个问题折腾了好久,百度都是噼里啪啦什么什么进入注册表什么的删除啊 操  看着难受死了 这边也有这个些 没有注册类原因什么的的百度一下就有了 解决办法 管理员身份运行CMD 输入 REG DELE ...

  8. FIS

    学习官网 http://fis.baidu.com/docs/beginning/getting-started.html   1. fis release: 编译并发布     fis releas ...

  9. 安装spf13-vim on Windows10

    安装之前 1.系统为 windows10  Version 1607 64位 企业版 2.参考 http://www.codeweblog.com/gvim-64%E4%BD%8D-windows-7 ...

  10. 查看python api

    以下方法可以查看python 的api,包括selenium webdriver,requests等 1.cmd进入dos命令行窗口,输入python -m pydoc -p 2345   (2345 ...