骑士使用递归的目的地

时间:2018-03-11 22:35:43

标签: c# recursion backtracking chess

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

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 - 跟踪到达目的地所需的移动次数

现在第一个检查我们是否到达目的地。第二个检查我们行进的坐标是否也没有受到阻碍(因为我的电路板是由零组成的,因此我们检查符号是否等于它是否导致它是&#39 ; s并不意味着路径受阻)。然后我们进入骑士可能的运动,这是该方法的主要部分。

另外还有另一个名为GaliJudeti的函数,用于检查我们是否在董事会的范围内(8x8)。

1 个答案:

答案 0 :(得分:0)

您的代码看起来必须正常工作。我只是使用你的算法,修改了一下,一切正常。我使用类来使它看起来更普遍,但事实上它们都是一样的。

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; }
}

希望这有帮助。