(define-module (gib-gab-gob board) #:use-module (srfi srfi-1) #:export (make-board board-ref board-assert-vacant board-choose! board-display board-winner?)) ;; TODO: This board is no longer time-travel friendly! ;; Have to decide if we go back to the old board with one actor per cell, ;; or make a new version. Board could becom a new board containing the new mark. (define ggg-size 3) ;; tic tac toe with more than 3x3 grid? (define (make-board) (make-array #f ggg-size ggg-size)) (define (board-ref board x y) (array-ref board y x)) (define (board-assert-vacant board x y) (define ref (board-ref board x y)) (if ref (error "That space is already occupied with:" ref) ref)) (define (board-choose! board val x y) (board-assert-vacant board x y) (array-set! board val y x)) (define (board-display board) (array-slice-for-each-in-order 1 (λ (row) (array-for-each (λ (x) (format #t "[~a]" (or x " "))) row) (format #t "\n")) board)) (define (board-winner? board mark) ;; e.g. '(0 1 2) (define idxs (iota ggg-size)) ;; true, if any item in list is non-false (define (any? l) (and (any identity l) #t)) ;; Iterate through iota calling fn and check if all are true (define (iter-all? fn) (apply eq? mark (map fn idxs))) ;; Iterate through the rows and see if any are winners (define (row-winner? b) (any? (map (λ (y) (iter-all? (λ (x) (board-ref b x y)))) idxs))) (or (row-winner? board) (row-winner? (transpose-array board 1 0)) ;; check the two diagonals (iter-all? (λ (x) (board-ref board x x))) (iter-all? (λ (x) (board-ref board x (- ggg-size x 1))))))