// Clone public ProjectileSourceBelief Clone() { ProjectileSourceBelief source = new ProjectileSourceBelief(Probability, Ammo, WeaponType.None); HashSet <WeaponType> newPossibleWeapons = new HashSet <WeaponType>(PossibleWeapons); source.PossibleWeapons = newPossibleWeapons; return(source); }
// Adds a belief to a dictionary modifying in place, also adding prob. to counter c void addBelief(Dictionary <IJCoords, ProjectileSourceBelief> dict, int i, int j, ProjectileSourceBelief belief, ref float c) { IJCoords key = new IJCoords(i, j); if (dict.ContainsKey(key)) { ProjectileSourceBelief oldBelief = dict[key]; oldBelief.Probability += belief.Probability; oldBelief.PossibleWeapons.UnionWith(belief.PossibleWeapons); oldBelief.Ammo = belief.Ammo > oldBelief.Ammo ? belief.Ammo : oldBelief.Ammo; } else { dict[key] = belief; } // Add to counter c += belief.Probability; }
// Adds a belief to a dictionary given an old belief, derived chance, and block world void addBeliefUsingWorld(Dictionary <IJCoords, ProjectileSourceBelief> dict, int newI, int newJ, ProjectileSourceBelief oldBelief, float derivedChance, ref float c) { ProjectileSourceBelief derivedBelief = oldBelief.Clone(); derivedBelief.Probability = derivedChance; // Check for ammo in new position WeaponType ammoTypeCheckResult = blockWorld.CheckAmmo(newI, newJ); if (ammoTypeCheckResult != WeaponType.None) { if (derivedBelief.Ammo != -1) { derivedBelief.Ammo = 3; // Lightning doesn't matter } derivedBelief.PossibleWeapons.Add(ammoTypeCheckResult); } addBelief(dict, newI, newJ, derivedBelief, ref c); }
// Runs trajectories of projectile source beliefs void runTrajectories() { // Iterate through each possibility foreach (KeyValuePair <IJCoords, ProjectileSourceBelief> entry in sourceBeliefs) { ProjectileSourceBelief sourceBelief = entry.Value; int sourceI = entry.Key.I; int sourceJ = entry.Key.J; int sourceAmmo = sourceBelief.Ammo; float sourceProbability = sourceBelief.Probability; // Iterate through each weapon type for each possibility foreach (WeaponType weaponType in sourceBelief.PossibleWeapons) { if (weaponType == WeaponType.Lightning) { // Add danger to all above for lightning - easy for (int j = -World.FloorLevelJ; j < World.BlocksHeight; j++) { if (j < sourceJ) { addDanger(sourceI, j, sourceProbability * LightningDangerWeight); } } } else { // Recursively add values to the danger zone 2D array // Use same blockworld for both directions since paths won't cross BlockWorld newBlockWorld = blockWorld.Clone(); addDangerToBlockAndNeighbors(sourceI, sourceJ, weaponType, sourceProbability, sourceAmmo, true, newBlockWorld); addDangerToBlockAndNeighbors(sourceI, sourceJ, weaponType, sourceProbability, sourceAmmo, false, newBlockWorld); } } } }
// Computes a belief distribution for the projectile sources void computeSourceBeliefs(int playerNum, World world) { // Find player World.Player player = playerNum == 1 ? world.Player1 : world.Player2; int playerI = World.XToI(player.X); int playerJ = World.YToJ(player.Y); sourceI = playerI; sourceJ = playerJ; // The initial source is at the player ProjectileSourceBelief initial = new ProjectileSourceBelief(1.0f, player.Ammo, player.Weapon); sourceBeliefs.Add(new IJCoords(playerI, playerJ), initial); // Compute distribution of projectile sources for (int iter = 0; iter < DistributionSteps; iter++) { Dictionary <IJCoords, ProjectileSourceBelief> newBeliefs = new Dictionary <IJCoords, ProjectileSourceBelief>(); float newBeliefsTotal = 0.0f; // Advance our belief state, except keep the old one around for efficiency foreach (KeyValuePair <IJCoords, ProjectileSourceBelief> entry in sourceBeliefs) { ProjectileSourceBelief belief = entry.Value; int i = entry.Key.I; int j = entry.Key.J; float prior = belief.Probability; // Determine possible directions bool upPossible = false; bool leftPossible = false; bool rightPossible = false; bool downPossible = false; bool stayPossible = false; int numPossibleDirections = 0; bool supported = blockWorld.CheckPositionSupported(i, j); if (!supported) { // Can only move down from unsupported positions numPossibleDirections++; downPossible = true; } else { stayPossible = true; numPossibleDirections++; if (!blockWorld.CheckGroundByIndex(i, j + 1)) { downPossible = true; numPossibleDirections++; } if (!blockWorld.CheckGroundByIndex(i + 1, j)) { leftPossible = true; numPossibleDirections++; } if (!blockWorld.CheckGroundByIndex(i - 1, j)) { rightPossible = true; numPossibleDirections++; } if (!blockWorld.CheckGroundByIndex(i, j - 1)) { upPossible = true; numPossibleDirections++; } } // Compute chance of each direction - uniform float chance = 1.0f / numPossibleDirections; float derivedChance = chance * prior; // Update beliefs based on possible directions // Staying in place is always an option if (stayPossible) { addBeliefUsingWorld(newBeliefs, i, j, belief, derivedChance, ref newBeliefsTotal); } if (upPossible) { addBeliefUsingWorld(newBeliefs, i, j - 1, belief, derivedChance, ref newBeliefsTotal); } if (downPossible) { addBeliefUsingWorld(newBeliefs, i, j + 1, belief, derivedChance, ref newBeliefsTotal); } if (leftPossible) { addBeliefUsingWorld(newBeliefs, i + 1, j, belief, derivedChance, ref newBeliefsTotal); } if (rightPossible) { addBeliefUsingWorld(newBeliefs, i - 1, j, belief, derivedChance, ref newBeliefsTotal); } } // Normalize our new belief state foreach (KeyValuePair <IJCoords, ProjectileSourceBelief> entry in newBeliefs) { entry.Value.Probability /= newBeliefsTotal; } // Update sourceBeliefs = newBeliefs; } }