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 }