iT邦幫忙

9

【Python 超入門】(11) (完結篇) 實作你的第一個遊戲-金頭腦益智問答

大家好,我是「心原一馬」,內心原來一心喜歡打程式碼。
相信很多人可能看過一些益智問答的電視節目,
幾個參賽者競爭高額獎金,回答節目裡的問題。

雖然小馬沒有提供高額獎金,
不過利用到目前為止所學的程式知識,
我們也可以做一個益智問答遊戲出來。

設計問題與答案

其實關於題目的類型你都可以隨自己的喜好來替換,
這邊小馬以數理邏輯類的問題為例,
給出三個問題:
Q1: 姜太公釣魚,猜一個數學名詞
A1: 等於 (等魚)

Q2: 小馬老師想把一打鉛筆分給一群小朋友,每個人都要拿到鉛筆而且每個人拿到的鉛筆數量不一樣多,試問: 最多可以分給幾個人? (輸入一個數字)
A2: 4
(解析: 如果分給5個人,至少要1+2+3+4+5=15隻筆; 分給4個人則每人可以分別拿1,2,3,6支筆,OK)

Q3: 計算下列算式之值: 2019*20202020-2020*20192019
A3: 0
(解析: 兩個數字都是 2019*2020*10001)

【Python 超入門】(9) input()函數- 使用者跟電腦對話的方法這篇文章中,
小馬教過各位用input()函數可以讓電腦取得使用者輸入的訊息。

輸入第一個問題

設計好自己的問題後,
我們用input()讀入使用者的答案,
再檢查答案是否正確。

#主程式
ans1 = input("姜太公釣魚,猜一個數學名詞: ")
if ans1=="等於":
    print("恭喜你答對了")

執行結果:
https://ithelp.ithome.com.tw/upload/images/20190716/20117114YbqwK2oygs.png

添加更多問題

同樣的方法,我們可以再把另外兩道問題加進去:

#主程式
ans1 = input("姜太公釣魚,猜一個數學名詞: ")
if ans1=="等於":
    print("恭喜你答對了")
ans2 = input("小馬老師想把一打鉛筆分給一群小朋友,每個人都要拿到鉛筆而且每個人拿到的鉛筆數量不一樣多,試問: 最多可以分給幾個人? (輸入一個數字) ")
if ans2=="4":
    print("恭喜你答對了")
ans3 = input("計算下列算式之值: 2019*20202020-2020*20192019= ")
if ans3=="0":
    print("恭喜你答對了")

這樣程式可以運行,
但是判斷答案是否正確的程式碼其實很類似,
我們可以獨立定義一個「檢查函式」,
讓主程式更簡潔。
(自定函數觀念可參考「【Python 超入門】(10) 自定義函數介紹- 主人向他的機器人管家抱怨:「你跟我這麼多年了,也該了解我們家的習慣了吧?」 」)

"""
自訂函式: check_answer
<參數> guess :使用者猜的答案,
       answer : 我們的標準答案
函數功能: 檢查使用者的答案跟標準答案是否一致。
"""
def check_ans(guess, answer):
    if guess==answer:
        print("恭喜你答對了")

修改主程式

有了自定義函數,我們可以簡單把主程式修改如下:

#主程式
ans1 = input("姜太公釣魚,猜一個數學名詞: ")
check_ans(ans1,"等於")
ans2 = input("小馬老師想把一打鉛筆分給一群小朋友,每個人都要拿到鉛筆而且每個人拿到的鉛筆數量不一樣多,試問: 最多可以分給幾個人? (輸入一個數字) ")
check_ans(ans2,"4")
ans3 = input("計算下列算式之值: 2019*20202020-2020*20192019= ")
check_ans(ans3,"0")

添加遊戲性- 計分

目前程式寫到這邊,
我們發現程式只是問問題,
然後告訴你答案對不對,略顯單調。
我們可以添加一個變數score,
記錄玩家所獲得的分數。

score = 0

我們修改自定函數 check_ans,讓使用者答對時加一分,
並且在使用者答錯時,也印出提示字串:

score = 0
def check_ans(guess, answer):
    global score 
    if guess==answer:
        print("恭喜你答對了")
        score += 1
    else:
        print("答錯了,再接再勵")

函數內使用了一個關鍵字global
這個字在之前的課程沒有講解到,這邊說明一下。
global score的意思是將 score 這個變數設為全域變數,
當在函數內修改這個變數時,
對整個程式都有影響。

結合所有程式碼

我們即將大功告成了,
我們把這些程式碼都寫在同一個檔案裡:

score = 0 #記錄玩家的分數

"""
自訂函式: check_answer
<參數> guess :使用者猜的答案,
       answer : 我們的標準答案
函數功能: 檢查使用者的答案跟標準答案是否一致。
"""
def check_ans(guess, answer):
    global score 
    if guess==answer:
        print("恭喜你答對了")
        score += 1  #每答對一題加1分
    else:
        print("答錯了,再接再勵")
        
#主程式
print("歡迎來到金頭腦益智問答遊戲~")
ans1 = input("姜太公釣魚,猜一個數學名詞: ")
check_ans(ans1,"等於")
ans2 = input("小馬老師想把一打鉛筆分給一群小朋友,每個人都要拿到鉛筆而且每個人拿到的鉛筆數量不一樣多,試問: 最多可以分給幾個人? (輸入一個數字) ")
check_ans(ans2,"4")
ans3 = input("計算下列算式之值: 2019*20202020-2020*20192019= ")
check_ans(ans3,"0")
print("您總共得到 "+str(score)+" 分") #印出最後的結果

這邊再嘗試執行一下,
小馬故意前兩題答錯,
最後一題答對,
順利顯示出 您總共得到 1 分:

https://ithelp.ithome.com.tw/upload/images/20190716/20117114abj5mzgiZk.png

至此已經製作出一個簡單的小遊戲了,
本篇內容活用了【Python 超入門】系列(1)~(10)的內容,
如有不理解之處,也歡迎在留言區發問。
再次感謝所有欣賞小馬文章及追蹤我的邦友,
也蠻開心過程中,看到許多邦友在留言區留言感謝小馬老師教學淺顯易懂,很有收穫

(2020/3/31補充)延伸學習


2 則留言

1
naorosie
iT邦新手 5 級 ‧ 2019-07-23 11:57:22

不好意思 還是有點不懂為何score要先指定為0?以及score為何要設為全域變數呢?那數字加總還有其他寫法嗎?謝謝~

看更多先前的回應...收起先前的回應...
心原一馬 iT邦研究生 5 級 ‧ 2019-07-23 12:54:14 檢舉

好的,謝謝你的發問哦~
這支程式確實融入了很多觀念在裡面呢~
小馬盡可能一一說清楚講明白~
(講解篇幅較長,我分兩個回應解答)

  1. 為何score要先指定為0?
    這邊隱含了兩個問題:
    (1)為何score要先設定初始值?
    (2)為何score的初始值設為0?
    小馬猜你的意思應該比較像是問(1),
    小馬著重在這部分回答:
    這個概念其實是說變數要使用之前必須要先「宣告」,
    什麼是「宣告」呢?
    就是一開始用「=」給這個變數設個初始值。
    例如下面簡單的程式,只有兩行:
score += 1
print(score)

實際執行之後會出現NameError: name 'score' is not defined
若沒有設定初始值,
程式並不知道score是什麼。

你可以想一個生活化的例子:
你今天到一間商店買東西,
老闆告訴你「這個商品降價100元」,
可是商品上並沒有標原價(也就是初始值),
那麼你還是不知道這個商品的價錢。
這也就是為什麼變數都需要一個初始值才能用。

上述程式可改為:

score = 0
score += 1
print(score)

即可印出結果1

心原一馬 iT邦研究生 5 級 ‧ 2019-07-23 13:24:03 檢舉
  1. score為何要設為全域變數?
    簡言之,因為我們希望在函數裡面,
    去修改函數外面設定的變數值(玩家的分數)。
    變數有分兩種:區域變數全域變數
    區域變數是在函數內部的變數,
    使用它不會對整支程式造成影響。
    全域變數則是寫在函數外,在整支程式裡都可以用。
    例如以下程式碼:
x = 10
def myFunction():
    x = 5
    print("在函數裡面x的值為", x)
myFunction()
print("在函數外面x的值為", x)

這支程式做了幾件事情:

  1. 一開始設定x的值為10
  2. 我們定義一個函數,叫作myFunction(),
    希望去修改x的值。我們在第五行呼叫它。
  3. 我們分別在函數內、外使用print(),試著印出x的值

結果為:
在函數裡面x的值為 5
在函數外面x的值為 10
在函數裡面更改x的值是不影響全域變數 x的。
那麼怎麼樣可以用函數真的改到x的值呢?
所以要加上global x這句話,
告訴程式現在x要當做全域變數來操作,
而不是當成區域變數

更改後程式如下:

x = 10
def myFunction():
    global x
    x = 5
    print("在函數裡面x的值為", x)
myFunction()
print("在函數外面x的值為", x)

結果為
在函數裡面x的值為 5
在函數外面x的值為 5

心原一馬 iT邦研究生 5 級 ‧ 2019-07-23 13:33:29 檢舉
  1. 數字加總還有其他寫法嗎?
    有點不確定您想問的意思,
    你是想問有沒有方法寫的更簡單嗎?
    由於我們希望每次玩家答對時,
    才去修改分數(即把分數加1),
    小馬尚未想到其它好的寫法。
    抱歉這次篇幅有點長~
    感謝您的耐心閱讀。
naorosie iT邦新手 5 級 ‧ 2019-07-23 15:30:09 檢舉

哇!了解~~感謝你的耐心解說 第三個問題其實是在問上一篇(10)的

scores = [50,60,35,20,40,0]
totolScore = 0 #用totolScore變數儲存全班的分數總和
for s in scores: #在迴圈中把每個人的分數加總
totolScore +=s

有點好奇是否有不用先將變數指定為0的寫法?
抱歉~不小心在這篇問了哈哈

心原一馬 iT邦研究生 5 級 ‧ 2019-07-23 18:29:11 檢舉

哈哈~ 我了解你的問題了,
由於本系列文是新手教學,
所以我選擇用基礎的程式邏輯來寫數字加總。
但其實python語言的特性是簡潔
它有許多好用內建函數可以讓程式更簡短好懂,
譬如說把列表中的數字加總只需用內建sum()函數即可:

scores = [50,60,35,20,40,0]
totolScore = sum(scores)
naorosie iT邦新手 5 級 ‧ 2019-07-24 11:51:21 檢舉

哦哦原來 感謝你回答我這麼多新手問題哈哈~~

1
medivh0102
iT邦新手 5 級 ‧ 2020-03-10 21:07:00

謝謝一馬哥一路以來的指導
請教一下一馬哥一個邏輯上的問題,滿好奇電腦是怎麼辨別這個先後邏輯的:
如果將

score=0
def lol_check (guest, ans):
    global score

寫成


def lol_check (guest, ans):
    score= 0
    global score

的話,那麼成績結算只會算到一題的分數,後續不管答對答錯都不影響計分,
可是如果是用第一種寫法的話就可以正常計分,請問寫在def之上或之下,對電腦來說是怎麼判斷的呢?往後練習寫程式的時候,又該怎麼去判斷哪一行要後寫哪一行要先寫呢?

看更多先前的回應...收起先前的回應...
心原一馬 iT邦研究生 5 級 ‧ 2020-03-10 21:32:21 檢舉

小馬覺得不太對哦~
如果函數寫成這樣的話:

def check_ans(guess, answer):
    score = 0
    global score 

那麼程式應該無法執行,
會出現SyntaxError: name 'score' is assigned to before global declaration
您再試試看~

global這個字比較特別,
請看這個例子(沒有使用global的狀況下):

x = 0
def function():
    x = 1
    print(x)
function()
print(x)

我們定義function()這個函數想把x的值設成1
並可以把x的值印出來,
那麼執行這支程式你猜會看到什麼結果呢?

告訴小馬你的猜測及你為什麼這樣猜,
小馬再繼續為你解答,
我想對你會更有幫助 ^^

心原一馬 iT邦研究生 5 級 ‧ 2020-03-10 21:37:45 檢舉

另外,你提到「往後練習寫程式的時候,又該怎麼去判斷哪一行要後寫哪一行要先寫呢?」其實程式執行的邏輯很簡單,就是從上往下執行,一般來說就是想要先執行的程式放在上面(如果你有看到什麼特例覺得程式不是由上而下執行也歡迎提出討論哦~)

心原一馬 iT邦研究生 5 級 ‧ 2020-03-10 21:44:51 檢舉

對了,恭喜你看完python超入門自學課程了~
/images/emoticon/emoticon42.gif/images/emoticon/emoticon42.gif/images/emoticon/emoticon42.gif
感覺你也成長了許多呢~
今後也歡迎繼續交流哦~

回答一馬哥:
答案令我出乎意料
我一開始以為是1
結果如下:

1
0

共兩行
我以為x在經過函數的x=1之後
0會變成1
所以我猜測應該是這樣:

x = 0
def function(): #這個函數邏輯會再x經過時將x變成1
    x = 1
    print(x)
function() #這一行的輸出是有經過函數的x,所以答案是1
print(x)  #這一行的print沒有經過函數(funtion),所以是0

附註:請問一馬哥為什麼我換成下面這樣就失敗了呢?

X = 123
def ans_check()
    if X >= 1:
    print("BIGGER")

失敗指令碼:SyntaxError: invalid syntax

心原一馬 iT邦研究生 5 級 ‧ 2020-03-10 23:33:19 檢舉

if X>=1:的次一行要「縮排」哦~
另外現在時間晚了,小馬先睡覺,
也許明天再回答你為什麼x沒有從0變成1~

心原一馬 iT邦研究生 5 級 ‧ 2020-03-11 21:56:50 檢舉

您好,小馬想了想,
感覺你問的問題蠻好的,
好像蠻多人會對於為什麼函數內要用global
近期小馬會試著再找時間發文教global的用法,
(也許新增補充於【Python 超入門】(12))
敬請期待~

心原一馬 iT邦研究生 5 級 ‧ 2020-03-31 11:09:08 檢舉

哈囉,邦友您好,小馬已經完成【Python 超入門】(12) (補充篇)當你的同學與全國明星同名同姓?談python的區域變數與全域變數細講global的概念了,歡迎閱讀~

我要留言

立即登入留言