我正在研究一种能解决3D谜题的算法。 但是我遇到了一个问题,我使用的算法是First Search Depth,它似乎运行良好,直到我得到“提升STORAGE_ERROR:EXCEPTION_STACK_OVERFLOW”。我不太确定为什么它不起作用。任何猜测为什么这不起作用?
我想要这个算法做什么: 它需要一个List,一个数字和一个目标。对于此示例,列表长7个部分。它试图进入第一个坐标的部分。如果它不适合,它会旋转直到它适合,然后它自己调用它(6个部分)。如果零件全部以24种方式旋转(所有可能的方式来旋转3D零件),那么它将移动到另一个坐标并再次尝试适合。当所有部件都没有或没有任何作用时,它应该退出,我有另一个算法,在同一个列表中发送另一个订单到这个算法。
我还希望算法查看最后一个坐标是否与目标不匹配,然后它应该回溯并尝试找到另一个解决方案。
以下是一些代码:
procedure Pseudo(Parts : in out List_Type; Figure : in out Figure_Type; Goal : in out Figure_Type; LastCoord : in out Integer) is
Unchanged : Part_Type := Parts.Data;
Next : boolean := False;
UnchangedFigure : Figure_Type;
begin
UnchangedFigure := Figure;
if Empty(Parts) then
raise Finished;
else
for I in 1..24 loop
RotNumber(Parts.Data,I); -- rotera
if Check(Parts.Data,Figure) then -- test om den platsar
Maincheck(Parts.Data,Figure,Goal,Next);
if Next then
Unchanged := Parts.Data;
Append_Part(Parts.Data,Figure);
Remove_First(Parts);
Next := False;
Pseudo(Parts,Figure,Goal,LastCoord);
Next := False;
Figure := UnchangedFigure;
Insert_First(Unchanged,Parts);
Figure.CoordX := 0;
Figure.CoordY := 0;
Figure.CoordZ := 0;
end if;
end if;
Parts.Data := Unchanged;
end loop;
end if;
-- if LastCoord /= 7 then --(Original
-- if To_String(Figure.Data)(LastCoord) /= To_String(Goal.Data)(LastCoord) then
-- Put("over");
-- return;
-- end if;
-- end if;
LastCoord := Figure.CoordZ*Figure.X*Figure.Y + (Figure.Y-Figure.CoordY-1)*(Figure.X) + Figure.CoordX +1;
if Figure.CoordY < Figure.Y-1 then
Figure.CoordY := Figure.CoordY +1;
Pseudo(Parts,Figure,Goal,LastCoord);
elsif Figure.CoordY = Figure.Y-1 then
if Figure.CoordX < Figure.X-1 then
Figure.CoordX := Figure.CoordX +1;
Figure.CoordY := 0;
Pseudo(Parts,Figure,Goal,LastCoord);
elsif Figure.CoordX = Figure.X-1 then
if Figure.CoordZ < Figure.Z-1 then
Figure.CoordZ := Figure.CoordZ +1;
Figure.CoordX := 0;
Figure.CoordY := 0;
Pseudo(Parts,Figure,Goal,LastCoord);
elsif Figure.CoordZ = Figure.Z-1 then
return;
end if;
end if;
end if;
end Pseudo;
答案 0 :(得分:1)
首先,不要使用异常来控制程序流,这是不好的做法。请考虑使用其他out
参数,而不是raise Finished
。
我认为将所有参数声明为in out
也是错误的。查看Parts
:在循环中,将图形附加到其Data
成员,然后删除列表的第一个元素。之后,您调用Pseudo
,它将再次列出该列表,如果不成功,Parts
将可能具有与调用之前完全不同的内容。你恢复之后的第一个元素,但是Append_Part
确实保持永久。我无法确定这是否真的是一个问题。在调用Pseudo
之后恢复列表和数字的努力也是一个明显的迹象,表明您不希望这些参数为in out
。
另一件看起来很可疑的事情是,在循环之后,你改变了图形的坐标,然后再次调用Pseudo
- 这会将第一次迭代结束时的坐标重置为0(如果条件匹配) 。可能的控制流程是:
Pseudo
开始,Parts
不为空。循环开始。我们假设图的Coord
值最初为0。Finished
。循环结束。Pseudo
。我们现在假设Parts
仍然具有与第一次调用Pseudo
时相同的值。正如我所写的那样,情况似乎并非如此,但如果我理解你的描述应该是正确的。Pseudo
它与第一次调用相同,只是图中某些坐标不同(可能Last_Coord
,这似乎并不重要)。Parts
不能为空,循环开始。Pseudo
的调用失败(如“不提升已完成”)。坐标将重置为0。Pseudo
调用的执行相同,因为它运行的数据现在是相同的。因此,循环中不会引发Finished
,之后,Pseudo
将第三次被调用,其参数与之前完全相同。如您所见,这将导致无休止的递归。我无法确定是否会发生这种情况,因为我对您的类型或您调用的子程序一无所知。
在目前的情况下,您的代码很难理解,因为它具有非常复杂的控制流。如果你带走了一些代码的复杂性,那么追踪错误会更容易。我建议使用循环迭代坐标而不是递归。这可以解决您的问题。