001 package com.croftsoft.apps.mars.ai; 002 003 import java.util.*; 004 005 import com.croftsoft.core.ai.astar.Cartographer; 006 import com.croftsoft.core.lang.NullArgumentException; 007 import com.croftsoft.core.math.geom.Point2DD; 008 import com.croftsoft.core.math.geom.PointXY; 009 010 /********************************************************************* 011 * Used with the Tank A* implementation. 012 * 013 * @version 014 * 2003-05-10 015 * @since 016 * 2003-03-21 017 * @author 018 * <a href="https://www.croftsoft.com/">David Wallace Croft</a> 019 *********************************************************************/ 020 021 public final class TankCartographer 022 implements Cartographer 023 ////////////////////////////////////////////////////////////////////// 024 ////////////////////////////////////////////////////////////////////// 025 { 026 027 private final double initStepSize; 028 029 private final int directions; 030 031 private final StateSpaceNode startStateSpaceNode; 032 033 private final StateSpaceNode goalStateSpaceNode; 034 035 private final List adjacentList; 036 037 // 038 039 private TankConsole tankConsole; 040 041 ////////////////////////////////////////////////////////////////////// 042 ////////////////////////////////////////////////////////////////////// 043 044 public TankCartographer ( 045 double initStepSize, 046 int directions ) 047 ////////////////////////////////////////////////////////////////////// 048 { 049 this.initStepSize = initStepSize; 050 051 this.directions = directions; 052 053 startStateSpaceNode = new StateSpaceNode ( ); 054 055 goalStateSpaceNode = new StateSpaceNode ( ); 056 057 adjacentList = new ArrayList ( ); 058 } 059 060 ////////////////////////////////////////////////////////////////////// 061 ////////////////////////////////////////////////////////////////////// 062 063 public void setGoalPointXY ( PointXY goalPointXY ) 064 ////////////////////////////////////////////////////////////////////// 065 { 066 goalStateSpaceNode.setPointXY ( goalPointXY ); 067 } 068 069 public void setStartStateSpaceNode ( 070 StateSpaceNode startStateSpaceNode ) 071 ////////////////////////////////////////////////////////////////////// 072 { 073 this.startStateSpaceNode.set ( startStateSpaceNode ); 074 } 075 076 public void setTankConsole ( TankConsole tankConsole ) 077 ////////////////////////////////////////////////////////////////////// 078 { 079 NullArgumentException.check ( this.tankConsole = tankConsole ); 080 } 081 082 ////////////////////////////////////////////////////////////////////// 083 // interface Cartographer methods 084 ////////////////////////////////////////////////////////////////////// 085 086 public double estimateCostToGoal ( Object node ) 087 ////////////////////////////////////////////////////////////////////// 088 { 089 return getCostToAdjacentNode ( node, goalStateSpaceNode ); 090 } 091 092 public Iterator getAdjacentNodes ( Object node ) 093 ////////////////////////////////////////////////////////////////////// 094 { 095 StateSpaceNode stateSpaceNode = ( StateSpaceNode ) node; 096 097 adjacentList.clear ( ); 098 099 double distanceToGoal 100 = stateSpaceNode.distance ( goalStateSpaceNode ); 101 102 double distanceFromStart 103 = stateSpaceNode.distance ( startStateSpaceNode ); 104 105 double stepSize 106 = ( ( int ) ( distanceFromStart / initStepSize ) ) * initStepSize; 107 108 stepSize = Math.max ( stepSize, initStepSize ); 109 110 if ( distanceToGoal <= stepSize ) 111 { 112 adjacentList.add ( goalStateSpaceNode ); 113 114 return adjacentList.iterator ( ); 115 } 116 117 PointXY pointXY = stateSpaceNode.getPointXY ( ); 118 119 double x = pointXY.getX ( ); 120 121 double y = pointXY.getY ( ); 122 123 PointXY goalPointXY = goalStateSpaceNode.getPointXY ( ); 124 125 double headingToGoal = Math.atan2 ( 126 goalPointXY.getY ( ) - y, 127 goalPointXY.getX ( ) - x ); 128 129 for ( int i = 0; i < directions; i++ ) 130 { 131 double heading = headingToGoal + i * 2.0 * Math.PI / directions; 132 133 StateSpaceNode adjacentStateSpaceNode = new StateSpaceNode ( 134 new Point2DD ( 135 x + stepSize * Math.cos ( heading ), 136 y + stepSize * Math.sin ( heading ) ), 137 heading ); 138 139 if ( tankConsole.isSpaceAvailable ( 140 adjacentStateSpaceNode.getPointXY ( ) ) ) 141 { 142 adjacentList.add ( adjacentStateSpaceNode ); 143 } 144 } 145 146 return adjacentList.iterator ( ); 147 } 148 149 public double getCostToAdjacentNode ( 150 Object fromNode, 151 Object toNode ) 152 ////////////////////////////////////////////////////////////////////// 153 { 154 StateSpaceNode fromStateSpaceNode = ( StateSpaceNode ) fromNode; 155 156 StateSpaceNode toStateSpaceNode = ( StateSpaceNode ) toNode; 157 158 double rotation = fromStateSpaceNode.rotation ( toStateSpaceNode ); 159 160 rotation = Math.abs ( rotation ); 161 162 double bodyRotationSpeed = tankConsole.getBodyRotationSpeed ( ); 163 164 double rotationTime = rotation / bodyRotationSpeed; 165 166 double travelTime = calculateTravelTime ( fromNode, toNode ); 167 168 double totalTime = travelTime + rotationTime; 169 170 return totalTime; 171 } 172 173 public boolean isGoalNode ( Object node ) 174 ////////////////////////////////////////////////////////////////////// 175 { 176 return 177 goalStateSpaceNode.distance ( ( StateSpaceNode ) node ) == 0.0; 178 } 179 180 ////////////////////////////////////////////////////////////////////// 181 ////////////////////////////////////////////////////////////////////// 182 183 private double calculateTravelTime ( 184 Object fromNode, 185 Object toNode ) 186 ////////////////////////////////////////////////////////////////////// 187 { 188 StateSpaceNode fromStateSpaceNode = ( StateSpaceNode ) fromNode; 189 190 StateSpaceNode toStateSpaceNode = ( StateSpaceNode ) toNode; 191 192 double distance = fromStateSpaceNode.distance ( toStateSpaceNode ); 193 194 return distance / tankConsole.getTankSpeed ( ); 195 } 196 197 ////////////////////////////////////////////////////////////////////// 198 ////////////////////////////////////////////////////////////////////// 199 }