使用递归的骑士的目的地
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;
【讨论】:
以上是关于使用递归的骑士的目的地的主要内容,如果未能解决你的问题,请参考以下文章