撰寫一個機器人模擬器。
某間機器人工廠的測試設施需要一支程式來驗證機器人的移動。
機器人有三種可能的移動:
機器人會被放在一個假想的無限網格上,面朝某個特定方向(北、東、南或西),並位於一組 {x,y} 座標上,例如 {3,8},座標值往北和往東遞增。
接著機器人會收到一連串指令,此時測試設施會驗證機器人的新位置,以及它面朝哪個方向。
測試分成 3 個步驟。
用 go test 執行所有測試,或用 -tags 選項執行特定測試。
範例:
go test # run all tests
go test -tags step1 # run just step 1 tests.
go test -tags 'step1 step2' # run step1 and step2 tests
你會拿到一個原始檔 defs.go,它定義了測試程式所需的若干項目。 這個檔案依步驟分成三個區段。
要完成步驟 1,你需要定義 Right、Left、Advance、N、S、E、W 和 Dir。 完成步驟 1 之後再繼續進行步驟 2。
在步驟 1 中你實作了機器人的移動,但這還稱不上是模擬。 例如,原始碼裡的「機器人」在哪裡?「網格」又在哪裡? 把機器人動作轉換成網格位置的運算又在哪裡?是在機器人裡,還是在網格裡? 真實世界可不是這樣運作的。
步驟 2 會引入一個「房間」。 這看起來只是個小小的補充,但我們會做很大的改變,來釐清「房間」、「機器人」和「測試程式」各自的角色,並開始釐清這個模擬的物理機制。 你要把 Room 和 Robot 定義成函式,測試程式會將它們以 goroutine 的方式啟動,藉此「讓它們誕生」。 資訊會透過 Go 的 channel 在測試程式、機器人和房間之間流動。
把 Room 想成一個「物理引擎」,用來建立模型並模擬一個有牆壁和機器人的實體房間。 它應該以某種方式為房間的座標空間、機器人和牆壁的位置建立模型,並且確保例如機器人不會穿牆而過。 我們希望 Robot 是執行各種動作的代理者,但希望 Room 維持一致的真實狀態。
測試程式會建立這些 channel,並啟動 Room 和 Robot 兩者。 接著測試程式會傳送指令給 Robot。 傳送完指令後,它會關閉指令 channel。 Robot 必須接受指令,並把它正在嘗試執行的動作告知 Room。 當它偵測到指令 channel 關閉時,必須自行關閉。 房間必須解讀機器人動作所造成的物理結果。 當它偵測到機器人關閉時,會傳送一份最終報告回測試程式,說明機器人的最終位置和方向。
步驟 3 有三項重大改變:
至於 Room3 送出的最終位置報告,你可以直接回傳從 robots channel 收到的那個切片,只要把位置和方向更新過就好。 以下情況必須在日誌 channel 上傳送訊息: