Package cz.cuni.mff.abacs.burglar.visual.multithreading

Source Code of cz.cuni.mff.abacs.burglar.visual.multithreading.PlanningThread$PseudoRandomCombinationGenerator

/**
*
*/
package cz.cuni.mff.abacs.burglar.visual.multithreading;

import cz.cuni.mff.abacs.burglar.logics.DataMap;
import cz.cuni.mff.abacs.burglar.logics.GameMap;
import cz.cuni.mff.abacs.burglar.logics.objects.agents.Agent;
import cz.cuni.mff.abacs.burglar.logics.objects.agents.Burglar;
import cz.cuni.mff.abacs.burglar.logics.objects.agents.Guard;
import cz.cuni.mff.abacs.burglar.logics.objects.positions.Door;
import cz.cuni.mff.abacs.burglar.logics.planning.PlannerHandler;
import cz.cuni.mff.abacs.burglar.logics.planning.PlannerHandlerFactory;
import cz.cuni.mff.abacs.burglar.logics.planning.instructions.Instruction;
import cz.cuni.mff.abacs.burglar.visual.VisualBurglar;
import cz.cuni.mff.abacs.tools.CombinationGenerator;
import java.util.*;


/**
* Thread to execute the planning and forward the results to the planning listener.
*
* @author abacs
*
*/
public class PlanningThread extends Thread {
 
 
  // constants:
 
  /** Planning type. */
  public enum Type {
    PLANNING,
    PLANNING_BURGLAR,
    PLANNING_AGENTS,
    SELECTING_TRAP_ROOMS,
  }
 
 
  // -------------------------------------------------------------------------
  // properties:
 
 
  /** Address to return the results. */
  private final PlanningListener _listener;
 
  /** Object to execute the planning. */
  private final PlannerHandler _planner =
    PlannerHandlerFactory.createPlannerHandler();
 
  /** Map to execute the planning on. */
  private final GameMap _map;
 
  /** List of agents to plan for. */
  private List<Agent> _agents = null;
 
  /** Planning type. */
  private final Type _type;
 
 
  // -------------------------------------------------------------------------
  // constructors:
 
 
  /**
   * Simple constructor.
   *
   * @param map map subject to plan on.
   * @param type planning type
   * @param listener address for the results
   */
  public PlanningThread(
      GameMap map,
      Type type,
      PlanningListener listener
  ) {
    super();
    this._map = map;
    this._type = type;
    this._listener = listener;
  }
 
 
  /**
   * Constructor to plan for selected agents.
   *
   * @param map map subject to plan on.
   * @param listener address for the results
   * @param agentsToPlan agents that need planning
   */
  public PlanningThread(
      GameMap map,
      PlanningListener listener,
      List<Agent> agentsToPlan
  ) {
    super();
    this._map = map;
    this._type = Type.PLANNING_AGENTS;
    this._listener = listener;
    this._agents = agentsToPlan;
  }
 
 
  // -------------------------------------------------------------------------
 
 
  /* (non-Javadoc)
   * @see java.lang.Runnable#run()
   */
  @Override
  public void run() {
    long startTime = System.currentTimeMillis();
   
    switch(this._type){
    case PLANNING:
      // the order of the following two instructions is important!
      // planBurglar does removes the planning flag
      this.planGuards();
      this.planBurglar();
      break;
    case PLANNING_BURGLAR:
      this.planBurglar();
      break;
    case SELECTING_TRAP_ROOMS:
      this.selectTrapRooms();
      break;
    case PLANNING_AGENTS:
      for(Agent agent : this._agents){
       
        // only active agents should plan:
        if(agent.isInState(Agent.State.WELL) == false)
          continue;
       
        this.planAgent(agent);
      }
      this._listener.planningFinished(this);
      break;
    }
   
    // print out the planning duration:
    long endTime = System.currentTimeMillis();
    long duration = endTime - startTime;
   
    System.out.println(
        "- Planning time: " + duration + " ms. (" + this._type + ')'
    );
   
  }
 
 
  // -------------------------------------------------------------------------
 
 
 
 
  // -------------------------------------------------------------------------
 
 
  private void planBurglar() {
    List<Integer> emptyList = new LinkedList<Integer>();
    List<Integer> avoidedTrapRooms = new ArrayList<Integer>();
   
    // instructions that the burglar would normally follow:
    List<Instruction> freeInstructions =
      this._planner.solveBurglarProblem(
          this._map,
          emptyList,
          emptyList
      );
   
    // for each trap in the map control whether the avoiding plan matches
    // the burglar's normal plan
/*    for(Integer trapRoomId : this._map.getTrapRoomIds()){
     
      List<Integer> trapRooms = new LinkedList<Integer>();
      trapRooms.add(trapRoomId);
     
      List<Instruction> avoidInstructions =
        this._planner.solveBurglarProblem(
            this._map,
            emptyList,
            trapRooms
        );
     
      if(this._map.instructionListsMatch(freeInstructions, avoidInstructions)){
        System.out.println("- trap room " + trapRoomId + " avoided");
        avoidedTrapRooms.add(trapRoomId);
      }
     
    }  */
   
    this._listener.planningFinished(freeInstructions, avoidedTrapRooms, this);
  }
 
 
  /**
   *
   */
  private void planGuards() {
    List<Instruction> result = new LinkedList<Instruction>();
    List<Integer> emptyList = new LinkedList<Integer>();
   
    for(Guard guard : this._map.getGuards()){
     
      // instructions that the burglar would normally follow:
      List<Instruction> instructions =
        this._planner.solveGuardProblem(
            guard,
            this._map,
            guard.getRoomsToVisit(),
            emptyList
        );
      result.addAll(instructions);
    }
   
    this._listener.planningFinished(result, this);
  }
 
 
  /**
   *
   * @param agent
   */
  private void planAgent(Agent agent) {
    List<Integer> emptyList = new LinkedList<Integer>();
    List<Instruction> result;
   
    switch(agent.getType()){
    case BURGLAR:
     
      result = this._planner.solveBurglarProblem(
          this._map,
          emptyList,
          emptyList
      );
     
      this._listener.planningFinished(result, this);
      break;
     
    case GUARD:
     
      Guard guard = (Guard)agent;
      result = this._planner.solveGuardProblem(
          guard,
          this._map,
          emptyList,
          emptyList
      );
     
      this._listener.planningFinished(result, this);
      break;
     
    default:
     
    }
  }
 
 
  private void selectTrapRooms() {
    if(VisualBurglar.FLAG_INVALIDATE_PREVIOUS_PATH){
      selectTrapRoomsWithPathInvalidating();
    }else{
      selectTrapRoomsWithoutPathInvalidating();
    }
  }
 
 
  private void selectTrapRoomsWithoutPathInvalidating() {
    //
    // plan a burglar path to get the rooms it uses:
    //
   
    List<Integer> emptyList = new LinkedList<Integer>();
   
    // instructions that the burglar would normally follow:
    List<Instruction> originalPlan =
      this._planner.solveBurglarProblem(this._map, emptyList, emptyList);
    List<Integer> originalRooms =
      getPlannedRoomIds(originalPlan, (DataMap)this._map);
   
    List<Integer> filteredRooms = this.removeUnavoidableRooms(originalRooms);
   
    // TODO
    debugPrint(
        "original path rooms (" + filteredRooms.size() + "): ",
        filteredRooms, ""
    );
   
    //
    // insert trap rooms:
    //
   
    int trapRoomCount = this._map.getRequiredTrapRoomCount();
    if(trapRoomCount > filteredRooms.size())
      trapRoomCount = filteredRooms.size();
   
    List<Integer> trapRooms = new ArrayList<Integer>(trapRoomCount);
   
    // try the maximal number of trap rooms the user wants, if not possible
    // try less:
    trapRoomCount++;
    while(trapRooms.isEmpty() && --trapRoomCount > 0){
     
      PseudoRandomCombinationGenerator gener =
          new PseudoRandomCombinationGenerator(
              filteredRooms.size(),
              trapRoomCount
          );
     
      // try all combinations of trap rooms for the current trap room count
      while(gener.hasMore()){
        // generate a trap room configuration:
        int[] combination = gener.getNext();
       
        selectSublist(filteredRooms, combination, trapRooms);
       
        // test the trap room configuration:
        List<Instruction> restrictedPlan =
          this._planner.solveBurglarProblem(this._map, emptyList, trapRooms);
       
        // TODO
        debugPrint(
            "trap rooms (" + trapRoomCount + ") tried: ",
            trapRooms,
            "does it work: " + !restrictedPlan.isEmpty()
        );
       
        // exit if plan is valid:
        if(restrictedPlan.isEmpty())
          trapRooms.clear();
        else
          break;
      }
    }
   
    //
    // insert traps to trap rooms
    //
   
    // TODO
    debugPrint("trap rooms that worked out ("+trapRoomCount+"): ", trapRooms, "");
   
    this._listener.selectingTrapRoomsFinished(trapRooms, this);
  }
 
 
  /**
   *
   */
  private void selectTrapRoomsWithPathInvalidating() {
    //
    // plan a burglar path to get the rooms it uses:
    //
   
    List<Integer> emptyList = new LinkedList<Integer>();
   
    List<Integer> avoidableRooms = new ArrayList<Integer>(this._map.getRoomIds().size());
    List<Integer> unavoidableRooms = new ArrayList<Integer>(this._map.getRoomIds().size());
   
    // get the unavoidable rooms:
    List<Integer> roomsToAvoid = new ArrayList<Integer>(1);
    for(Integer roomToTest : this._map.getRoomIds()){
     
      roomsToAvoid.clear();
      roomsToAvoid.add(roomToTest);
     
      // instructions that the burglar would follow without roomToTest:
      List<Instruction> plan =
        this._planner.solveBurglarProblem(this._map, emptyList, roomsToAvoid);
     
      // if there is a way, it's avoidable
      if(plan.isEmpty() == false){
        avoidableRooms.add(roomToTest);
        // debug print:
        System.out.println("room avoidable:" + roomToTest);
      }else{
        unavoidableRooms.add(roomToTest);
        // debug print:
        System.out.println("room unavoidable:" + roomToTest);
      }
    }
   
    if(avoidableRooms.isEmpty())
      return;
   
    int maxTraps = this._map.getRequiredTrapRoomCount();
    if(maxTraps > avoidableRooms.size())
      maxTraps = avoidableRooms.size();
   
    // plan the traprooms:
    roomsToAvoid.clear();
    List<Integer> trapRooms = new ArrayList<Integer>(maxTraps);
    List<Integer> finalPathRooms = new LinkedList<Integer>();
    int roomIndex = 0;
   
    for(int trapCounter = 0; trapCounter < maxTraps; trapCounter++){
     
      // instructions that the burglar would follow:
      List<Instruction> plan =
        this._planner.solveBurglarProblem(this._map, finalPathRooms, roomsToAvoid);
      List<Integer> pathRooms = getPlannedRoomIds(plan, (DataMap)this._map);
     
      // TODO test plan success
     
      // select the first available avoidable room in the path:
      // (index has to be larger than the last index)
      for(; roomIndex < pathRooms.size(); roomIndex++){
       
        int currentRoom = pathRooms.get(roomIndex);
        roomsToAvoid.add(currentRoom);
        List<Instruction> avoidingPlan =
          this._planner.solveBurglarProblem(this._map, finalPathRooms, roomsToAvoid);
        roomsToAvoid.remove(roomsToAvoid.size() - 1);
         
        if(avoidingPlan.isEmpty()){
          finalPathRooms.add(pathRooms.get(roomIndex));
        }else{
          break;
        }
      }
     
      if(roomIndex >= pathRooms.size())
        break;
     
      // add room to traprooms:
      trapRooms.add(pathRooms.get(roomIndex));
     
     
     
      // set the rooms to avoid as avoidable rooms
      // on current path starting with the last traproom:
      roomsToAvoid.clear();
      for(int avoidIndex = roomIndex; avoidIndex < pathRooms.size(); avoidIndex++){
        roomsToAvoid.add(pathRooms.get(roomIndex));
      }
      roomsToAvoid.addAll(trapRooms);
     
    }
   
    // TODO
    debugPrint("secondary: trap rooms that worked out ("+trapRooms.size()+"): ", trapRooms, "");
   
    this._listener.selectingTrapRoomsFinished(trapRooms, this);
  }
 
 
  protected List<Integer> removeUnavoidableRooms(
    List<Integer> originalRooms 
  ) {
    List<Integer> filteredRooms = new LinkedList<Integer>(originalRooms);
   
    // remove current room:
    Burglar burglar = this._map.getBurglar();
    if(filteredRooms.contains(burglar.getRoomId()))
      filteredRooms.remove(filteredRooms.indexOf(burglar.getRoomId()));
   
    // remove aim room:
    if(filteredRooms.contains(burglar.getAimId()))
      filteredRooms.remove(filteredRooms.indexOf(burglar.getAimId()));
   
   
    // remove the rooms that can't be walked around:
    List<Integer> trapRooms = new ArrayList<Integer>(1);
    List<Integer> roomsToControl = new ArrayList<Integer>(filteredRooms);
    List<Integer> emptyList = new LinkedList<Integer>();
   
    for(Integer roomId : roomsToControl){
      // test the trap room configuration:
     
      trapRooms.add(roomId);
      List<Instruction> restrictedPlan =
        this._planner.solveBurglarProblem(this._map, emptyList, trapRooms);
     
      // TODO
      System.out.println(
          "is room required? id: " +
          roomId + " " + restrictedPlan.isEmpty()
      );
     
      // exit if plan is not valid, current room is needed:
      if(restrictedPlan.isEmpty())
        filteredRooms.remove(filteredRooms.indexOf(roomId));
     
      trapRooms.clear();
    }
   
    return filteredRooms;
  }
 
 
  /**
   * Returns the rooms that the agent plans to visit.
   *
   * @param instructions
   * @param referenceMap
   * @return
   */
  protected static List<Integer> getPlannedRoomIds(
      List<Instruction> instructions,
      DataMap referenceMap
  ) {
    Set<Integer> rooms = new HashSet<Integer>();
   
    for(Instruction instr : instructions){
      if(instr._code == Instruction.code.ENTER_DOOR){
        Door subject = (Door)referenceMap.getPosition(instr._subjectId);
        int[] doorRooms = subject.getRoomIds();
        rooms.add(doorRooms[0]);
        rooms.add(doorRooms[1]);
      }
    }
   
    List<Integer> result = new ArrayList<Integer>(rooms.size());
    for(Integer roomId : rooms)
      result.add(roomId);
   
    return result;
  }
 
 
  /**
   * Selects subelements and places them to destination list.
   *
   * @param source source list
   * @param indexes indexes to copy
   * @param destination destination list
   */
  private static void selectSublist(
      List<Integer> source,
      int[] indexes,
      List<Integer> destination
  ) {
    destination.clear();
    for(int i = 0; i < indexes.length; i++)
      destination.add(source.get(indexes[i]));
  }
 
 
  // TODO debug
  /**
   *
   * @param leadingText
   * @param ids
   * @param endingText
   */
  private static void debugPrint(
      String leadingText,
      List<Integer> ids,
      String endingText
  ) {
    System.out.print(leadingText);
    for(Integer id : ids)System.out.print(id + ", ");
    System.out.println(endingText);
  }
 
 
  // -------------------------------------------------------------------------
 
 
  private class PseudoRandomCombinationGenerator {
    // constants:
   
   
    /**  */
    private final int BUFFER_SIZE = 500;
   
   
    // ---------------------------------------------------------------------
    // properties:
   
   
    /**  */
    private final CombinationGenerator _gener;
   
   
    /**  */
    private final List<int[]> _buffer = new ArrayList<int[]>(BUFFER_SIZE);
   
   
    // ---------------------------------------------------------------------
    // constructors:
   
   
    /**
     *
     * @param n
     * @param r
     */
    public PseudoRandomCombinationGenerator(int n, int r) {
      this._gener = new CombinationGenerator(n, r);
      this.fillBuffer();
    }
   
   
    // ---------------------------------------------------------------------
   
   
    /**
     *
     * @return
     */
    public boolean hasMore() {
      return this._buffer.isEmpty() == false || this._gener.hasMore();
    }
   
   
    /**
     *
     * @return
     */
    public int[] getNext() {
      if(this._buffer.isEmpty()){
        if(this._gener.hasMore()){
          this.fillBuffer();
          return this.getNext();
        }
        return null;
      }
      return this._buffer.remove(0);
    }
   
   
    // ---------------------------------------------------------------------
   
   
    /**
     *
     */
    private void fillBuffer() {
      while(this._buffer.size() < BUFFER_SIZE && this._gener.hasMore())
        this._buffer.add(this._gener.getNext().clone());
      Collections.shuffle(this._buffer);
    }
   
   
  }
 
 
}
TOP

Related Classes of cz.cuni.mff.abacs.burglar.visual.multithreading.PlanningThread$PseudoRandomCombinationGenerator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.