You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
57 lines
2.0 KiB
Racket
57 lines
2.0 KiB
Racket
#lang typed/racket
|
|
(require typed/rackunit trivial/regexp/no-colon)
|
|
(provide (all-defined-out))
|
|
|
|
(: increment-password (-> String String))
|
|
(define (increment-password password)
|
|
(: increment-letter (-> String String))
|
|
(define (increment-letter c)
|
|
(~a (integer->char (add1 (char->integer (car (string->list c)))))))
|
|
;bg;((compose1 ~a integer->char add1 char->integer car string->list) c)
|
|
(match-define (list _ prefix letter-to-increment trailing-zs)
|
|
(regexp-match #rx"^(.*?)(.)(z*)$" password))
|
|
(string-append* (list prefix (increment-letter letter-to-increment)
|
|
(regexp-replace* #rx"z" trailing-zs "a"))))
|
|
|
|
(: three-consecutive-letters? (-> String Boolean))
|
|
(define (three-consecutive-letters? str)
|
|
(define ints (map char->integer (string->list str)))
|
|
(let loop : Boolean ([differences (map - (cdr ints) (drop-right ints 1))])
|
|
(if (empty? differences)
|
|
#f
|
|
(or (list-prefix? '(1 1) differences) (loop (cdr differences))))))
|
|
|
|
(: no-iol? (-> String Boolean))
|
|
(define (no-iol? str)
|
|
(not (regexp-match #rx"[iol]" str)))
|
|
(: two-nonoverlapping-doubles? (-> String Boolean))
|
|
(define (two-nonoverlapping-doubles? str)
|
|
(regexp-match? #px"(\\w)\\1.*?(\\w)\\2" str)) ;;bg: add ?
|
|
|
|
(: valid? (-> String Boolean))
|
|
(define (valid? password)
|
|
(and (three-consecutive-letters? password)
|
|
(no-iol? password)
|
|
(two-nonoverlapping-doubles? password)))
|
|
(: find-next-valid-password (-> String String))
|
|
(define (find-next-valid-password starting-password)
|
|
(define candidate-pw (increment-password starting-password))
|
|
(if (valid? candidate-pw)
|
|
candidate-pw
|
|
(find-next-valid-password candidate-pw)))
|
|
|
|
(: q1 (-> String String))
|
|
(define (q1 input-key)
|
|
(find-next-valid-password input-key))
|
|
|
|
(: q2 (-> String String))
|
|
(define (q2 input-key)
|
|
(find-next-valid-password (q1 input-key)))
|
|
|
|
(module+ test
|
|
(define input-key (file->string "../day11-input.txt"))
|
|
(check-equal? (q1 input-key) "hxbxxyzz")
|
|
(check-equal? (q2 input-key) "hxcaabcc"))
|
|
|
|
|