Yunfi

Yunfi

tg_channel
github
email

記一個圍棋程式的製作過程

前情提要#

這是我大一計算機導論課的大作業之一,去年的學長還是寫的五子棋,不知道為什麼今年開始變成圍棋了,而且無論老師還是助教好像都和我一樣是不會下圍棋的。。。甚至把寫出圍棋 AI 作為附加題加分項,我覺得對於大一學生是挺離譜的。

先貼個專案的連結吧。。。#

yy4382/StupidGo | GitHub

作業要求#

請任意選擇一種編程語言,設計並實現一個圍棋小遊戲,要求能夠自動實現提子,判定勝負等功能。
附加題:

  1. 計時功能,超時判負功能。
  2. 人機對戰功能(機器人不和人比,僅與其他同學實現的機器人之間橫向比較。)

作業提交要求:最後給出代碼和描述文檔,文檔主要描述設計思路、以及你的代碼要如何使用(注意:文檔是判定成績的重要指標)

我的評價:

  1. 雖然要求是任選一種編程語言,但是其實課堂上老師是希望我們用 Python 的 tkinter 來實現的。而且我們其實只學過 C++,而 C++ 的 GUI 程式似乎比較難寫(我指 Qt,可見我上個學期寫的 這個 C++ Qt 專案,當時寫的可折磨了),又不至於去寫 js 之類的,所以 tkinter 應該是唯一的選擇了。
  2. 其他的要求,計時功能就是送分功能,輕鬆解決;自動提子略複雜,但是依舊可以一個晚上寫完;最煩的是判定勝負,且不談各種規則在這方面的混亂,光是提死子這一點實際上就要用到機器學習:最後還是沒能做成全自動的,手動提死子 + 自動判勝負。

編寫過程#

具體使用的規則和實現方式我寫了文檔,在 GitHub 倉庫的 readme 裡有連結。

整個程式有 4 個類:

  1. GoBasicAttributes:用來記錄當前棋盤的屬性,包括棋盤是幾乘幾的,棋盤的(像素)大小,棋盤上某個地方是什麼子,棋盤曾經的狀態等等。
  2. GoCore:最主要的邏輯處理類,絕大部分的核心邏輯是在這個類裡完成的。預留了給人機對戰的 ai 提供的 api,雖然最終沒寫 ai。
  3. GoBoard:是一個 tkinter.frame,畫棋盤用的。
  4. GoControl:統籌 GoCoreGoBoard,同時畫除了棋盤之外的控件。

原本是希望可以做到 GoCoreGoBoard 盡量解耦的,但是後來寫著寫著就又混一起了,然後擺爛不管了,互相影響就互相影響吧,反正我就寫幾天,作業交了我也不會再去看了,要什麼可維護性(

寫 GUI 的時候其實很方便,這種層次的東西直接打開 GitHub Copilot 寫個註釋它就幫你寫完了,但是寫邏輯的時候 Copilot 就是純純浪費時間的智障,直接關了寫的更快。

我第一個實現的功能是自動提子,就是在下子之後自動去除無氣的棋子。這個功能只花了我一個晚上,涉及的知識主要是學會把圍棋規則抽象為計算機可以理解的邏輯,其次是 BFS:其實廣度優先搜索涉及到了圍棋的每一個邏輯中,因為無論是棋子還是空白,都是以連接在一起的塊為單位的,需要 BFS 把這個連通圖遍歷一下。具體實現見 具體實現 - StupidGo

第二個功能是判定勝負。這可以說是整個專案中最複雜的功能,花了我好幾天研究。這玩意我選用的是中國規則的數子法,其實分為兩步:提死子和數子。此處的死子不是指此時沒有氣的子,而是無論之後如何下都一定不會形成兩眼的子。搜了半天,沒找到什麼我可以掌握的算法可以判斷死子,所以幹脆做了一個半自動版的:可以點一個死子,會自動把與它相關的死子都提掉,一般點 2-3 次就提完了。提完死子之後,每一個空白點組成的塊只會和一種顏色的棋子接壤,這樣數子就很好做了。

之後就主要做了一些體驗上的優化,同時把棋鐘加上了,但是數秒制我規則都沒看懂,最後還是搞了個方便的包干計時制。

至於為什麼我把專案起名為 StupidGo,是因為原本想做人機對戰的,如果要寫機器落子邏輯的話一定很傻,所以叫 Stupid。但是最後雖然我寫完的時候離 deadline 還有好幾天,但是直接開擺不寫了。

效果#

效果圖

最終的效果我覺得還行,美化界面的事就不管了吧,反正我又不用(

整個其實沒有用到什麼高深的算法技巧,最難的算法可能也就是 BFS 了,但是對於把實際問題用計算機解決的要求還是有一點的,所以還挺符合計算機導論這門課的定位?(

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。