久久国产乱子伦精品免费M,亚洲一区二区三区91,欧美国产在线视频,国产精品视频久久

小白用Python | 用Python破解斗地主殘局

相信大家都玩過斗地主,規(guī)則就不再引見了。

直接上一張朋友圈看到的殘局圖:

小白用Python | 用Python破解斗地主殘局

這道題我剛看到時,曾嘗試用手工來破解,每次都以為找到了農(nóng)民的必勝戰(zhàn)略時,最后都發(fā)現(xiàn)其實(shí)農(nóng)民跑不掉。由于手工破解無法窮盡一切可能性,所以這道題終究農(nóng)民有沒有妙手跑掉呢,只能經(jīng)過代碼來協(xié)助我們運(yùn)算了。

本文將簡要講述怎么通過代碼來求解此類問題,在最后會公布?xì)埦值淖詈蠼Y(jié)果,并開源代碼以供大家吐槽。

minimax

小白用Python | 用Python破解斗地主殘局

代碼的核心思想是minimax。minimax可以拆解為兩部分,mini和max,分別是最小和最大的意思。

直觀的理解是什么呢?就有點(diǎn)像A、B兩個人下棋。A現(xiàn)在可以在N個點(diǎn)走棋,假設(shè)A在某個點(diǎn)走棋了,使得A的這一步的盤面評估分?jǐn)?shù)最高;但是輪到B下的時候,就一定會朝著讓A最不利的方向走,使得A的下一步必然按照B設(shè)定的軌跡來,而沒法達(dá)到A在第一步時估算到這一步的最高盤面評分。

在牌局中是一樣的,如果農(nóng)民的一手牌,讓地主無論如何應(yīng)對都不能贏的話,那么可以說農(nóng)民有必勝策略;否則,農(nóng)民必輸。

核心邏輯

小白用Python | 用Python破解斗地主殘局

我們可以用一個函數(shù)hand_out來模擬一個人的出牌過程。在現(xiàn)實(shí)生活中,一個人想要出牌的話,必然需要知道自己手上的所有牌:me_pokers,也需要知道上一手的出的牌:last_hand。如果我們要用這個函數(shù)來模擬兩個人的出牌,則還需要知道對手當(dāng)前的所有牌:enemy_pokers。

這個函數(shù)的返回值,是輪到我me_pokers出牌時,是否能夠必贏牌。如果能贏則返回真,否則返回假。

小白用Python | 用Python破解斗地主殘局

假設(shè)輪到我出牌時,如果我手上的牌都出完了,那么我將立刻知道我贏了;反之如果對手的牌都出完了,而我沒有,則我失敗了。

小白用Python | 用Python破解斗地主殘局

因?yàn)楝F(xiàn)在輪到我出牌,所以我首先需要知道我現(xiàn)在能出的所有手牌組合。注意:這個組合中,包括過牌(即不出牌)的策略。

小白用Python | 用Python破解斗地主殘局

現(xiàn)在我們要對所有可能的手牌組合進(jìn)行遍歷。

首先我需要知道,上一手對方出的牌是什么。

  • 如果對方上一手選擇過牌,或者沒有上一手牌,那么我這一輪必須不能過牌,但是我可以出任意的牌
  • 如果對手上一手出了牌,則我必須要出一個比它更大的牌或者選擇這一輪直接過牌(不出牌)

關(guān)鍵點(diǎn)來了,在出完我的牌或選擇過牌后,我們需要用一個遞歸調(diào)用來模擬對手下一步的行為。如果對手的下一次出牌不能獲勝的話,則我這一次的出牌必勝;否則,對于我的每一個出牌選擇,對手都能獲勝的話,則我必敗。

全部代碼如下:

小白用Python | 用Python破解斗地主殘局

構(gòu)建

小白用Python | 用Python破解斗地主殘局

以上核心邏輯理清楚后,構(gòu)建破解器將變得十分簡單。

首先,我們要用數(shù)字來表示牌的大小,這里我們用3表示3,11來表示J,12表示Q,依次類推……

其次,我們需要求出一個手牌的所有出牌組合,這里需要get_all_hands函數(shù),具體實(shí)現(xiàn)比較繁瑣但是很簡單,就不在此贅述。

然后,我們還需要一個牌力判斷函數(shù)can_comb2_beat_comb1(comb1, comb2),這個函數(shù)用于比較兩組手牌的牌力,看是否comb2可以擊敗comb1。唯一需要注意的一點(diǎn),在斗地主的規(guī)則中,除了炸彈外,其他所有牌力均等,只有牌型一樣時才能去比較。

最后,我們需要一個模擬出牌函數(shù)make_hand(pokers, hand),用于求出在手牌為pokers的情況下打出一手牌hand后,剩下的手牌,實(shí)現(xiàn)也非常簡單,只需簡單的移除掉那些打出的牌即可。

效率

小白用Python | 用Python破解斗地主殘局

由于一副牌的可能手牌巨大,導(dǎo)致遞歸的分支數(shù)巨大。所以時間開銷非常大,為階乘級O(N!),根據(jù)斯特林公式,大約為O(N^N)。

由于可能會有很多重復(fù)的牌面出現(xiàn),導(dǎo)致了很多重復(fù)的遞歸調(diào)用。所以加一個緩存能極大提升效率。

即對我方手牌和敵方手牌和上一輪手牌的描述(str(me_pokers)+str(enemy_pokers)+str(last_hand))為鍵,將求出的結(jié)果存進(jìn)緩存字典中。下一次遇到相同的局面時,即可直接從緩存字典中取出,而無需再次重復(fù)計算。時間復(fù)雜度優(yōu)化為指數(shù)級O(C^N)。

結(jié)果

小白用Python | 用Python破解斗地主殘局

代碼運(yùn)算出來的結(jié)果是,農(nóng)民沒有必勝戰(zhàn)略。換言之,只需地主會玩,農(nóng)民不可能贏。階級固化曾經(jīng)如斯了么……

開源

代碼放于Github: doudizhu_solver,MIT協(xié)議,隨意玩。我曉得寫的很爛,歡送吐槽~

 

馬哥學(xué)習(xí)交流群

馬哥教育-Python開發(fā)-1群 335068227

馬哥教育-Python開發(fā)-2群 608459685

 

相關(guān)新聞

歷經(jīng)多年發(fā)展,已成為國內(nèi)好評如潮的Linux云計算運(yùn)維、SRE、Devops、網(wǎng)絡(luò)安全、云原生、Go、Python開發(fā)專業(yè)人才培訓(xùn)機(jī)構(gòu)!

    1. 主站蜘蛛池模板: 松潘县| 都江堰市| 曲松县| 都匀市| 朝阳县| 平江县| 乌什县| 武强县| 南陵县| 麻阳| 乐至县| 新乡县| 闽清县| 绥江县| 新密市| 临西县| 安陆市| 基隆市| 青浦区| 雅安市| 白沙| 法库县| 白城市| 古田县| 辉南县| 富阳市| 抚州市| 宁波市| 普陀区| 凌海市| 博客| 竹溪县| 榆社县| 富民县| 抚州市| 普兰县| 台南县| 广西| 定结县| 石林| 乌兰县|