package com.mycompany.mavenproject1; import java.util.Collections; import java.util.List; import java.util.logging.Level; import cz.cuni.amis.pogamut.base.agent.navigation.IPathExecutorState; import cz.cuni.amis.pogamut.base.agent.navigation.PathExecutorState; import cz.cuni.amis.pogamut.base.utils.guice.AgentScoped; import cz.cuni.amis.pogamut.ut2004.agent.module.utils.TabooSet; import cz.cuni.amis.pogamut.ut2004.agent.navigation.UT2004PathAutoFixer; import cz.cuni.amis.pogamut.ut2004.bot.impl.UT2004Bot; import cz.cuni.amis.pogamut.ut2004.bot.impl.UT2004BotModuleController; import cz.cuni.amis.pogamut.ut2004.communication.messages.gbcommands.Initialize; import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.BotKilled; import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.ConfigChange; import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.ControlMessage; import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.GameInfo; import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.InitedMessage; import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.NavPoint; import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Player; import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Self; import cz.cuni.amis.pogamut.ut2004.hideandseek.bot.UT2004BotHSController; import cz.cuni.amis.pogamut.ut2004.hideandseek.protocol.HSBotState; import cz.cuni.amis.pogamut.ut2004.hideandseek.protocol.HSScoreChangeReason; import cz.cuni.amis.pogamut.ut2004.hideandseek.protocol.messages.HSAssignSeeker; import cz.cuni.amis.pogamut.ut2004.hideandseek.protocol.messages.HSBotStateChanged; import cz.cuni.amis.pogamut.ut2004.hideandseek.protocol.messages.HSPlayerScoreChanged; import cz.cuni.amis.pogamut.ut2004.hideandseek.protocol.messages.HSRoundEnd; import cz.cuni.amis.pogamut.ut2004.hideandseek.protocol.messages.HSRoundStart; import cz.cuni.amis.pogamut.ut2004.hideandseek.protocol.messages.HSRoundState; import cz.cuni.amis.pogamut.ut2004.hideandseek.protocol.messages.HSRunnerCaptured; import cz.cuni.amis.pogamut.ut2004.hideandseek.protocol.messages.HSRunnerFouled; import cz.cuni.amis.pogamut.ut2004.hideandseek.protocol.messages.HSRunnerSafe; import cz.cuni.amis.pogamut.ut2004.hideandseek.protocol.messages.HSRunnerSpotted; import cz.cuni.amis.pogamut.ut2004.hideandseek.protocol.messages.HSRunnerSurvived; import cz.cuni.amis.pogamut.ut2004.hideandseek.server.UT2004HSServer; import cz.cuni.amis.pogamut.ut2004.utils.UT2004BotRunner; import cz.cuni.amis.utils.IFilter; import cz.cuni.amis.utils.collections.MyCollections; import cz.cuni.amis.utils.exception.PogamutException; import cz.cuni.amis.utils.flag.FlagListener; /** * Example of the bot playing HIDE-AND-SEEK-GAME according to {@link ControlMessage}s from {@link UT2004HSServer}. * * @author Jakub Gemrot aka Jimmy */ @AgentScoped public class HideAndSeekBot extends UT2004BotHSController { private static String[] names = new String[]{"Peter", "James", "Johnny", "Craig", "Jimmy", "Steve", "Ronnie", "Bobby"}; static { List n = MyCollections.toList(names); Collections.shuffle(n); names = n.toArray(new String[n.size()]); } /** * Just for the numbering of bots. */ private static int number = 0; /** * Taboo set is working as "black-list", that is you might add some * NavPoints to it for a certain time, marking them as "unavailable". */ protected TabooSet tabooNavPoints; /** * Path auto fixer watches for navigation failures and if some navigation * link is found to be unwalkable, it removes it from underlying navigation * graph. * * Note that UT2004 navigation graphs are some times VERY stupid or contains * VERY HARD TO FOLLOW links... */ protected UT2004PathAutoFixer autoFixer; /** * Here we can modify initializing command for our bot. * * @return */ @Override public Initialize getInitializeCommand() { return new Initialize().setName(names[(++number) % names.length]); } /** * The bot is initialized in the environment - a physical representation of * the bot is present in the game. * * @param config information about configuration * @param init information about configuration */ @SuppressWarnings("unchecked") @Override public void botInitialized(GameInfo gameInfo, ConfigChange config, InitedMessage init) { // initialize taboo set where we store temporarily unavailable navpoints tabooNavPoints = new TabooSet(bot); // auto-removes wrong navigation links between navpoints autoFixer = new UT2004PathAutoFixer(bot, navigation.getPathExecutor(), fwMap, aStar, navBuilder); // IMPORTANT // adds a listener to the path executor for its state changes, it will allow you to // react on stuff like "PATH TARGET REACHED" or "BOT STUCK" navigation.getPathExecutor().getState().addStrongListener(new FlagListener() { @Override public void flagChanged(IPathExecutorState changedValue) { pathExecutorStateChange(changedValue.getState()); } }); navigation.getLog().setLevel(Level.INFO); // ((SocketConnection)bot.getEventBus().getComponent(SocketConnection.COMPONENT_ID)).setLogMessages(true); // bot.getLogger().getCategory(SocketConnection.COMPONENT_ID.getToken()).setLevel(Level.ALL); // bot.getLogger().getCategory(YylexParser.COMPONENT_ID.getToken()).setLevel(Level.ALL); } /** * The bot is initialized in the environment - a physical representation of * the bot is present in the game. * * @param config information about configuration * @param init information about configuration */ @Override public void botFirstSpawn(GameInfo gameInfo, ConfigChange config, InitedMessage init, Self self) { // change to ALL to receive logs from the navigation so you can get a grasp on how it is working navigation.getPathExecutor().getLog().setLevel(Level.WARNING); } // -------------------- // ==================== // HIDE AND SEEK EVENTS // ==================== // -------------------- /** * Some RUNNER has just survived the round. *

* This event is triggered at the end of the round for every RUNNER that has not been FOULED, CAPTURED and did not make it to SAFE area. * * @param event */ @Override protected void hsRunnerSurvived(HSRunnerSurvived event, boolean me) { } /** * Some RUNNER has just been spotted by the SEEKER. * @param event */ @Override protected void hsRunnerSpotted(HSRunnerSpotted event, boolean me) { } /** * Some RUNNER has just made it to the safe-area. * @param event */ @Override protected void hsRunnerSafe(HSRunnerSafe event, boolean me) { } /** * Some RUNNER has just been fouled-out because it stepped into the restricted-area while it was activated. * @param event * @param me whether this event speaks about your bot */ @Override protected void hsRunnerFouled(HSRunnerFouled event, boolean me) { } /** * Some RUNNER has just been captured by the SEEKER, i.e., seeker has spotted the runner and made it to the safe-area before * the runner. * * @param event * @param me whether this event speaks about your bot */ @Override protected void hsRunnerCaptured(HSRunnerCaptured event, boolean me) { } /** * Round state update has been received. * @param event */ @Override protected void hsRoundState(HSRoundState event) { } /** * New round has just started, you may use this event to initialize your data-structures. * @param event */ @Override protected void hsRoundStart(HSRoundStart event) { hideNavPoint = null; targetNavPoint = null; goingToFoul = random.nextInt(6) == 5; // 1/6 probability that the RUNNER will perform FOUL BEHAVIOR, will remain in restricted area instead of hiding tabooNavPoints.clear(); navigation.stopNavigation(); // prevent commands from previous round to be still effective } /** * Round has just ended, you may use this event to cleanup your data-structures. * @param event */ @Override protected void hsRoundEnd(HSRoundEnd event) { } /** * Some player (runner/seeker) score has just changed, you may examine the reason within {@link HSPlayerScoreChanged${symbol_pound}getScoreChangeReason()}, see * {@link HSScoreChangeReason}. * * @param event * @param me whether this event speaks about your bot */ @Override protected void hsPlayerScoreChanged(HSPlayerScoreChanged event, boolean me) { } /** * Some bot {@link HSBotState} has been updated. * @param event * @param me whether this event speaks about your bot */ protected void hsBotStateChanged(HSBotStateChanged event, boolean me) { } /** * SEEKER role has been just assigned to some bot. * @param event * @param me whether this event speaks about your bot */ @Override protected void hsAssignSeeker(HSAssignSeeker event, boolean me) { } // ----- // ===== // LOGIC // ===== // ----- /** * This method is called only once right before actual logic() method is * called for the first time. */ @Override public void beforeFirstLogic() { } /** * Main method that controls the bot - makes decisions what to do next. It * is called iteratively by Pogamut engine every time a synchronous batch * from the environment is received. This is usually 4 times per second - it * is affected by visionTime variable, that can be adjusted in GameBots ini * file in UT2004/System folder. */ @Override public void logic() { // mark that another logic iteration has began log.info("====== LOGIC ITERATION ======"); // UNCOMMENT TO GET DETAIL INFO DURING RUN-TIME // logState(); if (!hide.isRoundRunning()) return; if (!hide.isMeAlive()) return; switch(hide.getMyState()) { case RUNNER: logicRunner(); break; case RUNNER_SPOTTED: logicRunnerSpotted(); break; case SEEKER: logicSeeker(); break; default: // SHOULD NOT REACH HERE, BUT LET'S PLAY SAFE... return; } } private void logState() { log.info("------ STATE ------"); log.info("Game state: " + hide.getGameState()); log.info("Game running: " + hide.isGameRunning()); if (!hide.isGameRunning()) return; log.info("Round running: " + hide.isRoundRunning()); if (!hide.isRoundRunning()) return; log.info("Me: " + hide.getMyState()); log.info("Me spawned? " + hide.isMeAlive()); log.info("Hiding time left: " + hide.getRemainingHidingTime()); log.info("Restricted area time left: " + hide.getRemainingRestrictedAreaTime()); log.info("Round time left: " + hide.getRemainingRoundTime()); log.info("Distance to safe-area: " + hide.getMySafeAreaDistance()); log.info("Distance to restricted-area: " + hide.getMyRestrictedAreaDistance()); } // ------------ // ============ // LOGIC RUNNER // ============ // ------------ NavPoint hideNavPoint; Boolean goingToFoul = null; private void logicRunner() { log.info("------ RUNNER ------"); if (hide.isHidingTime()) { if (goingToFoul) { log.info("GOING TO FOUL! Standing-stil..."); return; } log.info("HIDING!"); if (hideNavPoint == null) { hideNavPoint = chooseHideNavPoint(); if (hideNavPoint == null) { log.warning("THERE IS NO SUITABLE HIDE-POINT TO RUN TO!"); return; } } if (info.isAtLocation(hideNavPoint)) { if (navigation.isNavigating()) { navigation.stopNavigation(); } log.info("HIDDEN!"); move.turnHorizontal(30); return; } navigation.navigate(hideNavPoint); return; } if (hide.isRestrictedAreaActivated()) { log.info("RESTRICTED AREA ACTIVE, standing still!"); return; } runToSafePoint(); } private NavPoint chooseHideNavPoint() { if (visibility.isInitialized()) { // WE HAVE VISIBILITY INFORMATION! // => lets get smarty! return MyCollections.getRandomFiltered( visibility.getCoverNavPointsFrom(hide.getSafeArea()), new IFilter() { @Override public boolean isAccepted(NavPoint object) { return !hide.isInRestrictedArea(object, 50); } } ); } // NO VISIBILITY INFORMATION PROVIDED, CHOOSE RANDOM SUITABLE return MyCollections.getRandomFiltered( navPoints.getNavPoints().values(), new IFilter() { @Override public boolean isAccepted(NavPoint object) { return !hide.isInRestrictedArea(object, 50); } } ); } // -------------------- // ==================== // LOGIC RUNNER SPOTTED // ==================== // -------------------- private void logicRunnerSpotted() { runToSafePoint(); } private void runToSafePoint() { log.info("RUNNING TO SAFE POINT"); navigation.navigate(hide.getSafeArea()); } // ------------ // ============ // LOGIC SEEKER // ============ // ------------ private void logicSeeker() { log.info("------ SEEKER ------"); if (hide.canCaptureRunner()) { log.info("CAN CAPTURE RUNNER!"); runToSafePoint(); } else { if (players.canSeePlayers()) { targetNavPoint = null; handlePlayerNavigation(players.getNearestVisiblePlayer()); } else { handleNavPointNavigation(); } } } private NavPoint targetNavPoint; private void handleNavPointNavigation() { if (navigation.isNavigatingToNavPoint()) { // IS TARGET CLOSE & NEXT TARGET NOT SPECIFIED? while (navigation.getContinueTo() == null && navigation.getRemainingDistance() < 400) { // YES, THERE IS NO "next-target" SET AND WE'RE ABOUT TO REACH OUR TARGET! navigation.setContinueTo(getRandomNavPoint()); // note that it is WHILE because navigation may immediately eat up "next target" and next target may be actually still too close! } // WE'RE NAVIGATING TO SOME NAVPOINT return; } // NAVIGATION HAS STOPPED ... // => we need to choose another navpoint to navigate to // => possibly follow some players ... targetNavPoint = getRandomNavPoint(); if (targetNavPoint == null) { log.severe("COULD NOT CHOOSE ANY NAVIGATION POINT TO RUN TO!!!"); if (world.getAll(NavPoint.class).size() == 0) { log.severe("world.getAll(NavPoint.class).size() == 0, there are no navigation ponits to choose from! Is exporting of nav points enabled in GameBots2004.ini inside UT2004?"); } config.setName("NavigationBot [CRASHED]"); return; } navigation.navigate(targetNavPoint); } private void handlePlayerNavigation(Player player) { if (navigation.isNavigating() && navigation.getCurrentTargetPlayer() == player) { // WE'RE NAVIGATING TO SOME PLAYER return; } // START THE NAVIGATION navigation.navigate(player); } /** * Called each time our bot die. Good for reseting all bot state dependent * variables. * * @param event */ @Override public void botKilled(BotKilled event) { navigation.stopNavigation(); } /** * Path executor has changed its state (note that {@link UT2004BotModuleController${symbol_pound}getPathExecutor()} * is internally used by * {@link UT2004BotModuleController${symbol_pound}getNavigation()} as well!). * * @param state */ protected void pathExecutorStateChange(PathExecutorState state) { switch (state) { case PATH_COMPUTATION_FAILED: // if path computation fails to whatever reason, just try another navpoint // taboo bad navpoint for 10 seconds tabooNavPoints.add(targetNavPoint, 10); break; case TARGET_REACHED: // taboo reached navpoint for 10 seconds tabooNavPoints.add(targetNavPoint, 10); break; case STUCK: // the bot has stuck! ... target nav point is unavailable currently tabooNavPoints.add(targetNavPoint, 30); break; case STOPPED: // path execution has stopped targetNavPoint = null; break; } } /** * Randomly picks some navigation point to head to. * * @return randomly choosed navpoint */ protected NavPoint getRandomNavPoint() { log.info("Picking new target navpoint."); // choose one feasible navpoint (== not belonging to tabooNavPoints) randomly NavPoint chosen = MyCollections.getRandomFiltered(navPoints.getNavPoints().values(), tabooNavPoints); if (chosen != null) { return chosen; } log.warning("All navpoints are tabooized at this moment, choosing navpoint randomly!"); // ok, all navpoints have been visited probably, try to pick one at random return MyCollections.getRandom(navPoints.getNavPoints().values()); } public static void main(String args[]) throws PogamutException { // Starts 1 bot // If you want to execute the whole Hide&Seek game/match, execute {@link HideAndSeekGame}. new UT2004BotRunner(HideAndSeekBot.class, "HSBot").setMain(true).setLogLevel(Level.WARNING).startAgents(1); } }