<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          海龜繪圖案例分析之移動(dòng)火柴變等式游戲(2)

          共 7311字,需瀏覽 15分鐘

           ·

          2022-02-20 01:34

          說在前面

          移動(dòng)一根火柴棒使等式成立,是一種簡單有趣的智力游戲,只需具備簡單的算術(shù)知識(shí),就能參與游戲,老少皆宜,深受大家的喜愛。

          上節(jié)課我和大家分享了創(chuàng)建題庫的方法,并花了很大力氣來介紹如何將結(jié)構(gòu)相同的多段代碼精簡成循環(huán)語句,里面用到的一些技巧非常有趣,希望能對大家有所啟發(fā)。

          今天我們學(xué)習(xí)第二部分——繪制七段管算術(shù)表達(dá)式。


          1.七段管數(shù)字

          所謂七段管數(shù)字,就是用7個(gè)發(fā)光二極管來組成的阿拉伯?dāng)?shù)字。我們?yōu)檫@7個(gè)二極管按照從上到下、從左到右的順序依次編號(hào)為0-6。部分?jǐn)?shù)字所需二極管的編號(hào)如下圖所示:

          根據(jù)七段管數(shù)字的形狀,我們可以創(chuàng)建字典digits來存儲(chǔ)各數(shù)字所需二極管的編號(hào),有digits ={0:(0,1,2,4,5,6),1:(2,5),2:(0,2,3,4,6),3:(0,2,3,5,6),4:(1,2,3,5),5:(0,1,3,5,6),6:(0,1,3,4,5,6),7:(0,2,5),8:(0,1,2,3,4,5,6),9:(0,1,2,3,5,6)}。


          2.繪制單個(gè)二極管

          使用turtle模塊繪制二極管的方法很多,最簡單的方法就是繪制一條線段。在本例中可以設(shè)置畫筆粗細(xì)等于二極管的寬度,繪制與二極管等長的線段。因?yàn)椴煌幪?hào)的二極管方向不一樣,需要考慮畫筆的朝向,故操作比想象的要復(fù)雜。

          另一種思路是把每個(gè)二極管都看作是矩形,可以根據(jù)二極管的長度d和寬度w,按照編號(hào)順序,設(shè)置各二極管的左上角和右下角坐標(biāo)(假設(shè)數(shù)字的左上角為坐標(biāo)原點(diǎn)),并存儲(chǔ)到列表x_y中,有x_y =[(w*5/4,0,w*5/4+d,-w),(0,-w/2,w,-w/2-d),(d+w*3/2+1,-w/2,d+w*5/2+1,-w/2-d),(w*5/4,-w/4-d,w*5/4+d,-w/4-d-w),(0,-w-d,w,-w-d*2),(d+w*3/2+1,-w-d,d+w*5/2+1,-w-d*2),(w*5/4,-w/2-d*2,w*5/4+d,-w*3/2-d*2)]。

          由此可以根據(jù)二極管的坐標(biāo)信息,繪制矩形并填充顏色(此外,確定各二極管的坐標(biāo)范圍,還為后面鼠標(biāo)定位提供了方便)。自定義函數(shù)如下:

          '''函數(shù)功能:根據(jù)左上角和右下角坐標(biāo)繪制矩形并填充顏色函數(shù)名:draw_rectangle(x1, y1, x2, y2, c)參數(shù)表:x1, y1 -- 矩形的左上角坐標(biāo);       x2, y2 -- 矩形的右下角坐標(biāo);       c -- 畫筆顏色。返回值:沒有返回值。'''def draw_rectangle(x1, y1, x2, y2, c): #繪制某根二極管    tt.color(c)    tt.begin_fill()    tt.penup()    tt.goto(x1, y1)    tt.pendown()    tt.goto(x2, y1)    tt.goto(x2, y2)    tt.goto(x1, y2)    tt.goto(x1, y1)    tt.end_fill()
          3.繪制單個(gè)七段管數(shù)字

          ?? 有了字典digits和列表x_y,我們就可以調(diào)用draw_rectangle()函數(shù)在指定位置繪制單個(gè)七段管數(shù)字了。方法很簡單,就是遍歷digits[num],依次繪制組成數(shù)字num的每根二極管即可。參考代碼如下:

          '''函數(shù)功能:根據(jù)給定的左上角坐標(biāo)、長度、寬度和畫筆顏色,利用字典digits繪制七段管數(shù)字num函數(shù)名:draw_num(x, y, d, w,c, num)參數(shù)表:x,y -- 七段管數(shù)字的左上角坐標(biāo);        d,w -- 二極管的長度和寬度;        c -- 畫筆顏色;        num -- 要繪制的七段管數(shù)字。返回值:沒有返回值。'''def draw_num(x, y, d, w, c,num): #繪制七段管數(shù)字    for i in digits[num]:  #digits[num]包含了組成數(shù)字num的所有二極管編號(hào)        draw_rectangle(x_y[i][0]+x,x_y[i][1]+y, x_y[i][2]+x, x_y[i][3]+y, c)
          我們可以使用下列語句調(diào)用函數(shù)draw_num(),在不同位置繪制10個(gè)七段管數(shù)字:
          for i in range(10):    draw_num(-500+i*(d+d),150, d, w, 'green', i)    draw_num(-500+i*(d+d),300, d, w,  'red', i)

          效果圖如下所示:


          4.繪制七段管算術(shù)表達(dá)式

          若想要繪制七段管算術(shù)表達(dá)式,就需要預(yù)先定義繪制運(yùn)算符的函數(shù)。本案例中只考慮'+-='三種運(yùn)算符。我們可以模仿七段管數(shù)字的繪制方法,將它們看作矩形組合,根據(jù)二極管的長度和寬度,規(guī)定好每個(gè)矩形的左上角和右下角坐標(biāo),調(diào)用draw_rectangle()函數(shù)繪制各個(gè)矩形即可。參考代碼如下:
          '''函數(shù)功能:根據(jù)給定的左上角坐標(biāo)、邊長和畫筆顏色,繪制運(yùn)算符op函數(shù)名:draw_operator(x, y, d,w, c, op)參數(shù)表:x,y -- 七段管數(shù)字的左上角坐標(biāo);        d,w -- 二極管的長度和寬度;        c-- 畫筆顏色;        op -- 要繪制的運(yùn)算符。返回值:沒有返回值。'''def draw_operator(x, y, d, w,c, op): #繪制運(yùn)算符    if op == '-':        draw_rectangle(x+w, y-w/4-d, x+w+d,y-w/4-d-w, c)    elif op == '+':        draw_rectangle(x+w, y-w/4-d, x+w+d,y-w/4-d-w, c)        draw_rectangle(x+w/2+d/2, y-w*3/4-d/2,x+w/2+d/2+w, y-w*3/4-d/2-d, c)    elif op == '=':        draw_rectangle(x+w, y+w*5/4-d, x+w+d,y+w/4-d, c)        draw_rectangle(x+w, y-w*7/4-d, x+w+d,y-w*11/4-d, c)
          至此,我們完成了所有準(zhǔn)備工作,可以繪制算術(shù)表達(dá)式了。先創(chuàng)建一個(gè)存儲(chǔ)了算術(shù)表達(dá)式的字符串exp,然后遍歷exp,調(diào)用draw_num()函數(shù)繪制數(shù)字,調(diào)用draw_operator()函數(shù)繪制運(yùn)算符,參考代碼如下:
          exp = '3+6-5=4'for i, ch in enumerate(exp):    if ch in '+-=':       draw_operator(-500+i*(d+d), 0, d, w, 'red', ch)    else:        ch = int(ch)       draw_num(-500+i*(d+d), 0, d, w, 'red', ch)

          效果圖如下所示:


          5.程序升級(jí)?

          上述程序能夠繪制七段管算術(shù)表達(dá)式,但還沒有實(shí)現(xiàn)游戲中“移動(dòng)火柴棒”功能,因?yàn)樗挥幸恢М嫻P。要想獨(dú)立繪制或清除每一根火柴棒(二極管),我們需要為每根火柴棒(二極管)都創(chuàng)建一支畫筆。

          人生沒有白走的路,每一步都算數(shù)。每一個(gè)項(xiàng)目的編程經(jīng)驗(yàn)都可以遷移到新項(xiàng)目中。有了前面的鋪墊,我們可以順利地完成“火柴棒算式”的繪制工作。


          6.設(shè)置各火柴棒坐標(biāo)

          因?yàn)椤盎鸩癜羲闶健钡母袷绞枪潭ǖ?,形如a+b=c或a-b=c。所以我們可以事先設(shè)置好組成算式的各火柴棒的左上角和右下角坐標(biāo),以便今后繪圖。

          前面我們介紹了存儲(chǔ)單個(gè)七段管數(shù)字信息的列表x_y,我們可以在它的基礎(chǔ)上依次存儲(chǔ)數(shù)字a,b,c的全部二極管坐標(biāo)信息,再把構(gòu)成運(yùn)算符的二極管坐標(biāo)信息也存儲(chǔ)起來。每個(gè)數(shù)字和運(yùn)算符之間距離為2*d,在數(shù)字a的基礎(chǔ)上分別向右平移4*d和8*d,即可得到數(shù)字b和c的二極管坐標(biāo)信息。

          由此我們可以得到組成“火柴棒算式”的總共25根火柴棒(二極管)的坐標(biāo)信息(即矩形的左上角和右下角坐標(biāo))。參考代碼如下:

          '''函數(shù)功能:設(shè)置組成算式的各火柴棒左上角和右下角坐標(biāo),以便今后繪圖函數(shù)名:get_pos(x, y, d, w)參數(shù)表:d,w – 二極管的長度和寬度。返回值:返回存儲(chǔ)了各火柴棒左上角和右下角坐標(biāo)的列表。'''def get_pos(d, w): #設(shè)置組成算式的各火柴棒左上角和右下角坐標(biāo)    #根據(jù)七段管的長度和寬度,設(shè)置各二極管的左上角和右下角坐標(biāo)(以數(shù)字的左上角為坐標(biāo)原點(diǎn))    x_y =[(w*5/4,0,w*5/4+d,-w),(0,-w/2,w,-w/2-d),(d+w*3/2+1,-w/2,d+w*5/2+1,-w/2-d),(w*5/4,-w/4-d,w*5/4+d,-w/4-d-w),          (0,-w-d,w,-w-d*2),(d+w*3/2+1,-w-d,d+w*5/2+1,-w-d*2),(w*5/4,-w/2-d*2,w*5/4+d,-w*3/2-d*2)]       for i in (2, 4): #添加數(shù)字b和c各條邊的左上角和右下角坐標(biāo),向右平移2*d        for j in range(7):           x_y.append((x_y[j][0]+i*2*d, x_y[j][1], x_y[j][2]+i*2*d, x_y[j][3]))    #組成運(yùn)算符的各火柴棒左上角和右下角坐標(biāo)(減號(hào)只有一條橫線,加號(hào)再加一條豎線)    x_y.append((w+2*d,-w/4-d, w+d+2*d, -w/4-d-w))   x_y.append((w/2+d/2+2*d, -w*3/4-d/2, w/2+d/2+w+2*d, -w*3/4-d/2-d))    #組成等號(hào)的各火柴棒左上角和右下角坐標(biāo)(等號(hào)有2條橫線)    x_y.append((w+6*d,w*5/4-d, w+d+6*d, w/4-d))    x_y.append((w+6*d,-w*7/4-d, w+d+6*d, -w*11/4-d))    return x_y
          7.繪制單根火柴棒

          繪制單根火柴棒的函數(shù)與前面繪制單個(gè)二極管的函數(shù)幾乎一模一樣,唯一的區(qū)別就是:每根火柴棒都有單獨(dú)的畫筆,所以需要提供一個(gè)畫筆對象。代碼如下:

          '''函數(shù)功能:根據(jù)左上角和右下角坐標(biāo)繪制矩形并填充顏色函數(shù)名:draw_rectangle(x1, y1, x2, y2, c, mypen)參數(shù)表:x1, y1 -- 矩形的左上角坐標(biāo);       x2, y2 -- 矩形的右下角坐標(biāo);       c -- 畫筆顏色;       mypen -- 該條邊對應(yīng)的畫筆對象。返回值:沒有返回值。'''def draw_rectangle(x1, y1, x2, y2, c, mypen): #繪制七段管的某條邊    mypen.color(c)    mypen.begin_fill()    mypen.penup()    mypen.goto(x1, y1)    mypen.pendown()    mypen.goto(x2, y1)    mypen.goto(x2, y2)    mypen.goto(x1, y2)    mypen.goto(x1, y1)    mypen.end_fill()

          8.繪制操作數(shù)?

          繪制操作數(shù)就相當(dāng)于前面所講的繪制單個(gè)七段管數(shù)字,區(qū)別在于a,b,c三個(gè)操作數(shù)的位置已經(jīng)定下來了,我們可以根據(jù)其在算式字符串中的下標(biāo)來找到構(gòu)成它的火柴棒。

          此外,已經(jīng)存在的火柴棒不能被重復(fù)繪制,所以我們需要定義一個(gè)全局變量stick_flag,它是一個(gè)列表,存儲(chǔ)了各火柴棒是否已經(jīng)被繪制的信息——該列表記錄的信息是移動(dòng)火柴棒的憑據(jù),避免重復(fù)繪制火柴棒或移動(dòng)根本不存在的火柴棒。參考代碼如下:

          '''函數(shù)功能:根據(jù)某個(gè)操作數(shù)的起點(diǎn)坐標(biāo)和它在算式字符串中的下標(biāo)等信息,利用字典digits繪制該操作數(shù)函數(shù)名:draw_num(x, y, i, num, d, w, c)參數(shù)表:x, y -- 該操作數(shù)的左上角坐標(biāo);       i -- 該操作數(shù)在算式字符串中的下標(biāo);       num -- 該操作數(shù)的值;       d -- 七段管的邊長,即火柴棒的長度;       w,c -- 畫筆粗細(xì)和顏色。返回值:沒有返回值,全局變量stick_flag記錄用到了哪些火柴棒。'''def draw_num(x, y, i, num, d, w, c): #繪制某個(gè)操作數(shù)    global stick_flag #記錄火柴棒是否已經(jīng)被繪制    for j in digits[num]:#digits[num]包含了組成數(shù)字num的所有火柴棒編號(hào)        stick_flag[7*i+j]= True #編號(hào)為7*i+j的火柴棒已經(jīng)被繪制       draw_rectangle(pos_map[7*i+j][0]+x,pos_map[7*i+j][1]+y,pos_map[7*i+j][2]+x,pos_map[7*i+j][3]+y,c,stick_pens[7*i+j])
          9.繪制算式

          我們可以先調(diào)用函數(shù)get_pos()獲取組成“火柴棒算式”的總共25根火柴棒的坐標(biāo)信息,并依次存儲(chǔ)到列表pos_map中。然后根據(jù)各操作數(shù)和運(yùn)算符在列表pos_map中的下標(biāo),依次繪制3個(gè)操作數(shù)、運(yùn)算符和等號(hào)。代碼如下:

          '''函數(shù)功能:根據(jù)算式的起點(diǎn)坐標(biāo)和畫筆顏色,繪制算式exp函數(shù)名:draw_expression(x, y, c, exp)參數(shù)表:x, y -- 該算式的左上角坐標(biāo);       c -- 畫筆顏色;       exp -- 表示算式的字符串,例如'a+b=c'。返回值:沒有返回值,全局變量stick_flag記錄用到了哪些火柴棒。'''      def draw_expression(x, y, c, exp): #繪制算式    global stick_flag #記錄火柴棒是否已經(jīng)被繪制     for i in (0, 1, 2): #先依次繪制3個(gè)操作數(shù)        draw_num(x, y, i,int(exp[i*2]), d, w, c)    for i in range(21,25):  #再依次繪制運(yùn)算符和等號(hào)        if i == 22 andexp[1] != '+':            continue        stick_flag[i] =True   #編號(hào)為i的火柴棒已經(jīng)被繪制      draw_rectangle(pos_map[i][0]+x,pos_map[i][1]+y,pos_map[i][2]+x,pos_map[i][3]+y,c,stick_pens[i])

          有了這些自定義函數(shù),我們就可以在主函數(shù)中設(shè)置全局變量的初始值,并調(diào)用函數(shù)繪制算式了。主函數(shù)部分代碼如下:

          import turtle as ttimport random tt.TurtleScreen._RUNNING =True  # 啟動(dòng)繪圖,在IDE中運(yùn)行加這句可避免報(bào)錯(cuò)tt.speed(0)tt.delay(0)#組成七段管數(shù)字所需管子的編號(hào)(按照從上到下、從左到右順序)digits ={0:(0,1,2,4,5,6),1:(2,5),2:(0,2,3,4,6),3:(0,2,3,5,6),4:(1,2,3,5),         5:(0,1,3,5,6),6:(0,1,3,4,5,6),7:(0,2,5),8:(0,1,2,3,4,5,6),9:(0,1,2,3,5,6)}x0, y0 = -300, 250 #算式左上角坐標(biāo)d, w = 50, 10  #七段管的長度和寬度pos_map = get_pos(d, w) #存儲(chǔ)組成算術(shù)式的各火柴棒左上角和右下角坐標(biāo)stick_flag = [False for i inrange(25)] #判斷某根火柴棒是否已繪制,共25根火柴棒stick_pens = [tt.Pen() for iin range(26)] #為每一跟火柴棒設(shè)置一支畫筆,共25根,再加一支寫無解的畫筆for p in stick_pens:    p.ht()#隱藏筆頭    p.pensize(1)exp = '3+2=5'draw_expression(x0, y0,'red', exp) #繪制算式tt.done()

          程序輸出效果圖如下所示:


          課后作業(yè)

          除了將每個(gè)二極管都看作是矩形,我在文中還提到了設(shè)置畫筆粗細(xì)等于二極管的寬度,繪制與二極管等長的線段來表示二極管的方法。請根據(jù)此思路編寫繪制七段管算術(shù)表達(dá)式的程序。參考效果圖如下:


          需要本文PPT、源代碼和課后練習(xí)答案的,可以加入“Python算法之旅”知識(shí)星球參與討論和下載文件,Python算法之旅”知識(shí)星球匯集了數(shù)量眾多的同好,更多有趣的話題在這里討論,更多有用的資料在這里分享。

          我們專注Python算法,感興趣就一起來!

          相關(guān)優(yōu)秀文章:

          閱讀代碼和寫更好的代碼

          最有效的學(xué)習(xí)方式

          Python算法之旅文章分類

          海龜繪圖案例分析之移動(dòng)火柴變等式游戲

          瀏覽 27
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  97人人色 | 蜜桃网站视频无码高清 | 啪啪啪啪啪啪AVXXX | 婷婷一区二区 | 亚洲色图在线播放 |