public SjmGame(Action onCatMove) { BoardData = new bool[BoardSize, BoardSize]; int blocks = rand.Next(BoardSize * BoardSize / 5, BoardSize * BoardSize / 4); for (int i = 0; i < blocks; i++) { int r = rand.Next(0, BoardSize); int c = rand.Next(0, BoardSize); bool skip = false; for (int j = 0; j < CatsCount; j++) { if (r == BoardSize / 2 && c == BoardSize / 2 - CatsCount / 2 + j) skip = true; } if (skip) continue; if (!BoardData[r, c]) BoardData[r, c] = true; } Cats = new Cat[CatsCount]; for (int i = 0; i < CatsCount; i++) { Cats[i] = new Cat() { ColumnIndex = BoardSize / 2 - CatsCount / 2 + i, RowIndex = BoardSize / 2 , EscapeAtRow = -1, EscapeAtColumn = -1, EscapePath = new HashSet<Tuple<int,int>>() }; } Steps = 0; OnCatMove = onCatMove; }
private void ProcessAdjNode(int r, int c, Queue<Tuple<int, int>> queue, int newDistance, Tuple<int, int> pos, Cat cat, List<Tuple<int, int>> nextPos) { if (r >= 0 && c >= 0 && r < BoardSize && c < BoardSize && !BoardData[r, c] && !visited[r, c] && Cats.Count(cc => cc.RowIndex == r && cc.ColumnIndex == c) == 0) { var p = new Tuple<int, int>(r, c); queue.Enqueue(p); visited[r, c] = true; distance[r, c] = newDistance; prev[r, c] = pos; if (pos.Item1 == cat.RowIndex && pos.Item2 == cat.ColumnIndex) nextPos.Add(p); } }
private int FindMinimalEscapeDistance(Cat cat) { int r = cat.RowIndex; int c = cat.ColumnIndex; if (Escaped(r, c)) return 1; var queue = new Queue<Tuple<int, int>>(); queue.Enqueue(new Tuple<int, int>(r, c)); visited = new bool[BoardSize, BoardSize]; distance = new int[BoardSize, BoardSize]; for (int i = 0; i < BoardSize; i++) { for (int j = 0; j < BoardSize; j++) { distance[i, j] = int.MaxValue; } } prev = new Tuple<int,int>[BoardSize,BoardSize]; distance[r, c] = 0; prev[r, c] = null; visited[r, c] = true; int ret = int.MaxValue; cat.EscapeAtRow = -1; cat.EscapeAtColumn = -1; var nextPos = new List<Tuple<int, int>>(); while (queue.Count() != 0) { var pos = queue.Dequeue(); r = pos.Item1; c = pos.Item2; if (Escaped(r, c) && ret > distance[r, c]) { ret = distance[r, c]; cat.EscapeAtRow = r; cat.EscapeAtColumn = c; } int newDistance = distance[r, c] + 1; bool isOdd = (r & 1) == 1; int c2 = c + (isOdd ? 1 : -1); ProcessAdjNode(r - 1, c, queue, newDistance, pos, cat, nextPos); ProcessAdjNode(r - 1, c2, queue, newDistance, pos, cat, nextPos); ProcessAdjNode(r, c + 1, queue, newDistance, pos, cat, nextPos); ProcessAdjNode(r + 1, c, queue, newDistance, pos, cat, nextPos); ProcessAdjNode(r + 1, c2, queue, newDistance, pos, cat, nextPos); ProcessAdjNode(r, c - 1, queue, newDistance, pos, cat, nextPos); } if (ret == int.MaxValue) { cat.EscapePath.Clear(); if (nextPos.Count != 0) { int idx = rand.Next(0, nextPos.Count - 1); cat.RowIndex = nextPos[idx].Item1; cat.ColumnIndex = nextPos[idx].Item2; } else { return -1; } } else { cat.EscapePath.Clear(); int u = cat.EscapeAtRow; int v = cat.EscapeAtColumn; var next = new Tuple<int, int>(u, v); cat.EscapePath.Add(next); var back = prev[u, v]; back = prev[back.Item1, back.Item2]; while (back != null) { back = prev[back.Item1, back.Item2]; next = prev[next.Item1, next.Item2]; cat.EscapePath.Add(next); } cat.RowIndex = next.Item1; cat.ColumnIndex = next.Item2; } return ret; }