示例#1
0
        static void Main(string[] args)
        {
            Console.Clear();
            Console.WriteLine("Battle City AI, Copyright (c) 1985 U.S. Robots and Mechanical Men, Inc.");
#if DEBUG
            Console.WriteLine("Mode: DEBUG");
#else
            Console.WriteLine("Mode: RELEASE");
#endif
            Console.WriteLine(Environment.NewLine + "Welcome, scalvin.");

            string botname = "ctf";

            Console.BufferHeight = 4096;
            Console.WindowWidth  = 132;
            Console.WindowHeight = 40;

            Debug.Listeners.Add(new TextWriterTraceListener(System.Console.Out));

            var endpoint = "http://localhost:7070/Challenge/ChallengeService";
            if (args.Length > 0)
            {
                endpoint = args[0];
            }
            if (args.Length > 1)
            {
                botname = args[1].ToLower();
            }

            System.ServiceModel.BasicHttpBinding binding = new System.ServiceModel.BasicHttpBinding();
            binding.MaxReceivedMessageSize = Settings.MAX_SOAP_MSG_SIZE;
            System.ServiceModel.EndpointAddress remoteAddress = new System.ServiceModel.EndpointAddress(endpoint);
            client = new ChallengeService.ChallengeClient(binding, remoteAddress);

            try
            {
                ChallengeService.board result = client.login();
                board = new Board(result.states);
                board.endGamePoint = result.endGamePoint;

                // Set up the clock, and add all the tasks that should execute each cycle.
                clock = new Clock(Settings.SYNC_TICK, Settings.SYNC_DELTA_STEP_LO);

                // At the start of each cycle, process all events and prune the game trees.
                clock.AddTask(0, handleNewTick);

                // Some time through the cycle, post a preliminary move as backup.
                clock.AddTask(Settings.SCHEDULE_EARLY_MOVE, postEarlyMove);

                // Just before the end of the cycle, post the final best move found.
                clock.AddTask(Settings.SCHEDULE_FINAL_MOVE, postFinalMove);

                // In the first tick, the server status is read, and the clock is started based
                // on the reported millisecondsToNextTick.
                ChallengeService.game status = client.getStatus();
                board.Update(status);
                Console.Title = board.playerName;
                Debug.Listeners.Add(new TextWriterTraceListener(board.playerName + ".log"));

                switch (botname)
                {
                case "random":
                    bot = new AI_Random(board, client);
                    break;

                case "aggro":
                    bot = new AI_Aggro(board, client);
                    break;

                case "ctf":
                    bot = new AI_CTF(board, client);
                    break;

                default:
                    bot = new AI_Random(board, client);
                    break;
                }

                Console.WriteLine("Launching AI '{0}'" + Environment.NewLine, botname);

                clock.Start(status.millisecondsToNextTick + Settings.SYNC_INITIAL_DELAY);
                Debug.Flush();
            }
            catch (Exception e)
            {
                Debug.WriteLine(e);
            }
        }
示例#2
0
        public void Update(ChallengeService.game status)
        {
            if (playerName == null)     // First time update is called
            {
                playerName = status.playerName;
                if (status.players[0].name == status.playerName)
                {
                    playerID = 0;
                }
                else if (status.players[1].name == status.playerName)
                {
                    playerID = 1;
                }
                else
                {
                    throw new ArgumentException("Player '{0}' not found in player list.", status.playerName);
                }

                playerBase.x   = status.players[playerID][email protected];
                playerBase.y   = status.players[playerID][email protected];
                opponentBase.x = status.players[opponentID][email protected];
                opponentBase.y = status.players[opponentID][email protected];

                if ((status.players[playerID].bullets == null) && (status.players[opponentID].bullets == null))
                {
                    Debug.WriteLine("No bullets in play yet.");
                }
                else
                {
                    Debug.WriteLine("WARNING: bullets already in play!");
                }
                int i = 0;
                Debug.WriteLine("");
                Debug.WriteLine("Player base is at ({0},{1}).", playerBase.x, playerBase.y);
                Debug.WriteLine("Opponent base is at ({0},{1}).", opponentBase.x, opponentBase.y);

                foreach (ChallengeService.unit u in status.players[playerID].units)
                {
                    playerTank[i++] = new Tank(u.x, u.y, u.direction, u.id);
                    Debug.WriteLine("Player tank ID {0} starts at ({1},{2}), facing {3}.",
                                    u.id, u.x, u.y, u.direction);
                }

                i = 0;
                foreach (ChallengeService.unit u in status.players[opponentID].units)
                {
                    opponentTank[i++] = new Tank(u.x, u.y, u.direction, u.id);
                    Debug.WriteLine("Opponent tank ID {0} starts at ({1},{2}), facing {3}.",
                                    u.id, u.x, u.y, u.direction);
                }
            }

            // Update tank positions


            foreach (Tank t in playerTank)
            {
                bool wasDestroyed = t.destroyed;
                t.destroyed = true;
                ChallengeService.unit[] serverUnit = status.players[playerID].units;
                if ((serverUnit.Length > 0) && (serverUnit[0] != null) && (serverUnit[0].id == t.id))
                {
                    t.x         = serverUnit[0].x;
                    t.y         = serverUnit[0].y;
                    t.direction = serverUnit[0].direction;
                    t.destroyed = false;
                }
                else if ((serverUnit.Length > 1) && (serverUnit[1] != null) && (serverUnit[1].id == t.id))
                {
                    t.x         = serverUnit[1].x;
                    t.y         = serverUnit[1].y;
                    t.direction = serverUnit[1].direction;
                    t.destroyed = false;
                }
                else
                {
                    if (!wasDestroyed)
                    {
                        Debug.WriteLine("Player tank (id={0}) destroyed!", t.id);
                    }
                }
            }

            foreach (Tank t in opponentTank)
            {
                bool wasDestroyed = t.destroyed;
                t.destroyed = true;
                ChallengeService.unit[] serverUnit = status.players[opponentID].units;
                if ((serverUnit.Length > 0) && (serverUnit[0] != null) && (serverUnit[0].id == t.id))
                {
                    t.x         = serverUnit[0].x;
                    t.y         = serverUnit[0].y;
                    t.direction = serverUnit[0].direction;
                    t.destroyed = false;
                }
                else if ((serverUnit.Length > 1) && (serverUnit[1] != null) && (serverUnit[1].id == t.id))
                {
                    t.x         = serverUnit[1].x;
                    t.y         = serverUnit[1].y;
                    t.direction = serverUnit[1].direction;
                    t.destroyed = false;
                }
                else
                {
                    if (!wasDestroyed)
                    {
                        Debug.WriteLine("Opponent tank (id={0}) destroyed!", t.id);
                    }
                }
            }

            // Update bullet positions, and capture new ones.

            foreach (KeyValuePair <int, Bullet> bullet in playerBullet)
            {
                // For each bullet that we're tracking, clear its updated status. If it doesn't get updated
                // in the latest status report, we know that it's been destroyed.
                bullet.Value.updated = false;
            }

            if (status.players[playerID].bullets != null)
            {
                foreach (ChallengeService.bullet b in status.players[playerID].bullets)
                {
                    Bullet myBullet;
                    if (playerBullet.TryGetValue(b.id, out myBullet))
                    {
                        // This is a bullet we know. Update its position.
                        myBullet.x = b.x;
                        myBullet.y = b.y;
                        if (myBullet.direction != b.direction)
                        {
                            Debug.WriteLine("ERROR: Player bullet #{0} changed direction from {1} to {2}!",
                                            myBullet.direction, b.direction);
                        }
                        myBullet.updated = true;
                    }
                    else
                    {
                        // This is a bullet that has just been fired. Create a new entry, and find out who its daddy is.

                        Bullet newBullet = new Bullet(b.x, b.y, b.direction, b.id);
                        int    ownerX, ownerY;
                        switch (b.direction)
                        {
                        case ChallengeService.direction.DOWN:
                            ownerX = b.x;
                            ownerY = b.y - 3;
                            break;

                        case ChallengeService.direction.LEFT:
                            ownerX = b.x + 3;
                            ownerY = b.y;
                            break;

                        case ChallengeService.direction.RIGHT:
                            ownerX = b.x - 3;
                            ownerY = b.y;
                            break;

                        case ChallengeService.direction.UP:
                            ownerX = b.x;
                            ownerY = b.y + 3;
                            break;

                        default:
                            ownerX = b.x;
                            ownerY = b.y;
                            Debug.WriteLine("ERROR: Player bullet #{0} created without firing direction.", b.direction);
                            break;
                        }
                        if (!playerTank[0].destroyed && (playerTank[0].x == ownerX) && (playerTank[0].y == ownerY))
                        {
                            newBullet.owner      = playerTank[0];
                            playerTank[0].bullet = newBullet;
                        }
                        else if (!playerTank[1].destroyed && (playerTank[1].x == ownerX) && (playerTank[1].y == ownerY))
                        {
                            newBullet.owner      = playerTank[1];
                            playerTank[1].bullet = newBullet;
                        }
                        else if ((Math.Abs(playerTank[0].x - ownerX) <= 2) && (Math.Abs(playerTank[0].y - ownerY) <= 2))
                        {
                            Debug.WriteLine("WARNING: Player bullet #{0} created too far from closest active tank; taking the best guess.", b.id);
                            newBullet.owner      = playerTank[0];
                            playerTank[0].bullet = newBullet;
                        }
                        else if ((Math.Abs(playerTank[1].x - ownerX) <= 2) && (Math.Abs(playerTank[1].y - ownerY) <= 2))
                        {
                            Debug.WriteLine("WARNING: Player bullet #{0} created too far from closest active tank; taking the best guess.", b.id);
                            newBullet.owner      = playerTank[1];
                            playerTank[1].bullet = newBullet;
                        }
                        // REFACTOR: We're actually violating DRY here, since we're keeping two separate lists of bullets
                        // (one inside the player/opponent bullet lists, another inside the tank objects themselves. It
                        // could perhaps be cleaner just to store the bullet objects in the tank object.
                        playerBullet[b.id] = newBullet;
                    }
                }
            }

            List <int> destroyedBullets = new List <int>();

            foreach (KeyValuePair <int, Bullet> bullet in playerBullet)
            {
                if (bullet.Value.updated == false)
                {
                    // This bullet has not been updated this round, so it must have been destroyed.
                    // Remove the tank's reference to it.
                    if (bullet.Value.owner != null)
                    {
                        bullet.Value.owner.bullet = null;
                    }
                    // We can't remove it from the dictionary inside the loop, so take note of the destroyed bullets.
                    destroyedBullets.Add(bullet.Key);
                }
            }
            foreach (int key in destroyedBullets)
            {
                playerBullet.Remove(key);
            }

            foreach (KeyValuePair <int, Bullet> bullet in opponentBullet)
            {
                // For each bullet that we're tracking, clear its updated status. If it doesn't get updated
                // in the latest status report, we know that it's been destroyed.
                bullet.Value.updated = false;
            }

            if (status.players[opponentID].bullets != null)
            {
                foreach (ChallengeService.bullet b in status.players[opponentID].bullets)
                {
                    Bullet myBullet;
                    if (opponentBullet.TryGetValue(b.id, out myBullet))
                    {
                        // This is a bullet we know. Update its position.
                        myBullet.x = b.x;
                        myBullet.y = b.y;
                        if (myBullet.direction != b.direction)
                        {
                            Debug.WriteLine("ERROR: Opponent bullet #{0} changed direction from {1} to {2}!",
                                            myBullet.direction, b.direction);
                        }
                        myBullet.updated = true;
                    }
                    else
                    {
                        // This is a bullet that has just been fired. Create a new entry, and find out who its daddy is.

                        Bullet newBullet = new Bullet(b.x, b.y, b.direction, b.id);
                        int    ownerX, ownerY;
                        switch (b.direction)
                        {
                        case ChallengeService.direction.DOWN:
                            ownerX = b.x;
                            ownerY = b.y - 3;
                            break;

                        case ChallengeService.direction.LEFT:
                            ownerX = b.x + 3;
                            ownerY = b.y;
                            break;

                        case ChallengeService.direction.RIGHT:
                            ownerX = b.x - 3;
                            ownerY = b.y;
                            break;

                        case ChallengeService.direction.UP:
                            ownerX = b.x;
                            ownerY = b.y + 3;
                            break;

                        default:
                            ownerX = b.x;
                            ownerY = b.y;
                            Debug.WriteLine("ERROR: Opponent bullet #{0} created without firing direction.", b.direction);
                            break;
                        }
                        if (!opponentTank[0].destroyed && (opponentTank[0].x == ownerX) && (opponentTank[0].y == ownerY))
                        {
                            newBullet.owner        = opponentTank[0];
                            opponentTank[0].bullet = newBullet;
                        }
                        else if (!opponentTank[1].destroyed && (opponentTank[1].x == ownerX) && (opponentTank[1].y == ownerY))
                        {
                            newBullet.owner        = opponentTank[1];
                            opponentTank[1].bullet = newBullet;
                        }
                        else if ((Math.Abs(opponentTank[0].x - ownerX) <= 2) && (Math.Abs(opponentTank[0].y - ownerY) <= 2))
                        {
                            Debug.WriteLine("WARNING: Opponent bullet #{0} created too far from closest active tank; taking the best guess.", b.id);
                            newBullet.owner        = opponentTank[0];
                            opponentTank[0].bullet = newBullet;
                        }
                        else if ((Math.Abs(opponentTank[1].x - ownerX) <= 2) && (Math.Abs(opponentTank[1].y - ownerY) <= 2))
                        {
                            Debug.WriteLine("WARNING: Opponent bullet #{0} created too far from closest active tank; taking the best guess.", b.id);
                            newBullet.owner        = opponentTank[1];
                            opponentTank[1].bullet = newBullet;
                        }
                        opponentBullet[b.id] = newBullet;
                    }
                }
            }

            destroyedBullets = new List <int>();
            foreach (KeyValuePair <int, Bullet> bullet in opponentBullet)
            {
                if (bullet.Value.updated == false)
                {
                    // This bullet has not been updated this round, so it must have been destroyed.
                    // Remove the tank's reference to it.
                    if (bullet.Value.owner != null)
                    {
                        bullet.Value.owner.bullet = null;
                    }
                    // We can't remove it from the dictionary inside the loop, so take note of the destroyed bullets.
                    destroyedBullets.Add(bullet.Key);
                }
            }
            foreach (int key in destroyedBullets)
            {
                opponentBullet.Remove(key);
            }

            if (status.events == null)
            {
                // Debug.WriteLine("No events.");
                return;
            }
            else
            {
                // Debug.WriteLine(state.events.ToString());
            }
            if (status.events.blockEvents != null)
            {
                foreach (ChallengeService.blockEvent e in status.events.blockEvents)
                {
                    board[e.point.x][e.point.y] = e.newState;
                    Debug.WriteLine("Block at ({0},{1}) changed to {2}.", e.point.x, e.point.y, e.newState);
                }
            }
            if (status.events.unitEvents != null)
            {
                foreach (ChallengeService.unitEvent e in status.events.unitEvents)
                {
                    // These don't seem to do anything, so just ignore it.
                    Debug.WriteLine("WARNING: UNIT EVENT: {0}", e.unit);
                }
            }
        }