# APCS實作題2016年10月第4題:棒球遊戲 > 第1版:2023年2月14日 > 第2版:2023年6月14日,加上 C++ 程式碼 > 第3版:2023年10月19日,將 Python 程式碼改成較為精簡的版本 > 作者:王一哲 > 題目來源:[105年10月29日實作題第4題](https://apcs.csie.ntnu.edu.tw/wp-content/uploads/2020/11/1051029APCSImplementation.pdf) > [ZeroJudge 題目連結](https://zerojudge.tw/ShowProblem?problemid=c297) <br /> ## 題目 ### 問題描述 謙謙最近迷上棒球,他想自己寫一個簡化的棒球遊戲計分程式。這個程式會讀入球隊 中每位球員的打擊結果,然後計算出球隊的得分。 這是個簡化版的模擬,假設擊球員的打擊結果只有以下情況: 1. 安打:以 1B, 2B, 3B 和 HR 分別代表一壘打、二壘打、三壘打和全(四)壘打。 2. 出局:以 FO, GO, 和 SO 表示。 這個簡化版的規則如下: 1. 球場上有四個壘包,稱為本壘、一壘、二壘和三壘。 2. 站在本壘握著球棒打球的稱為「擊球員」,站在另外三個壘包的稱為「跑壘員」。 3. 當擊球員的打擊結果為「安打」時,場上球員(擊球員與跑壘員)可以移動;結果為「出局」時,跑壘員不動,擊球員離場,換下一位擊球員。 4. 球隊總共有九位球員,依序排列。比賽開始由第 1 位開始打擊,當第 $i$ 位球員打擊完畢後,由第 $(i+1)$ 位球員擔任擊球員。當第九位球員完畢後,則輪回第一位球員。 5. 當打出 K 壘打時,場上球員(擊球員和跑壘員)會前進 K 個壘包。從本壘前進一個壘包會移動到一壘,接著是二壘、三壘,最後回到本壘。 6. 每位球員回到本壘時可得 1 分。 7. 每達到三個出局數時,一、二和三壘就會清空(跑壘員都得離開),重新開始。 現在請你也寫出具備這樣功能的程式,計算球隊的總得分。 <br /> <img height="30%" width="30%" src="https://i.imgur.com/LJSgADK.png" style="display: block; margin-left: auto; margin-right: auto;"/> <br /> ### 輸入格式 1. 每組測試資料固定有十行。 2. 第一到九行,依照球員順序,每一行代表一位球員的打擊資訊。每一行開始有一個正整數 $a$ ($1 \leq a \leq 5$),代表球員總共打了 $a$ 次。接下來有 $a$ 個字串(均為兩個字元),依序代表每次打擊的結果。資料之間均以一個空白字元隔開。球員的打擊資訊不會有錯誤也不會缺漏。 3. 第十行有一個正整數 $b$ ($1 \leq b \leq 27$),表示我們想要計算當總出局數累計到 $b$ 時,該球隊的得分。輸入的打擊資訊中至少包含 $b$ 個出局。 <br /> ### 輸出格式 計算在總計第 $b$ 個出局數發生時的總得分,並將此得分輸出於一行。 <br /> ### 範例一:輸入 ``` 5 1B 1B FO GO 1B 5 1B 2B FO FO SO 4 SO HR SO 1B 4 FO FO FO HR 4 1B 1B 1B 1B 4 GO GO 3B GO 4 1B GO GO SO 4 SO GO 2B 2B 4 3B GO GO FO 3 ``` ### 範例一:正確輸出 ``` 0 ``` (說明) 1B:一壘有跑壘員。 1B:一、二壘有跑壘員。 SO:一、二壘有跑壘員,一出局。 FO:一、二壘有跑壘員,兩出局。 1B:一、二、三壘有跑壘員,兩出局。 GO:一、二、三壘有跑壘員,三出局。 達到第三個出局數時,一、二、三壘均有跑壘員,但無法得分。因為 $b = 3$,代表三個出局就結束比賽,因此得到 0 分。 <br /> ### 範例二:輸入 ``` 5 1B 1B FO GO 1B 5 1B 2B FO FO SO 4 SO HR SO 1B 4 FO FO FO HR 4 1B 1B 1B 1B 4 GO GO 3B GO 4 1B GO GO SO 4 SO GO 2B 2B 4 3B GO GO FO 6 ``` ### 範例二:正確輸出 ``` 5 ``` (說明)接續範例一,達到第三個出局數時未得分,壘上清空。 1B:一壘有跑壘員。 SO:一壘有跑壘員,一出局。 3B:三壘有跑壘員,一出局,得一分。 1B:一壘有跑壘員,一出局,得兩分。 2B:二、三壘有跑壘員,一出局,得兩分。 HR:一出局,得五分。 FO:兩出局,得五分。 1B:一壘有跑壘員,兩出局,得五分。 GO:一壘有跑壘員,三出局,得五分。 因為 $b = 6$,代表我們要計算的是累積六個出局時的得分,因此在前 3 個出局數時得 0 分,第 4~6 個出局數得到 5 分,因此總得分是 0 + 5 = 5 分。 <br /> ### 評分說明 輸入包含若干筆測試資料,每一筆測試資料的執行時間限制(time limit)均為 1 秒,依正確通過測資筆數給分。其中: - 第 1 子題組 20 分,打擊表現只有 HR 和 SO 兩種。 - 第 2 子題組 20 分,安打表現只有 1B,而且 b 固定為 3。 - 第 3 子題組 20 分, b 固定為 3。 - 第 4 子題組 40 分,無特別限制。 <br /> ## Python 程式碼 ```python= players = {} # 字典格式,儲存球員各打席的資料 for i in range(1, 10): # 棒次 i,由標準輸入讀取打擊表現 line = list(input().split()) players[i] = line[1:] b = int(input()) # 印出各打席資料及輸出分數時的出局數,提交程式碼測試時要註解或刪除 #print(players) #print(b) outs = 0 # 出局數 count = 0 # 總出局數 runs = 0 # 得分 first, second, third = False, False, False # 各壘包是否有人 idx = 1 # 目前的打者棒次 pa = 0 # 第幾打席,索引值由0開始 # 主要的程式碼,總出局數小於題目要求的b時繼續執行 while count < b: play = players[idx][pa] # 讀取打者該打席的表現 if play == "1B": # 一壘安打 if third == True: runs += 1; third = False if second == True: third = True; second = False if first == True: second = True; first = False first = True elif play == "2B": # 二壘安打 if third == True: runs += 1; third = False if second == True: runs += 1; second = False if first == True: third = True; first = False second = True elif play == "3B": # 三壘安打 if third == True: runs += 1; third = False if second == True: runs += 1; second = False if first == True: runs += 1; first = False third = True elif play == "HR": # 全壘打 if third == True: runs += 1; third = False if second == True: runs += 1; second = False if first == True: runs += 1; first = False runs += 1 elif play == "FO" or play == "GO" or play == "SO": # 出局 outs += 1; count += 1 if outs == 3: # 三出局,壘包清空,出局數 outs 歸零 first = second = third = False outs = 0 # 印出此打者打擊後壘上狀況、分數、出局數,提交程式碼測試時要註解或刪除 #print("idx: {:d}, First: {:}, Second: {:}, Third: {:}, Runs: {:d}, Outs:{:d}".format(idx, first, second, third, runs, outs)) idx += 1 # 棒次 idx 加1,若棒次大於9,輪回第1棒,打席 pa 加1 if idx > 9: idx -= 9; pa += 1 print(runs) # 印出第b個出局數時的分數,提交程式碼測試時維一印出的值 ``` <br /> 1. 程式碼中的變數名稱及用途已經寫在後方的註釋中,為了便於理解變數的用途,盡量採用棒球術語作為變數名稱,例如得分 (runs)、出局數 (outs)、打席 (plate appearance, PA),有興趣的同學可以上網搜尋一下。 2. 我選擇用字典格式儲存球員打席資料,key 值為棒次,格式為整數;元素值為各打席表現,格式為字串;不儲存打席數;資料內容為 ```python {1: ['1B', '1B', 'FO', 'GO', '1B'], 2: ['1B', '2B', 'FO', 'FO', 'SO'], 3: ['SO', 'HR', 'SO', '1B'], 4: ['FO', 'FO', 'FO', 'HR'], 5: ['1B', '1B', '1B', '1B'], 6: ['GO', 'GO', '3B', 'GO'], 7: ['1B', 'GO', 'GO', 'SO'], 8: ['SO', 'GO', '2B', '2B'], 9: ['3B', 'GO', 'GO', 'FO']} ``` 3. 依據打席表現可以分為以下5種狀況 1. 第21 ~ 25行:一壘安打 (1B),若三壘有人得1分、三壘清空;若二壘有人推進到三壘、二壘清空;若一壘有人推進到二壘、一壘清空;打者上一壘。 2. 第26 ~ 30行:二壘安打 (2B),若三壘有人得1分、三壘清空;若二壘有人得1分、二壘清空;若一壘有人推進到三壘、一壘清空;打者上二壘。 3. 第31 ~ 35行:三壘安打 (3B),若三壘有人得1分、三壘清空;若二壘有人得1分、二壘清空;若一壘有人得1分、一壘清空;打者上三壘。 4. 第36 ~ 40行:全壘打 (HR),若三壘有人得1分、三壘清空;若二壘有人得1分、二壘清空;若一壘有人得1分、一壘清空;打者回本壘得1分。 5. 第41、42行:飛球出局 (FO)、滾地球出局 (GO)、三振出局 (SO),出局數 outs 加1,總出局數 count 加1。 4. 第43 ~ 45行:三出局,壘包清空,出局數 outs 歸零。 5. 第48、49行:棒次 idx 加1,若 idx 等於 9,輪回第1棒,打席數 pa 加1。 6. 第51行:印出第b個出局數時的總得分,也是提交程式碼測試時維一印出的值。 6. 於 ZeroJudge 測試結果,每筆測資花費時間約 21 ms,使用記憶體 3.4 MB。 <br /><br /> ## C++ 程式碼 ```cpp= #include <iostream> #include <string> using namespace std; int main(int argc, char* argv[]) { // 由標準輸入讀取各棒次打席數存入陣列 PAs、打擊表現存入陣列 players int PAs[9]; string** players = new string* [9]; for(int i=0; i<9; i++) { cin >> PAs[i]; players[i] = new string[PAs[i]]; for(int j=0; j<PAs[i]; j++) { cin >> players[i][j]; } } // 由標準輸入讀取題目要求的出局數存入 b int b; cin >> b; // 除錯用,印出打擊表現 /* for(int i=0; i<9; i++) { for(int j=0; j<pa[i]; j++) { cout << players[i][j] << " "; } cout << endl; }*/ // 依序為出局數、總出局數、得分、目前打者棒次索引值由0開始、第幾打席索引值由0開始 int outs = 0, count = 0, runs = 0, idx = 0, pa = 0; // 各壘包是否有人 bool first = false, second = false, third = false; // 比賽過程 while(count < b) { string play = players[idx][pa]; // 讀取打者該打席的表現 if (play == "1B") { // 一壘安打 if (third) { runs++; third = false; } if (second) { third = true; second = false; } if (first) { second = true; first = false; } first = true; } else if (play == "2B") { // 二壘安打 if (third) { runs++; third = false; } if (second) { runs++; second = false; } if (first) { third = true; first = false; } second = true; } else if (play == "3B") { // 三壘安打 if (third) { runs++; third = false; } if (second) { runs++; second = false; } if (first) { runs++; first = false; } third = true; } else if (play == "HR") { // 全壘打 if (third) { runs++; third = false; } if (second) { runs++; second = false; } if (first) { runs++; first = false; } runs++; } else if (play == "FO" || play == "GO" || play == "SO") { // 出局 outs++; count++; } // 三出局,壘包清空,出局數 outs 歸零 if (outs == 3) { first = false; second = false; third = false; outs = 0; } // 棒次 idx 加1,若棒等於9,輪回第1棒,idx = 0,打席 pa 加1 idx++; if (idx == 9) { idx = 0; pa++; } } // 印出第b個出局數時的分數,提交程式碼測試時維一印出的值 cout << runs << endl; return 0; } ``` <br /> 1. 程式運作邏輯與 Python 程式碼相同,以下只說明不同之處。 2. 第7 ~ 15行:由標準輸入讀取各棒次打席數存入整數陣列 PAs、打擊表現存入二維字串陣列 players。 3. 第27行:棒次索引值 idx 由0開始。 4. 第62、63行:棒次 idx 加1,若棒等於9,輪回第1棒,idx = 0,打席數 pa 加1。 5. 第67行:印出第b個出局數時的總得分,也是提交程式碼測試時維一印出的值。 6. 於 ZeroJudge 測試結果,每筆測資花費時間約 2 ms,使用記憶體 332 kB。 <br /><br /> --- ###### tags:`APCS`、`C++`、`Python`