#lang br/quicklang
(require "../helper.rkt")
(provide read-syntax (rename-out [#%mb #%module-begin]) ★ ★★)

(define (read-syntax path port)
  (define lines (port->lines port))
  (strip-context #`(module mod "main.rkt"
                     #,@(for/list ([datum (in-port read (open-input-string (car lines)))])
                          datum)
                     #,@(cdr lines))))

(define-macro (#%mb STARS LINE ...)
  #'(#%module-begin
     (time (STARS (list LINE ...)))))

(define (infect lines bursts #:weak-mode [weak-mode? #f])
  (define chars (make-hasheqv))
  (define origin-adjust (/ (sub1 (string-length (car lines))) 2))
  (for* ([(line lidx) (in-indexed lines)]
         [(c cidx) (in-indexed (string->list line))])
    (define key (+ (- lidx origin-adjust) (* +i (- cidx origin-adjust))))
    (hash-set! chars key c))
  
  (define turn-left +i) (define turn-right -i)
  
  (define-macro (define-state ID CHAR)
    (with-pattern ([ID? (suffix-id #'ID "?")]
                   [SET-ID (prefix-id "set-" #'ID)])
      #'(begin (define ID CHAR)
               (define (SET-ID x) (hash-set! chars x ID))
               (define (ID? x) (eqv? (hash-ref! chars x #\.) ID)))))
  (define-state clean #\.)
  (define-state infected #\#)
  (define-state weakened #\W)
  (define-state flagged #\F)
  
  (for/fold ([here 0]
             [dir -1]
             [infections 0]
             #:result infections)
            ([burst (in-range bursts)])
    (match here
      [(? infected?)
       (define next-dir (* dir turn-right))
       ((if weak-mode? set-flagged set-clean) here)
       (values (+ here next-dir) next-dir infections)]
      [(? clean?)
       (define next-dir (* dir turn-left))
       ((if weak-mode? set-weakened set-infected) here)
       (values (+ here next-dir) next-dir ((if weak-mode? values add1) infections))]
      [(? weakened?)
       (define next-dir dir)
       (set-infected here)
       (values (+ here next-dir) next-dir (add1 infections))]
      [(? flagged?)
       (define next-dir (- dir))
       (set-clean here)
       (values (+ here next-dir) next-dir infections)])))

(define (★ lines) (infect lines 10000))

(define (★★ lines) (infect lines 10000000 #:weak-mode #t))
                                   

#lang br/quicklang
(require "../helper.rkt")
(provide read-syntax (rename-out [#%mb #%module-begin]) ★ ★★)

(define (read-syntax path port)
  (define lines (port->lines port))
  (strip-context #`(module mod "main.rkt"
                     #,@(for/list ([datum (in-port read (open-input-string (car lines)))])
                          datum)
                     #,@(cdr lines))))

(define-macro (#%mb STARS LINE ...)
  #'(#%module-begin
     (time (STARS (list LINE ...)))))

(define (infect lines bursts #:weak-mode [weak-mode? #f])
  (define chars (make-hasheqv))
  (define origin-adjust (/ (sub1 (string-length (car lines))) 2))
  (for* ([(line lidx) (in-indexed lines)]
         [(c cidx) (in-indexed (string->list line))])
    (define key (+ (- lidx origin-adjust) (* +i (- cidx origin-adjust))))
    (hash-set! chars key c))
  
  (define turn-left +i) (define turn-right -i)
  
  (define-macro (define-state ID CHAR)
    (with-pattern ([ID? (suffix-id #'ID "?")]
                   [SET-ID (prefix-id "set-" #'ID)])
      #'(begin (define ID CHAR)
               (define (SET-ID x) (hash-set! chars x ID))
               (define (ID? x) (eqv? (hash-ref! chars x #\.) ID)))))
  (define-state clean #\.)
  (define-state infected #\#)
  (define-state weakened #\W)
  (define-state flagged #\F)
  
  (for/fold ([here 0]
             [dir -1]
             [infections 0]
             #:result infections)
            ([burst (in-range bursts)])
    (match here
      [(? infected?)
       (define next-dir (* dir turn-right))
       ((if weak-mode? set-flagged set-clean) here)
       (values (+ here next-dir) next-dir infections)]
      [(? clean?)
       (define next-dir (* dir turn-left))
       ((if weak-mode? set-weakened set-infected) here)
       (values (+ here next-dir) next-dir ((if weak-mode? values add1) infections))]
      [(? weakened?)
       (define next-dir dir)
       (set-infected here)
       (values (+ here next-dir) next-dir (add1 infections))]
      [(? flagged?)
       (define next-dir (- dir))
       (set-clean here)
       (values (+ here next-dir) next-dir infections)])))

(define (★ lines) (infect lines 10000))

(define (★★ lines) (infect lines 10000000 #:weak-mode #t))
                                   
