[TASK] Almost finish simulation basis.

This commit is contained in:
Jan Philipp Timme 2016-08-10 17:12:32 +02:00
parent 32f2d21514
commit 56d2ef9fbe
6 changed files with 295 additions and 60 deletions

View File

@ -11,6 +11,7 @@ import eu.larkc.csparql.core.engine.CsparqlEngine;
import eu.larkc.csparql.core.engine.CsparqlEngineImpl;
import eu.larkc.csparql.core.engine.CsparqlQueryResultProxy;
import lu.jpt.csparqltest.rentacar.RentACarSimulation;
import lu.jpt.csparqltest.util.RandomHelper;
public class Main {
@ -45,7 +46,7 @@ public class Main {
simulationThread.start();
// Now build a query to run - interchangeable
String query = Main.getSPO();
String query = Main.getAllCarAttributesQuery();
// Create a result proxy by registering the query at the engine
CsparqlQueryResultProxy resultProxy = null;
@ -85,12 +86,31 @@ public class Main {
+ "PREFIX car: <http://myexample.org/car#> "
+ "SELECT ?s ?p ?o "
+ "FROM STREAM <http://myexample.org/car> [RANGE 5s STEP 1s] "
+ "FROM STREAM <http://myexample.org/driver> [RANGE 5s STEP 1s] "
+ "FROM STREAM <http://myexample.org/driver> [RANGE 15s STEP 1s] "
+ "WHERE { "
+ " ?s ?p ?o . "
+ "}";
}
private static String getAllCarAttributesQuery() {
return "REGISTER QUERY BasicCarInfo AS "
+ "PREFIX f: <http://larkc.eu/csparql/sparql/jena/ext#> "
+ "PREFIX xsd: <http://www.w3.org/2001/XMLSchema#> "
+ "PREFIX car: <http://myexample.org/car#> "
+ "SELECT ?car ?locked ?on ?speed ?rpm ?handbrake ?tirePressure "
+ "FROM STREAM <http://myexample.org/car> [RANGE 5s STEP 1s] "
+ "FROM STREAM <http://myexample.org/driver> [RANGE 15s STEP 1s] "
+ "WHERE { "
+ " ?e car:subject ?car . "
+ " ?e car:locked ?locked . "
+ " ?e car:motorOn ?on . "
+ " ?e car:speed ?speed . "
+ " ?e car:motorRPM ?rpm . "
+ " ?e car:handbrakeEngaged ?handbrake . "
+ " ?e car:tirePressure ?pressure . "
+ "}";
}
private static String getBasicCarInfoQuery() {
return "REGISTER QUERY BasicCarInfo AS "
+ "PREFIX f: <http://larkc.eu/csparql/sparql/jena/ext#> "

View File

@ -8,30 +8,8 @@ import lu.jpt.csparqltest.util.RandomHelper;
public class Car {
// State-change related enums
private enum CarAction {NONE, UNLOCKING, STARTING, ACCELERATING, BRAKING, DRIFTING, CRASHING, STOPPING, LOCKING};
private enum CarState {LOCKED, OFF, IDLE, DRIVE};
/* STATE-Übergänge
Überall: NONE
LOCKED
* UNLOCKING
STANDING
* LOCKING
* STARTING
IDLING
* ACCELERATING
* STOPPING
DRIVING
* ACCELERATING
* BRAKING
* DRIFTING
* CRASHING
* STOPPING
*/
private enum CarAction {NONE, UNLOCKING, STARTING, ACCELERATING, BRAKING, CRASHING, STOPPING, LOCKING, HALTING};
public enum CarState {LOCKED, OFF, IDLE, DRIVE, WRECKED};
// Fix knowledge about the available car types:
private static final String[] CAR_TYPENAME = {"A", "B", "C"};
@ -51,19 +29,23 @@ public class Car {
private final int CAR_TYPE;
private CarState currentState;
private boolean isCurrentActionHard;
private CarAction currentAction;
private int currentActionTicksLeft;
private boolean isLocked;
private boolean handbrakeEngaged;
private boolean motorOn;
private int motorRpm;
private int speed;
private double tirePressure;
// Sitzplätze? Reservierungen für X Personen?
public Car(int id, String baseIri) {
public Car(int id) {
this.id = id;
this.IRI = baseIri;
this.IRI = RentACarSimulation.CAR_IRI;
this.quads = new ArrayList<RdfQuadruple>();
this.CAR_TYPE = RandomHelper.nextInt(2);
this.initializeCarType(this.CAR_TYPE);
@ -79,15 +61,124 @@ public class Car {
// State data
this.currentState = CarState.LOCKED;
this.currentAction = CarAction.NONE;
this.isCurrentActionHard = false;
this.currentActionTicksLeft = 0;
}
public void keyClose() {
this.currentAction = CarAction.LOCKING;
this.currentActionTicksLeft = 1;
}
public void keyOpen() {
this.currentAction = CarAction.UNLOCKING;
this.currentActionTicksLeft = 1;
}
public void start() {
this.currentAction = CarAction.STARTING;
this.currentActionTicksLeft = 1;
}
public void accelerate(boolean isHard) {
this.currentAction = CarAction.ACCELERATING;
this.isCurrentActionHard = isHard;
this.currentActionTicksLeft = 3;
}
public void brake(boolean isHard) {
this.currentAction = CarAction.BRAKING;
this.isCurrentActionHard = isHard;
this.currentActionTicksLeft = 3;
}
public void engageHandbrake() {
this.handbrakeEngaged = true;
}
public void releaseHandbrake() {
this.handbrakeEngaged = false;
}
public boolean isHandbrakeEngaged() {
return this.handbrakeEngaged;
}
public void crash() {
this.currentAction = CarAction.CRASHING;
this.currentActionTicksLeft = 1;
// Create airbag-event
this.fireAirbagEvent();
}
public void comeToHalt() {
this.currentAction = CarAction.HALTING;
this.currentActionTicksLeft = 3;
}
public void stop() {
this.currentAction = CarAction.STOPPING;
this.currentActionTicksLeft = 1;
}
/**
* Update internal stuff according to state
*/
public void tick() {
int rpmBonus = 0;
System.err.println("Old state: " + this.currentState + ", Action: " + this.currentAction);
switch(this.currentAction) {
case STARTING:
this.motorOn = true;
this.motorRpm = Car.MIN_RPM[this.CAR_TYPE];
this.currentState = CarState.IDLE;
break;
case STOPPING:
this.motorOn = false;
this.motorRpm = 0;
this.currentState = CarState.OFF;
break;
case LOCKING:
this.isLocked = true;
this.currentState = CarState.LOCKED;
break;
case UNLOCKING:
this.isLocked = false;
this.currentState = CarState.OFF;
break;
case ACCELERATING:
if(this.currentState == CarState.IDLE) this.currentState = CarState.DRIVE;
if(this.isCurrentActionHard && this.currentActionTicksLeft == 3) rpmBonus = 200;
this.motorRpm += RandomHelper.getRandomNumberWithin(100, 350 + rpmBonus);
this.speed += RandomHelper.getRandomNumberWithin(5, 20);
if(this.isCurrentActionHard) this.speed += 30;
break;
case BRAKING:
if(this.isCurrentActionHard && this.currentActionTicksLeft == 3) rpmBonus = 200;
this.motorRpm -= RandomHelper.getRandomNumberWithin(100, 350 + rpmBonus);
this.speed -= RandomHelper.getRandomNumberWithin(5, 20);
if(this.isCurrentActionHard) this.speed -= 30;
if(this.speed < 0) this.speed = 0;
if(this.motorRpm < 0) this.motorRpm = Car.MIN_RPM[this.CAR_TYPE];
break;
case HALTING:
this.motorRpm -= RandomHelper.getRandomNumberWithin(100, 350 + rpmBonus);
this.speed -= RandomHelper.getRandomNumberWithin(5, 20);
if(this.isCurrentActionHard) this.speed -= 30;
if(this.speed < 0) this.speed = 0;
if(this.motorRpm < 0) this.motorRpm = Car.MIN_RPM[this.CAR_TYPE];
// Halt on last tick of halting action
if(this.currentActionTicksLeft == 1) {
this.currentState = CarState.IDLE;
this.speed = 0;
this.motorRpm = Car.MIN_RPM[this.CAR_TYPE];
}
// Decrease RPM and stuff to idle niveau
break;
case CRASHING:
this.currentState = CarState.WRECKED;
this.motorOn = false;
this.motorRpm = 0;
break;
case NONE:
break;
@ -99,8 +190,31 @@ public class Car {
if(this.currentActionTicksLeft == 0) {
this.currentAction = CarAction.NONE;
}
this.generateContinousReportQuads();
System.err.println("New state: " + this.currentState);
}
private void fireAirbagEvent() {
long time = System.currentTimeMillis();
String baseIri = RentACarSimulation.BASE_IRI;
String eventIri = baseIri + "/event#" + time;
this.quads.add(new RdfQuadruple(eventIri, "http://myexample.org/car#subject", this.getIri(), time));
this.quads.add(new RdfQuadruple(eventIri, "http://myexample.org/car#airbagTriggered", ""+true+"^^http://www.w3.org/2001/XMLSchema#boolean", time));
}
private void generateContinousReportQuads() {
long time = System.currentTimeMillis();
String baseIri = RentACarSimulation.BASE_IRI;
String eventIri = baseIri + "/event#" + time;
this.quads.add(new RdfQuadruple(eventIri, "http://myexample.org/car#subject", this.getIri(), time));
this.quads.add(new RdfQuadruple(eventIri, "http://myexample.org/car#motorOn", ""+this.motorOn+"^^http://www.w3.org/2001/XMLSchema#boolean", time));
this.quads.add(new RdfQuadruple(eventIri, "http://myexample.org/car#motorRPM", ""+this.motorRpm+"^^http://www.w3.org/2001/XMLSchema#integer", time));
this.quads.add(new RdfQuadruple(eventIri, "http://myexample.org/car#speed", ""+this.speed+"^^http://www.w3.org/2001/XMLSchema#integer", time));
this.quads.add(new RdfQuadruple(eventIri, "http://myexample.org/car#handbrakeEngaged", ""+this.handbrakeEngaged+"^^http://www.w3.org/2001/XMLSchema#boolean", time));
this.quads.add(new RdfQuadruple(eventIri, "http://myexample.org/car#tirePressure", ""+this.tirePressure+"^^http://www.w3.org/2001/XMLSchema#double", time));
this.quads.add(new RdfQuadruple(eventIri, "http://myexample.org/car#locked", ""+this.isLocked+"^^http://www.w3.org/2001/XMLSchema#boolean", time));
}
public CarState getState() {
return this.currentState;
}
@ -122,7 +236,7 @@ public class Car {
}
public String getIri() {
return this.IRI + "#" + this.id;
return RentACarSimulation.CAR_IRI + "#" + this.id;
}
public List<RdfQuadruple> getQuadruples() {
@ -137,5 +251,6 @@ public class Car {
sb.append("]");
return sb.toString();
}
}

View File

@ -11,12 +11,12 @@ public class CarPool {
private Random rand;
public CarPool(int numberOfCars, String carIri) {
public CarPool(int numberOfCars) {
this.rand = new Random();
this.cars = new ArrayList<Car>();
this.availableCars = new ArrayList<Car>();
for(int i = 0; i < numberOfCars; i++) {
Car newCar = new Car(i, carIri);
Car newCar = new Car(i);
this.cars.add(newCar);
this.availableCars.add(newCar);
}
@ -27,8 +27,14 @@ public class CarPool {
* @return Car the random car
*/
public Car takeRandomCar() {
Car randomCar = this.availableCars.get(this.rand.nextInt(this.availableCars.size()));
this.availableCars.remove(randomCar);
Car randomCar = null;
if(this.availableCars.isEmpty()) {
throw new RuntimeException("Tried to take a car, but no cars were there!");
} else {
int randomIndex = this.rand.nextInt(this.availableCars.size());
randomCar = this.availableCars.get(randomIndex);
this.availableCars.remove(randomCar);
}
return randomCar;
}

View File

@ -8,24 +8,33 @@ import lu.jpt.csparqltest.util.RandomHelper;
public class Driver {
// Traits with corresponding behaviour for certain situations
public enum Trait {CAREFUL, REGULAR, FAST, INSANE};
private static final double[] chanceToEngageHandbrakeOnLock = {1.00, 0.85, 0.60, 0.05};
private static final double[] chanceToReleaseHandbrakeOnUnlock = {1.00, 0.95, 0.90, 0.84};
private static final double[] chanceToCrashCar = {0.05, 0.10, 0.20, 0.40};
private static final double[] chanceToDriftCar = {0.00, 0.05, 0.15, 0.70};
private static final double[] chanceToChangeSpeedHard = {0.00, 0.10, 0.30, 0.80};
private static final double[] chanceToStallEngine = {0.20, 0.01, 0.00, 0.00};
private int id;
private final String IRI;
private CarPool carPool;
private int carUseCycles;
private Car car;
private Trait trait;
private List<RdfQuadruple> quads;
private enum Trait {CAREFUL, REGULAR, FAST, INSANE};
public Driver(int id, CarPool carPool, String baseIri) {
public Driver(int id, CarPool carPool) {
this.id = id;
this.carPool = carPool;
this.IRI = baseIri;
this.car = null;
this.quads = new ArrayList<RdfQuadruple>();
// Pick a random behaviour and stick to it.
this.trait = (Trait) RandomHelper.getRandomElementFromArray(Trait.values());
}
public int getID() {
@ -33,7 +42,7 @@ public class Driver {
}
public String getIri() {
return this.IRI + "#" + this.id;
return RentACarSimulation.DRIVER_IRI + "#" + this.id;
}
/**
@ -43,35 +52,113 @@ public class Driver {
public void tick() {
if(car == null) {
// Nothing to do, maybe randomly take a free car
if(RandomHelper.isLuckyByChance(0.4)) {
this.assignCar(this.carPool.takeRandomCar(), RandomHelper.getRandomNumberWithin(10,50));
if(RandomHelper.isLuckyByChance(0.75)) {
this.takeRandomCarFor(RandomHelper.getRandomNumberWithin(20,50));
}
} else {
// Do random things with the car
if(this.car.needsInput()) {
this.useCar(this.car);
}
// Decrement use cycles
this.carUseCycles--;
if(this.carUseCycles == 0) {
this.returnCar();
}
}
// Do random things with the car
if(this.car.needsInput()) {
this.useCar(this.car);
}
// Decrement use cycles
this.carUseCycles--;
if(this.carUseCycles == 0) {
this.returnCar();
}
}
/**
* Interact with the car by starting a CarAction on the car.
* @param car The given car
*/
private void useCar(Car car) {
// Whatever, hit the gas, slam the breaks, drift around, drive casually
Car.CarState carState = car.getState();
if(carState == Car.CarState.WRECKED) {
// Sad fade :-(
return;
}
switch(carState) {
case LOCKED:
if(this.carUseCycles > 5) {
car.keyOpen();
}
break;
case OFF:
if(this.carUseCycles > 4) {
car.start();
if(RandomHelper.isLuckyByChance(Driver.chanceToReleaseHandbrakeOnUnlock[this.trait.ordinal()])) {
car.releaseHandbrake();
}
} else {
if(RandomHelper.isLuckyByChance(Driver.chanceToEngageHandbrakeOnLock[this.trait.ordinal()])) {
car.engageHandbrake();
}
car.keyClose();
}
break;
case IDLE:
if(this.carUseCycles > 3) {
car.accelerate(RandomHelper.isLuckyByChance(Driver.chanceToChangeSpeedHard[this.trait.ordinal()]));
} else {
car.stop();
}
break;
case DRIVE:
// Always release handbrake after drifting or forgetting!
if(car.isHandbrakeEngaged()) {
car.releaseHandbrake();
}
if(this.carUseCycles > 3) {
if(RandomHelper.isLuckyByChance(Driver.chanceToCrashCar[this.trait.ordinal()])) {
car.crash();
} else if(RandomHelper.isLuckyByChance(Driver.chanceToStallEngine[this.trait.ordinal()])) {
car.stop();
} else {
int nextAction = RandomHelper.getRandomNumberWithin(0, 1);
switch(nextAction) {
case 0:
boolean accHard = RandomHelper.isLuckyByChance(Driver.chanceToChangeSpeedHard[this.trait.ordinal()]);
car.accelerate(accHard);
if(accHard) {
if(RandomHelper.isLuckyByChance(Driver.chanceToDriftCar[this.trait.ordinal()])) {
car.engageHandbrake();
}
}
break;
case 1:
car.brake(RandomHelper.isLuckyByChance(Driver.chanceToChangeSpeedHard[this.trait.ordinal()]));
break;
}
}
} else {
car.comeToHalt();
}
break;
default:
System.err.println("Driver cannot handle car state: " + carState);
break;
}
}
private void assignCar(Car car, int useCycles) {
this.car = car;
private void takeRandomCarFor(int useCycles) {
this.car = this.carPool.takeRandomCar();
this.carUseCycles = useCycles;
this.quads.add(new RdfQuadruple(this.getIri(), this.IRI+"#took", this.car.getIri(), System.currentTimeMillis()));
this.quads.add(new RdfQuadruple(this.getIri(), this.IRI+"#usagePeriod", useCycles+"^^http://www.w3.org/2001/XMLSchema#integer", System.currentTimeMillis()));
long time = System.currentTimeMillis();
String baseIri = RentACarSimulation.BASE_IRI;
String eventIri = baseIri + "/event#" + time;
this.quads.add(new RdfQuadruple(eventIri, baseIri+"#user", this.getIri(), time));
this.quads.add(new RdfQuadruple(eventIri, baseIri+"#took", this.car.getIri(), System.currentTimeMillis()));
this.quads.add(new RdfQuadruple(eventIri, baseIri+"#usagePeriod", ""+useCycles+"^^http://www.w3.org/2001/XMLSchema#integer", System.currentTimeMillis()));
}
private void returnCar() {
this.quads.add(new RdfQuadruple(this.getIri(), this.IRI+"#returned", this.car.getIri(), System.currentTimeMillis()));
long time = System.currentTimeMillis();
String baseIri = RentACarSimulation.BASE_IRI;
String eventIri = baseIri + "/event#" + time;
this.quads.add(new RdfQuadruple(eventIri, baseIri+"#user", this.getIri(), time));
this.quads.add(new RdfQuadruple(eventIri, baseIri+"#returned", this.car.getIri(), time));
this.carPool.returnCar(this.car);
this.car = null;
}
@ -84,6 +171,7 @@ public class Driver {
public String toString() {
StringBuilder sb = new StringBuilder("[#");
sb.append(this.id);
sb.append(" trait="+this.trait);
sb.append("]");
return sb.toString();
}

View File

@ -22,13 +22,15 @@ public class RentACarSimulation implements Runnable {
public RentACarSimulation() {
int numberOfCars = 6;
int numberOfCars = 1;
int numberOfCustomers = 1;
// Create a car pool and drivers
this.carPool = new CarPool(numberOfCars, CAR_IRI);
this.carPool = new CarPool(numberOfCars);
this.drivers = new ArrayList<Driver>();
for(int i = 0; i < numberOfCustomers; i++) {
this.drivers.add(new Driver(i, this.carPool, DRIVER_IRI));
Driver driver = new Driver(i, this.carPool);
System.out.println(driver);
this.drivers.add(driver);
}
// Create streams
this.carStream = new RdfStream(CAR_IRI);

View File

@ -21,4 +21,8 @@ public class RandomHelper {
return RandomHelper.myRandom.nextDouble() < chance;
}
public static Object getRandomElementFromArray(Object[] arr) {
return arr[RandomHelper.getRandomNumberWithin(0, (arr.length - 1))];
}
}