最近在学Python,想做点什么来练练手,命令行的贪吃蛇一般是C的练手项目,但是一时之间找不到别的,就先做个贪吃蛇来练练简单的语法。

  由于Python监听键盘很麻烦,没有C语言的kbhit(),所以这条贪吃蛇不会自己动,运行效果如下:

  

要求:用#表示边框,用*表示食物,o表示蛇的身体,O表示蛇头,使用wsad来移动

Python版本:3.6.1

系统环境:Win10

类:

  board:棋盘,也就是游戏区域

  snake:贪吃蛇,通过记录身体每个点来记录蛇的状态

  game:游戏类

  本来还想要个food类的,但是food只需要一个坐标,和一个新建,所以干脆使用list来保存坐标,新建food放在game里面,从逻辑上也没有太大问题

源码

  1. # Write By Guobao
  2. # 2017/4//7
  3. #
  4. # 贪吃蛇
  5. # 用#做边界,*做食物,o做身体和头部
  6. # python 3.6.1
  7.  
  8. import copy
  9. import random
  10. import os
  11. import msvcrt
  12.  
  13. # the board class, used to put everything
  14. class board:
  15.  
  16. __points =[]
  17.  
  18. def __init__(self):
  19. self.__points.clear()
  20. for i in range(22):
  21. line = []
  22. if i == 0 or i == 21:
  23. for j in range(22):
  24. line.append('#')
  25. else:
  26. line.append('#')
  27. for j in range(20):
  28. line.append(' ')
  29. line.append('#')
  30. self.__points.append(line)
  31.  
  32. def getPoint(self, location):
  33. return self.__points[location[0]][location[1]]
  34.  
  35. def clear(self):
  36. self.__points.clear()
  37. for i in range(22):
  38. line = []
  39. if i == 0 or i == 21:
  40. for j in range(22):
  41. line.append('#')
  42. else:
  43. line.append('#')
  44. for j in range(20):
  45. line.append(' ')
  46. line.append('#')
  47. self.__points.append(line)
  48.  
  49. def put_snake(self, snake_locations):
  50. # clear the board
  51. self.clear()
  52.  
  53. # put the snake points
  54. for x in snake_locations:
  55. self.__points[x[0]][x[1]] = 'o'
  56.  
  57. # the head
  58. x = snake_locations[len(snake_locations) - 1]
  59. self.__points[x[0]][x[1]] = 'O'
  60.  
  61. def put_food(self, food_location):
  62. self.__points[food_location[0]][food_location[1]] = '*'
  63.  
  64. def show(self):
  65. os.system("cls")
  66. for i in range(22):
  67. for j in range(22):
  68. print(self.__points[i][j], end='')
  69. print()
  70.  
  71. # the snake class
  72. class snake:
  73. __points = []
  74.  
  75. def __init__(self):
  76. for i in range(1, 6):
  77. self.__points.append([1, i])
  78.  
  79. def getPoints(self):
  80. return self.__points
  81.  
  82. # move to the next position
  83. # give the next head
  84. def move(self, next_head):
  85. self.__points.pop(0)
  86. self.__points.append(next_head)
  87.  
  88. # eat the food
  89. # give the next head
  90. def eat(self, next_head):
  91. self.__points.append(next_head)
  92.  
  93. # calc the next state
  94. # and return the direction
  95. def next_head(self, direction='default'):
  96.  
  97. # need to change the value, so copy it
  98. head = copy.deepcopy(self.__points[len(self.__points) - 1])
  99.  
  100. # calc the "default" direction
  101. if direction == 'default':
  102. neck = self.__points[len(self.__points) - 2]
  103. if neck[0] > head[0]:
  104. direction = 'up'
  105. elif neck[0] < head[0]:
  106. direction = 'down'
  107. elif neck[1] > head[1]:
  108. direction = 'left'
  109. elif neck[1] < head[1]:
  110. direction = 'right'
  111.  
  112. if direction == 'up':
  113. head[0] = head[0] - 1
  114. elif direction == 'down':
  115. head[0] = head[0] + 1
  116. elif direction == 'left':
  117. head[1] = head[1] - 1
  118. elif direction == 'right':
  119. head[1] = head[1] + 1
  120. return head
  121.  
  122. # the game
  123. class game:
  124.  
  125. board = board()
  126. snake = snake()
  127. food = []
  128. count = 0
  129.  
  130. def __init__(self):
  131. self.new_food()
  132. self.board.clear()
  133. self.board.put_snake(self.snake.getPoints())
  134. self.board.put_food(self.food)
  135.  
  136. def new_food(self):
  137. while 1:
  138. line = random.randint(1, 20)
  139. column = random.randint(1, 20)
  140. if self.board.getPoint([column, line]) == ' ':
  141. self.food = [column, line]
  142. return
  143.  
  144. def show(self):
  145. self.board.clear()
  146. self.board.put_snake(self.snake.getPoints())
  147. self.board.put_food(self.food)
  148. self.board.show()
  149.  
  150. def run(self):
  151. self.board.show()
  152.  
  153. # the 'w a s d' are the directions
  154. operation_dict = {b'w': 'up', b'W': 'up', b's': 'down', b'S': 'down', b'a': 'left', b'A': 'left', b'd': 'right', b'D': 'right'}
  155. op = msvcrt.getch()
  156.  
  157. while op != b'q':
  158. if op not in operation_dict:
  159. op = msvcrt.getch()
  160. else:
  161. new_head = self.snake.next_head(operation_dict[op])
  162.  
  163. # get the food
  164. if self.board.getPoint(new_head) == '*':
  165. self.snake.eat(new_head)
  166. self.count = self.count + 1
  167. if self.count >= 15:
  168. self.show()
  169. print("Good Job")
  170. break
  171. else:
  172. self.new_food()
  173. self.show()
  174.  
  175. # 反向一Q日神仙
  176. elif new_head == self.snake.getPoints()[len(self.snake.getPoints()) - 2]:
  177. pass
  178.  
  179. # rush the wall
  180. elif self.board.getPoint(new_head) == '#' or self.board.getPoint(new_head) == 'o':
  181. print('GG')
  182. break
  183.  
  184. # normal move
  185. else:
  186. self.snake.move(new_head)
  187. self.show()
  188. op = msvcrt.getch()
  189.  
  190. game().run()

笔记:

  1.Python 没有Switch case语句,可以利用dirt来实现

  2.Python的=号是复制,复制引用,深复制需要使用copy的deepcopy()函数来实现

  3.即使在成员函数内,也需要使用self来访问成员变量,这和C++、JAVA很不一样

2017.4.11 更新

  完成了贪吃蛇之后,我开始打一个简单的学生信息管理系统,内容简单,数据量小,但是可以用上MVC架构,又可以更好的训练。过程中发现自己在贪吃蛇中有一个致命的问题,虽然在贪吃蛇中,这个问题并不会影响结果。

  先看board类中的部分代码:

  1. class board:
  2.  
  3. __points =[]
    4 # 后面不重要

咋一看没有问题,但是看初始化__point的位置,并不是在__init__()中第一次初始化,这种情况下,__point是一个类变量,而不是一个成员变量,如果__point是一个不可变的类型(如整形),那可能不会看出什么影响,但是当它是一个可变的类型,如list,就会有很大的问题,看我在命令行上的试验:

①整形例子

到此为止,和我一开始的想法没有冲突,请看下面:

惊讶的发现可以直接通过类名来访问到num变量,而且还一直保持着最初的值,还能变

②list例子

试验的时候心理活动:嗯→很正常→就该这样→卧槽???

这时候可以再来一句:

分析:整形例子中,当我修改num的值,其实是让num指向了新的内存,所以会有c1,c2有着各自的num值;

而在list例子中,当我修改cc的值,修改的是cc指向的内存的值,cc一直指向同一个内存

个人理解:不论哪一个例子,都是在复制类变量,所以会有这种现象

贪吃蛇中,因为Snake和board我都只有一个实例,所以没有明显的问题。

与此相关可以看这篇博客:http://www.cnblogs.com/duanv/p/5947525.html

函数的默认参数中也有相似的问题,可以看:http://blog.jobbole.com/42706/#article-comment

用Python写一个贪吃蛇的更多相关文章

  1. 如何用Python写一个贪吃蛇AI

    前言 这两天在网上看到一张让人涨姿势的图片,图片中展示的是贪吃蛇游戏, 估计大部分人都玩过.但如果仅仅是贪吃蛇游戏,那么它就没有什么让人涨姿势的地方了. 问题的关键在于,图片中的贪吃蛇真的很贪吃XD, ...

  2. 使用Python写一个贪吃蛇

    参考代码http://blog.csdn.net/leepwang/article/details/7640880 我在程序中加入了分数显示,三种特殊食物,将贪吃蛇的游戏逻辑写到了SnakeGame的 ...

  3. python 写一个贪吃蛇游戏

    #!usr/bin/python #-*- coding:utf-8 -*- import random import curses s = curses.initscr() curses.curs_ ...

  4. 用 Python 写个贪吃蛇,保姆级教程!

    本文基于 Windows 环境开发,适合 Python 新手 本文作者:HelloGitHub-Anthony HelloGitHub 推出的<讲解开源项目>系列,本期介绍 Python ...

  5. 【C/C++】10分钟教你用C++写一个贪吃蛇附带AI功能(附源代码详解和下载)

    C++编写贪吃蛇小游戏快速入门 刚学完C++.一时兴起,就花几天时间手动做了个贪吃蛇,后来觉得不过瘾,于是又加入了AI功能.希望大家Enjoy It. 效果图示 AI模式演示 imageimage 整 ...

  6. pygame试水,写一个贪吃蛇

    最近学完python基础知识,就想着做一个游戏玩玩,于是就在https://www.pygame.org/docs/学着做了个贪吃蛇游戏. 首先要导入模块. import pygame import ...

  7. 一步一步用Canvas写一个贪吃蛇

    之前在慕课网看了几集Canvas的视频,一直想着写点东西练练手.感觉贪吃蛇算是比较简单的了,当年大学的时候还写过C语言字符版的,没想到还是遇到了很多问题. 最终效果如下(图太大的话 时间太长 录制gi ...

  8. Python写的贪吃蛇游戏例子

    第一次用Python写这种比较实用且好玩的东西,权当练手吧 游戏说明: * P键控制“暂停/开始”* 方向键控制贪吃蛇的方向 源代码如下: 复制代码代码如下: from Tkinter import ...

  9. 用js写一个贪吃蛇小游戏

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

随机推荐

  1. 【反编译系列】一、反编译代码(dex2jar + jd-gui)和反编译资源(apktool)

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! [反编译系列]二.反编译代码(jeb) [反编译系列]三.反编译神器(jadx) [反编译系列]四.反编译so文件(IDA_Pro) 概述 ...

  2. 关于MQ,你必须知道的

    我走过最长的路是你的套路 女:二号男嘉宾,假如我们牵手成功后,你会买名牌包包给我吗? 男:那你会听话吗? 女:会 听话. 男:听话 咱不买! OK那么消息队列MQ有什么套路呢?(这个话题转换生硬度连我 ...

  3. Java集合详解8:Java集合类细节精讲

    今天我们来探索一下Java集合类中的一些技术细节.主要是对一些比较容易被遗漏和误解的知识点做一些讲解和补充.可能不全面,还请谅解. 本文参考:http://cmsblogs.com/?cat=5 具体 ...

  4. Redux的中间件原理分析

    redux的中间件对于使用过redux的各位都不会感到陌生,通过应用上我们需要的所有要应用在redux流程上的中间件,我们可以加强dispatch的功能.最近也有一些初学者同时和实习生在询问中间件有关 ...

  5. 【JDBC 笔记】

    JDBC 笔记 作者:晨钟暮鼓c个人微信公众号:程序猿的月光宝盒 对应pdf版:https://download.csdn.net/download/qq_22430159/10754554 没有积分 ...

  6. 一个经典的 HTTP协议详解

    1引言 HTTP是一个属于应用层的面向对象的协议,由于其简捷.快速的方式,适用于分布式超媒体信息系统.它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展.目前在WWW中使用的是HTTP/1 ...

  7. Android ADB命令详解

    adb的全称为Android Debug Bridge.是android司机经常用到的工具 . 你能在本篇文章中学到什么? adb基本指令 Shell AM&PM adb模拟用户事件 logc ...

  8. Linux系统优化脚本

    #!/bin/bash ############################################################################## # File Na ...

  9. Visual Studio Code-批量添加或删除注释行

    小技巧一例,批量删除Visual Studio code或notepad++注解信息,便于读取有效代码或文本信息,具体操作如下: Visual Studio Code批量删除注解行信息: 在VS Co ...

  10. 20170310 - Python 3 下 SQLAlchemy 的 MySQL 数据库 URI 配置

    MySQL-Python 只用于 Python 2,URI配置为 mysql://username:password@server/db Python 3 下要使用另一个 PyMySQL 包,相应的U ...