/**
* Title: iSIM
* Copyright: Copyright (c) 2002
* Company: University of Oregon Computer Science Dept.
*
* @author Jason Prideaux
* @version 1.0
*
*/
package agent.autonomous;
import agent.*;
import controller.*;
import gui.*;
import transport.*;
import transport.protocol.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Date;
import java.io.*;
/* ====================================================================== */
/** This class represents a mobile autonomous robot. It has knowledge and
* state. The states determine the current goal of the robot. This robot
* simply searches the world for a person in distress. Once found, the
* robot will notify a Rescuer to save person. Once the Rescuer has saved
* the person, this robot will then continue to look for more people.
*
* When the robot senses data/communication it will respond by making some
* sort of actuation. So if the sensors were to fail. This robot would
* be dead in the water.
*
*/
public class Searcher extends Autonomous implements SocketReceiverListener{
/** The simulation controller, only used to determine our simulation
environment boundaries. */
private Controller controller;
// Knowledge
/** The location of the rescuer robot. */
private Point rescuer;
/** The location of person that needs to be rescued that we found. */
private Point distress;
// States
/** If true then remain idle. */
private boolean idle;
/** If true then search the world. */
private boolean searching;
/** If true then go to rescuer to get help. */
private boolean requesting;
/* ====================================================================== */
/** This constructor sets up the information needed for the robot.
* Naturally the robot must know its own abilities. The simulation
* controller is needed so that it can be given to the mediator class,
* Autonomous.java, which serves as an inbetween for a robot and the
* simulator.
*
* @param c The iSIM controller.
* @param loc The location of the agent.
* @param port The communication port need to speak with iSIM.
* @param range The wireless max range.
*
*/
public Searcher(Controller c, Point loc, int port, int range){
// Super our agent/user information.
super(c, loc, port, range, "searcher");
// Simulation controller
controller = c;
// our initial state.
idle = true;
searching = false;
requesting = false;
} //Constructor
// Use this method to receive new location data.
public void senseLocation(Point location, double heading){
if( !idle ){
Point newLocation = location;
double newHeading = heading;
if( searching ){
// Right now we search randomly
double coin = Math.random();
if( coin < 0.3333 ){
newHeading += 45;
}else if( coin < 0.6667 ){
newHeading -= 45;
}
if( newHeading < 0 ){
newHeading = 315;
}else if( newHeading > 315 ){
newHeading = 0;
}
int x = (int)(location.getX()+(Math.cos(Math.toRadians(newHeading))*15));
int y = (int)(location.getY()+(Math.sin(Math.toRadians(newHeading))*-15));
if( x < 15 ){
newHeading = 0;
}else if( y < 15 ){
newHeading = 270;
}else if( x > (controller.getChartComp().getSize().getWidth()-15) ){
newHeading = 180;
}else if( y > (controller.getChartComp().getSize().getHeight()-15) ){
newHeading = 90;
}else{
newLocation = new Point(x,y);
}
actuateLocation( newLocation, newHeading);
}else if( requesting ){
// Determine angle to rescuer to get help from
double hyp = Controller.diff(rescuer, location);
double opp = Math.abs(location.getY() - rescuer.getY());
double angle = Math.toDegrees(Math.asin(opp/hyp));
double fixed = 0;
if( location.getX() <= rescuer.getX() && location.getY() <= rescuer.getY() ){
fixed = 360 - angle;
}else if( location.getX() > rescuer.getX() && location.getY() <= rescuer.getY() ){
fixed = 180 + angle;
}else if( location.getX() <= rescuer.getX() && location.getY() > rescuer.getY()){
fixed = angle;
}else if( location.getX() > rescuer.getX() && location.getY() > rescuer.getY()){
fixed = 180 - angle;
}
double adjust = fixed%45;
if( adjust < 22.5 ){
newHeading = ((int)(fixed/45))*45;
}else{
newHeading = ((int)(fixed/45)+1)*45;
}
if( newHeading < 0 ){
newHeading = 315;
}else if( newHeading > 315 ){
newHeading = 0;
}
int x = (int)(location.getX()+(Math.cos(Math.toRadians(newHeading))*15));
int y = (int)(location.getY()+(Math.sin(Math.toRadians(newHeading))*-15));
if( x < 15 ){
newHeading = 0;
}else if( y < 15 ){
newHeading = 270;
}else if( x > (controller.getChartComp().getSize().getWidth()-15) ){
newHeading = 180;
}else if( y > (controller.getChartComp().getSize().getHeight()-15) ){
newHeading = 90;
}else{
newLocation = new Point(x,y);
}
actuateLocation( newLocation, newHeading);
}
}
}
// Use this method to receive communication from other robots
// and people agents.
public void senseMessage(HelpMessage msg){
// If idle then we only listen to rescuer to tell us to search again.
if( idle ){
if( ((HelpMessage)msg).getMessage().equalsIgnoreCase("rescuer") ){
rescuer = ((HelpMessage)msg).getLocation();
idle = false;
searching = true;
actuateMessage(new HelpMessage("searching", getPort(), 1, null ));
actuateLocation( this.getLocation(), this.getPosition().getHeading());
}
// If searching then we only listen to a person in distress
}else if( searching ){
if( ((HelpMessage)msg).getMessage().equalsIgnoreCase("help") ){
distress = ((HelpMessage)msg).getLocation();
searching = false;
requesting = true;
}
// If going to request help, then we only listen for a rescuer.
}else if( requesting ){
if( ((HelpMessage)msg).getMessage().equalsIgnoreCase("rescuer") ){
actuateMessage(new HelpMessage("request", getPort(), 1, distress ));
}else if( ((HelpMessage)msg).getMessage().equalsIgnoreCase("idle") ){
idle = true;
requesting = false;
}
}
}
} //class: Searcher