Advertisement
Guest User

Untitled

a guest
Dec 1st, 2018
127
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Racket 19.13 KB | None | 0 0
  1. #lang slideshow
  2. (require racket/class
  3.          racket/set
  4.          racket/promise
  5.          compatibility/mlist
  6.          (only-in racket/list shuffle argmax))
  7.  
  8. (define field-size 4)
  9.  
  10. ;(define all-colors (list "red" "yellow" "green" "black" "blue" "orange" "teal"))
  11. (define all-colors '("red" "yellow" "green"))
  12. (define (pick-random lst)
  13.   (list-ref lst (random (length lst)))
  14. )
  15.  
  16. (define (square size color)
  17.   (colorize (filled-rectangle size size) color))
  18. ;
  19. ;;;--------------------------------------------------------------------
  20. ;;; Реализация минимакса с альфа-бета отсечением
  21. (define (minimax tree)
  22.   (define (minimax-h node alpha beta max-player)
  23.     (define (next-max x v)
  24.       (if (or (null? x) (<= beta v))
  25.                 v
  26.                 (next-max (cdr x)
  27.                       (max v (minimax-h (car x) v beta (not max-player)))))
  28.     )
  29.     (define (next-min x v)
  30.       (if (or (null? x) (<= v alpha))
  31.                 v
  32.                 (next-min (cdr x)
  33.                       (min v (minimax-h (car x) alpha v (not max-player)))))
  34.     )
  35.     (cond
  36.          ((number? node) node)
  37.          ((null? node) 0.0)
  38.          (max-player (next-max node alpha))
  39.          (else (next-min node beta)))
  40.          
  41.   )
  42.   (minimax-h tree -inf.0 +inf.0 #f)
  43.  )
  44.  
  45.  
  46.  
  47. ;;;--------------------------------------------------------------------
  48. ;;; описание класса, реализующего логику и оптимальную стратегию произвольной игры с нулевой суммой и полной информацией
  49. (define game%
  50.   (class object%
  51.     (super-new)
  52.  
  53.     ;; виртуальные методы для задания правил игры
  54.     (init-field my-win?         ; State -> Bool
  55.                 my-loss?        ; State -> Bool
  56.                 draw-game?      ; State -> Bool
  57.                 my-move         ; State Move -> State
  58.                 opponent-move   ; State Move -> State
  59.                 possible-moves  ; State -> (list Move)
  60.                 show-state)     ; State -> Any
  61.  
  62.     ;; optimal-move :: State -> Move
  63.     ;; выбор оптимального хода по минимаксу
  64.     ;; из нескольких оптимальных выбирается один случайно
  65.     (define/public ((optimal-move look-ahead) S)
  66.       (argmax (lambda (m) (minimax (game-tree S m look-ahead))
  67.                  (shuffle (possible-moves S)))))
  68.  
  69.     ;; game-tree :: State -> (Move -> (Tree of Real))
  70.     ;; построение дерева с оценками
  71.     (define (game-tree St m look-ahead)
  72.        ;; вспомогательная функция, строящая закольцованный список из пары элементов
  73.       (define (help a b) (begin (define l (mlist a b a)) (set-mcdr! l (mcons b l)) l))
  74.       (define (new-ply moves i s)    
  75.         (cond
  76.           ((my-win? s) +inf.0) ; в выигрышной позиции оценка = + бесконечность
  77.           ((my-loss? s) -inf.0) ; в проигрышной = - бесконечность
  78.           ((draw-game? s)     0) ; при ничье = 0
  79.           ((>= i look-ahead)  (f-h s)) ; если исчерпана глубина, то используется эвристическая оценка
  80.           (else (map (lambda (x) (new-ply (mcdr moves) (+ 1 i) ((mcar moves) s x)))
  81.                      (possible-moves s))) ; рассматриваем все возможные ходы и строим их оценки
  82.         ))
  83.      (new-ply (help opponent-move my-move) 1 (my-move St m))
  84.     )
  85.  
  86.     ;; make-move :: State (State -> Move) -> (Move State Symbol)
  87.     (define/public (make-move S move)
  88.       (display "make-move got ")
  89.       (display S)
  90.       (display "\n")
  91.       (cond
  92.         ((my-loss? S)   (values '() S 'loss))        
  93.         ((draw-game? S) (values '() S 'draw))  
  94.         (else (let* ((m* (move S))
  95.                      (S* (my-move S m*))
  96.                      )
  97.                 (cond
  98.                   ((my-win? S*)    (values m* S* 'win))
  99.                   ((draw-game? S*) (values m* S* 'draw))
  100.                   (else (begin
  101.                    
  102.       (display "make-move sent ")
  103.       (display S*)
  104.       (display "\n")
  105.      
  106.                    (values m* S* 'next)))))))
  107.     )
  108.   ))
  109.  
  110.  
  111. ;;;--------------------------------------------------------------------
  112. ;;; макрос для описания партнеров в игре
  113. (define-syntax-rule
  114.   (define-partners game (A #:win A-wins #:move A-move)
  115.                         (B #:win B-wins #:move B-move))
  116.   (begin
  117.     (define A (class game
  118.                 (super-new
  119.                  [my-win?  A-wins]
  120.                  [my-loss? B-wins]
  121.                  [my-move  A-move]
  122.                  [opponent-move B-move])))
  123.     (define B (class game
  124.                 (super-new
  125.                  [my-win?  B-wins]
  126.                  [my-loss? A-wins]
  127.                  [my-move  B-move]
  128.                  [opponent-move A-move])))))
  129.  
  130. ;;;--------------------------------------------------------------------
  131.  
  132. ;; Структура представляющая ситуацию на игровой доске. В структуре одно поле - вектор в котором находятся цвета ячеек
  133. (struct board (colors))
  134.  
  135. ;; геттер цветов ячеек
  136. (define colors board-colors)
  137.  
  138. ;; в начале игровая доска пуста, гарантируется, что начальные цвета двух игроков разные. игроки начинают в верхнем левом и нижнем правом углах
  139. (define (make-board) (board  (list->vector (build-list (* field-size field-size) (lambda (x) (pick-random all-colors) )))))
  140. (define (make-empty-board)
  141.   (let ((b (make-board)))
  142.     (if (eq? (vector-ref (colors b) 0) (vector-ref (colors b) (sub1 (* field-size field-size)))) (make-empty-board) b)))
  143. (define empty-board (make-empty-board))
  144.  
  145. ;; изменить цвет клетки по ее позиции в векторе`
  146. (define (color-cell color number b)
  147.   (vector-set! b number color))
  148.  
  149. ;; получить цвет клетки по ее позиции в векторе
  150. (define (cell-color number b)
  151.   (vector-ref  b number))
  152.  
  153. ;; получить список соседних клеток по номеру, возвращяются только клетки такого же цвета, что и центральная
  154. ;; разобрано 9 случаев: центральная часть поля, 4 угла, 4 границы без угловых клеток
  155. (define (get-close-cells number b)
  156.   (let ((color-of-cell (cell-color number b))
  157.         (i (quotient number field-size))
  158.         (j (remainder number field-size))
  159.         (field-size-sub1 (sub1 field-size)))
  160.     (cond ((and (> i 0) (> j 0) (< i field-size-sub1) (< j field-size-sub1)) (filter (lambda (x) (eq? (cell-color x b) color-of-cell)) (list
  161.                                                                                                     (+ (* (+ 1 i) field-size) j)
  162.                                                                                                     (+ (* (- i 1) field-size) j)
  163.                                                                                                     (+ (* i field-size) (+ 1 j))
  164.                                                                                                     (+ (* i field-size) (- j 1)))))
  165.          
  166.           ((and  (= i field-size-sub1) (> j 0) (< j field-size-sub1)) (filter (lambda (x) (eq? (cell-color x b) color-of-cell)) (list
  167.                                                                                                     (+ (* i field-size) (+ 1 j))
  168.                                                                                                     (+ (* (- i 1) field-size) j)
  169.                                                                                                     (+ (* i field-size) (- j 1)))))
  170.           ((and (= i 0) (> j 0) (< j field-size-sub1)) (filter (lambda (x) (eq? (cell-color x b) color-of-cell)) (list
  171.                                                                                                     (+ (* (+ i 1) field-size) j)
  172.                                                                                                     (+ (* i field-size) (+ 1 j))
  173.                                                                                                     (+ (* i field-size) (- j 1)))))
  174.           ((and (= j 0) (> i 0) (< i field-size-sub1)) (filter (lambda (x) (eq? (cell-color x b) color-of-cell)) (list
  175.                                                                                                     (+ (* i field-size) (+ j 1))
  176.                                                                                                     (+ (* (+ i 1) field-size) j)
  177.                                                                                                     (+ (* (- i 1) field-size) j))))
  178.           ((and (= j field-size-sub1) (> i 0) (< i field-size-sub1)) (filter (lambda (x) (eq? (cell-color x b) color-of-cell)) (list
  179.                                                                                                     (+ (* i field-size) (- j 1))
  180.                                                                                                     (+ (* (+ i 1) field-size) j)
  181.                                                                                                     (+ (* (- i 1) field-size) j))))
  182.  
  183.          
  184.           ((and (= i 0) (= j 0)) (filter (lambda (x) (eq? (cell-color x b) color-of-cell)) (list
  185.                                                                                                     (+ (* (+ i 1) field-size) j)
  186.                                                                                                     (+ (* i field-size) (+ j 1)))))
  187.           ((and (= i field-size-sub1) (= j 0)) (filter (lambda (x) (eq? (cell-color x b) color-of-cell)) (list
  188.                                                                                                     (+ (* (- i 1) field-size) j)
  189.                                                                                                     (+ (* i field-size) (+ j 1)))))
  190.           ((and (= i 0) (= j field-size-sub1)) (filter (lambda (x) (eq? (cell-color x b) color-of-cell)) (list
  191.                                                                                                     (+ (* (+ i 1) field-size) j)
  192.                                                                                                     (+ (* i field-size) (- j 1)))))
  193.           ((and (= i field-size-sub1) (= j field-size-sub1)) (filter (lambda (x) (eq? (cell-color x b) color-of-cell)) (list
  194.                                                                                                    (+ (* (- i 1) field-size) j)
  195.                                                                                                     (+ (* i field-size) (- j 1)))))
  196.            )))
  197.  
  198. ;; закрасить клетки поля в заданный цвет по принципу flood-fill
  199. ;; закрашиваются только те клетки, которые имеют тот же цвет, что и начальная, и  существует путь от этой клетки до начальной, на котором все клетки имеют цвет начальной
  200. ;; на вход подается цвет закраски и номер начальной клетки
  201. (define (flood-fill11 color number b)
  202.   (define (helper  to-go visited)
  203.     (cond ((null? to-go) '())
  204.           ((member (car to-go) visited) (helper (cdr to-go) visited))
  205.           (else (helper (append (filter (lambda (x) (not (member x visited))) (get-close-cells (car to-go) b)) (cdr to-go)) (cons (car to-go) visited))
  206.                 (color-cell color (car to-go) b))))
  207.   (helper (list number) '())
  208.   (copy-vector b)
  209.   )
  210.  
  211. (define (flood-fill color number b)
  212.   (display b)
  213.   (display "\n")
  214.   (define (helper0 b res)
  215.     (cond ((null? b) (list->vector (reverse res)))
  216.           (else (helper0 (cdr b) (cons (car b) res)))))
  217.   (define (helper b to-go visited to-change)
  218.     (cond ((null? to-go) to-change)
  219.           ((member (car to-go) visited) (helper b (cdr to-go) visited to-change))
  220.           (else (helper b (append (filter (lambda (x) (not (member x visited))) (get-close-cells (car to-go) b)) (cdr to-go)) (cons (car to-go) visited) (cons (car to-go) to-change)))))
  221.   (define (helper2 color colors numbers to-change result)
  222.     (cond ((null? colors) result)
  223.           ((member (car numbers) to-change) (helper2 color (cdr colors) (cdr numbers) to-change (cons color result)))
  224.           (else (helper2 color (cdr colors) (cdr numbers) to-change (cons (car colors) result)))))
  225.   (display (helper (helper0 (vector->list b) '()) (list number) '() '()))
  226.   (display "\n")
  227.   (display (helper (helper0 (vector->list b) '()) (list number) '() '()))
  228.   (display "\n")
  229.   ;(show-board (helper0 (vector->list b) '()))
  230.   (display "\n")
  231.   (display (list->vector (reverse (helper2 color (vector->list b) (build-list (* field-size field-size) (lambda (x) x)) (helper (helper0 (vector->list b) '()) (list number) '() '()) '()))))
  232.   (display "\n")
  233.   (list->vector (reverse (helper2 color (vector->list b) (build-list (* field-size field-size) (lambda (x) x)) (helper (helper0 (vector->list b) '()) (list number) '() '()) '())))
  234.   ;(copy-vector b)
  235.   )
  236.  
  237. ;(build-list (* field-size field-size) (lambda (x) (pick-random all-colors) ))
  238. ;; возвращяет размер региона одного цвета, которому принадлежит ячейка с указанным номером
  239. (define (color-region-size number b)
  240.     (define (helper  to-go visited size-accum)
  241.     (cond ((null? to-go) size-accum)
  242.           ((member (car to-go) visited) (helper (cdr to-go) visited size-accum))
  243.           (else (helper (append (filter (lambda (x) (not (member x visited))) (get-close-cells (car to-go) b)) (cdr to-go)) (cons (car to-go) visited) (+ 1 size-accum)))))
  244.   (helper (list number) '() 0))
  245.  
  246.  
  247.  
  248. ;; проверка, является ли ситуация на игровой доске выигрышной для региона цвета, которому принадлежит ячейка с указанным номером
  249. (define ((wins? number) b)
  250.   (>=  (color-region-size number b)  (/ (* field-size field-size) 2 )))
  251.  
  252.  
  253. ;; проверка на ничью, она возможна только в одном случае - когда размер региона каждого игроока равен ровно половине размера поля
  254. (define (draw? b)
  255.   (let ((half-size (/ (* field-size field-size) 2))
  256.         (last-cell (- (* field-size field-size) 1)))
  257.     (and (= (color-region-size 0 b) half-size) ((= (color-region-size last-cell b) half-size)))))
  258.  
  259. ;; функция эвристической оценки позиции
  260. ;; из количества линий, открытых для крестиков, вычитается количество линий, открытых для ноликов
  261. (define (f-h s)
  262.   0
  263. )
  264.  
  265.  
  266. (define (full-copy list)
  267. (if (null? list)
  268.   '()
  269.   (if (list? list)
  270.       (cons (full-copy (car list)) (full-copy (cdr list)))
  271.       list)))
  272.  
  273. (define (copy-vector v)
  274.   (list->vector (full-copy (vector->list v))))
  275.  
  276. (define (copy-board b)
  277.   (board (list->vector (full-copy (vector->list (colors b))))))
  278.  
  279.  
  280.  
  281. ;; функции для осуществления ходов игроков
  282. (define (a-move b color)  (copy-vector (flood-fill color 0 (copy-vector b))))
  283. (define (b-move b color)  (copy-vector (flood-fill color (- (* field-size field-size) 1) (copy-vector b))))
  284.  
  285.  
  286. (define (show-board b)
  287.   (for ([i (build-list field-size (lambda (x) x))])
  288.     (for ([j (build-list field-size (lambda (x) x))])
  289.       (print (square 20 (vector-ref b (+ (* i field-size) j))))
  290.       (display " "))
  291.     (display "\n"))
  292. )
  293.  
  294.  
  295. ;;--------------------------------------------------------------------
  296. ;; Описание класса-игры крестики-нолики
  297. (define filler%
  298.   (class game%
  299.     (super-new
  300.      [draw-game?       draw?]
  301.      [possible-moves   all-colors]
  302.      [show-state       show-board])))
  303.  
  304. ;; описания партнеров для крестиков-ноликов
  305. (define-partners filler%
  306.   (playera% #:win (wins? 0) #:move a-move)
  307.   (playerb% #:win (wins? (- (* field-size field-size) 1)) #:move b-move))
  308.  
  309.  
  310. ;;--------------------------------------------------------------------
  311. ;; Реализация класса игрока
  312. ;; Параметр `game` указывает, в какая игра решается.
  313. (define (interactive-player game)
  314.   (class game
  315.     (super-new)
  316.  
  317.     (inherit-field show-state)
  318.     (inherit make-move optimal-move)
  319.  
  320.     (init-field name
  321.                 [look-ahead 4]
  322.                 [opponent 'undefined]
  323.                 [move-method (optimal-move look-ahead)])
  324.  
  325.     (define/public (your-turn S1)
  326.       (define-values (m S status) (make-move S1 move-method))
  327.       (printf "\n~a makes move ~a\n" name m)
  328.       (show-state S)
  329.       (case status
  330.            ['stop (displayln "The game was interrupted.")]
  331.            ['win  (printf "~a wins!" name)]
  332.            ['loss (printf "~a wins!" name)]
  333.            ['draw (printf "Draw!")]
  334.            [else (send opponent your-turn S)]))))
  335.            ;[else (send opponent your-turn (board (vector-copy (colors S*))))])))))
  336.  
  337.  
  338. ;;--------------------------------------------------------------------
  339.  
  340.  
  341. ;; объекты-игроки, принимающие ввод пользователя
  342. ;; проверка ввода частичная
  343. (define (input-move m)
  344.   (cond ((eq? m 'q) (exit))
  345.         ((member m all-colors) m)
  346.         (else m)))
  347.  
  348. (define user-A
  349.   (new (force (interactive-player playera%))
  350.        [name "User A"]
  351.        [move-method
  352.         (lambda (b) (input-move (read)))]
  353.         )
  354.  )
  355. (define user-B
  356.   (new (force (interactive-player playerb%))
  357.        [name "User B"]
  358.        [move-method
  359.         (lambda (b) (input-move (read)))]
  360.         )
  361.  )
  362.  
  363. ;;--------------------------------------------------------------------
  364. ;; функция, инициализирующая игру
  365. (define (start-game p1 p2 initial-state)
  366.   (set-field! opponent p1 p2)
  367.   (set-field! opponent p2 p1)
  368.   (send p1 your-turn initial-state))
  369. ;; пример использования
  370. (show-board (colors empty-board))
  371. (start-game user-A user-B (colors empty-board))
  372.  
  373. ;
  374. ;(define b empty-board)
  375. ;(show-board b)
  376. ;
  377. ;(define point 0)
  378. ;
  379. ;(define (black)
  380. ;  (flood-fill "black" point b)
  381. ;  (show-board b))
  382. ;(define (red)
  383. ;  (flood-fill "red" point b)
  384. ;  (show-board b))
  385. ;(define (green)
  386. ;  (flood-fill "green" point b)
  387. ;  (show-board b))
  388. ;(define (yellow)
  389. ;  (flood-fill "yellow" point b)
  390. ;  (show-board b))
  391. ;(define (blue)
  392. ;  (flood-fill "blue" point b)
  393. ;  (show-board b))
  394. ;(define (teal)
  395. ;  (flood-fill "teal" point b)
  396. ;  (show-board b))
  397. ;(define (orange)
  398. ;  (flood-fill "orange" point b)
  399. ;  (show-board b))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement