四叉树迷宫中的OCaml寻路

四叉树迷宫中的OCaml寻路,ocaml,path-finding,quadtree,Ocaml,Path Finding,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; }

我有一个四叉树类型,定义如下:

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;
}
由定义的坐标

type room = {
n : bool;
e : bool;
s : bool;
w : bool;
ps : coord;
exit : bool
}
type coord = {
x : int;
y : int;
}
所有这些,我有一个四叉树,里面有或没有上下左右的出口


现在的目标是创建一个函数,该函数将找到从一个房间到另一个房间(从其坐标)的方法(如果存在的话),问题是我不知道如何在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

编辑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”从来都不是真的,因此该方式永远不会返回,它会循环

知道为什么吗?问题是否存在于我的退出功能中

编辑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
                        []
                )
            )
        )
    )
;;
它有时是有效的。。。但其他时候它会阻塞,从一个房间到下面的房间,然后再上再下。。。我不明白为什么


如果您想尝试整个程序,请点击此处:

,然后您可以进行如下操作:

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四叉树=
|空的
|叶
|“a*”四叉树*“a*”四叉树*“a四叉树*”四叉树的节点;;
房间类型={
n:布尔;
e:布尔;
s:布尔;
w:布尔;
ps:coord;
出口:布尔
};;
类型坐标={
x:int;
y:int;
};;
让rec treefroom(树、房间)=
匹配树
|空->空
|叶l->如果l.ps==room.ps,则l为空
|节点(r、n、e、s、w)作为节点->
如果r==房间
然后节点
其他的
将((r.ps.x-room.ps.x),(r.ps.y-room.ps.y))与
|(0,n)->如果n>0,则树箭头(w)或树箭头(e)
|(n,0)->如果n>0,则树箭头(s)或树箭头(n)
(*假设树的根是我们开始的房间*)
让rec搜索路径(树,r)=
匹配树
|空->(假,0,[])
|叶l->如果l==r,则为(真,0)否则为(假,0,[])
|节点(r、n、e、s、w)作为节点->
设pn=searchPath(n,r)
和pe=搜索路径(e,r)
ps=搜索路径(s,r)
和pw=搜索路径(w,r)
在里面
找到最佳路径(p1、p2、p3、p4)
让我们找到最佳路径(p1,p2,p3,p4)=
将(p1、p2、p3、p4)与
|((假,,,,,(假,,,,,(假,,,,))->(假,-1,[]))
|((真,w,p),(假,,,,(假,,,,(假,,,))->(真,w,p)
|((假,,,,(真,w,p)),(假,,,,,(假,,,))->(真,w,p)
|((假,假,假,(真,w,p)),(假,w,p))->(真,w,p)
|((假,假,假,假,假,假,真,w,p))->(真,w,p)
|((p1ok,p1w,p1p),(p2ok,p2w,p2p),(p3ok,p3w,p3p),(p4ok,p4w,p4p))->
如果p1ok&&p2ok&&p3ok&&p4ok
然后
最小重量([(p1ok,p1w,p1p),(p2ok,p2w,p2p),(p3ok,p3w,p3p),(p4ok,p4w,p4p)])
其他的
....
让rec最小重量(l)=
匹配
|[]->(假,-1,[])
|[t]->t
|[(to,tw,tp)作为t::q]->让(mo,mw,mp)作为minw=最小重量(q)in
如果tw
我在类型定义中添加了根(
'a*…
),因此我可以创建一个函数来查找要遍历的好树。我还假设树遵守以下规则:
(根、北室、东室、南室、西室)
对于每个节点(您可以使用add函数来确保此属性)

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

此代码没有考虑穿过门的可能性,但它只是一个需要添加的检查,因为穿过树的方式已经正确定向

我让您完成并更正代码


希望它能对您有所帮助。

“我看不出如何在OCaml中实现这一点”并不是一个真正符合Stackoverflow范围的问题。你试了什么?你有解决问题的算法吗?如果是,OCaml在哪里阻碍了您的实现?正如@octachron所说,您没有提供足够的信息。如果您希望使用简单的算法:请使用递归函数来测试通向您希望去的房间的路径。它不是很有效,但在OCaml中运行良好,有助于基本理解递归。另外:找到一个算法,然后我们可以帮助您实现。另外,您是定义类型的人吗?你能改变它们吗?然后一个小的改变是添加节点的根,这样你就可以知道你所在的巫师室。OCaml是一种函数式语言,所以您应该使用递归函数,因为它们比OCaml中的循环更易于使用和编写。由于在函数中不使用指针,所以必须使子函数返回所需的内容。