private void Visit(CellState startCellState) { startCellState.Visited = true; count++; startCellState.DfsDepth = count; startCellState.DfsLow = count; foreach (CellState adjacentCellState in startCellState.GetAdjacentCellStates()) { if (adjacentCellState.OccupationStatus != OccupationStatus.YourWall && adjacentCellState.OccupationStatus != OccupationStatus.OpponentWall) { if (!adjacentCellState.Visited) { Edge newEdge = new Edge { StartVertex = startCellState, EndVertex = adjacentCellState }; edgeStack.Push(newEdge); adjacentCellState.ParentCellState = startCellState; Visit(adjacentCellState); if (adjacentCellState.DfsLow >= startCellState.DfsDepth) { // Create a biconnected component BiconnectedComponent component = new BiconnectedComponent(nextComponentNumber); nextComponentNumber++; startCellState.GameState.AddBiconnectedComponent(component); Edge poppedEdge = null; do { poppedEdge = edgeStack.Pop(); component.AddCell(poppedEdge.StartVertex); component.AddCell(poppedEdge.EndVertex); poppedEdge.StartVertex.AddBiconnectedComponent(component); poppedEdge.EndVertex.AddBiconnectedComponent(component); }while (poppedEdge != newEdge); } if (adjacentCellState.DfsLow < startCellState.DfsLow) { startCellState.DfsLow = adjacentCellState.DfsLow; } } else if (!(adjacentCellState.ParentCellState == startCellState) && (adjacentCellState.DfsDepth < startCellState.DfsDepth)) { // The link from startCellState to adjacentCellState is a back edge to an ancestor of startCellState: Edge backEdge = new Edge { StartVertex = startCellState, EndVertex = adjacentCellState }; edgeStack.Push(backEdge); if (adjacentCellState.DfsDepth < startCellState.DfsLow) { startCellState.DfsLow = adjacentCellState.DfsDepth; } } } } }
public override RuleOutcome ReplayAndChooseNextMove(GameState gameStateBeforeStep, GameState currentGameState) { Position to = To; if (GetPosition != null) { to = GetPosition(this, gameStateBeforeStep, currentGameState); } to = GetFlippedTo(to); Dijkstra.Perform(gameStateBeforeStep); CellState destinationState = gameStateBeforeStep[to]; int distanceFromYou = destinationState.DistanceFromYou; List <Position> positionsOnRoute = new List <Position>(); if (destinationState.OccupationStatus == OccupationStatus.Clear && (destinationState.CompartmentStatus == CompartmentStatus.InYourCompartment || destinationState.CompartmentStatus == CompartmentStatus.InSharedCompartment)) { for (int dist = distanceFromYou - 1; dist > 0; dist--) { int d = dist; destinationState = destinationState.GetAdjacentCellStates().Where( cs => cs.OccupationStatus == OccupationStatus.Clear && cs.DistanceFromYou == d).FirstOrDefault(); positionsOnRoute.Insert(0, destinationState.Position); } int nextMoveNumber = gameStateBeforeStep.YourCell.MoveNumber; foreach (Position nextPosition in positionsOnRoute) { nextMoveNumber++; RuleOutcome outcome = MoveToNextPosition(gameStateBeforeStep, currentGameState, nextPosition, nextMoveNumber); if (outcome.Status != RuleStatus.NoFurtherSuggestions) { return(outcome); } } return(new RuleOutcome { Status = RuleStatus.NoFurtherSuggestions }); } else { return(new RuleOutcome { Status = RuleStatus.OpponentBlockedMove }); } }
private static void CheckIfCellIsOnFrontierForPlayer(GameState gameState, CellState cellState, PlayerType playerType) { PlayerType otherPlayerType; OccupationStatus otherPlayerOccupationStatus; int distanceFromPlayer; int distanceFromOtherPlayer; switch (playerType) { case PlayerType.You: otherPlayerType = PlayerType.Opponent; otherPlayerOccupationStatus = OccupationStatus.Opponent; distanceFromPlayer = cellState.DistanceFromYou; distanceFromOtherPlayer = cellState.DistanceFromOpponent; break; default: // Assume PlayerType.Opponent otherPlayerType = PlayerType.You; otherPlayerOccupationStatus = OccupationStatus.You; distanceFromPlayer = cellState.DistanceFromOpponent; distanceFromOtherPlayer = cellState.DistanceFromYou; break; } // It's not on the frontier if it's too far from the other player: if (distanceFromPlayer < distanceFromOtherPlayer - 2) { return; } bool isOnFrontier = false; foreach (CellState adjacentCellState in cellState.GetAdjacentCellStates()) { if (adjacentCellState.ClosestPlayer == otherPlayerType && (adjacentCellState.OccupationStatus == OccupationStatus.Clear || adjacentCellState.OccupationStatus == otherPlayerOccupationStatus)) { isOnFrontier = true; break; } } if (isOnFrontier) { gameState.AddFrontierCellForPlayer(cellState, playerType); } }
private void Visit(CellState startCellState) { startCellState.Visited = true; count++; startCellState.DfsDepth = count; startCellState.DfsLow = count; foreach (CellState adjacentCellState in startCellState.GetAdjacentCellStates()) { if (adjacentCellState.ClosestPlayer == player && (adjacentCellState.OccupationStatus == OccupationStatus.Clear || adjacentCellState.OccupationStatus == playerOccupationStatus)) { if (!adjacentCellState.Visited) { Edge newEdge = new Edge { StartVertex = startCellState, EndVertex = adjacentCellState }; edgeStack.Push(newEdge); adjacentCellState.ParentCellState = startCellState; Visit(adjacentCellState); if (adjacentCellState.DfsLow >= startCellState.DfsDepth) { // Create a chamber Chamber chamber = new Chamber(nextChamberNumber); nextChamberNumber++; startCellState.GameState.AddChamber(chamber, player); Edge poppedEdge = null; do { poppedEdge = edgeStack.Pop(); chamber.AddCell(poppedEdge.StartVertex); chamber.AddCell(poppedEdge.EndVertex); poppedEdge.StartVertex.AddChamber(chamber, player); poppedEdge.EndVertex.AddChamber(chamber, player); }while (poppedEdge != newEdge); } if (adjacentCellState.DfsLow < startCellState.DfsLow) { startCellState.DfsLow = adjacentCellState.DfsLow; } } else if (!(adjacentCellState.ParentCellState == startCellState) && (adjacentCellState.DfsDepth < startCellState.DfsDepth)) { // The link from startCellState to adjacentCellState is a back edge to an ancestor of startCellState: Edge backEdge = new Edge { StartVertex = startCellState, EndVertex = adjacentCellState }; edgeStack.Push(backEdge); if (adjacentCellState.DfsDepth < startCellState.DfsLow) { startCellState.DfsLow = adjacentCellState.DfsDepth; } } } } }
protected override void CalculateDistancesFromAPlayer(GameState gameState, PlayerType player, HashSet <CellState> reachableCells) { int nextDistance = 0; int numberOfCellsReachable = 0; int totalDegreesOfCellsReachable = 0; Queue <CellState> cellsToExpand = new Queue <CellState>(120); // = 4 * 30; to prevent resizing later on DijkstraStatus dijkstraStatus = DijkstraStatus.NotCalculated; bool isPartiallyCalculated = false; int upToDateDijkstraDistance = 0; CellState playersCell; CompartmentStatus compartmentStatus; GetDistanceDelegate getDistance = null; SetDistanceDelegate setDistance = null; switch (player) { case PlayerType.You: compartmentStatus = CompartmentStatus.InYourCompartment; getDistance = GetDistanceFromYou; setDistance = SetDistanceFromYou; dijkstraStatus = gameState.YourDijkstraStatus; upToDateDijkstraDistance = gameState.YourUpToDateDijkstraDistance; playersCell = gameState.YourCell; break; case PlayerType.Opponent: compartmentStatus = CompartmentStatus.InOpponentsCompartment; getDistance = GetDistanceFromOpponent; setDistance = SetDistanceFromOpponent; dijkstraStatus = gameState.OpponentsDijkstraStatus; upToDateDijkstraDistance = gameState.OpponentsUpToDateDijkstraDistance; playersCell = gameState.OpponentsCell; break; default: throw new ApplicationException("The player must be specified when calculating distances"); } if (dijkstraStatus != DijkstraStatus.FullyCalculated) { if (player == PlayerType.You) { gameState.OpponentIsInSameCompartment = false; } isPartiallyCalculated = (dijkstraStatus == DijkstraStatus.PartiallyCalculated && upToDateDijkstraDistance > 0); if (isPartiallyCalculated) { nextDistance = upToDateDijkstraDistance; foreach (CellState cellState in gameState.GetAllCellStates()) { int distance = getDistance(cellState); if ((cellState.OccupationStatus == OccupationStatus.Clear) && (cellState.CompartmentStatus == compartmentStatus || cellState.CompartmentStatus == CompartmentStatus.InSharedCompartment) && (distance <= upToDateDijkstraDistance)) { if (reachableCells != null) { reachableCells.Add(cellState); } numberOfCellsReachable++; totalDegreesOfCellsReachable += cellState.DegreeOfVertex; if (distance == upToDateDijkstraDistance) { cellsToExpand.Enqueue(cellState); } } else { cellState.ClearDijkstraStateForPlayer(player); } } } else { gameState.ClearDijkstraPropertiesForPlayer(player); cellsToExpand.Enqueue(playersCell); } while (cellsToExpand.Count > 0) { CellState sourceCell = cellsToExpand.Dequeue(); nextDistance = getDistance(sourceCell) + 1; CellState[] adjacentCells = sourceCell.GetAdjacentCellStates(); foreach (CellState adjacentCell in adjacentCells) { switch (adjacentCell.OccupationStatus) { case OccupationStatus.Opponent: if (player == PlayerType.You) { gameState.OpponentIsInSameCompartment = true; } break; case OccupationStatus.Clear: adjacentCell.CompartmentStatus |= compartmentStatus; int existingDistance = getDistance(adjacentCell); if (nextDistance < existingDistance) { setDistance(adjacentCell, nextDistance); // HashSets automatically filter out duplicates, so no need to check: cellsToExpand.Enqueue(adjacentCell); if (reachableCells != null) { reachableCells.Add(adjacentCell); } } break; } } numberOfCellsReachable++; totalDegreesOfCellsReachable += sourceCell.DegreeOfVertex; } switch (player) { case PlayerType.You: gameState.NumberOfCellsReachableByYou = numberOfCellsReachable; gameState.TotalDegreesOfCellsReachableByYou = totalDegreesOfCellsReachable; break; case PlayerType.Opponent: gameState.NumberOfCellsReachableByOpponent = numberOfCellsReachable; gameState.TotalDegreesOfCellsReachableByOpponent = totalDegreesOfCellsReachable; break; } switch (player) { case PlayerType.You: gameState.YourDijkstraStatus = DijkstraStatus.FullyCalculated; gameState.YourUpToDateDijkstraDistance = int.MaxValue; break; case PlayerType.Opponent: gameState.OpponentsDijkstraStatus = DijkstraStatus.FullyCalculated; gameState.OpponentsUpToDateDijkstraDistance = int.MaxValue; break; } } else { // Fix ClosestPlayer: foreach (CellState cellState in gameState.GetAllCellStates()) { if (cellState.ClosestPlayer == PlayerType.Unknown) { switch (cellState.CompartmentStatus) { case CompartmentStatus.InYourCompartment: cellState.ClosestPlayer = PlayerType.You; break; case CompartmentStatus.InOpponentsCompartment: cellState.ClosestPlayer = PlayerType.Opponent; break; case CompartmentStatus.InSharedCompartment: if (cellState.DistanceFromYou > cellState.DistanceFromOpponent) { cellState.ClosestPlayer = PlayerType.You; } else if (cellState.DistanceFromOpponent > cellState.DistanceFromYou) { cellState.ClosestPlayer = PlayerType.Opponent; } else { cellState.ClosestPlayer = gameState.PlayerToMoveNext; } break; } } } gameState.YourCell.ClosestPlayer = PlayerType.You; gameState.OpponentsCell.ClosestPlayer = PlayerType.Opponent; } }