[JAVA] "Macchina a stati"

di il
9 risposte

[JAVA] "Macchina a stati"

Salve a tutti, mi trovo un pò in difficoltà con un progetto Java universitario che devo consegnare a breve,
Devo rappresentare un'ipotetica macchina in grado di cambiare stato in base ai caratteri di una stringa in input con i quali opera confronti:
le regole di cambio di stato sono definite da delle terzine (o triplette) formate da stato corrente, lettera, stato successivo, a tal proposito le ho create
come oggetti con i relativi 3 parametri (int,char,int), le ho inserite in un array di oggetti e ho creato appositi metodi per farmi restituire i valori contenuti
nell'array stesso iterandolo, ora devo scrivere un algoritmo che, a partire dallo stato iniziale = 1, fa transitare la macchina dallo stato corrente a quello successivo confrontando i parametri "lettera" degli oggetti triple nell'array con quelli della stringa in input (che ho inserito in un array "carattere per carattere"
col metodo toCharArray) senza dimenticare dello stato corrente della macchina che viene aggiornato ad ogni confronto, ogni valore degli oggetti triple è stato letto e caricato in memoria (almeno questo con successo) da un file di testo così come la stringa in input, lo stato a cui arriva la macchina alla fine del "confronto" con l'input viene salvato su un file txt di output (anche qui ci siamo peccato non sia il risultato esatto), c'è qualcuno che potrebbe aiutarmi cortesemente? so che sicuramente è una stupidaggine, ma mi sono goffamente incartata su questa questione

questo è il ""codice"" dell'algoritmo di cambio stato che ho buttato giù:
public int statoRaggiunto ()
	{
		for (int j=0; j<stringa.length; j++)
		{
			for (int i=0; i<size; i++) /* con size = capienza array di oggetti triple*/
			{
				firstStatus = 1;
				
				do
				{
					firstStatus = nextStatus;
					
				} while(stringa[j] == test[i].getLetter());
			}
		}
		return firstStatus;
	} 
P.s (in termini di costi computazionali mi è stato detto che la struttura dati utilizzata su cui operare non consente algoritmi ottimali, usare una matrice o una lista concatenata avrebbe abbassato la complessità dei calcoli ma per questione di tempo non mi resta che andare avanti con questa soluzione,colgo anche l'occasione di salutare tutti i membri del forum essendo questo il mio primo post,grazie anticipatamente )

9 Risposte

  • Re: [JAVA] "Macchina a stati"

    Dovresti postare un po' di codice in più e soprattutto essere un po' più precisa (anche se forse sono io che son tardo. Da quello che ho capito, la tua applicazione dovrebbe: prendere da un file txt una sequenza di char, inserirli in un array (o almeno questa è la soluzione che hai scelto tu), esaminarli uno a uno da uno stato iniziale dato, e muoversi come una macchina a stati finiti fino ad un certo stato finale, che deve essere scritto su un file txt di output. È corretto?

    In caso, secondo me è sbagliata la struttura che hai scelto. So che tu dici di non avere il tempo di cambiarla, ma così ora come ora non mi viene in mente una soluzione intelligente (anzi, non mi viene in mente neanche una soluzione stupida!) perché l'algoritmo richiesto funzioni. Hai bisogno di una classe che contenga lo stato corrente della macchina, una classe immutabile con dei metodi (statici) che a seconda del char e dell'int che ricevono restituiscono lo stato successivo. E dopo, diciamo nel "main", combinando le due cose puoi iterare più facilmente. Ma forse ho capito male io.
  • Re: [JAVA] "Macchina a stati"

    Ciao darkobra, grazie per aver risposto, mi spiego meglio: ho un array con oggetti di tipo "triple" (a loro volta formati da 3 parametri: int statocorrente, char lettera, int statosuccessivo) caricati correttamente nell'array dopo averli letti da un file di testo, per ogni oggetto presente ho creato i vari metodi get e set per avere i valori restituiti o modificarli, dopodichè ho una stringa in input (anche lei memorizzata in un array carattere per carattere) confrontando i caratteri della stringa in input con i parametri "lettera" degli oggetti nell'array dovrei far si che la macchina cambi stato (a incominciare da quello iniziale = 1) la mia difficoltà è quella di impostare lo stato iniziale = 1 e soprattutto creare un metodo che faccia si che questa macchina cambi stato , l'array di oggetti triple l'ho inizializzato e creato nel costruttore dell'oggetto macchina, nel main ho letto i dati da file di testo e li ho memorizzati correttamente e mi manca solo la creazione di questo metodo che possa essere invocato dalla macchina stessa e restituirmi il valore corretto ((
  • Re: [JAVA] "Macchina a stati"

    Ok, adesso è molto più chiara la struttura che hai dato. Potresti postare un po' il codice che hai fatto? Così vedo se posso darti una dritta
  • Re: [JAVA] "Macchina a stati"

    public class Macchina extends Triple
    {
    	int size; // CAPIENZA DELL'ARRAY DI OGGETTI TRIPLE.
    	int firstStatus; // STATO INIZIALE DELLA MACCHINA.
            Triple [] test ; // ARRAY DI PROVA DI OGGETTI TRIPLE.
    	char [] stringa; // STRINGA IN INPUT.
    	
    	/* COSTRUTTORE DELL'OGGETTO MACCHINA*/
      	public Macchina (Triple [] test)
    	{
    		test = new Triple[size]; /* CREA LO SPAZIO NELL'ARRAY DI PROVA*/
    
                    for(int i=0; i<size;i++)
    		{
    			test[i]= new Triple(currentStatus,letter,nextStatus);
    			firstStatus = 1; /* NON SO SE DEBBA ESSERE INIZIALIZZATO COSI :(
    		}
    		
    	}/* FINE DEL COSTRUTTORE*/
    	
    	 /*METODO PER INSERIRE LA STRINGA CARATTERE PER CARATTERE IN UN ARRAY*/
    	public void putStr(String s)
    	{
    		stringa=(s.toLowerCase()).toCharArray();
    	}
    	
    	/**	METODO CHE CONSENTE LA TRANSAZIONE DA UNO STATO ALL'ALTRO DELLA    MACCHINA (FATTO MALISSIMO, MI RESTITUISCE TUTTO TRANNE IL VERO VALORE :( )
    	public int statoRaggiunto ()
    	{
    		for (int j=0; j<stringa.length; j++)
    		{
    			for (int i=0; i<size; i++)
    			{
    				firstStatus = 1;
    				
    				if(stringa[j] == test[i].getLetter())
    				{
    					firstStatus = test[i].getNextStatus();
    				}
    			}
    		}
    		return firstStatus;
    	}
    }
    ovviamente il firstStatus che viene ritornato alla fine del metodo non dovrebbe essere altro che lo stato iniziale modificato ogni volta che la macchina cambia stato (quindi lo stato raggiunto), l'array di prova che utilizzo ha size come capienza ma dopo aver letto i parametri da passare agli oggetti contenuti dal file di txt ti assicuro che sono tutti al loro posto con il vero valore
  • Re: [JAVA] "Macchina a stati"

    Io credo che tu abbia fatto un po' di confusione, senza offesa sia chiaro. Non è sicuramente semplice se non si ha un po' di esperienza (e quella la si fa col tempo, ahimè).

    Avrei bisogno anche della classe Triple, questo perché vedo che tu hai definito una classe Macchina che la estende. Non è quello che, da un punto di vista della progettazione, farei io. In verità da quello che leggo, estendere la classe Triple non è proprio necessario! Te lo chiedo perché non so di quale facoltà sia il corso, né le specifiche del progetto, hai la possibilità di utilizzare classi di utilità della libreria Java? Come ArrayList, per esempio... perché non capisco come quel codice possa funzionare!
    
    public class Macchina extends Triple
    {
       	int size; // CAPIENZA DELL'ARRAY DI OGGETTI TRIPLE.
       	…
       
    	/* COSTRUTTORE DELL'OGGETTO MACCHINA*/
         public Macchina (Triple [] test)
       	{
         	test = new Triple[size]; /* CREA LO SPAZIO NELL'ARRAY DI PROVA*/
    
    	      for(int i=0; i<size;i++)
         	{
             		test[i]= new Triple(currentStatus,letter,nextStatus);
             		firstStatus = 1; /* NON SO SE DEBBA ESSERE INIZIALIZZATO COSI :(
          	}
          
       }/* FINE DEL COSTRUTTORE*/
    Prima di tutto, size non è stato inizializzato, quindi la riga
    
    test = new Triple[size];
    
    dovrebbe darti un errore.

    Inoltre, anche l'intero for ha lo stesso problema. Size, currentStatus, letter e nextStatus non sono inizializzati e quindi dovrebbero dare un errore. Inoltre, mettere la riga
    
    firstStatus = 1;
    
    all'interno del costrutto for è un errore semantico, quell'operazione deve essere fatta una volta sola!

    Per risolvere il problema della mancata inizializzazione di questi parametri, che è fondamentale (infatti è da lì che derivano tutti i problemi), devo prima sapere se puoi, da specifiche, utilizzare classi di utilità di Java quali appunto ArrayList. Puoi?

    Andiamo avanti.
    Questo metodo, non è corretto.
    
       /**   METODO CHE CONSENTE LA TRANSAZIONE DA UNO STATO ALL'ALTRO DELLA    MACCHINA (FATTO MALISSIMO, MI RESTITUISCE TUTTO TRANNE IL VERO VALORE :( )
       public int statoRaggiunto ()
       {
          for (int j=0; j<stringa.length; j++)
          {
             for (int i=0; i<size; i++)
             {
                firstStatus = 1;
                
                if(stringa[j] == test[i].getLetter())
                {
                   firstStatus = test[i].getNextStatus();
                }
             }
          }
          return firstStatus;
       }
    
    
    A parte il fatto che mi sarebbe molto più chiaro tutto se mi postassi la classe Triple, vorrei porre l'attenzione sulla riga
    
    firstStatus = 1;
    
    che viene eseguita ogni volta che viene eseguita ogni volta che le istruzioni dell'if vengono eseguite! Quindi in pratica ogni volta che si cicla sul secondo if, la variabile firstStatus viene re-inizializzata e questo sicuramente ti sfasa tutto.

    Se mi rispondi a quelle domande comunque credo che l'applicazione sia abbastanza fattibile.
  • Re: [JAVA] "Macchina a stati"

    Eccomi, scusa il ritardo della risposta ma sono rientrata ora, dunque per quanto riguarda gli arrayList (se mi dici che c'è bisogno di loro) posso utilizzarli, ho un libro che li illustra molto bene e potrei arrangiarmici senza problemi, per quanto riguarda la classe Triple eccola qui:
    public class Triple 
    { 
    	public int currentStatus; // stato corrente.
    	public int nextStatus;   // stato successivo.
    	public char letter;     // lettera da leggere per transitare allo stato successivo.
    	
    	/** COSTRUTTORE CHE PASSA I TRE PARAMETRI {I,C,J} ALL'OGGETTO TRIPLETTA */
    	public Triple (int currentStatus, char letter, int nextStatus)
    	{
    		this.currentStatus = currentStatus;
    		this.nextStatus = nextStatus;
    		this.letter = letter;
    	}
    	 
    	/** COSTRUTTORE CHE INIZIALIZZA UN OGGETTO TRIPLETTA VUOTO*/
    	public Triple()
    	{}
    	
    	public int getCurrentStatus()
    	    { 
    	    	return currentStatus;
    	    }
    	        
    	   public int getNextStatus()
    	   {
    		   return nextStatus;
    	   }
    
    	   
    	   public char getLetter()
    	   {
    		   return letter;
    	   }
    	
    	   public void setCurrentStatus(int realCurrentStatus)
    	   {
    		  this.currentStatus = realCurrentStatus;
    	   }
    	   
    	   public void setNextStatus(int realNextStatus)
    	   {
    		  this.nextStatus = realNextStatus;
    	   }
    	   
    	   public void setLetter(char realLetter)
    	   {
    		   this.letter = realLetter;
    	   }
    	 
    }
    
    Nel main poi creo l'array e lo farcisco di oggetti con i veri parametri e la vera capienza:
    public static void main (String args [])
    	{
    		ReadFile reader=new ReadFile("./src/input.txt"); /* CREA L'OGGETTO READER CHE ANDRA' A LEGGERE INFORMAZIONI NEL FILE SPECIFICATO*/
    		WriteFile writer=new WriteFile("./src/outputFile.txt");/*CREA L'OGGETTO WRITER CHE ANDRA'A SCRIVERE INFO NEL FILE SPECIFICATO*/
    		
    		/* APRE ENTRAMBI I CANALI, DI LETTURA E SCRITTURA, RELATIVI A READER E WRITER*/
    		reader.open();
    		writer.open();
    		
    		/* LEGGE DALLA PRIMA RIGA DEL FILE TXT APERTO I PARAMETRI {M,N,K} SUDDIVIDENDO LA LINEA IN TOKEN*/
    		String rules = reader.readNextLine();
    		StringTokenizer distinctRules = new StringTokenizer(rules);
    		int numberOfTriple = Integer.parseInt(distinctRules.nextToken());
    		int numberOfConfig = Integer.parseInt(distinctRules.nextToken(" " + numberOfTriple));
    		int stringElements = Integer.parseInt(distinctRules.nextToken(" " + numberOfConfig));
    		
    		/* LEGGE DALLA SECONDA RIGA DEL TXT LA STRINGA IN INPUT*/
    		String input[] = reader.parseNextLine();
    		
    		/*CREA IL VERO ARRAY DI OGGETTI TRIPLE CON IL VERO SPAZIO DI ALLOCAZIONE*/
    		Triple [] triplette = new Triple[numberOfTriple];
    		
    		/*CREA L'OGGETTO SARCOFAGO CONTENENTE IL VERO ARRAY DI OGGETTI TRIPLE*/
    		Macchina black = new Macchina(triplette);
    		
    		/* ITERA SUGLI EFFETTIVI SPAZI DELL'ARRAY TRIPLETTE (DEL SARCOFAGO)
    		 * CREANDO I VERI OGGETTI TRIPLE E ASSEGNANDO LORO I VERI PARAMETRI {I,C,J} 
    		 * CHE LI CARATTERIZZANO LEGGENDO LE M RIGHE RIMANENTI DEL FILE TXT DIVIDENDOLE IN 3 "COLONNE" */
    		for (int j = 0; j<numberOfTriple; j++)
    	    {
    			triplette[j] = new Triple();
    			
    			String textTriples = reader.readNextLine();
    			StringTokenizer choppedTriples = new StringTokenizer(textTriples);
    			        
    			int realCurrentStatus = Integer.parseInt(choppedTriples.nextToken());
    		    char realLetter = textTriples.charAt(2);
    			int realNextStatus = Integer.parseInt(choppedTriples.nextToken(" " + realLetter));
    		    
    			black.setCurrentStatus(realCurrentStatus);
    			black.setLetter(realLetter);
    			black.setNextStatus(realNextStatus);
    		}
    		
    		 /* LA MACCHINA INSERISCE LA STRINGA INPUT IN UN ARRAY CARATTERE PER CARATTERE, IL METODO TRIM RIMUOVE GLI SPAZI BIANCHI */
    	    black.putStr(input[0].trim());
    		
    	    /* LA MACCHINA INVOCA POI IL METODO GIVEMEQ CONFRONTANDO LA STRINGA INPUT CON IL VERO ARRAY DELLE TRIPLE
    		 * PER OTTENERE LO STATO RAGGIUNTO DALLA MACCHINA QUANDO HA FINITO DI ESAMINARE LA STRINGA INPUT E LO STAMPA SU UN FILE TXT DI OUTPUT*/
    		writer.printNextLine("" + black.statoRaggiunto());
    		
    		writer.close(); 
    	    reader.close();
    
    Tieni conto che ho provato a fare una stampa su schermo dei veri valori dell'array di triple (iterandolo) e in base a quelli che volevo vedere me li stampava correttamente, mi sono scordata a dire che il numero effettivo di triplette da leggere, il numero di stati possibili, la lunghezza dell'input ecc ecc vengono letti prima delle triple in se sul file di testo, quindi è anche grazie a loro che riesco a leggere quanti token voglio
  • Re: [JAVA] "Macchina a stati"

    Devi perdonarmi se ho capito male, è sicuramente colpa mia e del fatto che sono un po' tardo. Ma se ho capito bene, ho una soluzione semplice anche se una cosa non mi torna (in ogni caso puoi usare qualcuno degli algoritmi che sto utilizzando). Non sarà necessario usare ArrayList visto che la dimensione è segnata nel .txt.

    Dunque,
    prima di tutto ho scritto le due classi Triple e Macchina in modo separato, senza usare l'ereditarietà.

    Classe Triple
    
    public class Triple 
    {
    	private int currentStatus;
    	private char letter;
    	private int nextStatus;
    	
    	public Triple(int currentStatus, char letter, int nextStatus)
    	{
    		this.currentStatus = currentStatus;
    		this.letter = letter;
    		this.nextStatus = nextStatus;
    	}
    
    	public int getCurrentStatus() 
    	{
    		return currentStatus;
    	}
    	
    	public char getLetter() 
    	{
    		return letter;
    	}
    
    	public int getNextStatus() 
    	{
    		return nextStatus;
    	}
    	
    }
    
    Ho visto che avevi dichiarato dei parametri con visibilità public, e non credo che il professore ne sarebbe rimasto contento rimani sul private ed usa dei metodi per farteli restituire. Questa classe inoltre è immutabile, non hai modo di modificarne i valori dopo che hai istanziato un oggetto. È sempre meglio, quando possibile, far sì che le classi siano immutabili.

    Il cuore dell'applicazione è la classe Macchina, che ha un solo semplice metodo Compute, se ho capito bene è qui che ti sei confusa un poco
    
    public class Macchina 
    {
    	private Triple[] transizioni;
    	private int currentStatus;
    	
    	public Macchina(Triple[] transizioni, int currentStatus)
    	{
    		this.transizioni = transizioni;
    		this.currentStatus = currentStatus; //questo sarà lo stato iniziale
    	}
    	
    	/**
    	 * Metodo che esegue una computazione della macchina. La macchina ha un suo parametro currentStatus che
    	 * si può aggiornare solamente tramite questo metodo. Gli viene passata una letter, e a seconda di quella e 
    	 * e del currentStatus questo metodo determina lo stato successivo. Se non viene trovata una tripla
    	 * corrispondente, non fa niente e rimane nello stato attuale (sarebbe meglio lanciare una exception,
    	 * non so se le avete fatte).
    	 * @param letter la lettera che identifica la transizione corrente
    	 * @return currentStatus lo stato della macchina aggiornato dalla computazione
    	 */
    	public int compute(char letter) 
    	{
    		for(int i = 0; i<transizioni.length; i++) //itera su tutte le triplette per trovare una corrispondenza
    		{
    			if((transizioni[i].getCurrentStatus() == this.currentStatus) && (transizioni[i].getLetter() == letter))
    			{
    				//una corrispondenza tra le triplette è trovata quando currentStatus coincide con Triple.currentStatus
    				//e letter coincide con Triple.letter
    				this.currentStatus = transizioni[i].getNextStatus(); //in tal caso modifico this.currentStatus
    				return this.currentStatus; //e finisce la computazione
    			}
    		}
    		//se l'esecuzione arriva a questo punto, non si trova alcuna corrispondenza, e allora si rimane nello
    		//stato corrente
    		return this.currentStatus;
    	}
    }
    
    Ampiamente commentata. Sopra al metodo compute, ho anche messo un esempio di commento Javadoc, ho visto che da qualche parte li hai usati ma non in modo corretto. Se sono richiesti, guardati qualche @tag dalla guida ufficiale...

    A questo punto, il main. Non l'ho scritto tutto perché gran parte del codice era scritto bene, o andava riscritto di poco... ma mi sembravi comunque in grado di arrivarci senza fatica.
    
    public static void main (String args [])
    	   {
    		  //apro i file
    			
    	      int numberOfTriple = ... //numero di triplette
    	      int numberOfConfig = ... //possibili stati
    	      int stringElements = ... //input, anche se non sarebbe necessario
    	      int currentStatus = 1;
    	      
    	      //creo l'array di triplette
    	      Triple [] triplette;
    	      
    	      //popolo l'array di triplette
    	      for(int i = 0; i<numberOfTriple; i++)
    	      {
    	    	  triplette[i] = new Triple(/*puoi usare i metodi dello StringTokenizer per creare nuove triplette*/);
    	      }
    	     
    	      //creo la macchina e adesso gli passo l'array triplette, già popolato
    	      Macchina black = new Macchina(triplette, currentStatus);
    	      
    	      
    	      char[stringElements] input = //popolo l'array di char che costituisce l'input
    	      
    	      //itero sul numero di input che ho		  
    	      for(int i = 0; i<stringElements; i++)
    	      {
    	    	  currentStatus = black.compute(input[i]); //lancio semplicemente il
    	      }
    	      
    	      
    	     //scrivo lo stato che ho raggiunto, contenuto nella variabile currentStatus che si aggiorna nel for e chiudo i file
    	   }
    
    Quello che non capisco è a cosa serve sapere il numero possibile di stati. In verità non serve, o almeno, per come ho scritto io la classe Macchina ne è indipendente. L'unico dubbio che ho! Per il resto, fammi sapere se c'è qualcosa di poco chiaro o se sono io che ho ancora poco chiaro qualcosa della consegna!
  • Re: [JAVA] "Macchina a stati"

    Beh che dire se non..GRAZIEEEEE!!!! sei stato un tesoro, davvero gentilissimo, non è da tutti aiutare in maniera così generosa, tutto funziona a dovere....grazie di cuore, consegnato il progetto sarai la prima persona che informerò su com'è andata grazie ancora!!
  • Re: [JAVA] "Macchina a stati"

    ClaudiaRo93 ha scritto:


    Beh che dire se non..GRAZIEEEEE!!!! sei stato un tesoro, davvero gentilissimo, non è da tutti aiutare in maniera così generosa, tutto funziona a dovere....grazie di cuore, consegnato il progetto sarai la prima persona che informerò su com'è andata grazie ancora!!
    Ahahaha prego prego
    PS: hai un messaggio privato
Devi accedere o registrarti per scrivere nel forum
9 risposte