Prolog中的“Squares”逻辑谜语解决方案

时间:2013-04-23 08:46:39

标签: prolog logic puzzle

“的正方形”

输入

董事会规模m×n(m,n∈{1,...,32}),三元组列表(i, j, k),其中i∈{1,...,m},j∈{1 ,...,n},k∈{0,...,(n-2)·(m-2)})描述带数字的字段。

输出

显示已解决的谜语的三元组列表(i, j, d)。三重(i, j, d)在坐标(i, j)(i+d, j+d)处描述具有相对顶点的正方形。

示例:

输入:

  

7。   7. [(3,3,0),(3,5,0),(4,4,1),(5,1,0),(6,6,3)]。

输出

[(1,1,2), (1,5,2), (2,2,4), (5,1,2), (4,4,3)]

图片:

Example

解释

  

我必须找到x个正方形的位置(x =带数字的字段)。在   每个广场的电路,正好在他的一个角落应该是   只有一个数字等于广场内的数字位数。双方的   正方形不能相互覆盖,与角落相同。方线是   “填充字段”所以(0,0,1)方形填充4个字段并且内部有0个字段。

我需要一些帮助编码解决方案来解决Prolog中的这个谜题。有人能引导我朝着正确的方向前进吗?什么谓词,我应该使用的规则。

1 个答案:

答案 0 :(得分:1)

由于Naimads的生命值得保存(!),这里有一些指导性的帮助。

程序员倾向于在bottomp-up(从“较低”级别的功能开始,构建完整应用程序)或自上而下(从提供输入的高级“shell”功能开始)计算他们的项目/ output,但解决方案处理存根以供稍后细化)。

无论哪种方式,我都可以推荐一种由Ruby编程社区支持的Prolog编程方法:Test Driven Development

让我们选择一些功能要求,一个高,一个低,并讨论这个哲学如何帮助。

Prolog中的高级谓词是一个获取所有输入和输出参数并在语义上定义问题的谓词。请注意,我们可以写下这样的谓词,而无需关心如何实现解决方案流程:

/* squaresRiddle/4 takes inputs of Height and Width of a "board" with
   a list of (nonnegative) integers located at cells of the board, and
   produces a corresponding list of squares having one corner at each
   of those locations "boxing in" exactly the specified counts of them
   in their interiors.  No edges can overlap nor corners coincide.  */
squaresRiddle(Height,Width,BoxedCountList, OutputSquaresList).

到目前为止,我们刚刚解决了这个问题。评论给出了有用的进展(明确地定义了高级别的输入和输出),此时的代码只保证了传递任何参数的“成功”。所以这个代码的“测试”:

?= squaresRiddle(7,7,ListIn,ListOut).
除了自由变量之外,

不会产生任何东西。

接下来让我们考虑一下如何表示输入列表和输出列表。在课题中,建议使用整数三元组作为这些列表的条目。我建议改为使用命名的仿函数,因为那些输入三元组的语义(给出带有计数的单元格的x,y坐标)与输出三元组的语义略有不同(给出左上角的x,y坐标)和方形的“范围”(高度和宽度)。请特别注意,输出方块可以通过与相应输入项中的角不同的角来描述,尽管输入项中的那个角需要是输出方块的四个角之一。

因此,如果这些构造通过简单的函子名称区分,例如,它可以使代码更具可读性。 BoxedCountList = [box(3,3,0),box(3,5,0),box(4,4,1),box(5,1,0),box(6,6,3)]OutputSquaresList = [sqr(1,1,2), sqr(1,5,2), sqr(2,2,4), sqr(5,1,2), sqr(4,4,3)]

让我们稍微考虑一下搜索解决方案的进展情况。输出项与输入项一一对应,因此列表最终将具有相同的长度。但是,选择第k个输出项目不仅取决于第k个输入项目,还取决于 all 输入项目(因为我们计算输出方块内部的数量)和前面的输出项目(因为我们不允许会合的角落和重叠的边缘。)

管理符合此要求的决策流程有多种方法,选择一种方法并使其发挥作用似乎是本练习的关键。如果您熟悉difference listsaccumulators,那么您就可以先行一步。

现在让我们转而讨论一些较低级别的功能。给定输入box,可能有许多输出sqr可以与之对应。给定输出的正“范围”,输出的四个角中的任何一个都可以满足输入的X,Y坐标。虽然需要更多检查来验证解决方案,但这方面似乎是开始测试的好地方:

/* check that coordinates X,Y are indeed a corner of candidate square */
hasCorner(sqr(SX,SY,Extent),X,Y) :-
    (SX is X ; SX is X + Extent),
    (SY is Y ; SY is Y + Extent).

我们如何使用此测试?好吧,我们可以生成所有可能的正方形(可能限制在我们的“板”的高度和宽度内的那些),然后检查是否有任何角落。这可能效率很低。一种更好的方法(就效率而言)将使用角来生成可能的方块(通过Extent在四个方向中的任何一个方向上从角落延伸),这取决于板尺寸的参数。这种“优化”的实施留给读者练习。