コード例 #1
0
    // A player's danger zone must be calculated from a World and a blockWorld
    public DangerZone(int playerNum, World world, BlockWorld blockWorld)
    {
        // Init danger array
        dangerZoneArray = new float[World.BlocksWidth, dangerZoneHeight];

        // Init to zero
        for (int i = 0; i < World.BlocksWidth; i++)
        {
            for (int j = 0; j < dangerZoneHeight; j++)
            {
                dangerZoneArray[i, j] = 0.0f;
            }
        }

        // Store block world as a copy for modification
        this.blockWorld = blockWorld.Clone();

        // Uses exact filtering to compute a belief distribution for player position
        // and weapon type/ammo
        sourceBeliefs = new Dictionary <IJCoords, ProjectileSourceBelief>();
        computeSourceBeliefs(playerNum, world);

        // For each source belief computed by exact filtering, run the trajectory
        runTrajectories();
    }
コード例 #2
0
    // 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);
                }
            }
        }
    }
コード例 #3
0
ファイル: AStar.cs プロジェクト: facybenbook/tunnelwars-ai
    // Outputs the optimal path
    public Path ComputeBestPath(BlockWorld blockWorld)
    {
        HeapPriorityQueue <Path> frontier = new HeapPriorityQueue <Path>(MaxNodes);
        HashSet <BlockWorld>     explored = new HashSet <BlockWorld>();

        // Initial state, path
        BlockWorld initialState = blockWorld;
        Path       initialPath  = new Path(0, new List <BlockWorld>()
        {
            initialState
        });

        // Add the initial path to the frontier
        frontier.Enqueue(initialPath, 0 + Heuristic(initialState));


        // Find paths
        int expansions = 0;

        while (frontier.Count > 0)
        {
            Path       path      = frontier.Dequeue();
            BlockWorld lastWorld = path.Last();

            // Return the no path
            if (expansions > MaxExpansions)
            {
                return(null);
            }

            // Check goal
            if (GoalFunction(lastWorld))
            {
                return(path);
            }

            // Mark as explored
            explored.Add(lastWorld);

            // Iterate over possible actions
            List <BlockWorldAction> possibleActions = lastWorld.ApplicableActions();
            foreach (BlockWorldAction action in possibleActions)
            {
                // Try the action on a cloned block world
                BlockWorld newWorld = lastWorld.Clone();
                newWorld.Advance(action);

                // Check if explored already
                bool alreadyExplored = false;
                foreach (BlockWorld exploredWorld in explored)
                {
                    if (exploredWorld.PropertiesEqual(newWorld))
                    {
                        alreadyExplored = true;
                        break;
                    }
                }

                if (!alreadyExplored)
                {
                    // Extend path
                    Path newPath = path.ExtendedPath(newWorld, CostFunction(newWorld));

                    // Add to frontier
                    frontier.Enqueue(newPath, Heuristic(newWorld) + newPath.Cost);
                }
            }

            expansions++;
        }

        // No solution exists
        return(null);
    }
コード例 #4
0
    // Recursively add danger to the 2D array
    void addDangerToBlockAndNeighbors(int i, int j, WeaponType type, float probability, int ammo,
                                      bool facingRight, BlockWorld blockWorld, bool isFalling = false)
    {
        // Base cases
        if (probability < epsilon)
        {
            return;
        }
        if (ammo == 0)
        {
            return;                    // Master mode has negative ammo - do not return
        }
        // Blow out ground if there is any at the current position. If there is
        if (blockWorld.CheckGroundByIndex(i, j))
        {
            // Another base case for immutable ground
            bool immutable = blockWorld.CheckGroundImmutableByIndex(i, j);
            if (immutable)
            {
                return;                        // End of the line
            }
            // Blow out ground otherwise
            blockWorld.SetGroundByIndex(i, j, false);
            addDangerToBlockAndNeighbors(i, j, type, probability * groundBlowoutFactor, ammo - 1,
                                         facingRight, blockWorld);
            return;
        }
        else
        {
            int normalized = facingRight ? -1 : 1;

            switch (type)
            {
            case WeaponType.Rockets: {
                addDanger(i, j, probability * RocketsDangerWeight);
                addDangerToBlockAndNeighbors(i + normalized, j, type, probability, ammo,
                                             facingRight, blockWorld);
                break;
            }

            case WeaponType.Bombs: {
                addDanger(i, j, probability * BombsDangerWeight);
                addDangerToBlockAndNeighbors(i, j + 1, type, probability, ammo, facingRight, blockWorld);
                break;
            }

            case WeaponType.Minions: {
                addDanger(i, j, probability * MinionsDangerWeight);

                bool groundDown  = blockWorld.CheckGroundByIndex(i, j + 1);
                bool groundRight = blockWorld.CheckGroundByIndex(i + normalized, j);
                bool goRight     = false;
                bool goDown      = false;

                // Do natural motion - right first unless hasn't fallen
                if (!groundRight && !groundDown)
                {
                    if (isFalling && blockWorld.CheckGroundByIndex(i + normalized, j + 1))
                    {
                        goRight = true;
                    }
                    else
                    {
                        goDown = true;
                    }
                }
                else if (!groundRight && groundDown)
                {
                    goRight = true;
                }
                else if (groundRight && !groundDown)
                {
                    goDown = true;
                }
                else
                {
                    // Block worlds diverge, so make a new one
                    BlockWorld newBlockWorld = blockWorld.Clone();

                    // Go both directions
                    addDangerToBlockAndNeighbors(i + normalized, j, type, probability / 2.0f,
                                                 ammo, facingRight, blockWorld, false);
                    addDangerToBlockAndNeighbors(i, j + 1, type, probability / 2.0f,
                                                 ammo, facingRight, newBlockWorld, true);
                }

                // Do sole motions
                if (goRight)
                {
                    addDangerToBlockAndNeighbors(i + normalized, j, type, probability,
                                                 ammo, facingRight, blockWorld, false);
                    return;
                }
                if (goDown)
                {
                    addDangerToBlockAndNeighbors(i, j + 1, type, probability,
                                                 ammo, facingRight, blockWorld, true);
                    return;
                }

                break;
            }
            }
        }
    }