從軟體工具提升到資訊系統觀的12堂Python專題製作
以1A2B為例
泰布布
Lct4246@gmail.com
Lct4246@gmail.com
本project(專題)計以12節課帶領同學們以Software Engineering(軟體工程)的system view(系統觀)來開展一個應用軟體專題。它會統整了七年級的程式設計、八年級的進階程式設和演算法與九年級的資訊系統平台四大範籌,並學習以Pyhton程式語言新工具來implement(實現)之。
我們會以10個範例(如表1所示,本單元的設計亦適合Scratch零基礎的同學學習),運用learning by examples(從範例中學程式設計)方式一起玩從Python入門到專題製作的五大基本主題。
Structural programming(程構化程式設計)三大結構,Ex2.1~Ex2.7
Data types(資料型別),Ex2.2
進階程式設計1:array(陣列)、list(串列),Ex2.8
進階程式設計2:主副程式、modularized programming(模組化程式設計),Ex2.9
進階程式設計3:local variables( 區域變數) vs. global variables(全域變數),Ex2.10
各種programming languages(程式語言)及其applications(應用)
表1:範例程式列表
Problem definition(定義問題) 請先動手玩一局人(玩家)PK電腦(東家)電腦版的四位數字1A2B(https://reurl.cc/Lbk6NL)。回憶一下小時候和同學一起破關的美好回憶(https://reurl.cc/pgk33a),也順便建立intuition(直覺)的手感經驗。(想自選其他專題題目的組別請私下找老師討論方向。)
Problem solving(解決問題) 了解遊戲規則並實際體驗過之後,我們一起來整理剛剛玩這個1A2B的整個經過來回顧我們是怎麼解決這個問題的:
電腦先產生底牌,我們出一組四位數字猜。此時,電腦會告訴我剛剛猜的答案和它的底牌差距(?A?B)。緊接著,重複前述流程,直到猜到底牌或棄玩而提早結束。
我們將這個過程以圖1的data flow(資料流)來圖示之。其中,底牌以answer、答案以input_number分別代表之。而產生底牌、讀取答案和核對結果正是本問題的三大sub tasks(子任務),我們以genAns()、inputGuess()和checkResult()來表示。
緊接著,我們利用模組化程式設計技巧將問題以主、副程式分解之,以便進行三人一組的collaborative learning(合作學習)。其中:組長負責編寫main()和inputGuess()、組員2負責寫genAns()及組員3負責寫checkResult()。在project management(專案管理)時,請建一個1A2B資料夾,內置主程式宣告檔main.py和副程式宣告檔subs.py。
main program(主程式):main.py。如圖2所示,main.py的source code(原始程式)內含準備底牌answer和答案input_number變數以及制定副程式呼叫邏輯的主程式main(),整個副程式的控制流程如圖3所示。
subroutines(副程式):subs.py。內含下列三支副程式,詳如subs.py原始程式及圖4所示。
inputGuess():玩家輸入答案的控制邏輯。
genAns():電腦東家產生底牌的控制邏輯。詳細做法如圖5所示。此外,同學們也可以想想有沒有其他可以產生0~9的4位數亂數數字的方法呢?(註:要留意Python的randint( , )產生的值會重複。)
checkResult():電腦核對結果xAxB的控制邏輯。做法很簡單,同學們應該都可以想的出來。把底牌的每一位數和答案的每一位數一一比對後就能計算出A有幾個、B有幾個。詳如圖6所示。
圖1:資料流
圖2:主程式main(),儲存於main.py
圖3:主程式的流程圖
圖4:genAns()、inputGuess()及checkResut()三支副程式,儲存於Subs.py
圖5:genAns()解說
圖6:checkResut()解說
main.py原始程式:
from subs import *
answer=''
input_number=''
answer=genAns(answer)
input_number=inputGuess(input_number)
checkResult(answer, input_number)
subs.py原始程式:
from random import randint
#1. 產生四位數底牌answer
def genAns(answer):
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
random_answer = []
for i in range(4):
j = randint(0, 9-i)
random_answer.append(numbers[j])
numbers.remove(numbers[j])
i = i + 1
for i in range(4):
answer = answer + str(random_answer[i])
print('answer='+str(answer))
return answer
#2. 輸入答案input_number[_, _, _, _]
def inputGuess(input_number):
input_number = input('請輸入您猜測的4個數:')
return input_number
#3. 檢查xAxB
def checkResult(answer, input_number):
count_a = 0
count_b = 0
times = 1
#while times < 8 and input_number != answer:
while input_number != answer:
for i in range(4):
for j in range(4):
if i==j and input_number[i]==answer[j]:
count_a = count_a + 1
elif input_number[i]==answer[j]:
count_b = count_b + 1
print(str(count_a)+'A'+str(count_b)+'B')
count_a=0
count_b=0
times = times + 1
input_number = input('請輸入您猜測的4個數:')
#公告結果
if input_number == answer :
print('您答對了,正確答案是'+answer) # 備課用書答案有誤number要改成answer
else:
print('作答已達'+times+'次,遊戲結束,正確答案是'+answer)
想一個新的亂數0~9產生的方法來改寫genAns()。
將底牌改成5位數(或以上)。
多加一種結果xC,表示答案和底牌某位數字差1。請討論新增的規則對問題難易度造成的變化。
以recursive(遞迴)程式技巧改寫程式。
將遊戲改成視窗版,例如:https://reurl.cc/Q9MaAZ。
將玩家擴充成2家。
將只能猜8次擴充到一直猜到底牌或提早不玩為止。
利用 https://reurl.cc/kZzzYq 的技巧,讓遊戲加上sound effect(音效)。
換成人出題讓電腦猜。試著記錄電腦平均要猜幾次才會猜中,並和這篇 https://reurl.cc/0jr9YK 的解說做對照。
(AI)承9,電腦能在七次內猜中出題人的底牌(https://reurl.cc/43Xa8V)。
能否減少猜的平均次數呢?可以參考這篇的說明 https://reurl.cc/qglV0E 。
改寫成網路版,可以多人对战。