海龟绘图案例分析之“动动有奖”计步器
说在前面
这是我为选考班学生讲解“用算法解决问题的过程”时准备的一个案例,目的是帮助学生进一步理解“动动有奖”APP的运行界面和工作原理。虽然直接阅读教材也能理解相关知识点,但终归不如体验程序运行过程来得有趣;而且程序难度不大,学生可以自行修改相关参数,对程序教学也有帮助,也算是一举两得吧。
程序使用turtle模块绘制而成,用到了绘图、写字和响应鼠标点击事件等基本技术。代码写得比较粗糙,请各位老师批评指正,希望能起到抛砖引玉的作用,启发大家创作更多有趣的案例。
程序界面包括一个矩形方框、6行文字信息和1个矩形按钮。其中矩形方框和文字信息共用一支画笔mypen,矩形按钮直接使用画笔tt来绘制。
作图顺序是先直接绘制矩形方框,再调用自定义函数draw_info()在指定位置显示提示信息,最后调用自定义函数draw_keys()在指定位置绘制矩形按钮。参考代码如下:
'''
函数功能:显示程序界面
函数名:draw_windows(mypen)
参数表:mypen -- 当前画笔对象。
返回值:没有返回值。
'''
def draw_windows(c, info, mypen):
mypen.clear()
mypen.color('black')
mypen.penup()
mypen.goto(x0+150, y0+180)
mypen.down()
mypen.seth(0)
for i in range(2):
mypen.fd(300)
mypen.right(90)
mypen.fd(420)
mypen.right(90)
draw_info(x0+300, y0+100, "动动有奖计步器", 'black', 30, mypen)
draw_info(x0+300, y0+50, date.strftime('%Y年%m月%d日'), 'black', 20, mypen)
draw_info(x0+300, y0-10, str(steps)+'步', 'red', 30, mypen)
if continue_days >= 4:
double_info = '翻倍'
else:
double_info = '未翻倍'
draw_info(x0+300, y0-50, f'今日走路赚钱{money:0.1f}金 {double_info}', 'black', 15, mypen)
draw_info(x0+300, y0-100, f'连续签到 {continue_days}天', 'black', 20, mypen)
draw_info(x0+300, y0-150, f'累计奖金 {total_money:0.1f}金', 'black', 20, mypen)
tt.clear()
draw_keys(x0+200, y0-180, 220, 40, info, c, tt)
自定义函数draw_info()和draw_keys()是常用模块,我在多个案例中都用到过它们,算法原理非常简单,只需设置起始坐标等参数即可。参考代码如下:
'''
函数功能:显示提示信息
函数名:draw_info(x, y, text, c, size, mypen)
参数表:x, y -- 显示信息位置;
text -- 显示信息内容;
c -- 画笔颜色;
size -- 字体大小;
mypen -- 当前画笔对象。
返回值:没有返回值。
'''
def draw_info(x, y, text, c, size, mypen):
mypen.color(c)
mypen.penup()
mypen.goto(x, y)
mypen.pendown()
mypen.write(text, align="center", font=("Arial", size, "normal"))
'''
函数功能:根据输入的坐标和大小,绘制方框和文字
函数名:draw_keys(x, y, w, h, text, c, mypen)
参数表:x, y -- 方框左上角坐标;
w, h -- 方框的宽和高;
text -- 方框中文字;
c -- 画笔颜色;
mypen -- 绘制方框和文字所需要的画笔
返回值:没有返回值。
'''
def draw_keys(x, y, w, h, text, c, mypen):
mypen.color(c)
mypen.penup()
mypen.goto(x, y)
mypen.down()
mypen.seth(0)
for i in range(2):
mypen.fd(w)
mypen.right(90)
mypen.fd(h)
mypen.right(90)
mypen.penup()
mypen.goto(x+w/2, y-h*5/6)
mypen.down()
mypen.write(text, align="center", font=("黑体", 20, "normal"))
当点击矩形按钮时,若还未领奖,则需要领取当日奖金(这个与教材中领取昨日奖金不一致),更新相关参数并刷新APP界面。因为要修改奖金总额,连续领奖天数,领奖标记的值,故将它们设置为全局变量。
'''
函数功能:根据鼠标点击屏幕位置,做出相应操作
函数名:play_game(x, y)
参数表:x, y -- 表示鼠标在画布上点击的坐标。
返回值:没有返回值。
'''
def play_game(x, y):
global total_money, continue_days, prize_flag #奖金总额,连续领奖天数,领奖标记
if x0+200 < x < x0+420 and y0-220 < y < y0-180: #点击“点我签到”按钮
if not prize_flag: #还未领奖
prize_flag = True
continue_days += 1
total_money += money
draw_windows('red', "已领,明天再来", info_pen)
主函数部分的代码主要用来设置画笔对象和初始化各种参数。核心代码是一个死循环,循环体内主要有三种操作:响应屏幕鼠标点击事件、每6秒钟更新一次日期和刷新画面。程序使用变量num累计时间,每过1秒钟num增1,每6秒钟更新一次日期。
import turtle as tt
import datetime, time
import random
tt.TurtleScreen._RUNNING = True # 启动绘图,在IDE中运行加这句可避免报错
tt.hideturtle() #隐藏画笔
tt.delay(0)
screen = tt.Screen()
info_pen = tt.Pen() #为显示提示信息设置一只画笔
info_pen.ht()
info_pen.color('red')
info_pen.pensize(2)
total_money = 0 #奖金总额
continue_days = 0 #连续领奖天数
prize_flag = False #领奖标记
x0, y0 = -300, 100 #算式左上角坐标
date = datetime.date(2022, 2, 21)#date对象
num = 0
while True:
tt.tracer(0)
screen.onclick(play_game) #响应屏幕鼠标点击事件
time.sleep(1)
if num % 6 == 0: #每6秒钟更新一次日期
if not prize_flag: #还未领奖
continue_days = 0 #连续领奖天数
date += datetime.timedelta(days=1)
prize_flag = False #领奖标记
steps = random.randint(0, 60000) #走路步数
if steps < 1000:
money = 0
elif steps < 3000:
money = 0.3
elif steps < 55000:
money = 0.3+(steps-1000)//2000*0.1
else:
money = 3
if continue_days >= 3: #连续3天领奖,第4天起奖金翻倍
money *= 2
draw_windows('black', "快来,点我签到", info_pen)
tt.update() #刷新画面
num += 1
tt.done()
由于本案例是备课过程中临时想到的,代码写得很粗糙,尤其是主函数部分代码太长,还可以做进一步抽象,以符合模块化编程思想。
现在请你仔细阅读代码,根据自己的理解,重新编写程序,争取写出更简明高效的代码。
需要本文PPT、源代码和课后练习答案的,可以加入“Python算法之旅”知识星球参与讨论和下载文件,“Python算法之旅”知识星球汇集了数量众多的同好,更多有趣的话题在这里讨论,更多有用的资料在这里分享。
我们专注Python算法,感兴趣就一起来!
相关优秀文章: