SlideShare a Scribd company logo
1 of 21
Download to read offline
4 串列(一)
直條圖 (一)
50
本題直條圖長度介於 [1,9] 之間,以亂數決定,線條的數量由鍵
盤輸入。由於直條為縱向線與程式的橫向列印方向剛好垂直,程式無
法直接一次印出整條直線方式。上圖的直條線看似複雜,但初學者應
學會簡化問題到可以完成的形式,解決後再逐步修改到原始問題。
4 串列(一)
直條圖 (二)
51
假想問題為以下型式,* 的數量即是直條線長度,直條線上方空格使用
句點表示:
4 串列(一)
直條圖 (三)
52
讓直條圖的直線長度統一由底部向上數,且在圖形左側標示 s 軸,
由 9 向下遞減至 1,如此可觀察到對每條直條線,當 s 大於直條
線長度,則印空格(句點),否則印星號。加上一些設定,程式的主體
部份就可寫成以下形式:
n = int(input("> "))
vals = [ random.randint(1,9) for i in range(1,n) ]
for s in range(9,0,-1) :
for val in vals :
if s > val :
print( ’ ’ , end=" " )
else :
print( ’*’ , end=" " )
print()
4 串列(一)
直條圖 (四)
53
有了以上簡單可運作的程式後,再逐漸修改到原始問題就容易
了初學者要特別留意,雖然僅是在圖形上寫了一些數字與符號,
但往往透過這些簡單註記才聯想到可行的運作步驟,找到方法。
一般來說,程式設計經常有七成以上的時間用在紙筆推導,尋
找可行步驟,有了解題步驟後,剩下的時間才是用在程式撰寫上
。若在學習過程中省去了紙筆推導,往往要耗費更多的時間才能
完成程式設計,有時甚至無法順利完成,徒然浪費時間,這不是
一件划算的事。
4 串列(一) 54
直條圖 (五)
import random
while True :
# 斜條線數量
n = int( input("> ") )
# m 最長直線高
# w 直條圖寬 (>=3)
m , w = 9 , 3
# 使用亂數設定各直條線長
vals = [ random.randint(1,m) for i in range(1,n+1) ]
# 畫直條線
for s in range(m,0,-1) :
for val in vals :
if s > val :
print( " "*w , end=" " )
elif s == val :
print( "/" + "*"*(w-2) + "" , end=" " )
else :
print( "|" + "*"*(w-2) + "|" , end=" " )
print()
# 組合格式列印所使用的字串:置中對齊數字
ws = "{:^" + str(w) + "}"
# 輸出長度數字
for val in vals :
print( ws.format(val) , end=" " )
print()
4 串列(一) 55
螺旋數字 (一)
> 4 > 5
--------------------- --------------------------
| 1 | 2 | 3 | 4 | | 1 | 2 | 3 | 4 | 5 |
--------------------- --------------------------
| 12 | 13 | 14 | 5 | | 16 | 17 | 18 | 19 | 6 |
--------------------- --------------------------
| 11 | 16 | 15 | 6 | | 15 | 24 | 25 | 20 | 7 |
--------------------- --------------------------
| 10 | 9 | 8 | 7 | | 14 | 23 | 22 | 21 | 8 |
--------------------- --------------------------
| 13 | 12 | 11 | 10 | 9 |
--------------------------
4 串列(一) 56
螺旋數字 (二)
本範例要印出順時鐘螺旋遞增的數字,由於數字遞增方向與列印的順序不同,
同時也找不到數學公式可直接由位置推算數字,造成無法直接使用雙層迴圈方式列
印螺旋數字圖案。
一個可行方式是先設定一個二維串列,然後依照數字遞增位置螺旋式行進,逐
一存入數字。觀察下圖,,數字 1 由 ■ 開始,然後依照 → ↓ ← ↑ 四個方向
循環行進,每當走到 ▲、、▼、 等位置時就要改換下個方向。
4 串列(一) 57
螺旋數字 (三)
螺旋圖的四個循環方向可用變數 dir 來表示,以 0 1 2 3 分別代表 → ↓ ← ↑。
四個方向的行進方式可用 ds 與 dt 兩串列代表在 s 與 t 方向的移動距離。向 → 走
一步等同 dt 為 1,ds 不更動。向 ↓ 走一步即是 ds 為 1,dt 不變,以下表表示:
當填入的數字落到三角形位置時,就要轉彎改用下個方向,也就是要調整 dir 的數
值。此外程式設計的重點變得要找出所有三角形位置的幾何表示方式。仔細觀察三角形在
本頁圖中的位置分佈,利用簡單的國中數學即可推導出所有三角形都落在以下三個幾何條
件之中:
1. s + t == n-1
2. s >= n//2 and s == t
3. s < n//2 and s == t+1
有了以上的轉彎條件,換成程式語言就只是簡單的替換而已。由此例可知應用
「數學思維」於程式設計的重要性,否則本題的程式碼是無法憑空撰寫出來。
方向 → ↓ ← ↑
dir 0 1 2 3
ds 0 1 0 -1
dt 1 0 -1 0
4 串列(一)
螺旋數字 (四)
58
while True :
n = int( input("> ") )
# 二維串列儲存數字
nums = [ [None]*n for i in range(n) ]
# 起始位置
s , t = 0 , 0
# 四個方向的前進方式
ds , dt = [0,1,0,-1] , [1,0,-1,0]
# 中間數
m = n//2 + ( 1 if n%2 else 0 )
# 起始方向
dir = 0
for i in range(n*n) :
nums[s][t] = i + 1
# 判斷是否轉彎
if s+t==n-1 or ( s >= m and s==t ) or ( s < m and s==t+1 ) :
dir += 1
if dir == 4 : dir = 0
# 更新位置
s += ds[dir]
t += dt[dir]
# 列印數字
print( "-"*(5*n+1) )
for i in range(n) :
for j in range(n) :
print( "|{:>3}".format(nums[i][j]) , end=" " )
print( "|" )
print( "-"*(5*n+1) )
print()
4 串列(一)
點矩陣數字 (一)
59
 計算機輸出的文字許多都是用點矩陣來表示,所謂的點矩陣文字有點像將
文字的筆劃填入方格紙上的格子中,若文字的筆劃出現在小格子內,則表
示需要印出一小點,若沒在格子內,則印出空格。現在用八個二進位數來
表示八個格點,若是格子有塗滿則表示 1,若沒有塗滿則表示 0,舉例來
說,數字
用圖表示為
4 串列(一)
點矩陣數字 (二)
60
0 1 1 1 1 1 1 1 → 127
0 0 0 0 1 0 0 0 → 8
0 0 0 0 1 0 0 0 → 8
0 0 1 1 1 1 1 0 → 62
0 0 0 0 1 0 1 0 → 10
0 0 0 1 0 0 1 0 → 18
0 0 1 0 0 1 0 0 → 36
1 1 1 1 1 1 1 1 → 255
若每個文字使用 8× 8 的格子來表示,則下圖的國字「五」中每一排的數字分別為
以上「五」每列用一個數字,八列共八個數字。同樣的,若用 5× 4 格子點來表示
個別的阿拉伯數字,例如以下輸出的數字 9,五列分別是 15 9 15 1 15 等五
個數字,15 來自四個 1,即 ,9 為 ,其他依此類推。
4 串列(一)
點矩陣數字 (三)
61
> 9876543210
9999 8888 7777 6666 5555 4 4 3333 2222 1 0000
9 9 8 8 7 6 5 4 4 3 2 1 0 0
9999 8888 7 6666 5555 4444 3333 2222 1 0 0
9 8 8 7 6 6 5 4 3 2 1 0 0
9999 8888 7 6666 5555 4 3333 2222 1 0000
本程式先將 0 到 9 等十個數字的點矩資料存在二維串列 bmap,利用位
元運算可很快判斷某位元位置是否有值,隨即印出對應的格點字元。
4 串列(一)
點矩陣數字 (四)
62
# 0 到 9 數字點矩陣
bmap = ( (15,9,9,9,15), (2,2,2,2,2), (15,1,15,8,15), (15,1,15,1,15),
(9,9,15,1,1), (15,8,15,1,15), (15,8,15,9,15), (15,1,2,2,2),
(15,9,15,9,15), (15,9,15,1,15) )
# 每個矩矩陣的橫列數與直行數
R , C = len(bmap[0]) , 4
while True :
num = input("> " )
# nos 為 num 的各個位數串列
nos = [ int(s) for s in list(num) ] # num 也可不用置於 list() 內
print()
# 數字的每一列
for r in range(R) :
# 每個數字
for n in nos :
# 數字的每一行
for c in range(C-1,-1,-1) :
# 判斷位元位置是否有值
if bmap[n][r] & ( 1 << c ) :
print( n , end="" )
else :
print( " " , end="" )
print( " " , end="" )
print()
print()
4 串列(一)
中大雙重點矩陣 (一)
63
4 串列(一)
中大雙重點矩陣 (二)
64
本題要用程式印出上圖中的「中」字有中,「大」字有大的雙重點矩輸出圖案。
題目看似複雜,但卻可完全依照列印順序設計對應迴圈完成程式。
程式共用了五層迴圈,最外兩層迴圈分別為大小縱向 s 與 r ,內三層迴圈皆
為橫向,分別為 k、t、c。k 為「中大」兩字的下標,t 與 c 為大小橫向迴圈,
都為逆向遞減,以下為圖示。
4 串列(一)
中大雙重點矩陣 (三)
65
由以上圖示可知:s 走一步,r 需走一圈;r 走一步,k 走一圈; k 走一
步,t 逆向走一圈;t 走一步,c 逆向走一圈。這種走法如同時間的月、日、時
、分、秒運行方式一樣。此外以上 t 與 c 逆向排列的原因可參考上個範例程式
碼中的第 25 列。
由圖中可知,每當 r 走一步時,程式即需跳一列。在列印 o 字元時,需判
斷大點矩陣與小點矩陣是否同時有值,若無則印空格。程式中的「中」與「大」兩
個中文字的點矩陣直接使用 16 進位數字表示,這種數值表示方式是直接將每列
的點陣數值以每四個位元換一個 16 進位數替代,省去轉為十進位數的過程,使
得設定中文字的點陣數字變得簡單許多。
本程式雖用了五層迴圈,但只要依照字元列印順序,找出相關的變數變化方式
,即可正確排列出各層迴圈的順序。加上運用位元運算來判斷數值的位元資料,使
得撰寫出來的程式碼相當簡潔。本題有了以上的圖示後,程式碼即能很快地完成,
這也再度說明紙筆推導的重要性。
4 串列(一)
中大雙重點矩陣 (四)
66
# 「中大」兩字的點矩陣
ncu = ( (0x4,0x1f,0x15,0x1f,0x4) , (0x4,0x1f,0x4,0xa,0x11) )
R , C = len(ncu[0]) , 5
# 大縱向
for s in range(R):
# 小縱向
for r in range(R):
print( ” ” , end=”” )
# 每個中文字
for k in range(len(ncu)):
# 大橫向
for t in range(C-1,-1,-1):
# 小橫向
for c in range(C-1,-1,-1):
# 檢查列印條件是否滿足
if ( ncu[k][r] & ( 1 << c ) ) and ( ncu[k][s] & ( 1 << t ) ):
print( ”o” , end=”” )
else:
print( ” ” , end=”” )
print( ” ” , end=”” )
print( ” ” , end=”” )
print(” ”)
4 串列(一)
彈珠臺 (一)
67
4 串列(一)
彈珠臺 (二)
68
藉由計算機快速的運算能力,程式可以靠著大量的重複執行來模擬機率問題,
本問題是要藉由設計程式來模擬彈珠滾到彈珠臺底層各個字母欄位的機率。
本題程式設計的重點是要利用數學來定義球的橫向位置,當底層字母欄位
的位置確定了,就可知道彈珠最後落在哪個字母欄位。觀察彈珠臺可知滾輪由
左向右共有 11 個橫向位置,依次可設為 0 1 2 ... 10 等 11 個座標
。有了滾輪橫向位置,底層字母欄位就可定為 0 2 4 6 8 10,五個可能的
彈珠入口位置則為 1 3 5 7 9,參考下圖。
4 串列(一)
彈珠臺 (三)
69
每一次模擬,先以亂數決定彈珠是由哪個入口滾入彈珠臺,即產生 1 3 5
7 9 五數的其中一數。接下來當彈珠撞到滾輪時,以亂數決定彈珠向左或向右
彈跳。若向左,彈珠位置減 1,向右,彈珠位置加 1。若彈珠碰到兩側時,
直接將彈珠位置設定為 0 或 10 結束當次模擬。
迴圈的每一次都是利用數學模擬彈珠由上而下,一層層的撞到滾輪,向左
右彈跳,最後落在底層字母欄位而結束。模擬結束後,球落在字母欄位的機率
就是在各個欄位的彈珠數量與總模擬次數的比值,本題是一個簡單又有趣的數
學機率模擬題目。
4 串列(一)
彈珠臺(四)
70
from random import *
n , total = 5 , 50000
counts = [ 0 for x in range(n+1) ]
for k in range(total) :
# 起始落下的位置
p = 2*randint(1,n) – 1
# 第一層釘子
move = 2*randint(0,1) – 1
p += move
# 第二到第五層釘子
for i in range(2) :
move = 2*randint(0,1) – 1
p += move
# 碰到兩側,提前離開
if p < 0 or p > 2*n : break
move = 2*randint(0,1) – 1
p += move
# 球數統計
if p < 0 :
counts[0] += 1
elif p > 2*n :
counts[-1] += 1
else :
counts[p//2] += 1
# 列印
for no in counts :
s = int(160*no/total+0.5)
print(str(s)+”/160”,end=” ”)
print()

More Related Content

What's hot (20)

Ch9 習題
Ch9 習題Ch9 習題
Ch9 習題
 
Func diff cal_exercise2-3
Func diff cal_exercise2-3Func diff cal_exercise2-3
Func diff cal_exercise2-3
 
Ppt 1-50
Ppt 1-50Ppt 1-50
Ppt 1-50
 
Ppt 26-50
Ppt 26-50Ppt 26-50
Ppt 26-50
 
P127 135 new
P127 135 newP127 135 new
P127 135 new
 
Ppt 101-119
Ppt 101-119Ppt 101-119
Ppt 101-119
 
Ppt 1-25
Ppt 1-25Ppt 1-25
Ppt 1-25
 
Python p.193 197
Python p.193 197Python p.193 197
Python p.193 197
 
Polar example
Polar examplePolar example
Polar example
 
Ch2 教學
Ch2 教學Ch2 教學
Ch2 教學
 
Appendix A 教學
Appendix A 教學Appendix A 教學
Appendix A 教學
 
Ch10 習題
Ch10 習題Ch10 習題
Ch10 習題
 
Ch6 教學
Ch6 教學Ch6 教學
Ch6 教學
 
Ch12 範例
Ch12 範例Ch12 範例
Ch12 範例
 
Ppt 51-77
Ppt 51-77Ppt 51-77
Ppt 51-77
 
Ch7 習題
Ch7 習題Ch7 習題
Ch7 習題
 
Ch11 範例
Ch11 範例Ch11 範例
Ch11 範例
 
Ch9 範例
Ch9 範例Ch9 範例
Ch9 範例
 
Ch5 範例
Ch5 範例Ch5 範例
Ch5 範例
 
Python differential equation
Python differential equationPython differential equation
Python differential equation
 

More from hungchiayang1 (20)

Exercise 1 3
Exercise 1 3Exercise 1 3
Exercise 1 3
 
化學系 python 習題
化學系 python 習題化學系 python 習題
化學系 python 習題
 
化學系 python 練習
化學系 python 練習化學系 python 練習
化學系 python 練習
 
化學系 python 教學
化學系 python 教學化學系 python 教學
化學系 python 教學
 
Ppt 120-126
Ppt 120-126Ppt 120-126
Ppt 120-126
 
Ppt 151-151
Ppt 151-151Ppt 151-151
Ppt 151-151
 
Ppt 136-136
Ppt 136-136Ppt 136-136
Ppt 136-136
 
Ppt 143-143
Ppt 143-143Ppt 143-143
Ppt 143-143
 
Ppt 137-137
Ppt 137-137Ppt 137-137
Ppt 137-137
 
Ppt 150-150
Ppt 150-150Ppt 150-150
Ppt 150-150
 
Ppt 145-149
Ppt 145-149Ppt 145-149
Ppt 145-149
 
Ppt 138-142
Ppt 138-142Ppt 138-142
Ppt 138-142
 
Ppt 174-174
Ppt 174-174Ppt 174-174
Ppt 174-174
 
Ppt 144-144
Ppt 144-144Ppt 144-144
Ppt 144-144
 
Ppt 152-155
Ppt 152-155Ppt 152-155
Ppt 152-155
 
Ppt 156-156
Ppt 156-156Ppt 156-156
Ppt 156-156
 
Ppt 166-166
Ppt 166-166Ppt 166-166
Ppt 166-166
 
Ppt 165-165
Ppt 165-165Ppt 165-165
Ppt 165-165
 
Ppt 157-157
Ppt 157-157Ppt 157-157
Ppt 157-157
 
Ppt 175-175
Ppt 175-175Ppt 175-175
Ppt 175-175
 

Recently uploaded

哪里可以购买日本筑波学院大学学位记/做个假的文凭可认证吗/仿制日本大学毕业证/意大利语CELI证书定制
哪里可以购买日本筑波学院大学学位记/做个假的文凭可认证吗/仿制日本大学毕业证/意大利语CELI证书定制哪里可以购买日本筑波学院大学学位记/做个假的文凭可认证吗/仿制日本大学毕业证/意大利语CELI证书定制
哪里可以购买日本筑波学院大学学位记/做个假的文凭可认证吗/仿制日本大学毕业证/意大利语CELI证书定制jakepaige317
 
中国文学, 了解王安石变法,熙宁变法,熙盛变法- 中国古代改革的类型- 富国强兵,
中国文学, 了解王安石变法,熙宁变法,熙盛变法- 中国古代改革的类型- 富国强兵,中国文学, 了解王安石变法,熙宁变法,熙盛变法- 中国古代改革的类型- 富国强兵,
中国文学, 了解王安石变法,熙宁变法,熙盛变法- 中国古代改革的类型- 富国强兵,Xin Yun Teo
 
EDUC6506_ClassPresentation_TC330277 (1).pptx
EDUC6506_ClassPresentation_TC330277 (1).pptxEDUC6506_ClassPresentation_TC330277 (1).pptx
EDUC6506_ClassPresentation_TC330277 (1).pptxmekosin001123
 
educ6506presentationtc3302771-240427173057-06a46de5.pptx
educ6506presentationtc3302771-240427173057-06a46de5.pptxeduc6506presentationtc3302771-240427173057-06a46de5.pptx
educ6506presentationtc3302771-240427173057-06a46de5.pptxmekosin001123
 
EDUC6506(001)_ClassPresentation_2_TC330277 (1).pptx
EDUC6506(001)_ClassPresentation_2_TC330277 (1).pptxEDUC6506(001)_ClassPresentation_2_TC330277 (1).pptx
EDUC6506(001)_ClassPresentation_2_TC330277 (1).pptxmekosin001123
 
泽兰应用科学大学毕业证制作/定制国外大学录取通知书/购买一个假的建国科技大学硕士学位证书
泽兰应用科学大学毕业证制作/定制国外大学录取通知书/购买一个假的建国科技大学硕士学位证书泽兰应用科学大学毕业证制作/定制国外大学录取通知书/购买一个假的建国科技大学硕士学位证书
泽兰应用科学大学毕业证制作/定制国外大学录取通知书/购买一个假的建国科技大学硕士学位证书jakepaige317
 
1.🎉“入侵大学入学考试中心修改成绩”来袭!ALEVEL替考大揭秘,轻松搞定考试成绩! 💥你还在为无法进入大学招生系统而烦恼吗?想知道如何通过技术手段更改...
1.🎉“入侵大学入学考试中心修改成绩”来袭!ALEVEL替考大揭秘,轻松搞定考试成绩! 💥你还在为无法进入大学招生系统而烦恼吗?想知道如何通过技术手段更改...1.🎉“入侵大学入学考试中心修改成绩”来袭!ALEVEL替考大揭秘,轻松搞定考试成绩! 💥你还在为无法进入大学招生系统而烦恼吗?想知道如何通过技术手段更改...
1.🎉“入侵大学入学考试中心修改成绩”来袭!ALEVEL替考大揭秘,轻松搞定考试成绩! 💥你还在为无法进入大学招生系统而烦恼吗?想知道如何通过技术手段更改...黑客 接单【TG/微信qoqoqdqd】
 

Recently uploaded (7)

哪里可以购买日本筑波学院大学学位记/做个假的文凭可认证吗/仿制日本大学毕业证/意大利语CELI证书定制
哪里可以购买日本筑波学院大学学位记/做个假的文凭可认证吗/仿制日本大学毕业证/意大利语CELI证书定制哪里可以购买日本筑波学院大学学位记/做个假的文凭可认证吗/仿制日本大学毕业证/意大利语CELI证书定制
哪里可以购买日本筑波学院大学学位记/做个假的文凭可认证吗/仿制日本大学毕业证/意大利语CELI证书定制
 
中国文学, 了解王安石变法,熙宁变法,熙盛变法- 中国古代改革的类型- 富国强兵,
中国文学, 了解王安石变法,熙宁变法,熙盛变法- 中国古代改革的类型- 富国强兵,中国文学, 了解王安石变法,熙宁变法,熙盛变法- 中国古代改革的类型- 富国强兵,
中国文学, 了解王安石变法,熙宁变法,熙盛变法- 中国古代改革的类型- 富国强兵,
 
EDUC6506_ClassPresentation_TC330277 (1).pptx
EDUC6506_ClassPresentation_TC330277 (1).pptxEDUC6506_ClassPresentation_TC330277 (1).pptx
EDUC6506_ClassPresentation_TC330277 (1).pptx
 
educ6506presentationtc3302771-240427173057-06a46de5.pptx
educ6506presentationtc3302771-240427173057-06a46de5.pptxeduc6506presentationtc3302771-240427173057-06a46de5.pptx
educ6506presentationtc3302771-240427173057-06a46de5.pptx
 
EDUC6506(001)_ClassPresentation_2_TC330277 (1).pptx
EDUC6506(001)_ClassPresentation_2_TC330277 (1).pptxEDUC6506(001)_ClassPresentation_2_TC330277 (1).pptx
EDUC6506(001)_ClassPresentation_2_TC330277 (1).pptx
 
泽兰应用科学大学毕业证制作/定制国外大学录取通知书/购买一个假的建国科技大学硕士学位证书
泽兰应用科学大学毕业证制作/定制国外大学录取通知书/购买一个假的建国科技大学硕士学位证书泽兰应用科学大学毕业证制作/定制国外大学录取通知书/购买一个假的建国科技大学硕士学位证书
泽兰应用科学大学毕业证制作/定制国外大学录取通知书/购买一个假的建国科技大学硕士学位证书
 
1.🎉“入侵大学入学考试中心修改成绩”来袭!ALEVEL替考大揭秘,轻松搞定考试成绩! 💥你还在为无法进入大学招生系统而烦恼吗?想知道如何通过技术手段更改...
1.🎉“入侵大学入学考试中心修改成绩”来袭!ALEVEL替考大揭秘,轻松搞定考试成绩! 💥你还在为无法进入大学招生系统而烦恼吗?想知道如何通过技术手段更改...1.🎉“入侵大学入学考试中心修改成绩”来袭!ALEVEL替考大揭秘,轻松搞定考试成绩! 💥你还在为无法进入大学招生系统而烦恼吗?想知道如何通过技术手段更改...
1.🎉“入侵大学入学考试中心修改成绩”来袭!ALEVEL替考大揭秘,轻松搞定考试成绩! 💥你还在为无法进入大学招生系统而烦恼吗?想知道如何通过技术手段更改...
 

Ch4 範例

  • 1. 4 串列(一) 直條圖 (一) 50 本題直條圖長度介於 [1,9] 之間,以亂數決定,線條的數量由鍵 盤輸入。由於直條為縱向線與程式的橫向列印方向剛好垂直,程式無 法直接一次印出整條直線方式。上圖的直條線看似複雜,但初學者應 學會簡化問題到可以完成的形式,解決後再逐步修改到原始問題。
  • 2. 4 串列(一) 直條圖 (二) 51 假想問題為以下型式,* 的數量即是直條線長度,直條線上方空格使用 句點表示:
  • 3. 4 串列(一) 直條圖 (三) 52 讓直條圖的直線長度統一由底部向上數,且在圖形左側標示 s 軸, 由 9 向下遞減至 1,如此可觀察到對每條直條線,當 s 大於直條 線長度,則印空格(句點),否則印星號。加上一些設定,程式的主體 部份就可寫成以下形式: n = int(input("> ")) vals = [ random.randint(1,9) for i in range(1,n) ] for s in range(9,0,-1) : for val in vals : if s > val : print( ’ ’ , end=" " ) else : print( ’*’ , end=" " ) print()
  • 5. 4 串列(一) 54 直條圖 (五) import random while True : # 斜條線數量 n = int( input("> ") ) # m 最長直線高 # w 直條圖寬 (>=3) m , w = 9 , 3 # 使用亂數設定各直條線長 vals = [ random.randint(1,m) for i in range(1,n+1) ] # 畫直條線 for s in range(m,0,-1) : for val in vals : if s > val : print( " "*w , end=" " ) elif s == val : print( "/" + "*"*(w-2) + "" , end=" " ) else : print( "|" + "*"*(w-2) + "|" , end=" " ) print() # 組合格式列印所使用的字串:置中對齊數字 ws = "{:^" + str(w) + "}" # 輸出長度數字 for val in vals : print( ws.format(val) , end=" " ) print()
  • 6. 4 串列(一) 55 螺旋數字 (一) > 4 > 5 --------------------- -------------------------- | 1 | 2 | 3 | 4 | | 1 | 2 | 3 | 4 | 5 | --------------------- -------------------------- | 12 | 13 | 14 | 5 | | 16 | 17 | 18 | 19 | 6 | --------------------- -------------------------- | 11 | 16 | 15 | 6 | | 15 | 24 | 25 | 20 | 7 | --------------------- -------------------------- | 10 | 9 | 8 | 7 | | 14 | 23 | 22 | 21 | 8 | --------------------- -------------------------- | 13 | 12 | 11 | 10 | 9 | --------------------------
  • 7. 4 串列(一) 56 螺旋數字 (二) 本範例要印出順時鐘螺旋遞增的數字,由於數字遞增方向與列印的順序不同, 同時也找不到數學公式可直接由位置推算數字,造成無法直接使用雙層迴圈方式列 印螺旋數字圖案。 一個可行方式是先設定一個二維串列,然後依照數字遞增位置螺旋式行進,逐 一存入數字。觀察下圖,,數字 1 由 ■ 開始,然後依照 → ↓ ← ↑ 四個方向 循環行進,每當走到 ▲、、▼、 等位置時就要改換下個方向。
  • 8. 4 串列(一) 57 螺旋數字 (三) 螺旋圖的四個循環方向可用變數 dir 來表示,以 0 1 2 3 分別代表 → ↓ ← ↑。 四個方向的行進方式可用 ds 與 dt 兩串列代表在 s 與 t 方向的移動距離。向 → 走 一步等同 dt 為 1,ds 不更動。向 ↓ 走一步即是 ds 為 1,dt 不變,以下表表示: 當填入的數字落到三角形位置時,就要轉彎改用下個方向,也就是要調整 dir 的數 值。此外程式設計的重點變得要找出所有三角形位置的幾何表示方式。仔細觀察三角形在 本頁圖中的位置分佈,利用簡單的國中數學即可推導出所有三角形都落在以下三個幾何條 件之中: 1. s + t == n-1 2. s >= n//2 and s == t 3. s < n//2 and s == t+1 有了以上的轉彎條件,換成程式語言就只是簡單的替換而已。由此例可知應用 「數學思維」於程式設計的重要性,否則本題的程式碼是無法憑空撰寫出來。 方向 → ↓ ← ↑ dir 0 1 2 3 ds 0 1 0 -1 dt 1 0 -1 0
  • 9. 4 串列(一) 螺旋數字 (四) 58 while True : n = int( input("> ") ) # 二維串列儲存數字 nums = [ [None]*n for i in range(n) ] # 起始位置 s , t = 0 , 0 # 四個方向的前進方式 ds , dt = [0,1,0,-1] , [1,0,-1,0] # 中間數 m = n//2 + ( 1 if n%2 else 0 ) # 起始方向 dir = 0 for i in range(n*n) : nums[s][t] = i + 1 # 判斷是否轉彎 if s+t==n-1 or ( s >= m and s==t ) or ( s < m and s==t+1 ) : dir += 1 if dir == 4 : dir = 0 # 更新位置 s += ds[dir] t += dt[dir] # 列印數字 print( "-"*(5*n+1) ) for i in range(n) : for j in range(n) : print( "|{:>3}".format(nums[i][j]) , end=" " ) print( "|" ) print( "-"*(5*n+1) ) print()
  • 10. 4 串列(一) 點矩陣數字 (一) 59  計算機輸出的文字許多都是用點矩陣來表示,所謂的點矩陣文字有點像將 文字的筆劃填入方格紙上的格子中,若文字的筆劃出現在小格子內,則表 示需要印出一小點,若沒在格子內,則印出空格。現在用八個二進位數來 表示八個格點,若是格子有塗滿則表示 1,若沒有塗滿則表示 0,舉例來 說,數字 用圖表示為
  • 11. 4 串列(一) 點矩陣數字 (二) 60 0 1 1 1 1 1 1 1 → 127 0 0 0 0 1 0 0 0 → 8 0 0 0 0 1 0 0 0 → 8 0 0 1 1 1 1 1 0 → 62 0 0 0 0 1 0 1 0 → 10 0 0 0 1 0 0 1 0 → 18 0 0 1 0 0 1 0 0 → 36 1 1 1 1 1 1 1 1 → 255 若每個文字使用 8× 8 的格子來表示,則下圖的國字「五」中每一排的數字分別為 以上「五」每列用一個數字,八列共八個數字。同樣的,若用 5× 4 格子點來表示 個別的阿拉伯數字,例如以下輸出的數字 9,五列分別是 15 9 15 1 15 等五 個數字,15 來自四個 1,即 ,9 為 ,其他依此類推。
  • 12. 4 串列(一) 點矩陣數字 (三) 61 > 9876543210 9999 8888 7777 6666 5555 4 4 3333 2222 1 0000 9 9 8 8 7 6 5 4 4 3 2 1 0 0 9999 8888 7 6666 5555 4444 3333 2222 1 0 0 9 8 8 7 6 6 5 4 3 2 1 0 0 9999 8888 7 6666 5555 4 3333 2222 1 0000 本程式先將 0 到 9 等十個數字的點矩資料存在二維串列 bmap,利用位 元運算可很快判斷某位元位置是否有值,隨即印出對應的格點字元。
  • 13. 4 串列(一) 點矩陣數字 (四) 62 # 0 到 9 數字點矩陣 bmap = ( (15,9,9,9,15), (2,2,2,2,2), (15,1,15,8,15), (15,1,15,1,15), (9,9,15,1,1), (15,8,15,1,15), (15,8,15,9,15), (15,1,2,2,2), (15,9,15,9,15), (15,9,15,1,15) ) # 每個矩矩陣的橫列數與直行數 R , C = len(bmap[0]) , 4 while True : num = input("> " ) # nos 為 num 的各個位數串列 nos = [ int(s) for s in list(num) ] # num 也可不用置於 list() 內 print() # 數字的每一列 for r in range(R) : # 每個數字 for n in nos : # 數字的每一行 for c in range(C-1,-1,-1) : # 判斷位元位置是否有值 if bmap[n][r] & ( 1 << c ) : print( n , end="" ) else : print( " " , end="" ) print( " " , end="" ) print() print()
  • 16. 4 串列(一) 中大雙重點矩陣 (三) 65 由以上圖示可知:s 走一步,r 需走一圈;r 走一步,k 走一圈; k 走一 步,t 逆向走一圈;t 走一步,c 逆向走一圈。這種走法如同時間的月、日、時 、分、秒運行方式一樣。此外以上 t 與 c 逆向排列的原因可參考上個範例程式 碼中的第 25 列。 由圖中可知,每當 r 走一步時,程式即需跳一列。在列印 o 字元時,需判 斷大點矩陣與小點矩陣是否同時有值,若無則印空格。程式中的「中」與「大」兩 個中文字的點矩陣直接使用 16 進位數字表示,這種數值表示方式是直接將每列 的點陣數值以每四個位元換一個 16 進位數替代,省去轉為十進位數的過程,使 得設定中文字的點陣數字變得簡單許多。 本程式雖用了五層迴圈,但只要依照字元列印順序,找出相關的變數變化方式 ,即可正確排列出各層迴圈的順序。加上運用位元運算來判斷數值的位元資料,使 得撰寫出來的程式碼相當簡潔。本題有了以上的圖示後,程式碼即能很快地完成, 這也再度說明紙筆推導的重要性。
  • 17. 4 串列(一) 中大雙重點矩陣 (四) 66 # 「中大」兩字的點矩陣 ncu = ( (0x4,0x1f,0x15,0x1f,0x4) , (0x4,0x1f,0x4,0xa,0x11) ) R , C = len(ncu[0]) , 5 # 大縱向 for s in range(R): # 小縱向 for r in range(R): print( ” ” , end=”” ) # 每個中文字 for k in range(len(ncu)): # 大橫向 for t in range(C-1,-1,-1): # 小橫向 for c in range(C-1,-1,-1): # 檢查列印條件是否滿足 if ( ncu[k][r] & ( 1 << c ) ) and ( ncu[k][s] & ( 1 << t ) ): print( ”o” , end=”” ) else: print( ” ” , end=”” ) print( ” ” , end=”” ) print( ” ” , end=”” ) print(” ”)
  • 20. 4 串列(一) 彈珠臺 (三) 69 每一次模擬,先以亂數決定彈珠是由哪個入口滾入彈珠臺,即產生 1 3 5 7 9 五數的其中一數。接下來當彈珠撞到滾輪時,以亂數決定彈珠向左或向右 彈跳。若向左,彈珠位置減 1,向右,彈珠位置加 1。若彈珠碰到兩側時, 直接將彈珠位置設定為 0 或 10 結束當次模擬。 迴圈的每一次都是利用數學模擬彈珠由上而下,一層層的撞到滾輪,向左 右彈跳,最後落在底層字母欄位而結束。模擬結束後,球落在字母欄位的機率 就是在各個欄位的彈珠數量與總模擬次數的比值,本題是一個簡單又有趣的數 學機率模擬題目。
  • 21. 4 串列(一) 彈珠臺(四) 70 from random import * n , total = 5 , 50000 counts = [ 0 for x in range(n+1) ] for k in range(total) : # 起始落下的位置 p = 2*randint(1,n) – 1 # 第一層釘子 move = 2*randint(0,1) – 1 p += move # 第二到第五層釘子 for i in range(2) : move = 2*randint(0,1) – 1 p += move # 碰到兩側,提前離開 if p < 0 or p > 2*n : break move = 2*randint(0,1) – 1 p += move # 球數統計 if p < 0 : counts[0] += 1 elif p > 2*n : counts[-1] += 1 else : counts[p//2] += 1 # 列印 for no in counts : s = int(160*no/total+0.5) print(str(s)+”/160”,end=” ”) print()