Java tutorial
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package org.clipsmonitor.core; import java.awt.Color; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.file.Files; import java.nio.file.Paths; import java.util.ArrayList; import java.util.LinkedList; import java.util.ListIterator; import java.util.logging.Level; import java.util.logging.Logger; import org.clipsmonitor.clips.ClipsConsole; import org.clipsmonitor.monitor2015.RescueGenMap; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.json.simple.parser.JSONParser; import org.json.simple.parser.ParseException; /** * Questa classe astratta la parte di view (in un'architettura MVC) e * implementa Observer, per osservare il model (i.e. ClipsModel). Le * implementazioni di questa classe dovranno implementare i metodi per il * mantenimento dell'interfaccia grafica specifica per ogni progetto. * * @author Marco Corona, Alessandro Basile, Tobia Giani */ public abstract class MonitorGenMap { protected MonitorImages img; protected int NumCellX, NumCellY; //numero di celle sulle x e sulle y protected float CellWidth, CellHeight; //largezza e altezza celle protected float MapWidth, MapHeight; //largezza e altezza finestra protected String[][] scene; //matrice fondamentale rappresentante la scena protected String[][] move; // matrice fondamentale rappresentante i movimenti delle persone protected String[][] mapActive; //matrice per la visualizzazione sull'interfaccia protected String mode; // modalit di esecuzione del generatore protected int maxduration; // massima durata temporale di attivit del robot nell scena protected ClipsConsole console; // istanza della console clips protected String[] setKeyMap; // array dei possibili valori di scene corrispondenti alle // chiavi di accesso per l'hash map delle immagini protected String[] setKeyColor; // set di chiavi colori disponibili protected int NumPerson; // numero di persone attualmente inserite protected int MaxNumPerson; // numero massimo di persone rappresentabili protected String personName; //chiave che identifa le persona all'interno dell'hashmap protected int[] agentposition; // posizione attuale dell'agente all'inizio dello scenario protected int[] defaultagentposition; // posizione iniziale di default dell'agente protected LinkedList<Person> Persons; // Struttura che contiene i path delle varie persone protected String defaulagentcondition; // stringa di default utilizzata per inizializzare la scena // formata come background_keyagentdefault protected String direction; // direzione iniziale del robot; protected String log; /* Carica le immagini del progetto e genera l'array di stringhe che possono essere utilizzate per la scena (corrspondono alle chiavi dell'hash map di images) */ /** * Metodo per l'inizializzazione del modello della mappa in base al numero * di celle e alla dimensione totale dell'area di visualizzazione della * mappa. Inoltre il metodo setta la posizione iniziale dell'agente * * @param numCellX : numero di colonne * @param numCellY : numero di righr * @param mapWidth : larghezza in pixel della mappa * @param mapHeight : altezza in pixel della mappa */ public void initModelMap(int NewNumCellX, int NewNumCellY, float NewMapWidth, float NewMapHeight) { setSizeScreen(NewMapWidth, NewMapHeight); SetNumCell(NewNumCellX, NewNumCellY); //imposto la dimensione iniziale della scena scene = new String[NumCellX][NumCellY]; //genero la scena della dimensione specificata SetSizeCells(); setAgentDefaultPosition(); initScene(scene); move = clone(scene); CopyToActive(scene); } /** * Metodo per il ridimensionamento delle celle a seguito della modifica * della dimensione della griglia. * * @param NumCellX * @param NumCellY */ public void SetSizeCells() { //creo una scena con la nuova dimensione //salvo il numero di celle sulle x e sulle y //calcolo la larghezza delle celle CellWidth = (MapWidth - 20) / NumCellX; CellHeight = (MapHeight - 20) / NumCellY; if (CellWidth > CellHeight) { CellWidth = CellHeight; } else { CellHeight = CellWidth; } } public void setAgentDefaultPosition() { // aggiorno la posizione dell'agent in base alla nuova dimensione della griglia defaultagentposition[0] = NumCellX / 2; defaultagentposition[1] = NumCellY - 2; agentposition[0] = defaultagentposition[0]; agentposition[1] = defaultagentposition[1]; } /** * Metodo per il disegno della scena utilizzando i valori in stringhe della * mappa.le mappe sono di due tipologie per cui devono essere riempite in * maniera distinta. Per prima cosa viene eseguito il controllo su quale * matrice bisogna costruire. * * @param g : per effettuare il draw del pannello * @param MapWidth : larghezza in pixel del pannello della mappa * @param MapHeight : altezza in pixel del pannello della mappa */ public void drawScene(Graphics2D g, float MapWidth, float MapHeight) { BufferedImage[][] icons = makeIconMatrix(); //aggiorno le dimensioni della finestra MapWidth = MapWidth; MapHeight = MapHeight; //calcolo la larghezza delle celle CellWidth = (MapWidth - 20) / NumCellX; CellHeight = (MapHeight - 20) / NumCellY; //verifico chi delle due dimensioni minore e setto quella maggiore uguale a quella minore // per rendere le celle quadrate if (CellWidth > CellHeight) { CellWidth = CellHeight; } else { CellHeight = CellWidth; } //calcolo le coordinate di inizio della scena partendo a disegnare //dall'angolo in alto a sinistra della nostra scena float x0 = (MapWidth - CellWidth * NumCellX) / 2; float y0 = (MapHeight - CellHeight * NumCellY) / 2; //setto colore delle scritte g.setColor(Color.BLACK); //doppio ciclo sulla matrice for (int i = 0; i < NumCellX; i++) { for (int j = 0; j < NumCellY; j++) { //calcolo la posizione x,y dell'angolo in alto a sinistra della //cella corrente int x = (int) (x0 + i * CellWidth); int y = (int) (y0 + j * CellHeight); //se la cella non vuota, allora disegno l'immagine corrispondente if (!scene[i][j].equals("")) { //disegno l'immagine corretta usando la stringa che definisce la chiave per l'hashmap g.drawImage(icons[i][j], x, y, (int) (CellWidth - 1), (int) (CellHeight - 1), null); } //traccio il rettangolo della cella g.drawRect(x, y, (int) (CellWidth - 1), (int) (CellHeight - 1)); } } } /** * Metodo per clonare le mappe di stringhe, viene utilizzato per trasportare * la scena all'interno della mappa di move per ottenere una nuova copia su * cui lavorare * * @param map : mappa in input da clonare */ public String[][] clone(String[][] map) { String[][] clone = new String[map.length][map[0].length]; for (int i = 0; i < map.length; i++) { for (int j = 0; j < map[0].length; j++) { clone[i][j] = map[i][j]; } } return clone; } /** * Verifica se la posizione in pixel (x,y) ottenuta dal click sul mouse, * risulta valida e in caso affermativo resistuisce la cella corrispondente * alle coordinate * * @param x : coordinata x del pixel cliccato * @param y : coordinata y del pixel cliccato * @return : array indicante riga e colonna della cella corrispondente alle * coordinate in pixel */ public int[] getCellPosition(int x, int y) { int[] posCell = new int[2]; float x0 = (MapWidth - CellWidth * NumCellX) / 2; float y0 = (MapHeight - CellHeight * NumCellY) / 2; float cordx = x - x0; float cordy = y - y0; cordx = cordx / CellWidth; cordy = cordy / CellHeight; posCell[0] = (int) cordx; posCell[1] = (int) cordy; return posCell; } /**************** * SET E GET ****************/ /** * * @param NumCellX * @param NumCellY */ public void SetNumCell(int NewNumCellX, int NewNumCellY) { NumCellX = NewNumCellX; NumCellY = NewNumCellY; } /** * Imposta il valore di una singola cella nelle coordinate x,y * * @param x * @param y * @param value */ public void setCell(int x, int y, String value) { scene[x][y] = value; } public void setSizeScreen(float NewMapWidth, float NewMapHeight) { MapHeight = NewMapHeight; MapWidth = NewMapWidth; } public void setMaxDuration(int max_dur) { maxduration = max_dur; } public void setMode(String mode) { mode = mode; } public void setKeyMap(String[] keys) { setKeyMap = keys; } public void setLog(String log) { log = log; } public void setKeyColor(String[] keys) { setKeyColor = keys; } public String[][] getScene() { return scene; } public String getLog() { return log; } public String[][] getMove() { return move; } public int getNumx() { return NumCellX; } public int getNumy() { return NumCellY; } public int getMaxDuration() { return maxduration; } public String[] getSetKey() { return setKeyMap; } public String[] getSetKeyColor() { return setKeyColor; } public String getMode() { return mode; } /** * Copia una delle mappe in input sulla mappa attiva di modo che venga * visualizzata successivamente soltanto la mappa attiva * * @param map mappa di stringhe da copiare sulla active per la * visualizzazione */ public void CopyToActive(String[][] map) { mapActive = clone(map); } /** * Copia la nuova scena come base per le nuove move in modo da far * coincidere la mappa dello scenario con la mappa in cui si determinano le * moves */ public void CopySceneToMove() { move = clone(scene); } /* * Restituisce un mappa temporanea di move per la visualizzazione delle modifiche * sulla mappa. La move map restituita e soltanto temporanea * @param x : riga della cella da inserire la move * @param y : colonna della cella da inserire la move * @param color : colore temporaneo */ public String[][] getTmpMoveMap(int x, int y, String color) { String[][] newmap = new String[NumCellX][NumCellY]; for (int i = 0; i < newmap.length; i++) { for (int j = 0; j < newmap[0].length; j++) { String result = CheckBusyCellFromPerson(i, j, 0); if (!(result.equals("empty"))) { String[] resultSplit = result.split("_"); newmap[i][j] = resultSplit[0]; } else { newmap[i][j] = ""; } } } newmap[x][y] = color; return newmap; } /** * Questo metodo genera la mappa delle celle coinvolte in un certo movimento in base * ai parametri della persona o dello step a cui si interessati. * @param paramPerson : indice della persona nella linkedList * @param paramStep : numero di step a cui siamo interessati * @return newmap : stringa delle celle occupate da un movimento */ public String[][] getMoveCellMap(String paramPath, int paramStep) { String[][] newmap = new String[NumCellX][NumCellY]; for (int i = 0; i < newmap.length; i++) { for (int j = 0; j < newmap[0].length; j++) { newmap[i][j] = ""; } } if (paramPath.equals("empty")) { return newmap; } // caso di richiesta di uno specifico step if (paramPath.equals("none")) { ListIterator<Person> itPerson = Persons.listIterator(); while (itPerson.hasNext()) { Person p = itPerson.next(); ListIterator<Path> itPath = p.paths.listIterator(); Path succ = null; while (itPath.hasNext()) { succ = itPath.next(); if (paramStep >= succ.startStep && paramStep <= succ.lastStep) { int offset = paramStep - succ.startStep; try { StepMove s = succ.move.get(offset); String rgba = MonitorImages.getInstance().creatergbafromName(p.associatedColor, 0.25); newmap[s.x][s.y] = rgba + "+" + personName; break; } catch (IndexOutOfBoundsException ex) { String debug = "Error with ParamStep " + paramStep + " startStep " + succ.startStep + " laststep" + succ.lastStep; AppendLogMessage(debug, "error"); } } } } } // caso di richiesta di una specifico path agente else { int x = 0; int y = 0; Path result = getPathByName(paramPath); String[] splitResult = result.name.split("_"); ListIterator<StepMove> it = result.move.listIterator(); while (it.hasNext()) { StepMove s = it.next(); x = s.getX(); y = s.getY(); String rgba = MonitorImages.getInstance().creatergbafromName(splitResult[0], 0.25); if (newmap[x][y].equals("")) { newmap[x][y] = rgba; } else { newmap[x][y] += "+" + rgba; } } newmap[x][y] += "+" + personName; } return newmap; } /* * Questo metodo serve per generare la nuova mappa di stringhe move a partire * dalle celle coinvolte. Le celle coinvolte sono state generate prelevando * le informazioni dalla lista linkata delle persone */ public void ApplyUpdateOnMoveMap(String[][] cellMove) { move = loadMoveonMap(scene, cellMove); } /* * Metodo per il caricamento delle move da visualizzare sulla mappa.Il metodo * prende in input due mappe di stringhe, la prima rappresenta i valori della * scena, il background. Il secondo una mappa dove vengono messe le etichette dei * colori raffiguranti le celle occupate dai movimenti di un certo agente * @param map : la mappa delle stringhe di background * @param move : la mappa delle celle occupate da un certo movimento * * @return : la matrice di stringhe risultante */ public String[][] loadMoveonMap(String[][] map, String[][] move) { String[][] newmap = new String[map.length][map[0].length]; for (int i = 0; i < newmap.length; i++) { for (int j = 0; j < newmap[0].length; j++) { newmap[i][j] = map[i][j]; if (!move[i][j].equals("")) { newmap[i][j] += "+" + move[i][j]; } } } return newmap; } /** * Metodo per la creazione della matrice di icone da disegnare sulla mappa * del generatore .Il metodo si occupa di creare le icone con l'overlap. * @return la matrice di icone da disegnare sul pannello */ public BufferedImage[][] makeIconMatrix() { BufferedImage[][] iconMatrix = new BufferedImage[mapActive.length][mapActive[0].length]; for (int i = 0; i < NumCellX; i++) { for (int j = 0; j < NumCellY; j++) { BufferedImage tmpImage; // Split the map string in arguments String[] curCel = mapActive[i][j].split("\\+"); // Background image is the first argument iconMatrix[i][j] = img.getImage(curCel[0]); // All the others arguments are overlaps for (int k = 1; k < curCel.length; k++) { String curOverlap = curCel[k]; tmpImage = img.getImage(curOverlap); iconMatrix[i][j] = img.overlapImages(tmpImage, iconMatrix[i][j]); } } } return iconMatrix; } /* * Restituisce la distanza di Manhattam tra due celle */ public int ManhattamDistance(int xstart, int ystart, int xtarget, int ytarget) { return Math.abs(ytarget - ystart) + Math.abs(xtarget - xstart); } // Metodi per l'utilizzo del generatore della history dei movimenti /** * Classe utilizzata per memorizzare i movimenti che possono essere eseguiti * da agenti che si trovano a condividere l'ambiente con l'agente robotico. * Ogni istanza di StepMove descrive la posizione di un agente ad un certo * step */ protected class StepMove { protected int x; protected int y; protected int step; public StepMove(int r, int c, int s) { x = r; y = c; step = s; } public int getX() { return x; } public int getY() { return y; } public int getStep() { return step; } public void setX(int nr) { x = nr; } public void setY(int nc) { y = nc; } public void setStep(int ns) { step = ns; } } protected class Path { protected String name; protected int startStep; protected int lastStep; protected LinkedList<StepMove> move; public Path(String NewName, int NewStartStep) { name = NewName; startStep = NewStartStep; lastStep = startStep; move = new LinkedList<StepMove>(); } private Path(String NewName, int NewstartStep, int NewlastStep) { name = NewName; startStep = NewstartStep; lastStep = NewlastStep; move = new LinkedList<StepMove>(); } public LinkedList<StepMove> getMoves() { return move; } public String getName() { return name; } public int getLastStep() { return lastStep; } public int getStartStep() { return startStep; } public void AddMove(int r, int c) { int step = (move.size() == 0) ? startStep : lastStep + 1; move.add(new StepMove(r, c, step)); lastStep = step; } public void RemoveLast() { if (move.size() > 1) { move.removeLast(); lastStep = move.getLast().step; } } } /* Classe che descrive gli agenti che condividono l'ambiente assieme all'agente robotico Per il loro riconoscimento sono stati utilizzati dei colori i quali vengono utilizzati sulla mappa per indicare gli spostamenti di cella di un determinato agentes Ad ogni agenete viene definita una lista di tutti i movimenti fino ad adesso introdotti nella scena. */ protected class Person { protected String associatedColor; protected LinkedList<Path> paths; public Person(String color) { associatedColor = color; paths = new LinkedList<Path>(); } public String getColor() { return associatedColor; } public LinkedList<Path> getPaths() { return paths; } public void AddPath(int waitTime) { String name = associatedColor + "_" + paths.size(); int startStep; if (paths.size() > 0) { startStep = paths.getLast().lastStep + waitTime + 1; } else { startStep = waitTime; } paths.add(new Path(name, startStep)); } private void InsertPath(String name, int startStep, int lastStep) { paths.add(new Path(name, startStep, lastStep)); } public void RemoveLastPath() { if (paths.size() > 1) { paths.removeLast(); } } } /************************************************************** * SEARCH AND GET DATA FROM LINKED LISTS * *************************************************************/ /* * Restituisce l'oggetto path in base al nome che lo rappresenta.La ricerca si basa * sulla sintassi adottata, ovvero nomepath = color_numPath * @param name : nome del path da ricercare */ public Path getPathByName(String name) { if (name.equals("empty")) { return null; } String[] nameSplit = name.split("_"); String color = nameSplit[0]; Person p = findPersonByColor(color); int numPath = Integer.parseInt(nameSplit[1]); Path result = p.paths.get(numPath); return result; } public int getLastStepofPerson(String state) { int lastStep = 0; int pos = findIndexPosByColor(state); if (pos != -1) { Person p = Persons.get(pos); lastStep = p.paths.getLast().lastStep; } return lastStep; } /** * Restituisce il nome dell'ultimo percorso associato alla person * @param person name * @return ultimo path name associato alla person */ public String getLastPathOfPerson(String person) { String pathName = "empty"; int pos = findIndexPosByColor(person); if (pos != -1) { Person p = Persons.get(pos); pathName = p.paths.getLast().name; } return pathName; } /* * Metodo che resistuisce l'indice della persona associata al colore nella linkedList * @param color : colore associato * @return position : indice nella linkedList */ public int findIndexPosByColor(String color) { int position = 0; ListIterator<Person> it = Persons.listIterator(); Person p = null; while (it.hasNext()) { p = it.next(); if (p.associatedColor.equals(color)) { return position; } position++; } return -1; } /* * Questo metodo ricerca l'oggetto Person corrispondente al suo colore associato * @param color : stringa del colore associato alla persona * @return p : oggetto Person da restituire */ public Person findPersonByColor(String color) { ListIterator<Person> it = Persons.listIterator(); Person result = null; Person succ = null; while (it.hasNext()) { succ = it.next(); if (succ.associatedColor.equals(color)) { result = succ; return result; } } return result; } /* * Restituisce un array di tutti colori attualmente attivi nella mappa in modo * da controllare quali risultano essere le opzioni disponibili al generatore * delle move. */ public String[] getListColorActive() { ListIterator<Person> it = Persons.listIterator(); ArrayList<String> listColor = new ArrayList<String>(); String[] colors; while (it.hasNext()) { Person p = it.next(); listColor.add(p.associatedColor); } if (listColor.size() > 0) { colors = new String[listColor.size()]; colors = listColor.toArray(colors); } else { colors = new String[1]; colors[0] = ""; } return colors; } /* ritorna un array di stringhe che descrive le attuali persone attive nella scena Questo metodo verr poi richiesto per popolare la JList */ public String[] getListPerson() { String[] list = null; if (Persons.size() > 0) { list = new String[Persons.size() + 1]; ListIterator<Person> it = Persons.listIterator(); int i = 0; while (it.hasNext()) { list[i] = "person_" + it.next().getColor(); i++; } list[Persons.size()] = "all"; } return list; } public String getMoveString(String color, int step, String pathname, int x, int y) { return "C: " + color + "\t S: " + step + "\t Path: " + pathname + "\t (" + x + "," + y + ")"; } /* * Ritorna una stringa indicante il numero di step disponibili alla modifica in base * al parametro che li viene dato . * @param : param>-1 pu indicare l'indice della persona su cui costruire la lista * param==-1 indica che bisogna richiedere la lista globale di tutti gli step * in cui stato definito almeno un move */ public String[] getListStep(int param) { String[] list = null; int maxStep = 0; if (param == -1) { ListIterator<Person> it = Persons.listIterator(); while (it.hasNext()) { ListIterator<Path> itp = it.next().paths.listIterator(); int numStepPerson = 0; while (itp.hasNext()) { int numStepPath = itp.next().move.size(); numStepPerson += numStepPath; } if (numStepPerson > maxStep) { maxStep = numStepPerson; } } list = new String[maxStep]; } else { Person paramPerson = Persons.get(param); ListIterator<Path> itp = paramPerson.paths.listIterator(); int numStepPerson = 0; while (itp.hasNext()) { int numStepPath = itp.next().move.size(); numStepPerson += numStepPath; } list = new String[numStepPerson]; } list = new String[maxStep]; for (int i = 0; i < list.length; i++) { list[i] = "Step " + i; } return list; } /* * Ritorna la lista dei movimenti definiti fino a questo istante in base al parametro param * @paramPerson : paramPerson>-1 indica l'indice della persona da cui prelevare tutti le move definite * paramPerson==-1 indica la richiesta delle move per tutti le persone nella lista * * @paramStep : paramStep>-1 indica il numero dello step da cui prelevare tutti le move definite * paramStep==-1 indica la richieste delle move per tutti gli step */ public String[] getListMove(int paramPerson, int paramStep, String paramPath) { String[] list = null; ArrayList<String> moveslist = new ArrayList<String>(); // richiesta della lista completa degli step; if (paramPerson == -1 && paramStep == -1 && paramPath.equals("all")) { ListIterator<Person> it = Persons.listIterator(); while (it.hasNext()) { Person p = it.next(); ListIterator<Path> itpath = p.paths.listIterator(); while (itpath.hasNext()) { Path succ = itpath.next(); ListIterator<StepMove> moves = succ.move.listIterator(); while (moves.hasNext()) { StepMove s = moves.next(); String move = getMoveString(p.associatedColor, s.step, succ.getName(), s.x, s.y); moveslist.add(move); } } } } else { // richiesta della lista completa delle move in un determinato step if (paramStep > -1) { ListIterator<Person> itPerson = Persons.listIterator(); while (itPerson.hasNext()) { Person p = itPerson.next(); ListIterator<Path> itPath = p.paths.listIterator(); Path succ = null; while (itPath.hasNext()) { succ = itPath.next(); if (paramStep >= succ.startStep && paramStep <= succ.lastStep) { int offset = paramStep - succ.startStep; try { StepMove s = succ.move.get(offset); String move = getMoveString(p.associatedColor, s.step, succ.getName(), s.x, s.y); moveslist.add(move); break; } catch (IndexOutOfBoundsException ex) { String debug = "Error with ParamStep " + paramStep + " startStep " + succ.startStep + " laststep" + succ.lastStep; AppendLogMessage(debug, "error"); } } } } } // richiesta della lista delle move eseguita da una determinata persona else if (paramPerson > -1) { Person p = Persons.get(paramPerson); ListIterator<Path> itPath = p.paths.listIterator(); while (itPath.hasNext()) { Path succ = itPath.next(); ListIterator<StepMove> moves = succ.move.listIterator(); while (moves.hasNext()) { StepMove s = moves.next(); String move = getMoveString(p.associatedColor, s.step, succ.getName(), s.x, s.y); moveslist.add(move); } } } // richiesta della lista delle move eseguite all'interno di un determinato path else { Path succ = getPathByName(paramPath); String[] split = paramPath.split("_"); Person p = findPersonByColor(split[0]); ListIterator<StepMove> moves = succ.move.listIterator(); while (moves.hasNext()) { StepMove s = moves.next(); String move = getMoveString(p.associatedColor, s.step, succ.getName(), s.x, s.y); moveslist.add(move); } } } list = new String[moveslist.size()]; list = moveslist.toArray(list); return list; } /* * Restituisce l'elenco dei path gi dichiarati all'interno della linkedList delle persons. * Pu essere richiesto o l'elenco totale o l'elenco dei path specifici per una determinata person * Le stringhe sono costruite tutte con la struttura personName_pathName. * @paramPerson : paramPerson>-1 indica l'indice della persona da cui prelevare tutti i path definite * paramPerson==-1 indica la richiesta dei path per tutti le persone nella lista * @return : array di stringhe equivalente all'elenco */ public String[] getStringPaths(int paramPerson) { String[] paths = null; ArrayList<String> listPaths = new ArrayList<String>(); if (paramPerson == -1) { ListIterator<Person> it = Persons.listIterator(); while (it.hasNext()) { Person p = it.next(); ListIterator<Path> itPath = p.paths.listIterator(); while (itPath.hasNext()) { Path succ = itPath.next(); listPaths.add(succ.name); } } } else { Person p = Persons.get(paramPerson); ListIterator<Path> itPath = p.paths.listIterator(); while (itPath.hasNext()) { Path succ = itPath.next(); listPaths.add(succ.name); } } paths = new String[listPaths.size()]; paths = listPaths.toArray(paths); return paths; } /** * Restituisce un array di oggetti Path corrispondenti alla persona passata come parametro * @param paramPerson * @return un array di Path */ public Path[] getPaths(int paramPerson) { Path[] paths = null; ArrayList<Path> listPaths = new ArrayList<Path>(); if (paramPerson == -1) { ListIterator<Person> it = Persons.listIterator(); while (it.hasNext()) { Person p = it.next(); ListIterator<Path> itPath = p.paths.listIterator(); while (itPath.hasNext()) { Path succ = itPath.next(); listPaths.add(succ); } } } else { Person p = Persons.get(paramPerson); ListIterator<Path> itPath = p.paths.listIterator(); while (itPath.hasNext()) { Path succ = itPath.next(); listPaths.add(succ); } } paths = new Path[listPaths.size()]; paths = listPaths.toArray(paths); return paths; } /** * Restituisce un array di stringhe corrispondenti all'elenco dei path per la * person passato come parametro * @param paramPerson indice della person * @return un array di nomi di path */ public String[] getPersonPaths(int paramPerson) { String[] paths = null; ArrayList<String> listPaths = new ArrayList<String>(); if (paramPerson >= 0) { Person p = Persons.get(paramPerson); ListIterator<Path> itPath = p.paths.listIterator(); while (itPath.hasNext()) { Path succ = itPath.next(); listPaths.add(succ.name); } paths = new String[listPaths.size()]; paths = listPaths.toArray(paths); } return paths; } /** * Metodo per la verifica e la rimozione delle Move non piu valide a seguito * di un resize della mappa.Il metodo scorre la lista linkata e rimuove * tutte le move a partire dalla prima occorrenza non pu valida. Se ad un * certo step la move non valida non lo saranno pi tutte quelle * successivamente create */ public int[] RemoveStepAfterResize() { int[] pos = new int[2]; ListIterator<Person> it = Persons.listIterator(); while (it.hasNext()) { Person p = it.next(); ListIterator<Path> itPath = p.paths.listIterator(); while (itPath.hasNext()) { Path actual = itPath.next(); ListIterator<StepMove> its = actual.move.listIterator(); StepMove s = its.next(); boolean flag = false; while (its.hasNext()) { if (s.getX() < 0 || s.getX() > NumCellX || s.getY() < 0 || s.getY() > NumCellY || !PersonPositionIsValid(scene[s.getX()][s.getY()])) { flag = true; break; } s = its.next(); } if (flag) { int end = its.nextIndex(); for (int index = actual.move.size() - 1; index >= end - 1; index--) { actual.move.remove(index); } if (itPath.hasNext()) { ListIterator<Path> its2 = p.paths.listIterator(itPath.nextIndex()); while (its2.hasNext()) { Path succ = its2.next(); succ.move.addFirst(actual.getMoves().getLast()); succ.move.getFirst().setStep(succ.startStep); ListIterator<StepMove> its3 = succ.move.listIterator(1); int steps = succ.startStep; while (its3.hasNext()) { its3.next().setStep(steps++); } } } } } if (p.paths.getFirst().move.isEmpty()) { RemoveLastPath(p.associatedColor); Remove(p.associatedColor); } else { StepMove s = p.paths.getLast().getMoves().getLast(); pos[0] = s.x; pos[1] = s.y; } } return pos; } /******************************************************************** * UPDATE AND MODIFIDY MAPS * *******************************************************************/ /******************************************************************** * UPDATE AND MODIFIDY MAPS * *******************************************************************/ /** * Metodo per l'aggiornamento consistente delle celle. Il metodo ritorna * interi corrispondenti ad un particolare conclusione dell'esecuzione. * L'aggiornamento viene sostanzialmente separato in tre casi (richiesta di * una posizione dell'agente robotico , richiesta di una nuova posizione * iniziale di un agente umano, modifiche allo scenario). Il robot pu * essere modificato nella sua posizione solo se vengono rispettate le * condizoioni del progetto * * @param x ,y : possibile in riga e colonna della cella da modificare * @param state : nuovo stato da inserire * @return Success ==0 : aggiornamento consistente IllegalPosition ==1 : * posizione del cursore non valida KeyColorEmpty ==2 : le chiavi dei colori * non sono state correttamente generate KeyColorFull ==3 : le chiavi per * nuove person sono terminate IllegalRobotPosition ==4 : posizione del * robot non valida IllegalAgentPosition ==5 : posizione dell'agente umano * non valida PersonOverride ==6 : sovrascrittura di un agente umano */ public int UpdateCell(int x, int y, String state) { final int Success = 0; final int IllegalPosition = 1; final int IllegalRobotPosition = 2; if (x >= 0 && x < NumCellX && y >= 0 && y < NumCellY) { // se stato richiesto un aggiornamento della posizione di agent // controllo se attualmente non si trova nella stessa cella in cui vado a fare la modifica if (state.contains("agent")) { // se la nuova posizione agente diversa dalla precedente if (x != agentposition[0] || y != agentposition[1]) { if (RobotPositionIsValid(scene[x][y])) { // rimuovo l'agente dalla posizione corrente sostuiendolo con un empty // e successivamente inserisco il nuovo agente String[] split = scene[agentposition[0]][agentposition[1]].split("\\+"); String background = split[0]; scene[x][y] += "+" + state; scene[agentposition[0]][agentposition[1]] = background; SetRobotParams(state, x, y); } else { return IllegalRobotPosition; } } else { // stessa posizione attuale dell'agent position String[] split = scene[x][y].split("\\+"); String background = split[0]; scene[x][y] = background + "+" + state; } } // si richiedono modifiche alla scena diverse da tipologie di state agent else { // nel caso in cui dovessi sovrascrivere la posizione attuale dell'agente // allora semplicemente reimposto la posizione di default dell'agente if (x == agentposition[0] && y == agentposition[1]) { scene[x][y] = state; agentposition[0] = defaultagentposition[0]; agentposition[1] = defaultagentposition[1]; scene[agentposition[0]][agentposition[1]] = defaulagentcondition; } else { scene[x][y] = state; } } } else { // punto della mappa non disponibile per la modifica return IllegalPosition; } return Success; } /* * Restituisce il path della persona che attualmente che occupa attualemnte quella * cella oppure restituisce -1 in caso la cella sia libera. * @param x : numero di riga della cella * @param y : numero di colonna della cella * @param */ public String CheckBusyCellFromPerson(int x, int y, int Step) { ListIterator<Person> it = Persons.listIterator(); Person p = null; while (it.hasNext()) { p = it.next(); ListIterator<Path> itp = p.paths.listIterator(); Path succ = null; while (itp.hasNext()) { succ = itp.next(); if (succ.startStep <= Step && succ.lastStep >= Step) { break; } } int offset = Step - succ.startStep; if (offset < succ.move.size()) { if (succ.move.get(offset).getX() == x && succ.move.get(offset).getY() == y) { return succ.name; } } } return "empty"; } /** * Crea un nuovo path e lo aggiunge alla lista dei path della persona * indicata. L'aggiunta del path comporta sempre l'inserimento di una move * che determina lo stato iniziale per il nuovo path da eseguire. Un path * viene etichettato attraverso una label che risulta composta nel seguente * modo : (color_numPathPerson) * * @param color : colore associato alla person a cui si vuole aggiungere il * path * @param xstartStep : riga della cella iniziale del path * @param ystartStep : colonna della cella iniziale del path * @param waitStep : tempo di attesa dalla fine del path precedente */ public int AddNewPathToPerson(String color, int waitStep) { final int Success = 0; final int IllegalStartCell = 1; final int IllegalPerson = 2; final int PersonOverride = 3; Person p = findPersonByColor(color); if (p == null) { return IllegalPerson; } int start = p.paths.getLast().lastStep + waitStep + 1; int xStartStep = p.paths.getLast().move.getLast().x; int yStartStep = p.paths.getLast().move.getLast().y; String result = CheckBusyCellFromPerson(xStartStep, yStartStep, start); if (result.equals("empty")) { if (PersonPositionIsValid(scene[xStartStep][yStartStep])) { p.AddPath(waitStep); p.paths.getLast().AddMove(xStartStep, yStartStep); return Success; } else { return IllegalStartCell; } } else { return PersonOverride; } } /** * Questo metodo genera l'aggiornamento delle celle della mappa del * generatore in modalit move, determinando quali movimenti sono possibili * per un agente e in tal caso aggiorna la lista dei movimenti * * @param x : numero di riga * @param y : numero di colonna * @param p : persona a cui aggiungere la move */ public int UpdateMoveCell(int x, int y, String path) { final int Success = 0; final int IllegalPosition = 1; final int UnavaibleCellScenario = 2; final int PersonOverride = 3; final int LastMoveRemove = 4; String[] pathSplit = path.split("_"); String color = pathSplit[0]; Path p = getPathByName(path); if (x >= 0 && x < NumCellX && y >= 0 && y < NumCellY) { StepMove s = p.getMoves().getLast(); int step = p.getMoves().getLast().getStep() + 1; String result = CheckBusyCellFromPerson(x, y, step); if (!(result.equals("empty"))) { return PersonOverride; } // distanza di manhattam e check sulla attraversabilit della cella if (ManhattamDistance(s.getX(), s.getY(), x, y) == 1 && PersonPositionIsValid(scene[x][y])) { p.AddMove(x, y); return Success; } else if (ManhattamDistance(s.getX(), s.getY(), x, y) == 0) { p.RemoveLast(); return LastMoveRemove; } else { return UnavaibleCellScenario; } } else { return IllegalPosition; } } /** * Rimuove una persona in base al colore ad esso assegnata * * @param color : colore rappresentante la persona da rimuovere * @return boolean : verifica se la rimozione avvenuta correttamente */ public boolean Remove(String color) { ListIterator<Person> it = Persons.listIterator(); while (it.hasNext()) { Person p = it.next(); if (p.getColor().equals(color)) { Persons.remove(p); NumPerson--; return true; } } return false; } /** * Aggiunge una nuova persona allo scenario dichiarandone il colore * associato e la posizione di partenza * * @param x : riga della cella iniziale * @param y : colonna della cella iniziale * @param color : colore da associare */ public int AddNewPerson(int x, int y, String color, int waitTime) { final int Success = 0; final int IllegalPosition = 1; final int keyColorEmpty = 2; final int keyColorFull = 3; final int IllegalAgentPosition = 5; final int PersonOverride = 6; String result = ""; if (x >= 0 && x < NumCellX && y >= 0 && y < NumCellY) { // keycolor non ancora inizializzato if (setKeyColor.length == 0) { return keyColorEmpty; } // sovrascrittura dell'agente if (x == agentposition[0] && y == agentposition[1]) { return IllegalAgentPosition; } result = CheckBusyCellFromPerson(x, y, 0); if (!result.equals("empty")) { return PersonOverride; } if (findIndexPosByColor(color) != -1) { Person p = findPersonByColor(color); Path first = p.paths.get(0); first.move.getFirst().setX(x); first.move.getFirst().setY(y); return PersonOverride; } // ho ancora disponibilita di colori per indicare le person if (NumPerson < MaxNumPerson) { NumPerson++; Persons.add(new Person(color)); Persons.getLast().AddPath(waitTime); if (PersonPositionIsValid(move[x][y])) { Persons.getLast().paths.getLast().AddMove(x, y); String background = move[x][y]; move[x][y] = background + "+" + color + "+" + personName; } else { return IllegalAgentPosition; } } // ho terminato il numero di aggiunte che posso fare else { return keyColorFull; } return Success; } else { return IllegalPosition; } } /** * Rimuove l'ultimo path aggiunto ad una persona e restuisce un intero * equivalente al risultato ottenuto. * * @param color colore assegnato alla persona */ public int RemoveLastPath(String color) { final int Success = 0; final int PersonNotFound = 1; final int FirstPathRemove = 2; Person p = findPersonByColor(color); if (p != null) { if (p.paths.size() > 1) { p.RemoveLastPath(); return Success; } else { return FirstPathRemove; } } else { return PersonNotFound; } } /* ************************************************************** LOAD AND SAVE MAP FUNCTIONS ******************************************************************/ /** * Scrive su un file di testo la scena sviluppata tramite tool grafico * * @param directory : su cui salvare i file di RealMap e history con * rispettivi JSON * @return consoleOutput con il feedback delle operazioni di scrittura dei * file * @throws JSONException */ public String SaveFiles(File directory) throws JSONException { String consoleOutput = ""; consoleOutput += WriteSceneOnFile(directory); consoleOutput += WriteHistoryOnFile(directory); return consoleOutput; } /** * * @param directory * @return * @throws JSONException */ private String WriteSceneOnFile(File directory) throws JSONException { //richiamo l'export della scena il quale mi dar una stringa con tutto il codice clips corrispondente String sceneFile = exportScene(); String DirName = ""; String Parent = ""; String consoleOutput = ""; try { DirName = directory.getName(); Parent = directory.getParent(); // creazione nuovo file String infoMapPath = Parent + File.separator + DirName + File.separator + "RealMap.txt"; //scrivo il file della mappa Files.write(Paths.get(infoMapPath), sceneFile.getBytes()); consoleOutput += "File creato \n" + Paths.get(infoMapPath); String JSONMapPath = Parent + File.separator + DirName + File.separator + "InfoMap.json"; //scrivo il file json con la mappa scritta saveJSONMap(JSONMapPath); consoleOutput += "File creato \n" + Paths.get(JSONMapPath); } catch (IOException err) { return err.getMessage(); } return consoleOutput; } /** * Scrive su file di testo la history sviluppata mediante il tool move * all'interno del generatore * * @param directory * @return * @throws JSONException */ private String WriteHistoryOnFile(File directory) throws JSONException { String historyFile = exportHistory(); String DirName = ""; String Parent = ""; String consoleOutput = ""; try { DirName = directory.getName(); Parent = directory.getParent(); // creazione nuovo file if (historyFile.length() > 0) //scrivo il file della history solo se sono { //sono state aggiunte persone alla scena String HistoryPath = Parent + File.separator + DirName + File.separator + "history.txt"; Files.write(Paths.get(HistoryPath), historyFile.getBytes()); consoleOutput += "File creato \n" + Paths.get(HistoryPath); } //scrivo il file json con la mappa scritta String JSONMovePath = Parent + File.separator + DirName + File.separator + "InfoMove.json"; boolean MoveResult = saveJSONMoves(JSONMovePath); File json = new File(JSONMovePath); boolean RobotResult = this.SaveJsonRobotParams(json); if (MoveResult && RobotResult) { consoleOutput += "File creato \n" + Paths.get(JSONMovePath); } } catch (IOException err) { return err.getMessage(); } return consoleOutput; } public void LoadFiles(File directory) throws ParseException { String jsonMapPath = directory.getAbsolutePath() + File.separator + "InfoMap.json"; String jsonMovePath = directory.getAbsolutePath() + File.separator + "InfoMove.json"; File jsonMap = new File(jsonMapPath); File jsonMove = new File(jsonMovePath); LoadJsonMap(jsonMap); LoadMoves(jsonMove); LoadJsonRobotParams(jsonMove); } /** * Questo metdo utilizza dati strutturati JSON per il salvataggio della * scena. La struttura dati JSON cosi restituita viene successivamente * utilizzata per il caricamento della mappa cosi da poter essere modificata * in un secondo momento. * * @param nome : rappresenta il nome del file su cui eseguire il salvataggio * @return boolean : valuta se la scrittura sul JSON stata eseguita * correttamente */ public boolean saveJSONMap(String nome) throws JSONException { try { //Creo la radice con le informazioni sulla griglia JSONObject info = new JSONObject(); info.put("cell_x", getNumx()); info.put("cell_y", getNumy()); //ciclo sulla matrice degli stati per creare la struttura JSONArray ArrayCells = new JSONArray(); for (int i = 0; i < getNumx(); i++) { for (int j = 0; j < getNumy(); j++) { JSONObject cell = new JSONObject(); cell.put("x", i); cell.put("y", j); String background = scene[i][j]; if (scene[i][j].contains("agent")) { String[] split = scene[i][j].split("\\+"); background = split[0]; } cell.put("state", background); ArrayCells.put(cell); } } info.put("cells", ArrayCells); //salvo le informazioni in un file JSON della scenea Files.write(Paths.get(nome), info.toString(2).getBytes()); } catch (IOException ex) { AppendLogMessage(ex.getMessage(), "error"); Logger.getLogger(RescueGenMap.class.getName()).log(Level.SEVERE, null, ex); return false; } return true; } /* * Metodo per il caricamnento di una scena a partire da un file JSON precedentemente creato * Viene costruita la mappa e popolata dai valori contenuti nel JSON. * @param jsonFile : il file JSON da cui eseguire il load */ @SuppressWarnings("UnnecessaryUnboxing") private void LoadJsonMap(File jsonFile) throws ParseException { //creo una nuova istanza di scena try { //converto il file in un oggetto JSON FileReader jsonreader = new FileReader(jsonFile); char[] chars = new char[(int) jsonFile.length()]; jsonreader.read(chars); String jsonstring = new String(chars); jsonreader.close(); JSONObject json = new JSONObject(jsonstring); //leggo il numero di celle dalla radice del JSON int NumCellX = Integer.parseInt(json.get("cell_x").toString()); int NumCellY = Integer.parseInt(json.get("cell_y").toString()); SetNumCell(NumCellX, NumCellY); SetSizeCells(); //imposto la dimensione iniziale della scena scene = new String[NumCellX][NumCellY]; //initScene(scene); move = clone(scene); //estraggo il JSONArray dalla radice JSONArray arrayCelle = json.getJSONArray("cells"); for (int i = 0; i < arrayCelle.length(); i++) { //ciclo su ogni cella e setto il valore della cella letta nella scena JSONObject cell = arrayCelle.getJSONObject(i); int x = cell.getInt("x"); int y = cell.getInt("y"); String state = cell.getString("state"); setCell(x, y, state); } CopyToActive(scene); } catch (JSONException ex) { AppendLogMessage(ex.getMessage(), "error"); } catch (IOException ex) { AppendLogMessage(ex.getMessage(), "error"); } catch (NumberFormatException ex) { AppendLogMessage(ex.getMessage(), "error"); } } /* * Genera un file JSON corrispondente alla lista linkata salvata per le move fino ad ora definite * per la history. Il JSON viene utilizzato per semplificare il caricamente della history e dello * scenario. *@param name : nome del file su cui scrivere il JSON */ private boolean saveJSONMoves(String name) throws JSONException { try { JSONObject Info = new JSONObject(); JSONArray PersonsArray = new JSONArray(); for (int i = 0; i < Persons.size(); i++) { Person p = Persons.get(i); JSONObject person = new JSONObject(); person.put("color", p.associatedColor); JSONArray paths = new JSONArray(); for (int j = 0; j < p.paths.size(); j++) { Path pts = p.paths.get(j); JSONObject path = new JSONObject(); path.put("name", pts.name); path.put("startStep", pts.startStep); path.put("lastStep", pts.lastStep); JSONArray moves = new JSONArray(); for (int k = 0; k < pts.move.size(); k++) { JSONObject move = new JSONObject(); StepMove s = pts.move.get(k); move.put("x", s.x); move.put("y", s.y); move.put("step", s.step); moves.put(move); } path.put("moves", moves); paths.put(path); } person.put("paths", paths); PersonsArray.put(person); } Info.put("personList", PersonsArray); Info.put("time", maxduration); Files.write(Paths.get(name), Info.toString(2).getBytes()); return true; } catch (IOException err) { AppendLogMessage(err.getMessage(), "error"); return false; } } /* * Esegue il load della linkedList delle person partendo da un file JSON precedentemente creato. * Il file viene convertito nuovamente in un oggetto JSON e parsificato secondo la struttura * definita dal metodo LoadMoves sopra * @param jsonFile : file jsonFile da cui eseguire il load */ public void LoadMoves(File jsonFile) throws ParseException { try { //converto il file in un oggetto JSON FileReader jsonreader = new FileReader(jsonFile); char[] chars = new char[(int) jsonFile.length()]; jsonreader.read(chars); String jsonstring = new String(chars); jsonreader.close(); JSONObject json = new JSONObject(jsonstring); Persons = new LinkedList<Person>(); //estraggo il JSONArray dalla radice JSONArray arrayPersons = json.getJSONArray("personList"); for (int i = 0; i < arrayPersons.length(); i++) { JSONObject person = arrayPersons.getJSONObject(i); String color = person.getString("color"); Person p = new Person(color); JSONArray arrayPaths = person.getJSONArray("paths"); for (int j = 0; j < arrayPaths.length(); j++) { JSONObject path = arrayPaths.getJSONObject(j); String pathName = path.getString("name"); int startStep = path.getInt("startStep"); int lastStep = path.getInt("lastStep"); p.paths.add(new Path(pathName, startStep, lastStep)); JSONArray arrayMoves = path.getJSONArray("moves"); for (int k = 0; k < arrayMoves.length(); k++) { JSONObject move = arrayMoves.getJSONObject(k); int x = move.getInt("x"); int y = move.getInt("y"); int step = move.getInt("step"); p.paths.getLast().move.add(new StepMove(x, y, step)); } } Persons.add(p); } maxduration = json.getInt("time"); } catch (JSONException ex) { AppendLogMessage(ex.getMessage(), "error"); } catch (IOException ex) { AppendLogMessage(ex.getMessage(), "error"); } catch (NumberFormatException ex) { AppendLogMessage(ex.getMessage(), "error"); } } public String getNewPathName(String pathName) { String[] split = pathName.split("_"); String newpath = ""; for (int i = 0; i < split.length; i++) { newpath += split[i]; } return newpath; } protected int[] GenMapToMap(int i, int j) { return new int[] { scene[0].length - j, i + 1 }; } protected int[] GenMapToMap(int[] pos) { return new int[] { scene[0].length - pos[1], pos[0] + 1 }; } protected int[] MapToGenMap(int i, int j, int maxR) { return new int[] { j - 1, maxR - i }; } protected int[] MapToGenMap(int[] pos, int maxR) { return new int[] { pos[1] - 1, maxR - pos[0] }; } protected void AppendLogMessage(String newLog, String type) { String logMessage = ""; if (type.equals("error")) { logMessage = CreateErrorMessage(newLog); } else { logMessage = CreateLogMessage(newLog); } log = log + logMessage + "\n"; } protected String CreateLogMessage(String message) { String newString = "[INFO] : "; newString += message; return newString; } protected String CreateErrorMessage(String message) { String newString = "[ERROR] : "; newString += message; return newString; } /* * metodo che converte lo stream di file in un oggetto JSON */ private static JSONObject convertStreamToJson(InputStream is) throws ParseException { try { return (JSONObject) (new JSONParser()).parse(new BufferedReader(new InputStreamReader(is))); } catch (IOException ex) { return null; } } // PARTE ASTRATTA /* Metodo per l'inizializzazione della mappa. Dichiarato astratto poich ogni progetto determina caratteristiche custom da dare all'envirorment */ public abstract void initScene(String[][] scene); /* Metodo per la scrittura su file della history della scena */ public abstract String exportHistory(); /* Metodo per la scrittura su file della mappa iniziale */ public abstract String exportScene(); /* * Esegue l'init del generatore, viene eseguito a livello di classe derivata * specifica per il progetto */ public abstract void init(); /* * Verifica le condizioni imposte alla posizione del robot */ public abstract boolean RobotPositionIsValid(String mapPos); /* * Verifica le condizioni imposte alla posizione del robot */ public abstract boolean PersonPositionIsValid(String mapPos); /* * Setta le impostazioni del robot nel modello */ public abstract void SetRobotParams(String state, int x, int y); public abstract void LoadJsonRobotParams(File json); public abstract boolean SaveJsonRobotParams(File json); public abstract void createJsonScene(File map); public abstract void createJsonHistory(File history, File jsonMap); }