遊戲紀錄檔 - LanKuDot/MLGame GitHub Wiki

無論是在手動模式還是機器學習模式,只要在執行時指定 -r/--record 的 flag,MLGame 就會產生遊戲遊戲紀錄檔,並儲存在該遊戲的 log 資料夾中。遊戲紀錄檔會儲存遊戲提供的場景資訊與玩家或鍵盤的指令,可以用在訓練機器學習的模型。

遊戲紀錄檔

格式

遊戲紀錄由一個 dict 組成,裡面的鍵值有:

  • record_format_version:這個紀錄檔的格式版本。在 MLGame Beta 8.0 中加入此欄位,值為 2。
  • 其餘為機器學習端的名字,不同的機器學習端的紀錄會存在不同的鍵值裡。其值亦為 dict,有兩個鍵值:
    • scene_info:其值為一個 list,依序存放每個收到的場景資訊,即 Game.get_player_scene_info() 每次回傳的 dict 中,屬於該機器學習端的場景資訊。
    • command:其值也是一個 list,存放的是玩家或是鍵盤傳出的指令,即 MLPlay.update() 或是 Game.get_keyboard_command() 回傳的 dict 中,屬於該機器學習端的指令。

紀錄檔格式例子:

{
    "record_format_version": 2,
    "ml_1P": {
        "scene_info": [scene_info_0, scene_info_1, ..., scene_info_n],
        "command": [command_0, command_1, .., None]
    },
    "ml_2P": {
        "scene_info": [scene_info_0, scene_info_1, ..., scene_info_n],
        "command": [command_0, command_1, .., None]
    },
    "ml_3P": {
        "scene_info": [],
        "command": []
    }
}

第 n 個指令就是針對第 n 個場景資訊所產生的指令。而最後一個場景資訊所對應的指令一定為 None,因為在遊戲結束後,不會有指令傳出。在動態玩家人數的遊戲中,沒有被啟動的機器學習端就不會被紀錄,就像上述例子中的 "ml_3P",會是一個空 list。

要注意的是,MLGame 是以傳出場景資訊後,將當下收到的指令儲存到紀錄中,所以當機器學習端有延遲時,所儲存的指令也會是有延遲的。另外如果機器學習端沒有傳任何指令,則對應的指令紀錄會是 None

檔名

在遊戲結束時,也就是 Game.update() 回傳 "RESET""QUIT" 時,MLGame 會用 pickle.dump() 將儲存的遊戲紀錄寫到檔案中。檔案會存在該遊戲資料夾的 log 資料夾裡,如果該資料夾不存在,MLGame 會自動建立。

而產生的檔名格式為 "<模式>_<遊戲參數>_<時間戳記>.pickle":

  • 模式:手動模式為 "manual",機細學習模式為 "ml"
  • 遊戲參數:依照輸入的參數產生,以底線間隔
  • 時間戳記:格式為 "YYYY-MM-DD_HH-MM-SS"

例如以指令 python MLGame.py -r -m arkanoid EASY 1 啟動的遊戲,所產生的紀錄檔檔名為 "manual_EASY_1_2020-05-26_15-10-10.pickle"。

讀取紀錄檔

一樣使用 pickle 模組來讀取紀錄檔。

>>> import pickle
>>> with open("games/arkanoid/log/manual_EASY_1_2020-05-26_15-10-10.pickle", "rb") as f:
...     p = pickle.load(f)

要注意的是開啟模式是 rb,而不是 r,這樣才可以被 pickle 讀取。再使用 pickle.load() 將存在紀錄檔裡的資訊讀出來。

>>> p.keys()
dict_keys(['record_format_version', 'ml'])
>>> p["record_format_version"]
2
>>> len(p["ml"]["scene_info"])
204
>>> p["ml"]["scene_info"][42]
{'frame': 42, 'status': 'GAME_ALIVE', 'ball': (93, 395), 'platform': (75, 400), 'bricks': [(35,
 50), (60, 50), (85, 50), (110, 50), (135, 50)], 'hard_bricks': []}
>>> p["ml"]["command"][42]
'MOVE_LEFT'