From b44c54ef92d3ec7abe1a8f1a54b36f7e0e5eb4a0 Mon Sep 17 00:00:00 2001
From: dansl <dansl@LAPTOP-SIKRVJU7.ern.nps.edu>
Date: Thu, 25 May 2023 09:16:25 -0700
Subject: [PATCH] Commit Changes to Assignment 7 for Cookie Cutter Sensor

---
 .../mv3302/SimpleConstantRateMediator.java    |  43 ++++
 .../mv3302/SimpleConstantTimeMediator.java    |  30 +++
 .../mv3302/SimpleCookieCutterMediator.java    |  28 +++
 MV3302ClassCode/src/mv3302/SimpleMover.java   |   4 +-
 MV3302ClassCode/src/mv3302/SimpleReferee.java | 197 ++++++++++++++++++
 .../src/mv3302/run/Assignment7.java           |  71 +++----
 .../run/Assignment7CookieSensor2Movers.java   |  86 ++++++++
 .../src/mv3302/run/TestAnimations.java        | 110 ++++++++++
 .../mv3302/sensor/AbstractSimpleSensor.java   | 123 ++++++-----
 MV3302ClassCode/src/mv3302/sensor/Sensor.java |  10 +-
 .../sensor/SimpleConstantRateSensor.java      |  11 +-
 .../sensor/SimpleConstantTimeSensor.java      |  12 +-
 .../sensor/SimpleCookieCutterSensor.java      |  18 +-
 13 files changed, 624 insertions(+), 119 deletions(-)
 create mode 100644 MV3302ClassCode/src/mv3302/SimpleConstantRateMediator.java
 create mode 100644 MV3302ClassCode/src/mv3302/SimpleConstantTimeMediator.java
 create mode 100644 MV3302ClassCode/src/mv3302/SimpleCookieCutterMediator.java
 create mode 100644 MV3302ClassCode/src/mv3302/SimpleReferee.java
 create mode 100644 MV3302ClassCode/src/mv3302/run/Assignment7CookieSensor2Movers.java
 create mode 100644 MV3302ClassCode/src/mv3302/run/TestAnimations.java

diff --git a/MV3302ClassCode/src/mv3302/SimpleConstantRateMediator.java b/MV3302ClassCode/src/mv3302/SimpleConstantRateMediator.java
new file mode 100644
index 0000000000..810652978d
--- /dev/null
+++ b/MV3302ClassCode/src/mv3302/SimpleConstantRateMediator.java
@@ -0,0 +1,43 @@
+package mv3302;
+
+import mv3302.sensor.SimpleConstantRateSensor;
+import simkit.SimEntityBase;
+import simkit.random.RandomVariate;
+import simkit.smd.Mover;
+
+/**
+ *
+ * @author dansl
+ */
+public class SimpleConstantRateMediator extends SimEntityBase {
+
+    public RandomVariate exponentialGenerator;
+
+        public void doEnterRange(Mover target, SimpleConstantRateSensor sensor) {
+        if (!sensor.getContacts().contains(target)) {
+            sensor.waitDelay("Detection", exponentialGenerator.generate(), target);
+        }
+
+    }
+
+    public void doExitRange(Mover target, SimpleConstantRateSensor sensor) {
+        if (!sensor.getContacts().contains(target)) {
+            sensor.waitDelay("Undetection", exponentialGenerator.generate(), target);
+        }
+    }
+
+    /**
+     * @return the exponentialGenerator
+     */
+    public RandomVariate getExponentialGenerator() {
+        return exponentialGenerator;
+    }
+
+    /**
+     * @param exponentialGenerator the exponentialGenerator to set
+     */
+    public void setExponentialGenerator(RandomVariate exponentialGenerator) {
+        this.exponentialGenerator = exponentialGenerator;
+    }
+
+}
diff --git a/MV3302ClassCode/src/mv3302/SimpleConstantTimeMediator.java b/MV3302ClassCode/src/mv3302/SimpleConstantTimeMediator.java
new file mode 100644
index 0000000000..8f1789c993
--- /dev/null
+++ b/MV3302ClassCode/src/mv3302/SimpleConstantTimeMediator.java
@@ -0,0 +1,30 @@
+/*
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ */
+package mv3302;
+
+import mv3302.sensor.SimpleConstantTimeSensor;
+import simkit.SimEntityBase;
+import simkit.smd.Mover;
+
+/**
+ *
+ * @author dansl
+ */
+public class SimpleConstantTimeMediator extends SimEntityBase {
+
+    public void doEnterRange(Mover target, SimpleConstantTimeSensor sensor) {
+        if (!sensor.getContacts().contains(target)) {
+            sensor.waitDelay("Detection", sensor.getTimeToDetect(), target);
+        }
+
+    }
+
+    public void doExitRange(Mover target, SimpleConstantTimeSensor sensor) {
+        if (!sensor.getContacts().contains(target)) {
+            sensor.waitDelay("Undetection", 0.0, target);
+        }
+    }
+
+}
diff --git a/MV3302ClassCode/src/mv3302/SimpleCookieCutterMediator.java b/MV3302ClassCode/src/mv3302/SimpleCookieCutterMediator.java
new file mode 100644
index 0000000000..831f3e7764
--- /dev/null
+++ b/MV3302ClassCode/src/mv3302/SimpleCookieCutterMediator.java
@@ -0,0 +1,28 @@
+package mv3302;
+
+import mv3302.sensor.SimpleCookieCutterSensor;
+import simkit.SimEntityBase;
+import simkit.smd.Mover;
+
+/**
+ *
+ * @author dansl
+ */
+public class SimpleCookieCutterMediator extends SimEntityBase {
+
+    public void doEnterRange(Mover target, SimpleCookieCutterSensor sensor) {
+        if (!sensor.getContacts().contains(target)) {
+            sensor.waitDelay("Detection", 0.0, target);
+        }
+
+    }
+
+    public void doExitRange(Mover target, SimpleCookieCutterSensor sensor) {
+        if (!sensor.getContacts().contains(target)) {
+            sensor.waitDelay("Undetection", 0.0, target);
+        }
+        if (!sensor.getContacts().contains(target)) {
+            interrupt("Detection", 0.0, target);
+        }
+    }
+}
diff --git a/MV3302ClassCode/src/mv3302/SimpleMover.java b/MV3302ClassCode/src/mv3302/SimpleMover.java
index a28e919049..29010a428e 100644
--- a/MV3302ClassCode/src/mv3302/SimpleMover.java
+++ b/MV3302ClassCode/src/mv3302/SimpleMover.java
@@ -222,7 +222,7 @@ public class SimpleMover extends SimEntityBase implements Mover {
      * @return copy of the initialLocation
      */
     public Point2D getInitialLocation() {
-        return (Point2D) initialLocation.clone();
+        return (Point2D) initialLocation;
     }
 
     /**
@@ -247,7 +247,7 @@ public class SimpleMover extends SimEntityBase implements Mover {
      * @return copy of the lastStopLocation
      */
     public Point2D getLastStopLocation() {
-        return (Point2D) lastStopLocation.clone();
+        return (Point2D) lastStopLocation;
     }
 
     /**
diff --git a/MV3302ClassCode/src/mv3302/SimpleReferee.java b/MV3302ClassCode/src/mv3302/SimpleReferee.java
new file mode 100644
index 0000000000..bbb60c27b4
--- /dev/null
+++ b/MV3302ClassCode/src/mv3302/SimpleReferee.java
@@ -0,0 +1,197 @@
+package mv3302;
+
+import java.awt.geom.Point2D;
+import static java.lang.Math.sqrt;
+import java.util.ArrayList;
+import java.util.List;
+import simkit.SimEntityBase;
+import static simkit.smd.Math2D.ZERO;
+import simkit.smd.Mover;
+import simkit.smd.Sensor;
+
+/**
+ *
+ * @author dsloan
+ */
+public final class SimpleReferee extends SimEntityBase {
+
+    private List<Sensor> sensors;
+
+    private List<Mover> targets;
+
+    public SimpleReferee() {
+    }
+
+    public SimpleReferee(List<Sensor> sensors, List<Mover> targets) {
+        setSensors(sensors);
+        setTargets(targets);
+    }
+
+    public void doRun() {
+        if (!sensors.isEmpty()) {
+            waitDelay("InitSensor", 0.0, 0);
+        }
+    }
+
+    public void doInitSensor(int i) {
+        sensors.get(i).addSimEventListener(this);
+
+        if (i < sensors.size() - 1) {
+            waitDelay("InitSensor", 0.0, i + 1);
+        }
+
+        waitDelay("InitTarget", 0.0, i, 0);
+    }
+
+    public void doInitTarget(int i, int j) {
+        targets.get(j).addSimEventListener(this);
+        if (j < targets.size() - 1) {
+            waitDelay("InitTarget", 0.0, i, j + 1);
+        }
+
+        if (targets.get(j).getCurrentLocation().distance(sensors.get(i).getCurrentLocation()) < sensors.get(i).getMaxRange()) {
+            if (!targets.get(j).equals(sensors.get(i).getMover())) {
+                waitDelay("EnterRange", 0.0, targets.get(j), sensors.get(i));
+            }
+        }
+    }
+    
+    public void doUpdateSensor(int i, Mover target) {
+        Sensor sensor = sensors.get(i);
+        if (!sensor.equals(target)) {
+            double[] times = getEnterExitTimes(target, sensor);
+            switch (times.length) {
+                case 0 -> {
+                }
+                case 1 -> {
+                    interrupt("ExitRange", target, sensor);
+                    waitDelay("ExitRange", times[0], target, sensor);
+                }
+                case 2 -> {
+                    interrupt("EnterRange", target, sensor);
+                    waitDelay("EnterRange", times[0], target, sensor);
+                }
+            }
+        }
+
+        if (i < sensors.size() - 1) {
+            waitDelay("UpdateSensor", 0.0, i + 1, target);
+        }
+
+    }
+    public void doStartMove(Mover target) {
+        waitDelay("UpdateSensor", 0.0, 0, target);
+    }
+
+    public void doStop(Mover target) {
+        waitDelay("UpdateSensor", 0.0, 0, target);
+    }
+
+    public void doUpdateTarget(int i, Sensor sensor) {
+        Mover target = targets.get(i);
+        double[] times = getEnterExitTimes(target, sensor);
+        switch (times.length) {
+            case 0 -> {
+            }
+            case 1 -> {
+                interrupt("ExitRange", target, sensor);
+                waitDelay("ExitRange", times[0], target, sensor);
+            }
+            case 2 -> {
+                interrupt("EnterRange", target, sensor);
+                waitDelay("EnterRange", times[0], target, sensor);
+            }
+        }
+        
+        if (i < targets.size() - 1) {
+            waitDelay("UpdateTarget", i + 1, sensor);
+        }
+    }
+
+    public void doStartMove(Sensor sensor) {
+        waitDelay("UpdateTarget", 0.0, 0, sensor);
+    }
+
+    public void doStop(Sensor sensor) {
+        waitDelay("UpdateTarget", 0.0, 0, sensor);
+    }
+
+    public void doEnterRange(Mover target, Sensor sensor) {
+        double[] times = getEnterExitTimes(target, sensor);
+        if (times.length == 1) {
+            waitDelay("ExitRange", times[0], target, sensor);
+        } else if (times.length == 2) {
+            waitDelay("ExitRange", times[1], target, sensor);
+        }
+    }
+    
+    public void doExitRange(Mover target, Sensor sensor) {
+    }
+
+    private double[] getEnterExitTimes(Mover target, Sensor sensor) {
+        double[] times;
+
+        Point2D relativeLocation = new Point2D.Double(
+                target.getCurrentLocation().getX() - sensor.getCurrentLocation().getX(),
+                target.getCurrentLocation().getY() - sensor.getCurrentLocation().getY()
+        );
+        Point2D relativeVelocity = new Point2D.Double(
+                target.getVelocity().getX() - sensor.getVelocity().getX(),
+                target.getVelocity().getY() - sensor.getVelocity().getY()
+        );
+
+        double velocitySquared = relativeVelocity.distanceSq(ZERO);
+        double distanceSqured = relativeLocation.distanceSq(ZERO);
+
+        double innerProduct = relativeLocation.getX() * relativeVelocity.getX()
+                + relativeLocation.getY() * relativeVelocity.getY();
+
+        double determinant = velocitySquared * (sensor.getMaxRange() * sensor.getMaxRange()
+                - distanceSqured) + innerProduct * innerProduct;
+        if (determinant < 0.0) {
+            times = new double[0];
+        } else {
+            double first = -innerProduct / velocitySquared;
+            double smallerRoot = first - sqrt(determinant) / velocitySquared;
+            double biggerRoot = first + sqrt(determinant) / velocitySquared;
+            if (smallerRoot > 0.0) {
+                times = new double[]{smallerRoot, biggerRoot};
+            } else if (biggerRoot > 0) {
+                times = new double[]{biggerRoot};
+            } else {
+                times = new double[0];
+            }
+        }
+
+        return times;
+    }
+
+    /**
+     * @return the sensors
+     */
+    public List<Sensor> getSensors() {
+        return new ArrayList<>(sensors);
+    }
+
+    /**
+     * @param sensors the sensors to set
+     */
+    public void setSensors(List<Sensor> sensors) {
+        this.sensors = new ArrayList<>(sensors);
+    }
+
+    /**
+     * @return the targets
+     */
+    public List<Mover> getTargets() {
+        return new ArrayList<>(targets);
+    }
+
+    /**
+     * @param targets the targets to set
+     */
+    public void setTargets(List<Mover> targets) {
+        this.targets = new ArrayList<>(targets);
+    }
+
+}
\ No newline at end of file
diff --git a/MV3302ClassCode/src/mv3302/run/Assignment7.java b/MV3302ClassCode/src/mv3302/run/Assignment7.java
index 241d6c5094..ca0f41ed2f 100644
--- a/MV3302ClassCode/src/mv3302/run/Assignment7.java
+++ b/MV3302ClassCode/src/mv3302/run/Assignment7.java
@@ -5,12 +5,15 @@
 package mv3302.run;
 
 import java.awt.geom.Point2D;
+import java.util.Arrays;
+import mv3302.SimpleCookieCutterMediator;
 import mv3302.SimpleMover;
 import mv3302.SimplePathMoverManager;
-import mv3302.sensor.SimpleConstantRateSensor;
-import mv3302.sensor.SimpleConstantTimeSensor;
+import mv3302.SimpleReferee;
 import mv3302.sensor.SimpleCookieCutterSensor;
 import simkit.Schedule;
+import simkit.smd.Mover;
+import simkit.smd.Sensor;
 import simkit.util.SimplePropertyDumper;
 
 /**
@@ -23,49 +26,41 @@ public class Assignment7 {
      * @param args the command line arguments
      */
     public static void main(String[] args) {
-        SimpleCookieCutterSensor cookieCutterSensor = new SimpleCookieCutterSensor();
-        cookieCutterSensor.setSimpleMover(new SimpleMover());
-        cookieCutterSensor.setMaxRange(10.0);
-        System.out.println(cookieCutterSensor);
 
-        SimpleConstantTimeSensor constantTimeSensor = new SimpleConstantTimeSensor();
-        constantTimeSensor.setSimpleMover(new SimpleMover());
-        constantTimeSensor.setMaxRange(10);
-        constantTimeSensor.setTimeToDetect(5.0);
-        System.out.println(constantTimeSensor);
+        Mover[] targets = new Mover[]{
+            new SimpleMover(new Point2D.Double(30.0, 40.0), 20.0), 
+            new SimpleMover(new Point2D.Double(0, 0), 20.0)
+        };
 
-        SimpleConstantRateSensor constantRateSensor = new SimpleConstantRateSensor();
-        constantRateSensor.setSimpleMover(new SimpleMover());
-        constantRateSensor.setMaxRange(10.0);
-        constantRateSensor.setMeanTimeToDetect(3.0);
-        System.out.println(constantRateSensor);
+        Point2D[] targetPath = new Point2D[]{new Point2D.Double(-30.0, -40.0), new Point2D.Double(60.0, 80.0)};
+        Point2D[] sensorPath = new Point2D[]{new Point2D.Double(30.0, 40.0)};
+        SimplePathMoverManager[] targetMoverManager = new SimplePathMoverManager[]{
+            new SimplePathMoverManager(targetPath, true),
+            new SimplePathMoverManager(sensorPath, true)
+        };
 
-        Point2D sensorLocation = new Point2D.Double(0.0, 0.0);
-        SimpleMover simpleSensorMover = new SimpleMover();
-        double maxRange = 20.0;
-        double timeToDetect = 5.0;
-        SimpleConstantTimeSensor simpleConstantTimeSensor = new SimpleConstantTimeSensor(simpleSensorMover, maxRange, timeToDetect);
-        System.out.println(simpleSensorMover.paramString());
+        Sensor[] sensors = new Sensor[targets.length];
+        sensors[0] = new SimpleCookieCutterSensor(targets[0], 30);
+        sensors[1] = new SimpleCookieCutterSensor(targets[1], 40);
 
-        Point2D targetLocation = new Point2D.Double(0.0, 10.0);
-        double targetMaxSpeed = 40;
-        SimpleMover simpleMover = new SimpleMover(targetLocation, targetMaxSpeed);
-        System.out.println(simpleMover.paramString());
-
-        Point2D[] path = new Point2D[]{new Point2D.Double(50.0, -20.0)};
-        SimplePathMoverManager simplePathMoverManager = new SimplePathMoverManager(path, true);
-        System.out.println(simplePathMoverManager);
+        SimplePropertyDumper simplePropertyDumper = new SimplePropertyDumper(true);
+        for (Sensor sensor: sensors) {
+            sensor.addPropertyChangeListener(simplePropertyDumper);
+        }
+        
+        for (int i = 0; i < targets.length; ++i) {
+            targets[i].addSimEventListener(targetMoverManager[i]);
+            targetMoverManager[i].addSimEventListener(targets[i]);
+        }
 
-        simplePathMoverManager.addSimEventListener(simpleMover);
-        simpleMover.addSimEventListener(simplePathMoverManager);
+        SimpleReferee simpleReferee = new SimpleReferee(Arrays.asList(sensors),
+                Arrays.asList(targets));
+        System.out.println(simpleReferee);
+        
+        SimpleCookieCutterMediator simpleCookieCutterMediator = new SimpleCookieCutterMediator();
+        simpleReferee.addSimEventListener(simpleCookieCutterMediator);
 
-        SimplePropertyDumper simplePropertyDumper = new SimplePropertyDumper(true);
-        simpleConstantTimeSensor.addPropertyChangeListener(simplePropertyDumper);
-        simpleMover.addPropertyChangeListener(simplePropertyDumper);
-        simplePathMoverManager.addPropertyChangeListener(simplePropertyDumper);       
-                
         Schedule.setVerbose(true);
-        
         Schedule.reset();
         Schedule.startSimulation();
     }
diff --git a/MV3302ClassCode/src/mv3302/run/Assignment7CookieSensor2Movers.java b/MV3302ClassCode/src/mv3302/run/Assignment7CookieSensor2Movers.java
new file mode 100644
index 0000000000..630dfa055f
--- /dev/null
+++ b/MV3302ClassCode/src/mv3302/run/Assignment7CookieSensor2Movers.java
@@ -0,0 +1,86 @@
+package mv3302.run;
+
+import java.awt.geom.Point2D;
+import java.util.ArrayList;
+import java.util.List;
+import mv3302.SimpleCookieCutterMediator;
+import mv3302.SimpleMover;
+import mv3302.SimplePathMoverManager;
+import mv3302.SimpleReferee;
+import mv3302.sensor.AbstractSimpleSensor;
+import mv3302.sensor.SimpleCookieCutterSensor;
+import simkit.Schedule;
+import simkit.smd.Mover;
+import simkit.smd.Sensor;
+import simkit.util.SimplePropertyDumper;
+
+/**
+ *
+ * @author ahbuss
+ */
+public class Assignment7CookieSensor2Movers {
+
+    /**
+     * @param args the command line arguments
+     */
+    public static void main(String[] args) {
+        
+        SimpleMover mover1 = new SimpleMover(new Point2D.Double(-20.0, 0.0), 30.0);
+        AbstractSimpleSensor sensor1 = new SimpleCookieCutterSensor(mover1, 20.0);
+        Point2D[] moverPath1 = new Point2D[]{
+            new Point2D.Double(100.0, 0.0)
+        };
+        SimplePathMoverManager moverManager1 = new SimplePathMoverManager(moverPath1, true);
+        
+        mover1.addSimEventListener(moverManager1);
+        moverManager1.addSimEventListener(mover1);
+        
+        SimpleMover mover2 = new SimpleMover(new Point2D.Double(50.0, 0.0), 40.0);
+        AbstractSimpleSensor sensor2 = new SimpleCookieCutterSensor(mover2, 30.0);
+        Point2D[] moverPath2 = new Point2D[] {
+            new Point2D.Double(-100.0, 0.0)
+        };
+        SimplePathMoverManager moverManager2 = new SimplePathMoverManager(moverPath2, true);
+        mover2.addSimEventListener(moverManager2);
+        moverManager2.addSimEventListener(mover2);
+
+        SimplePropertyDumper simplePropertyDumper = new SimplePropertyDumper(true);
+        mover1.addPropertyChangeListener(simplePropertyDumper);
+        moverManager1.addPropertyChangeListener(simplePropertyDumper);
+        sensor1.addPropertyChangeListener(simplePropertyDumper);
+        
+        mover2.addPropertyChangeListener(simplePropertyDumper);
+        moverManager2.addPropertyChangeListener(simplePropertyDumper);
+        sensor2.addPropertyChangeListener(simplePropertyDumper);
+        
+        List<Mover> targets = new ArrayList<>();
+        targets.add(mover1);
+        targets.add(mover2);
+        
+        List<Sensor> sensors = new ArrayList<>();
+        sensors.add(sensor1);
+        sensors.add(sensor2);
+        
+        SimpleReferee referee = new SimpleReferee(sensors, targets);
+        
+        SimpleCookieCutterMediator mediator1 = new SimpleCookieCutterMediator();
+        referee.addSimEventListener(mediator1);
+        
+        System.out.println(mover1.paramString());
+        System.out.println(moverManager1);
+        System.out.println(sensor1.paramString());
+        
+        System.out.println(mover2.paramString());
+        System.out.println(moverManager2);
+        System.out.println(sensor2.paramString());
+        
+        System.out.println(referee);
+        
+        Schedule.setVerbose(true);
+        
+        Schedule.reset();
+        Schedule.startSimulation();
+        
+    }
+    
+}
diff --git a/MV3302ClassCode/src/mv3302/run/TestAnimations.java b/MV3302ClassCode/src/mv3302/run/TestAnimations.java
new file mode 100644
index 0000000000..ca548c6d86
--- /dev/null
+++ b/MV3302ClassCode/src/mv3302/run/TestAnimations.java
@@ -0,0 +1,110 @@
+import java.awt.Color;
+import java.awt.geom.Point2D;
+import java.util.ArrayList;
+import java.util.List;
+import mv3302.SimpleCookieCutterMediator;
+import mv3302.SimpleMover;
+import mv3302.SimplePatrolMoverManager;
+import mv3302.SimpleReferee;
+import mv3302.sensor.AbstractSimpleSensor;
+import mv3302.sensor.SimpleCookieCutterSensor;
+import simkit.Schedule;
+import simkit.animate.SandboxFrame;
+import simkit.smd.Mover;
+import simkit.smd.Sensor;
+import simkit.util.PropertyChangeFrame;
+
+/**
+ *
+ * @author ahbuss
+ */
+public class TestAnimations {
+
+    /**
+     * @param args the command line arguments
+     */
+    public static void main(String[] args) {
+        
+        SimpleMover mover1 = new SimpleMover(new Point2D.Double(-20.0, 0.0), 30.0);
+        AbstractSimpleSensor sensor1 = new SimpleCookieCutterSensor(mover1, 20.0);
+        Point2D[] moverPath1 = new Point2D[]{
+            new Point2D.Double(100.0, 0.0),
+            mover1.getInitialLocation()
+        };
+        SimplePatrolMoverManager moverManager1 = new SimplePatrolMoverManager(moverPath1, true);
+        
+        mover1.addSimEventListener(moverManager1);
+        moverManager1.addSimEventListener(mover1);
+        
+        SimpleMover mover2 = new SimpleMover(new Point2D.Double(50.0, 0.0), 40.0);
+        AbstractSimpleSensor sensor2 = new SimpleCookieCutterSensor(mover2, 30.0);
+        Point2D[] moverPath2 = new Point2D[] {
+            new Point2D.Double(-100.0, 0.0),
+            mover2.getInitialLocation()
+        };
+        SimplePatrolMoverManager moverManager2 = new SimplePatrolMoverManager(moverPath2, true);
+        mover2.addSimEventListener(moverManager2);
+        moverManager2.addSimEventListener(mover2);
+
+//        PropertyChangeListener propertyChangeFrame = new SimplePropertyDumper(true);
+        PropertyChangeFrame propertyChangeFrame = new PropertyChangeFrame();
+//        mover1.addPropertyChangeListener(propertyChangeFrame);
+//        moverManager1.addPropertyChangeListener(propertyChangeFrame);
+        sensor1.addPropertyChangeListener("detection", propertyChangeFrame);
+        sensor1.addPropertyChangeListener("undetection", propertyChangeFrame);
+        
+//        mover2.addPropertyChangeListener(propertyChangeFrame);
+//        moverManager2.addPropertyChangeListener(propertyChangeFrame);
+        sensor2.addPropertyChangeListener("detection", propertyChangeFrame);
+        sensor2.addPropertyChangeListener("undetection", propertyChangeFrame);
+//        
+        List<Mover> targets = new ArrayList<>();
+        targets.add(mover1);
+        targets.add(mover2);
+        
+        List<Sensor> sensors = new ArrayList<>();
+        sensors.add(sensor1);
+        sensors.add(sensor2);
+        
+        SimpleReferee referee = new SimpleReferee(sensors, targets);
+        
+        SimpleCookieCutterMediator mediator1 = new SimpleCookieCutterMediator();
+        referee.addSimEventListener(mediator1);
+        
+        System.out.println(mover1.paramString());
+        System.out.println(moverManager1);
+        System.out.println(sensor1.paramString());
+        
+        System.out.println(mover2.paramString());
+        System.out.println(moverManager2);
+        System.out.println(sensor2.paramString());
+        
+        System.out.println(referee);
+        
+        Schedule.setVerbose(false);
+        
+//        Schedule.stopOnEvent(5, "Detection", SimpleMover.class);
+        
+        
+        SandboxFrame sandboxFrame = new SandboxFrame("Simple Referee");
+        sandboxFrame.getSandbox().setOrigin(new Point2D.Double(200, 200));
+        sandboxFrame.getSandbox().setDrawAxes(true);
+        
+        sandboxFrame.addMover(mover1, Color.BLUE);
+        sandboxFrame.addSensor(sensor1, Color.RED);
+        sandboxFrame.addMover(mover2, Color.GREEN);
+        sandboxFrame.addSensor(sensor2, Color.ORANGE);
+        
+        sandboxFrame.setVisible(true);
+        
+        propertyChangeFrame.setLocation(sandboxFrame.getX() + sandboxFrame.getWidth(), sandboxFrame.getY());
+        propertyChangeFrame.setVisible(true);
+        Schedule.reset();
+        
+        Schedule.addIgnoreOnDump("Ping");
+
+//        Schedule.startSimulation();
+        
+    }
+    
+}
diff --git a/MV3302ClassCode/src/mv3302/sensor/AbstractSimpleSensor.java b/MV3302ClassCode/src/mv3302/sensor/AbstractSimpleSensor.java
index 09568c82eb..b466959138 100644
--- a/MV3302ClassCode/src/mv3302/sensor/AbstractSimpleSensor.java
+++ b/MV3302ClassCode/src/mv3302/sensor/AbstractSimpleSensor.java
@@ -1,109 +1,134 @@
-
 package mv3302.sensor;
 
 import java.awt.geom.Point2D;
 import java.util.HashSet;
 import java.util.Set;
-import mv3302.SimpleMover;
 import simkit.SimEntityBase;
+import simkit.smd.Mover;
+
+import simkit.smd.Sensor;
 
 /**
  *
- * @author dansl
+ * @author ahbuss
  */
 public abstract class AbstractSimpleSensor extends SimEntityBase implements Sensor {
 
-    public double maxRange;
-    public SimpleMover simpleMover;
-    public Set<SimpleMover> contacts;
+    private Mover mover;
+
+    private double maxRange;
+
+    protected Set<Mover> contacts;
 
     public AbstractSimpleSensor() {
         contacts = new HashSet<>();
     }
 
-    public AbstractSimpleSensor(SimpleMover simpleMover, double maxRange) {
+    public AbstractSimpleSensor(Mover mover, double maxRange) {
         this();
-        setSimpleMover(simpleMover);
+        setMover(mover);
         setMaxRange(maxRange);
     }
 
-    public void doRun() {
+    @Override
+    public void reset() {
+        super.reset();
         contacts.clear();
     }
 
-    public void doDetection(SimpleMover simpleMover) {
-        Set<SimpleMover> oldContacts = getContacts();
-        contacts.add(simpleMover);
+    public void doRun() {
+        firePropertyChange("contacts", getContacts());
+    }
+
+    public void doDetection(Mover target) {
+        Set<Mover> oldContacts = getContacts();
+        contacts.add(target);
         firePropertyChange("contacts", oldContacts, getContacts());
 
-        firePropertyChange("detection", simpleMover);
+        firePropertyChange("detection", target);
     }
 
-    public void doUndetection(SimpleMover simpleMover) {
-        Set<SimpleMover> oldContacts = getContacts();
-        contacts.remove(simpleMover);
+    public void doUndetection(Mover target) {
+        Set<Mover> oldContacts = getContacts();
+        contacts.remove(target);
         firePropertyChange("contacts", oldContacts, getContacts());
 
-        firePropertyChange("undetection", simpleMover);
+        firePropertyChange("undetection", target);
     }
 
-    public void doStartMove(SimpleMover simpleMover) {
+    public void doStartMove(Mover mover) {
         waitDelay("StartMove", 0.0, this);
     }
 
-    public void doStartMove(Sensor sensor) {
-    }
-
-    public void doStop(SimpleMover simpleMover) {
+    public void doStop(Mover mover) {
         waitDelay("Stop", 0.0, this);
     }
 
-    public void doStop(Sensor sensor) {
-
+    /**
+     * @param mover the mover to set
+     */
+    public void setMover(Mover mover) {
+        this.mover = mover;
+        this.mover.addSimEventListener(this);
     }
 
+    /**
+     * @return the maxRange
+     */
     @Override
-    public Point2D getCurrentLocation() {
-        return simpleMover.getCurrentLocation();
-    }
-
-    public Point2D getVelocity() {
-        return simpleMover.getVelocity();
-    }
-
-    public void setSimpleMover(SimpleMover simpleMover) {
-        this.simpleMover = simpleMover;
+    public double getMaxRange() {
+        return maxRange;
     }
 
+    /**
+     * @param maxRange the maxRange to set
+     */
     public void setMaxRange(double maxRange) {
-        if (maxRange <= 0.0) {
-            throw new IllegalArgumentException("maxRange must be > 0.0: " + maxRange);
+        if (maxRange < 0.0) {
+            throw new IllegalArgumentException("maxRange must be ≥ 0.0: " + maxRange);
         }
         this.maxRange = maxRange;
     }
 
-    public Set<SimpleMover> getContacts() {
+    /**
+     * @return the contacts
+     */
+    @Override
+    public Set<Mover> getContacts() {
         return new HashSet<>(contacts);
     }
 
     @Override
-    public String toString() {
-        return String.format("%s %s", getSimpleMover(), getMaxRange());
+    public Mover getMover() {
+        return mover;
     }
 
-    /**
-     * @return the maxRange
-     */
     @Override
-    public double getMaxRange() {
-        return maxRange;
+    public Point2D getCurrentLocation() {
+        return mover.getCurrentLocation();
     }
 
-    /**
-     * @return the simpleMover
-     */
     @Override
-    public SimpleMover getSimpleMover() {
-        return simpleMover;
+    public Point2D getVelocity() {
+        return mover.getVelocity();
     }
+
+    @Override
+    public void doStartMove(Sensor sensor) {
+    }
+
+    @Override
+    public void doStop(Sensor sensor) {
+    }
+    
+    public String paramString() {
+        return super.toString();
+    }
+    
+    @Override
+    public String toString() {
+        return String.format("%s %s %s %,.4f", getName(), mover.getCurrentLocation(), mover.getVelocity(),
+                getMaxRange());
+    }
+
 }
diff --git a/MV3302ClassCode/src/mv3302/sensor/Sensor.java b/MV3302ClassCode/src/mv3302/sensor/Sensor.java
index 7c2c05bd81..4b3c217bda 100644
--- a/MV3302ClassCode/src/mv3302/sensor/Sensor.java
+++ b/MV3302ClassCode/src/mv3302/sensor/Sensor.java
@@ -2,8 +2,8 @@ package mv3302.sensor;
 
 import java.awt.geom.Point2D;
 import java.util.Set;
-import mv3302.SimpleMover;
 import simkit.SimEntity;
+import simkit.smd.Mover;
 
 /**
  *
@@ -14,9 +14,9 @@ interface Sensor extends SimEntity {
     public Point2D getCurrentLocation();
     public Point2D getVelocity();
     public double getMaxRange();
-    public void doStartMove(SimpleMover simpleMover);
-    public void doStop(SimpleMover simpleMover);
-    public SimpleMover getSimpleMover();
-    public Set<SimpleMover> getContacts();
+    public void doStartMove(Mover mover);
+    public void doStop(Mover mover);
+    public Mover getMover();
+    public Set<Mover> getContacts();
 
 }
diff --git a/MV3302ClassCode/src/mv3302/sensor/SimpleConstantRateSensor.java b/MV3302ClassCode/src/mv3302/sensor/SimpleConstantRateSensor.java
index ba79c9b488..8f13494f73 100644
--- a/MV3302ClassCode/src/mv3302/sensor/SimpleConstantRateSensor.java
+++ b/MV3302ClassCode/src/mv3302/sensor/SimpleConstantRateSensor.java
@@ -1,8 +1,7 @@
 
 package mv3302.sensor;
 
-import java.util.HashSet;
-import mv3302.SimpleMover;
+import simkit.smd.Mover;
 
 /**
  *
@@ -13,13 +12,11 @@ public class SimpleConstantRateSensor extends AbstractSimpleSensor {
     private double meanTimeToDetect;
 
     public SimpleConstantRateSensor() {
-        contacts = new HashSet<>();
+        super();
     }
 
-    public SimpleConstantRateSensor(SimpleMover simpleMover, double maxRange, double meanTimeToDetect) {
-        this();
-        setSimpleMover(simpleMover);
-        setMaxRange(maxRange);
+    public SimpleConstantRateSensor(Mover mover, double maxRange, double meanTimeToDetect) {
+        super(mover, maxRange);
         setMeanTimeToDetect(meanTimeToDetect);
     }
 
diff --git a/MV3302ClassCode/src/mv3302/sensor/SimpleConstantTimeSensor.java b/MV3302ClassCode/src/mv3302/sensor/SimpleConstantTimeSensor.java
index da862ca784..ee004a827b 100644
--- a/MV3302ClassCode/src/mv3302/sensor/SimpleConstantTimeSensor.java
+++ b/MV3302ClassCode/src/mv3302/sensor/SimpleConstantTimeSensor.java
@@ -2,7 +2,7 @@
 package mv3302.sensor;
 
 import java.util.HashSet;
-import mv3302.SimpleMover;
+import simkit.smd.Mover;
 
 /**
  *
@@ -13,17 +13,15 @@ public class SimpleConstantTimeSensor extends AbstractSimpleSensor {
     private double timeToDetect;
 
     public SimpleConstantTimeSensor() {
-        contacts = new HashSet<>();
+                super();
     }
 
-    public SimpleConstantTimeSensor(SimpleMover simpleMover, double maxRange, double timeToDetect) {
-        this();
-        setSimpleMover(simpleMover);
-        setMaxRange(maxRange);
+    public SimpleConstantTimeSensor(Mover mover, double maxRange, double timeToDetect) {
+        super(mover, maxRange);
         setTimeToDetect(timeToDetect);
     }
 
-    double getTimeToDetect() {
+    public double getTimeToDetect() {
         return timeToDetect;
     }
 
diff --git a/MV3302ClassCode/src/mv3302/sensor/SimpleCookieCutterSensor.java b/MV3302ClassCode/src/mv3302/sensor/SimpleCookieCutterSensor.java
index b1d3fdc10f..94dd4759c1 100644
--- a/MV3302ClassCode/src/mv3302/sensor/SimpleCookieCutterSensor.java
+++ b/MV3302ClassCode/src/mv3302/sensor/SimpleCookieCutterSensor.java
@@ -1,23 +1,19 @@
 
 package mv3302.sensor;
 
-import java.util.HashSet;
-import mv3302.SimpleMover;
+import simkit.smd.Mover;
 
 /**
  *
- * @author dansl
+ * @author ahbuss
  */
 public class SimpleCookieCutterSensor extends AbstractSimpleSensor {
-
+    
     public SimpleCookieCutterSensor() {
-        contacts = new HashSet<>();
+        super();
     }
-
-    public SimpleCookieCutterSensor(SimpleMover simpleMover, double maxRange) {
-        this();
-        setSimpleMover(simpleMover);
-        setMaxRange(maxRange);
+    
+    public SimpleCookieCutterSensor(Mover mover, double maxRange) {
+        super(mover, maxRange);
     }
-
 }
-- 
GitLab