简体   繁体   English

在序言中解决一个简单的难题

[英]Solving a simple puzzle in prolog

I solved a puzzle in C and tried to do the same in Prolog but i'm having some trouble expressing the facts and goals in this language.我用 C 解决了一个难题,并尝试在 Prolog 中做同样的事情,但我在用这种语言表达事实和目标时遇到了一些麻烦。

The very simplified version of the problem is this: there's two levers in a room.这个问题的非常简化的版本是:一个房间里有两个杠杆。 Each lever control a mechanism that can move either forward or backward in four different positions (which i noted 0, 1, 2 or 3).每个杠杆控制一个可以在四个不同位置(我记为 0、1、2 或 3)向前或向后移动的机构。 If you move a mechanism four times in the same direction, it'll be in the same position as before.如果你在同一个方向上移动一个机构四次,它会和以前一样处于相同的位置。

The lever n°1 move the mechanism n°1 two positions forward.杠杆 n°1 将机构 n°1 向前移动两个位置。 The lever n°2 move the mechanism n°2 one position forward.杠杆 n°2 将机构 n°2 向前移动一个位置。

Initially, the mechanism n°1 is in position 2 and the mechanism n°2 is in position 1. The problem is to find the quickest way to move both mechanisms in position 0 and get the sequence of lever that lead to each solution.最初,机构 n°1 位于位置 2,机构 n°2 位于位置 1。问题是找到将两个机构移动到位置 0 的最快方法,并获得导致每个解决方案的杠杆顺序。

Of course here the problem is trivial and you only need to pull the lever n°1 one time and the lever n°2 three times to have a solution.当然,这里的问题是微不足道的,您只需拉动 n°1 的杆一次和拉动 n°2 的杆 3 次即可得到解决方案。

Here's a simple code in C which gives the sequence of lever to pull to solve this problem by pulling less than 5 levers:这是 C 语言中的一个简单代码,它给出了拉动拉杆的顺序,通过拉动少于 5 个拉杆来解决这个问题:

int pos1 = 2, pos2 = 1;

int main()
{
    resolve(0,5);
    return 0;
}

void lever1(){
    pos1 = (pos1 + 2) % 4;
}

void undolever1(){
    pos1 = (pos1 - 2) % 4;
}

void lever2(){
    pos2 = (pos2 + 1) % 4;
}

void undolever2(){
    pos2 = (pos2 - 1) % 4;
}

void resolve(l, k){
    if(k == 0){
        return;
    }
    if(pos1 == 0 && pos2 == 0){
        printf("Solution: %d\n", l);
        return;
    }
    if(k>0){
        k--;
        lever1();
        resolve(l*10+1,k);
        undolever1();
        lever2();
        resolve(l*10+2,k);
        undolever2();
    }
}

My code in Prolog looks like this so far:到目前为止,我在 Prolog 中的代码如下所示:

lever(l1).
lever(l2).

mechanism(m1).
mechanism(m2).

position(m1,2).
position(m2,1).

pullL1() :- position(m1, mod(position(m1,X)+2,4)).
pullL2() :- position(m2, mod(position(m2,X)+1,4)).

solve(k) :- solve_(k, []).
solve_(0, r) :- !, postion(m1, p1), postion(m2, p2), p1 == 0, p2 == 0.
solve_(k, r) :- k > 0, pullL1(), k1 is k - 1, append(r, [1], r1), solve_(k1, r1).
solve_(k, r) :- k > 0, pullL2(), k1 is k - 1, append(r, [2], r2), solve_(k1, r2).

I'm pretty sure there's multiple problems in this code but I'm not sure how to fix it.我很确定这段代码中存在多个问题,但我不确定如何解决它。 Any help would be really appreciated.任何帮助将非常感激。

I think this is a very interesting Problem.我认为这是一个非常有趣的问题。 I suppose you want a general solution -> one lever can move multiple mechanisms.我想你想要一个通用的解决方案 -> 一个杠杆可以移动多个机构。 In the case the problem is like yours, where one lever only controls one mechanism the solution is trivial.如果问题与您的一样,一个杠杆只控制一种机制,那么解决方案就很简单了。 You just move every lever for the amount of time until the mechanism is at state zero.您只需移动每个杠杆一段时间,直到该机构处于状态零。

But I want to provide a more general solution, so where one lever can move multiple mechanisms.但我想提供一个更通用的解决方案,以便一个杠杆可以移动多个机构。 But first a little bit math.但首先是一点数学。 Don't worry i'll end up doing an example too.别担心,我最终也会做一个例子。

Lets define让我们定义

as being n levers and作为 n 个杠杆和

being m mechanisms.是 m 机制。 Then lets define every lever by a vector:然后让我们用一个向量定义每个杠杆:

where在哪里is the amount of steps是步数moves移动forward.向前。

For the mechanisms we define:对于我们定义的机制:

beeing the bias of the mechanisms -> so beeing机制的偏见->所以is in initial state处于初始状态and

being the amount of states for every mechanism.是每个机制的状态数量。 So now we can describe our whole system like this:所以现在我们可以这样描述我们的整个系统:

wher哪里is the amount of times we have to activate是我们必须激活的次数. . If we want to set all mechanisms to zero.如果我们想将所有机制设置为零。 If you are not familiar with the如果你不熟悉 notation this just means that a%m = b%m.符号这只是意味着 a%m = b%m。

can we rewritten as:我们可以改写为:

where k can be any natural number.其中 k 可以是任何自然数。 So we can rewrite our system to an equation system:所以我们可以将我们的系统重写为一个方程系统:

prolog can solve for us such a equation system. prolog 可以为我们解出这样一个方程组。 (there are different solutions to solve diophantine equation systems look at https://en.wikipedia.org/wiki/Diophantine_equation ) (解决丢番图方程系统有不同的解决方案,请参见https://en.wikipedia.org/wiki/Diophantine_equation

Ok now lets make an example: let say we have two levers and three mechanisms with 4 states.好的,现在让我们举个例子:假设我们有两个杠杆和三个具有 4 个状态的机制。 The fist lever moves M1 one forward and M3 two forward.拳头杠杆将 M1 向前移动一个,将 M3 向前移动两个。 The second lever moves M2 one forward and M3 one forward.第二个杠杆将 M2 向前移动一个,将 M3 向前移动一个。 M1 is in State 2. M2 is in State 3. M3 is in State 3. So our equation system looks like this: M1 处于状态 2。M2 处于状态 3。M3 处于状态 3。所以我们的方程系统如下所示:

in prolog we can solve this with the clpfd libary.在 prolog 中,我们可以使用 clpfd 库解决这个问题。

?- [library(clpfd)].

and then solve like this:然后像这样解决:

?- X1+(-4)*K1+2 #= 0, 1*X2+(-4)*K2+3 #= 0, 2*X1+X2+(-4)*K3+3 #= 0,Vs = [X1,X2], Vs ins 0..100,label(Vs).

which gives us the solution这给了我们解决方案

Vs = [2, 1] VS = [2, 1]

-> so X1 = 2 and X2 = 1 which is correct. -> 所以 X1 = 2 和 X2 = 1 这是正确的。 Prolog can give you more solutions. Prolog可以给你更多的解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM