public IEnumerable<BfsState> DoBfs(UnitState startState, PowerPhraseInfo[] powerPhrases) { var queue = new Queue<BfsState>(); Debug.Assert(startState.GetCells(_unit).All(_field.IsValidCell)); _visited[startState] = new VisitInfo { MoveFuncIndex = -1, PrevState = null, AllPrevStates = new HashSet<UnitState>(), }; var startBfsState = new BfsState(startState, startState.GetCells(_unit)); //BfsState stateAfterPhrase = startBfsState; //if (powerPhrases != null) //{ // foreach (var phraseInfo in powerPhrases) // { // stateAfterPhrase = ApplyPhraseManyTimes(startBfsState, phraseInfo); // if (stateAfterPhrase.UnitState.Pivot != startState.Pivot || stateAfterPhrase.UnitState.Rotation != startState.Rotation) // break; // } //} var stateAfterPhrase = ApplyManyPhrasesManyTimes(startBfsState); queue.Enqueue(stateAfterPhrase); while (queue.Count > 0) { var state = queue.Dequeue(); int blockingMove = -1; for (int funcIndex = 0; funcIndex < UnitState.MoveFuncs.Length; ++funcIndex) { UnitState newUnitState = UnitState.MoveFuncs[funcIndex](state.UnitState); Cell[] cells; bool isBlocking; if (!TryAddVisitedState(newUnitState, state.UnitState, funcIndex, out cells, out isBlocking)) { if (isBlocking) blockingMove = funcIndex; continue; } queue.Enqueue(new BfsState(newUnitState, cells)); } if (blockingMove >= 0) { state.BlockingMove = blockingMove; yield return state; } } }
public void GetCells() { var u = new Unit(new[] {new Cell(0, 0), new Cell(1, 0), new Cell(1, 1)}, new Cell(0, 0)); var us = new UnitState(new Cell(2, 2), 0); var cells = us.GetCells(u); Assert.IsTrue(cells.Contains(new Cell(2, 2))); Assert.IsTrue(cells.Contains(new Cell(3, 2))); Assert.IsTrue(cells.Contains(new Cell(3, 3))); us = new UnitState(new Cell(2, 2), 1); cells = us.GetCells(u); Assert.IsTrue(cells.Contains(new Cell(2, 2))); Assert.IsTrue(cells.Contains(new Cell(2, 1))); Assert.IsTrue(cells.Contains(new Cell(3, 1))); us = new UnitState(new Cell(2, 3), 0); cells = us.GetCells(u); Assert.IsTrue(cells.Contains(new Cell(2, 3))); Assert.IsTrue(cells.Contains(new Cell(3, 3))); Assert.IsTrue(cells.Contains(new Cell(4, 4))); u = new Unit(new[] { new Cell(0, 1), new Cell(1, 1), new Cell(2, 2) }, new Cell(0, 1)); us = new UnitState(new Cell(2, 2), 0); cells = us.GetCells(u); Assert.IsTrue(cells.Contains(new Cell(2, 2))); Assert.IsTrue(cells.Contains(new Cell(3, 2))); Assert.IsTrue(cells.Contains(new Cell(3, 3))); }
public IEnumerable<BfsState> DoSimpleBfs(UnitState startState, bool backwards, bool returnStateCopies) { var queue = new Queue<UnitState>(); Debug.Assert(startState.GetCells(_unit).All(_field.IsValidCell)); _visited[startState] = new VisitInfo { MoveFuncIndex = -1, PrevState = null, AllPrevStates = new HashSet<UnitState>(), }; queue.Enqueue(startState); var moveFuncs = backwards ? UnitState.BackMoveFuncs : UnitState.MoveFuncs; BfsState returnState = new BfsState(null, null); while (queue.Count > 0) { var state = queue.Dequeue(); int blockingMove = -1; for (int funcIndex = 0; funcIndex < moveFuncs.Length; ++funcIndex) { UnitState newUnitState = moveFuncs[funcIndex](state); newUnitState.Normalize(_unit); Cell[] cells; bool isBlocking; if (!TryAddVisitedState(newUnitState, state, funcIndex, out cells, out isBlocking)) { if (isBlocking) blockingMove = funcIndex; continue; } queue.Enqueue(newUnitState); } if (blockingMove >= 0 || backwards) { if (returnStateCopies) { var retState = new BfsState(state, state.GetCells(_unit)); retState.BlockingMove = blockingMove; yield return retState; } else { returnState.UnitState = state; yield return returnState; } } } }
public void MoveE() { var unit = new Unit(new[] { new Cell(10, 0), new Cell(11, 1) }, new Cell(12, 2)); var unitState = new UnitState(unit.pivot, 0); unitState = UnitState.MoveE(unitState); var cells = unitState.GetCells(unit); Assert.IsTrue(cells.Contains(new Cell(11, 0))); Assert.IsTrue(cells.Contains(new Cell(12, 1))); Assert.AreEqual(new Cell(13, 2), unitState.Pivot); }
public void MoveSW() { var unit = new Unit(new[] { new Cell(10, 4), new Cell(11, 5) }, new Cell(12, 6)); var unitState = new UnitState(unit.pivot, 0); unitState = UnitState.MoveSW(unitState); var cells = unitState.GetCells(unit); Assert.AreEqual(2, cells.Length); Assert.IsTrue(cells.Contains(new Cell(9, 5))); Assert.IsTrue(cells.Contains(new Cell(11, 6))); Assert.AreEqual(new Cell(11, 7), unitState.Pivot); }
public void TurnClockwise() { var unit = new Unit(new[] { new Cell(3, 0) }, new Cell(2, 3)); var unitState = new UnitState(unit.pivot, 0); unitState = UnitState.TurnClockwise(unitState); Assert.AreEqual(new Cell(2, 3), unitState.Pivot); Assert.AreEqual(new Cell(5, 2), unitState.GetCells(unit)[0]); unitState = UnitState.TurnClockwise(unitState); Assert.AreEqual(new Cell(4, 5), unitState.GetCells(unit)[0]); unitState = UnitState.TurnClockwise(unitState); Assert.AreEqual(new Cell(2, 6), unitState.GetCells(unit)[0]); unitState = UnitState.TurnClockwise(unitState); Assert.AreEqual(new Cell(0, 4), unitState.GetCells(unit)[0]); unitState = UnitState.TurnClockwise(unitState); Assert.AreEqual(new Cell(0, 1), unitState.GetCells(unit)[0]); unit = new Unit(new[] { new Cell(0, 2), new Cell(4, 2) }, new Cell(2, 2)); unitState = new UnitState(unit.pivot, 0); unitState = UnitState.TurnClockwise(unitState); var cells = unitState.GetCells(unit); Assert.AreEqual(2, cells.Length); Assert.IsTrue(cells.Contains(new Cell(1, 0))); Assert.IsTrue(cells.Contains(new Cell(3, 4))); unitState = UnitState.TurnClockwise(unitState); cells = unitState.GetCells(unit); Assert.IsTrue(cells.Contains(new Cell(3, 0))); Assert.IsTrue(cells.Contains(new Cell(1, 4))); }
public void MoveW() { var unit = new Unit(new[] { new Cell(10, 0), new Cell(11, 0) }, new Cell(12, 0)); var unitState = new UnitState(unit.pivot, 0); unitState = UnitState.MoveW(unitState); var cells = unitState.GetCells(unit); Assert.IsTrue(cells.Contains(new Cell(9, 0))); Assert.IsTrue(cells.Contains(new Cell(10, 0))); }
public void TurnCounter() { var unit = new Unit(new[] { new Cell(3, 0) }, new Cell(2, 3)); var unitState = new UnitState(unit.pivot, 0); unitState = UnitState.TurnCounter(unitState); var cells = unitState.GetCells(unit); Assert.AreEqual(3, unitState.Pivot.y); Assert.AreEqual(2, unitState.Pivot.x); Assert.AreEqual(1, cells[0].y); Assert.AreEqual(0, cells[0].x); unitState = UnitState.TurnCounter(unitState); Assert.AreEqual(new Cell(0, 4), unitState.GetCells(unit)[0]); unitState = UnitState.TurnCounter(unitState); Assert.AreEqual(new Cell(2, 6), unitState.GetCells(unit)[0]); unitState = UnitState.TurnCounter(unitState); Assert.AreEqual(new Cell(4, 5), unitState.GetCells(unit)[0]); unitState = UnitState.TurnCounter(unitState); Assert.AreEqual(new Cell(5, 2), unitState.GetCells(unit)[0]); unit = new Unit(new[] { new Cell(0, 2), new Cell(4, 2) }, new Cell(2, 2)); unitState = new UnitState(unit.pivot, 0); unitState = UnitState.TurnCounter(unitState); cells = unitState.GetCells(unit); Assert.IsTrue(cells.Contains(new Cell(1, 4))); Assert.IsTrue(cells.Contains(new Cell(3, 0))); unitState = UnitState.TurnCounter(unitState); cells = unitState.GetCells(unit); Assert.IsTrue(cells.Contains(new Cell(3, 4))); Assert.IsTrue(cells.Contains(new Cell(1, 0))); }
private bool TryAddVisitedState(UnitState newState, UnitState state, int funcIndex, out Cell[] cells, out bool isBlockingMove, char moveChar = ANY_CHAR) { cells = null; isBlockingMove = false; if (_visited.ContainsKey(newState)) return false; cells = newState.GetCells(_unit); if (!cells.All(_field.IsValidCell)) { isBlockingMove = true; return false; } //if (_IsDuplicateState(state, newState)) // return false; var vi = new VisitInfo { MoveFuncIndex = funcIndex, PrevState = state, MoveChar = moveChar, //AllPrevStates = _visited[state].AllPrevStates // AllPrevStates = new HashSet<UnitState>(_visited[state].AllPrevStates) }; // vi.AllPrevStates.Add(new UnitState(state.Pivot, _unit.GetCanonicalRotation(state.Rotation))); _visited[newState] = vi; return true; }
public void Update(Unit unit, UnitState state) { Update(state.GetCells(unit)); }
public UnitState SpawnUnit(Unit unit) { int ymin = unit.members[0].y; foreach (var cell in unit.members) if (cell.y < ymin) ymin = cell.y; var us = new UnitState(new Cell(unit.pivot.x, unit.pivot.y - ymin), 0); var cells = us.GetCells(unit); int xmin = cells[0].x, xmax = cells[0].x; foreach (var cell in cells) { if (cell.x < xmin) xmin = cell.x; if (cell.x > xmax) xmax = cell.x; } int x0 = (Width - 1 - (xmax - xmin)) / 2; us = new UnitState(new Cell(us.Pivot.x - xmin + x0, us.Pivot.y), 0); foreach (var cell in us.GetCells(unit)) if (!IsValidCell(cell)) return null; us.Normalize(unit); return us; }
public void SimulateUnit(Unit unit, UnitState startState, string movesStr, bool debugWrite = false) { var visited = new List<VisitedInfo>(); Cell[] prevCells = null; Cell[] curCells = startState.GetCells(unit); Cell curPivot = startState.Pivot; visited.Add(new VisitedInfo(curPivot, curCells)); if (!curCells.All(_field.IsValidCell)) { throw new Exception("Start state is invalid"); } var moveCommands = MovesPrinter.GetCommands(movesStr); for (int moveIdx = 0; moveIdx < moveCommands.Length; ++moveIdx) { prevCells = curCells; int move = moveCommands[moveIdx]; switch (move) { case 0: curPivot = Moves.MoveW(curPivot); curCells = curCells.Select(Moves.MoveW).ToArray(); break; case 1: curPivot = Moves.MoveE(curPivot); curCells = curCells.Select(Moves.MoveE).ToArray(); break; case 2: curPivot = Moves.MoveSW(curPivot); curCells = curCells.Select(Moves.MoveSW).ToArray(); break; case 3: curPivot = Moves.MoveSE(curPivot); curCells = curCells.Select(Moves.MoveSE).ToArray(); break; case 4: curCells = curCells.Select(c => Moves.TurnClockwise(c, curPivot)).ToArray(); break; case 5: curCells = curCells.Select(c => Moves.TurnCounter(c, curPivot)).ToArray(); break; } bool isLast = moveIdx == moveCommands.Length - 1; if (!curCells.All(_field.IsValidCell)) { if (!isLast) { throw new Exception(string.Format("move number {0} is not the last but leads to invalid cells", moveIdx)); } } else { if (isLast) { throw new Exception(string.Format("Last move number {0} doesn't lock the unit", moveIdx)); } Array.Sort(curCells); if (debugWrite) { DebugPrinter.Write("After move #{0} {1} ({2}) pivot: ({3}, {4}), cells: ", moveIdx, move, movesStr[moveIdx], curPivot.x, curPivot.y); foreach (Cell c in curCells) DebugPrinter.Write("({0}, {1}), ", c.x, c.y); DebugPrinter.WriteLine(""); } bool duplicate = false; int visIdx = 0; for (; visIdx < visited.Count; ++visIdx) { var vi = visited[visIdx]; bool equal = true; if (vi.Pivot != curPivot) { equal = false; continue; } for (int i = 0; i < vi.Members.Length; ++i) { if (vi.Members[i] != curCells[i]) { equal = false; break; } } if (equal) { duplicate = true; break; } } if (duplicate) { if (!debugWrite) SimulateUnit(unit, startState, movesStr, true); else throw new Exception(string.Format("move number {0} introduces a duplicate with move {1}", moveIdx, visIdx)); } visited.Add(new VisitedInfo(curPivot, curCells)); } } _field.Update(prevCells); }
public static string PrettyPrintBeforeUpdate(Field field, Unit unit, UnitState state, Dictionary<Cell, char> pathCells = null) { string res = ""; var cells = state.GetCells(unit); for (int y = 0; y < field.Height; ++y) { if (y % 2 == 1) res += " "; for (int x = 0; x < field.Width; ++x) { Cell c = new Cell(x, y); if (pathCells != null && pathCells.ContainsKey(c)) res += pathCells[c] + " "; else if (field[y][x]) res += "* "; else if (cells.Contains(c)) res += "@ "; else res += ". "; } res += "|\n"; } return res; }