使用C++解决骑士巡游问题

3
我想解决骑士巡回问题。当我搜索时,我发现有很多解决方法。事实上,有非常高效和快速的算法来解决它,包括Warnsdoff的规则。但实际上,我从未想过复制任何一个算法。然后我看到了一个视频描述了一种在纸上解决这个问题的方法。视频链接是www.youtube.com%2Fwatch%3Fv%3DdWM5pKYZCHw&b=28。 我不知道那种方法是否已经被使用,但我决定跟随那种方法。这是算法的链接。 首先,我将解释一下解决骑士巡回问题的方法。我们假设有一个8*8的棋盘,并且我们已经给出了骑士的起始位置。现在,我将棋盘分成4个系统的盒子。左菱形系统、右菱形系统、左方系统、右方系统。首先,我将检查骑士在开始时处于哪个系统中。然后我将首先填充该系统,然后移动到下一个系统。为了填充该系统,我将首先进入当前块。整个棋盘被分成4个块(每个块都是(4*4),如您从视频中所见)。填充完该块后,我将移动到下一个块,依此类推。在填充所有块之后,我将移动到下一个系统。现在,我几乎做到了。我制作了一些函数,用于查找当前块、当前系统、是否可以进行移动、骑士在块中的下一个移动、块移位和最后系统移位。现在,我正在使用一个3D数组来存储有关每个盒子的一些重要信息。数组大小为[8][8][2]。在每个盒子的第一个元素中,我存储系统号,即我已经为每个四个系统分配了特定的数字以后识别它们。左菱形系统=1,右菱形系统=2,左方系统=3,右方系统=4。在每个盒子的下一个元素中,我存储有关该盒子的信息,无论我是否已经进入该盒子。在开始时,这些都是零,但随着我的进展,我会使它们成为1,表示我已经移动了该盒子。现在,我正在预测试模式下,并且在nextmove函数中遇到了一些逻辑问题。其他函数都运行完美。我在此处提供编码,但我只提供重要部分的选定代码。有一件事我忘记说的是,我正在一个名为current position的数组中存储骑士的当前位置,并且我将随着移动而更改当前位置。在整个代码中,m表示骑士的当前行,k表示当前列。以下是代码。
#include<iostream>
using namespace std;
// zero element for storing current row and 1 element for current column of knight.    
int currentposition[2]={0,0};
// 3d array for storing information
int   l[8][8][2]={ {{1,0} , {3,0} , {4,0} , {2,0} , {1,0} , {3,0} , {4,0} ,{2,0}}, 
                  {{4,0} , {2,0} , {1,0} , {3,0} , {4,0} , {2,0} , {1,0} , {3,0}},
                  {{3,0} , {1,0} , {2,0} , {4,0} , {3,0} , {1,0} , {2,0} , {4,0}},
                  {{2,0} , {4,0} , {3,0} , {1,0} , {2,0} , {4,0} , {3,0} , {1,0}},
                  {{1,0} , {3,0} , {4,0} , {2,0} , {1,0} , {3,0} , {4,0} , {2,0}},
                  {{4,0} , {2,0} , {1,0} , {3,0} , {4,0} , {2,0} , {1,0} , {3,0}},
                  {{3,0} , {1,0} , {2,0} , {4,0} , {3,0} , {1,0} , {2,0} , {4,0}},
                  {{2,0} , {4,0} , {3,0} , {1,0} , {2,0} , {4,0} , {3,0} ,{1,0}}};

//function for finding current block
int currentblock(int m , int k)    // m and k are current box       co-ordinates                         
{
int block;
if ((m>=0 && m<=3) && (k>=0 && k<=3))
     block= 1;
 if ((m>=0 && m<=3) && (k>3 && k<=7))
     block= 2;
 if ((m>3 && m<=7) && (k>=0 && k<=3))
     block= 3;
 if ((m>3 && m<=7) && (k>3 && k<=7))
     block= 4;
 return block;
}

//function telling that move is possible or not.
int movepossible(int m,int k,int i, int j)
// m and k represents current position and I and j represents the wanted position.
{             
          int ans=0;
          if ( ( (m-i)==1 && (k-j)==2 ) || ( (m-i)==2 && (k-j)==1 ) )
                          ans=1;
          if ( ( (m-i)==-1 && (k-j)==-2 ) || ( (m-i)==-2 && (k-j)==-1 ) )
                          ans=1;
          if ( ( (m-i)==-1 && (k-j)==2 ) || ( (m-i)==2 && (k-j)==-1 ) )
                          ans=1;
          if ( ( (m-i)==1 && (k-j)==-2 ) || ( (m-i)==-2 && (k-j)==1 ) )
                          ans=1;
          return ans;
}

//function to find the current system.
int currentsystem(int l[8][8][2],int m,int )

{
  int ans=l[m][k][0];
  return ans;
}
// function which move the knight in the specified box. 1 time  calling of function moves knight one time.
void nextmove(int l[8][8][2],int m,int k)
{     int block=currentblock(m,k);
      int system=currentsystem(l,m,k);
      int a,b,c,d;     
a,b,c,d, represents the range of the rows and columns for a specified block. There is no problem in this section I think.
  if (block==1)
   {   a=0;b=3;c=0;d=3;}
  else 
  {      if (block==2)
            {  a=0;b=3;c=4;d=3;}
         else 
            {     if (block==3)
                     { a=4;b=7;c=0;d=3;}
                  else
                      {   a=4;b=7;c=4;d=7;}
             }         
   }          

// now this will search the whole block for next move and it will check 3 conditions to move to a box.
for ( int rowmin=a; rowmin<=b ; rowmin+=1)
{         for (int colmin=c ;colmin<=d;colmin+=1)
         {     
               if (l[rowmin][colmin][1]!=1)   //this checks if we have already moved into that box or not
                {  if (l[rowmin][colmin][0]==system)
// this checks if box belongs to current system.
                   {    if  (movepossible(m,k,rowmin,colmin))
//this checks if move is possible or not
                        {
                                   currentposition[0]=rowmin;
// if all 3 conditions are satisfied knight will move to the box.
                                    currentposition[1]=colmin;
                                    l[rowmin][colmin][1]=1;
//this will change the value of the box to 1 in which we have moved.
                              }                            
                        }
                     }               
              }         
    }            
}                  


int main()
{  //int backtrackarray[8][8][2];
int m,k,i,j;
cout<<"Enter m:";   //Enters starting position(row) 
cin>>m;
cout<<"Enter k:";
// Enters starting position(column)
cin>>k;
currentposition[0]=m;   
// this updates the current position of knight in the currentposition array
currentposition[1]=k;
l[m][k][1]=1;

for (int u=0 ; u<3; u++)   // this loop is for testing of the nextmove function.
{     
  nextmove(l,currentposition[0],currentposition[1]);
  //calling of nextmove function.
     cout<<currentposition[0]<<" ,"<<currentposition[1];
  //displaying current position.
     cout<<endl;

}  
 cout<<"current block is"<<currentblock(m,k)<<endl;    //testing the current block function. Working perfect.

 cout<<"current system"<<currentsystem(l,m,k)<<endl;  //testing of current system function. Working perfect.

return 0;
}

此外,movepossible函数也运行得很好。现在的问题是当我调用下一个move函数时,它可以正确地进行第一和第二次移动,但无法进行块中的第三次移动。实际上,在特定系统的块中有三个移动,换句话说,它无法移动到块中的最后一个方框中。它不依赖于起始位置,对于每个起始位置都会出现这种情况。现在我已经花了很多时间找出问题所在,但没有找到。因此,请告诉我问题出在哪里。如果您对改进逻辑和代码有任何建议,请提出。当我输入起始位置(4,3)时,代码的输出如下:
6,2     //first move      

7,0     //second move

7,0     //not moved to the third one which is (5,1)


current block is3   //these are working perfect.
movepossible is1
current system2

但是输出应该像这样(仅适用于(4,3)):
6,2     //first move      

7,0     //second move

5,1     //third move

current block is3   //these are working perfect.
movepossible is1
current system2

5
我的问题会比较简短。这实际上与简短相反。如果您能够简化它,或者至少先给出一个简短版本,然后再提供详细信息,您就有更好的回答机会。 - interjay
3
在调试器中追踪它,看看它是如何失败的。 - Retired Ninja
当您有太多缩进级别时,代码难以跟踪,请考虑将代码重构为函数,您还可以使用结构体数组代替3D数组,这将简化代码并使其更易读。 - AndersK
我已经尝试了4到5个小时,但是我没有得到任何进展。 致退役忍者 - Ali Raza
我使用了许多函数,原始代码中几乎有10到12个函数,因为我还要执行回溯操作,但我只发布了包含3个函数的一部分代码。现在很难再添加更多的函数。给Claptrap。 - Ali Raza
显示剩余2条评论
2个回答

2
一次快速的调试让我发现,以下代码在你的情况下出现了错误:
     if (l[rowmin][colmin][1]!=1)   //this checks if we have already moved into that box or not
  1. 您应该进行调试(即使只是添加日志)。
  2. 这不是C++,这只是纯C,并在for循环中使用了一些iostream和声明。没有冒犯的意思,但我认为如果您以更符合C ++的方式重新思考代码,它将更易读/易于维护。

1
经过长时间的调试,我知道了。
if (l[rowmin][colmin][1]!=1)   //this checks if we have already moved into that box or not

只有整个问题是我的责任。 问题在于我将其写在循环内部,当函数搜索下一步时,它会在最终决策之前将值更改为1。当我将其放在花括号外面时,问题得到解决。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接