pygame 歡樂五子棋(二)

上期褒链,我們做好了游戲的棋盤,本期我們處理如何落子窘俺,及設(shè)計我們的AI
廢話少說是掰,先看看如何落子

落子

落子的過程大概為

  1. 獲取鼠標(biāo)的位置
  2. 計算位置所對應(yīng)的落子點
  3. 畫出棋子

看一下主函數(shù)中的流程

if event.type == pygame.QUIT:
    running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
    # 1.有鼠標(biāo)點擊事件發(fā)生了,我們獲取鼠標(biāo)的位置

    # 2.計算鼠標(biāo)點擊所在網(wǎng)格點的位置

    # 3.添加棋子
  1. 獲取鼠標(biāo)位置
    獲取鼠標(biāo)的位置很簡單耍休,pygame為我們做好了各種事件的檢測及記錄押蚤,我們只需要看有沒有鼠標(biāo)落下事件的發(fā)生,然后獲取位置就好了
    好了羹应,我們看如何獲取鼠標(biāo)的位置揽碘,只有一個語句就好了
pos = event.pos
  1. 計算網(wǎng)格點的位置
    計算網(wǎng)格點的位置也很簡單,只要用坐標(biāo)值除以網(wǎng)格的寬度就好了园匹,這里有一點需要注意雳刺,就是我們不可能每次都點擊到網(wǎng)格點上,因此需要有一個四舍五入的過程裸违,就是我們點擊的位置距離哪個點近掖桦,我們就默認(rèn)用戶點擊了哪一個點。
grid = (int(round(event.pos[0] / (GRID_WIDTH + .0))),
        int(round(event.pos[1] / (GRID_WIDTH + .0))))
  1. 添加棋子
    要畫出棋子供汛,我們必須記錄下我們走的每一步棋枪汪,并且在刷新屏幕的時候?qū)⑦@些棋子全部畫出來涌穆。我們定義一個全局變量movements用于我們的每一步棋。然后雀久,每次落子之后宿稀,我們就將落子信息存儲在里面。
movements = []
def add_coin(screen, pos, color):
    movements.append(((pos[0] * GRID_WIDTH, pos[1] * GRID_WIDTH), color))
    pygame.draw.circle(screen, color,
        (pos[0] * GRID_WIDTH, pos[1] * GRID_WIDTH), 16)

再定義一個畫出每一步棋的函數(shù)

def draw_movements(screen):
    for m ini movements:
        # m[0] 存的是位置赖捌,m[1]存的是顏色
        pygame.draw.circle(screen, m[1], m[0], 16)

好了祝沸,我們在添加棋子的注釋下面添加一句

add_coin(screen, pos, BLACK)

在刷新屏幕之前調(diào)用畫出棋子的函數(shù)

draw_movements(screen)

好了,我們運行一下越庇,在屏幕中畫一個五字~~

wu.png

OK罩锐,落子順利完成,
下一步就是我們游戲的核心了卤唉,我們要寫我們自己的AI~~

五子棋 AI

在我們開發(fā)我們的AI之前我們還有一個事情要做

判斷游戲結(jié)束

如何判斷游戲結(jié)束涩惑?只要有五個子連成線就好了!對的桑驱,每次落子的時候我們只要判斷所落的子周圍有沒有統(tǒng)一顏色的棋子可以連成五子的境氢,因此我們需要一個矩陣記錄每個位置子的顏色~

color_metrix = [[None] * 20 for i in range(20)]

此時,我們就可以定義我們的判斷游戲結(jié)束的函數(shù)了碰纬,函數(shù)的邏輯很簡單,只要判斷所落子的周圍是否有五子連成線一共有四個方向

def game_is_over(pos, color):
    hori = 1
    verti = 1
    slash = 1
    backslash = 1
    left = pos[0] - 1
    while left > 0 and color_metrix[left][pos[1]] == color:
        left -= 1
        hori += 1

    right = pos[0] + 1
    while right < 20 and color_metrix[right][pos[1]] == color:
        right += 1
        hori += 1

    up = pos[1] - 1
    while up > 0 and color_metrix[pos[0]][up] == color:
        up -= 1
        verti += 1

    down = pos[1] + 1
    while down < 20 and color_metrix[pos[0]][down] == color:
        down += 1
        verti += 1

    left = pos[0] - 1
    up = pos[1] - 1
    while left > 0 and up > 0 and color_metrix[left][up] == color:
        left -= 1
        up -= 1
        backslash += 1

    right = pos[0] + 1
    down = pos[1] + 1
    while right < 20 and down < 20 and color_metrix[right][down] == color:
        right += 1
        down += 1
        backslash += 1

    right = pos[0] + 1
    up = pos[1] - 1
    while right < 20 and up > 0 and color_metrix[right][up] == color:
        right += 1
        up -= 1
        slash += 1

    left = pos[0] - 1
    down = pos[1] + 1
    while left > 0 and down < 20 and color_metrix[left][down] == color:
        left -= 1
        down += 1
        slash += 1

    if max([hori, verti, backslash, slash]) == 5:
        return True

好的在我們畫出棋子之后加入游戲結(jié)束的判斷

if game_is_over(grid, BLACK):
    running = False

對了記得在添加棋子的函數(shù)里將改變我們color_metrix的語句加進去问芬。這樣只要我們有五個同色子連成線游戲就結(jié)束了悦析!
先前我們是直接在主循環(huán)中處理事件的這樣不好,我們提取出一個函數(shù)來用于處理用戶走子此衅,及AI的響應(yīng)函數(shù)接口像這樣:

def move(surf, pos):
    '''
    Args:
        surf: 我們的屏幕
        pos: 用戶落子的位置
    Returns a tuple or None:
        None: if move is invalid else return a
        tuple (bool, player):
            bool: True is game is not over else False
            player: winner (USER or AI)
    '''

這個函數(shù)首先判斷落子的位置是否已近有子强戴,有的話返回None, 否則落子為合法的挡鞍,我們調(diào)用add_coin骑歹, 最后我們調(diào)用respond函數(shù)
這個函數(shù)是我們用來運行我們的AI,并決定下一步動作的墨微,返回值和我們的move一樣道媚,這樣,我們的move就變成了下面這樣

def move(surf, pos):
    '''
    Args:
        surf: 我們的屏幕
        pos: 用戶落子的位置
    Returns a tuple or None:
        None: if move is invalid else return a
        tuple (bool, player):
            bool: True is game is not over else False
            player: winner (USER or AI)
    '''
    grid = (int(round(pos[0] / (GRID_WIDTH + .0))),
            int(round(pos[1] / (GRID_WIDTH + .0))))

    if grid[0] <= 0 or grid[0] > 19:
        return
    if grid[1] <= 0 or grid[1] > 19:
        return

    pos = (grid[0] * GRID_WIDTH, grid[1] * GRID_WIDTH)

    # num_pos = gridpos_2_num(grid)
    # if num_pos not in remain:
    #     return None
    if color_metrix[grid[0]][grid[1]] is not None:
        return None

    curr_move = (pos, BLACK)
    add_coin(surf, BLACK, grid, USER)

    if game_is_over(grid, BLACK):
        return (False, USER)

    return respond(surf, movements, curr_move)

這里我們給add_coin 添加了一個參數(shù)翘县,就是當(dāng)前落子的角色最域,其中

USER, AI = 1, 0

我們用隨機落子代替我們的AI

def respond(surf, movements, curr_move):
    # 測試用,隨機落子

    grid_pos = (random.randint(1, 19), random.randint(1, 19))
    # print(grid_pos)
    add_coin(surf, WHITE, grid_pos, 16)
    if game_is_over(grid_pos, WHITE):
        return (False, AI)

    return None

看一下效果~

屏幕快照_2017-08-16_下午8.50.16.png

好了~ 我們的五子棋完成了锈麸!

什么镀脂?? 不滿意忘伞?

好吧薄翅,AI確實比較麻煩沙兰,這里我給大家介紹一下思路,完整的代碼大家可以到我的github上去下載翘魄,下載鏈接在文章的最后~

AI思路

五子棋的規(guī)則大家都懂鼎天,沒下一個棋子都對周圍的區(qū)域會產(chǎn)生影響,我們的AI可以記錄每個位置的價值熟丸,每次下棋的時候可以選擇得分最高的那個位置训措,具體操作我們可以這樣,連成子的數(shù)目越多光羞,價值越高绩鸣,如果可以在多個方向上連成子,我們可以將價值相應(yīng)的增加倍數(shù)纱兑,同時在對方有三個子連成線(獨立的呀闻,即兩邊沒有其他子)的時候必須堵住對方。大概就是這樣的潜慎。
具體實現(xiàn)我們就不講解了捡多,看一下最終效果


final.png

我試了一下,和AI下我基本上有輸?shù)念盱牛灿汹A的垒手。可能是我的水平比較差倒信,大家可以寫自己的AI或者在我的AI基礎(chǔ)上再改進科贬!
完整的AI代碼可以去我的 github 看,點擊這里進入GitHub鳖悠。
如果這篇文章對您有幫助榜掌,贊賞一下吧~
您的支持是我繼續(xù)創(chuàng)作的動力~~~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市乘综,隨后出現(xiàn)的幾起案子憎账,更是在濱河造成了極大的恐慌,老刑警劉巖卡辰,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件胞皱,死亡現(xiàn)場離奇詭異,居然都是意外死亡九妈,警方通過查閱死者的電腦和手機朴恳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來允蚣,“玉大人于颖,你說我怎么就攤上這事∪峦茫” “怎么了森渐?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵做入,是天一觀的道長。 經(jīng)常有香客問我同衣,道長竟块,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任耐齐,我火速辦了婚禮浪秘,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘埠况。我一直安慰自己耸携,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布辕翰。 她就那樣靜靜地躺著夺衍,像睡著了一般。 火紅的嫁衣襯著肌膚如雪喜命。 梳的紋絲不亂的頭發(fā)上沟沙,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天,我揣著相機與錄音壁榕,去河邊找鬼矛紫。 笑死,一個胖子當(dāng)著我的面吹牛牌里,可吹牛的內(nèi)容都是我干的颊咬。 我是一名探鬼主播,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼二庵,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了缓呛?” 一聲冷哼從身側(cè)響起催享,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎哟绊,沒想到半個月后因妙,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡票髓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年攀涵,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片洽沟。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡以故,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出裆操,到底是詐尸還是另有隱情怒详,我是刑警寧澤炉媒,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站昆烁,受9級特大地震影響吊骤,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜静尼,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一白粉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧鼠渺,春花似錦鸭巴、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至掌敬,卻和暖如春惯豆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背奔害。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工楷兽, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人华临。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓芯杀,卻偏偏與公主長得像,于是被迫代替她去往敵國和親雅潭。 傳聞我的和親對象是個殘疾皇子揭厚,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,955評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 介紹內(nèi)容 前些時間,阿爾法狗對戰(zhàn)柯潔圍棋大賽很熱門扶供,那只是人工智能中的一個方向筛圆,展示了機器能代替人做某些事情。而圍...
    allen151閱讀 9,438評論 5 15
  • 內(nèi)容介紹 上一篇我們講到五子棋的UI篇的實現(xiàn)椿浓,現(xiàn)在這一篇我們來講五子棋的AI篇的實現(xiàn)太援。如果你還沒看過UI篇,建議先...
    allen151閱讀 9,614評論 9 14
  • 本文參加#致我們單純的小美好活動扳碍,本人承諾提岔,文章內(nèi)容為原創(chuàng),且未在其他平臺發(fā)表過笋敞。 一 蘇柑覺得很惶恐碱蒙。 ...
    Echoecho聲聲閱讀 862評論 0 0
  • 為什突然做這個,因為這是個筆試題夯巷,拖了一個月才寫(最近終于閑了O(∩_∩)O)振亮,廢話不多說巧还,說說這個題吧 題目要求...
    Stevenzwzhai閱讀 2,746評論 0 5
  • 非主流原意本身是一個很小資和小眾的圈子代表詞麸祷,但在中國被嚴(yán)重惡俗化了。所謂的非主流褒搔,已經(jīng)不是真正意義上的非主流阶牍,而...
    JianChun1閱讀 1,400評論 2 15