《我的第一本程式設計書》第四章 程式的變形,繪製大量的方塊

伊徵銀王發表於2019-12-31

第四章 程式的變形,繪製大量的方塊

1.回顧上一章,繪製一個4*4的方塊,並在左上角。

儲存區[1]->0
只要  儲存區[1]<4
    儲存區[0]->0
    只要 儲存區[0]<4
        儲存區[60000+儲存區[0]+(儲存區[1]*100)]->999999
        儲存區[0]->儲存區[0]+1
    儲存區[1]->儲存區[1]+1

2.繪製一個從上到下,間隔1畫素的這樣的方塊20個。

1)首先可以把上述的這個4*4的方塊理解成一個整體。
2)然後只要在這個基礎上迴圈20次。

儲存區[2]->0
只要 儲存區<20
    {4*4的方塊的程式碼}
    儲存區[2]->儲存區[2]+1

但這樣的迴圈,只會在4*4的方塊處原位重複20次,所以也就導致結果還是1個4*4的方塊。
所以,為了能讓4*4方塊向下輸出20個,並且還要有一個1畫素的間隔,就必須追加一個引數。

3)繪製有1畫素間隔的,從上到下有20個的4*4的方塊。

由於一個方塊是由4*4的畫素組成,所以從上到下需要4個畫素,也就是4行。再加上一個1畫素的間隔行,所以整體相加,也就是從需要5個畫素行,來對應一個方塊。
再根據螢幕的固定矩陣60000*69999,第一行第一個畫素與第二行第一個畫素之間的進位是:100。
所以5行的畫素就等於5*100=500
然後每5行為一個基本4*4方塊的單位,並用變數進行表示:

儲存區[2]*500

整體程式碼為:

儲存區[2]->0
只要 儲存區[2]<20
    儲存區[1]->0
    只要 儲存區[1]<4
        儲存區[0]->0
        只要 儲存區[0]<4
            儲存區[60000+儲存區[0]+(儲存區[1]*100)+(儲存區[2]*500)]->999999
            儲存區[0]->儲存區[0]+1
        儲存區[1]->儲存區[1]+1
    儲存區[2]->儲存區[2]+1

關鍵在:

儲存區[60000+儲存區[0]+(儲存區[1]*100)+(儲存區[2]*500)]->999999

i.儲存區[數字]->999999:“數字”在60000到69999之間的話,表示顯示畫素,“數字”在這之外的話,可以視為一個變數X。“999999”即可以表示數字,也可以表示顏色的數值。取決於儲存區內數字的範圍。
ii.“60000”:顯示畫素的儲存區啟示位置。 iii.“儲存區[0]”:為一橫行有幾個畫素 iv.“儲存區[1]*100”:為一豎行有幾個畫素 v.“儲存區[2]*500”:為一個方塊加1個畫素的基本量

3.繪製右側的牆壁
上述可作為俄羅斯方塊的左則的牆壁,所以通過修改儲存區[]內的數字,來繪製右側的牆壁。

繪製一個從左數,5*11個畫素距離的右側牆壁。
除去左牆壁佔據的5個畫素,所以中間活動的區域只有10個方塊的量。

儲存區[2]->0
只要 儲存區[2]<20
    儲存區[1]->0
    只要 儲存區[1]<4
        儲存區[0]->0
        只要 儲存區[0]<4
            儲存區[60055+儲存區[0]+(儲存區[1]*100)+(儲存區[2]*500)]->999999
            儲存區[0]->儲存區[0]+1
        儲存區[1]->儲存區[1]+1
    儲存區[2]->儲存區[2]+1

基本上也就是修改“60000”這個引數。並且一行也就100個畫素點,所以只要不超過“60099”行。 但一個4*4的方塊,一行需要4個畫素和一個畫素間隔,所以也就按照5的倍數進行相加,並且最終不能超過60099-5=60094

4.繪製底部牆壁。
由於左則牆壁最後一個方塊對應的是“69500”,再加上該區域已經有方塊被繪製出來,所以底部的牆壁起始點為69500+5=69505.
再加上左側牆壁和右側牆壁之間,只有10個4*4方塊的距離,所以迴圈的次數也不再是20,而是10. 最後就是因為橫向的關係,所以過度單位也不再是500,而是5. 於是如下:

儲存區[2]->0
只要 儲存區[2]<10
    儲存區[1]->0
    只要 儲存區[1]<4
        儲存區[0]->0
        只要 儲存區[0]<4
            儲存區[69505+儲存區[0]+(儲存區[1]*100)+(儲存區[2]*5)]->999999
            儲存區[0]->儲存區[0]+1
        儲存區[1]->儲存區[1]+1
    儲存區[2]->儲存區[2]+1

"69505":為最底層的方塊的第二個方塊的起點
“(儲存區[2]*5)”:為每一橫行的每個方塊的間隔量為5.

5.完整的程式碼

#左邊的牆壁
儲存區[2]->0
只要 儲存區[2]<20
    儲存區[1]->0
    只要 儲存區[1]<4
        儲存區[0]->0
        只要 儲存區[0]<4
            儲存區[60000+儲存區[0]+(儲存區[1]*100)+(儲存區[2]*500)]->999999
            儲存區[0]->儲存區[0]+1
        儲存區[1]->儲存區[1]+1
    儲存區[2]->儲存區[2]+1

#右邊的牆壁
儲存區[2]->0
只要 儲存區[2]<20
    儲存區[1]->0
    只要 儲存區[1]<4
        儲存區[0]->0
        只要 儲存區[0]<4
            儲存區[60055+儲存區[0]+(儲存區[1]*100)+(儲存區[2]*500)]->999999
            儲存區[0]->儲存區[0]+1
        儲存區[1]->儲存區[1]+1
    儲存區[2]->儲存區[2]+1

#底面的牆壁
儲存區[2]->0
只要 儲存區[2]<10
    儲存區[1]->0
    只要 儲存區[1]<4
        儲存區[0]->0
        只要 儲存區[0]<4
            儲存區[69505+儲存區[0]+(儲存區[1]*100)+(儲存區[2]*5)]->999999
            儲存區[0]->儲存區[0]+1
        儲存區[1]->儲存區[1]+1
    儲存區[2]->儲存區[2]+1

號為註釋,以便區分程式碼塊,從而更好的閱讀理解。

6.優化程式碼(這是我最難想到的地方!)

首先左側牆壁和右側牆壁的大部分都相同,除了最終的部分:

#左側牆壁
儲存區[60000+儲存區[0]+(儲存區[1]*100)+(儲存區[2]*500)]->999999
#右側牆壁
儲存區[60055+儲存區[0]+(儲存區[1]*100)+(儲存區[2]*500)]->999999

於是將這部分整合:

#左邊的牆壁
儲存區[2]->0
只要 儲存區[2]<20
    儲存區[1]->0
    只要 儲存區[1]<4
        儲存區[0]->0
        只要 儲存區[0]<4
            儲存區[60000+儲存區[0]+(儲存區[1]*100)+(儲存區[2]*500)]->999999
            儲存區[60055+儲存區[0]+(儲存區[1]*100)+(儲存區[2]*500)]->999999
            儲存區[0]->儲存區[0]+1
        儲存區[1]->儲存區[1]+1
    儲存區[2]->儲存區[2]+1

2)然而這之中還有被重複用到的比分! 即:

儲存區[0]+(儲存區[1]*100)+(儲存區[2]*500)

所以也就把這部分存放到一個變數中,即:

儲存區[3]->儲存區[0]+(儲存區[1]*100)+(儲存區[2]*500)

其實儲存區[3]裡的數字換成其他不在60000-69999之間的任何數都行,只是習慣的問題? 總之核心部分如下:

儲存區[3]->儲存區[0]+(儲存區[1]*100)+(儲存區[2]*500)
儲存區[60000+儲存區[3]]->999999
儲存區[60055+儲存區[3]]->999999

整體結構如下:

儲存區[2]->0
只要 儲存區[2]<20
    儲存區[1]->0
    只要 儲存區[1]<4
        儲存區[0]->0
        只要 儲存區[0]<4
            儲存區[3]->儲存區[0]+(儲存區[1]*100)+(儲存區[2]*500)
            儲存區[60000+儲存區[3]]->999999    #左側牆壁
            儲存區[60055+儲存區[3]]->999999    #右側牆壁
            儲存區[0]->儲存區[0]+1
        儲存區[1]->儲存區[1]+1
    儲存區[2]->儲存區[2]+1

3)合併底層牆壁
由於底層牆壁與左右兩側的個數不同,畫素點位置也不盡相同,但它們都需要遍歷出4*4個方塊。
於是,只要不注重輸出的過程形式,就可以選擇把4*4的方塊繪製拿到最外層。 如:

儲存區[1]->0
只要 儲存區[1]<4
    儲存區[0]->0
    只要 儲存區[0]<4
        {繪製牆壁的部分}
        儲存區[0]->儲存區[0]+1
    儲存區[1]->儲存區[1]+1

而牆壁的部分:

        #左右牆壁
        儲存區[2]->0
        只要 儲存區[2]<20
            儲存區[3]->儲存區[0]+(儲存區[1]*100)+(儲存區[2]*500)
            儲存區[60000+儲存區[3]]->999999
            儲存區[60055+儲存區[3]]->999999
            儲存區[2]->儲存區[2]+1

        #底層牆壁
        儲存區[2]->0
        只要 儲存區[2]<10
            儲存區[69505+儲存區[0]+(儲存區[1]*100)+(儲存區[2]*5)]->999999
            儲存區[2]->儲存區[2]+1

完成程式碼則是:

儲存區[1]->0
只要 儲存區[1]<4
    儲存區[0]->0
    只要 儲存區[0]<4

        #左右牆壁
        儲存區[2]->0
        只要 儲存區[2]<20
            儲存區[3]->儲存區[0]+(儲存區[1]*100)+(儲存區[2]*500)
            儲存區[60000+儲存區[3]]->999999
            儲存區[60055+儲存區[3]]->999999
            儲存區[2]->儲存區[2]+1

        #底層牆壁
        儲存區[2]->0
        只要 儲存區[2]<10
            儲存區[69505+儲存區[0]+(儲存區[1]*100)+(儲存區[2]*5)]->999999
            儲存區[2]->儲存區[2]+1
        儲存區[0]->儲存區[0]+1
    儲存區[1]->儲存區[1]+1

也就是一個畫素一個畫素的渲染,從而達到優化程式碼的效果。 (這是很重要的,而我卻就是無法獨立想出來啊!)

書中的本章總結:

1.有多重迴圈時,程式會變得很複雜。
(所以註釋的用途就顯現出來了!)

2.註釋的寫法。
(這裡採用的是#號,有些是//、/**/、等形式)

3.較之寫註釋,不如將程式寫得更易懂。但註釋也是很重要的。 (也就是說,能優化最好優化,但面對上千上萬的程式碼,再優化的程式碼也需要註釋來劃分啊!)

4.存在多個迴圈時,如果迴圈次數一樣,就可以進行合併。
但程式的順序會發生變化。 (能合併是沒錯,但輸出的樣子將會發生改變,而你所要求的效果與改變後的不符合,那就只能視情況而定了!)

5.當需要多次進行同一計算的時候,可以先計算出結果,然後重複使用。 (就像上面的“儲存區[3]”,將重複的部分賦值到儲存區[3]裡,然後再重複使用。)

6.有時可以對迴圈進行內外對調。但執行順序會發生改變。 (與上述4同理)

7.程式不一定越短越好。縮短程式只是程式設計中的手段罷了! (一切都視情況而定,畢竟要的效果不一樣,自然執行的程式也不一樣。)

相關文章