#lang racket ; dots and boxes players! (require "main.rkt" racket/random) (provide player-random player-first player-last player-greedy player-generous player-nico player-horizontal player-vertical) ; a Player that plays random moves (define player-random (player "Random" (lambda (g n) (let ([m (car (random-sample (valid-moves g) 1))]) (line (line-from m) (line-to m) n))))) ; plays the first valid move found (define player-first (player "First Move" (lambda (g n) (let ([m (first (valid-moves g))]) (line (line-from m) (line-to m) n))))) ; plays the last valid move found (define player-last (player "Last Move" (lambda (g n) (let ([m (last (valid-moves g))]) (line (line-from m) (line-to m) n))))) ; if a move completes a box, play it. Otherwise, play a random move. ; This isn't a "perfect" greedy - it will sometimes take a single box instead of two. (define player-greedy (player "Greedy" (lambda (g n) (let* ([moves (valid-moves g)] [box-finishing-moves (filter (lambda (m) (not (= 0 (completes-boxes g m)))) moves)]) (cond [(empty? box-finishing-moves) (let ([m (car (random-sample (valid-moves g) 1))]) (line (line-from m) (line-to m) n))] [else (line (line-from (first box-finishing-moves)) (line-to (first box-finishing-moves)) n)]))))) ; helper function for determining if a move makes a three-sided box. (define (three? gr l) (let ([boxes (boxes-for l gr)] [g (append-move gr l)]) (not (= 0 (length (filter (lambda (b) (= (count-box b g) 3)) boxes)))))) ; if a move completes a box, play it. Otherwise, play a move that avoids making a three-sided box. Otherwise, play a random move. ; this is reflective of a common simple human strategy, and the strategy that the program author uses. Hence, it is named for them. (define player-nico (player "Nico-bot" (lambda (g n) (let* ([moves (valid-moves g)] [non-three-moves (filter (lambda (m) (not (three? g m))) moves)] [box-finishing-moves (filter (lambda (m) (not (= 0 (completes-boxes g m)))) moves)]) (cond [(not (empty? box-finishing-moves)) (line (line-from (first box-finishing-moves)) (line-to (first box-finishing-moves)) n)] [(not (empty? non-three-moves)) (let ([m (car (random-sample non-three-moves 1))]) (line (line-from m) (line-to m) n))] [else (let ([m (car (random-sample (valid-moves g) 1))]) (line (line-from m) (line-to m) n))]))))) ; tries to give up boxes to the opponent whenever possible and deliberately avoids taking boxes ever (define player-generous (player "Generous" (lambda (g n) (let* ([moves (valid-moves g)] [three-moves (filter (lambda (m) (three? g m)) moves)] [non-box-finishing-moves (filter (lambda (m) (= 0 (completes-boxes g m))) moves)]) (cond [(not (empty? three-moves)) (let ([m (car (random-sample three-moves 1))]) (line (line-from m) (line-to m) n))] [(not (empty? non-box-finishing-moves)) (let ([m (car (random-sample non-box-finishing-moves 1))]) (line (line-from m) (line-to m) n))] [else (let ([m (car (random-sample (valid-moves g) 1))]) (line (line-from m) (line-to m) n))]))))) ; prefers vertical moves. (define player-vertical (player "Vertical" (lambda (g n) (let* ([moves (valid-moves g)] [vertical-moves (filter (curry vertical?) moves)]) (cond [(not (empty? vertical-moves)) (let ([m (car (random-sample vertical-moves 1))]) (line (line-from m) (line-to m) n))] [else (let ([m (car (random-sample (valid-moves g) 1))]) (line (line-from m) (line-to m) n))]))))) ; prefers horizontal moves. (define player-horizontal (player "Horizontal" (lambda (g n) (let* ([moves (valid-moves g)] [horizontal-moves (filter (curry horizontal?) moves)]) (cond [(not (empty? horizontal-moves)) (let ([m (car (random-sample horizontal-moves 1))]) (line (line-from m) (line-to m) n))] [else (let ([m (car (random-sample (valid-moves g) 1))]) (line (line-from m) (line-to m) n))])))))