Java 谁能帮我弄一下这个骑士';什么是旅游代码?

Java 谁能帮我弄一下这个骑士';什么是旅游代码?,java,recursion,Java,Recursion,代码对我来说似乎很好,但输出太短,当它应该是“是”时,答案是“否”(从a开始,0,骑士应该能够遍历整个棋盘) 顺便说一下,我的positionsListedarray是[9][9]的原因是我希望值为1-8,以匹配输出 public class KnightChessRiddle { static // given a chess board and a 0,0 starting point, can a knight pass through // all the the squares wit

代码对我来说似乎很好,但输出太短,当它应该是“是”时,答案是“否”(从a开始,0,骑士应该能够遍历整个棋盘)

顺便说一下,我的
positionsListed
array是[9][9]的原因是我希望值为1-8,以匹配输出

public class KnightChessRiddle {
static // given a chess board and a 0,0 starting point, can a knight pass through
// all the the squares without passing
// a square twice

int[][] positionsVisited = new int[9][9];
static int positionX = 1;
static int positionY = 1;
boolean stop = false;
static boolean continUe = false;
static int moveCounter = -1;

public static void main(String[] args) {
    if (recursive(1, 1, 0)) {
        System.out.println("yes");
    }
    else System.out.println("no");
}

public static boolean recursive(int x, int y, int moveType){


    if (x>8||x<=0||y>8||y<=0) return false;
    if (positionsVisited[x][y]==1) {
        return false;
    }
    positionX = x;
    positionY = y;
    positionsVisited[positionX][positionY]++;

    char c;
    c='a';
    switch (positionX) {
    case 1:
        c='a';
        break;
    case 2:
        c='b';
        break;
    case 3:
        c='c';
        break;
    case 4:
        c='d';
        break;
    case 5:
        c='e';
        break;
    case 6:
        c='f';
        break;
    case 7:
        c='g';
        break;
    case 8:
        c='h';
        break;

    default: 
        break;
    }
    moveCounter++;
    System.out.println("doing move "+moveType+" move count: "+moveCounter);
    System.out.println("Knight is in "+ c +","+positionY);

    try {
        Thread.sleep(100);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    if (recursive(positionX+2, positionY+1, 1)) {
        return true;
    }
    else if (recursive(positionX+1, positionY+2, 2) ) {
        return true;
    }
    else if (recursive(positionX+2, positionY-1, 3) ) {
        return true;
    }
    else if (recursive(positionX+1, positionY-2, 4)) {
        return true;
    }
    else if (recursive(positionX-2, positionY+1, 5)) {
        return true;
    }
    else if (recursive(positionX-1, positionY+2, 6)) {
        return true;
    }
    else if (recursive(positionX-2, positionY-1, 7)) {
        return true;
    }
    else if (recursive(positionX-1, positionY-2, 8)) {
        return true;
    }
    else return false;
}
您实现的算法如下所示:

private boolean isKnightsTour(Square currentSquare,
                              int[9][9] visitedSquares,
                              KnightsTour tour)
{
  // Append the current square to the array of visited squares.
  int[9][9] newVisitedSquares = visitedSquares;
  newVisitedSquares[currentSquare.getX()][currentSquare.getY()] = 1;

  // If we have visited all the squares, there is a knight's tour.  
  // Add some code here to check for that.
  if (allSquaresVisited()) {
    tour = new KnightsTour(currentSquare);
    return true;
  }

  // Test all squares a knight's move away.  If you get a knight's tour, 
  // append the current square to the start and return that.  
  KnightsTour newTour;
  if (isKnightsTour(currentSquare.doMove1(), newVisitedSquares, newTour) {
    newTour.appendStart(currentSquare);
    tour = newTour;
    return true;
  }

  // Repeat for the other knight's moves.

  else {
    tour = null;
    return false;
  }
}
按如下顺序从正方形排列可能的骑士招式:

在每次移动中,选择仍然允许的编号最低的移动

(A) 如果覆盖所有方块,则返回
true

(B) 如果无法继续移动,请返回
false

您的代码有两个问题。第一,已经指出,你错过了支票(A)。第二个更严重的问题是,该算法不起作用。事实上,你最终会得到以下结果:

private boolean isKnightsTour(Square currentSquare,
                              int[9][9] visitedSquares,
                              KnightsTour tour)
{
  // Append the current square to the array of visited squares.
  int[9][9] newVisitedSquares = visitedSquares;
  newVisitedSquares[currentSquare.getX()][currentSquare.getY()] = 1;

  // If we have visited all the squares, there is a knight's tour.  
  // Add some code here to check for that.
  if (allSquaresVisited()) {
    tour = new KnightsTour(currentSquare);
    return true;
  }

  // Test all squares a knight's move away.  If you get a knight's tour, 
  // append the current square to the start and return that.  
  KnightsTour newTour;
  if (isKnightsTour(currentSquare.doMove1(), newVisitedSquares, newTour) {
    newTour.appendStart(currentSquare);
    tour = newTour;
    return true;
  }

  // Repeat for the other knight's moves.

  else {
    tour = null;
    return false;
  }
}

在这张图片中,黑骑士代表开始和结束的方块,而白骑士代表所有其他被覆盖的方块。如果你遵循你的算法,你最终会在一个正方形中结束,在那里你无法到达任何其他没有被覆盖的正方形。这并不意味着你不能在棋盘上进行骑士之旅,只是你的算法不起作用


如果这确实是您想要实现的算法,那么就没有理由使用递归,因为
for
循环也可以工作。当我们当前所在的方格中存在有效的骑士移动时,您的函数
recursive
返回true。这实际上不是一个递归算法,有两个原因:

  • recursive
    函数不是幂等函数-它有一个副作用,即填充
    positionsVisited
    数组的一个平方
  • recursive
    函数调用全局变量-
    positionsVisited
    (我说的是“全局变量”,而不是“私有字段”,因为您编写的基本上是过程代码) 相反,函数
    recursive
    应该告诉您一个更一般的信息:给定棋盘上的一个特定方块,以及我们不允许访问的一组特定方块,是否有骑士之旅?(当然,使用正方形a1和访问位置的空数组调用该函数将告诉您是否存在骑士之旅。)该函数还可以返回一个字符串,该字符串将告诉您骑士之旅是什么

    递归函数的结构应如下所示:

    private boolean isKnightsTour(Square currentSquare,
                                  int[9][9] visitedSquares,
                                  KnightsTour tour)
    {
      // Append the current square to the array of visited squares.
      int[9][9] newVisitedSquares = visitedSquares;
      newVisitedSquares[currentSquare.getX()][currentSquare.getY()] = 1;
    
      // If we have visited all the squares, there is a knight's tour.  
      // Add some code here to check for that.
      if (allSquaresVisited()) {
        tour = new KnightsTour(currentSquare);
        return true;
      }
    
      // Test all squares a knight's move away.  If you get a knight's tour, 
      // append the current square to the start and return that.  
      KnightsTour newTour;
      if (isKnightsTour(currentSquare.doMove1(), newVisitedSquares, newTour) {
        newTour.appendStart(currentSquare);
        tour = newTour;
        return true;
      }
    
      // Repeat for the other knight's moves.
    
      else {
        tour = null;
        return false;
      }
    }
    
    或者,换言之:

    递归检查骑士离开当前方格的所有方格,传入新方格和通过添加当前方格而形成的新访问方格数组。如果有来自其中一个方块的骑士之旅,请将当前方块附加到其开头,以获得来自当前方块的骑士之旅

    而不是你写的是:

    递归地建立一个骑士之旅,从一个正方形开始,在每一步(相当随意地)选择一个合法的骑士移动。如果我们到了一个不能再做骑士招式的位置,返回
    false

    你能理解为什么第一个递归算法(当然更复杂)有效而你的算法无效吗

    除了“所有已访问”检查的问题外,我还看到至少一个问题,在类字段中。当算法通过递归的一个分支时,它将一些方块标记为已访问,并且由于该信息是类字段,所以当它失败当前分支并启动另一个分支时,它会看到以前尝试的所有无效信息

    如果您尝试将
    positionsVisited
    positionX
    positionY
    作为方法参数传递,并将其从类字段中删除,那么每个方法调用都会有自己的实际副本,会怎么样


    最终版本

    public class KnightChessRiddle {
    
        private final static Map<Integer, Character> letters = new HashMap<>();
    
        static {
            letters.put(0, 'a');
            letters.put(1, 'b');
            letters.put(2, 'c');
            letters.put(3, 'd');
            letters.put(4, 'e');
            letters.put(5, 'f');
        }
    
        public static void main(String[] args) {
            if (recursive(0, 0, 0, new boolean[6][6], 1, "")) {
                System.out.println("yes");
            } else {
                System.out.println("no");
            }
        }
    
        private static boolean allVisited(boolean[][] positionsVisited) {
            for (int i = 0; i < positionsVisited.length; i++) {
                for (int j = 0; j < positionsVisited.length; j++) {
                    if (!positionsVisited[i][j]) {
                        return false;
                    }
                }
            }
            return true;
        }
    
        private static boolean recursive(int positionX, int positionY, int moveType,
                boolean[][] positionsVisited, int moveCounter, String currentMoves) {
    
            // checks
            if (allVisited(positionsVisited)) {
                System.out.println(currentMoves);
                return true;
            }
    
            if (positionX > 5 || positionX < 0 || positionY > 5 || positionY < 0) {
                return false;
            }
    
            if (positionsVisited[positionX][positionY]) {
                return false;
            }
    
            // make move
            positionsVisited[positionX][positionY] = true;
    
            char c = letters.get(positionX);
            currentMoves += "" + c + (positionY + 1) + " (move type: " + (moveType + 1) + ")\r\n";
    
            if (recursive(positionX + 2, positionY + 1, 1, cloneArray(positionsVisited), moveCounter + 1, currentMoves)) {
                return true;
            } else if (recursive(positionX + 1, positionY + 2, 2, cloneArray(positionsVisited), moveCounter + 1, currentMoves)) {
                return true;
            } else if (recursive(positionX + 2, positionY - 1, 3, cloneArray(positionsVisited), moveCounter + 1, currentMoves)) {
                return true;
            } else if (recursive(positionX + 1, positionY - 2, 4, cloneArray(positionsVisited), moveCounter + 1, currentMoves)) {
                return true;
            } else if (recursive(positionX - 2, positionY + 1, 5, cloneArray(positionsVisited), moveCounter + 1, currentMoves)) {
                return true;
            } else if (recursive(positionX - 1, positionY + 2, 6, cloneArray(positionsVisited), moveCounter + 1, currentMoves)) {
                return true;
            } else if (recursive(positionX - 2, positionY - 1, 7, cloneArray(positionsVisited), moveCounter + 1, currentMoves)) {
                return true;
            } else if (recursive(positionX - 1, positionY - 2, 8, cloneArray(positionsVisited), moveCounter + 1, currentMoves)) {
                return true;
            } else {
                return false;
            }
    
        }
    
        private static boolean[][] cloneArray(boolean[][] src) {
            boolean[][] newPositions = new boolean[src.length][src.length];
            for (int i = 0; i < src.length; i++) {
                System.arraycopy(src[i], 0, newPositions[i], 0, src[0].length);
            }
            return newPositions;
        } 
    }
    
    公共类骑士俱乐部{
    private final static Map letters=new HashMap();
    静止的{
    字母。放入(0,'a');
    字母。将(1,'b');
    字母。将(2,'c');
    字母。放入(3,'d');
    字母。将(4,'e');
    字母。放入(5,'f');
    }
    公共静态void main(字符串[]args){
    if(递归(0,0,0,新布尔[6][6],1,”)){
    System.out.println(“是”);
    }否则{
    系统输出打印项次(“否”);
    }
    }
    私有静态布尔值allVisited(布尔值[][]位置Visited){
    对于(int i=0;i5 | |位置X<0 | |位置Y>5 | |位置Y<0){
    返回false;
    }
    如果(位置查看[positionX][positionY]){
    返回false;
    }
    //行动
    positionsVisited[positionX][positionY]=真;
    字符c=字母.get(位置x);
    currentMoves++=“c+(位置Y+1)+”(移动类型:“+(移动类型+1)+”)\r\n;
    if(递归(位置X+2、位置Y+1、1、cloneArray(位置可见)、移动计数器+1、当前移动)){
    返回true;
    }else if(递归(位置X+1、位置Y+2、2、cloneArray(位置可见)、移动计数器+1、当前移动)){
    返回true;
    }else if(递归)