Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions launay-iorgulescu-ex3/.settings/org.eclipse.jdt.core.prefs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.6
org.eclipse.jdt.core.compiler.source=1.8
11 changes: 9 additions & 2 deletions launay-iorgulescu-ex3/config/agents.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,20 @@
<!-- A list of agents and their behavior classes -->

<!-- #### DELIBERATIVE AGENTS ### -->
<agent name="deliberative-main">
<agent name="deliberative-agent">
<set class-path="bin/"/>
<set class-name="ch.epfl.iagents.DeliberativeAgent"/>
<set algorithm="ASTAR"/>
<set heuristic="MAXTRIP"/>
</agent>

<agent name="deliberative-main">
<set class-path="bin/"/>
<set class-name="template.DeliberativeMain"/>
<set algorithm="ASTAR"/>
<set heuristic="MAXTRIP"/>
</agent>

<agent name="deliberative-random">
<set class-path="bin/"/>
<set class-name="template.DeliberativeTemplate"/>
Expand Down
49 changes: 49 additions & 0 deletions launay-iorgulescu-ex3/src/ch/epfl/iagents/AStarPlanner.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package ch.epfl.iagents;

import java.util.*;
import java.util.stream.Collectors;

public class AStarPlanner extends Planner {
@Override
protected State getFinalState(State initialState) {
final int deliverableTaskCount = initialState.getDeliverableTaskCount();
// Set of "border" nodes. The use of TreeSet automatically sort them on insertion
TreeSet<State> q = new TreeSet<>(new StateComparator());
q.add(initialState); //start with origin

/*
* Set of node "seen". Because our heuristic is not consistent, we'll have to compare the cost of an already-seen node
* if we reach it again, hence the use of HashMap<State,f(State)>
*/
HashMap<State, Double> c = new HashMap<>();

int numLoop = 0; //feedback info
State s; //avoid re-instantiation and used as final node when the loop is over
do {
numLoop++;

s = q.pollFirst();
if (s.delivered == deliverableTaskCount) break;
//if not has not been reached yet, or we reached it with a better cost
if (!c.containsKey(s) || c.get(s) > s.f()) {
c.put(s, s.f());
//s.getSuccessors().collect(Collectors.toCollection(() -> q));
q.addAll(s.getSuccessors());
}
// System.out.println(q.size());
} while (!q.isEmpty());
System.out.println(c.size() + " estimated, " + q.size() + " border, " + numLoop + " loops, final cost: "
+ s.costToReach +" using ASTAR.");
return s;
}

// StateComparator required for TreeMap<State>
private class StateComparator implements Comparator<State> {
public int compare(State o1, State o2) {
int r = Double.compare(o1.f(), o2.f());
if (r != 0) return r;
// Hackish: if the states are equidistant, break the tie.
return o1.equals(o2) ? 0 : 1;
}
}
}
6 changes: 6 additions & 0 deletions launay-iorgulescu-ex3/src/ch/epfl/iagents/Algorithm.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package ch.epfl.iagents;

public enum Algorithm {
BFS,
ASTAR
}
29 changes: 29 additions & 0 deletions launay-iorgulescu-ex3/src/ch/epfl/iagents/BFSPlanner.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package ch.epfl.iagents;

import java.util.LinkedList;
import java.util.stream.Collectors;

public class BFSPlanner extends Planner {

@Override
protected State getFinalState(State initialState) {
final int deliverableTaskCount = initialState.getDeliverableTaskCount();
LinkedList<State> q = new LinkedList<>();
q.add(initialState);

State bestState = null;
Double bestResult = Double.POSITIVE_INFINITY;
while (!q.isEmpty()) {
State s = q.poll();
if (s.delivered == deliverableTaskCount && s.costToReach < bestResult) {
bestResult = s.costToReach;
bestState = s;
} else {
//s.getSuccessors().collect(Collectors.toCollection(() -> q));
q.addAll(s.getSuccessors());
}
}

return bestState;
}
}
94 changes: 94 additions & 0 deletions launay-iorgulescu-ex3/src/ch/epfl/iagents/DeliberativeAgent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package ch.epfl.iagents;

/* import table */

import logist.agent.Agent;
import logist.behavior.DeliberativeBehavior;
import logist.plan.Plan;
import logist.simulation.Vehicle;
import logist.task.Task;
import logist.task.TaskDistribution;
import logist.task.TaskSet;
import logist.topology.Topology;

import java.util.Arrays;

import static ch.epfl.iagents.State.HOLDING;
import static ch.epfl.iagents.State.NOT_PICKED;
import static ch.epfl.iagents.State.UNAVAILABLE;

/**
* An optimal planner for one vehicle.
*/
@SuppressWarnings("unused")
public class DeliberativeAgent implements DeliberativeBehavior {

/*
* Maximum (few seconds responses):
* BFS => 5 tasks
* ASTAR:NONE => 10 tasks
* ASTAR:MAXTRIP => 11 tasks
*/

/* Environment */
boolean environmentInitialized = false;
TaskSet carriedTasks;
Task[] tasks;

/* the properties of the agent */
int capacity;

Planner planner;
Heuristic heuristic;

@Override
public void setup(Topology topology, TaskDistribution td, Agent agent) {
// initialize the planner
this.capacity = agent.vehicles().get(0).capacity();
String algorithmName = agent.readProperty("algorithm", String.class, "ASTAR");
// Throws IllegalArgumentException if algorithm is unknown
planner = Planner.getPlanner(Algorithm.valueOf(algorithmName.toUpperCase()));

String heuristicName = agent.readProperty("heuristic", String.class, "MAXTRIP");
// Throws IllegalArgumentException if algorithm is unknown
heuristic = Heuristics.getHeuristic(HeuristicKind.valueOf(heuristicName.toUpperCase()));
}

private int[] getTaskStatuses(TaskSet tasks) {
int[] taskStatuses = new int[this.tasks.length];
Arrays.fill(taskStatuses, UNAVAILABLE);
tasks.forEach(t -> taskStatuses[t.id] = NOT_PICKED);
carriedTasks.forEach(t -> taskStatuses[t.id] = HOLDING);
return taskStatuses;
}

private void initialize(TaskSet tasks) {
// First call to plan().
// Setup carriedTasks to have the same universe as the tasks.
carriedTasks = TaskSet.noneOf(tasks);
// Setup tasks like taskSet universe.
// Since some tasks may be done, allocate space for the largest task id found.
this.tasks = new Task[tasks.stream().map(t -> t.id).mapToInt(Integer::intValue).max().orElse(-1) + 1];
tasks.forEach(t -> this.tasks[t.id] = t);
environmentInitialized = true;
}

@Override
public Plan plan(Vehicle vehicle, TaskSet tasks) {
if (!environmentInitialized) initialize(tasks);
if (tasks.isEmpty() && carriedTasks.isEmpty()) return Plan.EMPTY;
return planner.getPlan(new State(vehicle.getCurrentCity(), this.tasks, getTaskStatuses(tasks),
tasks.size() + carriedTasks.size(), null, 0.0,
capacity - carriedTasks.weightSum(), 0, heuristic));
}

@Override
public void planCancelled(TaskSet carriedTasks) {
/*
* Register the carriedTasks.
* They will be taken into account when plan() is called
*/
this.carriedTasks = carriedTasks;
}

}
5 changes: 5 additions & 0 deletions launay-iorgulescu-ex3/src/ch/epfl/iagents/Heuristic.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package ch.epfl.iagents;

public interface Heuristic {
double getEstimation(State currentState);
}
6 changes: 6 additions & 0 deletions launay-iorgulescu-ex3/src/ch/epfl/iagents/HeuristicKind.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package ch.epfl.iagents;

public enum HeuristicKind {
NONE,
MAXTRIP
}
51 changes: 51 additions & 0 deletions launay-iorgulescu-ex3/src/ch/epfl/iagents/Heuristics.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package ch.epfl.iagents;

import logist.task.Task;

import java.util.stream.Stream;

class Heuristics {

static Heuristic getHeuristic(HeuristicKind heuristic) throws IllegalArgumentException {
switch(heuristic) {
case MAXTRIP:
return new MaxTripHeuristic();
default:
throw new IllegalArgumentException("Undefined heuristic type: " + heuristic);
}
}

private static class MaxTripHeuristic implements Heuristic {
@Override
public double getEstimation(State currentState) {
/*
double pickupMax = Stream.of(currentState.tasks)
.filter(t -> currentState.taskStatuses[t.id] == State.NOT_PICKED)
.map(t -> currentState.inCity.distanceTo(t.pickupCity) + t.pickupCity.distanceTo(t.deliveryCity))
.mapToDouble(Double::doubleValue)
.max().orElse(0);

double deliverMax = Stream.of(currentState.tasks)
.filter(t -> currentState.taskStatuses[t.id] == State.HOLDING)
.map(t -> currentState.inCity.distanceTo(t.deliveryCity))
.mapToDouble(Double::doubleValue)
.max().orElse(0);

return pickupMax > deliverMax ? pickupMax : deliverMax;
*/
double result = 0;
for (Task t : currentState.tasks) {
if (t == null) continue;
double value = 0;
if (currentState.taskStatuses[t.id] == State.NOT_PICKED) {
value = currentState.inCity.distanceTo(t.pickupCity) + t.pickupCity.distanceTo(t.deliveryCity);
} else if (currentState.taskStatuses[t.id] == State.HOLDING) {
value = currentState.inCity.distanceTo(t.deliveryCity);
}
if (value > result) result = value;
}

return result;
}
}
}
62 changes: 62 additions & 0 deletions launay-iorgulescu-ex3/src/ch/epfl/iagents/Planner.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package ch.epfl.iagents;

import logist.plan.Action;
import logist.plan.Plan;
import logist.task.Task;
import logist.topology.Topology;

import java.util.ArrayList;
import java.util.Collections;
import java.util.stream.Collectors;

public abstract class Planner {
abstract protected State getFinalState(State initialState);

static Planner getPlanner(Algorithm algorithm)
throws IllegalArgumentException {
switch (algorithm) {
case BFS:
return new BFSPlanner();
case ASTAR:
return new AStarPlanner();
default:
throw new IllegalArgumentException("Undefined algorithm type: " + algorithm);
}
}

Plan getPlan(State initialState) {
assert(initialState != null);

long startTime = System.currentTimeMillis();
State state = getFinalState(initialState);
if (state != null) {
System.out.println(state.tasks.length + " tasks, result: " + state.costToReach + " in " +
(System.currentTimeMillis() - startTime) + " ms");
}

ArrayList<Action> plan = new ArrayList<>();
while (state.previousState != null) {
Task transitionTask = state.transitionTask;

// Check if the task was delivered or picked up.
if (state.taskStatuses[transitionTask.id] == State.DELIVERED)
plan.add(new Action.Delivery(transitionTask));
else plan.add(new Action.Pickup(transitionTask));

// Check if we moved to a different location.
// We construct the path from destination to source, since we need to reverse it at the end.
if (state.inCity != state.previousState.inCity) {
final Topology.City sourceCity = state.previousState.inCity;
plan.add(new Action.Move(state.inCity));
plan.addAll(state.inCity.pathTo(state.previousState.inCity)
.stream().filter(c -> c != sourceCity)
.map(Action.Move::new).collect(Collectors.toList()));
}

state = state.previousState;
}

Collections.reverse(plan);
return new Plan(state.inCity, plan);
}
}
Loading