【问题标题】:Knight's Tour Brute Force Recursion骑士之旅蛮力递归
【发布时间】:2018-02-08 02:37:15
【问题描述】:

我正在尝试编写一个程序,允许用户在棋盘上输入任何坐标并使用蛮力递归完成骑士之旅。我得到一个无限循环,我不知道为什么。这是用 C++ 编写的,我只能使用蛮力递归来编写它。进入骑士的起始位置后,我的控制台输出窗口在每次移动后打印当前棋盘(只是暂时的,用于故障排除),但根据我的输出,移动数卡在 1,程序没有尝试任何其他动作。任何帮助表示赞赏。

#include "stdafx.h"
#include <iostream>
#include <iomanip>
using namespace std;

void printBoard();
bool moveKnight(int col, int row, int movNum);


int totalMoves = 0;
int board[7][7] = { { 0 } };


int main()
{
    cout << "Welcome to the Knight's Tour Program!  Enter a starting place for the knight on a chess board to get started.\n";

    int col;
    int row;

    int a;
    int b;

    while (1 == 1)
    {
        col = 0;
        row = 0;

        cout << "Enter column (0-7): ";
        cin >> col;

        cout << "Enter row (0-7): ";
        cin >> row;

        if (row < 0 || row > 7 || col < 0 || col > 7)
        {
            cout << "Invalid knight placement.  Please try again.\n";
        }

        else
        {
            break;
        }
    }

    int movNum = 1;

    board[col][row] = movNum;
    totalMoves++;

    moveKnight(col, row, movNum);

    if (moveKnight(col, row, movNum == true))
    {
        cout << "Tour finished!  Total moves: " << totalMoves << endl;
        printBoard();
        cout << "\n\n";
    }

    system("pause");
    return 0;
}


void printBoard()
{
    cout << "Current board\n";
    for (int i = 0; i < 8; i++)
    {
        for (int x = 0; x < 8; x++)
        {
            cout << setw(3) << board[i][x] << "  ";

            if (x == 7)
            {
                cout << "\n\n";
            }
        }
    }
    cout << "\n";
}


bool moveKnight(int col, int row, int movNum)
{
     printBoard(); //just for troubleshooting
     cout << "\n" << totalMoves << endl;

     if (moveKnight(col, row, movNum) == false)
     {
         board[col][row] = 0; //if there are no available moves then set the current space to 0 and move back a spot
     }

     if (movNum == 64)
     {
         return true; //if tour complete return true
     }

     if (totalMoves % 10000 == 0)
     {
         printBoard(); //printBoard() every 10000 moves
     }

     if (col >= 0 && col <= 7 && row >= 0 && row <= 7 && board[row][col] == 0) //check if space is on board and if it is unoccupied
     {
        board[col][row] = movNum;
        totalMoves++;

        if (moveKnight(col + 1, row - 2, movNum + 1) != false)
            moveKnight(col + 1, row - 2, movNum + 1);

        else if (moveKnight(col + 2, row - 1, movNum + 1) != false)
            moveKnight(col + 2, row - 1, movNum + 1);

        else if (moveKnight(col + 2, row + 1, movNum + 1) != false)
            moveKnight(col + 2, row + 1, movNum + 1);

        else if (moveKnight(col + 1, row + 2, movNum + 1) != false)
            moveKnight(col + 1, row + 2, movNum + 1);

        else if (moveKnight(col - 1, row + 2, movNum + 1) != false)
            moveKnight(col - 1, row + 2, movNum + 1);

        else if (moveKnight(col - 2, row + 1, movNum + 1) != false)
            moveKnight(col - 2, row + 1, movNum + 1);

        else if (moveKnight(col - 2, row - 1, movNum + 1) != false)
            moveKnight(col - 2, row - 1, movNum + 1);

        else if (moveKnight(col - 1, row - 2, movNum + 1) != false)
            moveKnight(col - 1, row - 2, movNum + 1);
        else
            return false;
     }
}

【问题讨论】:

  • moveKnight(col, row, movNum) 做的第一件事几乎就是再次调用moveKnight(col, row, movNum);这反过来几乎立即调用moveKnight(col, row, movNum);反过来...
  • while (1 == 1) 是的。
  • 他在循环中有一个break语句。
  • @FeiXiang 你是对的。我认为更传统的“永远”循环是while(1)while(true)
  • 是的。不知道他为什么这样做。

标签: c++ recursion infinite-loop knights-tour


【解决方案1】:

如果您查看moveKnight() 函数,请注意if (moveKnight(col, row, movNum) == false) 行对函数进行递归调用,无论输入是什么。

每当您使用递归函数时,它必须具有所谓的基本情况,即不会发生递归调用。否则,递归调用将继续进行,直到堆栈溢出,因为函数的一次执行将启动另一个函数,而另一个函数将启动另一个函数,依此类推..

顺便说一句,函数中的一堆 if 语句没有任何意义,因为你正在调用一个函数并检查输出,如果它是真的,那么你用完全相同的参数再次调用该函数。此外,如果您想要一个稍后会中断的无限循环,则不需要像while(1 == 1) 这样的东西。使用while(1)while(true)

【讨论】:

    【解决方案2】:

    int board[7][7] = { { 0 } };

    棋盘是 8 x 8,因此数组中需要 8 个元素(从 0 到 7,包括 7,即 8)

    if (moveKnight(col, row, movNum == true))

    你有语法错误,编译器会告诉你这一切。在 Visual Studio 中确保将警告级别设置为 4。然后确保程序编译时出现零错误和零警告。

    我建议编写一个不需要用户输入的程序。这将使调试程序和修复逻辑变得更加容易。

    下面是一个简单的递归,它移动骑士直到骑士最后被卡住。您必须进一步改进逻辑,使其涵盖所有方格。

    确保允许递归函数中断。其他答案中对此进行了更详细的讨论。

    int board[8][8] = { 0 };
    
    void printBoard()
    {
        cout << "Current board\n";
        for(int i = 0; i < 8; i++)
        {
            for(int x = 0; x < 8; x++)
                cout << board[i][x] << " ";
            cout << "\n";
        }
        cout << "\n";
    }
    
    int test(int &row, int &col, int move_row, int move_col)
    {
        int r = row + move_row;
        int c = col + move_col;
        if(r >= 0 && r < 8 && c >= 0 && c < 8 && !board[r][c])
        {
            row = r;
            col = c;
            return 1;
        }
        return 0;
    }
    
    bool move_knight(int &row, int &col)
    {
        board[row][col] = 1;
        printBoard();
        system("pause");
        if(!test(row, col, 1, 2))
            if(!test(row, col, 1, -2))
                if(!test(row, col, -1, 2))
                    if(!test(row, col, -1, -2))
                        if(!test(row, col, 2, 1))
                            if(!test(row, col, 2, -1))
                                if(!test(row, col, -2, 1))
                                    if(!test(row, col, -2, -1))
                                        return false;
    
        move_knight(row, col);
        return true;
    }
    
    int main()
    {
        int col = 0;
        int row = 0;
        move_knight(col, row);
        system("pause");
        return 0;
    }
    

    【讨论】:

    • 为什么会有一堆嵌套的 if 语句?为什么不只使用一些逻辑运算符?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多