//
// Copyright (C) 2006 United States Government as represented by the
// Administrator of the National Aeronautics and Space Administration
// (NASA). All Rights Reserved.
//
// This software is distributed under the NASA Open Source Agreement
// (NOSA), version 1.3. The NOSA has been approved by the Open Source
// Initiative. See the file NOSA-1.3-JPF at the top of the distribution
// directory tree for the complete NOSA document.
//
// THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY
// KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT
// LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO
// SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
// A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT
// THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT
// DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE.
//
/**
* This is the famous Bridge-crossing puzzle. The aim is to see what the minimum
* amount of time is for 4 people to cross with flash-light (torch): 10.5.2.1.
* The answer is 17 for the given configuration.
*
* Purpose of this example is to show how to use the 'Verify' API in test
* applications (usually drivers)
*
* One can find this solution with JPF in BFS search mode - DFS will not
* work since this is an infinite-state program (time keeps increasing).
*
* If one uses the ignoreIf(cond) call the branches that will lead to
* solutions worst than the current will be cut-off and this will allow
* DFS also to complete - and BFS to terminate faster.
*
* When setting the native flag in main one can also save information
* from one run to the next using JPF's native peer methods -
* see JPF_Crossing.java for the code of getTotal() and setTotal(int).
*/
import gov.nasa.jpf.vm.Verify;
enum Side { LEFT, RIGHT }
class Bridge {
Side torchSide;
Person[] onBridge = new Person[2];
int numOnBridge = 0;
public Bridge (Side torchSide){
this.torchSide = torchSide;
}
void moveTorch(){
if (torchSide == Side.LEFT){
torchSide = Side.RIGHT;
} else {
torchSide = Side.LEFT;
}
}
public int cross() {
int time = 0;
moveTorch();
if (numOnBridge == 1) {
onBridge[0].side = torchSide;
time = onBridge[0].timeToCross;
//System.out.println("Person " + onBridge[0] +
// " moved to " + Torch.side +
// " in time " + time);
} else {
onBridge[0].side = torchSide;
onBridge[1].side = torchSide;
if (onBridge[0].timeToCross > onBridge[1].timeToCross) {
time = onBridge[0].timeToCross;
} else {
time = onBridge[1].timeToCross;
}
//System.out.println("Person " + onBridge[0] +
// " and Person " + onBridge[1] +
// " moved to " + Torch.side +
// " in time " + time);
}
return time;
}
public void clearBridge() {
numOnBridge = 0;
onBridge[0] = null;
onBridge[1] = null;
}
boolean isFull(){
return numOnBridge == 2;
}
boolean arePersonsOnBridge(){
return numOnBridge > 0;
}
boolean isPersonOnBridge (Person p){
return (p == onBridge[0] || p == onBridge[1]);
}
void putPersonOnBridge (Person p){
onBridge[numOnBridge++] = p;
}
}
class Person {
String name;
Side side;
int timeToCross;
public Person(String name, int timeToCross) {
this.timeToCross = timeToCross;
this.name = name;
}
public void tryToMove (Bridge bridge) {
if (side == bridge.torchSide) {
if (!Verify.getBoolean()) {
if (! (bridge.isFull() || bridge.isPersonOnBridge(this))){
bridge.putPersonOnBridge(this);
}
}
}
}
public String toString(){
return name;
}
}
public class Crossing {
Bridge bridge;
Person[] persons;
int elapsedTime;
Side initialSide;
public Crossing (Person[] persons, Side initialSide){
this.persons = persons;
for (Person p : persons){
p.side = initialSide;
}
this.bridge = new Bridge( initialSide);
this.initialSide = initialSide;
}
boolean haveAllPersonsCrossed (){
for (Person p : persons){
if (p.side == initialSide){
return false;
}
}
return true;
}
void solve (){
printPersons();
System.out.println();
printCrossingState();
//Verify.setCounter(0, Integer.MAX_VALUE);
while (!haveAllPersonsCrossed()){
for (Person p : persons){
p.tryToMove(bridge);
}
if (bridge.arePersonsOnBridge()) {
elapsedTime += bridge.cross();
//Verify.ignoreIf(elapsedTime >= Verify.getCounter(0));
//Verify.ignoreIf(elapsedTime > 17); //with this DFS will also find error
bridge.clearBridge();
}
printCrossingState();
}
System.out.println("total time = " + elapsedTime);
//Verify.setCounter(0, elapsedTime); // new minimum
Verify.printPathOutput("done");
Verify.storeTraceAndTerminateIf(elapsedTime == 17, null, null);
//assert (elapsedTime > 17);
}
String personsOnSide (Side side){
int n=0;
StringBuilder sb = new StringBuilder();
for (Person p : persons){
if (p.side == side){
if (n++ > 0){
sb.append(',');
}
sb.append( p);
}
}
return sb.toString();
}
String torchSymbol (Side side){
if (bridge.torchSide == side){
return "*";
} else {
return " ";
}
}
void printPersons(){
for (Person p : persons){
System.out.printf("%10s needs %2d min to cross\n", p.name, p.timeToCross);
}
}
void printCrossingState (){
System.out.printf("%20s %s====%s %-20s : elapsed time=%d\n",
personsOnSide(Side.LEFT), torchSymbol(Side.LEFT),
torchSymbol(Side.RIGHT), personsOnSide(Side.RIGHT), elapsedTime);
}
public static void main(String[] args) {
Person[] persons = {
new Person("Bill", 1),
new Person("Xoe", 2),
new Person("Sue", 5),
new Person("Joe", 10)
};
Crossing crossing = new Crossing( persons, Side.LEFT);
crossing.solve();
}
}