使用递归的骑士的目的地

Posted

技术标签:

【中文标题】使用递归的骑士的目的地【英文标题】:Knight's destination using recursion 【发布时间】:2018-03-11 22:35:42 【问题描述】:

我一直在做一个需要骑士(我们在开始时有它的坐标)前往目的地(也称为坐标)的项目。 我尝试使用递归编写,但我的代码似乎没有做任何事情,我找不到问题。这是我的代码:

static bool Kelias(int dabX, int dabY, string[] Lenta, int dX, int dY, int indeksas)

    if (dabX == dX && dabY == dY)
        return true;
    if (!Lenta[dabY][dabX].Equals('0'))
    
        return false;
    
    if (indeksas > 0)
    
        StringBuilder naujas = new StringBuilder(Lenta[dabY]);

        naujas[dabX] = (char)indeksas;

        Lenta[dabY] = naujas.ToString();
    

    // aukstyn desinen
    if (GaliJudeti(dabX + 2, dabY + 1)
            && Kelias(dabX + 2, dabY + 1, Lenta, dX, dY, indeksas + 1))
    
        return true;
    
    // aukstyn desinen
    if (GaliJudeti(dabX + 1, dabY + 2)
            && Kelias(dabX + 1, dabY + 2, Lenta, dX, dY, indeksas + 1))
    
        return true;
    
    // aukstyn kairen
    if (GaliJudeti(dabX - 1, dabY + 2)
            && Kelias(dabX - 1, dabY + 2, Lenta, dX, dY, indeksas + 1))
    
        return true;
    
    // aukstyn kairen
    if (GaliJudeti(dabX - 2, dabY + 1)
            && Kelias(dabX - 2, dabY + 1, Lenta, dX, dY, indeksas + 1))
    
        return true;
    

    // zemyn kairen
    if (GaliJudeti(dabX - 2, dabY - 1)
            && Kelias(dabX - 2, dabY - 1, Lenta, dX, dY, indeksas + 1))
    
        return true;
    

    // zemyn kairen
    if (GaliJudeti(dabX - 1, dabY - 2)
            && Kelias(dabX - 1, dabY - 2, Lenta, dX, dY, indeksas + 1))
    
        return true;
    

    // zemyn desinen
    if (GaliJudeti(dabX + 1, dabY - 2)
            && Kelias(dabX + 1, dabY - 2, Lenta, dX, dY, indeksas + 1))
    
        return true;
    

    // zemyn desinen
    if (GaliJudeti(dabX + 2, dabY - 1)
            && Kelias(dabX + 2, dabY - 1, Lenta, dX, dY, indeksas + 1))
    
        return true;
    

    indeksas--;
    return false;


static bool GaliJudeti(int x, int y)

    if (x >= 0 && y >= 0 && x < 8 && y < 8)
    
        return true;
    
    return false;

关于变量和我想要做什么的一点解释:

dabX, dabY - 骑士的当前坐标

Lenta - 是我的板(它是一个字符串,因为我正在从 txt 文件中读取起始数据)。

dX, dY - 是目标目的地

indeksas - 跟踪到达目的地所需的移动次数

现在第一个 if 检查我们是否到达目的地。第二个检查我们要前往的坐标是否也没有被阻碍(因为我的棋盘是由零组成的,因为它在一个字符串中,我们检查符号是否等于它,因为如果它不是意味着路径被阻碍)。然后我们继续讨论骑士可能的动作,这是该方法的主要部分。

还有另一个名为 GaliJudeti 的函数,它检查我们是否在棋盘的范围内 (8x8)。

【问题讨论】:

如果您可以选择自己的游戏来实现,请考虑改用 TicTacToe 之类的更简单的游戏。做国际象棋游戏是相当先进的,如果我有选择的话,我不会选择做的事情。如果您需要检查它是否有效,那就是断点的用途(docs.microsoft.com/en-us/visualstudio/debugger/…)一旦有了,您就可以检查变量的值并遵循确切的逻辑。 这不是一个游戏,它只是一个递归练习.. 变量名是我的母语(如果你知道就有意义),所以很抱歉我不能更好地解释它。 不知道你的“阻塞”部分是否意味着这个,但通常你必须跟踪你来自哪里,所以你不只是在两个位置之间来回移动(或转圈)。 【参考方案1】:

您的代码看起来必须有效。我刚刚使用了您的算法,对其进行了一些修改,一切正常。我用类让它看起来更一般,但实际上都是一样的。

static bool MoveFirstSolution(Knight knight, Board board, Point destination, int counter, Trace trace)

    board.Set(knight.X, knight.Y, counter);
    if (knight.IsInPoint(destination))
           
        //trace is an object to store found path         
        trace.Counter = counter;
        trace.Board = board;                   
        return true;
    
    counter++;
    Point[] moves = knight.AllPossibleMoves();
    foreach (Point point in moves)
    
        if (board.Contains(point) && board.IsFree(point))
        
            knight.MoveTo(point);
            if (MoveFirstSolution(knight, board.GetCopy(), destination, counter, trace))
            
                return true;
            
        
    
    return false;

但是,此函数将找到第一个解决方案并停止。如果您想要最佳解决方案,即使找到答案,您也需要继续搜索。这是一个执行它的函数:

static void Move(Knight knight, Board board, Point destination, int counter, Trace trace)

    board.Set(knight.X, knight.Y, counter);
    if (knight.IsInPoint(destination))
    
        if (!trace.IsShorterThen(counter))
        
            trace.Counter = counter;
            trace.Board = board;
            Console.WriteLine("Better trace");
            Console.WriteLine("Counter: " + trace.Counter);
            Console.WriteLine(trace.Board);
        
        return;
    
    counter++;
    Point[] moves = knight.AllPossibleMoves();
    foreach(Point point in moves)
    
        if (board.Contains(point) && board.IsFree(point))
        
            knight.MoveTo(point);
            Move(knight, board.GetCopy(), destination, counter, trace);
        
    

每次找到更好的跟踪时都会覆盖该跟踪。但是对于 8 * 8 板,执行起来需要很长时间。

对于您的代码,我建议您尝试Console.WriteLine() 以确保一切正常。也许,您 Lenta 没有像您预期的那样被覆盖,这会导致无限递归。尝试跟踪函数的每个动作,找出问题的根源。

这是我的主要功能:

static void Main(string[] args)

    Knight knight = new Knight(0, 0);
    Board board = new Board(8, 8);
    Point destination = new Point(0, 4);
    Trace bestTrace = new Trace();
    MoveFirstSolution(knight, board, destination, 1, bestTrace);

    Console.WriteLine("Best trace: " + bestTrace.Counter);
    Console.WriteLine(bestTrace.Board);
    Console.ReadLine();

以及其他必需的类,因此您可以将其作为工作示例进行尝试。

class Trace

    public Trace()
    
        this.Board = null;
        this.Counter = -1;
    
    public Trace(Board board, int counter)
    
        this.Board = board;
        this.Counter = counter;
    
    public bool IsShorterThen(int counter)
    
        return this.Counter > 0 && this.Counter <= counter;
    
    public Board Board  get; set; 
    public int Counter  get; set; 

class Board

    private int[][] _board;
    public Board(int N, int M)
    
        this._board = new int[N][];
        for (int i = 0; i < N; i++)
        
            this._board[i] = new int[M];
            for (int j = 0; j < M; j++)
            
                this._board[i][j] = 0;
            
        
    
    public int N
    
        get
        
            return this._board.Length;
        
    
    public int M
    
        get
        
            return this._board.Length > 0 ? this._board[0].Length : 0;
        
    
    public Board GetEmptyCopy()
    
        return new Board(this.N, this.M);
    
    public Board GetCopy()
    
        Board b = new Board(this.N, this.M);
        for (int i = 0; i < N; i++)
        
            for (int j = 0; j < M; j++)
            
                b.Set(i, j, this.Get(i, j));
            
        
        return b;
    
    public bool Contains(int i, int j)
    
        return (i >= 0) && (i < this.N) && (j >= 0) && (j < this.M);
    
    public bool Contains(Point point)
    
        return this.Contains(point.X, point.Y);
    
    public bool IsFree(int i, int j)
    
        return this._board[i][j] == 0;
    
    public bool IsFree(Point point)
    
        return this.IsFree(point.X, point.Y);
    
    public void Set(int i, int j, int val)
    
        this._board[i][j] = val;
    
    public int Get(int i, int j)
    
        return this._board[i][j];
    
    public override string ToString()
    
        string str = "";
        for (int i = 0; i < this.N; i++)
        
            for (int j = 0; j < this.M; j++)
            
                str += String.Format("0, 3", this._board[i][j]);
            
            str += "\r\n";
        
        return str;
    

class Knight
        
    public Knight(int x, int y)
    
        this.X = x;
        this.Y = y;
    
    public int X  get; private set; 
    public int Y  get; private set; 
    public Point[] AllPossibleMoves()
    
        Point[] moves = new Point[8];
        moves[0] = new Point(this.X + 1, this.Y + 2);
        moves[1] = new Point(this.X + 1, this.Y - 2);
        moves[2] = new Point(this.X + 2, this.Y + 1);
        moves[3] = new Point(this.X + 2, this.Y - 1);
        moves[4] = new Point(this.X - 1, this.Y + 2);
        moves[5] = new Point(this.X - 1, this.Y - 2);
        moves[6] = new Point(this.X - 2, this.Y + 1);
        moves[7] = new Point(this.X - 2, this.Y - 1);
        return moves;
    
    public bool IsInPoint(int x, int y)
    
        return this.X == x && this.Y == y;
    
    public bool IsInPoint(Point point)
    
        return this.IsInPoint(point.X, point.Y);
    
    public void MoveTo(int x, int y)
    
        this.X = x;
        this.Y = y;
    
    public void MoveTo(Point point)
    
        this.MoveTo(point.X, point.Y);
    

class Point

    public Point(int x, int y)
    
        this.X = x;
        this.Y = y;
    
    public int X  get; private set; 
    public int Y  get; private set; 

【讨论】:

以上是关于使用递归的骑士的目的地的主要内容,如果未能解决你的问题,请参考以下文章

c ++中的递归回溯骑士之旅

骑士之旅蛮力

骑士游历C语言递归,请大家帮忙看下哪里错了,谢谢

极其简单的递归——骑士与金币

每天刷个算法题20160523:骑士巡游的递归转非递归解法

骑士之旅中的堆栈实现[关闭]