2019年11月3日 星期日

夠Python,利用集合持性來開發新版的XAXB小遊戲

去年敏哥剛學Python時,寫了一篇用Python開發XAXB小遊戲,今天突然想起,有人說您是用C或Java觀念來寫Python程式,還是能寫出夠Python或很Python,也就是程式很有"Pythonic"。

XAXB又稱幾A幾B遊戲,兩人對玩,先個自寫下四個不同數字,不可讓對方知道,再請對方說出不同的四個數字,您再告訴他獲得幾A幾B,若數字位置對就可獲得1A,若數字有但位置不對就獲得1B,2A1B代表有2個數字位置相同,1個數字位置不同,有3個數字猜對,相互猜數字,直到有人全對,即4A0B,即可獲勝。

以下是2018年12月23日所寫的Python程式,很像C的寫法。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import random
x=random.sample('1234567890',4)
print (x)
play=True
while play:
    y=input("輸入4個不同數字:")
    print (y)
    z = list(y)
    print (z)
    a=0
    for i in range(4):
        if(x[i]==z[i]):
            a=a+1
    b=0
    j=0
    while j < 4:
        k=0
        while k < 4:
            if j==k :
                k=k+1
                continue
            if(x[j]==z[k]):
                b=b+1
            k=k+1
        j=j+1
    print(a,"A", b, "B")
    if a == 4:
        play = False
程式解析:
第1行 引入亂數套件。
第2行 取得四個不同的數字,當成答案。
第3行 將答案的數字顯示出來,是為了便於測試程式的正確性。
第4行 使用play變數預設值是True。
第5行 while迴圈直到play變數變成False。
第6-9行 從鍵盤中讀取4個不同數字,4個不同數字的組成是字串,再經由list轉換成串列。
第10-13行 判斷可以獲得幾A。
第14-25行 判斷可以獲得幾B。
第26行 印出幾A幾B。
第27-28行判斷是否結束遊戲。

2019年11月3日較具Pythonic的寫法。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import random
x=random.sample('1234567890',4)
print (x)
while True:
    y=input("輸入4個不同數字:")
    print (y)
    z = list(y)
    print (z)
    a=0
    for i in range(4):
        if x[i] is z[i]:
            a=a+1
    b=4-len(set(x)-set(z))-a
    print(a,"A", b, "B")
    if a == 4:
        break

程式大致上和上面程式一樣,僅說明不同的地方,
1.第4行和第16行是採用break來跳出迴圈。
2.第11行去掉括號把==改用is,is和==的用法可以參考,Python中is與==判斷的區別文章
3.第13是判斷幾B的程式,神奇的Python把原本需要12行指令,採用集合(Set)特性僅用1行就完成。我們採用集合概念,把兩個集合相減,就能去掉相同的部份,再取出其長度,就會知道有幾個數字是另一個集合沒有,再用4去減,就能還原有多少個相同,再減去幾A,就變成幾B的答案。

感謝Python Taiwan高手指點,程式變得很Python。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import random
x=random.sample('1234567890',4)
print (x)
while True:
    y = input("輸入4個不同數字:")
    print (y)
    z = list(y)
    print (z)
    a = len([1 for i in range(4) if x[i] is z[i]])
    b = 4-len(set(x)-set(z))-a
    print(a,"A", b, "B")
    if a == 4:
        break
第9行程式亦可以替換成a = sum((x[i] == z[i]) for i in range(4))或a = sum((x[i] == z[i]) for i in range(4)),可以使用sum函式來取代len函式,也可以使用下列兩行來取代第9行程式。
from operator import eq

a = sum(map(eq, x[:4], z[:4]))
以上程式都是經由Python Taiwan社群高手指點,Python超好玩。
map函式會根據函数對指定序列做映射,其用法可以參考Python 基礎系列 map() 用法解說

測試結果:

Python Taiwan社群高手如雲,剛剛又看到超級完美的程式碼,1A2B猜數字一行解

本篇文章引起Python Taiwan社群的熱情討論,大家討論情形,如下:
https://www.facebook.com/groups/pythontw/permalink/10159317947538438/

沒有留言:

張貼留言