我有可以手动使用硬编码下标正确执行的代码。 当我尝试循环执行时,它会失败。
我有疑问的代码在异步Button_Click函数中。
myTaskList.Add(Task.Factory.StartNew(() => words[3].AddRange(CalcWords(3))));
myTaskList.Add(Task.Factory.StartNew(() => words[4].AddRange(CalcWords(4))));
myTaskList.Add(Task.Factory.StartNew(() => words[5].AddRange(CalcWords(5))));
myTaskList.Add(Task.Factory.StartNew(() => words[6].AddRange(CalcWords(6))));
myTaskList.Add(Task.Factory.StartNew(() => words[7].AddRange(CalcWords(7))));
myTaskList.Add(Task.Factory.StartNew(() => words[8].AddRange(CalcWords(8))));
myTaskList.Add(Task.Factory.StartNew(() => words[9].AddRange(CalcWords(9))));
如果我尝试从3到9的循环中执行此操作,它将抛出索引超出范围异常。该代码应等效。
for (var index = 3; index < 10; index++)
{
myTaskList.Add(Task.Factory.StartNew(() => words[index].AddRange(CalcWords(index))));
}
下面是完整的代码。
主要代码
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
namespace SpellGrid
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
GridSolver Solver { get; } = new GridSolver();
string[,] Letters { get; set; } = null;
public MainWindow()
{
InitializeComponent();
}
private List<string> CalcWords(int wordlen)
{
var newWords = new List<string>();
for (var row = 0; row < 3; row++)
{
for (var col = 0; col < 3; col++)
{
var paths = Solver.CalcPaths(new Tuple<int, int>(row, col), wordlen);
if (MyDictionaries.dictionaries.TryGetValue(wordlen, out List<string> words))
{
foreach (var path in paths)
{
foreach (var word in words)
{
var nomatch = false;
for (var l = 0; nomatch == false && l < wordlen; l++)
{
var r = path[l].Item1;
var c = path[l].Item2;
nomatch = Letters[r, c][0] != word[l];
}
if (nomatch) continue;
if (!newWords.Contains(word))
{
newWords.Add(word);
}
}
}
}
}
}
newWords.Sort();
return newWords;
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
PathList.Items.Clear();
Letters = new string[3, 3]
{
{ G00.Text.ToLower(), G01.Text.ToLower(), G02.Text.ToLower() },
{ G10.Text.ToLower(), G11.Text.ToLower(), G12.Text.ToLower() },
{ G20.Text.ToLower(), G21.Text.ToLower(), G22.Text.ToLower() }
};
foreach (var letter in Letters)
{
if (letter.Length != 1) return;
}
CalculateButton.IsEnabled = false;
Progress.Value = 0;
Progress.Visibility = Visibility.Visible;
var myTaskList = new List<Task>();
const int MaxWordLen = 9;
const int MinWordLen = 3;
List<string>[] words =
{
new List<string>(),
new List<string>(),
new List<string>(),
new List<string>(),
new List<string>(),
new List<string>(),
new List<string>(),
new List<string>(),
new List<string>(),
new List<string>(),
};
myTaskList.Add(Task.Factory.StartNew(() => words[3].AddRange(CalcWords(3))));
myTaskList.Add(Task.Factory.StartNew(() => words[4].AddRange(CalcWords(4))));
myTaskList.Add(Task.Factory.StartNew(() => words[5].AddRange(CalcWords(5))));
myTaskList.Add(Task.Factory.StartNew(() => words[6].AddRange(CalcWords(6))));
myTaskList.Add(Task.Factory.StartNew(() => words[7].AddRange(CalcWords(7))));
myTaskList.Add(Task.Factory.StartNew(() => words[8].AddRange(CalcWords(8))));
myTaskList.Add(Task.Factory.StartNew(() => words[9].AddRange(CalcWords(9))));
var done = false;
while (!done)
{
done = Task.WaitAll(myTaskList.ToArray(), 0);
var count = 0;
foreach (var task in myTaskList)
{
if (task.IsCompleted)
{
count++;
}
}
Progress.Value = count;
await Task.Delay(1);
}
for (var len = MaxWordLen; len >= MinWordLen; len--)
{
if (words[len].Count > 0)
{
var grid = new Grid
{
HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Stretch
};
var r = new Rectangle
{
Fill = Brushes.Yellow,
Stroke = Brushes.Yellow,
HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Stretch
};
Grid.SetRow(r, 0);
Grid.SetColumn(r, 0);
grid.Children.Add(r);
var tb = new TextBlock { Text = len.ToString() + " Letters" };
Grid.SetRow(tb, 0);
Grid.SetColumn(tb, 0);
grid.Children.Add(tb);
PathList.Items.Add(grid);
foreach (var word in words[len])
{
PathList.Items.Add(word);
}
}
}
Progress.Visibility = Visibility.Hidden;
CalculateButton.IsEnabled = true;
}
}
}
这是GridSolver类,用于为给定的点和字长创建所有可能的路径
using System;
using System.Collections.Generic;
namespace SpellGrid
{
public class GridSolver
{
public int GridRowSize { get; set; } = 3;
public int GridColSize { get; set; } = 3;
/// <summary>
/// class to hold data when calculating a path
/// </summary>
private class GridElement
{
public Tuple<int, int> CurPos;
public List<Tuple<int, int>> Path;
}
/// <summary>
/// Process on GridElement
///
/// calculate possible next paths for a given element
/// </summary>
/// <param name="element"></param>
/// <param name="addedElements"></param>
private void ProcessElement(GridElement element, List<GridElement> addedElements, int pathLen)
{
if (PathDictionary.TryGetValue(element.CurPos, out List<Tuple<int, int>> paths))
{
foreach (var newpath in paths)
{
if (element.Path.Count < pathLen && !element.Path.Contains(newpath))
{
var newelement = new GridElement
{
CurPos = newpath,
Path = new List<Tuple<int, int>>(),
};
newelement.Path.AddRange(element.Path);
newelement.Path.Add(newpath);
addedElements.Add(newelement);
}
}
}
}
/// <summary>
/// Process the GridElements
///
/// Put solution paths in FinalList
/// </summary>
private void ProcessGridElements(List<GridElement>gridElements, List<List<Tuple<int, int>>> finalList, int pathLen)
{
while (gridElements.Count > 0)
{
var addedElements = new List<GridElement>();
foreach (var gridElement in gridElements)
{
var len = addedElements.Count;
ProcessElement(gridElement, addedElements, pathLen);
if (gridElement.Path.Count == pathLen)
{
finalList.Add(gridElement.Path);
}
}
gridElements.Clear();
gridElements.AddRange(addedElements);
}
}
/// <summary>
/// Dictionary to hold possible paths for each square
/// </summary>
private Dictionary<Tuple<int, int>, List<Tuple<int, int>>> PathDictionary = new Dictionary<Tuple<int, int>, List<Tuple<int, int>>>();
/// <summary>
/// Initialize the path dictionary
/// </summary>
private void InitPaths()
{
PathDictionary.Clear();
for (var rowstart = 0; rowstart < GridRowSize; rowstart++)
{
for (var colstart = 0; colstart < GridColSize; colstart++)
{
var tuples = new List<Tuple<int, int>>();
for (var r = rowstart - 1; r <= rowstart + 1; r++)
{
if (r < 0 || r >= GridRowSize) continue;
for (var c = colstart - 1; c <= colstart + 1; c++)
{
if (c < 0 || c >= GridColSize || (r == rowstart && c == colstart)) continue;
tuples.Add(new Tuple<int, int>(r, c));
}
}
PathDictionary.Add(new Tuple<int, int>(rowstart, colstart), tuples);
}
}
}
/// <summary>
/// Calculate all possible paths from a given position
/// </summary>
/// <param name="start"></param>
/// <param name="pathLen"></param>
public List<List<Tuple<int, int>>> CalcPaths(Tuple<int, int> start, int pathLen)
{
var path = new List<Tuple<int, int>>(new[] { start });
var elem = new GridElement { CurPos = start, Path = path };
var finalList = new List<List<Tuple<int, int>>>();
ProcessGridElements(new List<GridElement>() { elem }, finalList, pathLen);
return finalList;
}
public GridSolver()
{
InitPaths();
}
}
}