您的位置:首页 >聚焦 >

海龟绘图案例分析之“动动有奖”计步器

2022-03-18 09:43:36    来源:程序员客栈

说在前面

这是我为选考班学生讲解“用算法解决问题的过程”时准备的一个案例,目的是帮助学生进一步理解“动动有奖”APP的运行界面和工作原理。虽然直接阅读教材也能理解相关知识点,但终归不如体验程序运行过程来得有趣;而且程序难度不大,学生可以自行修改相关参数,对程序教学也有帮助,也算是一举两得吧。

程序使用turtle模块绘制而成,用到了绘图、写字和响应鼠标点击事件等基本技术。代码写得比较粗糙,请各位老师批评指正,希望能起到抛砖引玉的作用,启发大家创作更多有趣的案例。

成品效果图1.显示程序界面

程序界面包括一个矩形方框、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"))

2.响应鼠标点击事件

当点击矩形按钮时,若还未领奖,则需要领取当日奖金(这个与教材中领取昨日奖金不一致),更新相关参数并刷新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 = Truecontinue_days += 1total_money += moneydraw_windows("red", "已领,明天再来", info_pen)

3.主函数代码

主函数部分的代码主要用来设置画笔对象和初始化各种参数。核心代码是一个死循环,循环体内主要有三种操作:响应屏幕鼠标点击事件、每6秒钟更新一次日期和刷新画面。程序使用变量num累计时间,每过1秒钟num增1,每6秒钟更新一次日期。

import turtle as ttimport datetime, timeimport randomtt.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 = 0while 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 = 0elif steps < 3000:money = 0.3elif steps < 55000:money = 0.3+(steps-1000)//2000*0.1else:money = 3if continue_days >= 3: #连续3天领奖,第4天起奖金翻倍money *= 2draw_windows("black", "快来,点我签到", info_pen)tt.update() #刷新画面num += 1tt.done()

至此,我们就顺利地完成了模拟“动动有奖”APP的功能,你可以在主函数中修改各种参数,就能自定义程序界面和模拟效果了。课后练习

由于本案例是备课过程中临时想到的,代码写得很粗糙,尤其是主函数部分代码太长,还可以做进一步抽象,以符合模块化编程思想。

现在请你仔细阅读代码,根据自己的理解,重新编写程序,争取写出更简明高效的代码。

需要本文PPT、源代码和课后练习答案的,可以加入“Python算法之旅”知识星球参与讨论和下载文件,“Python算法之旅”知识星球汇集了数量众多的同好,更多有趣的话题在这里讨论,更多有用的资料在这里分享。

我们专注Python算法,感兴趣就一起来!

相关优秀文章:

阅读代码和写更好的代码

最有效的学习方式

Python算法之旅文章分类

关键词: 函数功能 显示提示 指定位置

相关阅读