You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
122 lines
4.3 KiB
Racket
122 lines
4.3 KiB
Racket
#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))]))))) |