海龜繪圖案例分析之“動(dòng)動(dòng)有獎(jiǎng)”計(jì)步器
說(shuō)在前面
這是我為選考班學(xué)生講解“用算法解決問(wèn)題的過(guò)程”時(shí)準(zhǔn)備的一個(gè)案例,目的是幫助學(xué)生進(jìn)一步理解“動(dòng)動(dòng)有獎(jiǎng)”APP的運(yùn)行界面和工作原理。雖然直接閱讀教材也能理解相關(guān)知識(shí)點(diǎn),但終歸不如體驗(yàn)程序運(yùn)行過(guò)程來(lái)得有趣;而且程序難度不大,學(xué)生可以自行修改相關(guān)參數(shù),對(duì)程序教學(xué)也有幫助,也算是一舉兩得吧。
程序使用turtle模塊繪制而成,用到了繪圖、寫字和響應(yīng)鼠標(biāo)點(diǎn)擊事件等基本技術(shù)。代碼寫得比較粗糙,請(qǐng)各位老師批評(píng)指正,希望能起到拋磚引玉的作用,啟發(fā)大家創(chuàng)作更多有趣的案例。

程序界面包括一個(gè)矩形方框、6行文字信息和1個(gè)矩形按鈕。其中矩形方框和文字信息共用一支畫筆mypen,矩形按鈕直接使用畫筆tt來(lái)繪制。
作圖順序是先直接繪制矩形方框,再調(diào)用自定義函數(shù)draw_info()在指定位置顯示提示信息,最后調(diào)用自定義函數(shù)draw_keys()在指定位置繪制矩形按鈕。參考代碼如下:
'''函數(shù)功能:顯示程序界面函數(shù)名:draw_windows(mypen)參數(shù)表:mypen -- 當(dāng)前畫筆對(duì)象。返回值:沒(méi)有返回值。'''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, "動(dòng)動(dòng)有獎(jiǎng)計(jì)步器", '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'連續(xù)簽到 {continue_days}天', 'black', 20, mypen)draw_info(x0+300, y0-150, f'累計(jì)獎(jiǎng)金 {total_money:0.1f}金', 'black', 20, mypen)tt.clear()draw_keys(x0+200, y0-180, 220, 40, info, c, tt)
自定義函數(shù)draw_info()和draw_keys()是常用模塊,我在多個(gè)案例中都用到過(guò)它們,算法原理非常簡(jiǎn)單,只需設(shè)置起始坐標(biāo)等參數(shù)即可。參考代碼如下:
'''函數(shù)功能:顯示提示信息函數(shù)名:draw_info(x, y, text, c, size, mypen)參數(shù)表:x, y -- 顯示信息位置;text -- 顯示信息內(nèi)容;c -- 畫筆顏色;size -- 字體大?。?/span>mypen -- 當(dāng)前畫筆對(duì)象。返回值:沒(méi)有返回值。'''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"))'''函數(shù)功能:根據(jù)輸入的坐標(biāo)和大小,繪制方框和文字函數(shù)名:draw_keys(x, y, w, h, text, c, mypen)參數(shù)表:x, y -- 方框左上角坐標(biāo);w, h -- 方框的寬和高;text -- 方框中文字;c -- 畫筆顏色;mypen -- 繪制方框和文字所需要的畫筆返回值:沒(méi)有返回值。'''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"))
當(dāng)點(diǎn)擊矩形按鈕時(shí),若還未領(lǐng)獎(jiǎng),則需要領(lǐng)取當(dāng)日獎(jiǎng)金(這個(gè)與教材中領(lǐng)取昨日獎(jiǎng)金不一致),更新相關(guān)參數(shù)并刷新APP界面。因?yàn)橐薷莫?jiǎng)金總額,連續(xù)領(lǐng)獎(jiǎng)天數(shù),領(lǐng)獎(jiǎng)標(biāo)記的值,故將它們?cè)O(shè)置為全局變量。
'''函數(shù)功能:根據(jù)鼠標(biāo)點(diǎn)擊屏幕位置,做出相應(yīng)操作函數(shù)名:play_game(x, y)參數(shù)表:x, y -- 表示鼠標(biāo)在畫布上點(diǎn)擊的坐標(biāo)。返回值:沒(méi)有返回值。'''def play_game(x, y):global total_money, continue_days, prize_flag #獎(jiǎng)金總額,連續(xù)領(lǐng)獎(jiǎng)天數(shù),領(lǐng)獎(jiǎng)標(biāo)記if x0+200 < x < x0+420 and y0-220 < y < y0-180: #點(diǎn)擊“點(diǎn)我簽到”按鈕if not prize_flag: #還未領(lǐng)獎(jiǎng)prize_flag = Truecontinue_days += 1total_money += moneydraw_windows('red', "已領(lǐng),明天再來(lái)", info_pen)
主函數(shù)部分的代碼主要用來(lái)設(shè)置畫筆對(duì)象和初始化各種參數(shù)。核心代碼是一個(gè)死循環(huán),循環(huán)體內(nèi)主要有三種操作:響應(yīng)屏幕鼠標(biāo)點(diǎn)擊事件、每6秒鐘更新一次日期和刷新畫面。程序使用變量num累計(jì)時(shí)間,每過(guò)1秒鐘num增1,每6秒鐘更新一次日期。?
import turtle as ttimport datetime, timeimport randomtt.TurtleScreen._RUNNING = True # 啟動(dòng)繪圖,在IDE中運(yùn)行加這句可避免報(bào)錯(cuò)tt.hideturtle() #隱藏畫筆tt.delay(0)screen = tt.Screen()info_pen = tt.Pen() #為顯示提示信息設(shè)置一只畫筆info_pen.ht()info_pen.color('red')info_pen.pensize(2)total_money = 0 #獎(jiǎng)金總額continue_days = 0 #連續(xù)領(lǐng)獎(jiǎng)天數(shù)prize_flag?=?False?#領(lǐng)獎(jiǎng)標(biāo)記x0, y0 = -300, 100 #算式左上角坐標(biāo)date = datetime.date(2022, 2, 21)#date對(duì)象num = 0while True:tt.tracer(0)screen.onclick(play_game) #響應(yīng)屏幕鼠標(biāo)點(diǎn)擊事件time.sleep(1)if num % 6 == 0: #每6秒鐘更新一次日期if not prize_flag: #還未領(lǐng)獎(jiǎng)continue_days = 0 #連續(xù)領(lǐng)獎(jiǎng)天數(shù)date += datetime.timedelta(days=1)prize_flag = False #領(lǐng)獎(jiǎng)標(biāo)記steps = random.randint(0, 60000) #走路步數(shù)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: #連續(xù)3天領(lǐng)獎(jiǎng),第4天起獎(jiǎng)金翻倍money *= 2draw_windows('black', "快來(lái),點(diǎn)我簽到", info_pen)tt.update() #刷新畫面num += 1tt.done()
由于本案例是備課過(guò)程中臨時(shí)想到的,代碼寫得很粗糙,尤其是主函數(shù)部分代碼太長(zhǎng),還可以做進(jìn)一步抽象,以符合模塊化編程思想。
現(xiàn)在請(qǐng)你仔細(xì)閱讀代碼,根據(jù)自己的理解,重新編寫程序,爭(zhēng)取寫出更簡(jiǎn)明高效的代碼。
需要本文PPT、源代碼和課后練習(xí)答案的,可以加入“Python算法之旅”知識(shí)星球參與討論和下載文件,“Python算法之旅”知識(shí)星球匯集了數(shù)量眾多的同好,更多有趣的話題在這里討論,更多有用的資料在這里分享。
我們專注Python算法,感興趣就一起來(lái)!
相關(guān)優(yōu)秀文章:
