1. 程式人生 > 其它 >20211315鄒雪梅《Python程式設計》實驗四報告

20211315鄒雪梅《Python程式設計》實驗四報告

目錄

《Python程式設計》實驗四報告

課程:《Python程式設計》
班級:2113
姓名:鄒雪梅
學號:20211315
實驗教師:王志強
實驗日期:2022年5月21日
必修/選修:公選課

一、實驗要求

Python綜合應用:爬蟲、資料處理、視覺化、機器學習、神經網路、遊戲、網路安全等。
課代表和各小組負責人收集作業(原始碼、視訊、綜合實踐報告)

注:在華為ECS伺服器(OpenOuler系統)和物理機(Windows/Linux系統)上使用VIM、PDB、IDLE、Pycharm等工具程式設計實現。

批閱:注意本次實驗不算做實驗總分,前三個實驗每個實驗10分,累計30分。本次實踐算入綜合實踐,打分為25分。
評分標準:
(1)程式能執行,功能豐富。(需求提交原始碼,並建議錄製程式執行的視訊)10分
(2)綜合實踐報告,要體現實驗分析、設計、實現過程、結果等資訊,格式規範,邏輯清晰,結構合理。10分。
(3)在實踐報告中,需要對全課進行總結,並寫課程感想體會、意見和建議等。5分

二、實驗內容

之前用pygame實現過俄羅斯方塊小遊戲,所以這次沒有用pygame,但是看到pygame可以加音效和開始動畫等,之後可能還會在假期等時間充足的時候用pygame做遊戲。本次實驗通過Python實現21點小遊戲,匯出為EXE小程式,上傳華為雲執行,程式碼上傳碼雲

三、實驗分析、設計、實現過程、結果

1.遊戲規則

首先要了解21點小遊戲的遊戲規則:
點數計算:每張牌都有點數。2 到 10 的牌的點數就是其牌面的數字,J、Q、K的點數是 10.
A有兩種演算法: 1 或者 11, 如果 A 算為 11 時總和大於 21,則 A 算為 1. 例如 (A, 8)是 19 點, (A,7,J)則為 18 點
爆牌:玩家手中牌的總點數超過 21 點
停牌:玩家不再要牌, 等待其他玩家操作
要牌:玩家根據自己手上的點數決定是否要牌, 如果要牌, 則系統再發一張牌給玩家. 如果要牌後總點數超過 21, 則算爆牌,玩家輸掉本輪遊戲;若要牌後點數為 21點, 則不能再要。如果要牌後總點數不到 21 點, 則玩家可以繼續 “要牌” “停牌”
莊家持牌總點數少於 17,則必須要牌,直到超過 16,如果莊家的總點數等於或多於 17 點,則必須停牌
如果莊家手中有 A,且 A 作 11 點時大於 16點,作 1 點時小於或等於 16 點, 則由莊家自己選擇是否要牌
注意:遊戲開始後,玩家和莊家各發兩張牌,莊家的第二張牌對外不可見。

2.原始碼

基於以上的規則,使用 Python 實現一個簡單的 21 點遊戲,該遊戲只有玩家和電腦兩個玩家,玩家通過命令列的方式輸入命令,決定是否要牌或停牌,電腦玩家要牌或停牌由程式自動控制。程式碼如下:

import random  # 匯入隨機包

# 模擬要牌, 從卡牌列表中隨機選擇一張卡牌
import time

def my_random_choose():
    card = random.choice(cards)   # 從卡牌列表中隨機選取一張牌
    flag = card[0]     # flag 存放卡牌的標記
    value = card[-1]   # value 存放卡牌的字串型別的值
    if value == 'A':   # 如果卡牌為 A
        return flag, value, 1   # 暫時給它的值賦為 1
    elif value == '0':
        return flag, '10', 10     # 卡牌為 10
    elif value == 'J' or value == 'Q' or value == 'K':
        return flag, value, 10    # 卡牌為 J, Q, K 的當作 10
    else:
        return flag, value, int(value)  # 其他卡牌, 按照卡牌上的數字計算即可

# 詢問玩家是否繼續要牌, 獲取玩家選擇
def get_Input():
    Input = input('是否繼續要牌(Y|N):')
    while Input != 'Y' and Input != 'N':  # 強制要求只能輸入 Y 或者 N, 其他輸入一律重新輸入
        Input = input('是否繼續要牌(Y|N):')
    return Input
    
# 玩家要牌
def player_hit():
    # 開始遊戲,隨機發給玩家兩張卡牌
    flag1, value1, num1 = my_random_choose()
    flag2, value2, num2 = my_random_choose()
    player_cards = []                # 玩家卡牌列表,存放玩家要的所有牌, 存放的是 flag 和 value
    # 如果第一張卡牌為 A, 則賦值為 11
    if num1 == 1:
        num1 = 11  # 卡牌數值為 11
    elif num1 != 1 and num2 == 1: # 如果第一張卡牌不為 A, 但是第二張卡牌為 A
        num2 = 11  # 卡牌數值為 11

    player_total = num1 + num2  # 計算當前玩家手中卡牌總點數

    # 將初始發的兩張卡牌放到玩家卡牌列表中, 存放的是字串, 所以不參與計算, 只是用於輸出卡牌擁有情況
    player_cards.append([flag1, value1])
    player_cards.append([flag2, value2])

    print('玩家手中的牌是:', [flag1, value1], [flag2, value2])

    if player_total == 21:   # 玩家當前點數為 21 點
        # 玩家贏了
        return player_total   # 返回玩家點數
    else:  # 玩家當前點數不為 21 點
        Input = get_Input()  # 詢問玩家是否要繼續要牌
        while Input == 'Y' or Input == 'N':
            if Input == 'Y':  # 玩家繼續要牌
                flag, value, num = my_random_choose()  # 隨機抽一張卡牌給玩家
                if num == 1 and (player_total + 11 <= 21):  # 如果抽到了 A, 將 A 看成 11, 看一下此時手中卡牌總點數是否大於 21
                    num = 11     # 如果不大於 21, 可以將當前 A 賦值為 11
                player_cards.append([flag, value])   # 將抽到的卡牌放到玩家卡牌列表中
                print('玩家手中的牌是:', player_cards)    # 輸出當前擁有的卡牌
                player_total += num            # 計算玩家當前擁有的卡牌的總點數
                if player_total > 21:                  # 如果玩家當前擁有的卡牌總點數大於 21
                    return player_total                # 玩家爆牌, 返回 玩家卡牌總點數, 結束函式執行
            elif Input == 'N':     # 玩家不要牌
                return player_total  # 返回玩家當前卡牌總點數, 結束函式執行, 讓莊家要牌

            Input = get_Input()   # 玩家之前要了牌, 但是牌的總點數小於 21, 詢問玩家是否繼續要牌
            
# 莊家要牌
def dealer_hit(num1, dealer_cards):
    
    DEALER_MIN_SCORE = 17  # 莊家手中的牌的總點數的最小值為 17, 如果小於 17, 莊家必須要牌
    
    flag2, value2, num2 = my_random_choose()  # 為莊家隨機選擇一張卡牌
    if num1 != 11 and num2 == 1:  # 莊家的第一張牌不是 A, 但是第二張卡牌是 A
        num2 = 11    # 給第二張卡牌賦值為 11
    dealer_cards.append([flag2, value2])   # 將莊家的第二張卡牌放到莊家卡牌列表中, 用於之後輸出擁有卡牌情況
    dealer_total = num1 + num2

    # 當莊家手中牌的總點數小於 17, 必須要牌,
    while dealer_total < DEALER_MIN_SCORE:
        flag, value, num = my_random_choose()
        if num == 1 and (dealer_total + 11 <= 21):
            num = 11
        dealer_cards.append([flag, value])
        print('莊家得到一張牌, 莊家手中的牌是: ', dealer_cards)
        dealer_total += num
    # 莊家手中的牌的總點數大於等於17, 必須停牌, 即返回總點數
    return dealer_total

# 決定贏家
def vs(player_total, dealer_total):

    if player_total > 21:   # 如果玩家爆牌
        # 玩家輸
        print('莊家點數為 ', dealer_total, ', 玩家點數為 ', player_total, ', 莊家贏了!')
        return 1, 0  # 分別返回莊家和玩家的比分
    else:
        if dealer_total > 21:  # 莊家爆牌

            print(' 莊家點數為 ', dealer_total, ', 玩家點數為 ', player_total, ', 玩家贏了!')
            return 0, 1
        else:
            if player_total == dealer_total:  # 平局

                print(' 莊家點數為 ', dealer_total, ', 玩家點數為 ', player_total, ', 平局!')
                return 1, 1
            elif player_total > dealer_total:  # 都沒有爆牌,但是玩家的卡牌總點數大於莊家卡牌總點數
                # 玩家贏
                print(' 莊家點數為 ', dealer_total, ', 玩家點數為 ', player_total, ', 玩家贏了!')
                return 0, 1
            else:
                # 莊家贏
                print(' 莊家點數為 ', dealer_total, ', 玩家點數為 ', player_total, ', 莊家贏了!')
                return 1, 0

def start_21_game():
    player_score = 0      # 玩家得分
    dealer_score = 0      # 莊家得分
    Input = 'Y'
    round_count = 0       # 比賽的輪數
    while Input == 'Y':
        round_count += 1
        print(f'第{round_count}輪比賽開始:')
        flag1, value1, num1 = my_random_choose()   # 從卡牌列表中隨機選擇一個卡牌
        if num1 == 1:    # 卡牌為 A
            num1 = 11    # 因為只有一個卡牌,所以不會爆牌,賦值為 11
        dealer_cards = []      # 莊家擁有的卡牌列表
        dealer_cards.append([flag1, value1])    # 將抽到的卡牌放到莊家卡牌列表中
        print('莊家手中的牌是: ', [flag1, value1], '?')
        player_total = player_hit()   # 呼叫玩家要牌函式, 返回值是玩家此時的卡牌總點數
        dealer_total = dealer_hit(num1, dealer_cards)   # 呼叫莊家要牌函式, 返回值是莊家此時的卡牌總點數
        dealer_point, player_point = vs(player_total, dealer_total)   # 根據玩家和莊家的卡牌總點數判斷贏家是誰, 返回值分別是莊家和贏家當局的比分
        print('------------------------------')
        player_score += player_point  # 將玩家當局的得分加到玩家總得分上
        dealer_score += dealer_point  # 將莊家當局的得分加到莊家總得分上

        Input = input('是否進行下一局 [Y|N]:')
        while Input != 'Y' and Input != 'N':
            print('請輸入 Y or N.', end='')
            Input = input('請重新輸入 [Y|N]:')
    return player_score, dealer_score

if __name__ == '__main__':

    # 定義一個存放卡牌的列表
    cards = ['♠A', '♠2', '♠3', '♠4', '♠5', '♠6', '♠7', '♠8', '♠9', '♠10', '♠J', '♠Q', '♠K',
             '♣A', '♣2', '♣3', '♣4', '♣5', '♣6', '♣7', '♣8', '♣9', '♣10', '♣J', '♣Q', '♣K',
             '♦A', '♦2', '♦3', '♦4', '♦5', '♦6', '♦7', '♦8', '♦9', '♦10', '♦J', '♦Q', '♦K']

    # play_score 記錄玩家的得分, dealer_score 記錄莊家的得分
    player_score, dealer_score = start_21_game()

    print(f'玩家, 莊家總比分為:{player_score}:{dealer_score}')
    if player_score > dealer_score:
        print('玩家勝出')
    elif player_score < dealer_score:
        print('莊家勝出')
    else:
        print('平局')
    print('遊戲結束')
    print('10秒後自動關閉視窗')
    time.sleep(10)

其中10s自動關閉、可重複多局遊戲、記錄遊戲得分等我自認為還是不錯的小功能(嘿嘿)

3.執行結果

(參考老師發的連結打包生成了EXE小程式)
pycharm執行

小程式執行

華為雲執行

三、程式碼上傳到碼雲

四、實驗過程中遇到的問題

問題1:華為雲執行錯誤

解決方案:詢問同學,並檢測Python位置版本,以Python形式執行(之前錯用了C語言的執行方式)

問題2:在程式編寫過程中,沒加一個功能幾乎就要錯一次
解決方案:去CSDN找大佬的部落格和經驗

五、全課總結,課程感想體會、意見和建議

1.全課總結

之前通過《看漫畫學Python》自學了一下Python但是學的並不系統也沒有深入。
學期初抱著多學習學習知識的心態,報名了python選修課。一學期下來果然沒有失望,課程進度飛快,感觸頗深。

python語言特點:

簡單:Python是一種代表簡單思想的語言。
易學:Python有極其簡單的語法。
免費、開源:Python是FLOSS(自由/開放原始碼軟體)之一。
高層語言:使用Python編寫程式時無需考慮如何管理程式使用的記憶體一類的底層細節。
可移植性:Python已被移植到很多平臺
解釋性:可以直接從原始碼執行。在計算機內部,python直譯器把原始碼轉換為位元組碼的中間形式,然後再把它翻譯成計算機使用的機器語言。
面向物件:python既支援面向過程程式設計也支援面向物件程式設計。
可擴充套件性:部分程式可以使用其他語言編寫,如c/c++。
可嵌入型:可以把Python嵌入到c/c++程式中,從而提供指令碼功能。
豐富的庫:Python標準庫確實很龐大。它可以幫助你處理各種工作,包括正則表示式、文件生成、單元測試、執行緒、資料庫、網頁瀏覽器、CGI、FTP、電子郵件、XML、XML-RPC、HTML、WAV檔案、密碼系統、GUI(圖形使用者介面)、Tk和其他與系統有關的操作
本學期學習的主要知識點:

變數賦值及其命名規則
運算子及其優先順序
基本資料型別
迴圈語句
列表、元組、字典、集合及其常用功能
字串與正則表示式
函式
面向物件程式設計
檔案操作及異常處理
Python操作資料庫
Python網路程式設計及爬蟲開發(Socket)

2.課程感想體會

(1)光聽不練假把式,多多實踐比只是聽課有用的多
(2)學會查詢相關資料,學會把運用別解決類似問題的方法解決自己的問題
(3)學習不能有怠惰心理,要持之以恆的努力
一個學期的學習感覺自己在Python或者說整個程式語言、計算機知識都收穫很多,之前通過自學不完整不繫統的知識都串聯起來了,而且通過老師幾次作業也真正會運用Python了,在一次次嘗試中也提高了自己解決問題的能力......總之感覺這門課“太值了”以後有學弟學妹問一定傾力推薦(手動狗頭)

3.意見和建議

上課同時看投影和跟著打程式碼會跟不上,投影的顯示還是不太清晰的(有時候會跟同學一起,她手機進入騰訊會議然後我們跟著騰訊會議的程式碼打,哈哈)
老師上課時候對於雲班課上Word課件的改動和一起編寫的小程式也建議分享一下,讓我們不至於因為沒跟上二“錯過就遺憾終身”

六參考資料

基本都是CSDN上大佬的部落格,因為太多和時間跨度大約有一個周,就不一一列舉了