public static MoveResolver Deny() { var block = new MoveResolver(null); block.Resolved = false; return(block); }
private void SetRoot(MoveResolver root) { if (root == _root) { throw new Exception("I think this implies an unresolved cycle"); } _root = root; foreach (var dependent in _dependents) { dependent.SetRoot(root); } }
public BattleController() { _playerBattleSquads = new Dictionary <int, BattleSquad>(); _opposingBattleSquads = new Dictionary <int, BattleSquad>();; _soldierBattleSquadMap = new Dictionary <int, BattleSquad>(); _moveResolver = new MoveResolver(); _moveResolver.OnRetreat.AddListener(MoveResolver_OnRetreat); _woundResolver = new WoundResolver(VERBOSE); _woundResolver.OnSoldierDeath.AddListener(WoundResolver_OnSoldierDeath); _woundResolver.OnSoldierFall.AddListener(WoundResolver_OnSoldierFall); _casualtyMap = new Dictionary <int, BattleSoldier>(); _startingPlayerBattleSoldiers = new List <BattleSoldier>(); }
public void SetParent(MoveResolver parent) { if (this._root != this) { throw new Exception("Assigned multiple dependencies"); } if (parent.Resolved.HasValue) // already been decided: propogate result { Resolve(parent.Resolved.Value); } else if (parent._root == this) // cyclic, unresolved dependencies: resolve true { Utils.Printf("Resolved cycle starting at move: {0}", Move); Resolve(true); } else // wait until a decision is made later { SetRoot(parent._root); parent._root._dependents.Add(this); // add to root to shorten call stack } }
/// <summary> /// Simulate the game for a single turn. /// </summary> public void DoTurn() { var activeUnits = new Dictionary <Unit, TurnPlan>(); foreach (var unit in _units) { unit.Reset(); activeUnits.Add(unit, unit.GetMovementPlan(_world)); } #if DEBUG DebugLogFrame(); #endif while (activeUnits.Count > 0) // main loop: iterate through each simulation frame { // STEP 1: COMBAT DETERMINATION var pendingCombat = new HashSet <Combat>(); // stops duplication of the same combat var unitsInCombat = new HashSet <Unit>(); foreach (var unit in activeUnits.Keys) { foreach (var adj in unit.Position.Adjacent().Select(pos => _world[pos])) // for each adjacent Hex { if (adj == null) { continue; } var neighbour = adj.Occupant; if (neighbour != null && neighbour.Owner != unit.Owner) { pendingCombat.Add(new Combat(unit, neighbour)); unitsInCombat.Add(unit); unitsInCombat.Add(neighbour); } } } // STEP 2: COMBAT RESOLUTION var pendingCombatSorted = new List <Combat>(pendingCombat); pendingCombatSorted.Sort(Combat.PriorityComparer); // sort by priortiy foreach (var combat in pendingCombatSorted) { var unit1 = combat.Unit1; var unit2 = combat.Unit2; if (!unit1.IsDead() && !unit2.IsDead()) { combat.Apply(); FinaliseCombat(unit1, unit2, activeUnits); // lambda/local-function would be FinaliseCombat(unit2, unit1, activeUnits); // ideal here! outdated version of C# } } // STEP 3: MOVE PRE-PROCESSING var moveDestinations = new Dictionary <TileVector, List <MoveResolver> >(); // where units want to move to var moveOrigins = new Dictionary <TileVector, MoveResolver>(); // where units are moving from foreach (var unit in _units) // collect all units' moves into the Dictionaries, using plans { TurnPlan plan = null; if (activeUnits.ContainsKey(unit)) // only active units can make moves - bind a plan { plan = activeUnits[unit]; if (!plan.IsActive()) // unit can no longer make moves, so remove from active units { activeUnits.Remove(unit); plan = null; // unbind plan for this frame } } var canMove = plan != null && !unitsInCombat.Contains(plan.Unit); var move = canMove? plan.GetNextMove() : null; var mayVacate = canMove && move.IsStep(); // if move is a step, moves here are conditional upon it. otherwise, deny outright var resolver = mayVacate ? MoveResolver.Of(move) : MoveResolver.Deny(); moveOrigins.Add(unit.Position, resolver); if (mayVacate) // add resolver to the move's intended destination for processing later { var hex = _world[move.Destination]; if (hex != null && !hex.Impassable) // if target is valid { List <MoveResolver> movesToDestination; if (moveDestinations.ContainsKey(move.Destination)) { movesToDestination = moveDestinations[move.Destination]; } else // initialise the list if it doesn't exist yet { movesToDestination = new List <MoveResolver>(6); moveDestinations.Add(move.Destination, movesToDestination); } movesToDestination.Add(resolver); } else { resolver.Resolve(false); // reject if move is illegal } } } // STEP 4: MOVE CONFLICT RESOLUTION foreach (var entry in moveDestinations) // check all future mech positions, finalise moves { var destination = entry.Key; var moves = entry.Value; var best = 0; for (var i = 1; i < moves.Count; i++) // reject all moves here except the best one { if (Move.PriorityComparer.Compare(moves[i].Move, moves[best].Move) > 0) { moves[best].Resolve(false); best = i; } else // not the best move: reject { moves[i].Resolve(false); } } var dependency = moveOrigins.ContainsKey(destination) ? moveOrigins[destination] : null; if (dependency != null) { moves[best].SetParent(dependency); } else { moves[best].Resolve(true); } } #if DEBUG DebugLogFrame(); #endif } RoundNumber++; }
private MoveResolver(Move move) { _root = this; Move = move; }