cg-Cad

Lisp »Tips 'n Tricks »Gioco del labirinto »1 »2 »3 »4

LABI implementa in AutoLISP l'algoritmo per cercare un'uscita da un labirinto.
Il campo da gioco è un recinto rettangolare diviso in n celle, ogni cella contiene o 0 (sentiero) o 1 (siepe). E si può muovere all'interno del labirinto a nord sud est ed ovest ma non in diagonale.
Il labirinto può essere rappresentato in un linguaggio come il Pascal con un array bidimensionale. E l'algoritmo è il seguente:

if E è sul confine then
   exit
else
   begin
      prova verso est
      if not exit then prova verso sud
      if not exit then prova verso ovest
      if not exit then prova verso nord
   end

Si vede che la soluzione è analoga alla procedura per camminare a Manhattan (vedi Tutorial n.36 in 'AutoLISP Tips & Tricks Volume I', e in particolare la pagina 6) cioè una funzione ricorsiva.
AutoLISP non usa gli array ma si può fingere di usare una lista come se fosse un array.
Il Lisp legge dal file LABI.TXT la struttura del labirinto e la salva in una lista, traducendo 1 (siepe) nel simbolo # e 0 (sentiero) nel simbolo .
Il file LABI.TXT deve avere il seguente formato-dati:
'(
(n0 n1 n2 n3 nn)
...
(n0 n1 n2 n3 nn)
)
n=0,1

cioè un elenco di liste con lo stesso numero di elementi racchiuso in una lista preceduta dal segno ' (vedi tutorial n.58).
Il lisp segna con il segno x i sentieri percorsi e con * il percorso per uscire dal labirinto; se esiste un'uscita (dal punto digitato alla linea di comando CAD) salva il labirinto, le strade tentate e il sentiero verso l'uscita nel file EXLABI.TXT. Esempio:

############
#**###xxxx##
##***#x###.#
#..#*#x#...#
###**xx#####
#..*###****#
#.#*****##*#
##########*#

Legenda del file EXLABI.TXT:
# = siepe
. = sentiero
* = percorso per uscire dal labirinto
x = vicolo cieco

Il lisp chiede latitudine e longitudine del punto d'inizio, 2 numeri interi maggiori di 0 e diversi dal numero delle righe e dal numero delle colonne del file LABI.TXT (confini del labirinto, in rosso nel codice sorgente).
Ad esempio le coordinate (1 1) corrispondono al rigo 2 e alla colonna 2 nel file LABI.TXT.

LABI

;|
   LABI.LSP (3 Luglio 2005)
   Copyright (C) 2005 Claudio Piccini.
   All rights reserved
   www.cg-cad.com

   Implementa in AutoLISP l'algoritmo 'maze'.

   Legge dal file LABI.TXT il disegno di un labirinto
   Struttura del file LABI.TXT (esempio):
   '(
   (1 1 1 1 1 1 1 1 1 1 1 1)
   (1 0 0 1 1 1 0 0 0 0 1 1)
   (1 1 0 0 0 1 0 1 1 1 0 1)
   (1 0 0 1 0 1 0 1 0 0 0 1)
   (1 1 1 0 0 0 0 1 1 1 1 1)
   (1 0 0 0 1 1 1 0 0 0 0 1)
   (1 0 1 0 0 0 0 0 1 1 0 1)
   (1 1 1 1 1 1 1 1 1 1 0 1)
   )
   Ogni lista deve avere lo stesso numero di elementi (1 0)
   I caratteri riconosciuti dal lisp sono solo 2:
   1 = siepe
   0 = sentiero

   Salva su EXLABI.TXT il percorso per uscire dal labirinto.
   Esempio:
   ############
   #**###xxxx##
   ##***#x###.#
   #..#*#x#...#
   ###**xx#####
   #..*###****#
   #.#*****##*#
   ##########*#

   Legenda:
   # = siepe
   . = sentiero
   * = percorso per uscire dal labirinto
   x = vicolo cieco
|;


;|
  LEGGEFILE()
  legge il file LABI.TXT
  salva il contenuto nella lista X -> L
  traduce 1 in "#" e 0 in "."
|;
(defun LeggeFile ( / nDir nf 
                     lista 
                     str i j e 
                     rigo X 
 )
 (setq nDir (getvar "dwgprefix"))
 (setq nf (strcat nDir "labi.txt"))
 (setq lista (load nf))
 (setq NR (length lista))
 (setq str (strcat "\nnumero righe file LABI.TXT=" (itoa NR)))
 (princ str)
 (setq NC (length (car lista)))
 (setq str (strcat "\nnumero colonne file LABI.TXT=" (itoa NC)))
 (princ str)
 (setq i 0)
 (while (< i NR)
  (setq j 0)
  (while (< j NC)
   (setq e (nth j (nth i lista)))
   (if (= e 0)
    (setq rigo (append rigo (list "."))) ; sentiero
    (setq rigo (append rigo (list "#"))) ; siepe
   )
   (setq j (1+ j))
  )
  (setq X (append X (list rigo))) 
  (setq rigo nil)
  (setq i (1+ i))
 )
 (setq X X)
)

;|
    SCRIVEFILE()
    salva la lista L nel file EXLABI.TXT
    il disegno del labirinto ed il percorso

    Legenda:
    # = siepe
    . = sentiero
    * = percorso per uscire dal labirinto
    x = vicolo cieco
|;
(defun ScriveFile ( NR NC lista / nDir nf f1 i j e )
 (setq nDir (getvar "dwgprefix"))
 (setq nf (strcat nDir "exlabi.txt"))
 (setq f1 (open nf "w"))
 (setq i 0)
 (while (< i NR)
  (setq j 0)
  (while (< j NC)
   (setq e (nth j (nth i lista)))
   (princ e f1)
   (setq j (1+ j))
  )
  (princ "\n" f1)
  (setq i (1+ i))
 )
 (close f1)
)

;|
   MAZE()
   Implementa l'istruzione 
   L[i,j] := valore
   con le liste
|;
(defun maze ( lista lat long segno / i j e rigo X )
 (setq i 0)
 (while (< i NR)
  (setq j 0)
  (while (< j NC)
   (setq e (nth j (nth i lista)))
   (if (and (= j long)(= i lat))
    (setq rigo (append rigo (list segno))) ; x *
    (setq rigo (append rigo (list e))) 
   )
   (setq j (1+ j))
  )
  (setq X (append X (list rigo))) 
  (setq rigo nil)
  (setq i (1+ i))
 )
 (setq X X)
)

;|
   CERCAEXIT()
   Cerca un sentiero 
   dal quadrato (lat long) 
   all'uscita
|;
(defun CercaExit ( lat long )
 (if (or (= lat 0)(= lat (1- NR))(= long 0)(= long (1- NC)))
  (setq exitOK T)
  (progn
   (setq L (maze L lat long "x"))
   (if (= (nth (1+ long)(nth lat L)) ".")
    (CercaExit lat (1+ long)) ; EST
   )  
   (if (not exitOK)
    (if (= (nth long (nth (1+ lat) L)) ".")
     (CercaExit (1+ lat) long) ; SUD
    )
   )
   (if (not exitOK)
    (if (= (nth (1- long)(nth lat L)) ".")
     (CercaExit lat (1- long)) ; OVEST
    )
   )
   (if (not exitOK)
    (if (= (nth long (nth (1- lat) L)) ".")
     (CercaExit (1- lat) long) ; NORD
    )
   )
  )
 )
 (if exitOK (setq L (maze L lat long "*")))
)

;|
  LABI
  funzione principale
  comando per eseguire il lisp
|;
(defun c:labi ( / str NR NC L
                  lat0 long0
                  exitOK ; valore booleano (T nil)
 )
 (setvar "cmdecho" 0)
 (setq L (LeggeFile))
 (setq str "\nInserire latitudine del quadrato di partenza: ")
 (while 
  (progn
   (initget (+ 1 2 4)) 
   (setq lat0 (getint str))
   (if (< lat0 NR) nil T)
  )
 )
 (setq str "\nInserire longitudine del quadrato di partenza: ")
 (while 
  (progn
   (initget (+ 1 2 4)) 
   (setq long0 (getint str))
   (if (< long0 NC) nil T)
  )
 )
 (setq exitOK nil)
 (CercaExit lat0 long0)
 (if (not exitOK)
  (princ "\nNon c'e' sentiero per uscire dal labirinto")
  (progn
   (princ "\nPercorso salvato in EXLABI.TXT")
   (ScriveFile NR NC L)
  )
 )
 (setvar "cmdecho" 1)
 (princ)
)
;;;eof

Test del Lisp

LABI.TXT:
'(
(1 1 1 1 1 1 1 1 1 1 1 1)
(1 0 0 1 1 1 0 0 0 0 1 1)
(1 1 0 0 0 1 0 1 1 1 0 1)
(1 0 0 1 0 1 0 1 0 0 0 1)
(1 1 1 0 0 0 0 1 1 1 1 1)
(1 0 0 0 1 1 1 0 0 0 0 1)
(1 0 1 0 0 0 0 0 1 1 0 1)
(1 1 1 1 1 1 1 1 1 1 0 1)
)

Command: labi
numero righe file LABI.TXT=8
numero colonne file LABI.TXT=12
Inserire latitudine del quadrato di partenza: 1
Inserire longitudine del quadrato di partenza: 1
Percorso salvato in EXLABI.TXT

############
#**###xxxx##
##***#x###.#
#..#*#x#...#
###**xx#####
#..*###****#
#.#*****##*#
##########*#

LABI.TXT:
'(
(1 1 1 1 1 1 1 1 1 1 1 1)
(1 0 0 1 1 1 0 0 0 0 1 1)
(1 1 0 0 0 1 0 1 1 1 0 1)
(1 0 0 1 0 1 0 1 0 0 0 1)
(1 1 1 0 0 0 0 1 1 1 1 1)
(1 0 0 0 1 1 1 0 0 0 0 1)
(1 0 1 0 0 0 0 0 1 1 0 1)
(1 1 1 1 1 1 1 1 1 1 0 1)
)

Command: labi
numero righe file LABI.TXT=8
numero colonne file LABI.TXT=12
Inserire latitudine del quadrato di partenza: 3
Inserire longitudine del quadrato di partenza: 9
Non c'e' sentiero per uscire dal labirinto

LABI.TXT:
'(
(1 1 1 1 1 1 1 1 1 1 1 1)
(1 0 0 1 1 1 0 0 0 0 1 1)
(1 1 0 0 0 1 0 1 1 1 0 1)
(1 0 0 1 0 1 0 1 0 0 0 1)
(1 1 1 0 0 0 0 1 1 1 1 1)
(1 0 0 0 1 1 1 0 0 0 0 1)
(1 0 1 0 0 0 0 0 1 1 0 1)
(1 1 1 1 1 1 1 1 1 1 0 1)
)

Command: labi
numero righe file LABI.TXT=8
numero colonne file LABI.TXT=12
Inserire latitudine del quadrato di partenza: 5
Inserire longitudine del quadrato di partenza: 1
Percorso salvato in EXLABI.TXT

############
#..###....##
##...#.###.#
#..#.#.#...#
###....#####
#***###****#
#.#*****##*#
##########*#

LABI.TXT:
'(
(1 1 1 1 1 1 1 1 1 1 1 1)
(1 1 0 1 1 1 1 1 1 1 1 1)
(1 0 0 1 1 1 0 0 0 0 1 1)
(1 1 0 0 0 1 0 1 1 0 0 1)
(1 0 0 1 0 1 0 1 0 0 0 1)
(1 1 1 0 0 0 0 1 0 1 1 1)
(1 0 0 0 1 1 1 0 0 0 0 1)
(1 0 1 0 0 0 0 0 1 1 0 1)
(1 0 0 1 1 0 1 1 1 1 0 1)
(1 1 1 1 1 0 1 1 1 0 1 1)
)

Command: labi
numero righe file LABI.TXT=10
numero colonne file LABI.TXT=12
Inserire latitudine del quadrato di partenza: 3
Inserire longitudine del quadrato di partenza: 3
Percorso salvato in EXLABI.TXT

############
##.#########
#..###****##
##.**#*##**#
#..#*#*#***#
###.***#*###
#...###**xx#
#.#..***##x#
#..##*####x#
#####*###.##

Trick

Come si esce dalla funzione ricorsiva CercaExit()? (non necessariamente dal labirinto).

Lisp »Tips 'n Tricks

Ultimo Aggiornamento_Last Update: 3 Luglio 2005