3.函数:贪吃蛇

上一节练习示例代码:

#猜大小.py
import random
num = random.randint(1,1000)
times = 0
while True:
    n = input("猜大小(%d-%d):"%(1,1000))
    n = int(n)
    times += 1
    if n<num:
        print("猜小了。")
    elif n>num:
        print("猜大了。")
    else:
        print("猜对了!")
        print("总共猜了%d次"%(times))
        break

只有文字和疼痛的手指,一点都不快乐。不过没关系,马上我们就要进行一项图像相关的经典游戏:贪吃蛇!我们将会在两个平台完成这个游戏:电脑上和手机上。

Python补充内容

拾遗补阙

学习Python的过程中,你会逐渐敲开三扇大门:循环、函数、类。

现在我们来敲开第二扇。

函数

初中你接触过这样的函数:

y = 2 x + 3 y=2x+3 y=2x+3

到了高中变成了这个样子:

f ( x ) = 2 x + 3 f(x)=2x+3 f(x)=2x+3

不变的是:左边是结果,右边是公式(函数),其中 x x x为自变量。

在Python中这样定义函数:

def f(x):
    return 2*x+3

a = f(2)
print(a)

def关键字用来定义函数,在上面的示例中f函数名,其后面括号里的x就是自变量,我们称为参数

return关键字表示要返回(得到)的结果。

如同上面中学的公式一样:a = f(2)左边是结果,右边是函数,不过我们给自变量代入了一个值,函数就会得到一个唯一的结果,print这个结果:

7

试试复杂点的:

def CircleArea(r):
    pi = 3.1415926
    S = pi*r**2
    return S
print(CircleArea(2))

没有晕头转向吧?搞明白上面实现了什么吗?

不要被circleArea这么长的名字唬住了,它只是个函数名,和上面的f没什么两样。

函数内定义了一个变量pi——泼艾 π π π。还有一个变量S,它的值是它后面式子的值。

S=pi*r**2完成了初中求圆面积公式: S = π r 2 S=πr^2 S=πr2

然后return返回了结果S,在最后我们传入函数一个值,得到了一个结果:

12.5663704

是不是愈发觉得Python是个不错的计算器了?

你可以尝试实现其他数学公式,但是不要把它带到考场上去。

我们可以给函数传入多个变量或者不传入参数,也可以让函数不返回值:

def Say():
    print("我不需要参数")
def SayTxt(txt):
    print("我需要一个参数:",txt)
def SaySay(a,b,c):
    print("我需要三个参数:",a,b,c)
Say()
SayTxt("一个参数")
SaySay("一个参数","两个参数","千万个参数")
print(Say())

运行结果:

我不需要参数
我需要一个参数: 一个参数
我需要三个参数: 一个参数 两个参数 千万个参数
None

注意最后一行的None,因为Say函数没有写return,Python就默认给了它一个返回值:None,表示:没有、什么都不是。注意,None是Python的一个关键字,不是字符串。

Python的一般是从上到下顺序执行,遇到循环再跳转回去,遇到函数跳到到函数里。

def关键字只是定义函数,不会执行具体的函数。但使用函数名+括号(如f(2))便调用了函数,Python会跳到函数内执行,直到遇到return或者执行完了再跳出函数。

可选参数
def f(a,b="B"):
    print(a,b)

f("A")
f("A",b="C")
A B
A C
调用自己
def boom():
    print("爆炸吧现冲!")
    boom()

boom()

如果你尝试运行上面的代码,你就会被同一句话刷屏,因为函数不断地调用自己永远不会返回值。

看看下面这段代码实现了什么?

def factorial(n):
    if n>1:
        n = n * factorial(n-1)
    return n

a = factorial(4)
print(a)

如果传入的n大于1if n>1,就让n等于n乘以factorial(n-1)的返回值,又进入判断n-1是否大于1。

实际上这段代码实现的就是阶乘,factorial(4)其实结果就是4*3*2等于24。

这种调用方式称为函数的迭代

跨文件调用

我们来做这样一件事:

创建一个新脚本fun.py

def f(x):
    return 2*x+3

没错,就是上面我们写的第一个函数。

然后在相同目录下创建另一个新脚本,随便起个文件名,但两个脚本要在同一个文件夹里。

在新脚本里运行这段代码:

import fun
a = fun.f(2)
print(a)
7

我们还可以只导入函数f

from fun import f
a = f(2)

发现了什么?

在其他脚本里通过关键字import导入,就可以像直接在fun.py里直接调用f函数一样使用函数。

回顾一下上次练习中的游戏猜大小的部分代码:

import random
num = random.randint(1,1000)

当然我们也可以只导入randint

form random import randint
num = randint(1,1000)

你可以理解为random是Python自带的一个隐形的文件,你导入了它,就可以使用它里面的函数。实际上你可以在你的Python安装目录下的lib文件夹里可以找到random文件。

什么,你不知道Python的安装目录?

打开cmd,输入咒语where python,回车,你就找到了。

不不,不要看着路径一下一下点进目录,直接拷贝你的python目录(注意是目录,不包括最后的python.exe),在cmd中接着输入start 粘贴你的目录,像这样:

回车,看看发生了什么。

cmd真是个好东西,我们以后可以用它来搞事情,当然是使用Python调用cmd。

Python标准库

像random这样由函数或类组成的包,在Python里称之为

python自带了很多这种库,被称为python标准库。而你上面写的fun.py可以当作非标准库。

https://docs.python.org/zh-cn/3/library/index.html里可以看到所有python的标准库,之后我也会陆续介绍一些常用的标准库。

这里介绍其中一个标准库:time

import time     #导入time库
help(time.time) #使用help函数获得time.time的帮助信息

如果你英语不错的话可以看懂运行结果,不然就和我一样借助词典:

Help on built-in function time in module time:

time(...)
    time() -> floating point number

    Return the current time in seconds since the Epoch.
    Fractions of a second may be present if the system clock provides them.

floating point number告诉我们这个函数返回是一个浮点数。

Return the current time in seconds since the Epoch.翻译过来就是:返回自Epoch到现在以来以秒为单位的时间。

Epoch是1970.01.01 00:00:00 这一时刻。

print出来看看:

import time
print(time.time())
1583914783.291243

你的值应该比我的大,除非你穿越而来在我写这一节前跑了上面这段程序,或者你电脑坏了。

注意使用help时用的time.time,而print时是time.time(),函数没括号代表着是函数它本身,函数后有括号则表示执行函数返回结果。

之后我们会用到各种各样的库,万一我抽风没把库讲清楚,你可以借助help函数本地查询用法。

而time标准库意义重大,这代表我们掌握一个伟大的工具:时间!

还记得最开始的手指抽筋模拟器吗,这里我要给出它的第一次升级版本:

#手指抽筋模拟器基础语法升级版.py

import time
num = 0
input("你点我啊!")
start = time.time()
while time.time()-start <= 10:
    input()
    num += 1
    print("啊啊啊~")
print("10秒内你点击了%d次"%(num))
while True:
    input()

input("你点我啊!")等待玩家开始点击。

start = time.time()记录开始时间。

while time.time()-start <= 10: 当时间过去的时间小于等于10,就继续循环,否则结束循环。

最后的又写了一个循环,是为了双击文件执行时,窗口不会在十秒结束循环后自动关闭。

列表、元组与字典

我们在穿过一扇门时就会看见另一扇门

列表
a = [1,"2",3.456]

Python中列表是由中括号括起来的元素的集合,元素可以是任何数据,包括函数和之后要提到的类。

列表的索引
print(a[1])
print(a[-1])

运行结果:

2
3.456

列表后面中括号来索引元素,中括号里的整数代表第几个元素。注意:在编程的世界里,第一个元素的索引是0,以此类推,所以a[1]的结果是"2"a[-1]索引的是倒数第一个元素,倒数第二个是a[-2],依次类推。

有点绕,多试试再继续下面的内容。

获取列表的长度
a = [1,2,3]
print(len(a))
3
列表的修改
a[1]=233
print(a)
[1, 233, 3.456]
列表的增减
a = []
a.append(1)
a.append(2)
a.append(3)
print(a)
[1, 2, 3]

a = []创建了一个空列表。

你注意到这里使用了.操作符,好像a是个上面函数中说的文件似的,但它确实是自己写的一个变量名啊!

Python赋予了列表类似文件中的函数效果,实际上不管是文件还是列表,python都把它当作一个类。之后我们回详细解释类,现在你只需要有这个概念就行了。

后面的append函数进行的是增加元素操作,它会把新元素添加在列表的最后。

在指定位置插入:

a = [1,2,3,4]
a.insert(2,2.5)
print(a)
[1, 2, 2.5, 3, 4]

a.insert(2,2.5)在索引为2的元素前面插入了新元素2.5。来,和我一起依次数索引:0,1,2,3 。

删除指定索引的元素:

a = [1,2,3,4]
a.pop(2)
print(a)
[1, 2, 4]

直接删除一个元素:

a = [1,2,3,2,3,4]
a.remove(2)
print(a)
[1, 3, 2, 3, 4]

注意:remove只会删除第一个匹配的值。

拼接与切片(截取)
a = [1,2,3]
b = [4,5,6]
c = a + b
d = a * 2
print(c)
print(d)
[1, 2, 3, 4, 5, 6]
[1, 2, 3, 1, 2, 3]

加法把两个列表元素连起来,乘法把元素个数翻倍,其它算术符号就不要试了,否则列表会说:“我们没有结果”,然后抛给你一推错误。

接下来特别重要,将来你会不断地尝试不断地疑惑列表的切片(就像我一样):

a = [1,2,3,4]
print(a[1:3])
print(a[2:])
print(a[:-2])
[2, 3]
[3, 4]
[1, 2]

中括号里[x:y]由冒号隔开的两个索引x、y切割了列表,它会返回列表索引x(包括x)到索引y(不包括y)之间的元素构成的新列表。

如果不写x,默认就是0,不写y,默认就是-1 。

多试一试,理解一下再继续。

元组
a = (1,"2",3.456)

元组是由小括号括起来的元素集合,它拥有和列表相同的操作方式,但是一点不同的是,元组一旦创建不能再修改里面的元素,如果你试图修改或增减元组:

a[1] = 5
Traceback (most recent call last):
    a[1] = 5
TypeError: 'tuple' object does not support item assignment
a.append(5)
Traceback (most recent call last):
    a.append(5)
AttributeError: 'tuple' object has no attribute 'append'

它会无情地抛出一推错误,顺便测试一下你的英语水平。

总结:元组不能修改增减元素,但可以向列表一样索引拼接和截取。

字典
a = {"狗":"dog","猫":"cat",1:"one","one":1}
print(a["狗"])
print(a[1])
dog
one

字典是由花括号括起,里面是一对对键值(key:value),键值对之间没有顺序,我们要通过键(key)来查询值(value)。

可以这样添加新的键值对:

a[2] = "two"

字典里的键是唯一的:

a = {}
a["two"] = 2
a["two"] = "兔"
print(a["two"])

删除操作:

del a["two"] #删除指定键值对
a.clear()    #清空字典
del a        #删除字典
字符串的拼接和切片
a = "Hello "
b = "World!"
print(a[1])
print(a+b)
print(a+'\n'+b)
e
Hello World!
Hello 
World!
a = "Hello World!"
print(a[2:5])
print(a[:-3])
llo
Hello Wor

可以看到,字符串的拼接和切片方式与列表完全一样。

for循环

Python提供了for……in来遍历(依次获取)列表或元组:

a = [1,2,3,4]
for b in a:
    print(b)
print("结束")
1
2
3
4
结束

上面这段代码依次从a中拿取元素赋值给变量b,直到a中的元素拿完。

forwhile一样可以使用breakcontinue

in也可以用作条件判断,表示“在……里”,搭配not关键字表示“不在……里”:

a = [1,2,3]
print(1 in a)
print("2" in a)
print("3" not in a)
True
False
True

实现游戏

我们已经学了很多Python的知识,但我们要做一个贪吃蛇游戏,还是不知道从何开始。

怎么把像素显示在屏幕上?

有人把像素显示在屏幕上的代码写成了一个个库,我们只要import一下就可以拿来用了。

电脑端有个不错游戏库叫做Pygame,但是它不能直接用在手机上。

手机上有个图像库叫做kivy,也可以用在电脑上,但是大量用到类,这个我们还没深入了解,冒然深入必将引起不快,所以我们先用Pygame实现游戏,构建游戏的逻辑明白后,不管用什么库都可以很快地重写一遍。

需求

  • 一条由方块组成的蛇,每吃掉一个“苹果”方块,身体便增长一格。

  • 每吃掉一个“苹果”便再随机生成一个新的“苹果”。

  • 玩家用键盘控制蛇的移动方向,蛇一格一格地移动。

  • “蛇头”碰到苹果便为“吃到”,碰到屏幕边缘“墙壁”或者自己的身体便游戏结束。

  • 游戏结束后给出分数(吃掉的苹果数)。

分析

  • 每个方块实际上是个位置信息,比如[x,y]

  • 一条蛇有很多块,我们可以存在一起:[[x0,y0],[x1,y1],[x2,y2]]

  • 需要判断是否吃到苹果或者自己、需要显示分数,可预见的要使用条件判断和函数

  • 每过半秒或多长时间刷新一下画面,让蛇移动一格。需要用到循环。


貌似我们已经学了上面分析中需要用到的所有东西,下一节我们将正式开始游戏之旅!

本系列地址:https://gitee.com/ZiKang12138/course/wikis

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值