Advertisement
waf9000

Untitled

Apr 5th, 2018
300
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Racket 11.27 KB | None | 0 0
  1. #lang racket
  2. (require debug)
  3. (define stdout (current-output-port))
  4. (define ((appls f) l) (apply f l))
  5. (define falses (stream-cons #f falses))
  6. (define member? (compose1 not not member))
  7. (define (char+ . args)
  8.   (integer->char (apply + (map (λ(x)
  9.                                  (cond
  10.                                    [(char? x) (char->integer x)]
  11.                                    [(integer? x) x])) args))))
  12. (define (char- . args)
  13.   (integer->char (apply - (map (λ(x)
  14.                                  (cond
  15.                                    [(char? x) (char->integer x)]
  16.                                    [(integer? x) x])) args))))
  17.  
  18. #| velocities of all playable characters except pawn |#
  19. (define knight-vel (append-map permutations(cartesian-product'(-2 2)'(-1 1))))
  20. (define bishop-vel (cartesian-product '(-1 1) '(-1 1)))
  21. (define rook-vel (append-map permutations '((1 0) (-1 0))))
  22. (define queen-vel (append bishop-vel rook-vel))
  23. (define king-vel queen-vel)
  24.  
  25. (define pretty-assoc
  26.   (map list (map (compose car string->list symbol->string)
  27.                  (append '(K Q R B N P k q r b n p | | _)))
  28.        (map integer->char (append (range 9812 9824)
  29.                                   '(#x3000 #x25a0)))))
  30.  
  31. ;; possible black squares: #x25a0 ,
  32.  
  33. (define (empty-piece . args)
  34.   (match-define (or `(,x ,y) `((,x ,y))) args)
  35.   (if (= 0 (modulo (- x y) 2)) #\space #\_))
  36.  
  37. (define empty-board
  38.   (build-list 8 (λ(y) (build-list 8 (λ(x) (empty-piece x y))))))
  39.  
  40. (define black-piece? char-lower-case?)
  41. (define white-piece? char-upper-case?)
  42.  
  43. (define (update-cell brd f . args)
  44.   (match-define (or `(,x ,y) `((,x ,y))) args)
  45.   (list-update brd y (curryr list-update x f)))
  46.  
  47. (define (get-cell brd . args)
  48.   (match-define (or `(,x ,y) `((,x ,y))) args)
  49.   (list-ref (list-ref brd y) x))
  50.  
  51. (define (set-row brd y to-set)
  52.   (list-set brd y to-set))
  53.  
  54. (define start-board
  55.   (foldl
  56.    (λ (args b)
  57.      (set-row b (car args)
  58.               (map (compose car string->list symbol->string)
  59.                (cadr args))))
  60.    empty-board
  61.    `((0 (r n b q k b n r))
  62.      (1 (p p p p p p p p))
  63.      (6 (P P P P P P P P))
  64.      (7 (R N B Q K B N R)))))
  65.  
  66. (define (place-piece brd p . args)
  67.   (match-define (or `(,x ,y) `((,x ,y)) `((,x . ,y))) args)
  68.   (update-cell brd (const (if p p (empty-piece x y))) x y))
  69.  
  70. (define test-board
  71.   (foldl (λ (args b) (place-piece b (car args) (cdr args)))
  72.    empty-board '((#\Q 3 3) (#\b 5 5) (#\B 5 3) (#\K 0 0)
  73.                            (#\k 7 7) (#\r 1 7) (#\r 7 1))))
  74.  
  75. (define (valid-coord? . args)
  76.   (match-define (or `(,x ,y) `((,x ,y))) args)
  77.   (and (< -1 x 8) (< -1 y 8)))
  78.  
  79. (define (safe-take l n)
  80.   (if (or (null? l) (<= n 0)) '()
  81.       (cons (car l) (safe-take (cdr l) (sub1 n)))))
  82. (define (safe-last ls) (if (null? ls) #f (last ls)))
  83.  
  84. (define (get-coords brd char)
  85.   (for/list {[row brd]  [y (in-naturals)] #:when #t
  86.              [cell row] [x (in-naturals)] #:when (char=? char cell)}
  87.     `(,x ,y)))
  88.  
  89. (define (in-2D-range start vel)
  90.   (let loop {[cur start]}
  91.     (stream-cons cur (loop (map + cur vel)))))
  92.  
  93. ;; you're only allowed to promote to queen
  94. (define (do-move brd . args)
  95.   (match-define (or `(,x,y,x2,y2) `((,x,y)(,x2,y2))) args)
  96.   (define p (get-cell brd x y))
  97.   (place-piece
  98.    (place-piece brd #f x y)
  99.    (match `(,p,y2)
  100.      ['(#\p 7) #\q]
  101.      ['(#\P 0) #\Q]
  102.      [else p]) x2 y2))
  103.  
  104. ;; requires: x and y in args are valid-coord?
  105. (define (valid-moves brd . args)
  106.   (match-define (or `(,x ,y) `((,x ,y))) args)
  107.   (define start `(,x,y))
  108.   (define p (get-cell brd start))
  109.   (define black? (black-piece? p))
  110.   (define ally? (if black? black-piece? white-piece?))
  111.   (define opponent? (if black? white-piece? black-piece?))
  112.  
  113.   (define (travel-until brd start vel [black? black?])
  114.     (define ally? (if black? black-piece? white-piece?))
  115.     (define opponent? (if black? white-piece? black-piece?))
  116.     (for/list
  117.         {[pos (stream-rest (in-2D-range start vel))]
  118.          #:break (or (not (valid-coord? pos))
  119.                      (ally? (get-cell brd pos)))
  120.          #:final (opponent? (get-cell brd pos))}
  121.       pos))
  122.  
  123.   ;; pawn moves are hard... en-poisson not implemented
  124.   (define (calc-pawn-moves)
  125.     (define vert-dir (if black? 1 -1))
  126.     (define vert-scalar
  127.       (if (or (and black? (= y 1))
  128.               (and (not black?) (= y 6)))
  129.           2 1))
  130.     (append
  131.      (safe-take (travel-until brd start `(0 ,vert-dir)) vert-scalar)
  132.      (filter-map
  133.       (λ(x)
  134.         (and (valid-coord? (map + start `(,x ,vert-dir)))
  135.              (opponent?
  136.               (get-cell brd (map + start `(,x ,vert-dir))))
  137.              `(,x ,vert-dir)))
  138.       '(-1 1))))
  139.  
  140.   (define (valid+free? pos)
  141.     (and (valid-coord? pos) (not (ally? (get-cell brd pos)))))
  142.  
  143.   (define (raw-valid-moves)
  144.     (match (char-downcase p)
  145.       [#\r (append-map (curry travel-until brd start)   rook-vel)]
  146.       [#\b (append-map (curry travel-until brd start) bishop-vel)]
  147.       [#\q (append-map (curry travel-until brd start)  queen-vel)]
  148.       [#\n (filter valid+free?(map(curry map + start) knight-vel))]
  149.       [#\k (filter valid+free?(map(curry map + start)   king-vel))]
  150.       [#\p (calc-pawn-moves)]))
  151.  
  152.   (define (in-check? brd)
  153.     (define king (if black? #\k #\K))
  154.     (define king-pos (car (get-coords brd king)))
  155.     (define opponent? (if black? white-piece? black-piece?))
  156.     (define pawn-vert (if black? 1 -1))
  157.  
  158.     (define ((offending-pieces-here? bad-pieces) opp-pos)
  159.       (define opp (get-cell brd opp-pos))
  160.       (and (opponent? opp) (memv (char-downcase opp) bad-pieces)))
  161.    
  162.     (or
  163.      (ormap
  164.       (offending-pieces-here? '(#\r #\q))
  165.       (filter-map (λ (vel)
  166.                     (safe-last (travel-until brd king-pos vel)))
  167.                   rook-vel))
  168.      (ormap
  169.       (offending-pieces-here? '(#\b #\q))
  170.       (filter-map (λ (vel)
  171.                     (safe-last (travel-until brd king-pos vel)))
  172.                   bishop-vel))
  173.      (ormap
  174.       (offending-pieces-here? '(#\n))
  175.       (filter valid-coord?
  176.               (map (curry map + king-pos) knight-vel)))
  177.      (ormap
  178.       (offending-pieces-here? '(#\p))
  179.       (filter valid-coord?
  180.               (map
  181.                (λ(x) (map + king-pos `(,x ,pawn-vert)))
  182.                '(-1 1))))))
  183.  
  184.   (define/debug (try-move . args2)
  185.     (match-define (or `(,x2 ,y2) `((,x2 ,y2))) args2)
  186.     (place-piece
  187.      (place-piece brd #f x y)
  188.      (match `(,p,y2)
  189.        ['(#\p 7) #\q]
  190.        ['(#\P 0) #\Q]
  191.        [else p])
  192.      x2 y2))
  193.  
  194.   (filter (compose not in-check? try-move) (raw-valid-moves)))
  195.  
  196. (define (print-stars brd ls)
  197.   (begin
  198.     (printf "\n\u3000~a\n"
  199.             (string-join (map (λ(i) (string (char+ #\uff21 i))) (range 8))
  200.                          "\u3000" #:before-first "\u3000" #:after-last "\u3000"))
  201.     (printf "\u3000┏~a┓\n" (string-join
  202.              (build-list 8 (λ(x) (if (member `(,x 0) ls) "┳" "━"))) "┳"))
  203.     (for {[row brd]
  204.           [y (in-naturals)]}
  205.       (printf "~a" (char- #\uFF18 y))
  206.       (for {[cell row]
  207.             [x (in-naturals)]}
  208.         (match (list (member? `(,x,y) ls) (member? `(,(- x 1),y) ls))
  209.           ['(#t #t)
  210.            (printf "╋~a" (cadr (assoc cell pretty-assoc)))]
  211.           ['(#t #f)
  212.            (printf "┣~a" (cadr (assoc cell pretty-assoc)))]
  213.           ['(#f #t)
  214.            (printf "┫~a" (cadr (assoc cell pretty-assoc)))]
  215.           [else
  216.            (printf "┃~a" (cadr (assoc cell pretty-assoc)))]))
  217.       (if (member `(7,y) ls)
  218.           (printf "┫~a\n\u3000" (char- #\uFF18 y))
  219.           (printf "┃~a\n\u3000" (char- #\uFF18 y)))
  220.       (if (< y 7)
  221.           (printf "┣~a┫\n" (string-join (build-list
  222.                     8 (λ(x)
  223.                         (match (list(member? `(,x,y) ls)(member?`(,x,(+ y 1)) ls))
  224.                           ['(#t #t) "╋"]
  225.                           ['(#t #f) "┻"]
  226.                           ['(#f #t) "┳"]
  227.                           [else "━"]))) "╋"))
  228.           (printf "┗~a┛\n" (string-join
  229.                    (build-list 8 (λ(x) (if (member `(,x,y) ls) "┻" "━"))) "┻"))))
  230.     (printf "\u3000~a\n\n"
  231.             (string-join (map (λ(i) (string (char+ #\uff21 i))) (range 8)) "\u3000"
  232.                          #:before-first "\u3000" #:after-last "\u3000"))))
  233.  
  234. (define (symbols->strings lol)
  235.   (cond
  236.     [(pair? lol) (map symbols->strings lol)]
  237.     [(symbol? lol) (symbol->string lol)]
  238.     [else lol]))
  239.  
  240. (define (parse-move in)
  241.   (match (symbols->strings in)
  242.     [`(,x,y) #:when (and (integer? x) (integer? y)) in]
  243.     [(regexp "([a-hA-h])([1-8])" (list _ x y))
  244.      (list (char->integer (char- (char-upcase (car (string->list x))) #\A))
  245.            (- 8 (string->number y)))]
  246.     [_ '(-1 -1)]))
  247.  
  248. (define (all-valid-moves brd [black? #f])
  249.   (define ally? (if black? black-piece? white-piece?))
  250.   (for/fold
  251.    {[acc '()]}
  252.    {[row brd]
  253.     [y (in-naturals)] #:when #t
  254.     [cell row]
  255.     [x (in-naturals)] #:when (ally? cell)}
  256.     (append (valid-moves brd x y) acc)))
  257.  
  258. ; #|
  259. ;; plays a game. returns void if successful, and 'quit if the user quit.
  260. (define {game [brdls `(,start-board)] [black? #f]}
  261.   (define ally? (if black? black-piece? white-piece?))
  262.   (define brd (car brdls))
  263.   (print-stars brd '())
  264.   (define all-moves (all-valid-moves brd black?))
  265.   (cond
  266.     [(null? all-moves)
  267.      (printf "~a is in checkmate! ~a wins!\nRestart? (y/n)\n"
  268.              (if black? 'Black 'White) (if black? 'White 'Black))
  269.      (match (read)
  270.        [`y (printf "restarting.\n") (game `(,start-board) #f)]
  271.        [`n (printf "quiting.\n")])]
  272.     [else
  273.      (printf "~a's turn!\n" (if black? 'Black 'White))
  274.      (let prompt {}
  275.        (match (read)
  276.          [`move
  277.           (define start (parse-move (read)))
  278.           (cond
  279.             [(or (not (valid-coord? start))
  280.                  (not (ally? (get-cell brd start))))
  281.              (printf "Please input a valid coordinate.\n") (prompt)]
  282.             [(let {[valid-ls (valid-moves brd start)]}
  283.                (print-stars brd (cons start valid-ls))
  284.                (define end (parse-move (read)))
  285.                (and (member end valid-ls) end))
  286.              => (λ (end) (game (cons (do-move brd start end) brdls) (not black?)))]
  287.             [else
  288.              (printf "Please input a valid move.\n") (prompt)])]
  289.          [`undo (printf "Undoing. Please wait 3-5 minutes.\n") (time (sleep 10))
  290.           (game (cdr brdls) (not black?))]
  291.          [`resign (printf "Restarting.\n")
  292.           (game `(,start-board) #f)]
  293.          [(or (? eof-object?) `quit) 'quit]
  294.          [_ (printf "Didn't understand. Please enter another command.\n")
  295.           (prompt)]))])) ; |#
  296.  
  297. (define (setup [brd empty-board])
  298.   3)
  299.  
  300. (define (main)
  301.   (define (quit) (printf "Quiting.\n"))
  302.   (printf "
  303. Welcome to Chess!
  304. Enter \"setup\" if you'd like to setup the board.
  305. Enter \"play\" if you'd like to play a game.
  306. Enter \"quit\" at any time to quit the program.
  307. ")
  308.  
  309.   (define first-setup? (box #t))
  310.   (define first-game? (box #t))
  311.  
  312.   (let menu {[brd empty-board]}
  313.     (match (read)
  314.       [`setup (menu (setup brd))]
  315.       [`play (define res (game (list (if (equal? brd empty-board) start-board brd))))
  316.              (if (eq? res 'quit) (quit) (menu brd))]
  317.       [`quit (quit)]
  318.       [_ (printf "Didn't understand. Please enter another command.\n")
  319.          (menu brd)])))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement