四叉树迷宫中的OCaml寻路

时间:2018-12-17 10:38:45

标签: ocaml path-finding quadtree

我有一个定义的quadTree类型:

type 'a quadtree = 
| Empty 
| Leaf of 'a 
| Node of 'a quadtree * 'a quadtree * 'a quadtree * 'a quadtree;;

客房定义

type room = {
n : bool;
e : bool;
s : bool;
w : bool;
ps : coord;
exit : bool
}

定义的坐标

type coord = {
x : int;
y : int;
}

所有TLDR中,我有一个四叉树的房间,上下左右都有出口。

现在的目标是创建一个函数,该函数将找到从一个房间到另一个房间(从其坐标)的方式(如果存在),问题是我看不到如何在OCaml中进行操作... 无论如何,谢谢您的时间,祝您愉快。

编辑: 为了澄清,我是定义类型的人,可以根据需要更改它们。 另外,我尝试实现Dijkstra的算法(来自Wikipedia的伪代码),但对图,OCaml的数组和列表都不太熟悉。确切地说,我的问题-我认为-来自以下事实:我无法修改函数中的变量,因此例如在Wikipedia的伪代码中,此行:

u ← Q.extract_min()                    // Remove and return best vertex

我看到了如何删除最佳顶点,并且看到了如何将其返回,但不能同时删除两者。 或者,在这里:

for each neighbor v of u:           // where v is still in Q.
    alt ← dist[u] + length(u, v)
    if alt < dist[v]:               // A shorter path to v has been found
        dist[v] ← alt 
        prev[v] ← u

如何在“ for”循环之外修改dist和prev?我可以使用for循环还是使用递归函数更简单/更好?

我还要明确指出迷宫是“定向的”,这意味着能够从A室进入B室并不意味着您就能从B室进入A室。

编辑2: 我应该在一开始就对此进行澄清,对不起: 四叉树遵循以下规则:

| Node of North West * North East * South West * South East

编辑3: 好的,改变计划,原来我做事很愚蠢。我不需要找到通往某个房间的方法,只需找到出口即可。所以我尝试了这个:

let rec contains_exit = function
    | [] -> false
    | e::l' when (getCell e.x e.y maze).exit -> true
    | e::l' when (getCell e.x e.y maze).exit = false -> contains_exit l'
;;

let rec find_exit start way =
    if is_exit start then 
        way
    else
    (let a = find_exit (northp start) way@[start] in
    if contains_exit a then
        way
        else
        (
        let b = find_exit (eastp start) way@[start] in
        if contains_exit b then
            way
            else 
            (
        let c = find_exit (southp start) way@[start] in
        if contains_exit c then
            way
                else
                (
            let d = find_exit (westp start) way@[start] in
            if contains_exit d then
                way
                    else
                        way
                )
            )
        )
    )
;;

但是它给了我一个堆栈溢出。经过一番研究,似乎“ contains_exit a”行从不正确,因此永远不会返回该方式,并且会循环!

知道为什么吗?我的 contains_exit 函数是问题吗?

编辑4: 最终完成了此功能:

let rec find_exit start way =
    sleep 50000000;
    let r = (Random.int 180) in
    set_color (rgb r r r);
    fill_rect (start.x * sizeCell + doorWidth * 2) (start.y * sizeCell + doorWidth * 2) (sizeCell - 4 * doorWidth) (sizeCell - 4 * doorWidth);
    if is_exit start then 
            way@[start]
    else
    (let a = if (getCell start.x start.y maze).n && ((mem (northp start) way) = false) then find_exit (northp start) way@[start] else [] in
    if a != [] then
        a
        else
        (
        let b = if (getCell start.x start.y maze).e && ((mem (eastp start) way) = false) then find_exit (eastp start) way@[start] else [] in
        if b != [] then
            b
            else 
            (
        let c = if (getCell start.x start.y maze).w && ((mem (westp start) way) = false) then find_exit (westp start) way@[start] else [] in
        if c != [] then
            c
                else
                (
            let d = if (getCell start.x start.y maze).s && ((mem (southp start) way) = false) then find_exit (southp start) way@[start] else [] in
            if d != [] then
                d
                    else
                        []
                )
            )
        )
    )
;;

有时它可以工作...但是有时它阻塞了,它从一个房间到下面一个房间,然后又上升又下降了...我不明白为什么!?

如果您想尝试整个程序,这里是:link

1 个答案:

答案 0 :(得分:0)

然后您可以尝试以下操作:

type 'a quadtree = 
| Empty 
| Leaf of 'a 
| Node of 'a * 'a quadtree * 'a quadtree * 'a quadtree * 'a quadtree;;

type room = {
n : bool;
e : bool;
s : bool;
w : bool;
ps : coord;
exit : bool
};;

type coord = {
x : int;
y : int;
};;

let rec treeForRoom(tree, room) = 
    match tree with
    | Empty -> Empty
    | Leaf l -> if l.ps == room.ps then l else Empty
    | Node (r, n, e, s, w) as node -> 
        if r == room 
        then  node
        else 
            match ((r.ps.x - room.ps.x), (r.ps.y - room.ps.y)) with
            | (0, n) -> if n > 0 then treeForRoom(w) else treeForRoom(e)
            | (n, 0) -> if n > 0 then treeForRoom(s) else treeForRoom(n)

(* Assuming the root of the tree is the room we start from *)
let rec searchPath(tree, r) = 
    match tree with
    | Empty -> (false, 0, [])
    | Leaf l -> if l == r then (true, 0) else (false, 0, [])
    | Node (r, n, e, s, w) as node -> 
       let pn = searchPath(n, r) 
       and pe = searchPath(e, r) 
       and ps = searchPath(s, r)
       and pw = searchPath(w, r)
    in
        find_best_path(p1, p2, p3, p4)

let find_best_path(p1, p2, p3, p4) = 
    match (p1, p2, p3, p4) with
    | ((false,_,_), (false,_,_), (false,_,_), (false,_,_)) -> (false, -1, [])
    | ((true, w, p), (false,_,_), (false,_,_), (false,_,_)) -> (true, w, p)
    | ((false,_,_), (true, w, p)), (false,_,_), (false,_,_)) -> (true, w, p)
    | ((false,_,_), (false,_,_), (true, w, p)), (false,_,_)) -> (true, w, p)
    | ((false,_,_), (false,_,_), (false,_,_),(true, w, p)) -> (true, w, p)
    | ((p1ok, p1w, p1p), (p2ok, p2w, p2p),(p3ok, p3w, p3p),(p4ok, p4w, p4p)) -> 
        if p1ok && p2ok && p3ok && p4ok
        then 
            min_weight([(p1ok, p1w, p1p), (p2ok, p2w, p2p),(p3ok, p3w, p3p),(p4ok, p4w, p4p)])
        else 
        ....

let rec min_weight(l) = 
    match l with
    | [] -> (false, -1, [])
    | [t] -> t 
    | [(to, tw, tp) as t::q] -> let (mo, mw, mp) as minw = min_weight(q) in 
        if tw < mw
        then
            t
        else
            minw

我将根添加到类型定义('a* ...)中,因此我可以创建一个函数来查找要通过的树。我还假设树遵循以下规则:对于每个节点(root, north room, east room, south room, west room)(您可以创建一个add函数来确保此属性)。

然后,您将从头开始探索树,并获得最小的重量路径,然后结束到起点。 (它的权重与在相同条件下通过相同路径的权重相同(因为您从头开始探索树,但从头到尾计算路径))。

此代码未考虑通过门的可能性,但是只是添加了一项检查,因为通过树的方式已经正确定向。

我让您完成并更正代码。

希望它会对您有所帮助。