(import (srfi :43)) ; vector extensions ; get list of lines from a file (define (get-lines file) (let loop [(lines '())] (if (eof-object? (peek-char file)) lines (loop (cons (get-line file) lines))))) ; reads a numnber from input ; also consumes the next non-number character in the file! (define (get-number file) (let [(sign 1)] (let loop [(index 0) (n 0)] (let [(c (get-char file))] (cond [(char-numeric? c) (loop (+ index 1) (+ (char->number c) (* n 10)))] [(and (char=? c #\-) (= index 0)) (set! sign -1) (loop 1 n)] [else (* sign n)]))))) ; returns a list of numbers parsed from the first line of the file, ; separated by commas (define (read-comma-separated-numbers file) (let loop [(draws '()) (n 0)] (let [(c (get-char file))] (cond [(char=? c #\,) (loop (cons n draws) 0)] [(char-whitespace? c) (reverse (cons n draws))] [else (loop draws (+ (* n 10) (char->number c)))])))) ; returns numbers 0 to 9 from ascii character (define (char->number c) (- (char->integer c) 48)) ; 48 is ASCII's number zero (define-record-type matrix (fields width height data)) ; builds a matrix record from the given 2D vector ; vectors inside data vector are expected to all be the same length (define (matrix-from-data data) (make-matrix (vector-length (vector-ref data 0)) (vector-length data) data)) ; returns a matrix object of given dimensions full of zeroes (define (filled-matrix width height filler) (matrix-from-data (do [(i 0 (+ i 1)) (v '() (cons (make-vector width filler) v))] ((>= i height) (list->vector v)) '()))) ; returns value at x,y coordinates in matrix ; if coordinate is out of bounds, returns default (define (matrix-get matrix x y default) (if (or (< x 0) (< y 0) (>= x (matrix-width matrix)) (>= y (matrix-height matrix))) default (vector-ref (vector-ref (matrix-data matrix) y) x))) ; set value at x,y in matrix with given one ; if coordinate is out of bounds, nothing happens (define (matrix-set! matrix x y value) (when (and (>= x 0) (>= y 0) (< x (matrix-width matrix)) (< y (matrix-height matrix))) (vector-set! (vector-ref (matrix-data matrix) y) x value))) ; print matrix line by line to console ; each line will be displayed as a scheme-vector (define (matrix-print matrix) (let y-loop [(y 0)] (printf "~a~%" (vector-ref (matrix-data matrix) y)) (when (< y (- (matrix-height matrix) 1)) (y-loop (+ y 1))))) ; parse 0-9 numerical data from file and return a matrix (define (load-matrix file) (let y-loop [(heightmap '())] (let x-loop [(line '())] (let [(c (get-char file))] (cond [(eof-object? c) (matrix-from-data (reverse-list->vector heightmap))] [(char-whitespace? c) (y-loop (cons (reverse-list->vector line) heightmap))] [(char-numeric? c) (x-loop (cons (char->number c) line))]))))) ; matrix visitor ; calls function with all coordinates of matrix and value at corresponding point ; value returned by function is set at the visiting coordinate (define (update-matrix! matrix function) (let [(data (matrix-data matrix)) (width-1 (- (matrix-width matrix) 1)) (height-1 (- (matrix-height matrix) 1))] (let y-loop [(y 0)] (let x-loop [(x 0)] (let [(value (vector-ref (vector-ref data y) x))] (vector-set! (vector-ref data y) x (function x y value)) (when (< x width-1) (x-loop (+ x 1))))) (when (< y height-1) (y-loop (+ y 1)))))) ; increase by 1 value at x,y in given matrix ; return that value too (define (matrix-inc! matrix x y) (let [(v (+ 1 (matrix-get matrix x y 0)))] (matrix-set! matrix x y v) v)) ; sum all values of matrix (define (matrix-sum matrix) (vector-fold (lambda (y sum line) (+ sum (vector-fold (lambda (x sum value) (+ sum value)) 0 line))) 0 (matrix-data matrix)))