1. 程式人生 > >ThoughtWorks演算法筆試題(計算機生成迷宮)

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)