天天看點

計算機博弈大賽源代碼,2020計算機博弈大賽幻影圍棋分組第一天 資訊互動子產品...

2020計算機博弈大賽幻影圍棋分組第一天

從學長那拿到了2018,2019年參加幻影圍棋比賽的代碼,鹹魚了幾天之後,我組三人正式開始準備2020年的比賽,這篇部落客要記錄我參與的部分。

在看到源碼的時候,不禁感歎,源碼之混亂(畢竟祖傳代碼傳了不止一代),是以下決心對源碼進行重構,并且加深對源碼的了解。

首先來看學長給的程式結構圖,這張結構圖清晰易懂,重構的大體架構還是按他這個來。

計算機博弈大賽源代碼,2020計算機博弈大賽幻影圍棋分組第一天 資訊互動子產品...

首先從最簡單也是最基礎的資訊互動子產品開始寫

資訊互動子產品

這個子產品的功能與平台進行資訊互動,從評估系統子產品接收下棋點,更新棋盤資訊等等。

引擎與平台通信的技術是程序間通信,是以我們隻需要用标準輸入輸出函數即可實作與平台的通信。

這是平台與引擎的通信協定規範

連結: https://pan.baidu.com/s/1OxH4YbOE5pEIk21rPn0pHQ

提取碼: u54e

引擎向平台發送的指令隻有move, 表明在哪下棋, 格式為 move + ’ ’ + positionlist, 例如

printf("move %c%c\n",step.point.x+'A',step.point.y+'A');

幻影圍棋允許pass

printf("move pass\n");

鑒于平台可能有更改通信格式的可能,是以我們将輸出封裝為一些函數,引擎調用該方法即可,指令格式改變不會影響整體程式的的運作。

"""

這裡有向平台發送指令和參數的函數, 已經封裝好了

"""

def sendMove(point):

"""

與平台通信,發送Move指令 格式 move 12 12是坐标1, 2

:param point: 向平台送出下棋的點坐标

:return: None

"""

print("move {0}{1}".format(chr(point.x + ord('A')), chr(point.y + ord('A'))))

def sendMoveByXY(x, y):

"""

與平台通信,發送Move指令 格式 move 12 12是坐标1, 2

:param point: 向平台送出下棋的點坐标

:return: None

"""

print("move {0}{1}".format(chr(x + ord('A')), chr(y + ord('A'))))

def sendMovePass():

print("move pass")

def sendName(name):

"""

向平台發送引擎名稱

:param name:名稱

:return: None

"""

print("name {0}".format(name))

資訊互動子產品中,當平台向引擎發送指令以及資料時,對于不同的指令都會有一些處理邏輯,最後可能導緻資訊互動子產品檔案if/else每條分支都很長,代碼可讀性和可維護性都大大降低。是以這裡我們将處理每條指令的邏輯都封裝為一個方法。

class BoardControlInterface(object):

"""

這是一個棋盤控制的接口,所有的棋盤控制類都應該繼承他,并且實作裡面的方法

"""

def move(self, msg):

"""

:param msg: 平台發送過來的資訊

:return:

"""

print("move action")

pass

def accept(self):

"""

如果下法被平台接受了,則執行這個方法

:return:

"""

print("accept action")

pass

def refuse(self):

"""

如果被平台拒絕了則執行這個方法

:return:

"""

print("refuse action")

pass

def take(self):

"""

如果我方提子,則執行這個方法

:return:

"""

print("take action")

pass

def taked(self, msg):

"""

如果我方被對方提子,則執行這個方法

:param msg:平台發送過來的資訊

:return:

"""

print("taked action")

pass

def new(self, msg):

"""

建立對局

:param msg:平台發送過來的資訊

:return:

"""

print("new action")

pass

接收平台資訊的子產品,原來的子產品代碼量大,處理邏輯複雜,重構就要解決這個問題,提高程式的可讀性和可維護性。沒有什麼是加一層不能解決的,如果有,那就加兩層,這裡将原來的資訊互動子產品分為了兩層,一層負責接收,另一層負責處理。

import sys

import go_configuration.game_conf as gf

import go_interaction.order_to_be_send as order

import go_board_control.board_control_interface as BoardControl

sys.path.append("..")

"""

這裡是總控制檔案,當處理的條件少的時候直接用if/else結構簡單清晰,條件變多的時候建議用反射機制實作

"""

def run():

boardControl = BoardControl.BoardControlInterface()

while True:

sys.stdout.flush()

msg = input().split(" ")

sys.stdin.flush()

if gf.GameStatus.isGuessMode == True:

pass

elif 'new' in msg[0]:

boardControl.new(msg)

pass

elif 'move' in msg[0]:

boardControl.move(msg)

order.sendMove(1, 2)

pass

elif 'accept' in msg[0]:

boardControl.accept()

pass

elif 'refuse' in msg[0]:

boardControl.refuse()

pass

elif 'take' in msg[0]:

boardControl.take()

pass

elif 'taked' in msg[0]:

boardControl.taked(msg)

pass

elif 'error' in msg[0]:

pass

elif 'name?' in msg[0]:

order.sendName("Blizzard")

msg.clear()

pass

總結:

1. 對于經常用到的語句,都把他們封裝為函數,以函數調用的方式執行,讓程式的可維護性大大提高。

2. 對于代碼邏輯複雜,單檔案過長導緻可讀性和可維護性都低的情況,可以在原有基礎上分層,每層盡量隻做一件事情。