• 0 voto(i) - 0 media
  • 1
  • 2
  • 3
  • 4
  • 5
Algoritmo per la gestione di un ascensore in C++
#1
Buongiorno,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:
#include "stdafx.h"
#include <iostream>
#include <conio.h>
using namespace std;

class Ascensore
{

private:
    int piani;

public:
    int piano_corrente;
    bool porte_aperte;
    Ascensore(int _piani, bool _porte_aperte) { piani = _piani; porte_aperte = _porte_aperte; piano_corrente = 0; }
    ~Ascensore() { cout << "\nProgramma terminato.\n"; };
    void Up()
    {
        char scelta;
        if(porte_aperte)
        {
            cout << "Le porte dell'ascensore sono aperte, non può muoversi. Chiudere le porte ? (S/N) ";
            cin >> scelta;
            if( (scelta == 'S') || (scelta == 's') ) porte_aperte = false;
            else if( (scelta == 'N') || (scelta == 'n') ) cout << "L'ascensore non può muoversi\n";
            else cout << "Scelta non valida, il programma terminerà";
        }
        else
        {
            if(piano_corrente == piani) cout << "L'ascensore si trova all'ultimo piano\n";
            else piano_corrente += 1;
        }
    }
    void Down()
    {
        char scelta;
        if(porte_aperte)
        {
            cout << "Le porte dell'ascensore sono aperte, non può muoversi. Chiudere le porte ? (S/N) ";
            cin >> scelta;
            if( (scelta == 'S') || (scelta == 's') ) porte_aperte = false;
            else if( (scelta == 'N') || (scelta == 'n') ) cout << "L'ascensore non può muoversi\n";
            else
            {
                cout << "Scelta non valida, il programma terminerà";
                _getch();
            }
        }
        else
        {
            if(piano_corrente == 0) cout << "L'ascensore si trova al piano terra\n";
            else piano_corrente -= 1;
        }
    }
};

int main()
{
    int scelta;
    Ascensore *ascensore = new Ascensore(5, false);
    do 
    {
        cout << "L'ascensore si trova al piano " << ascensore->piano_corrente << " cosa vuoi fare ?\n1. Sali\n2. Scendi\n3. Apri porte\n4. Chiudi porte\n5. Esci\nScegli (1/2/3/4/5) : ";
        cin >> scelta;
        switch(scelta)
        {
            case 1: ascensore->Up(); break;
            case 2: ascensore->Down(); break;
            case 3: ascensore->porte_aperte = true; break;
            case 4: ascensore->porte_aperte = false; break;
            case 5:
                delete ascensore;
                _getch();
                return 0;
                break;
            default: cout << "Scelta non corretta!\n"; break;
        } 
    } while( (scelta != 1) || (scelta != 2) || (scelta != 3) || (scelta != 4) || (scelta != 5) );
    _getch();
    return 0;
}

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.
  Cita messaggio


Vai al forum:


Utenti che stanno guardando questa discussione: 1 Ospite(i)