四叉树迷宫中的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中的循环更易于使用和编写。由于在函数中不使用指针,所以必须使子函数返回所需的内容。