Single-shot wallSmoothing
This is the thread's initial revision.
I came across a skill issue some time ago. I could get a robot to orbit an enemy, but wall-smashing became a certainty.
The problem was how to effectively implement wall-smoothing. The issue: some methods proved, given that the implementation may have been lacking accuracy, slower than others.
For this misguided reason I sought a one-shot method to appropriate the walls. The idea garnered a good reaction from the correct person to get a good reaction from.
== Brutish as it may be, the original idea implemented:
1) Project a point p some WallStick distance ahead of the robot in the ideal direction of travel. 2) Test for p in bounds of arena
-- If p in bounds return ideal direction of travel.
3) Test for locality of 'outness' (above arena, below arena, left of arena, right of arena) 4) Solve the problem of being co-out, or out of bounds in two ways (top and right, left and bottom, left and top, bottom and right)
- This can be done by ignoring the correct one based on desired direction of turn.
-- Return the absolute angle parallel to the wall-o'-incidence
That is to say, if you're going clockwise and hit the top wall, your desired ultimate angle of travel is due east at PI/2 radians or 90 degrees. if you're going counter-clockwise and hit the bottom wall, your desired ultimate angle of travel is also due east.
It is then up to the robot to govern itself.
===============[edit]
Recently, I wrote a distance-finding method for a problem I came across. The problem:
As a robot in the arena, if you traveled directly forward until you hit a wall (So, given a point and a heading), how far would you travel before you hit that wall?
There's the simple solution that walks the robot 1 pixel at a time down that heading until collision is detected, but it doesn't scale well if needed often.
But I propose a non-iterative solution; hidden in cosine similarity.
1) Check if facing right or left 2) Measure your known X, solving for lateral distance to wall. 2.1) Apply cosine similarity to heading and absolute angle of wall in that direction. 3) Check if facing up or down 4) Measure vertical distance from wall 4.1) Apply cosine similarity to that.
//At this point there's a pretty good chance you're gonna run across a huge number or infinity. //Luckily, only one of them will be super huge, the other is our solution. 5)It's the closest wall that matters, so take the minimum between the horizontal and vertical solutions.
static double calcWallSpace(final Point eCenter, double eGoing) { eGoing = Utils.normalAbsoluteAngle(eGoing); final double wallDistLat = eGoing < Helpers.PI ? (Identity.PLAY_WIDTH+18d-eCenter.getX()) / (Helpers.cos((Helpers.PI/2d - eGoing))) : eCenter.getX() / (Helpers.cos((3d*Helpers.PI/2d - eGoing))); eGoing = Utils.normalRelativeAngle(eGoing); final double wallDistVirt = Math.abs(Utils.normalRelativeAngle(eGoing)) < Helpers.PI / 2d ? (Identity.PLAY_HEIGHT+18d-eCenter.getY()) / (Helpers.cos(eGoing)) : eCenter.getY() / (Helpers.cos(Helpers.PI - eGoing)); return(float)(Math.min(wallDistLat, wallDistVirt) / Identity.MAX_DIST); }
====================[edit]
This rebirthed my hope for a somewhat more effective one-shot wall avoidance.
(Keep in mind these aren't really one-shot functions due to the angle renormalization methods in the distance-finding class above. However, these are likely going to execute once if at all, and don't seem to impose their full potential downsides on running time.)
The idea: Perhaps, using the distance-to-wall information can allow me to functionally smooth the response from the effective wallTurn method.
The conclusion: it can. I think I can rest now that we can glance at a wall and get a heading that gradually changes as we approach the wall.
static double wallSmooth(final Point center, final int velDir, double heading, final int latDir) { final double wallSpace; final Point future = project(center, velDir * 165d, heading); boolean top = future.getY() > Identity.PLAY_HEIGHT + 18d, bottom = future.getY() < 18, left = future.getX() < 18, right = future.getX() >= Identity.PLAY_WIDTH + 18d; //NOTE: I invert the heading for negative velocities in the next line final double wallSpaceFact = (1d - (wallSpace=Math.min(0.2d, calcWallSpace(center, Utils.normalAbsoluteAngle((heading = (heading + (velDir-1)/2 * Helpers.PI))))) * 5.2d)*wallSpace*wallSpace); double desiredAngle = heading; switch(latDir) { case 1: if(top && right) top = false; if(left && top) left = false; if(bottom && left) bottom = false; if(right && bottom) right = false; if(top) desiredAngle += Utils.normalRelativeAngle(Helpers.HALF_PI - heading) * wallSpaceFact; else if(right) desiredAngle += Utils.normalRelativeAngle(Helpers.PI - heading) * wallSpaceFact; else if(bottom) desiredAngle += Utils.normalRelativeAngle(Helpers.THREE_OVER_TWO_PI - heading) * wallSpaceFact; else if(left) desiredAngle += Utils.normalRelativeAngle(Helpers.TWO_PI - heading) * wallSpaceFact; break; case -1: if(top && right) right = false; if(left && top) top = false; if(bottom && left) left = false; if(right && bottom) bottom = false; if(top) desiredAngle += Utils.normalRelativeAngle(Helpers.THREE_OVER_TWO_PI - heading) * wallSpaceFact; else if(right) desiredAngle += Utils.normalRelativeAngle(0d - heading) * wallSpaceFact; else if(bottom) desiredAngle += Utils.normalRelativeAngle(Helpers.HALF_PI - heading) * wallSpaceFact; else if(left) desiredAngle += Utils.normalRelativeAngle(Helpers.PI - heading) * wallSpaceFact; break; default: System.out.println("quit it please"); break; } return Utils.normalAbsoluteAngle(desiredAngle); }
This makes one-shot avoidance 'smooth'.
As of the state of things, there is one testing bot that benefits in both speed and effectiveness by switching to this method. There are no other testing bots.