用Python写一个贪吃蛇
最近在学Python,想做点什么来练练手,命令行的贪吃蛇一般是C的练手项目,但是一时之间找不到别的,就先做个贪吃蛇来练练简单的语法。
由于Python监听键盘很麻烦,没有C语言的kbhit(),所以这条贪吃蛇不会自己动,运行效果如下:

要求:用#表示边框,用*表示食物,o表示蛇的身体,O表示蛇头,使用wsad来移动
Python版本:3.6.1
系统环境:Win10
类:
board:棋盘,也就是游戏区域
snake:贪吃蛇,通过记录身体每个点来记录蛇的状态
game:游戏类
本来还想要个food类的,但是food只需要一个坐标,和一个新建,所以干脆使用list来保存坐标,新建food放在game里面,从逻辑上也没有太大问题
源码
# Write By Guobao
# 2017/4//7
#
# 贪吃蛇
# 用#做边界,*做食物,o做身体和头部
# python 3.6.1 import copy
import random
import os
import msvcrt # the board class, used to put everything
class board: __points =[] def __init__(self):
self.__points.clear()
for i in range(22):
line = []
if i == 0 or i == 21:
for j in range(22):
line.append('#')
else:
line.append('#')
for j in range(20):
line.append(' ')
line.append('#')
self.__points.append(line) def getPoint(self, location):
return self.__points[location[0]][location[1]] def clear(self):
self.__points.clear()
for i in range(22):
line = []
if i == 0 or i == 21:
for j in range(22):
line.append('#')
else:
line.append('#')
for j in range(20):
line.append(' ')
line.append('#')
self.__points.append(line) def put_snake(self, snake_locations):
# clear the board
self.clear() # put the snake points
for x in snake_locations:
self.__points[x[0]][x[1]] = 'o' # the head
x = snake_locations[len(snake_locations) - 1]
self.__points[x[0]][x[1]] = 'O' def put_food(self, food_location):
self.__points[food_location[0]][food_location[1]] = '*' def show(self):
os.system("cls")
for i in range(22):
for j in range(22):
print(self.__points[i][j], end='')
print() # the snake class
class snake:
__points = [] def __init__(self):
for i in range(1, 6):
self.__points.append([1, i]) def getPoints(self):
return self.__points # move to the next position
# give the next head
def move(self, next_head):
self.__points.pop(0)
self.__points.append(next_head) # eat the food
# give the next head
def eat(self, next_head):
self.__points.append(next_head) # calc the next state
# and return the direction
def next_head(self, direction='default'): # need to change the value, so copy it
head = copy.deepcopy(self.__points[len(self.__points) - 1]) # calc the "default" direction
if direction == 'default':
neck = self.__points[len(self.__points) - 2]
if neck[0] > head[0]:
direction = 'up'
elif neck[0] < head[0]:
direction = 'down'
elif neck[1] > head[1]:
direction = 'left'
elif neck[1] < head[1]:
direction = 'right' if direction == 'up':
head[0] = head[0] - 1
elif direction == 'down':
head[0] = head[0] + 1
elif direction == 'left':
head[1] = head[1] - 1
elif direction == 'right':
head[1] = head[1] + 1
return head # the game
class game: board = board()
snake = snake()
food = []
count = 0 def __init__(self):
self.new_food()
self.board.clear()
self.board.put_snake(self.snake.getPoints())
self.board.put_food(self.food) def new_food(self):
while 1:
line = random.randint(1, 20)
column = random.randint(1, 20)
if self.board.getPoint([column, line]) == ' ':
self.food = [column, line]
return def show(self):
self.board.clear()
self.board.put_snake(self.snake.getPoints())
self.board.put_food(self.food)
self.board.show() def run(self):
self.board.show() # the 'w a s d' are the directions
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'}
op = msvcrt.getch() while op != b'q':
if op not in operation_dict:
op = msvcrt.getch()
else:
new_head = self.snake.next_head(operation_dict[op]) # get the food
if self.board.getPoint(new_head) == '*':
self.snake.eat(new_head)
self.count = self.count + 1
if self.count >= 15:
self.show()
print("Good Job")
break
else:
self.new_food()
self.show() # 反向一Q日神仙
elif new_head == self.snake.getPoints()[len(self.snake.getPoints()) - 2]:
pass # rush the wall
elif self.board.getPoint(new_head) == '#' or self.board.getPoint(new_head) == 'o':
print('GG')
break # normal move
else:
self.snake.move(new_head)
self.show()
op = msvcrt.getch() game().run()
笔记:
1.Python 没有Switch case语句,可以利用dirt来实现
2.Python的=号是复制,复制引用,深复制需要使用copy的deepcopy()函数来实现
3.即使在成员函数内,也需要使用self来访问成员变量,这和C++、JAVA很不一样
2017.4.11 更新
完成了贪吃蛇之后,我开始打一个简单的学生信息管理系统,内容简单,数据量小,但是可以用上MVC架构,又可以更好的训练。过程中发现自己在贪吃蛇中有一个致命的问题,虽然在贪吃蛇中,这个问题并不会影响结果。
先看board类中的部分代码:
class board:
__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写一个贪吃蛇的更多相关文章
- 如何用Python写一个贪吃蛇AI
前言 这两天在网上看到一张让人涨姿势的图片,图片中展示的是贪吃蛇游戏, 估计大部分人都玩过.但如果仅仅是贪吃蛇游戏,那么它就没有什么让人涨姿势的地方了. 问题的关键在于,图片中的贪吃蛇真的很贪吃XD, ...
- 使用Python写一个贪吃蛇
参考代码http://blog.csdn.net/leepwang/article/details/7640880 我在程序中加入了分数显示,三种特殊食物,将贪吃蛇的游戏逻辑写到了SnakeGame的 ...
- python 写一个贪吃蛇游戏
#!usr/bin/python #-*- coding:utf-8 -*- import random import curses s = curses.initscr() curses.curs_ ...
- 用 Python 写个贪吃蛇,保姆级教程!
本文基于 Windows 环境开发,适合 Python 新手 本文作者:HelloGitHub-Anthony HelloGitHub 推出的<讲解开源项目>系列,本期介绍 Python ...
- 【C/C++】10分钟教你用C++写一个贪吃蛇附带AI功能(附源代码详解和下载)
C++编写贪吃蛇小游戏快速入门 刚学完C++.一时兴起,就花几天时间手动做了个贪吃蛇,后来觉得不过瘾,于是又加入了AI功能.希望大家Enjoy It. 效果图示 AI模式演示 imageimage 整 ...
- pygame试水,写一个贪吃蛇
最近学完python基础知识,就想着做一个游戏玩玩,于是就在https://www.pygame.org/docs/学着做了个贪吃蛇游戏. 首先要导入模块. import pygame import ...
- 一步一步用Canvas写一个贪吃蛇
之前在慕课网看了几集Canvas的视频,一直想着写点东西练练手.感觉贪吃蛇算是比较简单的了,当年大学的时候还写过C语言字符版的,没想到还是遇到了很多问题. 最终效果如下(图太大的话 时间太长 录制gi ...
- Python写的贪吃蛇游戏例子
第一次用Python写这种比较实用且好玩的东西,权当练手吧 游戏说明: * P键控制“暂停/开始”* 方向键控制贪吃蛇的方向 源代码如下: 复制代码代码如下: from Tkinter import ...
- 用js写一个贪吃蛇小游戏
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
随机推荐
- 为什么我的会话状态在ASP.NET Core中不工作了?
原文:Why isn't my session state working in ASP.NET Core? Session state, GDPR, and non-essential cookie ...
- JavaScript引用类型之Array类型API详解
Array类型也是ECMASCRIPT中最常见的数据类型,而且数据的每一项可以保存任何类型的数值,而且数组的大小是可以动态调整的,可以随着数据的添加自动增长以容纳新的数据.下面,总结数据的一些常用方法 ...
- 『开源』扩展 JS 的 Date 处理函数
背景: JS 有自己的 时间类型 Date —— 但是,在某些情况下 这个对象似乎 不太好用. 本文 基于 JQuery 扩展了一些 JS日期函数,包括: > 字符串 转 Date 对象 万 ...
- Eclipse连接Hadoop集群及WordCount实践
声明:作者原创,转载注明出处. 作者:帅气陈吃苹果 一.环境准备 1.JDK安装与配置 2.Eclipse下载 下载解压即可,下载地址:https://pan.baidu.com/s/1i51UsVN ...
- Netty源码—六、tiny、small内存分配
tiny内存分配 tiny内存分配流程: 如果申请的是tiny类型,会先从tiny缓存中尝试分配,如果缓存分配成功则返回 否则从tinySubpagePools中尝试分配 如果上面没有分配成功则使用a ...
- JavaSE:关键字(全)
访问控制: private 访问控制方式:私有的 protected 访问控制方式:受保护的 public 访问控制方式:公共的 类.方法和变量修饰符: abstract 声明抽象,表明类或者成员方法 ...
- AES加密然后ajax传输数据
最近做的一个项目,需要对传输的参数进行aes加密,所以就顺便的了解了一下,因为这种东西,肯定都是有写好的,现成的,所有这里就简单的记录一下,方便以后自己和大家查找. 首先附上百度的关于AES的百度百科 ...
- 学习 day4 html 盒子模型
盒子模型 1.框模型 框:页面上所有元素都可以称为“框” 框模型:(BOX Model),又称盒子模型 定义框处理元素内容.内边距padding.外边距margin.边框的样式border 外边距ma ...
- Windows 2012安装odoo12
- OpenProject基础使用介绍
所有的活动都可以看做一个项目来管理.在企业中更是这样. 所以项目管理平台,对于任何一个高科技企业来讲都是必不可少的. OpenProject(以下简称OP)就是一个不错的项目管理平台, ...