Changeset 48


Ignore:
Timestamp:
04/02/10 04:33:38 (12 years ago)
Author:
BegemoT
Message:
 
Location:
SnowBallBot/src/snowball
Files:
3 deleted
4 edited

Legend:

Unmodified
Added
Removed
  • SnowBallBot/src/snowball/BotRunner.java

    r47 r48  
    2222 */ 
    2323public class BotRunner implements Runnable, IProtocolListener { 
    24     private static final Log LOG = LogFactory.getLog( BotRunner.class ); 
    25  
    26     private final Log log; 
    27  
    28  
    29     private static final long QUERY_INFO_TIMEOUT = 240000;  //4min 
    30  
    31     //private static final long MAX_IDLE_TIMEOUT = 600000;    //10min 
    32  
    33     private static final long RECONNECT_TIMEOUT = 300000;    //5min 
    34  
    35     private static final double ONE_SHOT_DAMAGE = 10; 
    36     private static final int RECONNECT_DELAY = 10;//sec 
    37  
    38     private static final double MAX_TEMPERATURE = 37.0; 
    39     private static final double AVG_HEAT_ONCE = 7; 
    40  
    41     private static final int MIN_HEATER_TIMEOUT = 10000; 
    42     private static final int IDLE_FIGHT_DROP_TIMEOUT = 180000; 
    43  
    44     private final String name; 
    45  
    46     private final Protocol protocol; 
    47  
    48     private final IBehaviorStrategy strategy = new IBehaviorStrategy(){ 
    49  
    50     }; 
    51  
    52     private final PeopleRegistry peopleRegistry; 
    53     private final FightsList fights; 
    54  
    55     public BotRunner( final String name, 
    56                       final Protocol protocol, 
    57                       final PeopleRegistry peopleRegistry ) { 
    58         this.log = LogFactory.getLog( BotRunner.class.getName() + "[" + name + "]" ); 
    59         this.name = name; 
    60         this.protocol = protocol; 
    61         this.peopleRegistry = peopleRegistry; 
    62  
    63         protocol.addProtocolListener( this ); 
    64  
    65         enemyFinder = new EnemyFinder( 
    66                 name, 
    67                 peopleRegistry, 
    68                 protocol, 
    69                 new IPeopleFilter() { 
    70                     public boolean appropriate( final UnitInfo u ) { 
    71                         return isEnemyWeaker( u ) && u.experience() > 5; 
    72                     } 
    73                 }, 
    74                 Commons.EXPERIENCE_COMPARATOR 
    75         ); 
    76  
    77         fights = new FightsList( peopleRegistry ); 
    78     } 
    79  
    80     private transient volatile long lastResponseProcessed = -1; 
    81  
    82     public synchronized void run() { 
    83         try { 
    84             if ( lastResponseProcessed < 0 ) { 
    85                 log.info( "Stand up and ready for fight!" ); 
    86             } else { 
    87                 if ( !reconnectIfIdle() ) { 
    88                     final long ellapsed = System.currentTimeMillis() - lastResponseProcessed; 
    89                     if ( ellapsed > QUERY_INFO_TIMEOUT ) { 
    90                         log.info( "Was idle too long. Let's clearifying situation: Where am I?" ); 
    91                     } else { 
    92                         //just update my stats 
    93                     } 
    94                 } 
    95             } 
    96             queryMyInfo(); 
    97         } catch ( XMPPException e ) { 
    98             protocol.disconnect(); 
    99             log.error( "XMPP error", e ); 
    100         } catch ( Throwable t ) { 
    101             protocol.disconnect(); 
    102             log.error( "Unknown error", t ); 
    103         } 
    104     } 
    105  
    106  
    107     private Place place = Place.UNKNOWN; 
    108  
    109     private double temperature = 30; 
    110  
    111     private int experience = 120; 
    112  
    113  
    114  
    115     private void updateInfo( final UnitInfo info ) { 
    116         updatePlace( info.place() ); 
    117         updateTemperature( info.temperature() ); 
    118         this.experience = info.experience(); 
    119     } 
    120  
    121     private void updateTemperature( final double tmp ) { 
    122         this.temperature = tmp; 
    123     } 
    124  
    125     private void updatePlace( final Place place ) { 
    126         if ( this.place != place ) { 
    127             log.info( "place(" + this.place + " -> " + place + ")" ); 
    128             this.place = place; 
    129             if ( place != Place.STREET ) { 
    130                 fights.outOfFight(); 
    131             } 
    132         } 
    133     } 
    134  
    135     public synchronized void responsed( final Response r ) { 
    136         try { 
    137             switch ( r.kind() ) { 
    138                 case OWN_INFO: 
    139                     final UnitInfo iam = ( UnitInfo )r.data(); 
    140                     log.info( "\t <- info" + iam ); 
    141                     updateInfo( iam ); 
    142                     switch ( place ) { 
    143                         case SNOWDRIFT: 
    144                         case BAR: 
    145                             if ( isEnoughHealthForFight() ) { 
    146                                 playSnowball(); 
    147                             } else { 
    148                                 heatIfRequired(); 
    149                             } 
    150                             break; 
    151                         case STREET: 
    152                             heatIfRequired(); 
    153                             if ( !fights.empty() ) { 
    154                                 final String name = fights.actualEnemy(); 
    155                                 if ( name != null ) { 
    156                                     attack( name ); 
    157                                 } else { 
    158                                     for ( final Fight fight : fights ) { 
    159                                         switch ( fight.state() ) { 
    160                                             case FREE: 
    161                                             case I_ATTACKED_BY_OPPONENT: 
    162                                                 attack( fight.opponentName() ); 
    163                                                 break; 
    164                                             case OPPONENT_ATTACKED_BY_ME: 
    165                                                 final long age = fight.age(); 
    166                                                 if ( age >= IDLE_FIGHT_DROP_TIMEOUT ) { 
    167                                                     attack( fight.opponentName() ); 
    168                                                 } else { 
    169                                                     log.info( "waiting for strike back" ); 
    170                                                 } 
    171                                                 break; 
    172                                             default: 
    173                                                 throw new IllegalStateException( "Unknown state:" + fight.state() ); 
    174                                         } 
    175                                         break; 
    176                                     } 
    177                                 } 
    178                             } else if ( isEnoughHealthForFight() ) { 
    179                                 lookForEnemyPrefetch( true ); 
    180                             } else { 
    181                                 if ( !canHeatAtOnce() ) { 
    182                                     hideInBar(); 
    183                                 } 
    184                             } 
    185                             break; 
    186                     } 
    187                     break; 
    188                 case ENEMIES_LIST: { 
    189                     final List<String> people = ( List<String> )r.data(); 
    190                     log.info( "\t <- people(" + people.size() + ")" ); 
    191                     peopleRegistry.updatePeopleList( people ); 
    192                     updatePlace( Place.STREET ); 
    193                     lookForEnemyPrefetch( false ); 
    194                     break; 
    195                 } 
    196                 case ENEMY_INFO: { 
    197                     heatIfRequired(); 
    198                     final UnitInfo people = ( UnitInfo )r.data(); 
    199                     peopleRegistry.update( people ); 
    200                     log.info( "\t <- people info" + people ); 
    201                     //dont attack if we're already on fight 
    202                     if ( enemyFinder.isLooking() ) { 
    203                         enemyFinder.update( people ); 
    204                         if ( !enemyFinder.isLooking() ) { 
    205                             final String enemy = enemyFinder.chooseOpponent(); 
    206                             final UnitInfo info = peopleRegistry.get( enemy ); 
    207                             log.info( "opponent choosen: " + info ); 
    208                             attack( enemy ); 
    209                         } 
    210                     } else { 
    211                         if ( peopleRegistry.isMostWanted( people.name() ) ) { 
    212                             //todo call for help! 
    213                         } 
    214                     } 
    215                     break; 
    216                 } 
    217                 case STREET_COME_CONFIRMED: 
    218                 case THROWN_OUT_OF_BAR: 
    219                     log.info( "\t <- on the street" ); 
    220                     updatePlace( Place.STREET ); 
    221                     heatIfRequired(); 
    222                     if ( isEnoughHealthForFight() || canHeatAtOnce() ) { 
    223                         final String enemy = fights.actualEnemy(); 
    224                         if ( enemy != null ) { 
    225                             //continue with such bastard 
    226                             attack( enemy ); 
    227                         } else { 
    228                             lookForEnemyPrefetch( true ); 
    229                         } 
    230                     } else { 
    231                         hideInBar(); 
    232                     } 
    233                     break; 
    234                 case ENEMY_ATTACKED_CONFIRMED: 
    235                     final String name = ( String )r.data(); 
    236                     log.info( "\t <- attacked(" + name + ")" ); 
    237                     updatePlace( Place.STREET ); 
    238                     fights.attackedConfirmed( name ); 
    239                     break; 
    240                 case ENEMY_STRIKED_BACK: { 
    241                     final EnemyStrikeBack eres = ( EnemyStrikeBack )r.data(); 
    242                     updatePlace( Place.STREET ); 
    243                     final String enemy = eres.enemyName(); 
    244                     fights.opponentStrikedBack( enemy ); 
    245                     temperature -= eres.ownHealthLost(); 
    246  
    247                     log.info( "\t <- strike back(" + enemy + " [-" + eres.enemyHealthLost() + "]/ myself [-" + eres.ownHealthLost() + "])" ); 
    248                     if ( isDangerous() ) { 
    249                         log.info( "It seems to be dangerous on the street -> go bar" ); 
    250                         tryToHideInBar(); 
    251                     } else if ( isVeryLowHealth() ) { 
    252                         log.info( "It seems to be cold(" + temperature + ") on the street -> go bar" ); 
    253                         tryToHideInBar(); 
    254                     } else { 
    255                         heatIfRequired(); 
    256                         attackCurrent(); 
    257                     } 
    258                     break; 
    259                 } 
    260                 case ENEMY_ESCAPED: { 
    261                     final String enemy = ( String )r.data(); 
    262                     updatePlace( Place.STREET ); 
    263                     fights.opponentEscaped( enemy ); 
     24        private static final Log LOG = LogFactory.getLog( BotRunner.class ); 
     25 
     26        private final Log log; 
     27 
     28 
     29        private static final long QUERY_INFO_TIMEOUT = 240000;  //4min 
     30 
     31        //private static final long MAX_IDLE_TIMEOUT = 600000;    //10min 
     32 
     33        private static final long RECONNECT_TIMEOUT = 300000;    //5min 
     34 
     35        private static final double ONE_SHOT_DAMAGE = 10; 
     36        private static final int RECONNECT_DELAY = 10;//sec 
     37 
     38        private static final double MAX_TEMPERATURE = 37.0; 
     39        private static final double AVG_HEAT_ONCE = 7; 
     40 
     41        private static final int MIN_HEATER_TIMEOUT = 10000; 
     42        private static final int IDLE_FIGHT_DROP_TIMEOUT = 180000; 
     43 
     44        private final String name; 
     45 
     46        private final Protocol protocol; 
     47 
     48        private final IBehaviorStrategy strategy = new IBehaviorStrategy() { 
     49 
     50        }; 
     51 
     52        private final PeopleRegistry peopleRegistry; 
     53        private final FightsList fights; 
     54 
     55        public BotRunner( final String name, 
     56                          final Protocol protocol, 
     57                          final PeopleRegistry peopleRegistry ) { 
     58                this.log = LogFactory.getLog( BotRunner.class.getName() + "[" + name + "]" ); 
     59                this.name = name; 
     60                this.protocol = protocol; 
     61                this.peopleRegistry = peopleRegistry; 
     62 
     63                protocol.addProtocolListener( this ); 
     64 
     65                enemyFinder = new EnemyFinder( 
     66                                name, 
     67                                peopleRegistry, 
     68                                protocol, 
     69                                new IPeopleFilter() { 
     70                                        public boolean appropriate( final UnitInfo u ) { 
     71                                                return isEnemyWeaker( u ) && u.experience() >= 0; 
     72                                        } 
     73                                }, 
     74                                Commons.EXPERIENCE_COMPARATOR 
     75                ); 
     76 
     77                fights = new FightsList( peopleRegistry ); 
     78        } 
     79 
     80        private transient volatile long lastResponseProcessed = -1; 
     81 
     82        public synchronized void run() { 
     83                try { 
     84                        if( lastResponseProcessed < 0 ) { 
     85                                log.info( "Stand up and ready for fight!" ); 
     86                        } else { 
     87                                if( !reconnectIfIdle() ) { 
     88                                        final long ellapsed = System.currentTimeMillis() - lastResponseProcessed; 
     89                                        if( ellapsed > QUERY_INFO_TIMEOUT ) { 
     90                                                log.info( "Was idle too long. Let's clearifying situation: Where am I?" ); 
     91                                        } else { 
     92                                                //just update my stats 
     93                                        } 
     94                                } 
     95                        } 
     96                        queryMyInfo(); 
     97                } catch( XMPPException e ) { 
     98                        protocol.disconnect(); 
     99                        log.error( "XMPP error", e ); 
     100                } catch( Throwable t ) { 
     101                        protocol.disconnect(); 
     102                        log.error( "Unknown error", t ); 
     103                } 
     104        } 
     105 
     106 
     107        private Place place = Place.UNKNOWN; 
     108 
     109        private double temperature = 30; 
     110 
     111        private int experience = 120; 
     112 
     113 
     114        private void updateInfo( final UnitInfo info ) { 
     115                updatePlace( info.place() ); 
     116                updateTemperature( info.temperature() ); 
     117                this.experience = info.experience(); 
     118        } 
     119 
     120        private void updateTemperature( final double tmp ) { 
     121                this.temperature = tmp; 
     122        } 
     123 
     124        private void updatePlace( final Place place ) { 
     125                if( this.place != place ) { 
     126                        log.info( "place(" + this.place + " -> " + place + ")" ); 
     127                        this.place = place; 
     128                        if( place != Place.STREET ) { 
     129                                fights.outOfFight(); 
     130                        } 
     131                } 
     132        } 
     133 
     134        public synchronized void responsed( final Response r ) { 
     135                try { 
     136                        switch( r.kind() ) { 
     137                                case OWN_INFO: 
     138                                        final UnitInfo iam = ( UnitInfo ) r.data(); 
     139                                        log.info( "\t <- info" + iam ); 
     140                                        updateInfo( iam ); 
     141                                        switch( place ) { 
     142                                                case SNOWDRIFT: 
     143                                                case BAR: 
     144                                                        if( isEnoughHealthForFight() ) { 
     145                                                                playSnowball(); 
     146                                                        } else { 
     147                                                                heatIfRequired(); 
     148                                                        } 
     149                                                        break; 
     150                                                case STREET: 
     151                                                        heatIfRequired(); 
     152                                                        if( !fights.empty() ) { 
     153                                                                final Fight name = fights.actualEnemy(); 
     154                                                                if( name != null ) { 
     155                                                                        attackCurrent(); 
     156                                                                } else { 
     157                                                                        for( final Fight fight : fights ) { 
     158                                                                                switch( fight.state() ) { 
     159                                                                                        case FREE: 
     160                                                                                        case I_ATTACKED_BY_OPPONENT: 
     161                                                                                                attack( fight.opponentName() ); 
     162                                                                                                break; 
     163                                                                                        case OPPONENT_ATTACKED_BY_ME: 
     164                                                                                                final long age = fight.age(); 
     165                                                                                                if( age >= IDLE_FIGHT_DROP_TIMEOUT ) { 
     166                                                                                                        attack( fight.opponentName() ); 
     167                                                                                                } else { 
     168                                                                                                        log.info( "waiting for strike back" ); 
     169                                                                                                } 
     170                                                                                                break; 
     171                                                                                        default: 
     172                                                                                                throw new IllegalStateException( "Unknown state:" + fight.state() ); 
     173                                                                                } 
     174                                                                                break; 
     175                                                                        } 
     176                                                                } 
     177                                                        } else if( isEnoughHealthForFight() ) { 
     178                                                                lookForEnemyPrefetch( true ); 
     179                                                        } else { 
     180                                                                if( !canHeatAtOnce() ) { 
     181                                                                        hideInBar(); 
     182                                                                } 
     183                                                        } 
     184                                                        break; 
     185                                        } 
     186                                        break; 
     187                                case ENEMIES_LIST: { 
     188                                        final List<String> people = ( List<String> ) r.data(); 
     189                                        log.info( "\t <- people(" + people.size() + ")" ); 
     190                                        peopleRegistry.updatePeopleList( people ); 
     191                                        updatePlace( Place.STREET ); 
     192                                        lookForEnemyPrefetch( false ); 
     193                                        break; 
     194                                } 
     195                                case ENEMY_INFO: { 
     196                                        heatIfRequired(); 
     197                                        final UnitInfo people = ( UnitInfo ) r.data(); 
     198                                        peopleRegistry.update( people ); 
     199                                        log.info( "\t <- people info" + people ); 
     200                                        //dont attack if we're already on fight 
     201                                        if( enemyFinder.isLooking() ) { 
     202                                                enemyFinder.update( people ); 
     203                                                if( !enemyFinder.isLooking() ) { 
     204                                                        final String enemy = enemyFinder.chooseOpponent(); 
     205                                                        final UnitInfo info = peopleRegistry.get( enemy ); 
     206                                                        log.info( "opponent choosen: " + info ); 
     207                                                        attack( enemy ); 
     208                                                } 
     209                                        } else { 
     210                                                if( peopleRegistry.isMostWanted( people.name() ) ) { 
     211                                                        //todo call for help! 
     212                                                } 
     213                                        } 
     214                                        break; 
     215                                } 
     216                                case STREET_COME_CONFIRMED: 
     217                                case THROWN_OUT_OF_BAR: 
     218                                        log.info( "\t <- on the street" ); 
     219                                        updatePlace( Place.STREET ); 
     220                                        heatIfRequired(); 
     221                                        if( isEnoughHealthForFight() || canHeatAtOnce() ) { 
     222                                                final Fight enemy = fights.actualEnemy(); 
     223                                                if( enemy != null ) { 
     224                                                        //continue with such bastard 
     225                                                        attackCurrent(); 
     226                                                } else { 
     227                                                        lookForEnemyPrefetch( true ); 
     228                                                } 
     229                                        } else { 
     230                                                hideInBar(); 
     231                                        } 
     232                                        break; 
     233                                case ENEMY_ATTACKED_CONFIRMED: 
     234                                        final String name = ( String ) r.data(); 
     235                                        log.info( "\t <- attacked(" + name + ")" ); 
     236                                        updatePlace( Place.STREET ); 
     237                                        fights.attackedConfirmed( name ); 
     238                                        break; 
     239                                case ENEMY_STRIKED_BACK: { 
     240                                        final EnemyStrikeBack eres = ( EnemyStrikeBack ) r.data(); 
     241                                        updatePlace( Place.STREET ); 
     242                                        final String enemy = eres.enemyName(); 
     243                                        fights.opponentStrikedBack( enemy ); 
     244                                        temperature -= eres.ownHealthLost(); 
     245 
     246                                        log.info( "\t <- strike back(" + enemy + " [-" + eres.enemyHealthLost() + "]/ myself [-" + eres.ownHealthLost() + "])" ); 
     247                                        if( isDangerous() ) { 
     248                                                log.info( "It seems to be dangerous on the street -> go bar" ); 
     249                                                tryToHideInBar(); 
     250                                        } else if( isVeryLowHealth() ) { 
     251                                                log.info( "It seems to be cold(" + temperature + ") on the street -> go bar" ); 
     252                                                tryToHideInBar(); 
     253                                        } else { 
     254                                                heatIfRequired(); 
     255                                                attackCurrent(); 
     256                                        } 
     257                                        break; 
     258                                } 
     259                                case ENEMY_ESCAPED: { 
     260                                        final String enemy = ( String ) r.data(); 
     261                                        updatePlace( Place.STREET ); 
     262                                        fights.opponentEscaped( enemy ); 
    264263//                                      temperature -= eres.ownHealthLost(); 
    265264 
    266                     log.info( "\t <- escaped(" + enemy + ")" ); 
    267  
    268                     heatIfRequired(); 
    269                     attackCurrent(); 
    270                     break; 
    271                 } 
    272                 case ENEMY_ESCAPING: { 
    273                     final EnemyStrikeBack eres = ( EnemyStrikeBack )r.data(); 
    274                     updatePlace( Place.STREET ); 
    275                     //updateState( State.IN_THE_FIGHT ); 
    276                     final String enemy = eres.enemyName(); 
    277                     fights.opponentEscaped( enemy ); 
     265                                        log.info( "\t <- escaped(" + enemy + ")" ); 
     266 
     267                                        heatIfRequired(); 
     268                                        attackCurrent(); 
     269                                        break; 
     270                                } 
     271                                case ENEMY_ESCAPING: { 
     272                                        final EnemyStrikeBack eres = ( EnemyStrikeBack ) r.data(); 
     273                                        updatePlace( Place.STREET ); 
     274                                        //updateState( State.IN_THE_FIGHT ); 
     275                                        final String enemy = eres.enemyName(); 
     276                                        fights.opponentEscaped( enemy ); 
    278277//                                      temperature -= eres.ownHealthLost(); 
    279278 
    280                     log.info( "\t <- escaping(" + enemy + " [-" + eres.enemyHealthLost() + "])" ); 
    281  
    282                     heatIfRequired(); 
    283                     attackCurrent(); 
    284                     break; 
    285                 } 
    286                 case I_AM_ATTACKED: { 
    287                     final String enemy = ( String )r.data(); 
    288                     fights.wasAttackedBy( enemy ); 
    289                     log.info( "\t <- attacked by(" + enemy + ")" ); 
    290                     updatePlace( Place.STREET ); 
    291                     if ( fights.activeFights() == 1 ) { 
    292                         if ( fights.size() == 1 && isEnoughHealthForFight() ) { 
    293                             //ìî÷è óáëþäêà! 
    294                             attack( enemy ); 
    295                         } else { 
    296                             //ìû íè÷åì _êðîìå_ îòâåòà íå ñâÿçàíû -- ìîæåì ñâàëèòü 
    297                             if ( temperature > ONE_SHOT_DAMAGE ) { 
    298                                 attack( enemy ); 
    299                             } else { 
    300                                 escape(); 
    301                             } 
    302                             hideInBar(); 
    303                         } 
    304                     } else { 
    305                         //ïðîñòî æäåì, ïîêà îñâîáîäèìñÿ 
    306                         //todo çâàòü íà ïîìîùü? 
    307                     } 
    308                     break; 
    309                 } 
    310                 case ENEMY_KILLED: 
    311                 case ENEMY_NOT_AVAILABLE: { 
    312                     final String enemy = ( String )r.data(); 
    313                     if ( r.kind() == ENEMY_KILLED ) { 
    314                         fights.opponentKilled( enemy ); 
    315                         log.info( "\t <- killed(" + enemy + ")" ); 
    316                     } else { 
    317                         if ( enemy == null ) { 
    318                             final Fight fight = fights.opponentNotAvailable(); 
    319                             if ( fight != null ) { 
    320                                 log.info( "\t <- not found(" + fight.opponentName() + "?)" ); 
    321                             } else { 
    322                                 log.info( "\t <- not found(???)" ); 
    323                             } 
    324                         } else { 
    325                             fights.opponentNotAvailable( enemy ); 
    326                             log.info( "\t <- not found(" + enemy + ")" ); 
    327                         } 
    328                     } 
    329                     updatePlace( Place.STREET ); 
    330                     //updateState( State.ON_THE_AIR ); 
    331                     heatIfRequired(); 
    332                     if ( isEnoughHealthForFight() || canHeatAtOnce() ) { 
    333                         lookForEnemyPrefetch( true ); 
    334                     } else { 
    335                         hideInBar(); 
    336                     } 
    337                     break; 
    338                 } 
    339                 case IN_SNOWDRIFT: 
    340                     log.info( "\t <- in snowdrift" ); 
    341                     updatePlace( Place.SNOWDRIFT ); 
    342                     playSnowball(); 
    343                     break; 
    344                 case IN_BAR: 
    345                     log.info( "\t <- in bar" ); 
    346                     updatePlace( Place.BAR ); 
    347                     heatIfRequired(); 
    348                     if ( isEnoughHealthForFight() ) { 
    349                         playSnowball(); 
    350                     } 
    351                     break; 
    352                 case HEATED_CONFIRMED: { 
    353                     final double temp = ( Double )r.data(); 
    354                     log.info( "\t <- heated(" + temp + ")" ); 
    355                     updateTemperature( temp ); 
    356                     if ( isEnoughHealthForFight() ) { 
    357                         if ( fights.empty() ) { 
    358                             if ( place != Place.STREET ) { 
    359                                 playSnowball(); 
    360                             } else { 
    361                                 queryNeighbours(); 
    362                             } 
    363                         } else { 
    364                             /*for( final Fight f : fights.fights() ) { 
    365                                        if( f.state() == Fight.State.I_ATTACKED_BY_OPPONENT ) { 
    366                                            attack( f.opponentName() ); 
    367                                        } 
    368                                    }*/ 
    369                             final String opponent = fights.actualEnemy(); 
    370                             if ( opponent != null ) { 
    371                                 attack( opponent ); 
    372                             } 
    373                             //todo íàäî êàê-òî ïðîäîëæèòü ñâàëêó? 
    374                         } 
    375                     } else { 
    376                         if ( place == Place.STREET && fights.isFree() ) { 
    377                             hideInBar(); 
    378                         } 
    379                         heatIfRequired(); 
    380                     } 
    381                 } 
    382                 break; 
    383                 case HEATER_DEPLETED: 
    384                     log.info( "\t <- heated depeleted" ); 
    385                     if ( place == Place.STREET ) { 
    386                         if ( fights.empty() ) { 
    387                             hideInBar(); 
    388                         } 
    389                         if ( isLowHealth() ) { 
    390                             if ( fights.canMove() ) { 
    391                                 hideInBar(); 
    392                             } else if ( fights.activeFights() > 1 ) { 
    393                                 tryToHideInBar(); 
    394                             } 
    395                         } 
    396                     } 
    397                     //and just wait for heater to refill 
    398                     break; 
    399                 case HEATER_CANT_BE_USED: 
    400                     log.info( "\t <- can't use heater(waiting for strikeback)" ); 
    401                     if ( place == Place.STREET ) { 
    402                         updatePlace( Place.STREET ); 
    403                         //just waiting for response to know, 
    404                         //who is the enemy 
    405                     } 
    406                     break; 
    407                 case REANIMATED_IN_BAR: 
    408                     updatePlace( Place.BAR ); 
    409                     playSnowball(); 
    410                     updateTemperature( MAX_TEMPERATURE ); 
    411                     break; 
    412                 case I_AM_KILLED: { 
    413                     final String enemy = ( String )r.data(); 
    414                     log.info( "\t <- I was killed by (" + enemy + ")" ); 
    415                     updatePlace( Place.REANIMATION ); 
    416                     updateTemperature( 0 ); 
    417                     fights.iWasKilled( enemy ); 
    418                     //just waiting 
    419                     break; 
    420                 } 
    421                 case IN_BAR_COME_CONFIRMED: 
    422                     updatePlace( Place.BAR ); 
    423                     heatIfRequired(); 
    424                     if ( isEnoughHealthForFight() ) { 
    425                         playSnowball(); 
    426                     } 
    427                     break; 
    428                 case BAR_ALREADY: 
    429                     log.info( "\t <- already in bar" ); 
    430                     updatePlace( Place.BAR ); 
    431                     break; 
    432                 case SNOWDRIFT_ALREADY: 
    433                     log.info( "\t <- already in snowdrift" ); 
    434                     updatePlace( Place.SNOWDRIFT ); 
    435                     break; 
    436                 case STREET_ALREADY: 
    437                     log.info( "\t <- already on the street" ); 
    438                     updatePlace( Place.STREET ); 
    439                     //todo continue fight 
    440                     break; 
    441                 case ENEMY_ALREADY_ATTACKED: 
    442                     log.info( "\t <- was already attacked" ); 
    443                     //updateState( State.ATTACKED ); 
    444                     updatePlace( Place.STREET ); 
    445                     break; 
    446                 case HEATER_USELESS: 
    447                     log.info( "\t <- heater useless (max temp)" ); 
    448                     updateTemperature( MAX_TEMPERATURE ); 
    449                     //nothing to do 
    450                     break; 
    451                 case CANT_ESCAPE: 
    452                     log.info( "\t <- I can't escape" ); 
    453                     updatePlace( Place.STREET ); 
    454                     //nothing to do 
    455                     break; 
    456                 case I_AM_ESCAPED: 
    457                     log.info( "\t <- I'm escaped" ); 
    458                     updatePlace( Place.STREET ); 
    459                     break; 
    460                 case IN_REANIMATION: 
    461                     log.info( "\t <- in reanimation" ); 
    462                     updatePlace( Place.REANIMATION ); 
    463                     updateTemperature( 0 ); 
    464                     break; 
    465                 case GOT_SUPERBALL: 
    466                     log.info( "\t <- got superball. happy" ); 
    467                     break; 
    468                 case UNRECOGNIZED: 
    469                     log.warn( "\t <- UNRECOGNIZED: " + r.message() ); 
    470                     break; 
    471                 default: 
    472                     log.info( "\t <- NOT PROCESSED: " + r.kind() ); 
    473             } 
    474         } catch ( Throwable e ) { 
    475             log.error( "Error sending message", e ); 
    476         } finally { 
    477             lastResponseProcessed = System.currentTimeMillis(); 
    478             printState(); 
    479         } 
    480     } 
    481  
    482     private boolean tryToHideInBar() throws Exception { 
    483         if ( !fights.canMove() ) { 
    484             if ( !fights.isWaitingForOpponent() ) { 
    485                 final boolean lowHealth = temperature / fights.activeFights() < ONE_SHOT_DAMAGE; 
    486                 for ( final Fight fight : fights ) { 
    487                     if ( fight.state() == Fight.State.I_ATTACKED_BY_OPPONENT ) { 
    488                         if ( lowHealth ) { 
    489                             escape(); 
    490                         } else { 
    491                             attack( fight.opponentName() ); 
    492                         } 
    493                     } 
    494                 } 
    495             } else { 
    496                 //continue to wait for strike back 
    497                 return false; 
    498             } 
    499         } 
    500         if ( fights.canMove() ) { 
    501             hideInBar(); 
    502             heatIfRequired(); 
    503             return true; 
    504         } else { 
    505             return false; 
    506         } 
    507     } 
    508  
    509     private boolean isDangerous() { 
    510         return fights.isDangerous(); 
    511     } 
    512  
    513     private boolean canHeatAtOnce() { 
    514         return MAX_TEMPERATURE - temperature <= AVG_HEAT_ONCE; 
    515     } 
    516  
    517     public void escape() throws Exception { 
    518         protocol.escape(); 
    519     } 
    520  
    521     public void queryMyInfo() throws Exception { 
    522         protocol.queryMyInfo(); 
    523         log.info( " -> info(myself)" ); 
    524     } 
    525  
    526     public void queryNeighbours() throws Exception { 
    527         protocol.queryNeighbours(); 
    528         log.info( " -> lookAround (@" + place + ", " + temperature + ")" ); 
    529     } 
    530  
    531     public void playSnowball() throws Exception { 
    532         fights.dropOutOld( IDLE_FIGHT_DROP_TIMEOUT ); 
    533         protocol.play(); 
    534         log.info( " -> play (from " + place + ", temp " + temperature + ")" ); 
    535     } 
    536  
    537     private boolean isEnoughHealthForFight() { 
    538         return temperature >= MAX_TEMPERATURE - 4; 
    539     } 
    540  
    541     private boolean isLowHealth() { 
    542         return temperature <= MAX_TEMPERATURE / 2; 
    543     } 
    544  
    545     private boolean isVeryLowHealth() { 
    546         return temperature < ONE_SHOT_DAMAGE; 
    547     } 
    548  
    549     private boolean isEnemyWeaker( final UnitInfo enemy ) { 
    550         final double ep = Commons.enemyPower( enemy.experience() ); 
    551         final double mp = Commons.enemyPower( experience ); 
    552         return ep <= mp /*&& isEnoughHealthForFight()*/; 
    553     } 
    554  
    555     public void hideInBar() throws Exception { 
    556         protocol.moveBar(); 
    557         log.info( " -> bar (temp:" + temperature + ")" ); 
    558     } 
    559  
    560     private long lastAttack = -1; 
    561  
    562     public void attack( final String name ) throws Exception { 
    563         enemyFinder.clear(); 
    564         fights.attacked( name ); 
    565         protocol.attack( name ); 
    566         lastAttack = System.currentTimeMillis(); 
    567         log.info( " -> attack(" + name + ")" ); 
    568     } 
    569  
    570     private void attackCurrent() throws Exception { 
    571         if ( !fights.empty() ) { 
    572 //                      for( final Fight fight : fights.fights() ) { 
    573 //                              attack( fight.opponentName() ); 
    574 //                              break; 
    575 //                      } 
    576             final String enemy = fights.actualEnemy(); 
    577             if ( enemy != null ) { 
    578                 attack( enemy ); 
    579             } 
    580         } else { 
    581             log.info( "no current enemy -- attack skipped" ); 
    582         } 
    583     } 
    584  
    585     private long lastHeaterUsed = -1; 
    586  
    587     private void heatIfRequired() throws Exception { 
    588         if ( !isEnoughHealthForFight() ) { 
    589             final long age = System.currentTimeMillis() - lastHeaterUsed; 
    590             if ( age <= MIN_HEATER_TIMEOUT ) { 
    591                 //skip 
    592                 log.info( "heater using skipped" ); 
    593                 return; 
    594             } 
    595             if ( canHeal() ) { 
    596                 protocol.useHeater(); 
    597                 log.info( " -> use heater (" + temperature + ")" ); 
    598                 lastHeaterUsed = System.currentTimeMillis(); 
    599             } 
    600         } 
    601     } 
    602  
    603     private boolean canHeal() { 
    604         switch ( place ) { 
    605             case BAR: 
    606                 return true; 
    607             case STREET: 
    608                 return fights.canUseHeater(); 
    609             case SNOWDRIFT: 
    610             case REANIMATION: 
    611                 return false; 
    612             default: 
    613                 throw new IllegalStateException( "Unknown place:" + place ); 
    614         } 
    615     } 
    616  
    617     private final EnemyFinder enemyFinder; 
    618  
    619     private void lookForEnemyPrefetch( final boolean forceRequery ) throws Exception { 
    620         if ( enemyFinder.isLooking() && !enemyFinder.isExpired() ) { 
    621             log.info( "Already looking for enemies -- skipped" ); 
    622             return; 
    623         } 
    624  
    625         enemyFinder.clear(); 
    626         if ( forceRequery || peopleRegistry.peopleListExpired() ) { 
    627             queryNeighbours(); 
    628         } else { 
    629             enemyFinder.investigate(); 
    630         } 
    631     } 
    632  
    633     public boolean reconnectIfIdle() { 
    634         final long ellapsed = System.currentTimeMillis() - lastResponseProcessed; 
    635         if ( ellapsed > RECONNECT_TIMEOUT ) { 
    636             log.info( "Too long idle -- reconnect" ); 
    637             reconnect(); 
    638             return true; 
    639         } else { 
    640             return false; 
    641         } 
    642     } 
    643  
    644     public void reconnect() { 
    645         protocol.disconnect(); 
    646         try { 
    647             Thread.sleep( RECONNECT_DELAY ); 
    648             protocol.ensureConnected(); 
    649         } catch ( Exception e ) { 
    650             log.error( "Error reconnecting", e ); 
    651         } 
    652     } 
    653  
    654     public Protocol getProtocol() { 
    655         return protocol; 
    656     } 
    657  
    658     private void printState() { 
    659         log.info( 
    660                 String.format( 
    661                         "%s(@%s, %f\u00B0, %d) %s", 
    662                         name, 
    663                         place, temperature, experience, 
    664                         fights 
    665                 ) 
    666         ); 
    667     } 
    668  
    669     public String name() { 
    670         return name; 
    671     } 
    672  
    673     @Override 
    674     public String toString() { 
    675         return String.format( 
    676                 "%s(@%s, %f\u00B0, %d) %s", 
    677                 name, 
    678                 place, temperature, experience, 
    679                 fights 
    680         ); 
    681     } 
    682  
    683     public static BotRunner startBot( final String name, 
    684                                       final PeopleRegistry peopleRegistry, 
    685                                       final Protocol protocol ) { 
    686         final BotRunner runner = new BotRunner( name, protocol, peopleRegistry ); 
    687  
    688  
    689         return runner; 
    690     } 
     279                                        log.info( "\t <- escaping(" + enemy + " [-" + eres.enemyHealthLost() + "])" ); 
     280 
     281                                        heatIfRequired(); 
     282                                        attackCurrent(); 
     283                                        break; 
     284                                } 
     285                                case I_AM_ATTACKED: { 
     286                                        final String enemy = ( String ) r.data(); 
     287                                        fights.wasAttackedBy( enemy ); 
     288                                        log.info( "\t <- attacked by(" + enemy + ")" ); 
     289                                        updatePlace( Place.STREET ); 
     290                                        if( fights.activeFights() == 1 ) { 
     291                                                if( fights.size() == 1 && isEnoughHealthForFight() ) { 
     292                                                        //ìî÷è óáëþäêà! 
     293                                                        attack( enemy ); 
     294                                                } else { 
     295                                                        //ìû íè÷åì _êðîìå_ îòâåòà íå ñâÿçàíû -- ìîæåì ñâàëèòü 
     296                                                        if( temperature > ONE_SHOT_DAMAGE ) { 
     297                                                                attack( enemy ); 
     298                                                        } else { 
     299                                                                escape(); 
     300                                                        } 
     301                                                        hideInBar(); 
     302                                                } 
     303                                        } else { 
     304                                                //ïðîñòî æäåì, ïîêà îñâîáîäèìñÿ 
     305                                                //todo çâàòü íà ïîìîùü? 
     306                                        } 
     307                                        break; 
     308                                } 
     309                                case ENEMY_KILLED: 
     310                                case ENEMY_NOT_AVAILABLE: { 
     311                                        final String enemy = ( String ) r.data(); 
     312                                        if( r.kind() == ENEMY_KILLED ) { 
     313                                                fights.opponentKilled( enemy ); 
     314                                                log.info( "\t <- killed(" + enemy + ")" ); 
     315                                        } else { 
     316                                                if( enemy == null ) { 
     317                                                        final Fight fight = fights.opponentNotAvailable(); 
     318                                                        if( fight != null ) { 
     319                                                                log.info( "\t <- not found(" + fight.opponentName() + "?)" ); 
     320                                                        } else { 
     321                                                                log.info( "\t <- not found(???)" ); 
     322                                                        } 
     323                                                } else { 
     324                                                        fights.opponentNotAvailable( enemy ); 
     325                                                        log.info( "\t <- not found(" + enemy + ")" ); 
     326                                                } 
     327                                        } 
     328                                        updatePlace( Place.STREET ); 
     329                                        heatIfRequired(); 
     330                                        if( isEnoughHealthForFight() || canHeatAtOnce() ) { 
     331                                                if( fights.empty() ) { 
     332                                                        lookForEnemyPrefetch( true ); 
     333                                                } else { 
     334                                                        attackCurrent(); 
     335                                                } 
     336                                        } else { 
     337                                                hideInBar(); 
     338                                        } 
     339                                        break; 
     340                                } 
     341                                case IN_SNOWDRIFT: 
     342                                        log.info( "\t <- in snowdrift" ); 
     343                                        updatePlace( Place.SNOWDRIFT ); 
     344                                        playSnowball(); 
     345                                        break; 
     346                                case IN_BAR: 
     347                                        log.info( "\t <- in bar" ); 
     348                                        updatePlace( Place.BAR ); 
     349                                        heatIfRequired(); 
     350                                        if( isEnoughHealthForFight() ) { 
     351                                                playSnowball(); 
     352                                        } 
     353                                        break; 
     354                                case HEATED_CONFIRMED: { 
     355                                        final double temp = ( Double ) r.data(); 
     356                                        log.info( "\t <- heated(" + temp + ")" ); 
     357                                        updateTemperature( temp ); 
     358                                        if( isEnoughHealthForFight() ) { 
     359                                                if( fights.empty() ) { 
     360                                                        if( place != Place.STREET ) { 
     361                                                                playSnowball(); 
     362                                                        } else { 
     363                                                                queryNeighbours(); 
     364                                                        } 
     365                                                } else { 
     366                                                        attackCurrent(); 
     367//                                                      final Fight opponent = fights.actualEnemy(); 
     368//                                                      if( opponent != null ) { 
     369//                                                              attackCurrent(); 
     370//                                                      } 
     371                                                        //íàäî êàê-òî ïðîäîëæèòü ñâàëêó? 
     372                                                } 
     373                                        } else { 
     374                                                if( place == Place.STREET && fights.isFree() ) { 
     375                                                        hideInBar(); 
     376                                                } 
     377                                                heatIfRequired(); 
     378                                        } 
     379                                } 
     380                                break; 
     381                                case HEATER_DEPLETED: 
     382                                        log.info( "\t <- heated depeleted" ); 
     383                                        if( place == Place.STREET ) { 
     384                                                if( fights.empty() ) { 
     385                                                        hideInBar(); 
     386                                                } 
     387                                                if( isLowHealth() ) { 
     388                                                        if( fights.canMove() ) { 
     389                                                                hideInBar(); 
     390                                                        } else if( fights.activeFights() > 1 ) { 
     391                                                                tryToHideInBar(); 
     392                                                        } 
     393                                                } 
     394                                        } 
     395                                        //and just wait for heater to refill 
     396                                        break; 
     397                                case HEATER_CANT_BE_USED: 
     398                                        log.info( "\t <- can't use heater(waiting for strikeback)" ); 
     399                                        if( place == Place.STREET ) { 
     400                                                updatePlace( Place.STREET ); 
     401                                                //just waiting for response to know, 
     402                                                //who is the enemy 
     403                                        } 
     404                                        break; 
     405                                case REANIMATED_IN_BAR: 
     406                                        updatePlace( Place.BAR ); 
     407                                        playSnowball(); 
     408                                        updateTemperature( MAX_TEMPERATURE ); 
     409                                        break; 
     410                                case I_AM_KILLED: { 
     411                                        final String enemy = ( String ) r.data(); 
     412                                        log.info( "\t <- I was killed by (" + enemy + ")" ); 
     413                                        updatePlace( Place.REANIMATION ); 
     414                                        updateTemperature( 0 ); 
     415                                        fights.iWasKilled( enemy ); 
     416                                        //just waiting 
     417                                        break; 
     418                                } 
     419                                case IN_BAR_COME_CONFIRMED: 
     420                                        updatePlace( Place.BAR ); 
     421                                        heatIfRequired(); 
     422                                        if( isEnoughHealthForFight() ) { 
     423                                                playSnowball(); 
     424                                        } 
     425                                        break; 
     426                                case BAR_ALREADY: 
     427                                        log.info( "\t <- already in bar" ); 
     428                                        updatePlace( Place.BAR ); 
     429                                        break; 
     430                                case SNOWDRIFT_ALREADY: 
     431                                        log.info( "\t <- already in snowdrift" ); 
     432                                        updatePlace( Place.SNOWDRIFT ); 
     433                                        break; 
     434                                case STREET_ALREADY: 
     435                                        log.info( "\t <- already on the street" ); 
     436                                        updatePlace( Place.STREET ); 
     437                                        //todo continue fight 
     438                                        break; 
     439                                case ENEMY_ALREADY_ATTACKED: 
     440                                        log.info( "\t <- was already attacked" ); 
     441                                        //updateState( State.ATTACKED ); 
     442                                        updatePlace( Place.STREET ); 
     443                                        break; 
     444                                case HEATER_USELESS: 
     445                                        log.info( "\t <- heater useless (max temp)" ); 
     446                                        updateTemperature( MAX_TEMPERATURE ); 
     447                                        //nothing to do 
     448                                        break; 
     449                                case CANT_ESCAPE: 
     450                                        log.info( "\t <- I can't escape" ); 
     451                                        updatePlace( Place.STREET ); 
     452                                        //nothing to do 
     453                                        break; 
     454                                case I_AM_ESCAPED: 
     455                                        log.info( "\t <- I'm escaped" ); 
     456                                        updatePlace( Place.STREET ); 
     457                                        break; 
     458                                case IN_REANIMATION: 
     459                                        log.info( "\t <- in reanimation" ); 
     460                                        updatePlace( Place.REANIMATION ); 
     461                                        updateTemperature( 0 ); 
     462                                        break; 
     463                                case GOT_SUPERBALL: 
     464                                        log.info( "\t <- got superball. happy" ); 
     465                                        break; 
     466                                case UNRECOGNIZED: 
     467                                        log.warn( "\t <- UNRECOGNIZED: " + r.message() ); 
     468                                        break; 
     469                                default: 
     470                                        log.info( "\t <- NOT PROCESSED: " + r.kind() ); 
     471                        } 
     472                } catch( Throwable e ) { 
     473                        log.error( "Error sending message", e ); 
     474                } finally { 
     475                        lastResponseProcessed = System.currentTimeMillis(); 
     476                        printState(); 
     477                } 
     478        } 
     479 
     480        private boolean tryToHideInBar() throws Exception { 
     481                if( !fights.canMove() ) { 
     482                        if( !fights.isWaitingForOpponent() ) { 
     483                                final boolean lowHealth = temperature / fights.activeFights() < ONE_SHOT_DAMAGE; 
     484                                for( final Fight fight : fights ) { 
     485                                        if( fight.state() == Fight.State.I_ATTACKED_BY_OPPONENT ) { 
     486                                                if( lowHealth ) { 
     487                                                        escape(); 
     488                                                } else { 
     489                                                        attack( fight.opponentName() ); 
     490                                                } 
     491                                        } 
     492                                } 
     493                        } else { 
     494                                //continue to wait for strike back 
     495                                return false; 
     496                        } 
     497                } 
     498                if( fights.canMove() ) { 
     499                        hideInBar(); 
     500                        heatIfRequired(); 
     501                        return true; 
     502                } else { 
     503                        return false; 
     504                } 
     505        } 
     506 
     507        private boolean isDangerous() { 
     508                return fights.isDangerous(); 
     509        } 
     510 
     511        private boolean canHeatAtOnce() { 
     512                return MAX_TEMPERATURE - temperature <= AVG_HEAT_ONCE; 
     513        } 
     514 
     515        public void escape() throws Exception { 
     516                protocol.escape(); 
     517        } 
     518 
     519        public void queryMyInfo() throws Exception { 
     520                protocol.queryMyInfo(); 
     521                log.info( " -> info(myself)" ); 
     522        } 
     523 
     524        public void queryNeighbours() throws Exception { 
     525                protocol.queryNeighbours(); 
     526                log.info( " -> lookAround (@" + place + ", " + temperature + ")" ); 
     527        } 
     528 
     529        public void playSnowball() throws Exception { 
     530                fights.dropOutOld( IDLE_FIGHT_DROP_TIMEOUT ); 
     531                protocol.play(); 
     532                log.info( " -> play (from " + place + ", temp " + temperature + ")" ); 
     533        } 
     534 
     535        private boolean isEnoughHealthForFight() { 
     536                return temperature >= MAX_TEMPERATURE - 4; 
     537        } 
     538 
     539        private boolean isLowHealth() { 
     540                return temperature <= MAX_TEMPERATURE / 2; 
     541        } 
     542 
     543        private boolean isVeryLowHealth() { 
     544                return temperature < ONE_SHOT_DAMAGE; 
     545        } 
     546 
     547        private boolean isEnemyWeaker( final UnitInfo enemy ) { 
     548                final double ep = Commons.enemyPower( enemy.experience() ); 
     549                final double mp = Commons.enemyPower( experience ); 
     550                return ep <= mp /*&& isEnoughHealthForFight()*/; 
     551        } 
     552 
     553        public void hideInBar() throws Exception { 
     554                protocol.moveBar(); 
     555                log.info( " -> bar (temp:" + temperature + ")" ); 
     556        } 
     557 
     558//    private long lastAttack = -1; 
     559 
     560        public void attack( final String name ) throws Exception { 
     561                enemyFinder.clear(); 
     562                fights.attacked( name ); 
     563                protocol.attack( name ); 
     564                log.info( " -> attack(" + name + ")" ); 
     565        } 
     566 
     567        private void attackCurrent() throws Exception { 
     568                if( !fights.empty() ) { 
     569                        final Fight fight = fights.actualEnemy(); 
     570                        if( fight != null ) { 
     571                                if( fight.state() != Fight.State.OPPONENT_ATTACKED_BY_ME ) { 
     572                                        attack( fight.opponentName() ); 
     573                                } else if( fight.age() >= IDLE_FIGHT_DROP_TIMEOUT ) { 
     574                                        attack( fight.opponentName() ); 
     575                                } else { 
     576                                        log.info( "Already attacked(" + fight.opponentName() + ") -> skipped" ); 
     577                                } 
     578                        } else { 
     579                                log.info( "No current enemy -> attack skipped" ); 
     580                        } 
     581                } else { 
     582                        log.info( "No current enemy -> attack skipped" ); 
     583                } 
     584        } 
     585 
     586        private long lastHeaterUsed = -1; 
     587 
     588        private void heatIfRequired() throws Exception { 
     589                if( !isEnoughHealthForFight() ) { 
     590                        final long age = System.currentTimeMillis() - lastHeaterUsed; 
     591                        if( age <= MIN_HEATER_TIMEOUT ) { 
     592                                //skip 
     593                                log.info( "Too frequent heater using -> skipped" ); 
     594                                return; 
     595                        } 
     596                        if( canHeal() ) { 
     597                                protocol.useHeater(); 
     598                                log.info( " -> use heater (" + temperature + ")" ); 
     599                                lastHeaterUsed = System.currentTimeMillis(); 
     600                        } 
     601                } 
     602        } 
     603 
     604        private boolean canHeal() { 
     605                switch( place ) { 
     606                        case BAR: 
     607                                return true; 
     608                        case STREET: 
     609                                return fights.canUseHeater(); 
     610                        case SNOWDRIFT: 
     611                        case REANIMATION: 
     612                                return false; 
     613                        default: 
     614                                throw new IllegalStateException( "Unknown place:" + place ); 
     615                } 
     616        } 
     617 
     618        private final EnemyFinder enemyFinder; 
     619 
     620        private void lookForEnemyPrefetch( final boolean forceRequery ) throws Exception { 
     621                if( enemyFinder.isLooking() && !enemyFinder.isExpired() ) { 
     622                        log.info( "Already looking for enemies -- skipped" ); 
     623                        return; 
     624                } 
     625 
     626                enemyFinder.clear(); 
     627                if( forceRequery || peopleRegistry.peopleListExpired() ) { 
     628                        queryNeighbours(); 
     629                } else { 
     630                        enemyFinder.investigate(); 
     631                } 
     632        } 
     633 
     634        public boolean reconnectIfIdle() { 
     635                final long ellapsed = System.currentTimeMillis() - lastResponseProcessed; 
     636                if( ellapsed > RECONNECT_TIMEOUT ) { 
     637                        log.info( "Too long idle -- reconnect" ); 
     638                        reconnect(); 
     639                        return true; 
     640                } else { 
     641                        return false; 
     642                } 
     643        } 
     644 
     645        public void reconnect() { 
     646                protocol.disconnect(); 
     647                try { 
     648                        Thread.sleep( RECONNECT_DELAY ); 
     649                        protocol.ensureConnected(); 
     650                } catch( Exception e ) { 
     651                        log.error( "Error reconnecting", e ); 
     652                } 
     653        } 
     654 
     655        public Protocol getProtocol() { 
     656                return protocol; 
     657        } 
     658 
     659        private void printState() { 
     660                log.info( 
     661                                String.format( 
     662                                                "%s(@%s, %s\u00B0, %d) %s", 
     663                                                name, 
     664                                                place, Double.toString( temperature ), experience, 
     665                                                fights 
     666                                ) 
     667                ); 
     668        } 
     669 
     670        public String name() { 
     671                return name; 
     672        } 
     673 
     674        @Override 
     675        public String toString() { 
     676                return String.format( 
     677                                "%s(@%s, %s\u00B0, %d) %s", 
     678                                name, 
     679                                place, Double.toString( temperature ), experience, 
     680                                fights 
     681                ); 
     682        } 
     683 
     684        public static BotRunner startBot( final String name, 
     685                                          final PeopleRegistry peopleRegistry, 
     686                                          final Protocol protocol ) { 
     687                final BotRunner runner = new BotRunner( name, protocol, peopleRegistry ); 
     688 
     689 
     690                return runner; 
     691        } 
    691692} 
  • SnowBallBot/src/snowball/Main.java

    r47 r48  
    5858 
    5959        final String gameServer = config.getProperty( "game-address", "snow@talk2play.ru" ); 
    60         final String[] bots = config.getProperty( "bots", "" ).split( "\\*s*,\\s*" ); 
     60        final String[] bots = config.getProperty( "bots", "" ).split( "\\s*,\\s*" ); 
    6161 
    6262        final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool( bots.length * 2 + 1 ); 
     
    7373 
    7474            final Protocol protocol = new Protocol( 
    75                     tag, server, port, service, 
     75                    name, server, port, service, 
    7676                    login, password, 
    7777                    gameServer, proxyInfo 
  • SnowBallBot/src/snowball/helpers/FightsList.java

    r46 r48  
    2424    } 
    2525 
    26     @Override 
    2726    public Iterator<Fight> iterator() { 
    2827        return Collections.unmodifiableCollection( fights ).iterator(); 
     
    176175     *         "â ðàñ÷åòå" (state != FREE). Äàëåå êòî ïîïàëî 
    177176     */ 
    178     public String actualEnemy() { 
     177    public Fight actualEnemy() { 
    179178        if ( empty() ) { 
    180179            return null; 
     
    182181        for ( final Fight fight : fights ) { 
    183182            if ( fight.isOpponentStarted() ) { 
    184                 return fight.opponentName(); 
     183                return fight; 
    185184            } 
    186185        } 
    187186        for ( final Fight fight : fights ) { 
    188187            if ( fight.isOpponentActive() ) { 
    189                 return fight.opponentName(); 
    190             } 
    191         } 
    192  
    193         String name = null; 
    194         for ( final Fight fight : fights ) { 
    195             name = fight.opponentName(); 
     188                return fight; 
     189            } 
     190        } 
     191 
     192        Fight f = null; 
     193        for ( final Fight fight : fights ) { 
     194            f = fight; 
    196195            if ( fight.state() != FREE ) { 
    197                 return name; 
    198             } 
    199         } 
    200         return name; 
     196                return fight; 
     197            } 
     198        } 
     199        return f; 
    201200    } 
    202201 
  • SnowBallBot/src/snowball/helpers/PeopleRegistry.java

    r47 r48  
    1515 */ 
    1616public class PeopleRegistry { 
    17     private static final Log log = LogFactory.getLog( PeopleRegistry.class ); 
    18  
    19     //private static final long EL_QUERY_EXPIRED = 180000;//3min 
    20     private static final int PL_EXPIRED_PERIOD = 120000; 
    21     //private static final int EL_EXPIRED = 120000; 
    22  
    23     /** 
    24      * íèêîãäà íå íàïàäàåì 
    25      */ 
    26     private static final List<String> FRIENDS = Arrays.asList( 
    27             "r.suhomlinov", 
    28             "BegemoT", 
    29             "cheremin", 
    30             "kotobaba"/*, 
     17        private static final Log log = LogFactory.getLog( PeopleRegistry.class ); 
     18 
     19        //private static final long EL_QUERY_EXPIRED = 180000;//3min 
     20        private static final int PL_EXPIRED_PERIOD = 120000; 
     21        //private static final int EL_EXPIRED = 120000; 
     22 
     23        /** íèêîãäà íå íàïàäàåì */ 
     24        private static final List<String> FRIENDS = Arrays.asList( 
     25                        "r.suhomlinov", 
     26                        "BegemoT", 
     27                        "cheremin", 
     28                        "kotobaba"/*, 
    3129            "feyaolya"*/ 
    32     ); 
    33  
    34     /** 
    35      * ñàìûå, ñöóêî, ïèäîðàñû 
    36      */ 
    37     private static final List<String> MOST_WANTED = Arrays.asList( 
    38             "v_vasia", 
    39             "Orfest" 
    40     ); 
    41  
    42  
    43     /** 
    44      * ýòèõ ïðîñòî ïðèÿòíî ïèçäèòü 
    45      */ 
    46     private static final List<String> TOP = Arrays.asList( 
    47             "v_vasia", 
    48             "Fog", 
    49             "Orfest", 
    50             "asbest884", 
    51             "qwmpo", 
    52             "ken_88", 
    53             "yur4enko" 
    54     ); 
    55  
    56     /** 
    57      * åñëè äîñòóïíûõ âðàãîâ íåò -- èùåì ýòèõ 
    58      */ 
    59     private static final List<String> FIRST_CLASS_CANDIDATES = union( 
    60             MOST_WANTED, 
    61             TOP, 
    62             Arrays.asList( 
    63                     "v_vasia", 
    64                     "Orfest", 
    65                     "tgmka", 
    66                     "terminator", 
    67                     "elenka_motyl", 
    68                     "snegovik", 
    69                     "DenisKo", 
    70                     "Yason", 
    71                     "whiteapt", 
    72                     "bigh0use", 
    73                     "440284239", 
    74                     "spartak.cham", 
    75                     "garik", 
    76                     "qwmpo", 
    77                     "Fog", 
    78                     "asbest884", 
    79                     "ken_88", 
    80                     "mike", 
    81                     "491504474", 
    82                     "stah", 
    83                     "m_o_z_i_a", 
    84                     "MAKAPOH", 
    85                     "kirdik", 
    86                     "batora", 
    87                     "macron" 
    88             ) 
    89     ); 
    90  
    91     private static final String STATS_FILE_NAME = "stats.txt"; 
    92     private static final String PARAMS_FILE_NAME = "params"; 
    93  
    94     private final List<String> peopleOnTheStreet = new ArrayList<String>(); 
    95  
    96     private volatile long peopleListTimestamp = -1; 
    97     private final Map<String, UnitInfo> people = new HashMap(); 
    98  
    99     private final List<UnitInfo> prioritized; 
    100  
    101     public PeopleRegistry() { 
    102         final File file = new File( PARAMS_FILE_NAME ); 
    103         List<UnitInfo> prioritized = load( file ); 
    104         if ( prioritized == null ) { 
    105             this.prioritized = new ArrayList(); 
    106         } else { 
    107             this.prioritized = prioritized; 
    108             for ( final UnitInfo info : prioritized ) { 
    109                 people.put( info.name(), info ); 
    110             } 
    111         } 
    112     } 
    113  
    114     public boolean isMostWanted( final String name ) { 
    115         return MOST_WANTED.contains( name ); 
    116     } 
    117  
    118     public Iterable<String> mostWanted() { 
    119         return MOST_WANTED; 
    120     } 
    121  
    122     public boolean isTop( final String name ) { 
    123         return TOP.contains( name ); 
    124     } 
    125  
    126     public UnitInfo get( final String name ) { 
    127         return people.get( name ); 
    128     } 
    129  
    130     public synchronized UnitInfo update( final String name, 
    131                                          final double temp, 
    132                                          final int exp, 
    133                                          final Place place ) { 
    134         final UnitInfo info = new UnitInfo( name, temp, exp, place ); 
    135         return update( info ); 
    136     } 
    137  
    138     public synchronized UnitInfo update( final UnitInfo info ) { 
    139         people.put( info.name(), info ); 
    140         if ( info.place() != Place.STREET ) { 
    141             peopleOnTheStreet.remove( info.name() ); 
    142         } 
    143         save(); 
    144         return info; 
    145     } 
    146  
    147     public synchronized void updatePeopleList( final List<String> enemies ) { 
    148         peopleListTimestamp = System.currentTimeMillis(); 
    149         final List<String> newEnemies = new ArrayList( enemies ); 
    150         newEnemies.removeAll( FRIENDS ); 
    151         if ( !newEnemies.isEmpty() ) { 
    152             peopleOnTheStreet.clear(); 
    153             peopleOnTheStreet.addAll( newEnemies ); 
    154             Collections.shuffle( peopleOnTheStreet, Util.random() ); 
    155         } else { 
    156             //îñòàâëÿåì ñòàðûé ñïèñîê -- âäðóã ïðîêàòèò? 
    157         } 
    158     } 
    159  
    160     public long peopleListAge() { 
    161         return System.currentTimeMillis() - peopleListTimestamp; 
    162     } 
    163  
    164     public boolean peopleListExpired() { 
    165         return peopleListAge() >= PL_EXPIRED_PERIOD; 
    166     } 
    167  
    168     //todo prioritized candidates based on their experience 
    169     public synchronized List<String> suggestCandidates( final int count ) { 
    170         final List<String> res; 
    171         if ( peopleOnTheStreet.isEmpty() ) { 
    172             log.info( "No new enemies -- look for somebody known" ); 
    173             res = new ArrayList( FIRST_CLASS_CANDIDATES ); 
    174         } else if ( !peopleOnTheStreet.isEmpty() ) { 
    175             res = new ArrayList(); 
    176             final int len = peopleOnTheStreet.size(); 
    177  
    178             //first of all use most-wanted 
    179             final int cnt = Math.min( count, len ); 
    180             res.addAll( MOST_WANTED ); 
    181  
    182             //next choose from shuffled list 
    183             for ( int i = 0; i < cnt; i++ ) { 
    184                 final String name = peopleOnTheStreet.remove( len - 1 ); 
    185                 //and move them to the end of queue 
    186                 peopleOnTheStreet.add( 0, name ); 
    187  
    188                 res.add( name ); 
    189             } 
    190         } else { 
    191             res = Collections.emptyList(); 
    192         } 
    193         return res; 
    194     } 
    195  
    196     public synchronized String suggestNext() { 
    197         if ( peopleOnTheStreet.isEmpty() ) { 
    198             return null; 
    199         } else { 
    200             final int len = peopleOnTheStreet.size(); 
    201             final String last = peopleOnTheStreet.remove( len - 1 ); 
    202             peopleOnTheStreet.add( 0, last ); 
    203             return last; 
    204         } 
    205     } 
    206  
    207     public int size() { 
    208         return peopleOnTheStreet.size(); 
    209     } 
    210  
    211     private static List<String> union( final List<String>... arrs ) { 
    212         final Set<String> res = new HashSet<String>(); 
    213         for ( List<String> arr : arrs ) { 
    214             for ( String name : arr ) { 
    215                 res.add( name ); 
    216             } 
    217         } 
    218         return Collections.unmodifiableList( new ArrayList( res ) ); 
    219     } 
    220  
    221     private int saveCalledCount = 0; 
    222  
    223     private static final boolean useSerialization = true; 
    224  
    225     private static List<UnitInfo> load( final File file ) { 
    226         final List<UnitInfo> res = new ArrayList(); 
    227         if ( file.exists() && file.length() > 0 ) { 
    228             try { 
    229                 final FileInputStream fis = new FileInputStream( file ); 
    230                 try { 
    231                     if ( useSerialization ) { 
    232                         final ObjectInputStream ois = new ObjectInputStream( fis ); 
    233                         return ( List<UnitInfo> )ois.readObject(); 
    234                     } else { 
    235                         final BufferedReader r = new BufferedReader( new InputStreamReader( fis ) ); 
    236                         try { 
    237                             final String line = r.readLine(); 
    238                             final String[] parts = line.split( "\\s*,\\s*" ); 
    239                             final String name = parts[0]; 
    240                             final int exp = Integer.parseInt( parts[1] ); 
    241                             final double temp = Double.parseDouble( parts[2] ); 
    242                             final Place place = Place.valueOf( parts[3] ); 
    243                             res.add( new UnitInfo( name, temp, exp, place ) ); 
    244                         } finally { 
    245                             r.close(); 
    246                         } 
    247                     } 
    248                 } finally { 
    249                     fis.close(); 
    250                 } 
    251             } catch ( Exception e ) { 
    252                 log.error( "can't load params", e ); 
    253             } 
    254         } 
    255         return res; 
    256     } 
    257  
    258     private synchronized void save() { 
    259         saveCalledCount++; 
    260         if ( saveCalledCount % 5 == 0 ) { 
    261             prioritized.clear(); 
    262             prioritized.addAll( people.values() ); 
    263             Collections.sort( prioritized, Commons.EXPERIENCE_COMPARATOR ); 
    264             try { 
    265                 final FileWriter fw = new FileWriter( STATS_FILE_NAME ); 
    266                 try { 
    267                     for ( UnitInfo unit : prioritized ) { 
    268                         fw.write( 
    269                                 String.format( 
    270                                         "%s, %d, %f, %s\n", 
    271                                         unit.name(), 
    272                                         unit.experience(), 
    273                                         unit.temperature(), 
    274                                         unit.place() 
    275                                 ) 
    276                         ); 
    277                     } 
    278                 } finally { 
    279                     fw.close(); 
    280                 } 
    281                 final OutputStream fos = new FileOutputStream( PARAMS_FILE_NAME ); 
    282                 try { 
    283                     final ObjectOutputStream oos = new ObjectOutputStream( fos ); 
    284                     oos.writeObject( prioritized ); 
    285                     oos.flush(); 
    286                 } finally { 
    287                     fos.close(); 
    288                 } 
    289             } catch ( IOException e ) { 
    290                 log.error( "IO", e ); 
    291             } 
    292         } 
    293     } 
     30        ); 
     31 
     32        /** ñàìûå, ñöóêî, ïèäîðàñû */ 
     33        private static final List<String> MOST_WANTED = Arrays.asList( 
     34                        "v_vasia", 
     35                        "Orfest" 
     36        ); 
     37 
     38 
     39        /** ýòèõ ïðîñòî ïðèÿòíî ïèçäèòü */ 
     40        private static final List<String> TOP = Arrays.asList( 
     41                        "v_vasia", 
     42                        "Fog", 
     43                        "Orfest", 
     44                        "asbest884", 
     45                        "qwmpo", 
     46                        "ken_88", 
     47                        "yur4enko" 
     48        ); 
     49 
     50        /** åñëè äîñòóïíûõ âðàãîâ íåò -- èùåì ýòèõ */ 
     51        private static final List<String> FIRST_CLASS_CANDIDATES = union( 
     52                        MOST_WANTED, 
     53                        TOP, 
     54                        Arrays.asList( 
     55                                        "v_vasia", 
     56                                        "Orfest", 
     57                                        "tgmka", 
     58                                        "terminator", 
     59                                        "elenka_motyl", 
     60                                        "snegovik", 
     61                                        "DenisKo", 
     62                                        "Yason", 
     63                                        "whiteapt", 
     64                                        "bigh0use", 
     65                                        "440284239", 
     66                                        "spartak.cham", 
     67                                        "garik", 
     68                                        "qwmpo", 
     69                                        "Fog", 
     70                                        "asbest884", 
     71                                        "ken_88", 
     72                                        "mike", 
     73                                        "491504474", 
     74                                        "stah", 
     75                                        "m_o_z_i_a", 
     76                                        "MAKAPOH", 
     77                                        "kirdik", 
     78                                        "batora", 
     79                                        "macron" 
     80                        ) 
     81        ); 
     82 
     83        private static final String STATS_FILE_NAME = "stats.txt"; 
     84        private static final String PARAMS_FILE_NAME = "params"; 
     85 
     86        private final List<String> peopleOnTheStreet = new ArrayList<String>(); 
     87 
     88        private final Map<String, UnitInfo> people = new HashMap(); 
     89        private final List<UnitInfo> prioritized; 
     90 
     91        private volatile long peopleListTimestamp = -1; 
     92 
     93        public PeopleRegistry() { 
     94                final File file = new File( PARAMS_FILE_NAME ); 
     95                this.prioritized = load( file ); 
     96                for( final UnitInfo info : prioritized ) { 
     97                        people.put( info.name(), info ); 
     98                } 
     99        } 
     100 
     101        public boolean isMostWanted( final String name ) { 
     102                return MOST_WANTED.contains( name ); 
     103        } 
     104 
     105        public Iterable<String> mostWanted() { 
     106                return MOST_WANTED; 
     107        } 
     108 
     109        public boolean isTop( final String name ) { 
     110                return TOP.contains( name ); 
     111        } 
     112 
     113        public UnitInfo get( final String name ) { 
     114                return people.get( name ); 
     115        } 
     116 
     117        public synchronized UnitInfo update( final String name, 
     118                                             final double temp, 
     119                                             final int exp, 
     120                                             final Place place ) { 
     121                final UnitInfo info = new UnitInfo( name, temp, exp, place ); 
     122                return update( info ); 
     123        } 
     124 
     125        public synchronized UnitInfo update( final UnitInfo info ) { 
     126                people.put( info.name(), info ); 
     127                if( info.place() != Place.STREET ) { 
     128                        peopleOnTheStreet.remove( info.name() ); 
     129                } 
     130                save(); 
     131                return info; 
     132        } 
     133 
     134        public synchronized void updatePeopleList( final List<String> enemies ) { 
     135                peopleListTimestamp = System.currentTimeMillis(); 
     136                final List<String> newEnemies = new ArrayList( enemies ); 
     137                newEnemies.removeAll( FRIENDS ); 
     138                if( !newEnemies.isEmpty() ) { 
     139                        peopleOnTheStreet.clear(); 
     140                        peopleOnTheStreet.addAll( newEnemies ); 
     141                        Collections.shuffle( peopleOnTheStreet, Util.random() ); 
     142                } else { 
     143                        //îñòàâëÿåì ñòàðûé ñïèñîê -- âäðóã ïðîêàòèò? 
     144                } 
     145        } 
     146 
     147        public long peopleListAge() { 
     148                return System.currentTimeMillis() - peopleListTimestamp; 
     149        } 
     150 
     151        public boolean peopleListExpired() { 
     152                return peopleListAge() >= PL_EXPIRED_PERIOD; 
     153        } 
     154 
     155        //todo prioritized candidates based on their experience 
     156        public synchronized List<String> suggestCandidates( final int count ) { 
     157                final List<String> res; 
     158                if( peopleOnTheStreet.isEmpty() ) { 
     159                        log.info( "No new enemies -- look for somebody known" ); 
     160                        res = new ArrayList( FIRST_CLASS_CANDIDATES ); 
     161                } else if( !peopleOnTheStreet.isEmpty() ) { 
     162                        res = new ArrayList(); 
     163                        final int len = peopleOnTheStreet.size(); 
     164 
     165                        //first of all use most-wanted 
     166                        final int cnt = Math.min( count, len ); 
     167                        res.addAll( MOST_WANTED ); 
     168 
     169                        //next choose from shuffled list 
     170                        for( int i = 0; i < cnt; i++ ) { 
     171                                final String name = peopleOnTheStreet.remove( len - 1 ); 
     172                                //and move them to the end of queue 
     173                                peopleOnTheStreet.add( 0, name ); 
     174 
     175                                res.add( name ); 
     176                        } 
     177                } else { 
     178                        res = Collections.emptyList(); 
     179                } 
     180                return res; 
     181        } 
     182 
     183        public synchronized String suggestNext() { 
     184                if( peopleOnTheStreet.isEmpty() ) { 
     185                        return null; 
     186                } else { 
     187                        final int len = peopleOnTheStreet.size(); 
     188                        final String last = peopleOnTheStreet.remove( len - 1 ); 
     189                        peopleOnTheStreet.add( 0, last ); 
     190                        return last; 
     191                } 
     192        } 
     193 
     194        public int size() { 
     195                return peopleOnTheStreet.size(); 
     196        } 
     197 
     198        private static List<String> union( final List<String>... arrs ) { 
     199                final Set<String> res = new HashSet<String>(); 
     200                for( List<String> arr : arrs ) { 
     201                        for( String name : arr ) { 
     202                                res.add( name ); 
     203                        } 
     204                } 
     205                return Collections.unmodifiableList( new ArrayList( res ) ); 
     206        } 
     207 
     208        private int saveCalledCount = 0; 
     209 
     210        private static final boolean useSerialization = false; 
     211 
     212        private static List<UnitInfo> load( final File file ) { 
     213                final List<UnitInfo> res = new ArrayList(); 
     214                if( file.exists() && file.length() > 0 ) { 
     215                        try { 
     216                                final FileInputStream fis = new FileInputStream( file ); 
     217                                try { 
     218                                        if( useSerialization ) { 
     219                                                final ObjectInputStream ois = new ObjectInputStream( fis ); 
     220                                                return ( List<UnitInfo> ) ois.readObject(); 
     221                                        } else { 
     222                                                final BufferedReader r = new BufferedReader( new InputStreamReader( fis ) ); 
     223                                                try { 
     224                                                        final String line = r.readLine(); 
     225                                                        final String[] parts = line.split( "\\s*,\\s*" ); 
     226                                                        final String name = parts[0]; 
     227                                                        final int exp = Integer.parseInt( parts[1] ); 
     228                                                        final double temp = Double.parseDouble( parts[2] ); 
     229                                                        final Place place = Place.valueOf( parts[3] ); 
     230                                                        res.add( new UnitInfo( name, temp, exp, place ) ); 
     231                                                } finally { 
     232                                                        r.close(); 
     233                                                } 
     234                                        } 
     235                                } finally { 
     236                                        fis.close(); 
     237                                } 
     238                        } catch( Exception e ) { 
     239                                log.error( "can't load params", e ); 
     240                        } 
     241                } 
     242                return res; 
     243        } 
     244 
     245        private synchronized void save() { 
     246                saveCalledCount++; 
     247                if( saveCalledCount % 5 == 0 ) { 
     248                        prioritized.clear(); 
     249                        prioritized.addAll( people.values() ); 
     250                        Collections.sort( prioritized, Commons.EXPERIENCE_COMPARATOR ); 
     251                        final File file = new File( PARAMS_FILE_NAME ); 
     252                        try { 
     253                                if( false/*useSerialization */ ) { 
     254                                        final OutputStream fos = new FileOutputStream( file ); 
     255                                        try { 
     256                                                final ObjectOutputStream oos = new ObjectOutputStream( fos ); 
     257                                                oos.writeObject( prioritized ); 
     258                                                oos.flush(); 
     259                                        } finally { 
     260                                                fos.close(); 
     261                                        } 
     262                                } else { 
     263                                        final FileWriter fw = new FileWriter( file ); 
     264                                        try { 
     265                                                for( UnitInfo unit : prioritized ) { 
     266                                                        fw.write( 
     267                                                                        String.format( 
     268                                                                                        "%s, %d, %s, %s\n", 
     269                                                                                        unit.name(), 
     270                                                                                        unit.experience(), 
     271                                                                                        Double.toString( unit.temperature() ), 
     272                                                                                        unit.place() 
     273                                                                        ) 
     274                                                        ); 
     275                                                } 
     276                                        } finally { 
     277                                                fw.close(); 
     278                                        } 
     279                                } 
     280                        } catch( IOException e ) { 
     281                                log.error( "IO", e ); 
     282                        } 
     283                } 
     284        } 
    294285} 
Note: See TracChangeset for help on using the changeset viewer.