<commit_before>;; Unfinished port of one-day-i-will-play-chess

(to ((main<- strategy-names) args)
  (display "(Moves look like 'e2e3')\n\n")
  (play-chess (strategy-names (args 1))
              (strategy-names (args 2))))

(to (play-chess white-strategy black-strategy)
  (play (initial-chess-board<-) `(,white-strategy ,black-strategy)))

(to (play board players)
  (begin playing ((board board))
    (print board)
    (unless board.outcome
      (display "\n\n")
      (playing (board .play-turn players)))))

(to (human-player board)
  (begin asking ()
    (display ("~d, your move? " .format (side-name board.mover)))
    (may stdin.read-line  ;TODO extract the stdin cap
      (be (? eof?) {resign})
      (be answer (or (board .parse-move answer)
                     (do (display "Illegal move\n")
                         (asking)))))))

(to (random-player<- rng)
  (to (random-player board)
    (rng .choice (as-list board.gen-legal-moves))))

(to (greedy-player board)
  (for min-by ((move board.gen-legal-moves))
    (greedy-evaluate (update move board))))

(to (minimax-player<- depth)
  (to (player board)
    (for min-by ((move board.gen-legal-moves))
      (minimax-evaluate (update move board) depth))))

;; Return the mover's weighted piece advantage.
(to (greedy-evaluate board)
  (let total (sum (each piece-values board.squares)))
  ;; Just a little randomness makes play less boring:
  ;;XXX need to set up with an rng
  ;; total += random.uniform(0, 0.001)
  (may board.mover
    (be 'white (- total))
    (else      total)))

;; TODO not really tested
(to (minimax-evaluate board depth)
  (may depth
    (be 0 (greedy-evaluate board))
    (else (may board.get-piece-moves
            (be '() 0)
            (be moves (- (min @(for each ((move moves))
                                 (minimax-evaluate (update move board)
                                                   depth.-)))))))))

(let piece-values
  (map<- '((#\space 0)
           (#\-     0))))
(for each! ((p "pnbrqk")
            (v '(10 31 33 50 90 10000)))
  (piece-values .set! p.lowercase v)
  (piece-values .set! p.uppercase (- v)))

(to (initial-chess-board<-)
  ;; XXX ok, what rep is nicest here?
  (let squares '("----------"           ;TODO a vector instead?
                 "-rnbqkbnr-"
                 "-pppppppp-"
                 "-        -"
                 "-        -"
                 "-        -"
                 "-        -"
                 "-PPPPPPPP-"
                 "-RNBQKBNR-"
                 "----------"))
  (let castling '((#yes #yes) (#yes #yes))) ;TODO vector instead?
  (board<- 'white squares castling #no #no))

(to (board<- mover squares castling en-passant-target outcome-param)
  (make board

    (to _.mover
      mover)

    (to (_ .selfie sink)
      (let lines (for each ((line (squares .slice 1 9)))
                   (line .slice 1 9)))
      (for each! ((`(,i ,line) lines.items))
        (format .to-sink sink "~w|" (- 8 i))
        (for each! ((`(,j ,piece) line.items))
          (format .to-sink sink " ~d" (if (and (= piece #\space)
                                               ((+ i j) .odd?))
                                          #\. ; An empty black square.
                                          piece)))
        (format .to-sink sink "\n"))
      (format .to-sink sink " +----------------\n")
      (format .to-sink sink "   a b c d e f g h    ~d\n"
              (may board.outcome
                (be #no   ("~d to move" .format (side-name mover)))
                (be 'draw "A draw.")
                (be w     ("~d wins!" .format (side-name w))))))

    ;; Return #no, draw, black, or white (meaning the winner).
    (to _.outcome
      (hm (or outcome-param)
          (if board.checkmate?             (opponent mover))
          (if board.get-piece-moves.empty? 'draw)
          (else                            #no)))

    ;; Is the player to move checkmated?
    (to _.checkmate?  ;;XXX are we getting this at the start? why?
      ;; Or: is the mover in check now, and in check after every possible move?
      ;; XXX also seems buggy in other ways, though these boards are hard to read in the console
      (to (in-check?)                    ;XXX redundant and untested. Not yet in the Python version.
        (let my-king (may mover
                       (be 'white #\K)
                       (be 'black #\k)))<commit_msg>tweak<commit_after>;; Unfinished port of one-day-i-will-play-chess

(to ((main<- strategy-names) args)
  (display "(Moves look like 'e2e3')\n\n")
  (play-chess (strategy-names (args 1))
              (strategy-names (args 2))))

(to (play-chess white-strategy black-strategy)
  (play (initial-chess-board<-) `(,white-strategy ,black-strategy)))

(to (play board players)
  (begin playing ((board board))
    (print board)
    (unless board.outcome
      (display "\n\n")
      (playing (board .play-turn players)))))

(to (human-player board)
  (begin asking ()
    (display ("~d, your move? " .format (side-name board.mover)))
    (may stdin.read-line  ;TODO extract the stdin cap
      (be (? eof?) {resign})
      (be answer (or (board .parse-move answer)
                     (do (display "Illegal move\n")
                         (asking)))))))

(to (random-player<- rng)
  (to (random-player board)
    (rng .choice (as-list board.gen-legal-moves))))

(to (greedy-player board)
  (for min-by ((move board.gen-legal-moves))
    (greedy-evaluate (update move board))))

(to (minimax-player<- depth)
  (to (player board)
    (for min-by ((move board.gen-legal-moves))
      (minimax-evaluate (update move board) depth))))

;; Return the mover's weighted piece advantage.
(to (greedy-evaluate board)
  (let total (sum (each piece-values board.squares)))
  ;; Just a little randomness makes play less boring:
  ;;XXX need to set up with an rng
  ;; total += random.uniform(0, 0.001)
  (may board.mover
    (be 'white (- total))
    (else      total)))

;; TODO not really tested
(to (minimax-evaluate board depth)
  (may depth
    (be 0 (greedy-evaluate board))
    (else (may board.get-piece-moves
            (be '() 0)
            (be moves (- (min @(for each ((move moves))
                                 (minimax-evaluate (update move board)
                                                   depth.-)))))))))

(let piece-values
  (map<- '((#\space 0)
           (#\-     0))))
(for each! ((p "pnbrqk")
            (v '(10 31 33 50 90 10000)))
  (piece-values .set! p.lowercase v)
  (piece-values .set! p.uppercase (- v)))

(to (initial-chess-board<-)
  ;; XXX ok, what rep is nicest here?
  (let squares '("----------"           ;TODO a vector instead?
                 "-rnbqkbnr-"
                 "-pppppppp-"
                 "-        -"
                 "-        -"
                 "-        -"
                 "-        -"
                 "-PPPPPPPP-"
                 "-RNBQKBNR-"
                 "----------"))
  (let castling '((#yes #yes) (#yes #yes))) ;TODO vector instead?
  (board<- 'white squares castling #no #no))

(to (board<- mover squares castling en-passant-target outcome-param)
  (make board

    (to _.mover
      mover)

    (to (_ .selfie sink)
      (let lines (each (_ .slice 1 9)
                       (squares .slice 1 9)))
      (for each! ((`(,i ,line) lines.items))
        (format .to-sink sink "~w|" (- 8 i))
        (for each! ((`(,j ,piece) line.items))
          (format .to-sink sink " ~d" (if (and (= piece #\space)
                                               ((+ i j) .odd?))
                                          #\. ; An empty black square.
                                          piece)))
        (format .to-sink sink "\n"))
      (format .to-sink sink " +----------------\n")
      (format .to-sink sink "   a b c d e f g h    ~d\n"
              (may board.outcome
                (be #no   ("~d to move" .format (side-name mover)))
                (be 'draw "A draw.")
                (be w     ("~d wins!" .format (side-name w))))))

    ;; Return #no, draw, black, or white (meaning the winner).
    (to _.outcome
      (hm (or outcome-param)
          (if board.checkmate?             (opponent mover))
          (if board.get-piece-moves.empty? 'draw)
          (else                            #no)))

    ;; Is the player to move checkmated?
    (to _.checkmate?  ;;XXX are we getting this at the start? why?
      ;; Or: is the mover in check now, and in check after every possible move?
      ;; XXX also seems buggy in other ways, though these boards are hard to read in the console
      (to (in-check?)                    ;XXX redundant and untested. Not yet in the Python version.
        (let my-king (may mover
                       (be 'white #\K)
                       (be 'black #\k)))
{'fraction_non_alphanumeric': 0.15637109642124458, 'fraction_numerical': 0.00752222475495783, 'mean_word_length': 1.6233183856502242, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 4, 'word_list_counts': {'cursed_substrings.json': 18, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1023979', 'n_tokens_mistral': 2876, 'n_tokens_neox': 2685, 'n_words': 878}