ThoughtWorks演算法筆試題(計算機生成迷宮)
用計算機生成迷宮是一個很有趣的任務。我們可以用 道路網格(Road Grid) 來表示迷宮的道路,那麼 3 x 3的 道路網格(圖-1 左)可以對應一個 7 x 7 的 渲染網格(Render Grid) ——圖-1 右 的方式(迷宮的牆是灰色的,道路是白色的):
如果我們將迷宮 道路網格 兩個相鄰的 cell 連通,則可以打通道路。如 圖-2 所示:
連通道路網格有如下的約束條件:
● 每一個 cell 只能夠直接與相鄰正南、正北、正東、正西的 cell 連通。不能夠和其他的 cell 連通。
● 兩個 cell 之間的連通一定是雙向的。即 cell(0,0) 和 cell(1,0) 連通等價於 cell(1,0) 和cell(0,0) 的連通
要求1:將迷宮渲染為字串
現在我們希望你書寫程式,將給定迷宮的 道路網格,渲染為字串輸出。例如,其使用方式如下(虛擬碼,僅做演示,實際實現時請應用實際語言的程式設計風格)
Maze maze = MazeFactory.Create(command);
String mazeText = maze.Render();
其中 command 是一個字串。它的定義如下:
● 第一行是迷宮 道路網格 的尺寸。例如 3 x 3 的迷宮為 3 3,而 5 x 4 的迷宮為 5 4(5 行 4 列)。
● 第二行是迷宮 道路網格 的連通性定義。如果 cell(0,1) 和 cell(0,2) 是連通的,則表示為:0,1 0,2,多個連通以分號 ; 隔開。
例如,如果給定輸入:
3 3
0,1 0,2;0,0 1,0;0,1 1,1;0,2 1,2;1,0 1,1;1,1 1,2;1,1 2,1;1,2 2,2;2,0 2,1
則輸出字串為(如果當前 渲染網格 為牆壁,則輸出 [W] 如果為道路則輸出 [R]):
[W] [W] [W] [W] [W] [W] [W]
[W] [R] [W] [R] [R] [R] [W]
[W] [R] [W] [R] [W] [R] [W]
[W] [R] [R] [R] [R] [R] [W]
[W] [W] [W] [R] [W] [R] [W]
[W] [R] [R] [R] [W] [R] [W]
[W] [W] [W] [W] [W] [W] [W]
要求2:檢查輸入的有效性
在處理輸入的時候需要檢查輸入的有效性。需要檢查的有效性包括如下的幾個方面:
● 無效的數字:輸入的字串無法正確的轉換為數字。此時,該函式的輸出為字串 ”Invalid
number format.”
● 數字超出預定範圍:數字超出了允許的範圍,例如為負數等。此時,該函式的輸出為字串
”Number out of range.”
● 格式錯誤:輸入命令的格式不符合約定。此時,該函式的輸出為字串 ”Incorrect command
format.”
● 連通性錯誤:如果兩個網格無法連通,則屬於這種錯誤。此時,該函式的輸出為字串 ”Maze
format error.”
當多個問題同時出現時,報告其中一個錯誤即可。
程式碼如下:
import numpy as np render_w = "[W]" render_r = "[R]" # 轉化道路上頂點座標為渲染網格座標 輸入為陣列 def road_coord_convert_render_coord(coord): coord = 2*coord+1 return coord # 轉化為道路網格上的頂點座標 def convert_road_coords(rows, cols): coords = [] for i in range(rows): for j in range(cols): coords.append([i, j]) return np.array(coords) # 構建原始渲染圖 def create_render_grapy(rows, cols): render_rows = 2 * rows + 1 render_cols = 2 * cols + 1 render_graph = [] for x in range(render_rows): render_line = [] for y in range(render_cols): render_line.extend([render_w]) render_graph.append(render_line) return render_graph # 轉化座標為渲染圖上的通路 def convert_coord_to_W_R(coords,render_graph): for coord in coords: x = coord[0] y = coord[1] render_graph[x][y] = render_r return render_graph # 計算通路座標 def cal_line_coord(line_coords): line_coord = (line_coords[0]+line_coords[1])//2 return line_coord # 直觀顯示渲染圖 def view_render_graph(render_graph): for i in range(len(render_graph)): line = render_graph[i] line_str = '' for str in line: temp_str = str+' ' line_str +=temp_str print(line_str) # 轉化輸入行列字串為整數 def get_rows_clos(rows_cols_str): rows_cols_ls = rows_cols_str.strip().split(' ') # 格式錯誤:輸入命令的格式不符合約定 if len(rows_cols_ls)!=2: print("Incorrect command format.") # 無效的數字:輸入的字串無法正確的轉換為數字 if rows_cols_ls[0]>'9'or rows_cols_ls[0]<'1' or rows_cols_ls[1]>'9'or rows_cols_ls[1]<'1': print("Invalid number format.") rows = int(rows_cols_ls[0]) cols = int(rows_cols_ls[1]) # 數字超出預定範圍:數字超出了允許的範圍,例如為負數 if rows<=0 or cols<=0: print("Number out of range.") return rows, cols # 轉化輸入連通座標為陣列 def get_array_line_coords(line_coords_str): line_coords_ls = line_coords_str.strip().split(';') # 格式錯誤:輸入命令的格式不符合約定 if len(line_coords_ls)<=0: print("Incorrect command format.") line_coords = [] for line_coords_ in line_coords_ls: temp_line_coords = line_coords_.strip().split(' ') one_line_coord = [] for line_coord in temp_line_coords: temp_line_coord = line_coord.strip().split(',') temp_line_coord = [int(x) for x in temp_line_coord] one_line_coord.append(temp_line_coord) line_coords.append(one_line_coord) result_coords = [] for i in range(len(line_coords)): if i % 2 == 1: result_coords.append(line_coords[i]) return np.array(result_coords) # 轉化連通座標為渲染圖上的通路 def conver_line_coord_to_W_R(render_line_coords,render_graph): for line_coords in render_line_coords: line_coord = cal_line_coord(line_coords) line_coord = line_coord[np.newaxis,:] render_graph = convert_coord_to_W_R(line_coord, render_graph) return render_graph # 檢查道路圖上的座標是否連通 def check_line_coords(line_coords): for line_coord in line_coords: result = np.sum(abs(line_coord[0]-line_coord[1])) if result!=1: print("Maze format error.") if __name__ == '__main__': rows_cols_str = input("enter the number of rows and columns:") # rows_cols_str = "3 3" # 轉化輸入行列字串為整數 rows, cols = get_rows_clos(rows_cols_str) line_coords_str = input("enter the connected coordinates:") # line_coords_str = "0,1 0,2;0,0 1,0;0,1 1,1;0,2 1,2;1,0 1,1;1,1 1,2;1,1 2,1;1,2 2,2;2,0 2,1" # 轉化輸入連通座標為陣列 line_coords = get_array_line_coords(line_coords_str) check_line_coords(line_coords) # 轉化為道路網格上的頂點座標 road_coords = convert_road_coords(rows, cols) # 構建原始渲染圖 render_graph = create_render_grapy(rows, cols) # 轉化道路上頂點座標為渲染網格座標 road_coords = road_coord_convert_render_coord(road_coords) # 轉化座標為渲染圖上的通路 render_graph = convert_coord_to_W_R(road_coords,render_graph) # 轉化連通座標為渲染網格座標 render_line_coords = road_coord_convert_render_coord(line_coords) # 轉化連通座標為渲染圖上的通路 render_graph = conver_line_coord_to_W_R(render_line_coords,render_graph) # 顯示最終渲染圖 view_render_graph(render_graph)