/*-
* Copyright Bogdan Mocanu, 2009
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* The Alpha algorithm implementation of the Diego player for the sled.
*
* @author mocanu
*/
public class AlphaBumperAlgorithm extends AbstractAlgorithm {
public AlphaAlgorithm parentAlgorithm;
public AlphaSledAlgorithm sledAlgorithm;
private AlphaBumperPlan bumperPlans[];
private boolean caseOfCusteredPucks_detected = false;
private RealPoint caseOfClusteredPucks_target = new RealPoint();
private boolean caseOfEnemyPlan_detected = false;
private RealPoint caseOfEnemyPlan_target = new RealPoint();
/**
* {@inheritDoc}
*/
@Override
public void init() {
bumperPlans = new AlphaBumperPlan[Const.BUMPER_NR];
for ( int bumperPlanIndex = 0; bumperPlanIndex < Const.BUMPER_NR; bumperPlanIndex++ ) {
bumperPlans[bumperPlanIndex] = new AlphaBumperPlan();
}
}
/**
* {@inheritDoc}
*/
@Override
public void execute() {
detectFriendlyPucksClustering( stateManager.friendBumpers[0] );
detectEnemyPlanAndTargetPuck( stateManager.friendBumpers[1] );
if ( bumperPlans[0].state == AlphaBumperState.READY ) {
if ( caseOfCusteredPucks_detected ) {
startBumperMovement( 0, caseOfClusteredPucks_target );
} else {
planBumperMovementToGrayPuck( 0 );
}
}
if ( bumperPlans[1].state == AlphaBumperState.READY ) {
if ( caseOfEnemyPlan_detected ) {
startBumperMovement( 1, caseOfEnemyPlan_target );
} else {
planBumperMovementToGrayPuck( 1 );
}
}
if ( bumperPlans[0].state != AlphaBumperState.READY ) {
continueBumperMovement( 0 );
}
if ( bumperPlans[1].state != AlphaBumperState.READY ) {
continueBumperMovement( 1 );
}
}
// -------------------------------------------------------------------------------------------------
private void startBumperMovement( int index, RealPoint target ) {
AlphaBumperPlan plan = bumperPlans[index];
if ( Const.DEBUG_BUMPER ) {
log.info( "bumper", "LOCKED", target.x, target.y );
}
plan.state = AlphaBumperState.LOCKED_ON;
plan.target.copyFrom( target );
}
private void continueBumperMovement( int index ) {
AlphaBumperPlan plan = bumperPlans[index];
Bumper bumper = stateManager.friendBumpers[index];
RealPoint bumperAcceleration = responseManager.bumperAccelerations[index];
if ( plan.state == AlphaBumperState.READY ) {
bumperAcceleration.x = -bumper.velocity.x;
bumperAcceleration.y = -bumper.velocity.y;
return;
}
if ( plan.state == AlphaBumperState.LOCKED_ON && distance( bumper.coord, plan.target ) < 8 ) {
if ( Const.DEBUG_BUMPER ) {
log.info( "bumper", "STOPPING" );
}
plan.state = AlphaBumperState.STOPPING;
plan.stopSequence = Const.BUMPER_MAX_STOP_SEQUENCE;
}
if ( plan.state == AlphaBumperState.STOPPING && Math.max( bumper.velocity.x, bumper.velocity.y ) <= 0.5 ) {
if ( Const.DEBUG_BUMPER ) {
log.info( "bumper", "STOPPING->READY" );
}
plan.state = AlphaBumperState.READY;
bumperAcceleration.x = 0;
bumperAcceleration.y = 0;
}
if ( plan.state == AlphaBumperState.READY ) {
bumperAcceleration.x = -bumper.velocity.x;
bumperAcceleration.y = -bumper.velocity.y;
}
if ( plan.state == AlphaBumperState.LOCKED_ON ) {
bumperAcceleration.x = limit( plan.target.x - bumper.coord.x - bumper.velocity.x, -Const.BUMPER_ACCELLERATION_LIMIT, Const.BUMPER_ACCELLERATION_LIMIT );
bumperAcceleration.y = limit( plan.target.y - bumper.coord.y - bumper.velocity.y, -Const.BUMPER_ACCELLERATION_LIMIT, Const.BUMPER_ACCELLERATION_LIMIT );
}
if ( plan.state == AlphaBumperState.STOPPING ) {
plan.stopSequence--;
if ( plan.stopSequence <= 0 ) {
if ( Const.DEBUG_BUMPER ) {
log.info( "bumper", "STOPPING->READY (stopSeq)" );
}
plan.state = AlphaBumperState.READY;
bumperAcceleration.x = 0;
bumperAcceleration.y = 0;
} else {
bumperAcceleration.x = -bumper.velocity.x;
bumperAcceleration.y = -bumper.velocity.y;
}
}
}
private void detectFriendlyPucksClustering( Bumper baseBumper ) {
caseOfCusteredPucks_detected = false;
int maxPucks = 0;
double minDistanceToBase = Integer.MAX_VALUE;
RealPoint cursorForTarget = new RealPoint();
for ( int puckIndex1 = 0; puckIndex1 < stateManager.pucksNr - 1; puckIndex1++ ) {
Puck currentPuck1 = stateManager.pucks[puckIndex1];
if ( currentPuck1.type == PuckType.FRIEND ) {
int nrOfClusteredPucks = 1;
cursorForTarget.x = currentPuck1.coord.x;
cursorForTarget.y = currentPuck1.coord.y;
for ( int puckIndex2 = puckIndex1 + 1; puckIndex2 < stateManager.pucksNr; puckIndex2++ ) {
Puck currentPuck2 = stateManager.pucks[puckIndex2];
if ( currentPuck2.type == PuckType.FRIEND ) {
double currentDistance = distance( currentPuck1.coord, currentPuck2.coord );
if ( currentDistance < Const.PARAM_BUMPER_CLUSTERING_DISTANCE_LIMIT ) {
if ( nrOfClusteredPucks == 1 ) {
// first paired puck found
middleOf( currentPuck1.coord, currentPuck2.coord, cursorForTarget );
}
nrOfClusteredPucks++;
}
}
}
if ( nrOfClusteredPucks >= Const.PARAM_BUMPER_CLUSTERING_MINIMUM_NR && nrOfClusteredPucks >= maxPucks ) {
if ( Const.DEBUG_BUMPER ) {
log.info( "bumper", "Detected clustering, nrOfPucks:", nrOfClusteredPucks );
}
caseOfCusteredPucks_detected = true;
// we have a case of clustering
double currentDistance = distance( cursorForTarget, baseBumper.coord );
if ( nrOfClusteredPucks > maxPucks || currentDistance < minDistanceToBase ) {
maxPucks = nrOfClusteredPucks;
minDistanceToBase = currentDistance;
caseOfClusteredPucks_target.x = cursorForTarget.x;
caseOfClusteredPucks_target.y = cursorForTarget.y;
}
}
}
}
}
private void detectEnemyPlanAndTargetPuck( Bumper baseBumper ) {
caseOfEnemyPlan_detected = false;
double minDistance = Double.MAX_VALUE;
for ( int puckIndex = 0; puckIndex < stateManager.pucksNr; puckIndex++ ) {
Puck currentPuck = stateManager.pucks[puckIndex];
if ( currentPuck.type == PuckType.ENEMY ) {
double distanceToSled = distance( currentPuck.coord, stateManager.enemySled.coord );
if ( distanceToSled < Const.PARAM_BUMPER_ENEMY_PLAN_TARGET_PUCK_DISTANCE_LIMIT
&& distanceToSled < minDistance ) {
if ( Const.DEBUG_BUMPER ) {
log.info( "bumper", "Detected ENEMY plan; distance", distanceToSled );
}
caseOfEnemyPlan_detected = true;
minDistance = distanceToSled;
caseOfEnemyPlan_target.x = currentPuck.coord.x;
caseOfEnemyPlan_target.y = currentPuck.coord.y;
}
}
}
}
private void planBumperMovementToGrayPuck( int index ) {
Bumper bumper = stateManager.friendBumpers[index];
double minDistance = Double.MAX_VALUE;
Puck targetPuck = null;
for ( int puckIndex = 0; puckIndex < stateManager.pucksNr; puckIndex++ ) {
Puck currentPuck = stateManager.pucks[puckIndex];
if ( currentPuck.type == PuckType.GRAY ) {
double distanceToPlanCenter = distance( currentPuck.coord, sledAlgorithm.currentPlan_center );
if ( distanceToPlanCenter > Const.TRAIL_LIMIT_CIRCLE_RADIUS && ( index == 1 || distanceToPlanCenter < minDistance ) ) {
if ( Const.DEBUG_BUMPER ) {
log.info( "bumper", "Detected GRAY puck; distance", distanceToPlanCenter );
}
minDistance = distanceToPlanCenter;
targetPuck = currentPuck;
}
}
}
if ( targetPuck == null ) {
stopBumper( index );
return;
}
double angleOfBumperAndPuck = angleOf( bumper.coord, targetPuck.coord );
double angleOfPuckAndCenter = angleOf( targetPuck.coord, sledAlgorithm.currentPlan_center );
if ( Math.abs( angleOfPuckAndCenter - angleOfBumperAndPuck ) < 0.5 ) {
// we are on the same line (or close) with the puck and the center of the plan
planBumperMovement( index, targetPuck.coord );
} else {
// we are not on the same line, must get behind the puck
RealPoint pointBehind = new RealPoint();
pointBehind.x = (4 / 3F) * targetPuck.coord.x - sledAlgorithm.currentPlan_center.x;
pointBehind.y = (4 / 3F) * targetPuck.coord.y - sledAlgorithm.currentPlan_center.y;
// RealPoint closeToPointBehind = new RealPoint();
// closeToPointBehind.x = limit( (3 / 4F) * (bumper.coord.x + pointBehind.x), 5,
// Const.TABLE_SIZE - 5 );
// closeToPointBehind.y = limit( (3 / 4F) * (bumper.coord.y + pointBehind.y), 5,
// Const.TABLE_SIZE - 5 );
planBumperMovement( index, pointBehind );
}
}
private void stopBumper( int index ) {
responseManager.bumperAccelerations[index].x = -stateManager.friendBumpers[index].velocity.x;
responseManager.bumperAccelerations[index].y = -stateManager.friendBumpers[index].velocity.y;
}
private void planBumperMovement( int index, RealPoint targetPoint ) {
Bumper bumper = stateManager.friendBumpers[index];
responseManager.bumperAccelerations[index].x = limit( targetPoint.x - bumper.coord.x, -Const.BUMPER_ACCELLERATION_LIMIT, Const.BUMPER_ACCELLERATION_LIMIT );
responseManager.bumperAccelerations[index].y = limit( targetPoint.y - bumper.coord.y, -Const.BUMPER_ACCELLERATION_LIMIT, Const.BUMPER_ACCELLERATION_LIMIT );
}
}