;;;Código fuente del libro "Experto AutoCAD con Visual LISP"
;;; (c) Ediciones ARTUAL, S.L. Barcelona, España.
;;; (c) 2012-2020 Reinaldo Togores. Todos los derechos reservados
;;; Se permite su uso mencionando la obra y su autor.
;;;CapÃtulo 5.  Funciones definidas por el usuario.
;;;5.2  Cargar y ejecutar funciones de usuario.------------------
(defun cap-i-cua (x y z) (strcat x y z y x))
;;;Listado 5.1. Código de la función CAP-I-CUA.
;;;5.3  Variables globales y locales.----------------------------
(defun mensaje-1 (/ x)Â
  (setq x "SEGUNDA")
  (princ. "\n Mensaje-1 asigna a x ")
  (princ. x)
  (princ. "\n Pero z sigue ")
  (princ. z))
(defun mensaje-2 (/ x)Â
  (setq x "TERCERA")
  (princ "\n Mensaje-2 asigna a x ")
  (princ x)
  (princ "\n Pero z sigue ")
  (princ z))
(defun mensajes (/ x z)Â
  (setq x "PRIMERA"
        z "SIN CAMBIOS")
  (princ "\n mensajes asigna a la variable x ")
  (princ x)
  (princ "\n y a la variable z ")
  (princ z)
  (mensaje-1)
  (mensaje-2)
  (princ "\n y de regreso a mensajes, x contiene ")
  (princ x)
  (princ "\n y como siempre, z ")
  (princ z)
  (princ))
;;;Listado 5.2. Demostración con variables locales.
;;;5.4  Predicados y Condicionales.------------------------------
(defun par-punteado-p (arg)Â
  (and (vl-consp arg) (atom (cdr arg))))
;;;Listado 5.3. Predicado PAR-PUNTEADO-P.
(defun stringp (arg)Â
  (eq (type arg) 'STR))
;;;Listado 5.4. Predicado STRINGP.
(defun lista? (arg / resultado)Â
  (if (listp arg)Â
    (setq resultado "SÃ")
    (setq resultado "No"))
  (princ (strcat resultado " es una lista"))
  (princ))
;;;Listado 5.5. Función LISTA? con asignación a variables locales.
(defun lista? (arg)Â
  (princÂ
    (strcatÂ
      (if (listp arg)Â
        "SÃ"
        "No")
      " es una lista"))
  (princ))
;;;Listado 5.6. Función LISTA? sin variables locales.
(defun tipo? (arg)Â
  (condÂ
    ((listp arg)
     (princ arg)
     (princ " es una lista"))
    ((vl-symbolp arg)
     (princ arg)
     (princ " es un sÃmbolo"))
    ((and (numberp arg) (zerop arg))
     (princ arg)
     (princ " es el número cero"))
    ((and (numberp arg) (minusp arg))
     (princ arg)
     (princ " es un número negativo"))
    ((numberp arg)
     (princ arg)
     (princ " es un número positivo"))
    (t
     (princ "no sabemos qué es ")
     (princ arg)))
  (princ))
;;;Listado 5.7. Función TIPO?.
(defun ordena-lista (lista funcion)Â
  (mapcar '(lambda (x) (nth x lista))Â
          (vl-sort-i lista funcion)))
;;;Listado 5.8. Función para ordenar listas.
(defun ordena-puntos (lista-puntos coordenada)Â
  (mapcarÂ
    '(lambda (x) (nth x lista-puntos))
    (vl-sort-iÂ
      lista-puntos
      '(lambda (x y)Â
         (< (nth coordenada x) (nth coordenada y))))))
;;;Listado 5.9. Ordenar lista de puntos según una de sus coordenadas.
(defun ordena-cadenas (cadena funcion)Â
  (apply 'strcatÂ
         (mapcar 'chrÂ
                 (ordena-listaÂ
                   (vl-string->list cadena)
                   funcion))))
;;;Listado 5.10. Función que ordena cadenas de caracteres.
(defun ordena-frase (frase funcion)Â
  (ordena-listaÂ
    (mapcar 'vl-princ-to-stringÂ
            (read (strcat "(" frase ")")))
    funcion))
;;;Listado 5.11. Función que ordena las palabras en una frase.
;;;Actualización: la función en el Listado 5.12 puede entrar en un bucle sin fin en caso
;;;de que la nueva cadena contenga los mismos caracteres que la antigua, como en
;;;sustituir "x" con "xx". Eso puede evitarse usando el siguiente código:
(defun sustituye  (nuevo viejo cadena / pos)
  (while (setq pos (vl-string-search viejo cadena pos))
    (setq cadena (vl-string-subst nuevo viejo cadena pos)
          pos (+ pos (strlen nuevo))))
  cadena)
;;;Listado 5.12. Sustitución de caracteres en una cadena.
(defun ordenar-frases-como-cadenas (frase / lista-frase)Â
  (acad_strlsortÂ
    (setq lista-frase (readÂ
                        (strcat "(\""Â
                                (sustituye "\"\"" " " frase)
                                "\")")))))
;;;Listado 5.13. Función para ordenar palabras contenidas en frases.
;;;5.5  Recursión---------------------------------------------------
(defun factorial (n)Â
  (condÂ
    ((zerop n) 1)
    (t (* n (factorial (- n 1))))))
;;;Listado 5.14. Factorial de un número.
(defun cuenta-miembros (elem lista)Â
  (condÂ
    ((null (member elem lista)) 0)
    (t
     (+ 1Â
        (cuenta-miembros elem (cdr (member elem lista)))))))
;;;Listado 5.15. Función para contar miembros de una lista.
(defun miembro (elem lista)Â
  (condÂ
    ((null lista) nil)
    ((equal (car lista) elem) lista)
    (t (miembro elem (cdr lista)))))
;;;Listado 5.16. Definición recursiva de la función member.
(defun aplana (lista)Â
  (condÂ
    ((atom lista) (list lista))
    (t
     (appendÂ
       (aplana (car lista))
       (aplana (cdr lista))))))
;;;Listado 5.17. Función para aplanar listas anidadas.
(defun aplana (lista)Â
  (condÂ
    ((null lista) nil)
    ((atom lista) (list lista))
    (t
     (appendÂ
       (aplana (car lista))
       (aplana (cdr lista))))))
;;;Listado 5.18. Función aplana eliminando términos nil.
;;;5.6  Iteración----------------------------------------------------
(defun fibonacci (cuantos / serie prox)Â
  (setq serie '(1)
        prox  1)
  (repeat (- cuantos 1)Â
    (setq serie (cons prox serie)
          prox  (+ (car serie) (cadr serie))))
  (reverse serie))
;;;Listado 5.19. Función FIBONACCI implementada con REPEAT.
(defun cap-i-cua-p (cadena / cont resultado)Â
  (setq cont      0
        resultado t)
  (repeat (/ (strlen cadena) 2)Â
    (ifÂ
      (notÂ
        (equalÂ
          (strcase (substr cadena (1+ cont) 1))
          (strcaseÂ
            (substr cadena (- (strlen cadena) cont) 1))))
      (setq resultado nil))
    (setq cont (1+ cont)))
  resultado)
;;;Listado 5.20. Predicado CAP-I-CUA-P (usando repeat).
(defun imprime-lista (lista /)Â
  (foreach term lista (print term))
  (princ))
;;;Listado 5.21. Impresión de lista (con FOREACH).
(defun imprime-lista (lista /)Â
  (mapcar 'print lista)
  (princ))
;;;Listado 5.22. Impresión de lista (con MAPCAR).
(defun cuadrados-1 (lista)Â
  (mapcar '(lambda (term) (* term term)) lista))
;;;Listado 5.23. Cuadrados de una lista (con mapcar).
(defun cuadrados-2 (lista)Â
  (condÂ
    ((null lista) nil)
    (t
     (cons (* (car lista) (car lista))Â
           (cuadrados-2 (cdr lista))))))
;;;Listado 5.24. Cuadrados de una lista (recursiva).
(defun cuadrados-3 (lista / resultado)Â
  (setq resultado nil)
  (foreach term listaÂ
    (setq resultado (cons (* term term) resultado)))
  (reverse resultado))
;;;Listado 5.25. Cuadrados de una lista (foreach).
(defun cuenta-entidades (/ cont ent)Â
  (setq cont 0
        ent  (entnext))
  (while entÂ
    (setq cont (1+ cont)
          ent  (entnext ent)))
  cont)
;;;Listado 5.26. Conteo de entidades.
(defun cap-i-cua-p (cadena / cont resultado)Â
  (setq cont      0
        resultado t)
  (while (and (<= cont (/ (strlen cadena) 2)) resultado)Â
    (ifÂ
      (notÂ
        (equal (substr cadena (1+ cont) 1)Â
               (substr cadena (- (strlen cadena) cont) 1)))
      (setq resultado nil))
    (setq cont (1+ cont)))
  resultado)
;;;Listado 5.27. Predicado CAP-I-CUA-P (con while).
(defun lista-nombres (tabla / nombre tmp)Â
  (setq tmp (cons (cdr (assoc 2 (tblnext tabla t))) tmp))
  (while (setq nombre (cdr (assoc 2 (tblnext tabla))))Â
    (setq tmp (cons nombre tmp)))
  (acad_strlsort tmp))
;;;Listado 5.28. Obtención de los nombres de elementos contenidos en las tablas de sÃmbolos.