;; ;; nimrod-solns.scm - 6.090 IAP '05 project solutions (hw6) ;; (load-option 'format) (define (make-piles a b) (if (< a b) (list a b) (list b a))) (define (pile-a piles) (first piles)) (define (pile-b piles) (second piles)) (define (random-piles min max) (make-piles (+ (random (- max min)) min) (+ (random (- max min)) min))) (define (empty-piles? piles) (and (= (pile-a piles) 0) (= (pile-b piles) 0))) (define (valid-piles? piles) (and (>= (pile-a piles) 0) (>= (pile-b piles) 0))) (define (display-piles piles) (format #t "~%Pile A: ~A Pile B: ~A~%" (pile-a piles) (pile-b piles))) (define (make-move amta amtb) (list amta amtb)) (define (move-amta move) (first move)) (define (move-amtb move) (second move)) (define (valid-move? move) (and (or (= (move-amta move) (move-amtb move)) (= (move-amta move) 0) (= (move-amtb move) 0)) (>= (move-amta move) 0) (>= (move-amtb move) 0) (not (and (= (move-amta move) 0) (= (move-amtb move) 0))))) (define (apply-move piles move) (make-piles (- (pile-a piles) (move-amta move)) (- (pile-b piles) (move-amtb move)))) (define (play-nimrod name1 strat1 name2 strat2 piles) (display-piles piles) (if (empty-piles? piles) (format #t "~A wins! ~A loses!~%" name2 name1) (let ((move (strat1 name1 piles))) (format #t "~A takes ~A from pile A and ~A from pile B~%" name1 (move-amta move) (move-amtb move)) (if (and (valid-move? move) (valid-piles? (apply-move piles move))) (play-nimrod name2 strat2 name1 strat1 (apply-move piles move)) (begin (format #t "Bad move ~A, try again:~%" name1) (play-nimrod name1 strat1 name2 strat2 piles)))))) (define (safe-play-nimrod name1 strat1 name2 strat2 piles errors) (display-piles piles) (if (= errors 0) (format #t "Error tolerance exceeded; terminating!~%") (if (empty-piles? piles) (format #t "~A wins! ~A loses!~%" name2 name1) (let ((move (strat1 name1 piles))) (format #t "~A takes ~A from pile A and ~A from pile B~%" name1 (move-amta move) (move-amtb move)) (if (and (valid-move? move) (valid-piles? (apply-move piles move))) (safe-play-nimrod name2 strat2 name1 strat1 (apply-move piles move) errors) (begin (format #t "Bad move ~A, try again:~%" name1) (safe-play-nimrod name1 strat1 name2 strat2 piles (- errors 1)))))))) (define (human-strat name piles) (format #t "~A how many to take from A: " name) (let ((a (read))) (format #t "~A how many to take from B: " name) (make-move a (read)))) (define (simple-strat name piles) (make-move 0 1)) (define (list-of-ints start end) (if (= start end) (list start) (cons start (list-of-ints (+ start 1) end)))) (define (without-n lst n) (if (null? lst) nil (if (= (car lst) n) (cdr lst) (cons (car lst) (without-n (cdr lst) n))))) (without-n (list-of-ints 1 100) 7) (define (make-lose-positions n) (lose-position-helper (list-of-ints 0 n) 0)) (define (lose-position-helper ints i) (if (null? ints) nil (cons (make-piles (car ints) (+ (car ints) i)) (lose-position-helper (without-n (cdr ints) (+ (car ints) i)) (+ i 1))))) (make-lose-positions 15) (define lose-positions (make-lose-positions 100)) (define (move-to piles objective-piles) (let ((move (make-move (- (pile-a piles) (pile-a objective-piles)) (- (pile-b piles) (pile-b objective-piles))))) (if (valid-move? move) move (let ((move (make-move (- (pile-a piles) (pile-b objective-piles)) (- (pile-b piles) (pile-a objective-piles))))) (if (valid-move? move) move #f))))) (define (optimal-helper positions piles) (if (null? positions) (make-move 0 1) (let ((move (move-to piles (car positions)))) (if move move (optimal-helper (cdr positions) piles))))) (define optimal-strat (lambda (name piles) (optimal-helper lose-positions piles)))