乌龟吃鱼游戏雏形
pygame
-
游戏编程:按以下要求定义一个乌龟类和鱼类并尝试编写游戏
假设游戏场景为范围(x,y)为0<=x<=10,0<=y<=10
游戏生成1只乌龟和10条鱼
它们的移动方向均随机
乌龟的最大移动能力为2(它可以随机选择1还是2移动),鱼儿的最大移动能力是1
当移动到场景边缘,自动向反方向移动
乌龟初始化体力为100(上限)
乌龟每移动一次,体力消耗1
当乌龟和鱼坐标重叠,乌龟吃掉鱼,乌龟体力增加20
鱼暂不计算体力
当乌龟体力值为0(挂掉)或者鱼儿的数量为0游戏结束
import random
class Turtle(object):
# 构造函数什么时候执行? =---=====创建对象时执行
def __init__(self): # self指的是实例化的对象;
# 乌龟的属性: x,y轴坐标和体力值
# 乌龟的x轴, 范围1,10
self.x = random.randint(1, 10)
self.y = random.randint(1, 10)
# 乌龟初始化体力为100
self.power = 100
# 类的方法:
def move(self):
# 乌龟的最大移动能力为2,[-2, -1, 0, 1, 2]
move_skill = [-2, -1, 0, 1, 2]
# 计算出乌龟的新坐标(10, 12)
new_x = self.x + random.choice(move_skill)
new_y = self.y + random.choice(move_skill)
# 对于新坐标进行检验, 是哦否合法, 如果不合法, 进行处理
self.x = self.is_vaild(new_x)
self.y = self.is_vaild(new_y)
# 乌龟每移动一次,体力消耗1
self.power -= 1
def is_vaild(self, value):
"""
判断传进来的x轴坐标或者y轴坐标是否合法?
1). 如果合法, 直接返回传进来的值;
2). value<=0; =====> abs(value);
3). value > 10 ======> 10-(value-10);
:param value:
:return:
"""
if 1 <= value <= 10:
return value
elif value < 1:
return abs(value)
else:
return 10 - (value - 10)
def eat(self):
"""
当乌龟和鱼坐标重叠,乌龟吃掉鱼,乌龟体力增加20
:return:
"""
self.power += 20
class Fish(object):
# 构造函数什么时候执行? =---=====创建对象时执行
def __init__(self):
# 鱼的属性: x, y轴坐标
# 鱼的x轴, 范围1,10
self.x = random.randint(1, 10)
self.y = random.randint(1, 10)
# 类的方法:
def move(self):
# 鱼的最大移动能力为1,[ -1, 0, 1]
move_skill = [-1, 0, 1]
# 计算出鱼的新坐标(10, 12)
new_x = self.x + random.choice(move_skill)
new_y = self.y + random.choice(move_skill)
# 对于新坐标进行检验, 是否合法, 如果不合法, 进行处理
self.x = self.is_vaild(new_x)
self.y = self.is_vaild(new_y)
def is_vaild(self, value):
"""
判断传进来的x轴坐标或者y轴坐标是否合法?
1). 如果合法, 直接返回传进来的值;
2). value<=0; =====> abs(value);
3). value > 10 ======> 10-(value-10);
:param value:
:return:
"""
if 1 <= value <= 10:
return value
elif value < 1:
return abs(value)
else:
return 10 - (value - 10)
def main():
# 创建一个乌龟;
turtle = Turtle()
print(turtle.x, turtle.y) #打印乌龟初始坐标
# for循环创建10个鱼
# fishs = []
# for i in range(10):
# fishs.append(Fish())
# 创建10个鱼对象;
fishs = [Fish() for i in range(10)]
# 游戏开始
while True:
# 判断游戏是否结束?( 当乌龟体力值为0(挂掉)或者鱼儿的数量为0游戏结束)
if turtle.power <= 0:
print("乌龟没有体力了, Game over......")
break
elif len(fishs) == 0:
print("鱼被吃光, Game over......")
break
else:
# 游戏没有结束. 乌龟和鱼随机移动
turtle.move()
# 鱼移动
for fish in fishs:
fish.move()
# 判断鱼是否被乌龟吃掉?
# 当乌龟和鱼坐标重叠,乌龟吃掉鱼,乌龟体力增加20
if turtle.x == fish.x and turtle.y == fish.y:
turtle.eat()
# 删除被乌龟吃掉的鱼
fishs.remove(fish)
print("鱼被乌龟吃掉, 还剩%d条鱼....." % (len(fishs)))
print("乌龟的最新体力为%s" % (turtle.power))
# 乌龟跟10个鱼都比较结束后, 没有发现吃到一个鱼, 才执行, 跟for是一块的;
else:
print("乌龟没有吃到鱼,最新体力为%s" % (turtle.power))
# pygame
if __name__ == "__main__":
print("游戏开始".center(30, "*"))
main()
继承的使用
OKGREEN = "\033[32m"
ERRRED = "\033[31m"
WARNYELLOW = "\033[33m"
if __name__ == "__main__":
print(OKGREEN + 'HELLO')
print(ERRRED + 'hello')
print(WARNYELLOW + 'hello')
import random
from day12.colorFont import *
class Animal(object):
"""
将乌龟和鱼的共同特性抽象出来的类
"""
def __init__(self):
self.x = random.randint(1, 10)
self.y = random.randint(1, 10)
# 类的方法:
def move(self, move_skill):
# 计算出乌龟的新坐标(10, 12)
new_x = self.x + random.choice(move_skill)
new_y = self.y + random.choice(move_skill)
# 对于新坐标进行检验, 是哦否合法, 如果不合法, 进行处理
self.x = self.is_vaild(new_x)
self.y = self.is_vaild(new_y)
def is_vaild(self, value):
"""
判断传进来的x轴坐标或者y轴坐标是否合法?
1). 如果合法, 直接返回传进来的值;
2). value<=0; =====> abs(value);
3). value > 10 ======> 10-(value-10);
:param value:
:return:
"""
if 1 <= value <= 10:
return value
elif value < 1:
return abs(value)
else:
return 10 - (value - 10)
class Turtle(Animal):
# 构造函数什么时候执行? =---=====创建对象时执行
def __init__(self): # self指的是实例化的对象;
super(Turtle, self).__init__()
# 乌龟初始化体力为100
self.power = 100
# 类的方法:
def move(self, move_skill=(-2, -1, 0, 1, 2)):
super(Turtle, self).move(move_skill)
# 乌龟每移动一次,体力消耗1
self.power -= 1
def eat(self):
"""
当乌龟和鱼坐标重叠,乌龟吃掉鱼,乌龟体力增加20
:return:
"""
self.power += 20
class Fish(Animal):
# 类的方法:
def move(self, move_skill=[-1, 0, 1]):
super(Fish, self).move(move_skill)
def main():
# 创建一个乌龟;
turtle = Turtle()
print(turtle.x, turtle.y)
# for循环创建10个鱼
# fishs = []
# for i in range(10):
# fishs.append(Fish())
# 创建10个鱼对象;
fishs = [Fish() for i in range(10)]
# 游戏开始
while True:
# 判断游戏是否结束?( 当乌龟体力值为0(挂掉)或者鱼儿的数量为0游戏结束)
if turtle.power <= 0:
print(ERRRED + "乌龟没有体力了, Game over......")
break
elif len(fishs) == 0:
print(OKGREEN + "鱼被吃光, Game over......")
break
else:
# 游戏没有结束. 乌龟和鱼随机移动
turtle.move()
# 鱼移动
for fish in fishs:
fish.move()
# 判断鱼是否被乌龟吃掉?
# 当乌龟和鱼坐标重叠,乌龟吃掉鱼,乌龟体力增加20
if turtle.x == fish.x and turtle.y == fish.y:
turtle.eat()
# 删除被乌龟吃掉的鱼
fishs.remove(fish)
print(OKGREEN + "鱼被乌龟吃掉, 还剩%d条鱼....." % (len(fishs)))
print(WARNYELLOW + "乌龟的最新体力为%s" % (turtle.power))
# 乌龟跟10个鱼都比较结束后, 没有发现吃到一个鱼, 才执行, 跟for是一块的;
else:
print(ERRRED + "乌龟没有吃到鱼,最新体力为%s" % (turtle.power))
# pygame
if __name__ == "__main__":
print("游戏开始".center(30, "*"))
main()
字体颜色更改
- 实现过程:
终端的字符颜色是用转义序列控制的,是文本模式下的系统显示功能,和具体的语言无关。
转义序列是以ESC开头,即用\033来完成(ESC的ASCII码用十进制表示是27,用八进制表示就是033)。 - 书写格式:
开头部分:\033[显示方式;前景色;背景色m + 结尾部分:\033[0m
注意:开头部分的三个参数:显示方式,前景色,背景色是可选参数,可以只写其中的某一个;另 外由于表示三个参数不同含义的数值都是唯一的没有重复的,所以三个参数的书写先后顺序没有固定要>求,系统都能识别;但是,建议按照默认的格式规范书写。
对于结尾部分,其实也可以省略,但是为了书写规范,建议\033[***开头,\033[0m结尾。 - 数值表示的参数含义: 显示方式: 0(默认值)、1(高亮)、22(非粗体)、4(下划线)、24(非下划线)、
5(闪烁)、25(非闪烁)、7(反显)、27(非反显) 前景色: 30(黑色)、31(红色)、32(绿色)、
33(黄色)、34(蓝色)、35(洋 红)、36(青色>)、37(白色) 背景色: 40(黑色)、41(红色)、42(绿色)、
43(黄色)、44(蓝色)、45(洋 红)、46(青色>)、47(白色) - 成功: 绿色字体
- 失败: 红色字体
- 警告: 黄色字体
- 详细查看colorFont.py文件
类的切片和索引的实现
类的重复和连接的实现
# 1. python里面一切皆对象;
# 2. 如何给自己编写的类实现切片和索引的功能?
# 3. 实现索引的几个魔术方法?
class Student(object):
def __init__(self, name, scores):
self.name = name
self.scores = scores
# 索引的是学生的成绩
def __getitem__(self, index): # 1).索引值的获取
#print(index, type(index))
return self.scores[index]
def __setitem__(self, key, value): # 2). 索引值的重新赋值
self.scores[key] = value
def __delitem__(self, key): # 3). 删除索引值
del self.scores[key]
def __mul__(self, other): # 4). 实现*的效果, 具体返回什么取决于代码的业务需求
"""对于学生的每一门成绩乘3"""
return [i*other for i in self.scores]
def __add__(self, other): # 5). 连接的时候必须是同一种数据;类型
# 将两个学生的成绩拼接起来
return self.scores + other.scores
def __contains__(self, item): # 6). 判断某个元素是否存在于这个对象中?
return item in self.scores
def __iter__(self): # 7). 迭代, 使得该对象可以实现for循环
# 将列表转换为迭代的类型, 可以for循环, 一定要返回iter类型的数据;
return iter(self.scores)
def __lt__(self, other): # 8). 比较两个对象的大小;
return (sum(self.scores)/3) < (sum(other.scores)/3)
liming = Student('liming', [100, 89, 100])
1.索引值的获取
print(liming[0])
print(liming[1])
print(liming[2])
2.索引值重新赋值
liming[0] = 90
print(liming[0])
3.删除切片值
del liming[:2]
print(liming.scores)
4.判断是否可以重复
print(liming * 3)
5.连接
xiaohong = Student('小红', [100, 90, 90])
print(xiaohong + liming)
6.成员操作符,判断是否在对象里面
print(100 in xiaohong)
print(101 in xiaohong)
print(101 not in xiaohong)
7.实现for循环
for item in liming:
print(item)
8.比较对象大小
-
列表大小的比较: 列表之间也可以比较大小
-
从第一个元素顺序开始比较,如果相等,则继续,返回第一个不想等元素比较的结果。如果所有元素比较均相等,则长的列表大,一样长则两列表相等
print(liming > xiaohong)
print(liming < xiaohong)
魔术方法总结
- 基本的魔术方法
__new__(cls[, ...])
#1. __new__ 是在一个对象实例化的时候所调用的第一个方法
#2. 它的第一个参数是这个类,其他的参数是用来直接传递给 __init__ 方法
#3. __new__ 决定是否要使用该 __init__ 方法,因为 __new__ 可以调用其他类的构造方法或者直接返回别的实例对象来作为本类的实例,如果 __new__ 没有返回实例对象,则 __init__ 不会被调用
#4. __new__ 主要是用于继承一个不可变的类型比如一个 tuple 或者 string
__init__(self[, ...])
构造器,当一个实例被创建的时候调用的初始化方法
__del__(self)
析构器,当一个实例被销毁的时候调用的方法
__call__(self[, args...])
允许一个类的实例像函数一样被调用:x(a, b) 调用 x.__call__(a, b)
__len__(self)
定义当被 len() 调用时的行为
__repr__(self)
定义当被 repr() 调用或者直接执行对象时的行为
__str__(self)
定义当被 str() 调用或者打印对象时的行为
__bytes__(self)
定义当被 bytes() 调用时的行为
__hash__(self)
定义当被 hash() 调用时的行为
__bool__(self)
定义当被 bool() 调用时的行为,应该返回 True 或 False
__format__(self, format_spec)
定义当被 format() 调用时的行为
- 有关属性
__getattr__(self, name) 定义当用户试图获取一个不存在的属性时的行为
__getattribute__(self, name) 定义当该类的属性被访问时的行为
__setattr__(self, name, value) 定义当一个属性被设置时的行为
__delattr__(self, name) 定义当一个属性被删除时的行为
__dir__(self) 定义当 dir() 被调用时的行为
__get__(self, instance, owner) 定义当描述符的值被取得时的行为
__set__(self, instance, value) 定义当描述符的值被改变时的行为
__delete__(self, instance) 定义当描述符的值被删除时的行为
- 比较操作符
__lt__(self, other) 定义小于号的行为:x < y 调用 x.__lt__(y)
__le__(self, other) 定义小于等于号的行为:x <= y 调用 x.__le__(y)
__eq__(self, other) 定义等于号的行为:x == y 调用 x.__eq__(y)
__ne__(self, other) 定义不等号的行为:x != y 调用 x.__ne__(y)
__gt__(self, other) 定义大于号的行为:x > y 调用 x.__gt__(y)
__ge__(self, other) 定义大于等于号的行为:x >= y 调用 x.__ge__(y)
- 算术运算符
__add__(self, other) 定义加法的行为:+
__sub__(self, other) 定义减法的行为:-
__mul__(self, other) 定义乘法的行为:*
__truediv__(self, other) 定义真除法的行为:/
__floordiv__(self, other) 定义整数除法的行为://
__mod__(self, other) 定义取模算法的行为:%
__divmod__(self, other) 定义当被 divmod() 调用时的行为
__pow__(self, other[, modulo]) 定义当被 power() 调用或 ** 运算时的行为
__lshift__(self, other) 定义按位左移位的行为:<<
__rshift__(self, other) 定义按位右移位的行为:>>
__and__(self, other) 定义按位与操作的行为:&
__xor__(self, other) 定义按位异或操作的行为:^
__or__(self, other) 定义按位或操作的行为:|
- 反运算
__radd__(self, other) (与上方相同,当左操作数不支持相应的操作时被调用)
__rsub__(self, other) (与上方相同,当左操作数不支持相应的操作时被调用)
__rmul__(self, other) (与上方相同,当左操作数不支持相应的操作时被调用)
__rtruediv__(self, other) (与上方相同,当左操作数不支持相应的操作时被调用)
__rfloordiv__(self, other) (与上方相同,当左操作数不支持相应的操作时被调用)
__rmod__(self, other) (与上方相同,当左操作数不支持相应的操作时被调用)
__rdivmod__(self, other) (与上方相同,当左操作数不支持相应的操作时被调用)
__rpow__(self, other) (与上方相同,当左操作数不支持相应的操作时被调用)
__rlshift__(self, other) (与上方相同,当左操作数不支持相应的操作时被调用)
__rrshift__(self, other) (与上方相同,当左操作数不支持相应的操作时被调用)
__rand__(self, other) (与上方相同,当左操作数不支持相应的操作时被调用)
__rxor__(self, other) (与上方相同,当左操作数不支持相应的操作时被调用)
__ror__(self, other) (与上方相同,当左操作数不支持相应的操作时被调用)
- 增量赋值运算
__iadd__(self, other) 定义赋值加法的行为:+=
__isub__(self, other) 定义赋值减法的行为:-=
__imul__(self, other) 定义赋值乘法的行为:*=
__itruediv__(self, other) 定义赋值真除法的行为:/=
__ifloordiv__(self, other) 定义赋值整数除法的行为://=
__imod__(self, other) 定义赋值取模算法的行为:%=
__ipow__(self, other[, modulo]) 定义赋值幂运算的行为:**=
__ilshift__(self, other) 定义赋值按位左移位的行为:<<=
__irshift__(self, other) 定义赋值按位右移位的行为:>>=
__iand__(self, other) 定义赋值按位与操作的行为:&=
__ixor__(self, other) 定义赋值按位异或操作的行为:^=
__ior__(self, other) 定义赋值按位或操作的行为:|=
- 一元操作符
__pos__(self) 定义正号的行为:+x
__neg__(self) 定义负号的行为:-x
__abs__(self) 定义当被 abs() 调用时的行为
__invert__(self) 定义按位求反的行为:~x
- 类型转换
__complex__(self) 定义当被 complex() 调用时的行为(需要返回恰当的值)
__int__(self) 定义当被 int() 调用时的行为(需要返回恰当的值)
__float__(self) 定义当被 float() 调用时的行为(需要返回恰当的值)
__round__(self[, n]) 定义当被 round() 调用时的行为(需要返回恰当的值)
__index__(self)
#1. 当对象是被应用在切片表达式中时,实现整形强制转换
#2. 如果你定义了一个可能在切片时用到的定制的数值型,你应该定义 __index__
#3. 如果 __index__ 被定义,则 __int__ 也需要被定义,且返回相同的值
- 上下文管理(with语句)
__enter__(self)
#1. 定义当使用 with 语句时的初始化行为
#2. __enter__ 的返回值被 with 语句的目标或者 as 后的名字绑定
__exit__(self, exc_type, exc_value, traceback)
#1. 定义当一个代码块被执行或者终止后上下文管理器应该做什么
#2. 一般被用来处理异常,清除工作或者做一些代码块执行完毕之后的日常工作
- 容器类型
__len__(self) 定义当被 len() 调用时的行为(返回容器中元素的个数)
__getitem__(self, key) 定义获取容器中指定元素的行为,相当于 self[key]
__setitem__(self, key, value) 定义设置容器中指定元素的行为,相当于 self[key] = value
__delitem__(self, key) 定义删除容器中指定元素的行为,相当于 del self[key]
__iter__(self) 定义当迭代容器中的元素的行为
__reversed__(self) 定义当被 reversed() 调用时的行为
__contains__(self, item) 定义当使用成员测试运算符(in 或 not in)时的行为
property属性
- 总结:
1). Python内置的@property装饰器就是负责把一个方法变成属性调用的;
2). @property本身又创建了另一个装饰器@state.setter,负责把一个
setter方法变成属性赋值,于是,我们就拥有一个可控的属性操作.
3). @property广泛应用在类的定义中,可以让调用者写出简短的代码,
同时保证对参数进行必要的检查,这样,程序运行时就减少了出错的可能性。
源代码应用范例: 让属性只读:
from datetime import date
# Read-only field accessors
@property
def year(self):
# year (1-9999)
return self._year
@property
def month(self):
# month (1-12)
return self._month
@property
def day(self):
# day (1-31)
return self._day
from teach.day12.colorFont import *
class Book(object):
def __init__(self, name, kind, state):
self.name = name
self.kind = kind
# 0: 借出 1: "未借出"
# 书的状态只能是0或者1, 如果是其他, 应该报错;
# 查看书状态, 希望是汉字形式, 有实际意义的;
self.__state = 0
@property # 将这个方法转换为类的属性; print(book.state)
def state(self):
if self.__state == 0:
return ERRRED + "借出"
elif self.__state == 1:
return OKGREEN + "未借出"
@state.setter # book.state = 0
def state(self, value):
if value in (0,1):
# 更新书状态
self.__state = value
else:
print(ERRRED + "更新错误, 必须是0或者1")
@state.deleter # del book.state
def state(self):
del self.__state
print(OKGREEN + "删除书状态成功!")
if __name__ == "__main__":
book = Book("python核心编程", 'python', 1)
print(book.state)
book.state = 1
print(book.state)
del book.state
from datetime import date
from datetime import time
import time
if __name__ == "__main__":
d = date(2019, 10, 10)
print(d.year)
print(d.month)
print(d.day)
d.year = 2020 # 此处不成功, year是只读的
del d.year # 此处不成功, year是只读的
print(d.year)
类方法和静态方法
-
Python中至少有三种比较常见的方法类型,即实例方法,类方法、静态方法。它们是如何定义的呢? 如何调用的呢?它们又有何区别和作用呢?
首先,这三种方法都定义在类中。 实例方法
定义:第一个参数必须是实例对象,该参数名一般约定为“self”,通过它来传递实例的属性和方法(也可以传类的属性和方法);
调用:只能由实例对象调用。类方法
定义:使用装饰器@classmethod。第一个参数必须是当前类对象,该参数名一般约定为“cls”,
通过它来传递类的属性和方法(不能传实例的属性和方法);
调用:实例对象和类对象都可以调用。静态方法
定义:使用装饰器@staticmethod。参数随意,没有“self”和“cls”参数,但是方法体中不能使用类或实例的任何属性和方法;
调用:实例对象和类对象都可以调用
。
# 源代码:
@classmethod
def today(cls):
"Construct a date from time.time()."
t = _time.time()
return cls.fromtimestamp(t)
@classmethod
def fromordinal(cls, n):
y, m, d = _ord2ymd(n)
return cls(y, m, d)
class Date(object):
def __init__(self, year, month, day):
self.__year = year
self.__month = month
self.__day = day
# 实例方法,
def echo(self):
print("%s %s %s" % (self.__year, self.__month, self.__day))
# 默认情况下, 需要将所有相关日期的操作封装到Date类中;
# 如果不做任何改变, s实质上时实例化的对象本身, 不是我们想要的字符串;
@classmethod # 类方法
def as_string(cls, s): # "2019-10-10"
year, month, day = s.split('-')
return cls(year, month, day) # cls实质上就是Date
@staticmethod
def is_valid(s):
year, month, day = map(int, s.split('-'))
return year > 0 and 0 < month <= 12 and 1 <= day <= 31
if __name__ == "__main__":
# 实例化日期类
d = Date(2019, 10, 2)
s = "2019-10-10"
# Date.as_string(s).echo()
print(Date.is_valid(s))
with语句安全上下文管理
class Myopen(object):
def __init__(self, name, mode='r'):
self.name = name
self.mode = mode
def __enter__(self):
# 当with语句进入并开始执行时, 执行的内容, 需要返回一个对象, 在执行结束之后用来关闭或者其他操作;;
self.f = open(self.name, self.mode)
print("正在打开文件%s......" %(self.name))
return self.f
def __exit__(self, exc_type, exc_val, exc_tb):
# 当with语句执行结束后, 做什么操作
self.f.close()
print("文件正在关闭..........")
with Myopen('/tmp/passwd') as f:
print(f.read())