考虑到5x5网格,它需要记录所有可能的骑士移动组合,从每个起始方格,到后续的每个方格。
我设想它是一个类似二叉树的结构,但是由于棋盘上的每个方块都可以有超过2个潜在的下一步动作,我认为它不会起作用。我查看了A * / Pathfinding算法,但是它们都需要一个终端节点来处理我所能看到的,并且我不知道每次都在运行的终端节点会不同。
到目前为止,我的伪代码是:
For each square on the board
Check if this key has potential moves
If Potential moves
<Some way of selecting a next move (this could be the square we just originated from too!)>
Register this move into a collection we can check against for subsequent moves
Recursively call function with the square we just landed on
Else Continue
End
任何建议/指示都会非常感激,因为我很丢失!
答案 0 :(得分:3)
好的,正如评论所暗示的那样,会有极端数量的可能移动序列。 这是我的头脑,所以忍受我。
非递归版本:您需要一个位置列表列表(称为位置列表),这将是您的最终答案,我将该列表称为路由列表。
为每个起始位置创建一个列表,并将它们全部放入路线列表中。
While the routes list has a position list that's less than the required length
{
Get a position list that's too short.
Remove it from the routes list
Create new position lists that are a copy of the list we just removed + a possible next position from the last position in the list.
Add those lists to the routes list.
}
编辑:递归版本:
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
namespace ConsoleApplication1
{
class Program
{
static int GridSize = 5;
static void Main(string[] args)
{
List<List<Point>> Positions = (from X in Enumerable.Range(0, GridSize)
from Y in Enumerable.Range(0, GridSize)
select new List<Point>() { new Point(X, Y) }).ToList();
var PossibleRoutes = WalkGraph(Positions, 5);
}
static List<List<Point>> WalkGraph(List<List<Point>> RoutesList, int DesiredLength)
{
List<List<Point>> Result = new List<List<Point>>();
foreach (var Route in RoutesList)
{
if (Route.Count < DesiredLength)
{
// Extend the route (produces a list of routes) and recurse
Result.AddRange(WalkGraph(ExtendRoute(Route), DesiredLength));
}
else
{
Result.Add(Route);
}
}
return Result;
}
static List<List<Point>> ExtendRoute(List<Point> Route)
{
List<List<Point>> NextMoveRoutes = new List<List<Point>>();
// Itterate through each possible move
foreach (var NextMove in PossibleMoves(Route.Last()))
{
// Create a copy of the route, and add this possible move to it.
List<Point> NextMoveRoot = new List<Point>(Route);
NextMoveRoot.Add(NextMove);
NextMoveRoutes.Add(NextMoveRoot);
}
return NextMoveRoutes;
}
static List<Point> PossibleMoves(Point P)
{
// TODO Generate a list of possible places to move to
List<Point> Result = new List<Point>();
Result.Add(new Point(P.X + 1, P.Y + 2));
Result.Add(new Point(P.X - 1, P.Y + 2));
Result.Add(new Point(P.X + 1, P.Y - 2));
Result.Add(new Point(P.X - 1, P.Y - 2));
Result.Add(new Point(P.X + 2, P.Y + 1));
Result.Add(new Point(P.X - 2, P.Y + 1));
Result.Add(new Point(P.X + 2, P.Y - 1));
Result.Add(new Point(P.X - 2, P.Y - 1));
Result.RemoveAll(PossibleMove => PossibleMove.X < 0 || PossibleMove.X > GridSize ||
PossibleMove.Y < 0 || PossibleMove.Y > GridSize);
return Result;
}
}
}
编辑:以下是使用IEnumerable的版本,以消除初始计算时间,并大幅减少内存占用。
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
namespace ConsoleApplication1
{
class Program
{
static int GridSize = 5;
static void Main(string[] args)
{
IEnumerable<IEnumerable<Point>> Positions = from X in Enumerable.Range(0, GridSize)
from Y in Enumerable.Range(0, GridSize)
select new List<Point>() { new Point(X, Y) } as IEnumerable<Point>;
var PossibleRoutes = WalkGraph(Positions, 100);
foreach (var Route in PossibleRoutes)
{
Console.WriteLine(Route.Select(P => P.ToString()).Aggregate((curr, next) => curr + " " + next));
//Thread.Sleep(500); // Uncomment this to slow things down so you can read them!
}
Console.ReadKey();
}
static IEnumerable<IEnumerable<Point>> WalkGraph(IEnumerable<IEnumerable<Point>> RoutesList, int DesiredLength)
{
foreach (var Route in RoutesList)
{
if (Route.Count() < DesiredLength)
{
// Extend the route (produces a list of routes) and recurse
foreach (var ExtendedRoute in WalkGraph(ExtendRoute(Route), DesiredLength))
yield return ExtendedRoute;
}
else
{
//Result.Add(Route);
yield return Route;
}
}
}
static IEnumerable<IEnumerable<Point>> ExtendRoute(IEnumerable<Point> Route)
{
// Itterate through each possible move
foreach (var NextMove in PossibleMoves(Route.Last()))
{
// Create a copy of the route, and add this possible move to it.
List<Point> NextMoveRoute = new List<Point>(Route);
NextMoveRoute.Add(NextMove);
yield return NextMoveRoute;
}
}
static IEnumerable<Point> PossibleMoves(Point P)
{
List<Point> Result = new List<Point>();
Result.Add(new Point(P.X + 1, P.Y + 2));
Result.Add(new Point(P.X - 1, P.Y + 2));
Result.Add(new Point(P.X + 1, P.Y - 2));
Result.Add(new Point(P.X - 1, P.Y - 2));
Result.Add(new Point(P.X + 2, P.Y + 1));
Result.Add(new Point(P.X - 2, P.Y + 1));
Result.Add(new Point(P.X + 2, P.Y - 1));
Result.Add(new Point(P.X - 2, P.Y - 1));
Result.RemoveAll(PossibleMove => PossibleMove.X < 0 || PossibleMove.X > GridSize ||
PossibleMove.Y < 0 || PossibleMove.Y > GridSize);
return Result as IEnumerable<Point>;
}
}
}
答案 1 :(得分:1)
虽然深度优先搜索会起作用,但我认为你可以通过广度优先搜索更好(更快),因为你实际上不需要生成移动,你只需要计算移动的数量。
如果你可以在进行第(n-1)次移动时创建一个包含可能分支数的矩阵,那么你可以用它来计算第n次移动的可能分支数。
在迭代0中,矩阵只是一个矩阵,因为你尚未移动你的碎片:
table0
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
让我们将表格命名为table0,因为这是第0步。要从table1
获取table0
,您需要执行table1[r1c1] = table0[r2c3] + table0[r3c2]
,因为r1c1只能由r2c3和r3c2中的骑士到达,这是另一个例子,因为r2c2只能通过r {1}来找到r1c4,r3c4,r4c3,r4c1中的骑士。等等。
使用此算法,表的下几个值是这样的:
table1[r2c2] = table0[r1c4] + table0[r3c4] + table0[r4c3] + table0[r4c1]
所以基本上在这个4x4游戏中,这将是计算下一个网格的公式:
table1
2 3 3 2
3 4 4 3
3 4 4 3
2 3 3 2
table2
8 10 10 8
10 10 10 10
10 10 10 10
8 10 10 8
table3
20 30 30 20
30 36 36 30
30 36 36 30
20 30 30 20
table4
72 96 96 72
96 100 100 96
96 100 100 96
72 96 96 72
table5
200 292 192 200
192 336 336 192
192 336 336 192
200 192 192 200
这将采用常数存储器O(1),并且操作次数是线性O(n),具体取决于移动次数。注意:您需要检查此算法是否真的有效,我没有考虑是否正确计算了计数。
答案 2 :(得分:0)
所以这可以通过DFS完成。我相当确定自DFS生成每个路径以来有更快的方法,并且有O(2 ^ {count})个路径。这里有一些python代码,只是每个起点的每条路径都是DFS
def extended_knight_tours(width, height, count):
start_x, start_y = -1, -1
def dfs(x, y, moves_left):
if not (0 <= x < width and 0 <= y < height):
return 0
if moves_left == 0:
if (start_x, start_y) == (x, y):
return 1
else:
return 0
knight_moves = [(1, 2), (-1, 2), (1, -2), (-1, -2),
(2, 1), (2, -1), (-2, 1), (-2, -1)]
return sum(dfs(x + dx, y + dy, moves_left - 1)
for dx, dy in knight_moves)
ans = 0
for x in range(width):
for y in range(height):
start_x = x
start_y = y
ans += dfs(x, y, count)
return ans
一个简单的空间与时间的权衡,你可以加快速度,只需记住DFS(记得清除每个起始位置的缓存)。
从玩这个功能开始我注意到,对于每个奇数,答案都是零。因此,可能更快的算法是找到每个起始位置具有长度计数/ 2(不一定是路线)的路径的数量。然后可以使用count / 2值计算位置为中点的路径数,但我会将其作为练习留给读者:)