;; -*- Mode: Irken -*- (include "lib/basis.scm") (include "lib/map.scm") (include "lib/codecs/hex.scm") (define (xor-char ch n) (int->char (logxor n (char->int ch)))) (define (xor-onebyte s key) (let ((slen (string-length s)) (r (copy-string s slen))) (for-range i slen (string-set! r i (xor-char (string-ref s i) key))) r)) ;; https://en.wikipedia.org/wiki/Letter_frequency#Relative_frequencies_of_letters_in_the_English_language ;; the percentages are encoded as integers. A-Z. e.g. A == 8.167%, E = 12.702%. (define letter-scores #(8167 1492 2782 4253 12702 2228 2015 6094 6966 0153 0772 4025 2406 6749 7507 1929 0095 5987 6327 9056 2758 0978 2360 0150 1974 0074)) ;; make an int[256] vector of scores, filling in A-Za-z. (define char-scores (let ((v (make-vector 256 0))) (for-range i 256 (cond ((and (>= i 65) (< i (+ 65 26))) ;; uppercase letter (set! v[i] letter-scores[(- i 65)])) ((and (>= i 97) (< i (+ 97 26))) (set! v[i] letter-scores[(- i 97)])) ((> i 127) ;; bias against 8-bit chars (set! v[i] -1000)) )) ;; these values I just made up. (set! v[32] 2000) ;; space (set! v[46] 1000) ;; period v)) ;; score a string (define (get-score s) (let ((r 0)) (for-string ch s (inc! r char-scores[(char->int ch)])) r)) (define (get-scores ct) (let ((scores (tree/empty)) (results '())) (for-range i 256 (let ((pt (xor-onebyte ct i)) (score (get-score pt))) ;;(printf "i: " (int i) " score: " (int score) " pt: " (string pt) "\n") (tree/insert! scores int-cmp score (:tuple i pt)))) scores)) (define (get-top5 m) (slice (generator->list (tree/make-reverse-generator m)) 0 5)) (define (print-top top) (for-list item top (match item with (:tuple score (:tuple key pt)) -> (printf (lpad 2 (hex key)) " " (lpad 8 (int score)) " " (string pt) "\n") ))) (let ((f (file/open-read "01_04.txt")) (lines (map hex->string (file/read-lines f)))) (printf (int (length lines)) " lines.\n") (let ((line-scores (tree/empty)) (results '())) (for-list line lines (let ((top5 (get-top5 (get-scores line))) (score-sum 0)) (for-list item top5 (match item with (:tuple score (:tuple key pt)) -> (inc! score-sum score))) (tree/insert! line-scores int-cmp score-sum line) )) (match (tree/max line-scores) with (:tuple score line) -> (begin (printf "maximum score: " (int score) " on line " (string->hex line) "\n") (printf "top 5 decodes:\n") (print-top (get-top5 (get-scores line))) )) ))