{ File: palude4.pas }

{ Scopo: esercizio significativo sull'uso di pile }

program AttraversaPalude;
{ Legge da un file di testo una matrice di 0 e 1 che rappresenta una palude,
  la stampa, cerca un attraversamento e lo stampa se esiste.

  Variante in cui sono possibili movimenti solo in avanti, cioe`
  da <riga,colonna> a
   - <riga-1, colonna+1>  (solo se la riga non e` la prima)
   - <riga,   colonna+1>
   - <riga+1, colonna+1>  (solo se la riga non e` l'ultima)

  Soluzione che fa uso una pila che simula la pila dei record di attivazione
  in una implementazione ricorsiva.
}

const
  R = 5;    { numero di righe, cioe` larghezza della palude }
  C = 7;    { numero di colonne, cioe` lunghezza della palude,
              coincide con la lunghezza di un cammino attraverso la palude }

  MaxPila = C;

type
  TipoRiga      = 1..R;
  TipoColonna   = 1..C;
  TipoPalude    = array [TipoRiga, TipoColonna] of 0..1;
  TipoCammino   = array [TipoColonna] of TipoRiga;

  TipoElemPila  = TipoRiga;   { gli elementi della pila sono indici di riga }

{$I PILESEQ.PAS} { Inclusione delle procedure e funzioni per la gestione di pile }


  procedure EsploraPalude (palude      : TipoPalude;
                           var trovato : boolean;
                           var cammino : TipoCammino);
  { Cerca un cammino che porti dalla prima fino all'ultima colonna della
    palude. }

  var
    ri  : integer;
    p   : TipoPila;
    col : TipoColonna;

    procedure CercaCammino (riga: TipoRiga);
    { Cerca un cammino a partire dalla prima posizione della riga della palude
      usando una pila.
      Se il cammino viene trovato viene memorizzato nella pila stessa. }
    var
      colonna   : TipoColonna;
      riga_prec : TipoRiga;
      backtrack : boolean;
  { variabili esterne utilizzate
      palude    : TipoPalude;
      trovato   : boolean; }

    begin { CercaCammino }
      Push(p, riga);
      colonna := 1;

      while (not trovato) and (not TestPilaVuota(p)) do
                                   { fino a quando non ho trovato un cammino
                                     e ho ancora alternative continuo }
      begin
        TopPila(p, riga);          { vedo su che riga sono }
        if palude[riga,colonna] = 1 then  { se sono su una posizione di terra }
          if colonna = C then      { se sono arrivato alla fine della palude }
            trovato := TRUE        { ... forzo la terminazione del ciclo }
          else                     { non sono arrivato alla fine della palude }
          begin                    { ... e provo ad andare avanti }
            colonna := colonna + 1;
            if riga > 1 then
              Push(p, riga-1)      { ... sulla riga precedente }
            else
              Push(p, riga)        { ... o sulla stessa riga }
          end
        else                       { se sono su una posizione di mare }
        begin                      { ... devo fare backtrack }
          backtrack := TRUE;
          repeat
            Pop(p, riga);          { ... ritratto l'ultima scelta fatta }
            if (colonna = 1) then      { se ero sulla prima colonna }
              backtrack := FALSE       { ... smetto }
            else                       { altrimenti }
            begin
              TopPila(p, riga_prec);
              if (riga < riga_prec + 1) and (riga < R) then
                                       { ... se ho alternative }
              begin
                Push(p, riga + 1);         { ... provo la prossima }
                backtrack := FALSE         {     e smetto di fare backtrack }
              end
              else                         { altrimenti }
                colonna := colonna - 1     { ... devo tornare indietro }
            end
          until not backtrack
        end
      end
    end; { CercaCammino }

  begin { EsploraPalude }
    trovato := FALSE;
    InitPila(p);

    { prova a passare per gli elementi della prima colonna, fino a quando
      non e` stato trovato un cammino }
    ri := 1;
    while (not trovato) and (ri <= R) do
    begin
      CercaCammino(ri);
      ri := ri + 1
    end;

    if trovato then             { la pila contiene il cammino (al contrario) }
      for col := C downto 1 do  { svuoto la pila e memorizzo il cammino }
        Pop(p, cammino[col])
  end; { EsploraPalude }


  procedure StampaCammino (pal: TipoPalude; cammino: TipoCammino);
  { Stampa su video una palude evidenziando un cammino attraverso asterischi. }
  var
    riga    : TipoRiga;
    colonna : TipoColonna;

  begin
    writeln('Cammino che attraversa la palude:');

    for riga := 1 to R do
    begin
      for colonna := 1 to C do
      begin
        write(pal[riga,colonna]);        { stampa l'elemento della matrice  }
        if riga = cammino[colonna] then  { se il punto fa parte del cammino }
          write('*')                     {   stampa '*'                     }
        else                             { altrimenti                       }
          write(' ')                     {   stampa uno spazio              }
      end;
      writeln
    end
  end; { StampaCammino }


  procedure LeggiPalude (var pal: TipoPalude);
  { Legge da un file di testo una matrice di 0 e 1 che rappresenta una
    palude. }
  var
    nome_file    : string;       { nome del file dal quale leggere la matrice }
    file_matrice : text;         { nome del file logico }
    riga         : TipoRiga;     { usati come indici dei cicli }
    colonna      : TipoColonna;

  begin { LeggiPalude }
    writeln('Nome del file contenente la rappresentazione della palude ?');
    readln(nome_file);

    assign(file_matrice, nome_file);
    reset(file_matrice);
    for riga := 1 to R do
      for colonna := 1 to C do
        read(file_matrice, pal[riga,colonna]);
    close(file_matrice)
  end; { LeggiPalude }


  procedure StampaPalude (pal: TipoPalude);
  { Stampa su video una matrice di 0 e 1 che rappresenta una palude. }
  var
    riga    : TipoRiga;
    colonna : TipoColonna;

  begin { StampaPalude }
    for riga := 1 to R do
    begin
      for colonna := 1 to C do
        write(pal[riga,colonna],' ');
      writeln
    end
  end; { StampaPalude }


{ variabili utilizzate nel corpo del programma principale }
var
  pal          : TipoPalude;   { matrice che rappresenta la palude }
  camm         : TipoCammino;  { cammino trovato nella palude }
  trov         : boolean;      { indica se e` stato trovato un cammino }

begin { AttraversaPalude }
  LeggiPalude(pal);                   { lettura della matrice da file }
  writeln('Palude:');
  writeln;
  StampaPalude(pal);                  { stampa di verifica della matrice }

  EsploraPalude(pal, trov, camm);     { ricerca del cammino }
  if trov then
    StampaCammino(pal, camm)
  else
    writeln('Non ci sono cammini che attraversano la palude')
end. { AttraversaPalude }