• Regolamento Macrocategoria DEV
    Prima di aprire un topic nella Macrocategoria DEV, è bene leggerne il suo regolamento. Sei un'azienda o un hosting/provider? Qui sono anche contenute informazioni per collaborare con Sciax2 ed ottenere l'accredito nella nostra community!

Info Algoritmo per la gestione di un ascensore in C++

System32

Utente Stellare
Autore del topic
2 Gennaio 2010
15.556
112
Miglior risposta
0
Buongiorno, è da tanto che non scrivo in questa sezione. Oggi vi propongo un algoritmo che gestisce, in modo semplice e chiaro, un ascensore. Alt. Quello che leggerete di seguito non è un sorgente che gestirà realmente un ascensore, si tratta solo di un'emulazione, è bene che lo sappiate. Dunque, questo "progetto" è partito, come tutti, da un problema ( ricordatevi sempre che la logica di un programmatore è la seguente : ho un problema ? Devo scomporlo, se complesso, in piccolo sotto-problemi ) : il problema era come far capire all'ascensore che se le porte di quest'ultimo sono aperte non deve né salire, né scendere. Un altro problema, di poca rilevanza perché è semplice, era quello di far capire all'ascensore che se, dato un numero di piani ( un condominio, per esempio, ha un numero fisso di piani ) se esso si trova all'ultimo piano non deve più salire; viceversa se si trova al piano terra non deve scendere. Di seguito il sorgente :

PHP:
Perfavore, Entra oppure Registrati per vedere i codici!

NB: la prima riga in assoluto, ovvero #include "stdafx.h", non è altro che un file di intestazione che non esiste in altri IDE, solo in Visual Studio o Visual C++ perciò se non state usando uno di quei due IDE togliete pure quella riga.

Spiegazione del codice

File di intestazione : I file di intestazione che ho utilizzato sono iostream ( header di base del C++ ) e conio.h ( per poter chiamare la funzione _getch().

Classe Ascensore: All'interno di questa classe ho dichiarato due tipi di variabili : variabili pubbliche ( public, utilizzabili in qualsiasi parte del codice, purché sia creato l'oggetto Ascensore ) e variabili private ( private, il cui scope, ovvero visibilità, è limitata solo alla classe in cui la variabile è dichiarata ). Sotto private ho inserito solo una variabile ( piani ) perché questa non deve essere in alcun modo modificata dall'utente, difatti non verrà toccata al di fuori della sua classe. Invece sotto public ho inserito le variabili che verranno modificate al di fuori della classe in cui sono dichiarate.

Il costruttore : Ho creato il costruttore Ascensore che accetta due parametri : il primo non è modificabile, poiché è private, il secondo invece lo è. Più avanti lo vedremo meglio.

NB: Volevo soffermarmi un attimo sulla questione "costruttori/distruttori". In una classe è importantissimo definire il costruttore e il relativo distruttore di quest'ultima. Una classe, quando viene istanziata, può accettare diversi parametri, o può non accettarne; questo ce lo dice il costruttore il quale, in caso di mancato passaggio di parametri, ci avverte che l'istanza della classe che abbiamo scritto o non esiste oppure è scritta in modo sbagliato ( per chiarire : non ce lo dice il costruttore, in fase di linking è il linker che non trovando una corrispondenza tra quello che abbiamo scritto e quello che avremmo dovuto scrivere ci avvisa ). Per quanto riguarda il distruttore invece anche questo è assai importante. Supponiamo di aver scritto un programma complesso. L'utente decide di terminare il programma. Il programma apriva un paio di connessioni ad internet, e le terminava quando l'utente premeva un bottone. Voi direte : non c'è bisogno del distruttore, si possono chiudere le eventuali connessioni nell'evento Form_Closing ( in caso stessimo programmando una Windows Form ). Io vi dico che avete ragione, ma otterreste lo stesso risultato ( visibile anche in modo più appropriato e corretto ) con il distruttore. Il distruttore in parole povere ( richiamandolo con delete Nome_Classe ) non fa altro che rilasciare le risorse del programma senza lasciare memoria allocata. Questo perché, ma penso lo sappiate, quando si crea una classe viene allocata la memoria per le sue variabili, metodi, proprietà e per quanto scritto all'interno del suo corpo ( corpo della classe ).

Il distruttore : Come appena spiegato, il distruttore permette il rilascio delle risorse in modo sicuro ed efficiente.

La funzione Up() : Bene qui iniziamo a comprendere la logica dell'algoritmo. Innanzitutto ricordiamo cos'è un algoritmo : un algoritmo è una sequenza logica, studiata e infine messa per iscritto di un problema, la cui non sempre semplice soluzione si ottiene scomponendo il problema in tanti piccolo sotto-problemi. Orbene, come tutti comprendono, l'ascensore non può muoversi se le porte sono aperte. Perché devo verificare che le porte siano aperte ? Beh prima di tutto perché l'ascensore se le porte sono aperte si suppone che lo siano per far salire le persone, quindi se si muovesse le persone precipiterebbero verso il basso; secondariamente, e qui è importante, dobbiamo ricordarsi che nel costruttore il programmatore può decidere se l'ascensore avrò o no le porte aperte quando partirà il programma ( io per logica le ho chiuse, un inquilino di due piani più sopra potrebbe chiamarlo e se avesse le porte aperte di default non potrebbe muoversi, dovrebbe scendere, chiudere le porte, risalire e chiamarlo e non avrebbe senso ). Ecco perché il primo controllo che la funzione Up() controlla è se le porte sono aperte; se lo sono le chiude, altrimenti le lascia aperte perché evidentemente stanno salendo persone ( oppure, cosa improbabile, qualche genio si è dimenticato di chiuderle eheh ). Infine, la funzione controlla se l'ascensore non si trovi già all'ultimo piano, ovviamente non potrebbe più salire, mica vola questo ascensore. Se l'ascensore è all'ultimo piano informa l'utente, altrimenti lo fa salire di un piano.

La funzione Down() : La funzione Down() segue la stessa identica logica della funzione Up(). Logicamente il controllo del piano dell'ascensore è inerente al piano terra, non all'ultimo.

Entry-point della funzione, o main() : Proprio così, la funzione main() si chiama Entry-point poiché il programma parte proprio da quella funzione. Nella programmazione di un Progetto Win32 difatti troverete la funzione main() definita come segue : int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPTSTR lpCmdLine, _In_ int nCmdShow). Detto questo, nella suddetta funzione istanzio la classe Ascensore passando come parametri il numero fisso di piani e false per indicare che le porte dell'ascensore sono inizialmente chiuse. Successivamente stampo una sorta di menù per l'utente dove gli chiedo cosa vuole che faccia questo ascensore.

NB: Come vi dicevo è importante controllare se le porte sono aperte o meno, perché nel menù l'utente può scegliere se aprirle o chiuderle. Supponiamo che un cretino apra le porte e subito dopo le chiuda, senza usare l'ascensore ( una volta ho visto un tizio farlo, questa supposizione è quindi veritiera non inventata ), quando queste saranno aperte l'ascensore non si muoverà, viceversa se fossero chiude l'ascensore potrebbe muoversi.

E il do-while ? Il do-while l'ho inserito per evitare che l'utente scelta una delle opzioni e, una volta eseguita l'opzione scelta, il programma termini. Con il do-while l'utente utilizzerà il programma finché non sceglierà l'opzione per uscire dal programma stesso. Inutile spiegare come funziona, spero sia chiaro.

Per oggi è tutto, alla prossima.
 
Ultima modifica:
  • Like
Reactions: 3 people
Buongiorno, è da tanto che non scrivo in questa sezione. Oggi vi propongo un algoritmo che gestisce, in modo semplice e chiaro, un ascensore. Alt. Quello che leggerete di seguito non è un sorgente che gestirà realmente un ascensore, si tratta solo di un'emulazione, è bene che lo sappiate. Dunque, questo "progetto" è partito, come tutti, da un problema ( ricordatevi sempre che la logica di un programmatore è la seguente : ho un problema ? Devo scomporlo, se complesso, in piccolo sotto-problemi ) : il problema era come far capire all'ascensore che se le porte di quest'ultimo sono aperte non deve né salire, né scendere. Un altro problema, di poca rilevanza perché è semplice, era quello di far capire all'ascensore che se, dato un numero di piani ( un condominio, per esempio, ha un numero fisso di piani ) se esso si trova all'ultimo piano non deve più salire; viceversa se si trova al piano terra non deve scendere. Di seguito il sorgente :

PHP:
Perfavore, Entra oppure Registrati per vedere i codici!

NB: la prima riga in assoluto, ovvero #include "stdafx.h", non è altro che un file di intestazione che non esiste in altri IDE, solo in Visual Studio o Visual C++ perciò se non state usando uno di quei due IDE togliete pure quella riga.

Spiegazione del codice

File di intestazione : I file di intestazione che ho utilizzato sono iostream ( header di base del C++ ) e conio.h ( per poter chiamare la funzione _getch().

Classe Ascensore: All'interno di questa classe ho dichiarato due tipi di variabili : variabili pubbliche ( public, utilizzabili in qualsiasi parte del codice, purché sia creato l'oggetto Ascensore ) e variabili private ( private, il cui scope, ovvero visibilità, è limitata solo alla classe in cui la variabile è dichiarata ). Sotto private ho inserito solo una variabile ( piani ) perché questa non deve essere in alcun modo modificata dall'utente, difatti non verrà toccata al di fuori della sua classe. Invece sotto public ho inserito le variabili che verranno modificate al di fuori della classe in cui sono dichiarate.

Il costruttore : Ho creato il costruttore Ascensore che accetta due parametri : il primo non è modificabile, poiché è private, il secondo invece lo è. Più avanti lo vedremo meglio.

NB: Volevo soffermarmi un attimo sulla questione "costruttori/distruttori". In una classe è importantissimo definire il costruttore e il relativo distruttore di quest'ultima. Una classe, quando viene istanziata, può accettare diversi parametri, o può non accettarne; questo ce lo dice il costruttore il quale, in caso di mancato passaggio di parametri, ci avverte che l'istanza della classe che abbiamo scritto o non esiste oppure è scritta in modo sbagliato ( per chiarire : non ce lo dice il costruttore, in fase di linking è il linker che non trovando una corrispondenza tra quello che abbiamo scritto e quello che avremmo dovuto scrivere ci avvisa ). Per quanto riguarda il distruttore invece anche questo è assai importante. Supponiamo di aver scritto un programma complesso. L'utente decide di terminare il programma. Il programma apriva un paio di connessioni ad internet, e le terminava quando l'utente premeva un bottone. Voi direte : non c'è bisogno del distruttore, si possono chiudere le eventuali connessioni nell'evento Form_Closing ( in caso stessimo programmando una Windows Form ). Io vi dico che avete ragione, ma otterreste lo stesso risultato ( visibile anche in modo più appropriato e corretto ) con il distruttore. Il distruttore in parole povere ( richiamandolo con delete Nome_Classe ) non fa altro che rilasciare le risorse del programma senza lasciare memoria allocata. Questo perché, ma penso lo sappiate, quando si crea una classe viene allocata la memoria per le sue variabili, metodi, proprietà e per quanto scritto all'interno del suo corpo ( corpo della classe ).

Il distruttore : Come appena spiegato, il distruttore permette il rilascio delle risorse in modo sicuro ed efficiente.

La funzione Up() : Bene qui iniziamo a comprendere la logica dell'algoritmo. Innanzitutto ricordiamo cos'è un algoritmo : un algoritmo è una sequenza logica, studiata e infine messa per iscritto di un problema, la cui non sempre semplice soluzione si ottiene scomponendo il problema in tanti piccolo sotto-problemi. Orbene, come tutti comprendono, l'ascensore non può muoversi se le porte sono aperte. Perché devo verificare che le porte siano aperte ? Beh prima di tutto perché l'ascensore se le porte sono aperte si suppone che lo siano per far salire le persone, quindi se si muovesse le persone precipiterebbero verso il basso; secondariamente, e qui è importante, dobbiamo ricordarsi che nel costruttore il programmatore può decidere se l'ascensore avrò o no le porte aperte quando partirà il programma ( io per logica le ho chiuse, un inquilino di due piani più sopra potrebbe chiamarlo e se avesse le porte aperte di default non potrebbe muoversi, dovrebbe scendere, chiudere le porte, risalire e chiamarlo e non avrebbe senso ). Ecco perché il primo controllo che la funzione Up() controlla è se le porte sono aperte; se lo sono le chiude, altrimenti le lascia aperte perché evidentemente stanno salendo persone ( oppure, cosa improbabile, qualche genio si è dimenticato di chiuderle eheh ). Infine, la funzione controlla se l'ascensore non si trovi già all'ultimo piano, ovviamente non potrebbe più salire, mica vola questo ascensore. Se l'ascensore è all'ultimo piano informa l'utente, altrimenti lo fa salire di un piano.

La funzione Down() : La funzione Down() segue la stessa identica logica della funzione Up(). Logicamente il controllo del piano dell'ascensore è inerente al piano terra, non all'ultimo.

Entry-point della funzione, o main() Proprio così, la funzione main() si chiama Entry-point poiché il programma parte proprio da quella funzione. Nella programmazione di un Progetto Win32 difatti troverete la funzione main() definita come segue : int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPTSTR lpCmdLine, _In_ int nCmdShow). Detto questo, nella suddetta funzione istanzio la classe Ascensore passando come parametri il numero fisso di piani e false per indicare che le porte dell'ascensore sono inizialmente chiuse. Successivamente stampo una sorta di menù per l'utente dove gli chiedo cosa vuole che faccia questo ascensore.

NB: Come vi dicevo è importante controllare se le porte sono aperte o meno, perché nel menù l'utente può scegliere se aprirle o chiuderle. Supponiamo che un cretino apra le porte e subito dopo le chiuda, senza usare l'ascensore ( una volta ho visto un tizio farlo, questa supposizione è quindi veritiera non inventata ), quando queste saranno aperte l'ascensore non si muoverà, viceversa se fossero chiude l'ascensore potrebbe muoversi.

E il do-while ? Il do-while l'ho inserito per evitare che l'utente scelta una delle opzioni e, una volta eseguita l'opzione scelta, il programma termini. Con il do-while l'utente utilizzerà il programma finché non sceglierà l'opzione per uscire dal programma stesso. Inutile spiegare come funziona, spero sia chiaro.

Per oggi è tutto, alla prossima.
io dopo aver studiato il python , ieri ho cominciato con il c ed è moltooo meglio sopratutto per la completa "gestione" sembra quasi binario xD
Comunque ottimo codice , pulito , anche se io avrei messo dei commenti // direttamente nel codice
 
Comunque ottimo codice , pulito , anche se io avrei messo dei commenti // direttamente nel codice

Non ho inserito i commenti direttamente nel sorgente perché la spiegazione dell'algoritmo è lineare e non pezzo per pezzo; lineare nel senso che come vedi ho spiegato per esteso la logica del programma, cosa che non avrei potuto fare inserendo dei commenti, se lo avessi fatto avrei commentato riga per riga e non era questo il mio obiettivo.
 
Questo algoritmo è da Premio Nobel :|

BRAVISSIMO. Il fatto che tu abbia usato l'Ascensore come protagonista dell'algoritmo è davvero originale e una genialata. Complimenti ^_^
 
Questo algoritmo è da Premio Nobel :|

BRAVISSIMO. Il fatto che tu abbia usato l'Ascensore come protagonista dell'algoritmo è davvero originale e una genialata. Complimenti ^_^

EDIT:
@System32

Spiegami una cosa. Perché hai scritto:

ascensore->piano_corrente e non ascensore.piano_corrente se piano_corrente è un attributo della classe? Inoltre a me da anche errore scrivendo ascensore.piano_corrente
 
EDIT:
@System32

Spiegami una cosa. Perché hai scritto:

ascensore->piano_corrente e non ascensore.piano_corrente se piano_corrente è un attributo della classe? Inoltre a me da anche errore scrivendo ascensore.piano_corrente

dato che ascensore è un oggetto ,
Codice:
Perfavore, Entra oppure Registrati per vedere i codici!
quando chiama il costruttore restituisce un riferimento di tale classe e il suo relativo indirizzo in memoria.Per accedervi dato che si sta riferendo a un puntatore , usa un operatore definito già dallo standard C99 appunto ->.La sintassi alternativa sarebbe
Codice:
Perfavore, Entra oppure Registrati per vedere i codici!
questo, perché il punto ha priorità maggiore del *(operatore di indirezione)
 
dato che ascensore è un oggetto ,
Codice:
Perfavore, Entra oppure Registrati per vedere i codici!
quando chiama il costruttore restituisce un riferimento di tale classe e il suo relativo indirizzo in memoria.Per accedervi dato che si sta riferendo a un puntatore , usa un operatore definito già dallo standard C99 appunto ->.La sintassi alternativa sarebbe
Codice:
Perfavore, Entra oppure Registrati per vedere i codici!
questo, perché il punto ha priorità maggiore del *(operatore di indirezione)

Moment, non credo di aver ben capito. Se creo una classe

Codice:
Perfavore, Entra oppure Registrati per vedere i codici!

Come vedi qui sopra, ho creato l'oggetto appartenente alla classe TBH.
eta è l'attributo della classe

Ora quel -> perché si usa? Perché io ho potuto usare il punto? forse perché, nel nostro caso, prova non è un puntatore? aiut
 
Moment, non credo di aver ben capito. Se creo una classe

Codice:
Perfavore, Entra oppure Registrati per vedere i codici!

Come vedi qui sopra, ho creato l'oggetto appartenente alla classe TBH.
eta è l'attributo della classe

Ora quel -> perché si usa? Perché io ho potuto usare il punto? forse perché, nel nostro caso, prova non è un puntatore? aiut


allora è la memorizzazione che è diversa . Il metodo usato da system sopra è memorizzato sul heap (memoria dinamica).
Nel tuo caso è salvato sullo stack che è memoria statica.
 
@HabboFanNumero1
eh bella domanda...
prima di risponderti analizzerò entrambi velocemente , riportando le principali caratteristiche di entrambi.
Stack
-accesso rapido (pro)
-Non ha un modo esplicito per deallocare (contro)
-Lo spazio è di tipo maneged, diciamo che è controllato inoltre la memoria non è frammentata (Pro)
-Per oggetti estremamente grandi è limitato (nel caso ad esempio di troppe chiamate ricorsive e oggetti troppi ampi) (Contro)
-Lo spazio dello stack cambia in base all'Os (contro)
-Lo spazio assegnato dallo stack non può essere ridimensionato (contro)

Heap

-Non legato al sistema operativo , nessun limite in memoria (Pro)
-Permette di deallocare la memoria manualmente tramite delete - delete[] oppure free (Pro)
-Accesso più lento (Contro) , è relativamente più lento
-La memoria può essere fragmentata (nel caso di molte allocazione e deallocazioni) (Dipende dal caso)
-In c++ per accedervi si userà un puntatore quindi riferimento a tale classe
-Lo spazio può essere riallocato durante l'esecuzione (Pro)


Sulla questione tra heap e stack troverai molto , perché ci sono fattori che io non ho citato nemmeno.Io personalmente credo che nel caso non si conosca la dimensione , o non si sà lo spazio da utilizzare è meglio usare il salvataggio sull'heap e accedervi indirettamente.
ti faccio un esempio veloce

Codice:
Perfavore, Entra oppure Registrati per vedere i codici!

se si conosce preventivamente lo spazio da utilizzare è preferibile usare lo stack altrimenti l'heap. Nel caso delle istanze di classi meglio ottenere il riferimento della classe e salvarla sul heap.

Ti aggiungo un link dove puoi approfondire:
Perfavore, Entra oppure Registrati per vedere i Link!
 
Ultima modifica:
@HabboFanNumero1
eh bella domanda...
prima di risponderti analizzerò entrambi velocemente , riportando le principali caratteristiche di entrambi.
Stack
-accesso rapido (pro)
-Non ha un modo esplicito per deallocare (contro)
-Lo spazio è di tipo maneged, diciamo che è controllato inoltre la memoria non è frammentata (Pro)
-Per oggetti estremamente grandi è limitato (nel caso ad esempio di troppe chiamate ricorsive e oggetti troppi ampi) (Contro)
-Lo spazio dello stack cambia in base all'Os (contro)
-Lo spazio assegnato dallo stack non può essere ridimensionato (contro)

Heap

-Non legato al sistema operativo , nessun limite in memoria (Pro)
-Permette di deallocare la memoria manualmente tramite delete - delete[] oppure free (Pro)
-Accesso più lento (Contro) , è relativamente più lento
-La memoria può essere fragmentata (nel caso di molte allocazione e deallocazioni) (Dipende dal caso)
-In c++ per accedervi si userà un puntatore quindi riferimento a tale classe
-Lo spazio può essere riallocato durante l'esecuzione (Pro)


Sulla questione tra heap e stack troverai molto , perché ci sono fattori che io non ho citato nemmeno.Io personalmente credo che nel caso non si conosca la dimensione , o non si sà lo spazio da utilizzare è meglio usare il salvataggio sull'heap e accedervi indirettamente.
ti faccio un esempio veloce

Codice:
Perfavore, Entra oppure Registrati per vedere i codici!

se si conosce preventivamente lo spazio da utilizzare è preferibile usare lo stack altrimenti l'heap. Nel caso delle istanze di classi meglio ottenere il riferimento della classe e salvarla sul heap.

Ti aggiungo un link dove puoi approfondire:
Perfavore, Entra oppure Registrati per vedere i Link!

Ma la differenza SOSTANZIALE, quella EVIDENTE qual è? A chi usa il programma intendo
 
@HabboFanNumero1

Evidenti , dipende dal programma ^^ .. in genere l'utilizzatore non se ne rende conto. Ovvio se tipo scrivi e vai oltre lo stack , l'applicazione chrasha inesorabilemente.
 
Ma la differenza SOSTANZIALE, quella EVIDENTE qual è? A chi usa il programma intendo

Il programmatore deve sapere cosa sta facendo e deve anche sapere come gestire la memoria, altrimenti, non testando il programma, si rischia di mandarlo in crash.

Ovvio se tipo scrivi e vai oltre lo stack , l'applicazione chrasha inesorabilemente.

Questo succede o se il programma non viene testato del tutto o se non si tiene conto di eventuali effetti negativi provenienti da un errore logico.
 
Il programmatore deve sapere cosa sta facendo e deve anche sapere come gestire la memoria, altrimenti, non testando il programma, si rischia di mandarlo in crash.

Quale sottospecie di pigro programmatore sarebbe capace di non testare il suo programma prima di rilasciarlo? :emoji_relieved:
 
Quale sottospecie di pigro programmatore sarebbe capace di non testare il suo programma prima di rilasciarlo? :emoji_relieved:

Volendo chiunque, anche un programmatore di tutto rispetto potrebbe non valutare un particolare caso in cui il programma potrebbe crashare. Secondo te perché esistono gli aggiornamenti dei software ? Secondo te il programma una volta scritto è perfetto e privo di errori ? Nella programmazione non esiste la perfezione.
 
Volendo chiunque, anche un programmatore di tutto rispetto potrebbe non valutare un particolare caso in cui il programma potrebbe crashare. Secondo te perché esistono gli aggiornamenti dei software ? Secondo te il programma una volta scritto è perfetto e privo di errori ? Nella programmazione non esiste la perfezione.

No, forse hai frainteso. La maggior parte dei programmatori, prima di rilasciare un programma, lo testano in tutto. Se poi tralasciano qualcosina e se ne accorgono dopo, lì poi fanno uscire l'aggiornamento, o no?
 
No, forse hai frainteso. La maggior parte dei programmatori, prima di rilasciare un programma, lo testano in tutto. Se poi tralasciano qualcosina e se ne accorgono dopo, lì poi fanno uscire l'aggiornamento, o no?

Io ho scritto che il programmatore, testando il programma, potrebbe non accorgersi di qualcosa. Può capitare. Una volta che il programmatore se ne accorge rilascia l'aggiornamento nel caso in cui il programma sia già stato pubblicato, altrimenti lo corregge e lo rilascia senza problemi.
 
Io ho scritto che il programmatore, testando il programma, potrebbe non accorgersi di qualcosa. Può capitare. Una volta che il programmatore se ne accorge rilascia l'aggiornamento nel caso in cui il programma sia già stato pubblicato, altrimenti lo corregge e lo rilascia senza problemi.

Abbiamo detto la stessa cosa :emoji_relieved: