diff --git a/src/main/java/com/opennars/applications/crossing/BehaviourComponent.java b/src/main/java/com/opennars/applications/crossing/BehaviourComponent.java new file mode 100644 index 0000000..7ec0f5f --- /dev/null +++ b/src/main/java/com/opennars/applications/crossing/BehaviourComponent.java @@ -0,0 +1,140 @@ +/* + * The MIT License + * + * Copyright 2018 The OpenNARS authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.opennars.applications.crossing; + +import org.opennars.entity.TruthValue; + +import java.util.List; + +/** + * Component for the behaviour of an entity + */ +public class BehaviourComponent { + private final EnumType type; + + // initial angle (for the pedestriant) + public double initialAngle; + + public float maxSpeed = 2.0f; + + + + public BehaviourComponent(final EnumType type) { + this.type = type; + } + + public void tick(Entity entity, List streets, List trafficLights, List entities, TruthValue truth, long time) { + if (type == EnumType.CAR) { + carTick(entity, streets, trafficLights, entities, truth, time); + } + else if (type == EnumType.PEDESTRIAN) { + carTick(entity, streets, trafficLights, entities, truth, time); + + + + entity.angle+=(Util.rnd.nextFloat()*0.1-0.05); + //ok pedestrian, don't go on grass + boolean forPedestrians = false; + for(Street street : streets) { + if(!street.forCarsOnly && entity.posX > street.startX && entity.posX < street.endX && entity.posY > street.startY && entity.posY < street.endY) { + forPedestrians = true; + break; + } + } + + + if(!forPedestrians) { + entity.angle = initialAngle; + entity.posX = entity.prevX; + entity.posY = entity.prevY; + } + } + } + + + static protected void carTick(Entity entity, List streets, List trafficLights, List entities, TruthValue truth, long time) { + if(truth != null) { + return; + } + + boolean accelerate = true; + for (TrafficLight l : trafficLights) { + if (Util.distance(entity.posX, entity.posY, l.posX, l.posY) < l.radius) { + if (l.colour == l.RED) { + if (Util.rnd.nextFloat() > 0.3 && ((entity.tag.equals("car") && !entity.carIgnoreTrafficLight) || (entity.tag.equals("pedestrian") && !entity.pedestrianIgnoreTrafficLight))) { + entity.velocity *= 0.5; + accelerate = false; + } + } + } + } + for (Entity e : entities) { + boolean collidable = !(entity.tag.equals("pedestrian") && e.tag.equals("pedestrian")); + if (e != entity && collidable) { + double nearEnough = 10; + for (double k = 0; k < nearEnough; k += 0.1) { + double pXNew = entity.posX + k * Math.cos(entity.angle); + double pYNew = entity.posY + k * Math.sin(entity.angle); + if (Util.distance(pXNew, pYNew, e.posX, e.posY) < nearEnough) { + entity.velocity *= 0.8; + accelerate = false; + } + } + } + } + + if (accelerate && entity.velocity < entity.behaviour.maxSpeed) { + entity.velocity += 0.02; + } + + double aX = Math.cos(entity.angle); + double aY = Math.sin(entity.angle); + entity.posX += aX * entity.velocity; + entity.posY += aY * entity.velocity; + + double epsilon = 1; + if (entity.posY < 0) { + entity.posY = 1000 - epsilon; + //this.id = entityID++; + } + if (entity.posY > 1000) { + entity.posY = epsilon; + //this.id = entityID++; + } + if (entity.posX < 0) { + entity.posX = 1000 - epsilon; + //this.id = entityID++; + } + if (entity.posX > 1000) { + entity.posX = epsilon; + //this.id = entityID++; + } + } + + public enum EnumType { + CAR, + PEDESTRIAN, + } + +} diff --git a/src/main/java/com/opennars/applications/crossing/Car.java b/src/main/java/com/opennars/applications/crossing/Car.java deleted file mode 100644 index b825d33..0000000 --- a/src/main/java/com/opennars/applications/crossing/Car.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * The MIT License - * - * Copyright 2018 The OpenNARS authors. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.opennars.applications.crossing; - -import java.util.List; -import org.opennars.entity.TruthValue; -import processing.core.PApplet; - -public class Car extends Entity { - - public Car(int id, double posX, double posY, double velocity, double angle) { - super(id, posX, posY, velocity, angle); - maxSpeed = 2; - } - - public void draw(PApplet applet, List streets, List trafficLights, List entities, TruthValue truth, long time) { - float mul = Util.truthToValue(truth) * Util.timeToValue(time); - applet.fill(255, 0, 255, mul*255.0f); - - if (!isPredicted && isAnomaly()) { - applet.stroke(255,0,0); - } - else { - applet.stroke(127); - } - - super.draw(applet, streets, trafficLights, entities, truth, time); - - applet.stroke(127); - } -} diff --git a/src/main/java/com/opennars/applications/crossing/Crossing.java b/src/main/java/com/opennars/applications/crossing/Crossing.java index 5e04c6f..508e944 100644 --- a/src/main/java/com/opennars/applications/crossing/Crossing.java +++ b/src/main/java/com/opennars/applications/crossing/Crossing.java @@ -65,13 +65,13 @@ public void setup() { trafficLights.add(new TrafficLight(trafficLightID++, trafficLightRadius/2, 500, 500 - trafficLightRadius, 1)); int cars = 4; //cars and pedestrians for (float i = 0; i < cars/2; i += 1.05) { - entities.add(new Car(entityID++, 500 + streetWidth - Util.discretization+1, 900 - i * 100, 0.3, -PI / 2)); - entities.add(new Car(entityID++, 500 + Util.discretization, 900 - i * 100, 0.3, PI / 2)); + entities.add(makeEntity("car", entityID++, 500 + streetWidth - Util.discretization+1, 900 - i * 100, 0.3, -PI / 2)); + entities.add(makeEntity("car", entityID++, 500 + Util.discretization, 900 - i * 100, 0.3, PI / 2)); } int pedestrians = 4;//4; for (float i = 0; i < pedestrians/2; i += 1.05) { - entities.add(new Pedestrian(entityID++, 900 - i * 100, 500 + streetWidth - Util.discretization, 0.3, 0)); - entities.add(new Pedestrian(entityID++, 900 - i * 100, 500 + Util.discretization, 0.3, -PI)); + entities.add(makeEntity("pedestrian", entityID++, 900 - i * 100, 500 + streetWidth - Util.discretization, 0.3, 0)); + entities.add(makeEntity("pedestrian", entityID++, 900 - i * 100, 500 + Util.discretization, 0.3, -PI)); } /*for (TrafficLight l : trafficLights) { //it can't move anyway, so why would the coordinates matter to NARS? String pos = Util.positionToTerm(l.posX, l.posY); @@ -126,7 +126,7 @@ public void draw() { // tick for (Entity ie : entities) { - ie.tick(); + ie.tick(streets, trafficLights, entities, null, 0); } @@ -141,10 +141,10 @@ public void draw() { if(showAnomalies) { for (Prediction pred : disappointments) { Entity e = pred.ent; - if(e instanceof Car) { + if(e.tag.equals("car")) { fill(255,0,0); } - if(e instanceof Pedestrian) { + if(e.tag.equals("pedestrian")) { fill(0,0,255); } this.text("ANOMALY", (float)e.posX, (float)e.posY); @@ -190,6 +190,27 @@ public void mouseDragged() { viewport.mouseDragged(); } + public static Entity makeEntity(final String tag, int id, double posX, double posY, double velocity, double angle) { + if (tag.equals("car")) { + Entity entity = new Entity(id, posX, posY, velocity, angle, "car", new BehaviourComponent(BehaviourComponent.EnumType.CAR)); + entity.behaviour.maxSpeed = 2; + return entity; + } + else if (tag.equals("pedestrian")) { + final float pedestrianScale = 0.75f; + + Entity entity = new Entity(id, posX, posY, velocity, angle, "pedestrian", new BehaviourComponent(BehaviourComponent.EnumType.PEDESTRIAN)); + entity.behaviour.initialAngle = angle; + entity.behaviour.maxSpeed = 1; + entity.scale = pedestrianScale; + return entity; + } + else { + return null; + } + } + + public static void main(String[] args) { /* Set the Nimbus look and feel */ // diff --git a/src/main/java/com/opennars/applications/crossing/Entity.java b/src/main/java/com/opennars/applications/crossing/Entity.java index fa3dba9..8486f70 100644 --- a/src/main/java/com/opennars/applications/crossing/Entity.java +++ b/src/main/java/com/opennars/applications/crossing/Entity.java @@ -30,12 +30,18 @@ public class Entity { public static int entityID = 0; + + public BehaviourComponent behaviour; + + + public double prevX = 0; + public double prevY = 0; + public double posX, posY; public double velocity; public double angle; public int id; public float scale = 1.0f; - public float maxSpeed = 2.0f; public static boolean pedestrianIgnoreTrafficLight = false; public static boolean carIgnoreTrafficLight = false; @@ -46,23 +52,34 @@ public class Entity { public double lastPosX = 0; public double lastPosY = 0; + public String tag; // tag used to identify the type of the entity + public Entity() { } - public Entity(int id, double posX, double posY, double velocity, double angle) { + public Entity(int id, double posX, double posY, double velocity, double angle, final String tag, final BehaviourComponent behaviour) { this.id = id; this.posX = posX; this.posY = posY; this.velocity = velocity; this.angle = angle; + this.tag = tag; + this.behaviour = behaviour; } - public void tick() { + public void tick(List streets, List trafficLights, List entities, TruthValue truth, long time) { // decay normalness // 0.96 is to slow //normalness *= 0.8; is to fast normalness *= 0.91; + + // store old position + prevX = posX; + prevY = posY; + + + behaviour.tick(this, streets, trafficLights, entities, truth, time); } boolean hasMoved() { @@ -75,7 +92,24 @@ public boolean isAnomaly() { return normalness < 0.3 && hasMoved(); } + public void draw(PApplet applet, List streets, List trafficLights, List entities, TruthValue truth, long time) { + float mul = Util.truthToValue(truth) * Util.timeToValue(time); + applet.fill(255, 0, 255, mul*255.0f); + + if (!isPredicted && isAnomaly()) { + applet.stroke(255,0,0); + } + else { + applet.stroke(127); + } + + drawInternal(applet, streets, trafficLights, entities, truth, time); + + applet.stroke(127); + } + + public void drawInternal(PApplet applet, List streets, List trafficLights, List entities, TruthValue truth, long time) { applet.pushMatrix(); //float posXDiscrete = (((int) this.posX)/Util.discretization * Util.discretization); //float posYDiscrete = (((int) this.posY)/Util.discretization * Util.discretization); @@ -88,61 +122,5 @@ public void draw(PApplet applet, List streets, List traffi applet.popMatrix(); applet.fill(0); applet.text(String.valueOf(id), (float)posX, (float)posY); - if(truth != null) { - return; - } - - boolean accelerate = true; - for (TrafficLight l : trafficLights) { - if (Util.distance(posX, posY, l.posX, l.posY) < l.radius) { - if (l.colour == l.RED) { - if (Util.rnd.nextFloat() > 0.3 && ((this instanceof Car && !carIgnoreTrafficLight) || (this instanceof Pedestrian && !pedestrianIgnoreTrafficLight))) { - velocity *= 0.5; - accelerate = false; - } - } - } - } - for (Entity e : entities) { - boolean collidable = !(this instanceof Pedestrian && e instanceof Pedestrian); - if (e != this && collidable) { - double nearEnough = 10; - for (double k = 0; k < nearEnough; k += 0.1) { - double pXNew = posX + k * Math.cos(angle); - double pYNew = posY + k * Math.sin(angle); - if (Util.distance(pXNew, pYNew, e.posX, e.posY) < nearEnough) { - velocity *= 0.8; - accelerate = false; - } - } - } - } - - if (accelerate && velocity < maxSpeed) { - velocity += 0.02; - } - - double aX = Math.cos(angle); - double aY = Math.sin(angle); - posX += aX * velocity; - posY += aY * velocity; - - double epsilon = 1; - if (posY < 0) { - posY = 1000 - epsilon; - //this.id = entityID++; - } - if (posY > 1000) { - posY = epsilon; - //this.id = entityID++; - } - if (posX < 0) { - posX = 1000 - epsilon; - //this.id = entityID++; - } - if (posX > 1000) { - posX = epsilon; - //this.id = entityID++; - } } } diff --git a/src/main/java/com/opennars/applications/crossing/InformNARS.java b/src/main/java/com/opennars/applications/crossing/InformNARS.java index a6aebf5..56d3741 100644 --- a/src/main/java/com/opennars/applications/crossing/InformNARS.java +++ b/src/main/java/com/opennars/applications/crossing/InformNARS.java @@ -39,11 +39,11 @@ public void informAboutEntity(Nar nar, Entity ent, int minX, int minY) { id = "0"; } String pos = Util.positionToTerm((int) ent.posX-minX, (int) ent.posY-minY); - if (ent instanceof Car) { + if (ent.tag.equals("car")) { inputs.add("<(*,car" + id + ","+ pos + ") --> at>. :|:"); input += inputs.get(inputs.size()-1); } - if (ent instanceof Pedestrian) { + if (ent.tag.equals("pedestrian")) { inputs.add("<(*,pedestrian" + id + "," + pos + ") --> at>. :|:"); input += inputs.get(inputs.size()-1); } diff --git a/src/main/java/com/opennars/applications/crossing/NarListener.java b/src/main/java/com/opennars/applications/crossing/NarListener.java index d0c211e..327cc7a 100644 --- a/src/main/java/com/opennars/applications/crossing/NarListener.java +++ b/src/main/java/com/opennars/applications/crossing/NarListener.java @@ -115,14 +115,14 @@ public Prediction predictionFromTask(Task t) { Entity pred; if(type.toString().startsWith(car.toString())) { String id = type.toString().substring(car.toString().length(), type.toString().length()); - pred = new Car(Integer.valueOf(id), posX, posY, 0, 0); + pred = Crossing.makeEntity("car", Integer.valueOf(id), posX, posY, 0, 0); pred.isPredicted = true; prediction = new Prediction(pred, t.sentence.truth, t.sentence.getOccurenceTime(), "car"); } else if(type.toString().startsWith(pedestrian.toString())) { String id = type.toString().substring(pedestrian.toString().length(), type.toString().length()); - pred = new Pedestrian(Integer.valueOf(id), posX, posY, 0, 0); + pred = Crossing.makeEntity("pedestrian", Integer.valueOf(id), posX, posY, 0, 0); pred.isPredicted = true; prediction = new Prediction(pred, t.sentence.truth, t.sentence.getOccurenceTime(), "pedestrian"); } diff --git a/src/main/java/com/opennars/applications/crossing/Pedestrian.java b/src/main/java/com/opennars/applications/crossing/Pedestrian.java deleted file mode 100644 index 96c74db..0000000 --- a/src/main/java/com/opennars/applications/crossing/Pedestrian.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * The MIT License - * - * Copyright 2018 The OpenNARS authors. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.opennars.applications.crossing; - -import java.util.List; -import org.opennars.entity.TruthValue; -import processing.core.PApplet; - -public class Pedestrian extends Entity { - - double initialAngle; - double prevX = 0; - double prevY = 0; - public final static float pedestrianScale = 0.75f; - public Pedestrian(int id, double posX, double posY, double velocity, double angle) { - super(id, posX, posY, velocity, angle); - initialAngle = angle; - scale = pedestrianScale; - maxSpeed = 1; - } - - public void draw(PApplet applet, List streets, List trafficLights, List entities, TruthValue truth, long time) { - prevX = posX; - prevY = posY; - float mul = Util.truthToValue(truth) * Util.timeToValue(time); - applet.fill(0, 255, 255, mul*255.0f); - super.draw(applet, streets, trafficLights, entities, truth, time); - angle+=(Util.rnd.nextFloat()*0.1-0.05); - //ok pedestrian, don't go on grass - boolean forPedestrians = false; - for(Street street : streets) { - if(!street.forCarsOnly && this.posX > street.startX && this.posX < street.endX && this.posY > street.startY && this.posY < street.endY) { - forPedestrians = true; - break; - } - } - if(!forPedestrians) { - this.angle = this.initialAngle; - this.posX = prevX; - this.posY = prevY; - } - } -}