我正在用C#编写一个单词搜索拼图,我希望能够以优雅的方式搜索二维字符数组。
从左到右,从上到下等基本搜索并不难写,但是当在对角线上搜索时,事情开始变得有点冗长。我已经开始工作,但我确信那里有更好的解决方案。
以下是我想要解决的难题的一个例子,任何想法都会受到高度赞赏。
BXXD
AXEX
TRXX
FXXX
BAT FRED
编辑:感谢史蒂夫给我搜索罗盘点的想法
编辑:搜索结果需要返回数组中单词的x1,y1和x2,y2坐标。
编辑:感谢Antti为搜索数组提供了一个很好的算法。
这是我想出的最终结果。我基于Antti的答案中的算法,修改它以返回任何单词的开头和结尾的数组偏移量。这个算法将用于我在WPF中为我的孩子写的Word Search游戏。感谢大家帮助我。当它受到尊重时,我会在这里发布一个链接到该应用程序。
public class Range
{
public Range(Coordinate start, Coordinate end)
{
Start = start;
End = end;
}
public Coordinate Start { get; set; }
public Coordinate End { get; set; }
}
public class Coordinate
{
public Coordinate(int x, int y)
{
X = x;
Y = y;
}
public int X { get; set; }
public int Y { get; set; }
}
public class WordSearcher
{
public WordSearcher(char[,] puzzle)
{
Puzzle = puzzle;
}
public char[,] Puzzle { get; set; }
// represents the array offsets for each
// character surrounding the current one
private Coordinate[] directions =
{
new Coordinate(-1, 0), // West
new Coordinate(-1,-1), // North West
new Coordinate(0, -1), // North
new Coordinate(1, -1), // North East
new Coordinate(1, 0), // East
new Coordinate(1, 1), // South East
new Coordinate(0, 1), // South
new Coordinate(-1, 1) // South West
};
public Range Search(string word)
{
// scan the puzzle line by line
for (int y = 0; y < Puzzle.GetLength(0); y++)
{
for (int x = 0; x < Puzzle.GetLength(1); x++)
{
if (Puzzle[y, x] == word[0])
{
// and when we find a character that matches
// the start of the word, scan in each direction
// around it looking for the rest of the word
var start = new Coordinate(x, y);
var end = SearchEachDirection(word, x, y);
if (end != null)
{
return new Range(start, end);
}
}
}
}
return null;
}
private Coordinate SearchEachDirection(string word, int x, int y)
{
char[] chars = word.ToCharArray();
for (int direction = 0; direction < 8; direction++)
{
var reference = SearchDirection(chars, x, y, direction);
if (reference != null)
{
return reference;
}
}
return null;
}
private Coordinate SearchDirection(char[] chars, int x, int y, int direction)
{
// have we ve moved passed the boundary of the puzzle
if (x < 0 || y < 0 || x >= Puzzle.GetLength(1) || y >= Puzzle.GetLength(0))
return null;
if (Puzzle[y, x] != chars[0])
return null;
// when we reach the last character in the word
// the values of x,y represent location in the
// puzzle where the word stops
if (chars.Length == 1)
return new Coordinate(x, y);
// test the next character in the current direction
char[] copy = new char[chars.Length - 1];
Array.Copy(chars, 1, copy, 0, chars.Length - 1);
return SearchDirection(copy, x + directions[direction].X, y + directions[direction].Y, direction);
}
}
答案 0 :(得分:6)
这个解决方案是用C ++编写的,但原则是相同的
如果您的拼图由
表示char puzzle[N][N]
声明数组
int xd[8] = { -1, -1, 0, +1, +1, +1, 0, -1 };
int yd[8] = { 0, -1, -1, -1, 0, +1, +1, +1 };
然后当你想检查在方向d(d和0之间的d)的位置(x,y)是否可以找到单词'w'时,只需执行
bool wordsearch(const char *w, int x, int y, int d) {
if (*w == 0) return true; // end of word
if (x<0||y<0||x>=N||y>=N) return false; // out of bounds
if (puzzle[y][x] != w[0]) return false; // wrong character
// otherwise scan forwards
return wordsearch(w + 1, x + xd[d], y + yd[d], d);
}
然后是司机
bool wordsearch(const char *w, int x, int y) {
int d;
for (d=0;d<8;d++)
if (wordsearch(w, x, y, d)) return true;
return false;
}
bool wordsearch(const char *w) {
int x, y;
for (x=0;x<N;x++) for(y=0;y<N;y++) if (wordsearch(w, x, y)) return true;
return false;
}
答案 1 :(得分:4)
这是您应该使用特里数据结构的典型问题:http://en.wikipedia.org/wiki/Trie
一旦你有一个包含所有目标词的字典,你就会遍历二维数组的每个位置,并调用一个递归函数来扩展所有8种方法。有点像。
void Explore(TwoDimArray puzzle, Point2D currentCell, string currentMatch, List<string> foundSolutions);
如果出现以下情况,则停止递归:
- 你找到一个匹配
- currentMatch + currentCell的字符不再构成可能的匹配
- currentCell位置不再位于拼图区域内。
答案 2 :(得分:2)
在列表或某些此类数据结构中保留您要查找的每个单词的首字母。按顺序搜索每个字母。如果它是您要搜索的单词的第一个字母,则搜索其周围的每个字母以获取第二个字母。如果在单词中找到第二个字母,则记下单词对象中具有方向枚举的方向,即{N = 0,NE,E,SE,S,SW,W,NW}。然后只需按照该方向,直到您确定找不到或找到该单词。它们的关键是让搜索对象知道它正在查看多少个单词。因此,如果你正在寻找cater和牛,如果你发现C-A-T向东北方向移动,它可能也是。此外,如果你找到一个F,你需要确保检查每个方向,因为你可以让FRIAR向东,FAT向西。然后它就像确保你不出界一样简单,因为NE是X + 1 Y-1等......
答案 3 :(得分:2)
public class Range
{
public Range(Coordinate start, Coordinate end)
{
Start = start;
End = end;
}
public Coordinate Start { get; set; }
public Coordinate End { get; set; }
}
public class Coordinate
{
public Coordinate(int x, int y)
{
X = x;
Y = y;
}
public int X { get; set; }
public int Y { get; set; }
}
public class WordSearcher
{
public WordSearcher(char[,] puzzle)
{
Puzzle = puzzle;
}
public char[,] Puzzle { get; set; }
// represents the array offsets for each
// character surrounding the current one
private Coordinate[] directions =
{
new Coordinate(-1, 0), // West
new Coordinate(-1,-1), // North West
new Coordinate(0, -1), // North
new Coordinate(1, -1), // North East
new Coordinate(1, 0), // East
new Coordinate(1, 1), // South East
new Coordinate(0, 1), // South
new Coordinate(-1, 1) // South West
};
public Range Search(string word)
{
// scan the puzzle line by line
for (int y = 0; y < Puzzle.GetLength(0); y++)
{
for (int x = 0; x < Puzzle.GetLength(1); x++)
{
if (Puzzle[y, x] == word[0])
{
// and when we find a character that matches
// the start of the word, scan in each direction
// around it looking for the rest of the word
var start = new Coordinate(x, y);
var end = SearchEachDirection(word, x, y);
if (end != null)
{
return new Range(start, end);
}
}
}
}
return null;
}
private Coordinate SearchEachDirection(string word, int x, int y)
{
char[] chars = word.ToCharArray();
for (int direction = 0; direction < 8; direction++)
{
var reference = SearchDirection(chars, x, y, direction);
if (reference != null)
{
return reference;
}
}
return null;
}
private Coordinate SearchDirection(char[] chars, int x, int y, int direction)
{
// have we ve moved passed the boundary of the puzzle
if (x < 0 || y < 0 || x >= Puzzle.GetLength(1) || y >= Puzzle.GetLength(0))
return null;
if (Puzzle[y, x] != chars[0])
return null;
// when we reach the last character in the word
// the values of x,y represent location in the
// puzzle where the word stops
if (chars.Length == 1)
return new Coordinate(x, y);
// test the next character in the current direction
char[] copy = new char[chars.Length - 1];
Array.Copy(chars, 1, copy, 0, chars.Length - 1);
return SearchDirection(copy, x + directions[direction].X, y + directions[direction].Y, direction);
}
}
答案 4 :(得分:1)
不要使用二维数组来拼图。对于NxM字搜索,请使用(N + 2)*(M + 2)的数组。在你的拼图周围放置1个字符的填充。所以这个例子就变成了:
...... .BXXD. .AXEX. .TRXX. .FXXX. ......
句点是填充,所有这些都是1d数组。
调用新网格的宽度行跨度(S),您现在可以创建一个包含8个方向“向量”的数组D = [-S-1,-S,-S + 1,-1,1, S-1,S,S + 1]。使用此功能,您可以使用Puzzle [position + D [direction]]从任意方向的网格拼图[position]中的任意位置查看其邻居。
您的位置当然是单个变量而不是一对坐标。边框周围的填充物告诉您是否到达了棋盘的边缘,并且应该是一个从未在拼图内部使用过的角色。