;RICHARD SHEK ;0882570 ;COMP 210 ;FINAL PROJECT (BASIC & EXTRA COMPONENTS) ;A move is either (define-struct move (x y win block-win)) ;where x and y are coordinates of where to place the piece, win is either a boolean or a list that contains the 4 numbers representing that square's horizontal, vertical, and the two diagonal winning values, and block-win is again either a boolean or a list of 4 numbers that represent the square's value in blocking an opponent's possible horizontal, vertical, and the two diagonal wins. For win and block-win, boolean values are used in the first, basic part of the program, which is determining the existence of automatic wins or blocks. ;or it is 'NOMOVE ;EXAMPLES ;(define m1 (make-move 2 3 true false)) ;(define m2 (make-move 0 0 (list 80 80 10 4) (list 60 40 0 0))) ;'NOMOVE ;a matrix is a vector of vectors ;EXAMPLES ;(define m (vector (vector 1 2) (vector 2 3))) ;definition for the max number in row needed to win (define WIN_NUM 5) ;definition for the symbol that represents us (define us 'X) ;definition for a symbol for opponent (define them 'O) ;definition for the empty symbol (define EMPTY_SQUARE '-) ;FUNCTION getmax: -> ;PURPOSE: returns the largest number in the list ;EXAMPLES ;(getmax (list 1 2 3)) = 3 ;BODY (define (getmax alist) (local [(define (getmaxhelper alist n) (cond [(empty? alist) n] [(> (first alist) n) (getmaxhelper (rest alist) (first alist))] [else (getmaxhelper (rest alist) n)]))] (getmaxhelper (rest alist) (first alist)))) ;TESTCASE ;(getmax (list 1 2 3)) ;FUNCTION bestwin: -> ;PURPOSE: returns the best winning move ;EXAMPLES ;(bestwin (list (make-move 0 0 (list 14 44 1 1) (list 25 3 1 1)) (make-move 2 3 (list 18 48 48 48) (list 13 1 34 1)))) = (make-move 2 3 (list 18 48 48 48) (list 13 1 34 1)) ;(bestwin (list (make-move 0 0 (list 44 1 1 1) (list 0 0 0 0)) (make-move 3 4 (list 44 1 1 2) (list 0 0 0 0)))) = (make-move 3 4 (list 44 1 1 2) (list 0 0 0 0)) ;(bestwin (list (make-move 0 0 (list 44 1 1 1) (list 0 0 0 0)) (make-move 3 4 (list 44 1 1 1) (list 1 0 0 0)))) = (make-move 3 4 (list 44 1 1 2) (list 0 0 0 0)) ;(bestwin (list (make-move 0 0 (list 44 1 1 1) (list 2 0 0 0)) (make-move 2 2 (list 44 1 1 1) (list 2 1 0 0)))) = (make-move 2 2 (list 44 1 1 1) (list 2 1 0 0)) ;BODY ;(define (bestwin amove) ; (local [(define (bestwinhelper alist m) ; (cond ; [(empty? alist) m] ; [(= (getmax (move-win (first alist))) (getmax (move-win m))) ; (cond ; [(> (getmax (move-block-win (first alist))) (getmax (move-block-win m))) ; (bestwinhelper (rest alist) (first alist))] ; [else (bestwinhelper (rest alist) m)])] ; [(> (getmax (move-win (first alist))) (getmax (move-win m))) (bestwinhelper (rest alist) (first alist))] ; [else (bestwinhelper (rest alist) m)]))] ; (bestwinhelper (rest amove) (first amove)))) (define (bestwin amove) (local [(define (bestwinhelper alist m) (cond [(empty? alist) m] [(= (getmax (move-win (first alist))) (getmax (move-win m))) (cond [(> (foldr + 0 (move-win (first alist))) (foldr + 0 (move-win m))) (bestwinhelper (rest alist) (first alist))] [(= (foldr + 0 (move-win (first alist))) (foldr + 0 (move-win m))) (cond [(> (getmax (move-block-win (first alist))) (getmax (move-block-win m))) (bestwinhelper (rest alist) (first alist))] [(= (getmax (move-block-win (first alist))) (getmax (move-block-win m))) (cond [(> (foldr + 0 (move-block-win (first alist))) (foldr + 0 (move-block-win m))) (bestwinhelper (rest alist) (first alist))] [else (bestwinhelper (rest alist) m)])] [else (bestwinhelper (rest alist) m)])] [else (bestwinhelper (rest alist) m)])] [(> (getmax (move-win (first alist))) (getmax (move-win m))) (bestwinhelper (rest alist) (first alist))] [else (bestwinhelper (rest alist) m)]))] (bestwinhelper (rest amove) (first amove)))) ;TESTCASES ;(bestwin (list (make-move 0 0 (list 14 44 1 1) (list 25 3 1 1)) (make-move 2 3 (list 18 48 48 48) (list 13 1 34 1)))) ;(bestwin (list (make-move 0 0 (list 44 1 1 1) (list 0 0 0 0)) (make-move 3 4 (list 44 1 1 2) (list 0 0 0 0)))) ;(bestwin (list (make-move 0 0 (list 44 1 1 1) (list 0 0 0 0)) (make-move 3 4 (list 44 1 1 1) (list 1 0 0 0)))) ;(bestwin (list (make-move 0 0 (list 44 1 1 1) (list 2 0 0 0)) (make-move 2 2 (list 44 1 1 1) (list 2 1 0 0)))) ;FUNCTION bestblock: -> ;PURPOSE: returns the best blocking move ;EXAMPLES ;(bestblock (list (make-move 0 0 (list 14 44 1 1) (list 25 3 1 1)) (make-move 2 3 (list 18 48 48 48) (list 13 1 34 1)))) = (make-move 2 3 (list 18 48 48 48) (list 13 1 34 1)) ;(bestblock (list (make-move 0 0 (list 0 0 0 0) (list 40 0 0 0)) (make-move 2 3 (list 0 0 0 0) (list 40 2 3 1)))) = (make-move 2 3 (list 0 0 0 0) (list 40 2 3 1)) ;(bestblock (list (make-move 0 0 (list 0 0 0 0) (list 30 2 3 1)) (make-move 2 3 (list 9 0 0 0) (list 30 6 0 0)))) = (make-move 2 3 (list 0 0 0 0) (list 40 2 3 1)) ;(bestblock (list (make-move 2 3 (list 9 0 0 0) (list 30 2 3 1)) (make-move 0 0 (list 9 2 0 0) (list 30 6 0 0)))) = (make-move 0 0 (list 0 0 0 0) (list 40 2 3 1)) ;BODY (define (bestblock amove) (local [(define (bestblockhelper alist m) (cond [(empty? alist) m] [(= (getmax (move-block-win (first alist))) (getmax (move-block-win m))) (cond [(> (foldr + 0 (move-block-win (first alist))) (foldr + 0 (move-block-win m))) (bestblockhelper (rest alist) (first alist))] [(= (foldr + 0 (move-block-win (first alist))) (foldr + 0 (move-block-win m))) (cond [(> (getmax (move-win (first alist))) (getmax (move-win m))) (bestblockhelper (rest alist) (first alist))] [(= (getmax (move-win (first alist))) (getmax (move-win m))) (cond [(> (foldr + 0 (move-win (first alist))) (foldr + 0 (move-win m))) (bestblockhelper (rest alist) (first alist))] [else (bestblockhelper (rest alist) m)])] [else (bestblockhelper (rest alist) m)])] [else (bestblockhelper (rest alist) m)])] [(> (getmax (move-block-win (first alist))) (getmax (move-block-win m))) (bestblockhelper (rest alist) (first alist))] [else (bestblockhelper (rest alist) m)]))] (bestblockhelper (rest amove) (first amove)))) ;TESTCASES ;(bestblock (list (make-move 0 0 (list 14 44 1 1) (list 25 3 1 1)) (make-move 2 3 (list 18 48 48 48) (list 13 1 34 1)))) ;(bestblock (list (make-move 0 0 (list 0 0 0 0) (list 40 0 0 0)) (make-move 2 3 (list 0 0 0 0) (list 40 2 3 1)))) ;(bestblock (list (make-move 0 0 (list 0 0 0 0) (list 30 2 3 1)) (make-move 2 3 (list 9 0 0 0) (list 30 6 0 0)))) ;(bestblock (list (make-move 2 3 (list 9 0 0 0) (list 30 2 3 1)) (make-move 0 0 (list 9 2 0 0) (list 30 6 0 0)))) ;FUNCTION bestoverall: -> ;PURPOSE: returns the best move overall, when there are no winning or blocking moves ;EXAMPLES ;(bestoverall (list (make-move 0 0 (list 14 44 1 1) (list 25 3 1 1)) (make-move 2 3 (list 18 48 48 48) (list 13 1 34 1)))) = (make-move 2 3 (list 18 48 48 48) (list 13 1 34 1)) ;BODY (define (bestoverall amove) (local [(define (bestoverallhelper alist m) (cond [(empty? alist) m] [(> (foldr + 0 (move-win (first alist))) (foldr + 0 (move-win m))) (bestoverallhelper (rest alist) (first alist))] [else (bestoverallhelper (rest alist) m)]))] (bestoverallhelper (rest amove) (first amove)))) ;TESTCASES ;(bestoverall (list (make-move 0 0 (list 14 44 1 1) (list 25 3 1 1)) (make-move 2 3 (list 18 48 48 48) (list 13 1 34 1)))) = (make-move 2 3 (list 18 48 48 48) (list 13 1 34 1)) ;FUNCTION for: alpha (alpha->boolean) (alpha -> alpha) -> (void) ;PURPOSE: The purpose of this function is to provide a looping construct for our functions ;EXAMPLES ;(for 0 (lambda (a) (< a 5)) (lambda (a) (begin (printf "blah") (+ a 1)))) ;prints out "blah" "blah" "blah" "blah" "blah" ;BODY (define (for i condition fuc) (cond [(condition i) (for (fuc i) condition fuc)] [else (void)] )) ;TESTCASES ;(for 0 (lambda (a) (< a 5)) (lambda (a) (begin (printf "blah") (+ a 1)))) ;FUNCTION: matrix num num -> boolean ;PURPOSE: The purpose of this function is to tell if the x y coordinates are valid in the matrix range ;EXAMPLES ;(within? (make-matrix (list (list 1 2) (list 1 2))) 0 0) = true ;(within? (make-matrix (list (list 1 2) (list 1 2))) 220 220) = false ;BODY (define (within? matboard x y) (if (and (>= x 0) (< x (matrix-cols matboard)) (>= y 0) (< y (matrix-rows matboard))) true false)) ;TESTCASES ;(within? (make-matrix (list (list 1 2) (list 1 2))) 0 0) ;(within? (make-matrix (list (list 1 2) (list 1 2))) 220 220) ;FUNCTION: list num -> anything ;PURPOSE: The purpose of this function is to get the nth element of a list ;EXAMPLES ;(list-getNElement (list 1 2 3) 2) = 3 ;BODY (define (list-getNElement l n) (cond [(empty? l) NORESULT] [else (if (= n 0) (first l) (list-getNElement (rest l) (- n 1)))])) ;TESTCASES ;(list-getNElement (list 1 2 3) 2) ;FUNCTION: matrix -> num ;PURPOSE: returns the number of columns in the input matrix ;HEADER: (define (matrix-cols matrix)...) ;EXAMPLES ;(matrix-cols (make-matrix (list (list 2 3) (list 2 1)))) = 2 ;BODY (define (matrix-cols matrix) (vector-length (vector-ref matrix 1))) ;TESTCASES ;(matrix-cols (make-matrix (list (list 2 3) (list 2 1)))) ;FUNCTION: matrix -> num ;PURPOSE: returns the number of rows in the input matrix ;HEADER: (define (matrix-rows matrix)...) ;EXAMPLES ;(matrix-rows (make-matrix (list (list 2 3) (list 2 1)))) = 2 ;BODY (define (matrix-rows matrix) (vector-length matrix)) ;TESTCASES ;(matrix-rows (make-matrix (list (list 2 3) (list 2 1)))) ;FUNCTION: -> ;PURPOSE: takes in a list of lists and change it into a matrix ;EXAMPLES ;(make-matrix (list (list 2 3) (list 4 1))) = (vector (vector 2 3) (vector 4 1)) ;BODY (define (make-matrix lol) (local [ (define xsize (length (first lol))) (define ysize (length lol)) (define matrix (make-vector ysize false)) ] (begin (for 0 (lambda (y) (< y ysize)) (lambda (y) (begin (vector-set! matrix y (list->vector (list-getNElement lol y))) (+ y 1) ))) matrix))) ;TESTCASES ;(make-matrix (list (list 2 3) (list 4 1))) ;FUNCTION: matrix num num -> ANYTHING ;PURPOSE: returns the contents of a matrix square at x, y coordinates ;EXAMPLES ;(matrix-xy (vector (vector 2 3) (vector 4 1)) 1 1) = 1 ;BODY (define (matrix-xy matrix x y) (if (or (< x 0) (< y 0)) 'not_a_vector (vector-ref (vector-ref matrix y) x))) ;TESTCASES ;(matrix-xy (vector (vector 2 3) (vector 4 1)) 1 1) ;FUNCTION: (void) -> (void) ;PURPOSE: starts the game and goes through its processes; side-effect is that it prints out the next move ;EXAMPLES ;(game) *it all depends what board you read in ;BODY (define (game) (local [(define matboard (make-matrix (read))) (define moves (getBoardMoves matboard win_or_lose win_or_lose)) (define selectedmove (decide matboard moves))] (printf "(~s ~s)" (move-x selectedmove) (move-y selectedmove)) )) ;TESTCASES ;(game) ;FUNCTION getBoardMoves: (alpha -> beta) (alpha -> beta) -> list of move ;PURPOSE: This function takes in a matrix and two functions (which determine whether the following analysis will be for determining automatic win/blocks or just to find the best resutl) and returns a list of the possible moves. ;EXAMPLES ;giving a matrix board of ; ;(getBoardMoves (make-matrix ; (list (list '- 'O 'O 'O '-) ; (list 'X 'X 'X 'X 'O) ; (list 'X 'O 'X 'O 'O) ; (list 'X 'X '- 'X 'O) ; (list 'X '- '- '- 'O))) win_or_lose win_or_lose) ;= ;(list ; (make-move 0 0 true false) ; (make-move 4 0 true true) ; (make-move 2 3 false false) ; (make-move 1 4 false false) ; (make-move 2 4 false false) ; (make-move 3 4 false false)) ;(getBoardMoves (make-matrix '((- - - - -) (- - - - -) (- - - - -) (- - - - -) (- - - - -))) checkWin checkBlockWin) ;= ;(list ; (make-move 0 0 (list 74 0 74 74) (list 74 0 74 74)) ; (make-move 1 0 (list 57 20 77 74) (list 57 20 77 74)) ; (make-move 2 0 (list 39 39 78 74) (list 39 39 78 74)) ; (make-move 3 0 (list 20 57 77 74) (list 20 57 77 74)) ; (make-move 4 0 (list 0 74 74 74) (list 0 74 74 74)) ; (make-move 0 1 (list 57 20 74 77) (list 57 20 74 77)) ; (make-move 1 1 (list 77 40 77 77) (list 77 40 77 77)) ; (make-move 2 1 (list 59 59 78 77) (list 59 59 78 77)) ; (make-move 3 1 (list 40 77 77 77) (list 40 77 77 77)) ; (make-move 4 1 (list 20 57 74 77) (list 20 57 74 77)) ; (make-move 0 2 (list 39 39 74 78) (list 39 39 74 78)) ; (make-move 1 2 (list 59 59 77 78) (list 59 59 77 78)) ; (make-move 2 2 (list 78 78 78 78) (list 78 78 78 78)) ; (make-move 3 2 (list 59 59 77 78) (list 59 59 77 78)) ; (make-move 4 2 (list 39 39 74 78) (list 39 39 74 78)) ; (make-move 0 3 (list 20 57 74 77) (list 20 57 74 77)) ; (make-move 1 3 (list 40 77 77 77) (list 40 77 77 77)) ; (make-move 2 3 (list 59 59 78 77) (list 59 59 78 77)) ; (make-move 3 3 (list 77 40 77 77) (list 77 40 77 77)) ; (make-move 4 3 (list 57 20 74 77) (list 57 20 74 77)) ; (make-move 0 4 (list 0 74 74 74) (list 0 74 74 74)) ; (make-move 1 4 (list 20 57 77 74) (list 20 57 77 74)) ; (make-move 2 4 (list 39 39 78 74) (list 39 39 78 74)) ; (make-move 3 4 (list 57 20 77 74) (list 57 20 77 74)) ; (make-move 4 4 (list 74 0 74 74) (list 74 0 74 74))) ;BODY (define (getBoardMoves matboard body1 body2) (local [(define moves empty)] (begin (for 0 (lambda (y) (< y (matrix-rows matboard))) (lambda (y) (begin (for 0 (lambda (x) (< x (matrix-cols matboard))) (lambda (x) (begin (local [(define possiblemove (getMove matboard x y body1 body2))] (if (move? possiblemove) (set! moves (append moves (list possiblemove))) (void))) (+ x 1)))) (+ y 1)) )) moves))) ;TESTCASES ;(getBoardMoves (make-matrix ;(list (list '- 'O 'O 'O '-) ; (list 'X 'X 'X 'X 'O) ; (list 'X 'O 'X 'O 'O) ; (list 'X 'X '- 'X 'O) ; (list 'X '- '- '- 'O))) win_or_lose win_or_lose) ;(getBoardMoves (make-matrix '((- - - - -) (- - - - -) (- - - - -) (- - - - -) (- - - - -))) checkWin checkBlockWin) ;FUNCTION: analyzer: matrix num num symbol symbol -> boolean ;PURPOSE: this function analyzes the continuity of a certain function in various directions, and returns true if the total number of continuous symbols of the type given in equal to one less than that of the number needed to win in one of the directions of left diagonal, right diagonal, horizontal, or vertical ;EXAMPLES: ;(analyzer (make-matrix (list ; (list '- 'O 'O 'O '-) ; (list 'X 'X 'X 'X 'O) ; (list 'X 'O 'X 'O 'O) ; (list 'X 'X '- 'X 'O) ; (list 'X '- '- '- 'O))) 4 0 them us) = (list -10 -10 51 70) ;(analyzer (make-matrix (list ; (list 'O 'O 'O 'O '-) ; (list 'X 'X 'X 'X 'O) ; (list 'X 'O 'X 'O 'X) ; (list 'X 'X '- 'X 'O) ; (list 'X '- '- '- 'O))) 4 0 them us) = (list -10 -10 70 10) ;(analyzer (make-matrix (list ; (list '- 'O 'O 'O '-) ; (list 'X 'X 'X 'X 'O) ; (list 'X 'O 'X 'O 'O) ; (list 'X 'X '- 'X 'O) ; (list 'X '- '- '- 'X))) 0 0 us them) = (list 70 -10 -10 70) ;(analyzer (make-matrix (list ; (list '- 'O 'O 'O '-) ; (list 'X 'X 'X 'X 'O) ; (list 'X 'O 'X 'O 'O) ; (list 'X 'X '- 'X 'O) ; (list 'X '- '- '- 'X))) 2 4 us them) = (list 30 10 30 29) ;BODY (define (analyzer matboard x y symyes symnot) (local [ ;FUNCTION checkHorizontal: (void) -> ;PURPOSE: gives a position's value in a row ;BODY (define (checkHorizontal) (local [(define (numsright i s sinc) (cond [(or (not (within? matboard (+ x i) y)) (symbol=? symnot (matrix-xy matboard (+ x i) y))) (- s 5)] [(and (symbol=? symyes us) (symbol=? EMPTY_SQUARE (matrix-xy matboard (+ i x) y)) (or (< s WIN_NUM) (= s 20))) (numsright (+ i 1) (+ s 1) (- sinc 2))] [(and (symbol=? EMPTY_SQUARE (matrix-xy matboard (+ x i) y)) (>= s 20)) (- s 4)] [(symbol=? symyes (matrix-xy matboard (+ x i) y)) (numsright (+ i 1) (+ sinc s) sinc)] [(symbol=? EMPTY_SQUARE (matrix-xy matboard (+ i x) y)) (numsright (+ i 1) s (- sinc 2))])) (define (numsleft i s sinc) (cond [(or (not (within? matboard (- x i) y)) (symbol=? symnot (matrix-xy matboard (- x i) y))) (- s 5)] [(and (symbol=? symyes us) (symbol=? EMPTY_SQUARE (matrix-xy matboard (- x i) y)) (or (< s WIN_NUM) (= s 20))) (numsleft (+ i 1) (+ s 1) (- sinc 2))] [(and (symbol=? EMPTY_SQUARE (matrix-xy matboard (- x i) y)) (>= s 20)) (- s 4)] [(symbol=? symyes (matrix-xy matboard (- x i) y)) (numsleft (+ i 1) (+ sinc s) sinc)] [(symbol=? EMPTY_SQUARE (matrix-xy matboard (- x i) y)) (numsleft (+ i 1) s (- sinc 2))]))] (+ (numsright 1 0 20) (numsleft 1 0 20)))) ;FUNCTION checkVertical: (void) -> ;PURPOSE: checks a position's value in a column ;BODY (define (checkVertical) (local [(define (numstop i s sinc) (cond [(or (not (within? matboard x (- y i))) (symbol=? symnot (matrix-xy matboard x (- y i)))) (- s 5)] [(and (symbol=? symyes us) (symbol=? EMPTY_SQUARE (matrix-xy matboard x (- y i))) (or (< s WIN_NUM) (= s 20))) (numstop (+ i 1) (+ s 1) (- sinc 2))] [(and (symbol=? EMPTY_SQUARE (matrix-xy matboard x (- y i))) (>= s 20)) (- s 4)] [(symbol=? symyes (matrix-xy matboard x (- y i))) (numstop (+ i 1) (+ sinc s) sinc)] [(symbol=? EMPTY_SQUARE (matrix-xy matboard x (- y i))) (numstop (+ i 1) s (- sinc 2))])) (define (numsdown i s sinc) (cond [(or (not (within? matboard x (+ y i))) (symbol=? symnot (matrix-xy matboard x (+ y i)))) (- s 5)] [(and (symbol=? symyes us) (symbol=? EMPTY_SQUARE (matrix-xy matboard x (+ y i))) (or (< s WIN_NUM) (= s 20))) (numsdown (+ i 1) (+ s 1) (- sinc 2))] [(and (symbol=? EMPTY_SQUARE (matrix-xy matboard x (+ y i))) (>= s 20)) (- s 4)] [(symbol=? symyes (matrix-xy matboard x (+ y i))) (numsdown (+ i 1) (+ sinc s) sinc)] [(symbol=? EMPTY_SQUARE (matrix-xy matboard x (+ y i))) (numsdown (+ i 1) s (- sinc 2))]))] (+ (numstop 1 0 20) (numsdown 1 0 20)))) ;FUNCTION checkDiagonalLeft: (void) -> ;PURPOSE: checks a position's value in a left diagonal ;BODY (define (checkDiagonalLeft) (local [(define (numsright i s sinc) (cond [(or (not (within? matboard (+ x i) (+ y i))) (symbol=? symnot (matrix-xy matboard (+ x i) (+ y i)))) (- s 5)] [(and (symbol=? symyes us) (symbol=? EMPTY_SQUARE (matrix-xy matboard (+ i x) (+ y i))) (or (< s WIN_NUM) (= s 20))) (numsright (+ i 1) (+ s 1) (- sinc 2))] [(and (symbol=? EMPTY_SQUARE (matrix-xy matboard (+ x i) (+ y i))) (>= s 20)) (- s 4)] [(symbol=? symyes (matrix-xy matboard (+ x i) (+ y i))) (numsright (+ i 1) (+ sinc s) sinc)] [(symbol=? EMPTY_SQUARE (matrix-xy matboard (+ i x) (+ y i))) (numsright (+ i 1) s (- sinc 2))])) (define (numsleft i s sinc) (cond [(or (not (within? matboard (- x i) (- y i))) (symbol=? symnot (matrix-xy matboard (- x i) (- y i)))) (- s 5)] [(and (symbol=? symyes us) (symbol=? EMPTY_SQUARE (matrix-xy matboard (- x i) (- y i))) (or (< s WIN_NUM) (= s 20))) (numsleft (+ i 1) (+ s 1) (- sinc 2))] [(and (symbol=? EMPTY_SQUARE (matrix-xy matboard (- x i) (- y i))) (>= s 20)) (- s 4)] [(symbol=? symyes (matrix-xy matboard (- x i) (- y i))) (numsleft (+ i 1) (+ sinc s) sinc)] [(symbol=? EMPTY_SQUARE (matrix-xy matboard (- x i) (- y i))) (numsleft (+ i 1) s (- sinc 2))]))] (+ (numsright 1 0 20) (numsleft 1 0 20)))) ;FUNCTION checkDiagonalRight: (void) -> ;PURPOSE: checks a position's value in a right diagonal ;BODY (define (checkDiagonalRight) (local [(define (numsright i s sinc) (cond [(or (not (within? matboard (+ x i) (- y i))) (symbol=? symnot (matrix-xy matboard (+ x i) (- y i)))) (- s 5)] [(and (symbol=? symyes us) (symbol=? EMPTY_SQUARE (matrix-xy matboard (+ i x) (- y i))) (or (< s WIN_NUM) (= s 20))) (numsright (+ i 1) (+ s 1) (- sinc 2))] [(and (symbol=? EMPTY_SQUARE (matrix-xy matboard (+ x i) (- y i))) (>= s 20)) (- s 4)] [(symbol=? symyes (matrix-xy matboard (+ x i) (- y i))) (numsright (+ i 1) (+ sinc s) sinc)] [(symbol=? EMPTY_SQUARE (matrix-xy matboard (+ i x) (- y i))) (numsright (+ i 1) s (- sinc 2))])) (define (numsleft i s sinc) (cond [(or (not (within? matboard (- x i) (+ y i))) (symbol=? symnot (matrix-xy matboard (- x i) (+ y i)))) (- s 5)] [(and (symbol=? symyes us) (symbol=? EMPTY_SQUARE (matrix-xy matboard (- x i) (+ y i))) (or (< s WIN_NUM) (= s 20))) (numsleft (+ i 1) (+ s 1) (- sinc 2))] [(and (symbol=? EMPTY_SQUARE (matrix-xy matboard (- x i) (+ y i))) (>= s 20)) (- s 4)] [(symbol=? symyes (matrix-xy matboard (- x i) (+ y i))) (numsleft (+ i 1) (+ sinc s) sinc)] [(symbol=? EMPTY_SQUARE (matrix-xy matboard (- x i) (+ y i))) (numsleft (+ i 1) s (- sinc 2))]))] (+ (numsright 1 0 20) (numsleft 1 0 20)))) ] (list (checkDiagonalLeft) (checkDiagonalRight) (checkHorizontal) (checkVertical)) )) ;(analyzer (make-matrix (list ; (list '- 'O 'O 'O '-) ; (list 'X 'X 'X 'X 'O) ; (list 'X 'O 'X 'O 'O) ; (list 'X 'X '- 'X 'O) ; (list 'X '- '- '- 'O))) 4 0 them us) ;(analyzer (make-matrix (list ; (list '- 'O 'O 'O '-) ; (list 'X 'X 'X 'X 'O) ; (list 'X 'O 'X 'O 'O) ; (list 'X 'X '- 'X 'O) ; (list 'X '- '- '- 'O))) 4 0 us them) ;(analyzer (make-matrix (list ; (list 'O 'O 'O 'O '-) ; (list 'X 'X 'X 'X 'O) ; (list 'X 'O 'X 'O 'X) ; (list 'X 'X '- 'X 'O) ; (list 'X '- '- '- 'O))) 4 0 them us) ;(analyzer (make-matrix (list ; (list '- 'O 'O 'O '-) ; (list 'X 'X 'X 'X 'O) ; (list 'X 'O 'X 'O 'O) ; (list 'X 'X '- 'X 'O) ; (list 'X '- '- '- 'X))) 0 0 us them) ;(analyzer (make-matrix (list ; (list '- 'O 'O 'O '-) ; (list 'X 'X 'X 'X 'O) ; (list 'X 'O 'X 'O 'O) ; (list 'X 'X '- 'X 'O) ; (list 'X '- '- '- 'X))) 2 4 us them) ;FUNCTION: checkWin: matrix num num sym -> num ;PURPOSE: This function takes in the x and y coordinates and returns a number that gives the ranking importance of that square in terms of winning. The extra symbol parameter is of no importance, its presence merely helps making other function calls compatible with the function win_or_lose ;EXAMPLES ;checkWin is a wrapper function for analyzer when used to check for winning values, therefore it has the same examples and testcases for the win-checking situation in analyzer ;BODY (define (checkWin matboard x y sym) (analyzer matboard x y us them) ) ;TESTCASES ;check with examples ;FUNCTION: checkBlockWin: matrix num num sym -> boolean ;PURPOSE: This function takes in the x and y coordinates and returns a number that gives the ranking importance of that square in terms of blocking the opponent. This time again, the symbol parameter is only needed for compatibility with win_or_lose ;EXAMPLES ;checkBlockWin is a wrapper function for analyzer when used to check for blocking values, therefore it has the same examples and testcases for the block-checking situation in analyzer (define (checkBlockWin matboard x y sym) (analyzer matboard x y them us)) ;TESTCASES ;check examples ;FUNCTION: getMove: matrix num num (alpha -> beta) (alpha -> beta) -> move ;PURPOSE: The purpose of this function is to return a move for a given coordinate and matrix board, in which the move contains its winning and blocking values (either in boolean or in number, depending on whether the input function parameters are win_or_lose or checkWin/checkBlockWin) ;EXAMPLES ;(getMove (make-matrix (list ; (list '- 'O 'O 'O '-) ; (list 'X 'X 'X 'X 'O) ; (list 'X 'O 'X 'O 'O) ; (list 'X 'X '- 'X 'O) ; (list 'X '- '- '- 'X))) 1 1 ) = 'NOMOVE ;(getMove (make-matrix (list ; (list '- 'O 'O 'O '-) ; (list 'X 'X 'X 'X 'O) ; (list 'X 'O 'X 'O 'O) ; (list 'X 'X '- 'X 'O) ; (list 'X '- '- '- 'X))) 0 0 win_or_lose win_or_lose) = (make-move 0 0 true false) ;(getMove (make-matrix (list ; (list '- 'O 'O 'O 'O) ; (list 'X 'X 'X 'X 'O) ; (list 'X 'O 'X 'O 'O) ; (list 'X 'X '- 'X 'O) ; (list 'X '- '- '- 'X))) 0 0 win_or_lose win_or_lose) = (make-move 0 0 true true) ;(getMove (make-matrix (list ; (list '- 'O 'O 'O 'O) ; (list 'O 'X 'X 'X 'O) ; (list 'X 'O 'O 'O 'O) ; (list 'X 'X '- 'X 'O) ; (list 'X '- '- '- 'X))) 0 0 win_or_lose win_or_lose) = (make-move 0 0 false true) ;(getMove (make-matrix (list ; (list '- 'O 'X 'O 'O) ; (list 'O 'X 'X 'X 'O) ; (list 'X 'O 'O 'O 'O) ; (list 'X 'X '- 'X 'O) ; (list 'X '- '- '- 'X))) 0 0 win_or_lose win_or_lose) = (make-move 0 0 false false) ;(getMove (make-matrix (list ; (list '- 'O 'O 'O '-) ; (list 'X 'X 'X 'X 'O) ; (list 'X 'O 'X 'O 'O) ; (list 'X 'X '- 'X 'O) ; (list 'X '- '- '- 'X))) 2 4 checkWin checkBlockWin) = (make-move 2 4 (list 30 10 30 29) (list -10 -10 -8 -9)) ;BODY (define (getMove matboard x y afunction1 afunction2) (local [(define square (matrix-xy matboard x y))] (cond [(symbol=? square EMPTY_SQUARE) (begin (make-move x y (afunction1 matboard x y us) (afunction2 matboard x y them))) ] [else 'NOMOVE]))) ;TESTCASE ;(getMove (make-matrix (list ; (list '- 'O 'O 'O '-) ; (list 'X 'X 'X 'X 'O) ; (list 'X 'O 'X 'O 'O) ; (list 'X 'X '- 'X 'O) ; (list 'X '- '- '- 'X)) 1 1 win_or_lose win_or_lose) ;(getMove (make-matrix (list ; (list '- 'O 'O 'O '-) ; (list 'X 'X 'X 'X 'O) ; (list 'X 'O 'X 'O 'O) ; (list 'X 'X '- 'X 'O) ; (list 'X '- '- '- 'X)) 0 0 win_or_lose win_or_lose) ;(getMove (make-matrix (list ; (list '- 'O 'O 'O 'O) ; (list 'X 'X 'X 'X 'O) ; (list 'X 'O 'X 'O 'O) ; (list 'X 'X '- 'X 'O) ; (list 'X '- '- '- 'X)) 0 0 win_or_lose win_or_lose) ;(getMove (make-matrix (list ; (list '- 'O 'O 'O 'O) ; (list 'O 'X 'X 'X 'O) ; (list 'X 'O 'O 'O 'O) ; (list 'X 'X '- 'X 'O) ; (list 'X '- '- '- 'X)) 0 0 win_or_lose win_or_lose) ;(getMove (make-matrix (list ; (list '- 'O 'X 'O 'O) ; (list 'O 'X 'X 'X 'O) ; (list 'X 'O 'O 'O 'O) ; (list 'X 'X '- 'X 'O) ; (list 'X '- '- '- 'X)) 0 0 win_or_lose win_or_lose) ;(getMove (make-matrix (list ; (list '- 'O 'O 'O '-) ; (list 'X 'X 'X 'X 'O) ; (list 'X 'O 'X 'O 'O) ; (list 'X 'X '- 'X 'O) ; (list 'X '- '- '- 'X))) 2 4 checkWin checkBlockWin) ;FUNCTION win_or_lose: -> ;PURPOSE: check to see if a winning or blocking move exist in a square ;(win_or_lose (make-matrix (list ; (list '- 'O 'O 'O '-) ; (list 'X 'X 'X 'X 'O) ; (list 'X 'O 'X 'O 'O) ; (list 'X 'X '- 'X 'O) ; (list 'X '- '- '- 'O)) 4 0 us) = true ;(win_or_lose (make-matrix (list ; (list '- 'O 'O 'O 'O) ; (list 'X 'X 'X 'X '-) ; (list 'X 'O 'X 'O 'O) ; (list 'X 'X '- 'X 'O) ; (list 'X '- '- '- 'O)) 4 1 us) = true ;(win_or_lose (make-matrix (list ; (list '- 'O 'O 'O '-) ; (list 'X 'X 'X 'X 'O) ; (list 'X 'O 'X 'O 'X) ; (list 'X 'X '- 'X 'O) ; (list 'X '- '- '- 'O)) 0 0 us) = true ;(win_or_lose (make-matrix (list ; (list '- 'O 'O 'O '-) ; (list 'X 'X 'X 'X 'O) ; (list 'X 'O 'X 'O 'O) ; (list 'X 'X '- 'X 'O) ; (list 'X '- '- '- 'X)) 0 0 us) = true ;(win_or_lose (make-matrix (list ; (list '- 'O 'O 'O '-) ; (list 'X 'X 'X 'X 'O) ; (list 'X 'O 'X 'O 'O) ; (list 'X 'X '- 'X 'O) ; (list 'X '- '- '- 'X)) 2 4 us) = false ;(win_or_lose (make-matrix (list ; (list 'O 'O 'O 'O '-) ; (list 'X 'X 'X 'X 'O) ; (list 'X 'O 'X 'O 'O) ; (list 'X 'X '- 'X 'O) ; (list 'X '- '- '- 'X)) 4 0 them) = true ;(win_or_lose (make-matrix (list ; (list '- 'O 'O 'O '-) ; (list 'X 'X 'X 'X 'O) ; (list 'X 'O 'X 'O 'O) ; (list 'X 'X '- 'X 'O) ; (list 'X '- '- '- 'X)) 2 4 them) = false ;BODY (define (win_or_lose matboard x y sym) (local [ ;FUNCTION checkDiagonalLeft: -> ;PURPOSE: takes in a board and the x y coordinates, and determine if the left diagonal line is an automatic win ;BODY (define (checkDiagonalLeft matboard x y) (local [ (define numusaboveleft 0) (define numusbelowright 0) ] (begin (for 1 (lambda (i) (and (within? matboard (- x i) (- y i)) (symbol=? sym (matrix-xy matboard (- x i) (- y i))))) (lambda (i) (begin (set! numusaboveleft (+ numusaboveleft 1)) (+ i 1)))) (for 1 (lambda (i) (and (within? matboard (+ x i) (+ y i)) (symbol=? sym (matrix-xy matboard (+ x i) (+ y i))))) (lambda (i) (begin (set! numusbelowright (+ numusbelowright 1)) (+ i 1)))) (if (= (+ numusaboveleft numusbelowright) (- WIN_NUM 1)) true false) ) )) ;FUNCTION checkDiagonalRight: -> ;PURPOSE: takes in a board and the x y coordinates, and determine if the right diagonal line is an automatic win ;BODY (define (checkDiagonalRight matboard x y) (local [ (define numusaboveright 0) (define numusbelowleft 0) ] (begin (for 1 (lambda (i) (and (within? matboard (+ x i) (- y i)) (symbol=? sym (matrix-xy matboard (+ x i) (- y i))))) (lambda (i) (begin (set! numusaboveright (+ numusaboveright 1)) (+ i 1)))) (for 1 (lambda (i) (and (within? matboard (- x i) (+ y i)) (symbol=? sym (matrix-xy matboard (- x i) (+ y i))))) (lambda (i) (begin (set! numusbelowleft (+ numusbelowleft 1)) (+ i 1)))) (if (= (+ numusaboveright numusbelowleft) (- WIN_NUM 1)) true false) ) ) ) ;FUNCTION checkDiagonalLeft: -> ;PURPOSE: takes in a board and the x y coordinates, and determine if the left diagonal line is an automatic win ;BODY (define (checkHorizontal matboard x y) (local [ (define numusleft 0) (define numusright 0) ] (begin (for (- x 1) (lambda (x) (and (within? matboard x y) (symbol=? sym (matrix-xy matboard x y)))) (lambda (x) (begin (set! numusleft (+ numusleft 1)) (- x 1)))) (for (+ x 1) (lambda (x) (and (within? matboard x y) (symbol=? sym (matrix-xy matboard x y)))) (lambda (x) (begin (set! numusright (+ numusright 1)) (+ x 1)))) (if (= (+ numusleft numusright) (- WIN_NUM 1)) true false) ) )) ;FUNCTION checkVertical: -> ;PURPOSE: takes in a board and the x y coordinates, and determine if the vertical line is an automatic win ;BODY (define (checkVertical matboard x y) (local [ (define numusabove 0) (define numusbelow 0) ] (begin (for (- y 1) (lambda (y) (and (within? matboard x y) (symbol=? sym (matrix-xy matboard x y)))) (lambda (y) (begin (set! numusabove (+ numusabove 1)) (- y 1)))) (for (+ y 1) (lambda (y) (and (within? matboard x y) (symbol=? sym (matrix-xy matboard x y)))) (lambda (y) (begin (set! numusbelow (+ numusbelow 1)) (+ y 1)))) (if (= (+ numusabove numusbelow) (- WIN_NUM 1)) true false) ) )) ] (begin (or (checkDiagonalLeft matboard x y) (checkDiagonalRight matboard x y) (checkHorizontal matboard x y) (checkVertical matboard x y)) ))) ;TESTCASES ;(win_or_lose (make-matrix (list ; (list '- 'O 'O 'O '-) ; (list 'X 'X 'X 'X 'O) ; (list 'X 'O 'X 'O 'O) ; (list 'X 'X '- 'X 'O) ; (list 'X '- '- '- 'O)) 4 0 us) ;(win_or_lose (make-matrix (list ; (list '- 'O 'O 'O 'O) ; (list 'X 'X 'X 'X '-) ; (list 'X 'O 'X 'O 'O) ; (list 'X 'X '- 'X 'O) ; (list 'X '- '- '- 'O)) 4 1 us) ;(win_or_lose (make-matrix (list ; (list '- 'O 'O 'O '-) ; (list 'X 'X 'X 'X 'O) ; (list 'X 'O 'X 'O 'X) ; (list 'X 'X '- 'X 'O) ; (list 'X '- '- '- 'O)) 0 0 us) ;(win_or_lose (make-matrix (list ; (list '- 'O 'O 'O '-) ; (list 'X 'X 'X 'X 'O) ; (list 'X 'O 'X 'O 'O) ; (list 'X 'X '- 'X 'O) ; (list 'X '- '- '- 'X)) 0 0 us) ;(win_or_lose (make-matrix (list ; (list '- 'O 'O 'O '-) ; (list 'X 'X 'X 'X 'O) ; (list 'X 'O 'X 'O 'O) ; (list 'X 'X '- 'X 'O) ; (list 'X '- '- '- 'X)) 2 4 us) ;(win_or_lose (make-matrix (list ; (list 'O 'O 'O 'O '-) ; (list 'X 'X 'X 'X 'O) ; (list 'X 'O 'X 'O 'O) ; (list 'X 'X '- 'X 'O) ; (list 'X '- '- '- 'X)) 4 0 them) ;(win_or_lose (make-matrix (list ; (list '- 'O 'O 'O '-) ; (list 'X 'X 'X 'X 'O) ; (list 'X 'O 'X 'O 'O) ; (list 'X 'X '- 'X 'O) ; (list 'X '- '- '- 'X)) 2 4 them) ;FUNCTION: decide: -> ;PURPOSE: This function returns a winning or blocking move. If neither of the two are present, then it will use the function nextbest to determine the best move ;EXAMPLES ;(decide (make-matrix '((- O O O O) (X - - - -) (X - - - -) (X - - - -) (X - - - -))) (list (make-move 0 0 true true) (make-move 3 3 false false))) = (make-move 0 0 true true) ;(decide (make-matrix '((- O O O O) (- - - - -) (X - - - -) (X - - - -) (X - - - -))) (list (make-move 0 0 false true) (make-move 3 3 false false))) = (make-move 0 0 false true) ;(decide (make-matrix '((- O O O O) (X O - - -) (X - O - -) (X - - - -) (X - - - O))) (list (make-move 0 0 false true) (make-move 3 3 true false))) = (make-move 3 3 true false) ;(decide (make-matrix '((- X O O O) (O - - - -) (X - - - -) (X - - - -) (X - - - -))) (list (make-move 0 0 false false) (make-move 3 3 false false))) = (make-move 0 0 false false) ;BODY (define (decide aboard moves) (local[ (define winmoves (filter (lambda (a) (move-win a)) moves)) (define blockwinmoves (filter (lambda (a) (move-block-win a)) moves)) ] (cond [(cons? winmoves) (first winmoves)] [(cons? blockwinmoves) (first blockwinmoves)] [else (nextbest (getBoardMoves aboard checkWin checkBlockWin))]))) ;TESTCASES ;(decide (make-matrix '((- O O O O) (X - - - -) (X - - - -) (X - - - -) (X - - - -))) (list (make-move 0 0 true true) (make-move 3 3 false false))) ;(decide (make-matrix '((- O O O O) (- - - - -) (X - - - -) (X - - - -) (X - - - -))) (list (make-move 0 0 false true) (make-move 3 3 false false)) ;(decide (make-matrix '((- O O O O) (X O - - -) (X - O - -) (X - - - -) (X - - - O))) (list (make-move 0 0 false true) (make-move 3 3 true false))) ;(decide (make-matrix '((- X O O O) (O - - - -) (X - - - -) (X - - - -) (X - - - -))) (list (make-move 0 0 false false) (make-move 3 3 false false))) ;FUNCTION nextbest: -> ;PURPOSE: if there are no winning or block moves, then return the best move possible ;EXAMPLES ;(nextbest (list (make-move 0 0 (list 24 13 1 1) (list 12 45 89 89)) (make-move 3 2 (list 23 45 8 1) (list 2 34 1 1)))) = (make-move 0 0 (list 24 13 1 1) (list 12 45 89 89)) ;BODY (define (nextbest ms) (local [(define bwin (bestwin ms)) (define bblock (bestblock ms))] (cond [(>= (getmax (move-win bwin)) 52) bwin] [(> (getmax (move-block-win bblock)) 50) bblock] [else (bestoverall ms)]))) ;TESTCASES ;(nextbest (list (make-move 0 0 (list 24 13 1 1) (list 12 45 89 89)) (make-move 3 2 (list 23 45 8 1) (list 2 34 1 1)))) (game)