我有一个定义的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
答案 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函数来确保此属性)。
然后,您将从头开始探索树,并获得最小的重量路径,然后结束到起点。 (它的权重与在相同条件下通过相同路径的权重相同(因为您从头开始探索树,但从头到尾计算路径))。
此代码未考虑通过门的可能性,但是只是添加了一项检查,因为通过树的方式已经正确定向。
我让您完成并更正代码。
希望它会对您有所帮助。