用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 ...
随机推荐
- 【反编译系列】一、反编译代码(dex2jar + jd-gui)和反编译资源(apktool)
版权声明:本文为HaiyuKing原创文章,转载请注明出处! [反编译系列]二.反编译代码(jeb) [反编译系列]三.反编译神器(jadx) [反编译系列]四.反编译so文件(IDA_Pro) 概述 ...
- 关于MQ,你必须知道的
我走过最长的路是你的套路 女:二号男嘉宾,假如我们牵手成功后,你会买名牌包包给我吗? 男:那你会听话吗? 女:会 听话. 男:听话 咱不买! OK那么消息队列MQ有什么套路呢?(这个话题转换生硬度连我 ...
- Java集合详解8:Java集合类细节精讲
今天我们来探索一下Java集合类中的一些技术细节.主要是对一些比较容易被遗漏和误解的知识点做一些讲解和补充.可能不全面,还请谅解. 本文参考:http://cmsblogs.com/?cat=5 具体 ...
- Redux的中间件原理分析
redux的中间件对于使用过redux的各位都不会感到陌生,通过应用上我们需要的所有要应用在redux流程上的中间件,我们可以加强dispatch的功能.最近也有一些初学者同时和实习生在询问中间件有关 ...
- 【JDBC 笔记】
JDBC 笔记 作者:晨钟暮鼓c个人微信公众号:程序猿的月光宝盒 对应pdf版:https://download.csdn.net/download/qq_22430159/10754554 没有积分 ...
- 一个经典的 HTTP协议详解
1引言 HTTP是一个属于应用层的面向对象的协议,由于其简捷.快速的方式,适用于分布式超媒体信息系统.它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展.目前在WWW中使用的是HTTP/1 ...
- Android ADB命令详解
adb的全称为Android Debug Bridge.是android司机经常用到的工具 . 你能在本篇文章中学到什么? adb基本指令 Shell AM&PM adb模拟用户事件 logc ...
- Linux系统优化脚本
#!/bin/bash ############################################################################## # File Na ...
- Visual Studio Code-批量添加或删除注释行
小技巧一例,批量删除Visual Studio code或notepad++注解信息,便于读取有效代码或文本信息,具体操作如下: Visual Studio Code批量删除注解行信息: 在VS Co ...
- 20170310 - Python 3 下 SQLAlchemy 的 MySQL 数据库 URI 配置
MySQL-Python 只用于 Python 2,URI配置为 mysql://username:password@server/db Python 3 下要使用另一个 PyMySQL 包,相应的U ...