Skip to content

Commit fb740ed

Browse files
committed
Faster board evaluation
1 parent f54a7ac commit fb740ed

3 files changed

Lines changed: 37 additions & 12 deletions

File tree

src/swordfight/ai.clj

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
black-king black-queen black-rook
1111
black-bishop black-knight black-pawn
1212
empty-square white black
13-
piece-type ->piece]]
13+
piece-type ->piece move-piece
14+
notation->coords]]
1415
#_[taoensso.tufte :refer [defnp p profiled profile]]
1516
#_[swordfight.profiling]))
1617

@@ -102,6 +103,14 @@
102103
(for [[y x] all-coords]
103104
[(get-in board [y x]) [y x]]))))
104105

106+
(defn board-value-delta [board board' move]
107+
(let [[move-from move-to] move
108+
[from-pos to-pos] [move-from (subs move-to 0 2)]
109+
[from-idx to-idx] (map notation->coords [from-pos to-pos])]
110+
(- (piece-val-with-bonus (get-in board' to-idx) to-idx)
111+
(piece-val-with-bonus (get-in board to-idx) to-idx)
112+
(piece-val-with-bonus (get-in board from-idx) from-idx))))
113+
105114
(def checkmated-val {white -100000 black 100000})
106115
(defn stalemated-val [board] (/ (eval-board board) 4))
107116

@@ -113,10 +122,23 @@
113122

114123
(defn move-evaluation [game-state alpha beta depth piece-move]
115124
(let [state-after-move (move game-state piece-move)
125+
extra-board-changes (not= (:board state-after-move)
126+
(first (move-piece (:board game-state)
127+
piece-move)))
128+
evaled-state-after-move (assoc state-after-move
129+
:board-value
130+
(if extra-board-changes
131+
;; full board reevaluation only after
132+
;; castling, en passant and promotions
133+
(eval-board (:board state-after-move))
134+
(+ (:board-value game-state)
135+
(board-value-delta (:board game-state)
136+
(:board state-after-move)
137+
piece-move))))
116138
move-value (if (or (= depth 1) @hurried-move)
117-
(eval-board (:board state-after-move))
139+
(:board-value evaled-state-after-move)
118140
(second
119-
(best-move state-after-move alpha beta (dec depth))))]
141+
(best-move evaled-state-after-move alpha beta (dec depth))))]
120142
[piece-move move-value]))
121143

122144
(defn best-move [{:keys [board turn] :as game-state} alpha beta depth]
@@ -172,8 +194,10 @@
172194

173195
(defn computer-move [game-state]
174196
(let [moves-cnt (:moves-cnt game-state)
197+
board-value (eval-board (:board game-state))
198+
evaled-board-game-state (assoc game-state :board-value board-value)
175199
[square-from square-to] (if (and (< moves-cnt early-game-turns)
176200
(false? (:edited game-state)))
177-
(early-move game-state)
178-
(midgame-move game-state))]
201+
(early-move evaled-board-game-state)
202+
(midgame-move evaled-board-game-state))]
179203
[square-from square-to]))

src/swordfight/game_rules.clj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@
213213
[last-m-from last-m-to last-moved-piece] (:last-move game-state)
214214
[[last-m-from-y _] [last-m-to-y last-m-to-x]]
215215
(map notation->coords [last-m-from last-m-to])]
216-
;; We assume here the moves being made are (pseudo)legal:
216+
;; We assume here the moves being made are pseudolegal:
217217
(if (and (pawn? last-moved-piece)
218218
(= (Math/abs (- last-m-from-y last-m-to-y)) 2)
219219
(= last-m-to-y from-y)

test/swordfight/ai_test.clj

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
(:require [midje.sweet :refer [facts fact has-prefix]]
33
[swordfight.board :refer [white black ->board
44
white-pawn black-pawn white-king]]
5-
[swordfight.ai :refer [midgame-move]]))
5+
[swordfight.ai :refer [midgame-move eval-board]]))
66

77
(facts "about en passant moves"
88
(let [board (->board [" . . . . k . . . "
@@ -15,7 +15,7 @@
1515
" . . . . K . . . "])
1616
en-passant-move ["b4" "a3"]
1717
game-state {:board board :turn black :last-move ["a2" "a4" white-pawn]
18-
:moves-cnt 0}]
18+
:moves-cnt 0 :board-value (eval-board board)}]
1919
(fact "Engine makes an en passant move in an obvious scenario"
2020
(midgame-move game-state) => (has-prefix [en-passant-move])))
2121

@@ -28,7 +28,8 @@
2828
" . . . . . . . . "
2929
" . . . . K . . . "])
3030
forward-move ["b4" "b3"]
31-
game-state {:board board :turn black :last-move ["a3" "a4" white-pawn] :moves-cnt 0}]
31+
game-state {:board board :turn black :last-move ["a3" "a4" white-pawn]
32+
:moves-cnt 0 :board-value (eval-board board)}]
3233
(fact "Engine makes an obvious best move when en passant not possible"
3334
(midgame-move game-state) => (has-prefix [forward-move]))))
3435

@@ -51,7 +52,7 @@
5152
" . q . . K . . . "])
5253
promotion-move ["b2" "b1q"]
5354
game-state {:board board :turn black :last-move ["a5" "a6" white-pawn]
54-
:moves-cnt 10}]
55+
:moves-cnt 10 :board-value (eval-board board)}]
5556
(fact "Engine promotes pawns to queens"
5657
(midgame-move game-state) => (has-prefix [promotion-move])))
5758

@@ -73,7 +74,7 @@
7374
" R N n . . . . . "])
7475
promotion-move ["c2" "c1n"]
7576
game-state {:board board :turn black :last-move ["b3" "a2" white-king]
76-
:moves-cnt 10}]
77+
:moves-cnt 10 :board-value (eval-board board)}]
7778
(fact "Engine promotes pawns to knights"
7879
(midgame-move game-state) => (has-prefix [promotion-move]))))
7980

@@ -96,6 +97,6 @@
9697
" R N . . . . . . "])
9798
regular-pawn-attack ["g2" "h3"]
9899
game-state {:board board :turn white :last-move ["h4" "h3" black-pawn]
99-
:moves-cnt 10}]
100+
:moves-cnt 10 :board-value (eval-board board)}]
100101
(fact "Engine chooses to attack with pawn"
101102
(midgame-move game-state) => (has-prefix [regular-pawn-attack]))))

0 commit comments

Comments
 (0)