#lang racket/gui

;;;EN ESTA VERSIÓN CADA RED/TABLA TIENE UNA CONFIGURACIÓN INICIAL DISTINTA

;;;Matrices
(require "Matrices.rkt")

;;;Vecindad
;; Ver fichero: Reglas-vecindad.rkt
(define filas 0); 0 to 4
(define columnas 199); 0 to 5
(define radio 1)

(printf "Número de autómatas 250 (probar 100)? ")
(set! columnas (sub1 (read)))
(printf "Representación circular del autómata con radio 3 (probar 10)? ")
(set! radio (read))

(require "Reglas-vecindad.rkt")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;Automatas
(define automata-celular%
  (class object%
    (field
     (estado 0)
     (tabla 'una-tabla)
     )
    (define/public set-tabla
      (lambda (table)
        (set! tabla table) ))
    (define/public get-tabla
      (lambda ()
        tabla ))
    (define/public set-estado
      (lambda (valor)
        (set! estado valor) ))
    (define/public get-estado
      (lambda ()
        estado ))
    (define/public procesar!
      (lambda entrada
        (letrec
            ((aux 
              (lambda (inputs table)
                (let* ((fila-tabla (car table))
                       (estado+inputs (append inputs (list estado)))
                       (fila-info (car fila-tabla))
                       )
                  (if
                   (equal? estado+inputs fila-info)
                   (last fila-tabla)
                   (aux inputs (cdr table))))))
             )
          (set! estado (aux entrada tabla))
          estado
          ) ))
    (super-new) ))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;Todas las tablas posibles (256)
(require "Tablas-de-CA.rkt")

(define combinaciones (generador-combinaciones 0 255))

(define todas_tablas 
  (todos_automatas combinaciones tabla-ini))

(define numero-orden-de-la-tabla (random 256))

(define la-tabla (list-ref todas_tablas numero-orden-de-la-tabla))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;La red
(define red-celular%
  (class object%
    (init-field
     (ff 0)
     (cc 0)
     )
    (define haz-automata
      (lambda ()
        (let ((cell (make-object automata-celular%)))
          (send cell set-estado (random 2))
          (send cell set-tabla la-tabla)
          cell
          )
        ))
    (define set-matriz-automatas
      (lambda (matriz)
        (let rows ((i 0)
                    (j ff))
          (if (= i j)
              matriz
              (let columnas ((m 0)
                             (n cc))
                (if (= m n)
                    (rows (add1 i) j)
                    (begin
                      (matriz-set! matriz i m (haz-automata))
                      (columnas (add1 m) n))
                    )
                )
              )
          )
        ))
    (define es-configuracion
      (lambda ()
        (let go ((i 0)
                 (j ff)
                 (salida '())
                 )
          (if (= i j)
              (reverse salida)
              (let columnas ((m 0)
                             (n cc)
                             (output '())
                             )
                (if (= m n)
                    (go (add1 i) j (append salida (list output)))
                    (columnas (add1 m) n
                              (append
                               output
                               (list (send 
                                      (matriz-ref matriz-automatas i m vector-ref)
                                      get-estado))
                               )
                              )
                    )
                )
              )
          )
        ))
    (field
     (matriz-automatas
      (set-matriz-automatas
       (make-matriz ff cc)) )
     (configuracion (es-configuracion))
     )    
    (define/public get-matriz
      (lambda ()
        matriz-automatas ))
    (define/public get-configuracion
      (lambda ()
        configuracion ))
    (define/public procesar!
      (lambda ()
        (let rows
          ((i 0)
           (j ff)
           )
          (if (= i j)
              (set! configuracion (es-configuracion))
              (let columns
                ((m 0)
                 (n cc)
                 )
                (if (= m n)
                    (rows (add1 i) j)
                    (let*-values
                        ([(vec-1 vec-2) (regla-1 m columnas)]
                         [(estado-v1)
                          (matriz-ref 
                           configuracion (car vec-1) (cdr vec-1) list-ref)]
                         [(estado-v2)
                          (matriz-ref 
                           configuracion (car vec-2) (cdr vec-2) list-ref)]
                         )
                      (send 
                       (matriz-ref matriz-automatas i m vector-ref) 
                       procesar! estado-v1 estado-v2)
                      (columns (add1 m) n)
                      )
                    )
                )
              )
          )
        ))
    (super-new)
    ))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define red (make-object red-celular% (add1 filas) (add1 columnas)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; LAS FUNCIONES DE DIBUJO
;;; LAS HERRAMIENTAS GRÁFICAS
(define lapiz-0
  (make-object pen%
    "white"
    radio
    'solid))
(define lapiz-1
  (make-object pen%
    "red"; black
    radio
    'solid))
;;; La ventana
(define num-aut (* (add1 filas) (add1 columnas))) 
(define titulo
  (string-append 
   "Monitor de una red de "
   (number->string num-aut)
   " autómatas") )
(define ventana
  (make-object frame% 
    titulo 
    #f 
    (+ 10 (* radio (add1 columnas))) 1200
    1200 0))
;;; El lienzo
(define lienzo
  (instantiate canvas%
    (ventana)
    (style '(border))
    ))
(define dc (send lienzo get-dc))
;;; PROCEDIMIENTOS DE DIBUJO
(define pinta-una-fila
  (lambda (output x y hoffset)
    (cond
      ((null? output) )
      ((= (car output) 1)
       (send dc set-pen lapiz-1)
       (send dc draw-point x y)
       (pinta-una-fila (cdr output) (+ x hoffset) y hoffset))
      (else
       (send dc set-pen lapiz-0)
       (send dc draw-point x y)
       (pinta-una-fila (cdr output) (+ x hoffset) y hoffset))
      ) ))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define ejecuta
  (lambda (dc)
    (define text
      (string-append 
       "Tabla " 
       (number->string numero-orden-de-la-tabla)
       ": "
       (combinacion->string 
        (list-ref combinaciones numero-orden-de-la-tabla))
       ))
    (send dc clear)
    (sleep/yield 1)
    (pinta-una-fila
     (car (send red get-configuracion))
     4 0 radio)
    (send dc draw-text text 100 10)
    (sleep/yield 0.5)
    (do
        ((voffset 30)
         (i 1 (add1 i))
         )
      ((>= voffset (- 1200 30 40))
       (set! text (string-append "Iteraciones: " (number->string i)))
       (send dc draw-text text 100 (+ voffset 1)))
      (send red procesar!)
      (pinta-una-fila
       (car (send red get-configuracion))
       4 voffset radio)
      (set! voffset (+ voffset radio))
      )
    ))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define driver
  (lambda (dc)
    (let go ((i 20)
             (j 256))
      (if (= i j)
          #t
          (begin
            (set! numero-orden-de-la-tabla i)
            (set! la-tabla 
                  (list-ref todas_tablas numero-orden-de-la-tabla))
            (set! red 
                  (make-object red-celular% (add1 filas) (add1 columnas)))
            (ejecuta dc)
            ;(read-char)
            (sleep/yield 3)
            (go (add1 i) j)
            )
          )
      )
    ))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(send ventana show #t)
(sleep/yield 1)

(driver dc)
