亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

python實現五子棋人機對戰游戲

系統 2048 0

本文代碼基于 python3.6 和 pygame1.9.4。

五子棋比起我之前寫的幾款游戲來說,難度提高了不少。如果是人與人對戰,那么,電腦只需要判斷是否贏了就可以。如果是人機對戰,那你還得讓電腦知道怎么下。

我們先從簡單的問題來看。

開端

畫棋盤

首先肯定是要畫出棋盤來,用 pygame 畫出一個 19 × 19 或 15 × 15 的棋盤并不是什么難事,這在之前的文章中已經多次用到,就不贅述了。

畫棋子

需要說一下的是畫棋子,因為沒找到什么合適的棋子圖片,所以只要自己來畫棋子。
我們用 pygame.draw.circle 畫出來的圓形是這樣的:

python實現五子棋人機對戰游戲_第1張圖片

鋸齒狀十分明顯,pygame.draw 中有畫抗鋸齒直線的函數 aaline,但是并沒有 aacircle 這樣的函數來畫一個抗鋸齒的圓。

這里就需要用到 pygame.gfxdraw 啦。pygame.gfxdraw 目前還僅是實驗版本,這意味著這個 API? 可能會在以后的 pygame 版本中發生變化或消失。

要繪制抗鋸齒和填充形狀,請首先使用函數的aa *版本,然后使用填充版本。例如:

            
col = (255, 0, 0)
surf.fill((255, 255, 255))
pygame.gfxdraw.aacircle(surf, x, y, 30, col)
pygame.gfxdraw.filled_circle(surf, x, y, 30, col)
          

我們用這個方法在棋盤上畫一個棋子試試看。

python實現五子棋人機對戰游戲_第2張圖片

可以看到效果已明顯改善。

落子

落子需要判斷鼠標事件,當鼠標左鍵點擊,獲取鼠標點擊的位置,然后根據棋盤的位置,計算出棋子落在棋盤的位置。

            
while True:
    for event in pygame.event.get():
      if event.type == QUIT:
        sys.exit()
      elif event.type == MOUSEBUTTONDOWN:
        pressed_array = pygame.mouse.get_pressed()
        if pressed_array[0]: # 鼠標左鍵點擊
          mouse_pos = pygame.mouse.get_pos()
          click_point = _get_clickpoint(mouse_pos)
          

勝利判定

當一子落下,如何判定是否勝利?

可以肯定的是,當某一子落下的時候,如果出現了 5 連,那么落下的這顆子必定在這條 5 連線上。那么這個問題就可以簡化了,我們無需全盤掃描,只需要在落子位置上橫豎撇捺掃描一下,判斷是否出現 5 連即可。

我們定義一個棋盤類,類中實例化一個 19 × 19 的二維數組,初始值皆為 0,表示空,用 1 表示黑子,2 表示白子。這個類對外提供一個落子方法 drop,接收參數落子方和落子坐標,如果落子后勝利,則返回勝利者,否則返回 None。

            
Chessman = namedtuple('Chessman', 'Name Value Color')
Point = namedtuple('Point', 'X Y')
 
BLACK_CHESSMAN = Chessman('黑子', 1, (45, 45, 45))
WHITE_CHESSMAN = Chessman('白子', 2, (219, 219, 219))
 
offset = [(1, 0), (0, 1), (1, 1), (1, -1)]
 
 
class Checkerboard:
  def __init__(self, line_points):
    self._line_points = line_points
    self._checkerboard = [[0] * line_points for _ in range(line_points)]
 
  def _get_checkerboard(self):
    return self._checkerboard
 
  checkerboard = property(_get_checkerboard)
 
  # 判斷是否可落子
  def can_drop(self, point):
    return self._checkerboard[point.Y][point.X] == 0
 
  def drop(self, chessman, point):
    """
    落子
    :param chessman: 黑子/白子
    :param point:落子位置
    :return:若該子落下之后即可獲勝,則返回獲勝方,否則返回 None
    """
    print(f'{chessman.Name} ({point.X}, {point.Y})')
    self._checkerboard[point.Y][point.X] = chessman.Value
 
    if self._win(point):
      print(f'{chessman.Name}獲勝')
      return chessman
 
  # 判斷是否贏了
  def _win(self, point):
    cur_value = self._checkerboard[point.Y][point.X]
    for os in offset:
      if self._get_count_on_direction(point, cur_value, os[0], os[1]):
        return True
 
  def _get_count_on_direction(self, point, value, x_offset, y_offset):
    count = 1
    for step in range(1, 5):
      x = point.X + step * x_offset
      y = point.Y + step * y_offset
      if 0 <= x < self._line_points and 0 <= y < self._line_points and self._checkerboard[y][x] == value:
        count += 1
      else:
        break
    for step in range(1, 5):
      x = point.X - step * x_offset
      y = point.Y - step * y_offset
      if 0 <= x < self._line_points and 0 <= y < self._line_points and self._checkerboard[y][x] == value:
        count += 1
      else:
        break
 
    return count >= 5
          

這里我定義了一個偏移量,我們一共要計算橫豎撇捺 4 條線,任意一條線出現 5 連就算獲勝。計算方法實際上是一樣的,只是方向不同,所以定義一個偏移量數組,不同的偏移量表示不同的方向,這樣就可以利用循環來實現了,節省了很多代碼。

電腦落子

這就是全篇的重頭戲了,要怎么教電腦下五子棋。
首先聲明,我用的是相對傳統的方式,不是深度學習。

五子棋就是要實現 5 連,所以,一開始,我的想法是:將所有連線保存在一個數組中,落子的時候選擇最長的連線落子。但這樣有個問題解決不掉,如何讓電腦識別“三三”呢?

后來網上看到篇文章,使用的方法是:遍歷棋盤上的空位,計算每一個位置其橫豎撇捺 8 個方向上是否有己方的子,有一個就加 10 分,最后選得分最高的位置落子。

這樣不太嚴謹,寫出來的電腦估計水平很菜,但是這個思路卻是對的,落子就是要找到最值得的地方,那么我們干脆對每一個可落子的地方來做一個評估,選出最優解。

這里我們需要了解一下五子棋的幾種基本棋形:連五,活四,沖四,活三,眠三,活二,眠二。

連五

顧名思義,五顆同色棋子連在一起,贏了。

活四

四顆同色棋子連在一起,并且左右兩邊都沒有對方棋子阻擋,有兩個連五點。

沖四

四顆同色棋子連在一起,并且一邊有對方棋子阻擋,或者四顆棋子不是連的,當中有個空擋,這時只有一個連五點。

python實現五子棋人機對戰游戲_第3張圖片

活三、跳活三

活三 :三顆同色棋子連在一起。

跳活三 :中間隔了一個空格的活三。

眠三

只能夠形成沖四的三,無外乎兩種情況,一是一邊被擋住了,一是當中有 2 個空格。(其實我在代碼中僅考慮了第一種情況,即便形成沖四,也不是什么危險局面。)

python實現五子棋人機對戰游戲_第4張圖片

活二和眠二

活二,能夠形成活三的二;眠二,能夠形成眠三的二。這里就不放圖了,參考活三眠三。

打分機制

理解了這些棋形,那么按我們之前的思路,就是如何打分了。

  • 首先,連五肯定是不存在的,出現連五勝負已分,所以只要棋局還在進行中,就不會出現連五。那么,什么優先級最高?自然就是活四了。
  • 其次是對方的“四”,對方活四,你防不防都一樣輸了,對方沖四,你就必須防守。
  • 再次是我方的活三或沖四,活三跟沖四其實是一個級別的,對方必須防守。
  • 再次是對方的活三或沖四。

以此類推下去。我們可以總結一點規律:

  • 相同的棋形,我方優于對方。
  • 沖四跟活三一個級別,眠三跟活二一個級別。
  • 如果中間有空格的話,肯定是要比沒空格的略微低級一點,但不至于降級。

基本邏輯就是這樣,這一塊的代碼我寫得也不好,整個判斷寫了100多行,就不貼代碼了,大家可以直接下源碼看。

五子棋執黑是必贏的,代碼中,玩家就是執黑先手,電腦執白后手,所以,下的好是完全可以贏電腦的,不過一個小小失誤也很可能被電腦翻盤。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 欧美丰满大乳大屁股毛片 | 手机看片日韩日韩国产在线看 | 久青草国产手机在线视频 | 亚洲成色 | 青青久草在线 | 精品视频一区二区三三区四区 | 网站免费黄色 | 久久综合久久久久 | 日韩欧美亚洲精品 | 日本在线中文 | 全免费一级毛片在线播放 | 久久激情免费视频 | 在线精品免费视频 | 国内久久精品视频 | 亚洲第成色999久久网站 | 成人欧美在线 | 国产亚洲自拍一区 | 日本精品在线视频 | 爆操白虎逼 | 欧美一级毛片在线观看 | 97在线成人免费视频观看 | 26uuu欧美日本| 五月天在线免费视频 | 一区二三区国产 | 毛片2 | 国产日韩欧美综合 | 国产小呦 | 热久久视久久精品18国产 | 国产一区二区精品久久 | 久久9热| 四虎影视大全 | 视频大全在线观看免费 | 嘿咻成人免费视频欧美激情 | 麻豆成人久久精品二区三区小说 | 玖玖玖精品视频免费播放 | 国内视频一区 | 97福利 | 狠狠色视频 | 久在线| 五月婷婷在线观看 | 精品久久久久久无码中文字幕 |