001 package com.croftsoft.apps.mars.ai; 002 003 import java.io.Serializable; 004 import java.util.*; 005 006 import com.croftsoft.core.ai.astar.AStar; 007 import com.croftsoft.core.lang.NullArgumentException; 008 import com.croftsoft.core.math.geom.Circle; 009 import com.croftsoft.core.math.geom.Point2DD; 010 import com.croftsoft.core.math.geom.PointXY; 011 import com.croftsoft.core.math.geom.ShapeLib; 012 013 /********************************************************************* 014 * Default TankOperator implementation. 015 * 016 * @version 017 * 2003-05-10 018 * @since 019 * 2003-03-21 020 * @author 021 * <a href="https://www.croftsoft.com/">David Wallace Croft</a> 022 *********************************************************************/ 023 024 public final class DefaultTankOperator 025 implements TankOperator, Serializable 026 ////////////////////////////////////////////////////////////////////// 027 ////////////////////////////////////////////////////////////////////// 028 { 029 030 private static final long serialVersionUID = 0L; 031 032 /** Probability of firing during one second of time. */ 033 private static final double FIRING_PROBABILITY = 1.0; 034 035 /** Probability of drifting during one second of time. */ 036 private static final double DRIFT_PROBABILITY = 0.1; 037 038 private static final int A_STAR_LOOPS = 100; 039 040 private static final double STEP_SIZE = 10.0; 041 042 private static final int DIRECTIONS = 8; 043 044 // 045 046 private final Point2DD center; 047 048 private final Point2DD destination; 049 050 private final Random random; 051 052 private final AStar aStar; 053 054 private final TankCartographer tankCartographer; 055 056 private final StateSpaceNode startStateSpaceNode; 057 058 // 059 060 private TankConsole tankConsole; 061 062 private PointXY enemyCenter; 063 064 ////////////////////////////////////////////////////////////////////// 065 ////////////////////////////////////////////////////////////////////// 066 067 public DefaultTankOperator ( Random random ) 068 ////////////////////////////////////////////////////////////////////// 069 { 070 NullArgumentException.check ( this.random = random ); 071 072 center = new Point2DD ( ); 073 074 destination = new Point2DD ( ); 075 076 tankCartographer = new TankCartographer ( STEP_SIZE, DIRECTIONS ); 077 078 aStar = new AStar ( tankCartographer ); 079 080 startStateSpaceNode = new StateSpaceNode ( ); 081 } 082 083 ////////////////////////////////////////////////////////////////////// 084 ////////////////////////////////////////////////////////////////////// 085 086 public void fire ( ) 087 ////////////////////////////////////////////////////////////////////// 088 { 089 // do something here 090 } 091 092 public void go ( PointXY destination ) 093 ////////////////////////////////////////////////////////////////////// 094 { 095 // do something here 096 } 097 098 public void setTankConsole ( TankConsole tankConsole ) 099 ////////////////////////////////////////////////////////////////////// 100 { 101 NullArgumentException.check ( this.tankConsole = tankConsole ); 102 103 tankCartographer.setTankConsole ( tankConsole ); 104 } 105 106 public void update ( double timeDelta ) 107 ////////////////////////////////////////////////////////////////////// 108 { 109 ShapeLib.getCenter ( tankConsole.getShape ( ), center ); 110 111 enemyCenter = tankConsole.getClosestEnemyTankCenter ( ); 112 113 tankConsole.rotateTurret ( enemyCenter ); 114 115 if ( tankConsole.getAmmo ( ) < 1.0 ) 116 { 117 PointXY ammoDumpCenter 118 = tankConsole.getClosestAmmoDumpCenter ( ); 119 120 if ( ammoDumpCenter != null ) 121 { 122 tankConsole.go ( getFirstStep ( ammoDumpCenter ) ); 123 } 124 125 return; 126 } 127 128 if ( enemyCenter != null ) 129 { 130 tankConsole.go ( getFirstStep ( enemyCenter ) ); 131 132 if ( random.nextDouble ( ) < timeDelta * FIRING_PROBABILITY ) 133 { 134 tankConsole.fire ( ); 135 } 136 137 return; 138 } 139 140 if ( random.nextDouble ( ) < timeDelta * DRIFT_PROBABILITY ) 141 { 142 destination.setXY ( 143 center.x + 2 * random.nextDouble ( ) - 1, 144 center.y + 2 * random.nextDouble ( ) - 1 ); 145 146 tankConsole.go ( destination ); 147 } 148 149 if ( random.nextDouble ( ) < timeDelta * FIRING_PROBABILITY ) 150 { 151 tankConsole.fire ( ); 152 } 153 } 154 155 public Iterator getPath ( ) { return aStar.getPath ( ); } 156 157 ////////////////////////////////////////////////////////////////////// 158 ////////////////////////////////////////////////////////////////////// 159 160 private PointXY getFirstStep ( PointXY destination ) 161 ////////////////////////////////////////////////////////////////////// 162 { 163 NullArgumentException.check ( destination ); 164 165 startStateSpaceNode.setPointXY ( center ); 166 167 startStateSpaceNode.setHeading ( tankConsole.getBodyHeading ( ) ); 168 169 tankCartographer.setStartStateSpaceNode ( startStateSpaceNode ); 170 171 aStar.reset ( startStateSpaceNode ); 172 173 tankCartographer.setGoalPointXY ( destination ); 174 175 for ( int i = 0; i < A_STAR_LOOPS; i++ ) 176 { 177 if ( !aStar.loop ( ) ) 178 { 179 break; 180 } 181 } 182 183 if ( !aStar.isGoalFound ( ) ) 184 { 185 return destination; 186 } 187 188 StateSpaceNode stateSpaceNode 189 = ( StateSpaceNode ) aStar.getFirstStep ( ); 190 191 if ( stateSpaceNode == null ) 192 { 193 return destination; 194 } 195 196 return stateSpaceNode.getPointXY ( ); 197 } 198 199 ////////////////////////////////////////////////////////////////////// 200 ////////////////////////////////////////////////////////////////////// 201 }