#lang racket

(require "Tacto-art.rkt")
(require "Olfato-art.rkt")
(require "Red-discriminacion-olfato.rkt")
(require "Red-discriminacion-tacto.rkt")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define control%
  (class object%
    (init-field
     (Cortex_tacto 'cortex_tacto)
     (Cortex_olfato 'cortex_olfato)
     (Discriminacion_olfato 'discriminacion_olfativa)
     (Discriminacion_tacto 'discriminacion_tactil)
     )
    (field
     (objetivo 'buscar);'buscar comida o 'regresar al nido
     (orientacion 'N)
     (sig_accion #f)
     )
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    (define/public set-orientacion
      (lambda (hacia)
        (set! orientacion hacia)
        ))
    (define/public set-objetivo
      (lambda (valor)
        (set! objetivo valor)
        ))
    (define/public get-objetivo
      (lambda ()
        objetivo ))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    (define/public proceso!
      (lambda (output_tactil output_olfativo lista_olores lista-vec_coord)
        (let*-values
            ([(output-tacto) 
              (send Cortex_tacto proceso! output_tactil)]
             [(pre-orden_tacto) 
              (send Discriminacion_tacto proceso! output-tacto)]
             [(output-olfato)
              (send Cortex_olfato proceso! output_olfativo)]
             [(pre-orden_olfato) 
              (send Discriminacion_olfato proceso! output-olfato)]
             [(lista-fero orden)
              (cond
                ((eq? objetivo 'buscar)
                 (buscando pre-orden_tacto pre-orden_olfato lista_olores) )
                ((eq? objetivo 'regresar)
                 (regresando pre-orden_tacto pre-orden_olfato lista_olores lista-vec_coord) )
                )]
             )
          (values lista-fero orden pre-orden_tacto pre-orden_olfato)
          )
        ))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    (define hay-blanco?
      (lambda (discr_tacto)
        (if (member 0 discr_tacto)
            #t
            #f)
        ))
    (define avanzar-al-blanco
      (lambda (discr_tacto)
        (let* ((blancos
                (filter-map
                 (lambda (index)
                   (if (= (list-ref discr_tacto index) 0)
                       index
                       #f)
                   )
                 '(0 1 2 3 4)) )
               (azar (if (= (length blancos) 1) 0 (random (length blancos))))
               (locus (list-ref blancos azar))
               (to-orden
                (lambda (sitio)
                  (map
                   (lambda (lugar)
                     (if (= lugar sitio)
                         0;sitio
                         '_
                         )
                     )
                   '(0 1 2 3 4))) )
               )
          (to-orden locus)
          )
        ))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    (define feromonas-en
      ;;devuelve la lista de índices de elementos en que existe feromona
      (lambda (discr_olfato indices)
        (if (null? discr_olfato)
            '()
            (if (= (car discr_olfato) 1/2)
                (cons
                 (car indices)
                 (feromonas-en (cdr discr_olfato) (cdr indices)))
                (feromonas-en (cdr discr_olfato) (cdr indices))
                )
            )
        ))
    (define rastro-a-seguir
      ;si hay uno de mayor intensidad, se sigue ese; si hay más de uno, al azar se sigue uno de ellos
      (lambda (lista-sitios+feromonas lista-olores)
        (let* ((intensidades
                ;lista de pares; cada par: intensidad . sitio
                (map
                 (lambda (sitio)
                   (cons (send (list-ref lista-olores sitio) get-intensidad) sitio)
                   )
                 lista-sitios+feromonas))
               (intensidades-ordenadas (sort intensidades #:key car >))
               ;intensidades ordenadas de mayor a menor
               (primero (car intensidades-ordenadas))
               ;de intensidad mayor: intensidad . sitio
               (iguales-a-primero
                ;otras que pueden tener igual intensidad; lista de pares: intensidad . sitio
                (filter-map
                 (lambda (uno)
                   (if (= (car uno) (car primero))
                       uno
                       #f)
                   )
                 (rest intensidades-ordenadas)) )
               (to-orden
                (lambda (sitio)
                  (map
                   (lambda (lugar)
                     (if (= lugar sitio)
                         1/2;sitio
                         '_
                         )
                     )
                   '(0 1 2 3 4))) )
               )
          (cond
            ((null? iguales-a-primero)
             (to-orden (cdr primero)) )
            (else
             (let* ((feromonas (cons primero iguales-a-primero))
                    (azar (random (add1 (length iguales-a-primero))))
                    (elegido (list-ref feromonas azar))
                    )
;               (printf "Feromonas: ~a Elegido: ~a ~n" feromonas elegido)
;               (read-char)
             (to-orden
              (cdr elegido))
             )
             )
            )
          )
        ))
    (define hay-feromona?
      (lambda (discr_olfato)
        (if (member 1/2 discr_olfato)
            #t
            #f)
        ))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    (define hormiga-enfrente?
      (lambda (discr_tacto)
        (= (list-ref discr_tacto 2) 2)
        ))
    (define ceder-sitio
      (lambda (discr_tacto)
        (cond
          ((= (list-ref discr_tacto 1) 0) '(_ 0 2 _ _))
          ((= (list-ref discr_tacto 3) 0) '(_ _ 2 0 _))
          ((= (list-ref discr_tacto 0) 0) '(0 _ 2 _ _))
          ((= (list-ref discr_tacto 4) 0) '(_ _ 2 _ 0))
          (else '(-1 -1 -1 -1 -1))
          )
        ))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    (define hay-comida?
      (lambda (discr_tacto)
        (if (member 1 discr_tacto)
            #t
            #f)
        ))
    (define recoger-comida
      (lambda (discr_tacto)
        (let* ((comidas
                (filter-map
                 (lambda (index)
                   (if (= (list-ref discr_tacto index) 1)
                       index
                       #f)
                   )
                 '(0 1 2 3 4)) )
               (azar (if (= (length comidas) 1) 0 (random (length comidas))))
               (locus (list-ref comidas azar))
               (to-orden
                (lambda (sitio)
                  (map
                   (lambda (lugar)
                     (if (= lugar sitio)
                         1
                         '_
                         )
                     )
                   '(0 1 2 3 4))) )
               )
          (to-orden locus)
          )
        ))
;;;;NAVEGACIÓN DE REGRESO    
    (define avanzar-por-ruta-mas-corta
      (lambda (lista-vec_coord discr_tacto)
        (let* ((blancos
                (filter-map
                 (lambda (index)
                   (if (= (list-ref discr_tacto index) 0)
                       index
                       #f)
                   )
                 '(0 1 2 3 4)) )
               (distancia
                (lambda (home coord)
                  (+ 
                   (expt (- (car home) (car coord)) 2) 
                   (expt (- (cdr home) (cdr coord)) 2))
                  ))
               (vec-menor-distancia
                (let ((vec (cons (first blancos) (distancia (cons 44 40) (list-ref lista-vec_coord (first blancos))))) )
                  (for-each
                   (lambda (blanco)
                     (if (< (distancia (cons 44 40) (list-ref lista-vec_coord blanco)) (cdr vec))
                         (set! vec (cons blanco (distancia (cons 44 40) (list-ref lista-vec_coord blanco))))
                         #t)
                     )
                   (rest blancos))
                  (car vec)
                  )
                )
               (to-orden
                (lambda (sitio)
                  (map
                   (lambda (lugar)
                     (if (= lugar sitio)
                         0;sitio
                         '_
                         )
                     )
                   '(0 1 2 3 4))) )
               )
          (to-orden vec-menor-distancia)
          )
        ))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;    
    (define buscando
      (lambda (discr_tacto discr_olfato lista-olores)
        (let ((Ant (hormiga-enfrente? discr_tacto))
              (Comida (hay-comida? discr_tacto))
              (Feromona (hay-feromona? discr_olfato))
              (Blanco (hay-blanco? discr_tacto))
              )
          (cond
            (sig_accion
             (if (eq? sig_accion orientacion)
                 (begin
                   (set! sig_accion #f)
                   (values #f
                     '(-2 -2 -2 -2 -2) )
                   )
                 (values #f
                     '(-1 -1 -1 -1 -1) )
                 )
             )
            (Ant
             (set! sig_accion orientacion)
             (values #f
                     (ceder-sitio discr_tacto) );cambiar de lugar para ceder el sitio
             )
            (Comida
             (values #f
                     (recoger-comida discr_tacto) )
             )
            (Feromona
             (let* ((feromonas_set (feromonas-en discr_olfato '(0 1 2 3 4)))
                    (lista-intensidades
                     (map
                      (lambda (fero)
                        (exact->inexact (send (list-ref lista-olores fero) get-intensidad))
                        )
                      feromonas_set))
                    )
               (values lista-intensidades
                       (rastro-a-seguir 
                        feromonas_set
                        lista-olores) )
               )
             )
            (Blanco
             (values #f
                     (avanzar-al-blanco discr_tacto) )
             )
            (else
             (values #f
                     '(-1 -1 -1 -1 -1) )
             )
            )
          )
        ))

    (define regresando
      (lambda (discr_tacto discr_olfato lista-olores lista-vec_coord)
        (let ((Ant (hormiga-enfrente? discr_tacto))
              (Feromona (hay-feromona? discr_olfato))
              (Blanco (hay-blanco? discr_tacto))
              )
          (cond
            (Ant
             (values #f
                     '(-2 -2 -2 -2 -2) );pararse
             )
            (Feromona
             (let* ((feromonas_set (feromonas-en discr_olfato '(0 1 2 3 4)))
                    (lista-intensidades
                     (map
                      (lambda (fero)
                        (exact->inexact (send (list-ref lista-olores fero) get-intensidad))
                        )
                      feromonas_set))
                    )
               (values lista-intensidades
                       (rastro-a-seguir 
                        feromonas_set 
                        lista-olores) )
               )
             )
            (Blanco
             (values #f
                     (avanzar-por-ruta-mas-corta lista-vec_coord discr_tacto) );calcular ruta más corta
              )
            (else
             (values #f
                     '(-1 -1 -1 -1 -1) )
             )
            )
          )
        ))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    (super-new)
    ))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define C1 (make-object control% cortex_tacto cortex_olfato discriminacion_olfativa discriminacion_tactil))
(define C2 (make-object control% cortex_tacto cortex_olfato discriminacion_olfativa discriminacion_tactil))
(define C3 (make-object control% cortex_tacto cortex_olfato discriminacion_olfativa discriminacion_tactil))
(define C4 (make-object control% cortex_tacto cortex_olfato discriminacion_olfativa discriminacion_tactil))
(define C5 (make-object control% cortex_tacto cortex_olfato discriminacion_olfativa discriminacion_tactil))
(define C6 (make-object control% cortex_tacto cortex_olfato discriminacion_olfativa discriminacion_tactil))
(define C7 (make-object control% cortex_tacto cortex_olfato discriminacion_olfativa discriminacion_tactil))
(define C8 (make-object control% cortex_tacto cortex_olfato discriminacion_olfativa discriminacion_tactil))
(define C9 (make-object control% cortex_tacto cortex_olfato discriminacion_olfativa discriminacion_tactil))
(define C10 (make-object control% cortex_tacto cortex_olfato discriminacion_olfativa discriminacion_tactil))
(define C11 (make-object control% cortex_tacto cortex_olfato discriminacion_olfativa discriminacion_tactil))
(define C12 (make-object control% cortex_tacto cortex_olfato discriminacion_olfativa discriminacion_tactil))
(define C13 (make-object control% cortex_tacto cortex_olfato discriminacion_olfativa discriminacion_tactil))
(define C14 (make-object control% cortex_tacto cortex_olfato discriminacion_olfativa discriminacion_tactil))
(define C15 (make-object control% cortex_tacto cortex_olfato discriminacion_olfativa discriminacion_tactil))
(define C16 (make-object control% cortex_tacto cortex_olfato discriminacion_olfativa discriminacion_tactil))
(define C17 (make-object control% cortex_tacto cortex_olfato discriminacion_olfativa discriminacion_tactil))
(define C18 (make-object control% cortex_tacto cortex_olfato discriminacion_olfativa discriminacion_tactil))
(define C19 (make-object control% cortex_tacto cortex_olfato discriminacion_olfativa discriminacion_tactil))
(define C20 (make-object control% cortex_tacto cortex_olfato discriminacion_olfativa discriminacion_tactil))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(provide C1 C2 C3 C4 C5 C6 C7 C8 C9 C10 C11 C12 C13 C14 C15 C16 C17 C18 C19 C20) 
;;;;;;;;;;;;;;;;;;;
