// Damage Calculation to be implemented // This is the retaliation damage done to other enemies List <AttackLog> ApplyAndRecordDamage(Piece piece, ICollection <MoveData> attackerMoveDatas) { int baseDamage = piece.attack; List <AttackLog> attackLogs = new List <AttackLog>(); foreach (MoveData attackerMoveData in attackerMoveDatas) { double damage = baseDamage; // apply enemy specific multipliers here // damage dampening if outnumbered switch (attackerMoveDatas.Count) { case 2: // 40% on 2 enemies damage *= 0.4; break; case 3: // 20% on 3 enemies damage *= 0.2; break; case 4: // 5% on 4 enemies damage *= 0.05; break; } if (piece.IsCounteredBy(attackerMoveData.piece)) { damage *= 1.2; } damage *= piece.health / (double)piece.maxHealth; Piece attacker = attackerMoveData.piece; attacker.health -= (damage < 1) ? 1 : (int)damage; // at least deal 1 dmg Move.Direction directionOfRetaliation = Move.OppositeDirection(attackerMoveData.direction); AttackLog attackLog = new AttackLog((int)damage, directionOfRetaliation); attackLogs.Add(attackLog); } return(attackLogs); }
public bool IsColliding(IReadOnlyDictionary <TimedMove, int> timedMovesToAgentID) { if (timedMovesToAgentID == null) { return(false); } Move.Direction saveDirection = this.direction; this.direction = Move.Direction.NO_DIRECTION; if (timedMovesToAgentID.ContainsKey(this)) { this.direction = saveDirection; return(true); } this.direction = saveDirection; if (Constants.ALLOW_HEAD_ON_COLLISION == false) { this.setOppositeMove(); if (timedMovesToAgentID.ContainsKey(this)) // Check direction too now { this.setOppositeMove(); return(true); } this.setOppositeMove(); } return(false); }
public MoveData(Move move, Square currentSquare, Square nextSquare) { this.direction = move.direction; this.piece = move.piece; this.currentSquare = currentSquare; this.nextSquare = nextSquare; }
public bool IsColliding(ICollection <TimedMove> CAT) { // Sadly, since there's currently no System.Collections.Generic.IReadOnlySet, Move.IsColliding accepts an ISet<Move>, // so the compiler doesn't let us just call base.IsColliding(CAT) because base might put a Move that isn't a TimedMove in CAT, if (CAT == null) { return(false); } Move.Direction saveDirection = this.direction; this.direction = Move.Direction.NO_DIRECTION; if (CAT.Contains(this)) { this.direction = saveDirection; return(true); } this.direction = saveDirection; this.setOppositeMove(); if (CAT.Contains(this)) // Check direction too now { this.setOppositeMove(); return(true); } this.setOppositeMove(); return(false); }
private void Update() { if (moveCtrl == null) { return; } sprite.sortingOrder = 10 + LevelData.instance.Height - moveCtrl.curCoord.y; var currentDir = moveCtrl.Dir; var currentIsMoving = moveCtrl.Dir != Move.Direction.Stay; if (!currentIsMoving) { currentDir = lastDir; } if (currentIsMoving != lastIsMoving || lastDir != currentDir) { PlayState(MoveDir2AnimDir(currentDir), currentIsMoving); } lastDir = currentDir; lastIsMoving = currentIsMoving; }
public Square NextSquare(Move move) { Square currentSquare = GetCurrentSquare(move.piece); Move.Direction direction = move.direction; return(NextSquare(currentSquare, direction)); }
/// <summary> /// Gets a dictionary mapping TimedMoves to the agents that already made them /// and returns a list of agents this TimedMove collides with. /// </summary> /// <param name="timedMovesToAgentNumLists"></param> /// <returns></returns> public IReadOnlyList <int> GetColliding(ConflictAvoidanceTable timedMovesToAgentNumLists) { List <int> ans = null; Move.Direction saveDirection = this.direction; Direction[] directions; if (Constants.ALLOW_DIAGONAL_MOVE) { directions = Move.validDirections; } else { directions = Move.validDirectionsNoDiag; } foreach (var direction in directions) // TEMP FIX! Need to get rid of the whole NO_DIRECTION SHTICK! It breaks transitivity! { this.direction = direction; if (timedMovesToAgentNumLists.ContainsKey(this)) { if (ans == null) { ans = new List <int>(timedMovesToAgentNumLists[this]); } else { ans.AddRange(timedMovesToAgentNumLists[this]); } } } this.direction = saveDirection; if (Constants.ALLOW_HEAD_ON_COLLISION == false) { this.setOppositeMove(); if (timedMovesToAgentNumLists.ContainsKey(this)) // Check direction too now { if (ans == null) { ans = new List <int>(timedMovesToAgentNumLists[this]); } else { ans.AddRange(timedMovesToAgentNumLists[this]); } } this.setOppositeMove(); } if (ans != null) { return(ans); } else { return(TimedMove.emptyList); } }
public MMStarConstraint(int agentNum, int posX, int posY, Move.Direction direction, int timeStep) { this.move = new TimedMove(posX, posY, direction, timeStep); this.agentNum = agentNum; if (direction == Move.Direction.NO_DIRECTION) { this.vertexConflict = true; } else { this.vertexConflict = false; } }
/// <summary> /// Gets a dictionary mapping TimedMoves to the agent that already made them /// and returns a list of agents this TimedMove collides with. /// </summary> /// <param name="timedMovesToAgentIndex"></param> /// <returns></returns> public List <int> GetColliding(IReadOnlyDictionary <TimedMove, int> timedMovesToAgentIndex) { List <int> ans = null; Move.Direction saveDirection = this.direction; Direction[] directions; if (Constants.ALLOW_DIAGONAL_MOVE) { directions = Move.validDirections; } else { directions = Move.validDirectionsNoDiag; } foreach (var direction in directions) // TEMP FIX! Need to get rid of the whole NO_DIRECTION SHTICK! It breaks transitivity! { this.direction = direction; if (timedMovesToAgentIndex.ContainsKey(this)) { if (ans == null) { ans = new List <int>(4); } ans.Add(timedMovesToAgentIndex[this]); } } this.direction = saveDirection; this.setOppositeMove(); if (timedMovesToAgentIndex.ContainsKey(this)) // Check direction too now { if (ans == null) { ans = new List <int>(1); } ans.Add(timedMovesToAgentIndex[this]); } this.setOppositeMove(); if (ans != null) { return(ans); } else { return(TimedMove.emptyList); } }
PhaseLog[] ResolveCombat(MoveData[] moveDatas) { PhaseLog[] phaseLogs = new PhaseLog[moveDatas.Length]; for (int i = 0; i < moveDatas.Length; i++) { MoveData moveData = moveDatas[i]; Piece piece = moveData.piece; Move.Direction direction = moveData.direction; // where the piece is during combat Square combatSquare = moveData.isBounce ? moveData.nextSquare : moveData.currentSquare; // check for attackers List <MoveData> attackedBy = new List <MoveData>(); foreach (MoveData otherMoveData in moveDatas) { Piece otherPiece = otherMoveData.piece; if (piece == otherPiece) { continue; } if (otherMoveData.direction == Move.Direction.NONE) { continue; } if (piece.owner == otherPiece.owner) { continue; } Square attackingSquare = otherMoveData.nextSquare; if (combatSquare == attackingSquare) { attackedBy.Add(otherMoveData); } } // Create Phase Log Here List <AttackLog> attackLogs = ApplyAndRecordDamage(piece, attackedBy); Square finalSquare = moveData.isBounce ? moveData.currentSquare : combatSquare; MoveLog moveLog = new MoveLog(combatSquare, finalSquare); PhaseLog phaseLog = new PhaseLog(piece, moveLog, attackLogs.ToArray()); phaseLogs[i] = phaseLog; } return(phaseLogs); }
private AnimationDir MoveDir2AnimDir(Move.Direction dir) { switch (dir) { case Move.Direction.Left: return(AnimationDir.Left); case Move.Direction.Right: return(AnimationDir.Right); case Move.Direction.Up: return(AnimationDir.Up); case Move.Direction.Down: return(AnimationDir.Down); default: return(AnimationDir.Down); } }
public Square NextSquare(Square currentSquare, Move.Direction direction) { int row, col; switch (direction) { case Move.Direction.UP: row = currentSquare.row > 0 ? currentSquare.row - 1 : 0; return new Square(row, currentSquare.col); case Move.Direction.DOWN: row = currentSquare.row < numRows - 1 ? currentSquare.row + 1 : numRows - 1; return new Square(row, currentSquare.col); case Move.Direction.LEFT: col = currentSquare.col > 0 ? currentSquare.col - 1 : 0; return new Square(currentSquare.row, col); case Move.Direction.RIGHT: col = currentSquare.col < numCols - 1 ? currentSquare.col + 1 : numCols - 1; return new Square(currentSquare.row, col); } return currentSquare; }
public bool IsColliding(ICollection <TimedMove> moves) { Move.Direction saveDirection = this.direction; this.direction = Move.Direction.NO_DIRECTION; if (moves.Contains(this)) { this.direction = saveDirection; return(true); } this.direction = saveDirection; this.setOppositeMove(); if (moves.Contains(this)) // Check direction too now { this.setOppositeMove(); return(true); } this.setOppositeMove(); return(false); }
public List <int> GetColliding(IReadOnlyDictionary <TimedMove, List <int> > CAT) { var ans = new List <int>(); // TODO: This method usually just returns an empty list. Have a static empty list ready and return it when necessary. Move.Direction saveDirection = this.direction; this.direction = Move.Direction.NO_DIRECTION; if (CAT.ContainsKey(this)) { ans.AddRange(CAT[this]); } this.direction = saveDirection; this.setOppositeMove(); if (CAT.ContainsKey(this)) // Check direction too now { ans.AddRange(CAT[this]); } this.setOppositeMove(); return(ans); }
public bool IsColliding(IReadOnlyDictionary <TimedMove, int> timedMovesToAgentID) { Move.Direction saveDirection = this.direction; this.direction = Move.Direction.NO_DIRECTION; if (timedMovesToAgentID.ContainsKey(this)) { this.direction = saveDirection; return(true); } this.direction = saveDirection; this.setOppositeMove(); if (timedMovesToAgentID.ContainsKey(this)) // Check direction too now { this.setOppositeMove(); return(true); } this.setOppositeMove(); return(false); }
/// <summary> /// Counts the number of times this node collides with each agent move in the conflict avoidance table. /// </summary> /// <param name="conflictAvoidance"></param> /// <returns></returns> public virtual void UpdateConflictCounts(IReadOnlyDictionary <TimedMove, List <int> > conflictAvoidance, int conflictRange = 0) { int countMoves = -1; if (conflictRange == -1) //p-robust { countMoves = 0; WorldState currentCbsNode = this; while (currentCbsNode != null) { Move.Direction currentDirection = currentCbsNode.allAgentsState[0].lastMove.direction; if (currentDirection != Move.Direction.NO_DIRECTION && currentDirection != Move.Direction.Wait) { countMoves++; } currentCbsNode = currentCbsNode.prevStep; } } for (int i = 0; i < this.allAgentsState.Length; i++) { this.allAgentsState[i].lastMove.UpdateConflictCounts(conflictAvoidance, this.cbsInternalConflicts, this.conflictTimes); } }
/// <summary> /// Almost isn't used anywhere /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <param name="direction"></param> /// <param name="time"></param> public void setup(int x, int y, Move.Direction direction, int time) { base.setup(x, y, direction); this.time = time; }
// public static const int FOREVER_AFTER = int.MaxValue public TimedMove(int x, int y, Move.Direction direction, int time) : base(x, y, direction) { this.time = time; }
public Move MakeMove(Move.Direction direction) { return(new Move(new Piece(this), direction)); }
public void Init(int agentNum, int posX, int posY, Move.Direction direction, int timeStep) { this.Init(agentNum, new TimedMove(posX, posY, direction, timeStep)); }
/// <summary> /// Generates a problem instance based on a DAO map file. /// TODO: Fix code dup with GenerateProblemInstance and Import later. /// </summary> /// <param name="agentsNum"></param> /// <returns></returns> public ProblemInstance GenerateDragonAgeProblemInstance(string mapFileName, int agentsNum) { /** * Randomization based on timer is disabled for purposes of getting * reproducible experiments. */ //Random rand = new Random(); m_mapFileName = mapFileName; m_agentNum = agentsNum; TextReader input = new StreamReader(mapFileName); string[] lineParts; string line; line = input.ReadLine(); Debug.Assert(line.StartsWith("type octile")); // Read grid dimensions line = input.ReadLine(); lineParts = line.Split(' '); Debug.Assert(lineParts[0].StartsWith("height")); int maxX = int.Parse(lineParts[1]); line = input.ReadLine(); lineParts = line.Split(' '); Debug.Assert(lineParts[0].StartsWith("width")); int maxY = int.Parse(lineParts[1]); line = input.ReadLine(); Debug.Assert(line.StartsWith("map")); bool[][] grid = new bool[maxX][]; char cell; for (int i = 0; i < maxX; i++) { grid[i] = new bool[maxY]; line = input.ReadLine(); for (int j = 0; j < maxY; j++) { cell = line.ElementAt(j); if (cell == '@' || cell == 'O' || cell == 'T' || cell == 'W' /* Water isn't traversable from land */) { grid[i][j] = true; } else { grid[i][j] = false; } } } int x; int y; Agent[] agentGoals = new Agent[agentsNum]; AgentState[] agentStates = new AgentState[agentsNum]; bool[][] goals = new bool[maxX][]; for (int i = 0; i < maxX; i++) { goals[i] = new bool[maxY]; } // Choose random valid unclaimed goal locations for (int i = 0; i < agentsNum; i++) { x = rand.Next(maxX); y = rand.Next(maxY); if (goals[x][y] || grid[x][y]) { i--; } else { goals[x][y] = true; agentGoals[i] = new Agent(x, y, i); } } // Select random start/goal locations for every agent by performing a random walk for (int i = 0; i < agentsNum; i++) { agentStates[i] = new AgentState(agentGoals[i].Goal.x, agentGoals[i].Goal.y, agentGoals[i]); } ProblemInstance problem = new ProblemInstance(); problem.parameters[ProblemInstance.GRID_NAME_KEY] = Path.GetFileNameWithoutExtension(mapFileName); problem.Init(agentStates, grid); for (int j = 0; j < RANDOM_WALK_STEPS; j++) { for (int i = 0; i < agentsNum; i++) { goals[agentStates[i].lastMove.x][agentStates[i].lastMove.y] = false; // We're going to move the goal somewhere else // Move in a random legal direction: while (true) { Move.Direction op = (Move.Direction)rand.Next(0, 5); // TODO: fixme agentStates[i].lastMove.Update(op); if (problem.IsValid(agentStates[i].lastMove) && !goals[agentStates[i].lastMove.x][agentStates[i].lastMove.y]) // This spot isn't another agent's goal { break; } else { agentStates[i].lastMove.setOppositeMove(); // Rollback } } goals[agentStates[i].lastMove.x][agentStates[i].lastMove.y] = true; // Claim agent's new goal } } // Zero the agents' timesteps foreach (AgentState agentStart in agentStates) { agentStart.lastMove.time = 0; } return(problem); }
public void Init(int agentNum, int posX, int posY, Move.Direction direction, int timeStep, int constraintRange = 0) { this.Init(agentNum, new TimedMove(posX, posY, direction, timeStep), constraintRange); }
public CbsConstraint(int agentNum, int posX, int posY, Move.Direction direction, int timeStep, int constraintRange = 0) { this.Init(agentNum, posX, posY, direction, timeStep, constraintRange); }
public Move.Direction direction; // direction of attack, world direction // Other metadata for visuals can be added, for example: crits, dampening public AttackLog(int damage, Move.Direction direction) { this.damage = damage; this.direction = direction; }
public CFMCbsConstraint(int agentNum, int posX, int posY, Move.Direction direction, int timeStep) { this.Init(agentNum, posX, posY, direction, timeStep); }
/// <summary> /// Generates a problem instance, including a board, start and goal locations of desired number of agents /// and desired precentage of obstacles /// TODO: Refactor to use operators. /// </summary> /// <param name="gridSize"></param> /// <param name="agentsNum"></param> /// <param name="obstaclesNum"></param> /// <returns></returns> public ProblemInstance GenerateProblemInstance(int gridSize, int agentsNum, int obstaclesNum) { m_mapFileName = "GRID" + gridSize + "X" + gridSize; m_agentNum = agentsNum; /** * Randomization based on timer is disabled for purposes of getting * reproducible experiments. */ //Random rand = new Random(); if (agentsNum + obstaclesNum + 1 > gridSize * gridSize) { throw new Exception("Not enough room for " + agentsNum + ", " + obstaclesNum + " and one empty space in a " + gridSize + "x" + gridSize + "map."); } int x; int y; Agent[] aGoals = new Agent[agentsNum]; AgentState[] aStart = new AgentState[agentsNum]; bool[][] grid = new bool[gridSize][]; bool[][] goals = new bool[gridSize][]; // Generate a random grid for (int i = 0; i < gridSize; i++) { grid[i] = new bool[gridSize]; goals[i] = new bool[gridSize]; } for (int i = 0; i < obstaclesNum; i++) { x = rand.Next(gridSize); y = rand.Next(gridSize); if (grid[x][y]) // Already an obstacle { i--; } grid[x][y] = true; } // Choose random goal locations for (int i = 0; i < agentsNum; i++) { x = rand.Next(gridSize); y = rand.Next(gridSize); if (goals[x][y] || grid[x][y]) { i--; } else { goals[x][y] = true; aGoals[i] = new Agent(x, y, i); } } // Select random start/goal locations for every agent by performing a random walk for (int i = 0; i < agentsNum; i++) { aStart[i] = new AgentState(aGoals[i].Goal.x, aGoals[i].Goal.y, aGoals[i]); } // Initialized here only for the IsValid() call. TODO: Think how this can be sidestepped elegantly. ProblemInstance problem = new ProblemInstance(); problem.Init(aStart, grid); for (int j = 0; j < RANDOM_WALK_STEPS; j++) { for (int i = 0; i < agentsNum; i++) { goals[aStart[i].lastMove.x][aStart[i].lastMove.y] = false; // We're going to move the goal somewhere else while (true) { Move.Direction op = (Move.Direction)rand.Next(0, 5); // TODO: fixme aStart[i].lastMove.Update(op); if (problem.IsValid(aStart[i].lastMove) && !goals[aStart[i].lastMove.x][aStart[i].lastMove.y]) // this spot isn't another agent's goal { break; } else { aStart[i].lastMove.setOppositeMove(); // Rollback } } goals[aStart[i].lastMove.x][aStart[i].lastMove.y] = true; // Claim agent's new goal } } // Zero the agents' timesteps foreach (AgentState agentStart in aStart) { agentStart.lastMove.time = 0; } // TODO: There is some repetition here of previous instantiation of ProblemInstance. Think how to elegantly bypass this. problem = new ProblemInstance(); problem.Init(aStart, grid); return(problem); }