(define make-type (lambda (name) name)) (define typed-value-packer (lambda (type) (lambda (value) (cons type value)))) (define typed-value-unpacker (lambda (type) (lambda (value) (if (equal? type (car value)) (cdr value) (error "type mismatch"))))) (define move-type (make-type 'move)) (define move-packer (typed-value-packer move-type)) (define move-unpacker (typed-value-unpacker move-type)) (define game-state-type (make-type 'game-state)) (define game-state-packer (typed-value-packer game-state-type)) (define game-state-unpacker (typed-value-unpacker game-state-type)) (define play-nim (lambda (game-state player) (display-game-state game-state) (if (game-over? game-state) (announce-winner game-state player) (let ((move (next-move game-state player))) (announce-move player move) (play-nim (apply-move move game-state) (other-player player)))))) (define make-game-state (lambda (pile-1 pile-2) (game-state-packer (cons pile-1 pile-2)))) (define size-of-pile (lambda (game-state pile-number) (if (= pile-number 1) (car (game-state-unpacker game-state)) (cdr (game-state-unpacker game-state))))) (define make-move (lambda (pile n-coins) (move-packer (cons pile n-coins)))) (define move-pile (lambda (move) (car (move-unpacker move)))) (define move-n-coins (lambda (move) (cdr (move-unpacker move)))) (define next-move (lambda (game-state player) (if (equal? player 'human) (human-move game-state) (computer-move game-state)))) (define other-player (lambda (player) (if (equal? player 'human) 'computer 'human))) (define computer-move (lambda (game-state) (if (> (size-of-pile game-state 1) 0) (make-move 1 1) (make-move 2 1)))) (define prompt (lambda (prompt-string) (display prompt-string) (newline) (read))) (define human-move (lambda (game-state) (let ((pile (prompt "Which pile will you remove from?"))) (let ((n-coins (prompt "How many coins do you want to remove?"))) (make-move pile n-coins))))) (define game-over? (lambda (game-state) (and (= 0 (size-of-pile game-state 1)) (= 0 (size-of-pile game-state 2))))) (define announce-winner (lambda (game-state player) (let ((winner (other-player player))) (if (equal? winner 'human) (display "You win. Congratulations.") (display "You lose. Better luck next time.")) (newline)))) (define display-game-state (lambda (game-state) (display " Pile 1: ") (display (size-of-pile game-state 1)) (newline) (display " Pile 2: ") (display (size-of-pile game-state 2)) (newline))) (define announce-move (lambda (player move) (if (equal? player 'human) (display "You") (display "I")) (display " take ") (display (move-n-coins move)) (display " coins from pile ") (display (move-pile move)) (display ".") (newline))) (define apply-move (lambda (move game-state) (let ((pile (move-pile move)) (n-coins (move-n-coins move))) (if (= pile 1) (make-game-state (- (size-of-pile game-state 1) n-coins) (size-of-pile game-state 2)) (make-game-state (size-of-pile game-state 1) (- (size-of-pile game-state 2) n-coins))))))