62 Commits

Author SHA1 Message Date
0145664567 minor fixes
Some checks are pending
pre-release / Pre Release (push) Waiting to run
2025-02-16 09:30:59 +01:00
959ecdeb7d added the opponenent pawn attack map move better ordering 2025-02-16 09:29:50 +01:00
adf21ee021 minor stuff 2025-02-09 21:18:51 +01:00
989225c2d7 fixed bugs 2025-02-07 20:08:25 +01:00
aef6fc39e3 fixed slight bug 2025-02-07 19:39:52 +01:00
2260cd918a implemented promotion for white 2025-02-07 19:39:51 +01:00
3bc5b75f1e implemented v4 that resolves all the captures
after looking at the next two moves (all of them)
2025-02-07 19:14:09 +01:00
377e5dfdcc implemented move ordering to improve on alpha_beta
pruning
2025-02-07 18:24:57 +01:00
10de9828be implemented alpha beta pruning 2025-02-07 17:49:08 +01:00
9942832b18 caching check and nlm 2025-02-07 17:35:14 +01:00
5b45fc32c0 annoying 2025-02-07 16:18:11 +01:00
d28008d913 committing to stash and compare 2025-02-07 15:08:53 +01:00
86beb9cc85 renamed v1_simple to v1_pure_minimax 2025-02-07 15:08:10 +01:00
8edde1a8b1 caching checks and no legal moves 2025-02-07 14:15:10 +01:00
182d183247 committing to stash and compare 2025-02-07 14:02:56 +01:00
1b14ed693d made small opti 2025-02-07 12:04:20 +01:00
a80fc9482d base for testing optimization 2025-02-07 11:08:59 +01:00
88b2d01cf8 made v1_simple multithreaded again 2025-02-07 10:03:37 +01:00
979d44fad0 fixed small bug 2025-02-07 10:03:32 +01:00
db87c2ec8b minor stuff 2025-02-07 09:52:37 +01:00
f3e28d2646 found better terminal condition for v1_simple 2025-02-07 09:52:09 +01:00
7e888bba61 made v1_simple single threaded because it was
getting messy
2025-02-07 09:51:49 +01:00
1d83c066f6 made v0_random thinking longer 2025-02-07 09:51:22 +01:00
2764787e63 made v1_simple look 4 moves into the future, it's
parallelized
2025-02-07 00:34:22 +01:00
c71cabb3cd fixed tests 2025-02-07 00:29:49 +01:00
0525bd565e minor fixes 2025-02-07 00:29:39 +01:00
695cef33df fixed test execution 2025-02-07 00:29:17 +01:00
75b6c35cc5 if the ai found the move before the thinking_time
is over, stop the thread to return
2025-02-06 23:46:34 +01:00
74fa99fe7b faking some thought for the random player 2025-02-06 23:46:06 +01:00
0274f44647 minor fix 2025-02-06 23:46:00 +01:00
a5abe39aa4 added a position to perft 2025-02-06 23:37:55 +01:00
e056ef0805 minor modifications to ai v1 2025-02-06 22:57:06 +01:00
dc6631f79c made AIs aware what colour they were playing 2025-02-06 22:56:41 +01:00
d6aa977a15 added the 50-move draw rule 2025-02-06 22:39:11 +01:00
6e567f2f11 added the check for insufficient material 2025-02-06 22:34:48 +01:00
fced9757c2 made figuring whether the board is terminal easier 2025-02-06 22:10:47 +01:00
04134f013c implemented the ai vs ai controller
Some checks failed
pre-release / Pre Release (push) Has been cancelled
2025-02-06 21:21:18 +01:00
47cf8b3539 unified controller interface 2025-02-06 20:59:05 +01:00
a47130e5d0 fixed variable name 2025-02-06 20:41:17 +01:00
e0a52f57b7 made the thinking time of AIs common to all of them 2025-02-06 20:38:27 +01:00
74e4d596a7 very easily implemented the human_vs_ai controller
Some checks failed
pre-release / Pre Release (push) Waiting to run
tagged-release / Tagged Release (push) Has been cancelled
(god i love a good design)
2025-02-06 20:12:12 +01:00
60e1a77fcb fixed slight bug 2025-02-06 20:11:58 +01:00
46a835df4b moved some code around because it made more sense 2025-02-06 20:11:11 +01:00
10257351cb created a no-op gui (to run the games without
showing them, can be useful)
2025-02-06 19:53:11 +01:00
96f0ec5399 implemented full manual controller 2025-02-06 19:42:48 +01:00
e376d67c83 added to string for piece and colour 2025-02-06 19:42:30 +01:00
d8557d02df now showing target squares of legal moves 2025-02-06 19:11:30 +01:00
d08a5cca39 extracted a function to utils 2025-02-06 19:11:03 +01:00
058616fa89 extracted the drawing of the annotation in it's
own function
2025-02-06 18:45:11 +01:00
b8627ace14 quick little refactoring 2025-02-06 18:34:54 +01:00
77f77ac04e now we draw the annotations for the squares 2025-02-06 18:23:44 +01:00
56b74318c1 moved colours 2025-02-06 18:23:19 +01:00
811acaa479 drawing pieces correctly 2025-02-06 17:58:49 +01:00
1ae0cad802 fixed colours 2025-02-06 17:34:37 +01:00
f540246817 we're starting to get somewhere here 2025-02-06 17:31:16 +01:00
42484f4217 small refactoring to get rid of compiler warning 2025-02-06 16:18:13 +01:00
72f3431418 big refactoring: put everything in model to allow
for better mvc structure (yes i'm doing view in cpp)
2025-02-06 16:15:56 +01:00
1231e4da92 added the less than operator to store the objects
in maps
2025-02-06 15:57:21 +01:00
32c7832001 cleaned up the ais a bit 2025-02-06 15:57:06 +01:00
5f093907f3 small refactoring 2025-02-06 15:45:32 +01:00
6d8a3f7dc0 made lambda capture values by reference, not by
value
2025-02-06 10:55:25 +01:00
108c0c3b90 added 500 equal positions to start from for the
AIs to fight
2025-02-06 10:44:54 +01:00
62 changed files with 2029 additions and 368 deletions

View File

@ -1,4 +1,5 @@
CXXFLAGS += -O3 -Wall
# CXXFLAGS += -pg
# Add .d to Make's recognized suffixes.
SUFFIXES += .d
@ -28,7 +29,7 @@ obj/%.o:
$(CXX) $(CXXFLAGS) -o $@ -c $<
main: $(OBJFILES)
$(CXX) $(LDFLAGS) $(OBJFILES) $(LOADLIBES) $(LDLIBS) -o main
$(CXX) $(CXXFLAGS) $(OBJFILES) $(LOADLIBES) $(LDLIBS) -o main -lsfml-graphics -lsfml-window -lsfml-system
clean:
rm -rf obj/* $(DEPFILES) test_bin/
@ -46,7 +47,7 @@ LIBS := $(filter-out obj/main.o,$(OBJFILES))
test_bin/%: tests/%.cpp $(LIBS)
@echo $(LIBS)
@mkdir -p $(dir $@)
$(CXX) $(CXXFLAGS) -o $@ $< $(LIBS)
$(CXX) $(CXXFLAGS) -o $@ $< $(LIBS) -lsfml-graphics -lsfml-window -lsfml-system
# The 'test' target builds all tests and then runs each one.
.PHONY: test

BIN
cpp/res/arial.ttf Normal file

Binary file not shown.

500
cpp/res/equal_positions.fen Normal file
View File

@ -0,0 +1,500 @@
r1bq1rk1/pp3pbp/2n1pnp1/2pp4/2P5/2NPP1P1/PP2NPBP/R1BQ1RK1 w - - 0 9
2kr2nr/ppp1b1pp/2n5/2N1p3/P5q1/3PQN2/1PP2PP1/R3KB1R w KQ - 0 16
r4rk1/pp1b1ppp/4pn2/2b5/2P5/2N5/PP2BPPP/R1BR2K1 w - - 0 13
r1bq1rk1/1p3ppp/p1n1pn2/2b5/2B5/2N1PN2/PP1B1PPP/R2Q1RK1 w - - 0 10
1q2rrk1/pp1n1ppp/2pbpn2/3p3b/2PP4/1P1BPN1P/PB1NQPP1/2RR2K1 w - - 7 14
r2qr1k1/pp3ppp/4b1n1/2pNb3/2P5/1P5P/PB2BPP1/R2Q1RK1 w - - 0 17
3q1rk1/3nbpp1/r1p1pn1p/2Pp2B1/3P4/2N1PN2/5PPP/2RQ1RK1 w - - 0 15
rnbq1rk1/pp4pp/3b4/2pPpp2/2P1p3/4P1P1/PP1N1PBP/R1BQ1RK1 w - - 0 12
r2qkb1r/pp4pp/2npbn2/2p1p3/7N/2PP4/PP2BPPP/RNBQ1RK1 w kq - 3 9
r4rk1/pbpn2pp/1p2p1q1/4Pp2/2P5/5PP1/PPQB2BP/R3R1K1 w - - 1 18
rn2k2r/pp1b1ppp/1qpp1b2/3Pp3/2P1P3/2N2N2/PP3PPP/R2QKB1R w KQkq - 0 9
r2qr1k1/p1p2pp1/2pp1n1p/2b3B1/4P1b1/2NB4/PPPQ1PPP/R4RK1 w - - 0 12
r1bqr1k1/ppp2p1p/3p1pn1/3P4/2PQ4/5NP1/P4PBP/R4RK1 w - - 0 15
r3k1nr/pp3bpp/2pb1n2/5p1P/8/2NP3N/PPP2PB1/R1B1K2R w KQkq - 10 17
r2qk1nr/pp3pp1/2nb2b1/2ppp3/6P1/P2PP3/1PPNQ1BP/R1B1K1NR w KQkq - 1 10
r1bqk2r/p4ppp/2p2n2/3pp3/4P3/P1b2P2/1PPB2PP/R2QKB1R w KQkq - 0 10
r2q1rk1/pn1bbppp/2p2n2/4p1N1/1P6/1BP5/P2P1PPP/RNBQK2R w KQ - 3 12
r1bq1rk1/1p2bp1p/p2ppnpP/2p1n3/4P3/1BPP2B1/PP2QPP1/RN2K1NR w KQ - 0 13
r1bq1rk1/4bpp1/p3pn1p/1p2n3/2pP1B2/2N1P2P/PPB2PP1/R2Q1RK1 w - - 0 14
2kr2nr/1ppn1pp1/p2p3p/3Pp1q1/4P3/2N2B2/PPP2PPP/R1Q2RK1 w - - 2 12
r1b2rk1/1pp3p1/p1nb1q1p/3p1p2/1P1P4/P3PN1P/1B1n1PP1/RB1Q1RK1 w - - 0 14
1k1r3r/pppnqpp1/3b2p1/3B2P1/8/4P1PP/PPPNQ3/2KR3R w - - 1 18
r3k2r/ppp2ppp/1nn5/4P3/1bP3b1/5N2/PP2BPPP/R1BNK2R w KQkq - 5 10
r2q1rk1/1pp1ppbp/p2p1np1/2nP1b2/2P5/1PN1PN2/PB2BPPP/R2QK2R w KQ - 0 10
r2qk2r/pp3ppp/2n1bn2/2bp4/8/2N1P1P1/PP3PBP/R1BQK1NR w KQkq - 3 9
1r3rk1/p1q2ppp/2pb1n2/2pp4/5P2/3P1Q1P/PPP1N1P1/R1B1R1K1 w - - 5 15
2r2rk1/1p1nqpbp/pn4p1/Q1pp4/8/2PPB2P/PP1NNPP1/R4RK1 w - - 2 16
3q1rk1/4ppbp/3p1np1/1r6/1p1BP3/1P3P2/P2Q2PP/2RN1RK1 w - - 0 18
r2q1rk1/4bppp/pp2p3/2p2n2/8/1PBPP1P1/P4PNP/2RQ1RK1 w - - 1 16
r2qkb1r/2p1pppp/p1n1b3/1p6/B2P4/2P1P3/P4PPP/R1BQK1NR w KQkq - 0 9
r2q1rk1/1p2bppp/p1n1pn2/3p4/3P4/2N1PB2/PPQ2PPP/R1B1R1K1 w - - 2 12
r1b1kbnr/p1p2ppp/2p5/8/4q3/5N2/PPP2PPP/RNBQK2R w KQkq - 0 9
r1b1kbnr/4pppp/p7/1P6/1np5/8/1P2PPPP/R1BNKBNR w KQkq - 1 9
2kr1br1/pp1b2pp/2n1p3/5p2/8/1PB1P1P1/P3NP1P/R3KB1R w KQ - 1 14
rn1q1rk1/pb2bppp/1p2pn2/3p4/3P4/2N1PN1P/PP2BPP1/R1BQ1RK1 w - - 2 10
rnb1k2r/pp2n1pp/2pb1p2/3pN3/3P4/2N5/PPP2PPP/R1B1KB1R w KQkq - 0 9
rn1qr1k1/pb3ppp/1p2pn2/2ppN3/2PP4/P1b1P3/1P1BBPPP/R2Q1RK1 w - - 0 11
r1b2rk1/2qn1ppp/p2bpn2/1p1p4/1P1P4/P2B1NP1/2P1NP1P/R1BQ1RK1 w - - 0 12
rn1qk2r/pbp2pp1/1p2pb1p/3p4/3P4/2N1PNP1/PPP2PBP/R2QK2R w KQkq - 0 9
r4rk1/pp2ppbp/2n3p1/2qp1b2/3P4/1P2P3/PB1NBPPP/2R2RK1 w - - 0 15
r4rk1/ppBq1ppp/2n5/2nN3b/1P6/P4N1P/4BPP1/b2Q1RK1 w - - 0 17
r2qk2r/p2n1ppp/3bpn2/3p1b2/3P4/2N5/PP2PPPP/R1BQKBNR w KQkq - 5 9
r2q1rk1/ppp1bppp/1nn1p3/8/3PP1b1/P1N2N2/1P2BPPP/R1BQ1RK1 w - - 5 10
r2q1rk1/pppb1ppn/2np3p/4p3/1P2P1P1/P2PbN1P/2P1QPB1/RN3RK1 w - - 0 12
2kr3r/ppp1nppp/4b3/3n4/2B5/2P2N2/PP3PPP/RN3RK1 w - - 0 12
r3kb1r/pp1bnppp/2n1p3/q2pP3/N2P1P2/3B1N2/PP4PP/R1BQK2R w KQkq - 9 11
2kr2nr/pp1b4/2n1p3/P2pPpqp/2pP2p1/2P1N1P1/1P3PBP/RN1QK2R w KQ f6 0 15
r2q1rk1/1p1bbppp/p1n1p3/8/4P3/2P1BN2/P2QBPPP/R3K2R w KQ - 4 13
r3r3/pp1kbppp/2bp4/3n4/3N1B2/2N5/PPP2PPP/R3R1K1 w - - 6 15
r2qk2r/pp3ppp/2npbn2/4p1B1/1b2P3/2N2P2/PPPQN1PP/R3KB1R w KQkq - 1 10
rnbq1rk1/pp2b1pp/2p5/3p1p2/3Pn2N/2N3P1/PP2PPBP/R1BQ1RK1 w - - 7 10
r3kb1r/1pp1qpp1/p1n4p/3pPb2/3P1P2/5N2/PP4PP/RNBQ1RK1 w kq - 2 12
r4bnr/1pkb2pp/p1n2p2/2p1p3/2N5/2P1P1P1/PP2NPBP/R1B1K2R w KQ - 2 14
2kr3r/ppp1nppp/6q1/5b2/3p4/3P1P2/PPPQ1KPP/R1B2B1R w - - 0 15
r3k2r/1p1qbppp/p3pn2/3p2B1/8/2N2Q2/PPP2PPP/2KRR3 w kq - 2 17
r3kb1r/pp3p1p/1qn1bpp1/1B1p4/3P4/1QN1P3/PP3PPP/R3K1NR w KQkq - 3 10
rnbq1rk1/5ppp/1p1b1n2/3pp3/1P6/P1P1P3/1B3PPP/RN1QKBNR w KQ - 1 9
r1bq1rk1/ppp2pp1/2n2p1p/8/1bBP4/2N1PN2/PP3PPP/R2QK2R w KQ - 1 9
r3k3/pp1n1ppr/3bb2p/2p5/8/4BN2/PPP2PPP/RN2K2R w KQq - 0 13
r1bqr1k1/pp1nppbp/2pp2p1/3P4/2PP4/1P1BB3/P2Q1PPP/R3K1NR w KQ - 2 12
r3kb1r/1p1n1ppp/p1p1p3/2Pp1bB1/3P4/1PN2P2/1P2P1PP/R3KB1R w KQkq - 0 12
r3k2r/ppp1n1pp/2nppq2/4p3/1P1bP3/P1N2N1P/2PP1PP1/R1BQ1RK1 w kq - 1 10
rn1qr1k1/1p3pbp/p2p1np1/2pP1bB1/2P5/2N2N2/PP2BPPP/R2Q1RK1 w - - 2 12
1k1rr3/1ppnqppp/4b3/1N1pP3/8/3B4/PPPbQPPP/1K1R3R w - - 0 16
3rk2r/ppp1bppp/5nb1/4p3/2B1P3/5P1P/PPP3P1/RNB2RK1 w k - 1 12
r2qk2r/p1pn1pp1/2pbpn1p/3p4/3P1B2/P3PN1P/1PP1NPP1/R2QK2R w KQkq - 0 11
r1bq1rk1/pp3pbp/2np1np1/2p1p3/4P3/P1NP1N1P/1PPBBPP1/R2QK2R w KQ - 4 9
r1bq1r2/pp2ppkp/3p1np1/8/3nP3/2N5/PPPQBPPP/R3K2R w KQ - 0 11
rn1q1rk1/pb3ppp/1p2p3/2pn4/8/1P1P1NP1/Pb1NPPBP/R1Q2RK1 w - - 0 12
r4b1r/pppkp1p1/2nq1nQ1/3p3p/3P3P/4PP2/PPP5/RNB1K1NR w KQ - 3 12
r2qk1nr/1bp2ppp/p3p3/1p2P3/1P1P4/1B6/P2N1PPP/R2Q1RK1 w kq - 4 18
r1bqk2r/p1p2ppp/2p5/3p4/3Pn3/3Q1N2/PP3PPP/RN3RK1 w kq - 0 12
r2q1rk1/pbp1bppn/1p1p3p/8/4P2B/2N1QN2/PPP2PPP/R2R2K1 w - - 4 14
r2q1rk1/p2bbppp/2pp1n2/4p1B1/Q3P3/2N2N2/PPP2PPP/R4RK1 w - - 8 11
r1bqk2r/2p1bpp1/p1np1n1p/1p2p3/2B1P3/2NPBN1P/PPPQ1PP1/R3K2R w KQkq - 0 9
r2q1rk1/1bp1bppp/p1np1n2/1p2p3/4P3/PB1P1N1P/1PP2PP1/RNBQ1RK1 w - - 1 10
rn1q1rk1/pp2p1bp/3ppnpB/2p5/3PP3/5P2/PPPQ2PP/RN2K1NR w KQ - 0 9
rn3rk1/3pqppp/b1pb4/1p2p3/2P1P3/BB1P1N2/5PPP/R2Q1RK1 w - - 1 16
r1bq1rk1/1pp1npbp/p1np2p1/4p3/1PP1P3/P2PBN2/4BPPP/RN1QK2R w KQ - 2 9
r1b2rk1/1pq1ppbp/p2p1np1/8/3NP3/2NQ1P2/PPP3PP/R1B2RK1 w - - 0 13
rnb2rk1/4qppp/p2pp3/2n5/1p1N4/1B4N1/PPP2PPP/R2QR1K1 w - - 4 14
r1q1kb1r/1p1npppp/p1p3b1/P1Pp4/1P1PnB2/2N4P/2Q1PPP1/R3KBNR w KQkq - 5 11
r2qk1nr/p2bbppp/2p1p3/3pP3/3P1P2/5N2/PP4PP/RNBQK2R w KQkq - 2 10
r1b2rk1/1pq1bppp/p1nppn2/6B1/P2NP3/1BN5/1PP2PPP/R2Q1RK1 w - - 7 11
r2qk2r/1bpn1pb1/pp1p2pp/8/1PPNP3/P2nBN1P/5PP1/1R1Q1RK1 w kq - 0 16
r1bqnrk1/pp1nbp1p/2p3p1/3p2B1/3P4/2NBP3/PPQ1NPPP/R4RK1 w - - 4 11
r2q1rk1/pbpnnppp/1p2p3/8/3PPP2/2NB1N2/PP4PP/R2QK2R w KQ - 4 11
r1b1k2r/1pp1bppp/p1p2n2/8/8/5N2/PPPPKPPP/RNB1R3 w kq - 3 10
r2qk2r/1b2nppp/p3p3/3pP3/8/1N1Qb3/PP3PPP/RN3RK1 w kq - 0 14
r3kb1r/ppp2ppp/2n2n2/4p3/2P5/3BPb1P/PP3PP1/RNBK3R w kq - 0 9
r3kb1r/ppp2pp1/2n3qp/4p3/2P3b1/P2P1N2/1P2BPPP/R1BQ1RK1 w kq - 1 11
rnb1k3/ppq1b2r/2p1pnN1/3p4/3P1P1P/2N5/PPPB2P1/R2QK2R w KQq - 1 14
r2qrbk1/pp1bnppp/3p4/3Pp3/8/1N4P1/PP2PPBP/R1BQ1RK1 w - - 1 14
2kr3r/pppbbppp/3q4/4n3/2B2B2/2P2Q2/PP3PPP/RN3RK1 w - - 2 13
rn2kbnr/pp2pppp/8/2p1P3/2Pp1B2/3P1q1P/PP3PP1/RN2KB1R w KQkq - 0 9
r4rk1/5ppp/p4n2/2bp1qB1/8/2N5/PP3PPP/R2Q1RK1 w - - 4 16
r1b2rk1/pppnqppp/8/4p3/4P2N/1P1P3P/1PP3P1/RN1QK2R w KQ - 0 13
r1b1kb1r/p4ppp/2p5/2pp2B1/6n1/3P1N2/PPP1KPPP/RN5R w kq - 1 11
rnbq1rk1/pp2bpp1/4pn1p/2p5/2BPP2B/2N2N2/PP3PPP/R2QK2R w KQ - 0 9
r3kb1r/2Bn1ppp/2ppp1n1/8/2B1P3/2P5/PP3PPP/RN2K2R w KQkq - 3 13
r1bq1rk1/ppp1bppp/1n6/4p3/8/1PN4P/1PPPNPP1/R1BQ1RK1 w - - 0 12
r1bqk2r/np3ppp/1bpp1n2/pP2p3/P3P1P1/3P1N1P/2P2P2/RNBQKB1R w KQkq - 0 10
r3k2r/2p1bpp1/p1nqp2p/1p1p1b2/1P1Pn3/PNPBPN1P/1B3PP1/R2QK2R w KQkq - 4 12
r1bqk2r/1pp2pb1/p2p1npp/3Pp2n/1P2P3/2PB1PP1/P2NN2P/R1BQK2R w KQkq - 1 12
r4rk1/pp2npp1/1qpNb2p/4P3/4P3/4N3/PPP3PP/R2Q1RK1 w - - 3 16
1k1rr3/1pp3pp/p1nbRp1n/8/3P4/P1N2N1P/1P3PP1/R1B3K1 w - - 1 18
r3k1nr/p3bpp1/1pqp3p/3Np3/4P2B/3Q1b2/PPP2PPP/R4RK1 w kq - 0 13
2bqr1k1/r3bppp/2n1pn2/p1pp4/PpP5/1P1PPNP1/2QN1PBP/1RB2RK1 w - - 1 14
r2qkb1r/2p2ppp/p1np4/1p2p2n/1P2P3/P7/R1PP1PPP/1NBQ1RK1 w kq - 0 12
r1b1k1nr/1p4pp/1pn1pp2/3pP3/1b1P1P2/5N2/PP4PP/RNB1KB1R w KQkq - 1 10
2rq1rk1/pp1bbppp/4pn2/2p1N1B1/8/2NP4/PPP2PPP/R2Q1RK1 w - - 5 11
r2q1rk1/pp2bppp/2np1n2/2p1p3/4P3/1PNP1bPP/PBP2PB1/R2QK2R w KQ - 0 10
r1bqkbnr/3p1pp1/n3p2p/1p1P4/p1p1P3/P1P2N2/BP1N1PPP/R1BQK2R w KQkq - 0 11
r3k2r/pbqnbppp/1p2pn2/2pp4/Q1P5/P2P1NP1/1P1NPPBP/R1B2RK1 w kq - 1 10
r3kb1r/pp1nppp1/2p2n1p/8/5q2/2NP1B2/PPP2PPP/R1B2RK1 w kq - 0 11
r2q1rk1/ppp1ppbp/2np2p1/7n/2P1PP2/P1NPB2P/1P4P1/R2QKB1R w KQ - 1 12
r2q1rk1/p1n2p2/3p2pp/1ppPp3/4P2b/2PB2NP/PP3PP1/R2Q1RK1 w - - 0 18
r2q1rk1/p4ppp/1bp1p1n1/3pP3/1P1P4/P1N1BQ1P/5PP1/R3K2R w KQ - 3 15
r2qk2r/pppb1ppp/3p1n2/2b1n3/3NPB2/2P4P/PP2BPP1/RN1QK2R w KQkq - 3 10
rnbr2k1/pp3ppp/2p2bn1/4p3/2P5/1P2PNP1/PB3PBP/RN3RK1 w - - 0 12
r1br2k1/pppnbpp1/4p2p/3q4/8/P2PBN1P/1PP1BPP1/R2Q1RK1 w - - 0 13
r2qk1nr/ppp3bp/2n1bpp1/3p2P1/1P1Pp2P/4P3/P1PB1P2/RN1QKBNR w KQkq - 0 9
2kr1b1r/p1p1pppp/2p1bn2/8/3P4/2N5/PPP2PPP/R1B1K1NR w KQ - 0 10
r3kb1r/p4ppp/npp1pn2/2Pq4/N2P1B2/P7/1P3NPP/R2QK2R w KQkq - 2 15
r2qk2r/pp3ppp/3b1n2/2np4/6b1/P3PN2/1P2BPPP/RNBQK2R w KQkq - 4 10
r2qk2r/pp2bppp/3p4/2pnp3/3BP3/PP4P1/2PP1P1P/R2QK1NR w KQkq - 0 14
rn1q1rk1/pbp1bppp/1p1pp1n1/8/2B1P3/P1NP1N1P/1PP2PP1/R1BQ1RK1 w - - 0 9
r1b1k2r/pp4p1/1nppBn2/6Bp/3P4/P7/P4PPP/R3K1NR w KQkq - 4 14
2k1r2r/1ppn4/p2qppbb/1P1p1n1p/P2P1P1P/2N1P2B/2P1N3/R1BQK2R w KQ - 1 16
r1bq1rk1/p3b1pp/1p2p3/nBp1Pp2/3P4/2P1BN2/P1PQ2PP/R4RK1 w - - 4 14
rnbqk2r/1p3ppp/p3pb2/8/2BP4/2N2N2/PP3PPP/R2QK2R w KQkq - 0 10
r1bqk2r/pp1nbpp1/2p1pn1p/2Pp4/3P3B/2N1P3/PP3PPP/R2QKBNR w KQkq - 1 9
r2qk2r/pp4bp/n1pp1ppn/4p1B1/4P2P/P1NP1QP1/1PPK1PB1/R6R w kq - 0 13
r2qkb1r/1p3pp1/p1npbn1p/2p1p3/4P3/2NPBNP1/PPPQ1PBP/2KR3R w kq - 8 10
2rqk2r/pp1nbpp1/2n1p1p1/3p2B1/3P2P1/2P2PN1/PP5P/RN1Q1RK1 w k - 2 15
r1bq1rk1/pp1nppbp/2np2p1/8/2B1PB2/2N2N1P/PP2QPP1/R4RK1 w - - 1 11
r2qkb1r/pp2pppp/2b2n2/1B2n3/4p3/P1N5/1PP1QPPP/R1B1K1NR w KQkq - 0 9
r2qk1nr/pp1n2pp/2p1bp2/4b3/P7/1PB2N2/2PP2PP/RN1QKB1R w KQkq - 0 11
2r1r1k1/ppqn1ppp/3b4/3Pp3/7N/1P4P1/P3QP1P/R1B2RK1 w - - 1 18
rnbq1rk1/p3ppbp/1ppp2p1/4P3/3P1P2/2P3P1/PP4BP/RN1QK1NR w KQ - 0 10
r3k2r/ppp2ppp/2n1p3/3pP1q1/3P3n/5B1P/PPP1NPP1/R2Q1RK1 w kq - 6 12
rn2r1k1/ppp1bp2/3pbn1p/6p1/2N5/2NP2B1/PPP2PPP/2KR1B1R w - - 2 13
1r1q1rk1/pb1pppbp/2n2np1/2p5/1p2P1P1/6NP/PPPPNPB1/R1BQ1RK1 w - - 2 11
1rbq1rk1/b1p2pp1/2n4p/4p3/NnB5/3P1N1P/1P3PP1/R1BQ1R1K w - - 0 18
r2q1rk1/pp1n1ppp/2p1bn2/3pp3/2P1P3/P1PPBN1P/4BPP1/R2QK2R w KQ - 0 11
r2q1rk1/5ppp/p1p2nb1/3p4/1P2p3/4PPN1/1PP1N1PP/R2QK2R w KQ - 0 16
r1bq1rk1/1p2nppp/p1npp3/3p4/3P4/2NBPN2/PPP2PPP/R2Q1RK1 w - - 2 9
r2q1rk1/1p1n1ppp/p2pbb2/3Np3/4P3/1N6/PPP1BPPP/R2Q1RK1 w - - 2 12
r4rk1/pp3ppp/5n2/2bq4/8/5N2/PP3PPP/R1BQ1RK1 w - - 0 15
rn1qk2r/pp2ppbp/1n1p2p1/8/2PP2b1/5N2/PP2BPPP/RNBQ1RK1 w kq - 1 9
rn1q1rk1/pbp1bppp/1p3n2/3p2B1/3P4/P1N1PN2/1P3PPP/R2QKB1R w KQ - 1 9
rnbqk2r/1pp3pp/p2npp2/3p4/1P1P4/P3PN2/2P2PPP/RN1QKB1R w KQkq - 0 9
r1b1q1k1/1p3pbp/p4np1/3pr3/3Q4/N1P1BB1P/PP3PP1/R3K2R w KQ - 0 15
2rr2k1/pp2bpp1/1qp1pnp1/8/2PP1B2/1Q4P1/PP3PBP/3RR1K1 w - - 3 18
rnbq1rk1/pp2bpp1/3p1n1p/2p3B1/2B5/5N2/PPPN1PPP/R2QR1K1 w - - 0 11
r3kb1r/1p1b1pp1/pqn1p1p1/3pP3/P2P4/5N2/1P3PPP/RNBQ1RK1 w kq - 1 12
r1b2rk1/1pp1qppn/p1n1p2p/3p4/3P1P2/NPPBPNP1/P6P/R2QK2R w KQ - 1 12
r4rk1/ppp2ppp/2nq1b2/4p3/1PP3b1/P2P1N2/4BPPP/R1BQ1RK1 w - - 1 12
r3kb1r/3n1pp1/2ppbn2/1p2p3/p3P2p/P1PPBP2/1PB1N1PP/RN3RK1 w kq - 2 14
r1bq1rk1/p3ppbp/6p1/3p4/8/4BP2/PPP1B1PP/R2Q1RK1 w - - 0 13
r2q1rk1/pp1bppbp/2np1np1/1B6/3NP3/2P1B3/PP1N1PPP/R2Q1RK1 w - - 6 10
1r1qk1nr/p1pb1ppp/6n1/4P3/1b1PB3/2N5/PPP2PPP/R1BQK2R w KQk - 5 12
r2qkb1r/pbpp2pp/1pn2p2/4p3/1P1P1Pn1/2P1PNP1/P2Q3P/R1B1KBNR w KQkq - 1 10
r3kbnr/ppp2ppp/4b3/8/3p1P2/2N5/PPPP2PP/R1B1KB1R w KQkq - 0 9
rnbq1rk1/1p2bpp1/p1p1pn1p/3pB3/1P1P4/P1P2N2/3NPPPP/R2QKB1R w KQ - 3 9
r1b1k2r/pp1n1pp1/2pp1n2/4p1Bp/2B1P3/2PP4/P1P1NPPP/R3K2R w KQkq - 2 10
r3r1k1/pp3pb1/3p1qpp/3Pp3/4P1b1/2NQ1N2/PP3PPP/R4RK1 w - - 0 16
r1b1k1nr/1pq1bppp/p1n5/1Bpp4/P7/1P3N2/2PP1PPP/RNBQ1RK1 w kq - 0 9
r2qk2r/1p1nbppp/p1p1pn2/3pB3/1P1P4/P2PPN2/5PPP/RN1QK2R w KQkq - 1 10
r4rk1/pp3ppp/2n1bn2/3qp3/8/1NP1P3/P3BPPP/R1BQ1RK1 w - - 0 12
rnbqr1k1/ppp2pp1/3p1b1p/P7/2PP4/3B1NP1/1P3PP1/RN1Q1RK1 w - - 3 15
2kr1bnr/ppp1pppp/6b1/q5N1/3P4/2NnB3/PPP2PPP/R2Q1RK1 w - - 0 11
r3k2r/pp2ppbp/2p3p1/3n1b2/N2n1N2/3P4/PPPB1PPP/R2BK2R w KQkq - 14 15
r1bq1rk1/pp3ppp/8/4p2Q/1b1pN2P/1P1P2N1/1PP2PP1/R3K2R w KQ - 1 16
rn1qkb1r/ppp2p2/5n1p/4p1p1/2BP1pb1/2N2N2/PPP3PP/R1BQ1RK1 w kq - 0 9
rnb2k1r/ppp1q1pp/8/4N3/6n1/2Q5/PP3PPP/RNB1K2R w KQ - 1 12
r1bq1rk1/ppp1bppp/3p1n2/4p1B1/4P3/1PNP1N2/1PP2PPP/R2QK2R w KQ - 3 9
r2qkb1r/1p1n1ppp/p3pn2/1B1p1b2/3P1P2/2N1PN2/PP4PP/R1BQK2R w KQkq - 0 9
r1b1k1nr/1p1p1ppp/p3p3/q1b5/4P3/3B1N2/PPP1NPPP/R2Q1RK1 w kq - 2 13
rnbq1rk1/ppp3pp/1n6/3Ppp2/4P3/2N2P2/PP1Q2PP/R3KBNR w KQ - 0 10
rn1qk1nr/1p3ppp/p2bp3/3pN3/3P4/2N5/PPP1bPPP/R1BQ1RK1 w kq - 0 9
3r1rk1/4qppp/1pnp1n2/p1p1p3/P1P1P1b1/1P1P1NP1/2QN1PBP/R3R1K1 w - - 1 15
r1bqk2r/1p1pbppp/p1n1p3/4P3/2B3n1/2N1BN2/PP3PPP/R2Q1RK1 w kq - 1 10
r2qk2r/1pp2p2/p1np1n1p/2b1p1p1/2B1P1b1/P1NP1NB1/1PP2PPP/R2QK2R w KQkq - 2 10
rnbq1rk1/1pp1bppp/p3p3/8/2pP4/2N1PN2/PP2BPPP/R2Q1RK1 w - - 0 10
r1b2rk1/4q1pp/p1pp1p2/np2p1B1/4P3/3P1N1P/PPP2PP1/R2Q1RK1 w - - 0 14
r4rk1/1p2qpp1/p2pnn1p/4p2b/1PB1P2B/2PP1N1P/5PP1/R2Q1RK1 w - - 1 16
r2q1rk1/pb1nn1bp/1p4p1/4pp2/3pP3/1N1P1P1P/PP2BBPN/2RQ1RK1 w - - 0 16
r3k2r/1pp1bp2/p1np2pp/P3p2n/1PB1P2P/2PP3P/1B3P2/RN2K1R1 w Qkq - 1 16
rnbqkb1r/pp4pp/5p2/3np3/4P3/2N5/PP3PPP/R1BQK1NR w KQkq - 0 9
rn1q1rk1/ppp1bpp1/7p/3p4/3P2b1/3BPN2/PP3PPP/R1BQ1RK1 w - - 2 10
r1b1k2r/ppp2ppp/4q3/4n3/2P1Q3/3P4/P2B2PP/R3KB1R w KQkq - 0 16
2kr3r/pppbqpbp/1n4p1/3Pp3/4Pp2/1PNB4/PBPQ2PP/1K2R2R w - - 2 16
r2qkb1r/1p1n1ppn/p3p2p/3p1b2/8/PBNP1P1P/1PP1N1P1/R1BQK2R w KQkq - 4 11
rn2k1r1/pp2p2p/3p2p1/2pP1p1P/b1P1n3/2P1BN2/P3PPP1/2R1KB1R w Kq - 1 14
r2qk2r/ppp2ppp/2nbp3/3p4/3P1B2/3PPN2/PP1Q1PPP/R4RK1 w kq - 1 10
r2qrbk1/1ppb1ppp/p2p1n2/8/4PB2/1PNP3P/1PP3PN/R2Q1R1K w - - 3 14
r2qr1k1/pp1bnppp/2pb1n2/3pp3/P3P3/3P1NPP/1PPNQPB1/R1B2RK1 w - - 1 11
r2q1rk1/1ppbb1pp/p3p3/3pBp2/1P1PnP2/2PBP1P1/P6P/RN2QRK1 w - - 1 16
r1bq1rk1/b1p2pp1/p1n2n1p/1p6/1PNp1B2/P2B1N1P/2P2PP1/R2QR1K1 w - - 0 15
rnbq1rk1/pp2bppp/2p2n2/3p4/3P4/2NB1N2/PPP2PPP/R1BQ1RK1 w - - 2 10
r1bqk2r/1p1nn1p1/2pp3p/p3p3/4P3/2NB1N1P/PPP2PP1/R2Q1RK1 w kq - 0 11
r2qk2r/1p2b1pp/p1np1n2/2p1pb2/8/2NPBN2/PPPQBPPP/R4RK1 w kq - 2 10
rn1qk2r/pp2nppp/1b2p3/3pP3/3P1P2/5N2/PP4PP/RNBQK2R w KQkq - 3 10
r1bqk2r/p3npbp/1pn1p1p1/3p4/B7/2N2N2/PPPP1PPP/R1BQR1K1 w kq - 0 10
r2q1rk1/pp3ppp/2nbpn2/3p4/3P2b1/P1N2NP1/1P2PPBP/R1BQ1RK1 w - - 3 10
rn2k2r/pp2bppp/2p1pn2/q7/3P4/2NbBN2/PPP2PPP/R2Q1RK1 w kq - 0 10
2r1r1k1/pp2bpp1/2ppq1np/8/3PPQN1/2N4P/PPP3P1/3R1RK1 w - - 1 18
r1bq1rk1/pp2nppp/2pp4/1B1Pp3/1bP5/3P1N2/PP3PPP/R1BQ1RK1 w - - 0 10
rn1q1rk1/pp2bppp/2p1bn2/2Pp4/BP1Pp3/P1N1P3/5PPP/R1BQK1NR w KQ - 2 10
r1bq1rk1/2p2pp1/p2p1b1p/1p1P4/8/PPPB3P/5PP1/R1BQ1RK1 w - - 1 15
r2q1rk1/4bpp1/pp2pn1p/2pp4/P2P1P2/2PBPQ2/1P1B2PP/R4RK1 w - - 0 17
rnbqk2r/ppb2ppp/2p1pn2/P2p4/1P1P3P/2P1PN2/5PP1/RNBQKB1R w KQkq - 1 9
rn3b1r/ppp1k1pp/3p1nb1/6N1/2BPp3/8/PPP2PPP/RNB1K2R w KQ - 0 10
r1bqr1k1/1p2bppp/p1pp1n2/8/3pP3/1PN1BN1P/1PPQ1PP1/R4RK1 w - - 0 13
2kr1b2/ppq5/3p2pn/3p1b2/3PpP2/1B2B3/PP4PP/RN3RK1 w - - 2 17
r2q1rk1/ppp2ppp/3b1n2/3pNb2/3P1B2/2PB3P/PP1n1PP1/R2Q1RK1 w - - 0 13
r2r2k1/ppp2pbp/2n1p1p1/4P3/3P4/Pb2BN2/1P2BPPP/R4RK1 w - - 0 18
2kr2nr/pp3ppp/4p3/8/1bBnP3/2N2P2/PP3P1P/R1B2RK1 w - - 4 16
r3k1nr/1bp1qpp1/p1pp3p/2b1p3/Q3P3/2PP1N2/PP3PPP/RNB2RK1 w kq - 3 10
r1bq1rk1/pp2b1pp/2np4/2p1pp2/2P2Bn1/P1NP1NP1/1P2PPBP/R2Q1RK1 w - - 0 11
r3k1nr/pp3ppp/1q2p3/3p4/3b4/P4PP1/1P3PBP/1RBQ1RK1 w kq - 0 14
r2qk2r/ppp1bppp/3p1nb1/3Np3/2B1P1P1/5Q1P/PPPP1P2/R1B1R1K1 w kq - 3 11
2rqkb1r/pp3ppp/2n1pn2/3p3b/3P4/2NBP2P/PPQ1NPP1/R1B1K2R w KQk - 3 10
r2qk2r/ppp1bppn/2npb2p/8/4P1P1/2N2P1N/PPP4P/R1BQKBR1 w Qkq - 6 10
r1bq1rk1/ppp2pp1/1bnp1n1p/4p3/2B1P3/P1NPBN1P/1PP2PP1/R2QK2R w KQ - 3 9
r1bqkb1r/p4ppp/2p5/n2np1N1/8/3B4/PPPP1PPP/RNBQK2R w KQkq - 2 9
2kr1b1r/1ppqnpp1/p3p2p/P2pP3/1PnP2P1/2P2N2/5P1P/RNBQ1R1K w - - 0 14
r2qkb1r/1pp3pp/p2p1n2/8/4Pp2/3Q4/PPP3PP/RNB2RK1 w kq - 0 12
r4rk1/1p2bppp/p4n2/4p3/PnB1P1b1/2N2N2/1P3PPP/R1BR2K1 w - - 1 15
r1bnk1nr/pp2b1p1/7p/2p2pN1/4pB2/2N3P1/PPP1PPBP/R4RK1 w kq - 0 11
r3k1nr/1p1n1pp1/2p1bq1p/p1b1p3/P3P3/2NBBN2/1PP2PPP/R2Q1RK1 w kq - 5 11
r2q1rk1/pp1bppbp/2p3p1/8/3P4/2B1PN1P/PP2QPP1/2R1K2R w K - 1 15
rn1qk2r/ppp1bppp/2b1p3/4P3/3P4/1Q6/PP3PPP/R1B1KBNR w KQkq - 4 11
r2qkb1r/1b2nppp/p3p3/1pn1P3/8/P2B1N2/1P1N1PPP/R1BQ1RK1 w kq - 0 12
r1bq1rk1/ppp2ppp/2n5/2bnp3/8/3P1NN1/PPP1BPPP/R1BQ1RK1 w - - 7 9
rnbq1rk1/1p1p2bp/2p1p1p1/p2n4/4p3/1PP2PP1/PB1PN1BP/RN1Q1RK1 w - - 0 11
r4rk1/3qbppp/p1n1pn2/1p1p4/1P4b1/P4NP1/1BPNPPBP/2RQ1RK1 w - - 2 14
rn2k2r/pp6/2p3pp/7n/3PpB1P/5bP1/PPP5/RN2KB1R w KQkq - 2 18
r3k1nr/p4p1p/2bp1b2/nBp2P2/8/2P5/PP2N2P/RNB1KR2 w Qkq - 4 17
r1bq1rk1/1pp2pp1/2np3p/p2Np3/2P1P1n1/P2PPN2/1P2B1PP/R2QK2R w KQ - 0 11
r1bq1rk1/4bppp/p2p1n2/npp1p3/4P3/2PP1N1P/PPB2PP1/RNBQ1RK1 w - - 0 11
r1bq1rk1/ppp1npp1/1b3n1p/1P1p4/2B1P3/2PP1N2/P4PPP/RNBQK2R w KQ - 0 10
r2q1rk1/p4ppp/1ppp1b2/8/P1B1P3/1QP2PPb/1P1N3P/R3R1K1 w - - 1 18
r4rk1/1b2qpbp/p3p1p1/np1p4/3P1N2/N1P3P1/PP3PBP/R2Q1RK1 w - - 4 16
r2qk2r/pp1b2pp/2pbp3/5p2/3Pp3/1P2P1P1/PBP1NP1P/R2Q1RK1 w kq - 0 13
r2qkb1r/1ppb3p/p1n1pp2/3p4/3P3B/5N2/PPP2PPP/RN1QK2R w KQkq - 2 10
r2qk2r/p1pbbppn/2pp3p/8/3NP2B/2N5/PPP2PPP/R2Q1RK1 w kq - 2 11
r2q1rk1/1p3pp1/p4b1p/2pp4/3n4/PB1P1QNP/1PP2PP1/R4RK1 w - - 1 16
3r1rk1/ppp1bppp/5n2/3p4/1n1P4/2NPBN1P/PP3PP1/4RRK1 w - - 3 15
r1b2rk1/1ppn1ppp/p4q2/4p3/2BP4/P3PN2/1P3PPP/R2Q1RK1 w - - 0 13
rn2kbnr/p1p1pp1p/1p4p1/8/3P4/2PB1P2/PP5P/RNB1K2R w KQkq - 0 10
2r2rk1/pp3ppp/1n1qpn2/8/5P2/1PR1PN2/PB2Q1PP/5RK1 w - - 1 18
3q1rk1/p1pn1ppp/4rn2/2b1p3/8/2P1p2N/PPQP1PPP/RNB1K2R w KQ - 0 13
rnbqk2r/2p1bpp1/p2p1n1p/1p6/2BNP3/P4P2/1PP3PP/RNBQ1RK1 w kq - 0 9
rn1qk2r/pp3pp1/4bn1p/2bpp3/7B/2PP4/PPB2PPP/RN1QK1NR w KQkq - 0 9
r3k2r/p1pp1ppp/np2p3/3nP3/3P4/2P2N2/P1PB1PPP/R3K2R w KQkq - 0 13
r2q1rk1/pp1bbppp/2nppn2/2p3B1/2P1P3/2NP1N2/PP1QBPPP/R3K2R w KQ - 8 9
r2q1rk1/ppp1bppp/2n1bn2/3pp3/4P3/1PNP1N1P/PBP1BPP1/R2QK2R w KQ - 0 9
r1bq1rk1/pp1nppbp/3p2p1/2p5/2BPPPn1/2N1BN2/PPPQ2PP/R3K2R w KQ - 2 9
r1b1kr2/pppq2pp/4pp2/4P3/1Q2p3/P3P3/2P2PPP/R1B1K2R w KQq - 0 15
r4rk1/pp2nppp/1qn1p3/3pP3/3P4/N4N2/PP1Q1PPP/R4RK1 w - - 3 13
r1bq1rk1/pp1nb1pp/2p1p3/2Pp1p2/3PnB2/2NBPN1P/PP3PP1/R2QK2R w KQ - 3 10
r1bq1rk1/1p1pppbp/p1n2np1/8/4P3/1NN5/PPP1BPPP/R1BQ1RK1 w - - 0 9
rnbq1rk1/ppppp1bp/6p1/6N1/3P4/5N2/PPP2PPP/R2QKB1R w KQ - 3 9
r3k2r/pppqnpbp/2npb1p1/4p3/2P1P3/PPN2N1P/1B1P1PP1/R2QKB1R w KQkq - 3 9
r3k2r/pppq1pp1/2bp1b2/4p2p/4P3/2NP1N1P/PPPQ1PP1/R3K2R w KQkq - 2 11
r3kb1r/pp1nnpp1/2p1p2p/3pP3/3P4/2NP1N2/PP1B1PPP/2R2RK1 w kq - 0 12
r2qkb1r/ppp2ppp/5n2/4p3/3Q4/7P/PPP1NPP1/R1B1K2R w KQkq - 0 11
2kr3r/1pp1qppn/p1bp4/4p2p/4P3/2NP1N1P/PPP1QPP1/R2R2K1 w - - 0 14
r4rk1/1bp2ppp/np1qpn2/p2p4/P2P4/NPP1P1P1/4NPBP/R2QK2R w KQ - 5 11
r1br2k1/1pp1nppp/p1p5/2b5/3NP3/2P5/PP1N1PPP/R1B2RK1 w - - 5 11
1k1r3r/bpp2pp1/p2q1n2/3Pp2p/4P1b1/1BN1B3/PP3PPP/R3QRK1 w - - 2 17
r2q1rk1/1pp2ppp/p1bbpn2/3pN3/5P2/1P1PP3/PBP3PP/RN1Q1RK1 w - - 2 11
rn3rk1/1b1qppbp/3p1np1/1pp5/4P3/BPNB1P2/2PPN1PP/R2QK2R w KQ - 0 13
1rb1nrk1/p2n2qp/3p2pQ/1pp5/4N1P1/5P2/PPP1P3/R3KBNR w KQ - 4 18
r2q1rk1/pbppn1bp/1p2p1p1/8/4P3/1PNB1Q2/P1PB1PPP/2R1R1K1 w - - 2 13
r1bqk2r/1n4pp/2pp1b2/pp2pp2/1P2P3/P1NP3P/B1P1NPP1/R2QK2R w KQkq - 0 13
rnbq1k1r/ppp5/3p1n1p/3p2p1/8/B1P2Q2/P1P2PPP/R3KBNR w KQ - 0 11
rn1q1rk1/pp3pp1/2pb1n1p/3p4/2PP4/1P3B2/PB1N1PPP/R2Q1RK1 w - - 5 12
r2qk2r/pb1nnpbp/1p1pp1p1/2p5/3PPP2/1BN1B3/PPPQN1PP/R3K2R w KQkq - 0 10
rn2k2r/p1p2ppp/1p2bn2/P3p3/4P3/5P2/P1PB2PP/R2K1BNR w q - 2 11
r3k1nr/pp3p2/2ppq2p/2n1p1p1/4P3/P2P1N1P/1PP2PP1/R1BQ1RK1 w kq - 0 12
r1b1k2r/pp1qbpp1/3p1n1p/2pBp3/Q1P1P3/3P1N2/PP3PPP/R1B2RK1 w kq - 3 11
r1b2rk1/p4ppp/2p1pn2/q7/2p5/1PNBP3/P4PPP/2RQK2R w K - 0 13
r4rk1/p4ppp/1q2pn2/1bbp4/8/P1P1PQ2/3NBPPP/R1B2RK1 w - - 6 15
r4rk1/2qbbp1p/p2p1np1/1pnPp3/P1p1P3/2P2NNP/1PB2PP1/R1BQR1K1 w - - 0 17
r3kb1r/p4p1p/2pp1np1/1pn5/4P3/1BN2P2/PPP2P1P/R1B1K1R1 w Qkq - 2 13
r3nrk1/p1p2p1p/3bp1pP/1N1p1b2/8/P3PN2/1PP2PP1/R1B1K2R w KQ - 4 14
r1b2rk1/ppp2ppp/1b6/1q2P3/2N5/5N2/PPP1Q1PP/2KR3R w - - 2 15
r3kbnr/pb3ppp/2p1p3/8/8/4P1P1/PP3P1P/RNBK1B1R w kq - 1 10
r2qkb1r/pp1nppp1/2p4p/3n3b/3P4/2N1PN1P/PP2BPP1/R1BQK2R w KQkq - 1 9
r1b2rk1/1p2bppp/2n1pn2/2qp4/2P5/P3PNP1/1B1N1PBP/R1Q2RK1 w - - 1 15
r1bq2nr/pppk3p/2nb4/3p1p1B/3PpNp1/4P3/PPP2PPP/RNBQ1RK1 w - - 2 11
r1bq1rk1/ppp2pp1/1bnp1n1p/4p3/2B1P2B/1N1P1N2/PPP2PPP/R2QK2R w KQ - 2 9
r4rk1/4qppp/1pnp1b2/p1p1p3/2P1P3/PP1P4/1B1NbPPP/R2Q1RK1 w - - 0 14
rnbqkb1r/p3pppp/2p5/3nP3/P2PN3/2p2N2/5PPP/R1BQKB1R w KQkq - 0 10
rn2k2r/1bppqpbp/pp2pnp1/6N1/2B1P3/2PP1Q2/PP3PPP/RNB2RK1 w kq - 0 9
r3r1k1/pp1qbpp1/2n1bn1p/3p4/2pP4/P1N2NB1/1PPQBPPP/R4RK1 w - - 8 14
r1bq1rk1/1p2bpp1/p1n1pn1p/8/2p4B/P1N1PN2/1P3PPP/2RQKB1R w K - 0 12
r3k2r/2pqppbp/ppbp1np1/8/3PP3/2N1BN2/PPPQ1PPP/R4RK1 w kq - 2 11
r1bq1rk1/1p2bppp/pn6/2pP4/P7/2N5/BP3PPP/R2QK1NR w KQ - 2 12
r1bq1rk1/pp2ppbp/5np1/3P4/1nBN4/2N1BP2/PPP3PP/R2QK2R w KQ - 1 10
rnb1k1nr/pp2bppp/2p1p3/3pP3/3P1B2/1NP5/PP3PPP/R3KBNR w KQkq - 0 9
rnb1k2r/pp2q1pp/3b4/3n1p2/3Pp3/1Q2P3/PP1NBPPP/R1B1K2R w KQkq - 0 11
r1bq1rk1/pp3ppp/n1pbp3/8/3P4/4PN2/PPP3PP/RNBQ1RK1 w - - 3 11
1r1qr1k1/p2nbppp/5n2/2p4b/2Pp4/1P3N1P/P1B2PP1/RNBQR1K1 w - - 1 16
2kr3r/1pp2ppp/p1pbbn2/4N3/8/8/PPPP1PPP/RNB1RK2 w - - 7 12
r2qkb1r/pppnpp1p/6p1/3pP3/5P2/4P3/PPP1Q1PP/RNB1K2R w KQkq - 0 9
r2qkb1r/ppp3pp/5n2/3p1b2/3n4/P3P3/1PP1BPPP/RNBQK2R w KQkq - 0 9
r2q1rk1/pp1bppbp/2np1np1/2p5/4PP2/3P3P/PPP1B1PN/RNBQ1RK1 w - - 1 9
2kr3r/pppqbpp1/5n1p/3pn3/3P2b1/1P4P1/PB1NPPBP/R2Q1RK1 w - - 0 12
rn1qk2r/pp2npp1/1bp1p2p/3pP3/3P1Pb1/2P2NP1/PP4BP/RNBQK2R w KQkq - 1 10
rnb2r1k/1p3ppp/2pp3n/p3p1q1/P1B1P2N/2NPP2P/1PP3PK/R2Q1R2 w - - 7 13
r3kb1r/pp3ppp/2n1p3/2p5/4nP2/2P1Bb1P/PP2K1P1/RN3B1R w kq - 0 11
r2qr1k1/pp2ppbp/2p2np1/6B1/3P4/2P2Q1P/PPB2PP1/R4RK1 w - - 3 14
3r1rk1/1bq1bppp/p1n1pn2/1p1p2B1/4P3/PNNB4/1PPQ1PPP/3R1R1K w - - 0 15
r1bq1rk1/pppp2bp/2n1p1p1/5n2/2PP4/2N1BN2/PP2BPPP/R2QK2R w KQ - 2 9
rnb1k2r/pp1p1pp1/2p2n1p/2b1p3/2B1P2P/2NP1P2/PPP1NP2/R1B1K2R w KQkq - 1 9
rn1qk2r/1b3pp1/p3pb1p/1pp5/8/PB1P1N2/1PP1QPPP/R1B2RK1 w kq - 0 13
r2qk2r/ppp2pp1/3b3p/n2Bn3/4P1b1/1QP2N2/PP1N1PPP/R1B1K2R w KQkq - 2 11
r1b1k1nr/5ppp/p2p1q2/1pp1p3/2PbP3/1B6/PP1PQPPP/RNB1R1K1 w kq - 0 11
r4rk1/ppq1bppp/3ppn2/2p5/4PP2/2PPBQP1/PP1N3P/R4RK1 w - - 6 13
rn2kbnr/p1p2ppp/2ppp3/2q3B1/6P1/2NP1N2/PPP1PP1P/R2QK2R w KQkq - 1 9
r1bq1rk1/5ppp/p1nbpn2/1p1p4/8/2PP1NP1/PP1N1PBP/R1BQR1K1 w - - 0 11
r1bq1k1r/1p1nbppp/p1n1p3/3p2B1/5P1P/2N4N/PPPQ2P1/2KR1B1R w - - 1 13
r2q1rk1/pp3ppp/2n2n2/2bp4/5Bb1/3B1N2/PPPN1PPP/R2Q1RK1 w - - 8 10
r1b1kbnr/2pn1pp1/p2p3p/1p1Pp3/4P3/1B3P1P/PPP1NP2/RNB1K2R w KQkq - 1 10
r2q1rk1/ppp1nppp/3p4/3Np1b1/4P1B1/3P4/PPP2PPP/R2Q1RK1 w - - 6 15
r1b1k2r/pp3ppp/2nqpn2/3p4/3P4/2N1PN2/PP3PPP/R2QKB1R w KQkq - 0 9
rnbq1rk1/pp3pb1/2p1pn1p/4p1p1/3P3B/2NB1N2/PPP2PPP/R2Q1RK1 w - - 0 11
r4rk1/pp2ppbp/2n3p1/2pqP3/6b1/2PB1N2/PP3PPP/R1BQR1K1 w - - 1 12
2rqkb1r/pp1n1ppp/2p1pn2/3p4/3P4/1P2PB2/PBP2PPP/RN1Q1RK1 w k - 2 9
4r1k1/ppp2ppp/1q1b1n2/8/2P1r1b1/1P1Q1N2/P2B1PPP/RN3RK1 w - - 2 17
r2qr1k1/pp1n1ppp/3bbn2/2pp4/3P4/2NBBN1P/PPP2PP1/R2QR1K1 w - - 0 11
r1n2rk1/1p1b1pp1/p1p2q1p/2bp4/3P4/P3PN2/1P2BPPP/2RQ1RK1 w - - 0 17
r3k2r/1ppq1ppp/p1nbpnb1/1N1p2B1/3P2P1/5N1P/PPP1PPB1/R2Q1RK1 w kq - 0 11
r4rk1/pppq1p1p/2np1bp1/3Bp2b/4P3/2PP2QN/PP3PPP/RN2K2R w KQ - 0 12
r1b1rnk1/ppq2ppp/2p2n2/3p4/3P4/3BPN2/PPQN1PPP/2R2RK1 w - - 0 14
r1b1k1nr/1p1p1pp1/4pq2/p1b2P1p/2P1P1n1/1Q5N/PP2B1PP/RNB1K2R w KQkq - 0 11
r1b2rk1/1ppp1pp1/2n2q1p/p1b1p3/4P3/2PP1N2/PP2BPPP/RN1Q1RK1 w - - 0 9
r2qkbnr/pp1n2pp/2p2p2/3p3b/Q2P4/2N2N2/PP2PPPP/R1B1KB1R w KQkq - 2 9
r1bq1rk1/pp2npbp/2n1p1p1/2p1P3/3p1P2/3P1N2/PPP1BBPP/RN1Q1RK1 w - - 0 10
4rrk1/ppqb2pp/2pbp3/3pN3/3PpP2/PP2P3/1BP3PP/R2Q1R1K w - - 0 17
r1bq1rk1/2p1bppp/p1np1n2/1p2p3/4P3/1BPP1N1P/PP3PP1/RNBQK2R w KQ - 1 9
r1b1k2r/1p1pnpbp/p1n1p3/5p2/8/2NBPN1P/PPP2PP1/R1B2RK1 w kq - 1 12
4k1nr/2ppq1pp/rpn2p2/4P3/8/P3PN2/1B1Q1PPP/R3K2R w KQk - 0 13
rnb1kbnr/pp2q1pp/3p4/4p3/4p3/2P1BPP1/PP5P/RN1QKBNR w KQkq - 0 9
r4rk1/ppp2ppp/3pb3/4p3/1PB1P1nq/P2P1n1P/2P1NPP1/R1BQ1R1K w - - 3 13
rnbqk2r/pp2bpp1/2p4p/3p4/3P3B/5N2/PP2PPPP/R2QKB1R w KQkq - 0 9
r1b1r1k1/4ppbp/pq4p1/npp5/4N3/P1PPn1NP/1PB2PP1/R3QRK1 w - - 0 17
r3kbnr/1pp4p/p2q2p1/3pp2Q/1P6/P3P1P1/2P2P1P/RN2KB1R w KQkq - 0 12
r3k2r/2pq1ppp/p1nbpn2/1p1p4/3P1P2/2P1P2P/PPB2P2/RNBQK2R w KQkq - 1 11
r2qkb1r/p1pb1ppp/3p1n2/2p5/4P3/1N6/PPP2PPP/RNBQ1RK1 w kq - 2 9
2kr3r/pppq2p1/2nppb2/7p/P3P3/2P1BP2/1P1N2PP/R2Q1RK1 w - - 0 14
r4rk1/4nppp/pqp1p3/3pP3/QP4P1/2Pb1N1P/P4P2/R1B2RK1 w - - 2 18
r1b1k2r/ppp2ppp/2n2n2/2b1pP2/4P3/2N2N2/PPP3PP/R1BK1B1R w kq - 1 9
r1b1qrk1/p1p3pp/1p1b1n2/5p2/2P1p3/1P2P1P1/PBQ1NPBP/R4RK1 w - - 0 16
r1bqk1nr/1pp2ppp/1p1p4/8/2BnP3/8/PPP2PPP/R1BQK2R w KQkq - 0 9
rnbq1rk1/ppp2pp1/4pn1p/b7/2p5/PP4PN/1B1PPPBP/RN1Q1RK1 w - - 0 9
r2q1rk1/pp1n1ppp/2p1p3/3n1b2/2BPP3/2b2N2/PP1B1PPP/R2Q1RK1 w - - 0 11
r2q2k1/pp3pp1/2pbb2p/3n4/3P4/3B1N1P/PP1B1PP1/R3Q1K1 w - - 1 17
r1bq1rk1/bpp3pp/p1np2n1/4pp2/1PP1P3/P4NP1/1B1P1PBP/RN1Q1RK1 w - - 0 11
rnbq1rk1/pp3pp1/3p1n1p/2pPp1B1/2P1P3/2P2N2/P1Q2PPP/R3KB1R w KQ - 0 10
r1b1k2r/ppq2ppp/2nb1n2/1B1pN3/3P4/2N5/PP3PPP/R1BQK2R w KQkq - 8 10
3r1rk1/1pq1bppp/p1npbn2/8/2P5/1PN2N2/PB2BPPP/R2Q1RK1 w - - 4 13
r3kbnr/pp3ppp/2q1p3/2ppP3/3P4/P1N2b1P/1PP2PP1/R1BQ1RK1 w kq - 0 11
rn1qk2r/pp2bpp1/2n1p3/1B1pPb1p/Q2P4/2N2N2/PP3PPP/R1B1K2R w KQkq - 4 10
r2q1rk1/1ppnppbp/p2p1np1/8/1P1P2b1/P3PN2/1BPNBPPP/R2QK2R w KQ - 0 9
r1bq1rk1/2p1bppp/p1np1n2/1p2p3/4P3/1BNP1N1P/PPP2PP1/R1BQK2R w KQ - 3 9
r3r1k1/p1p2ppp/1pn5/2q5/2P3b1/3P1N2/PQPB2PP/R4R1K w - - 2 17
r3k1nr/pp3pp1/2n1p2p/2qpP3/8/2PB1Q1P/PP3PP1/RN2K2R w KQkq - 0 12
r3kbnr/ppp2ppp/5q2/4p3/3P2b1/1P1P1pP1/P2N1PBP/R1BQK2R w KQkq - 0 10
r1bq1rk1/pp3ppp/1bn2n2/3p4/8/1N1B1N2/PPP2PPP/R1BQ1RK1 w - - 6 10
r1b2rk1/p2p1ppp/2p1pn2/2q5/2P5/P1N1P3/3QBPPP/RR4K1 w - - 6 15
r2q1rk1/pb2ppbp/1p4p1/n1p1P3/2P5/1P3N2/PBQNRPPP/R5K1 w - - 0 16
rn1qk2r/pp2nppp/4p3/3pP3/8/3QbN2/PPP2PPP/RN3RK1 w kq - 0 10
2kr3r/pppqbppp/3p4/4nP2/2B1P3/2P5/PP4PP/R1BQ1RK1 w - - 0 15
r1bq1rk1/pp1nppbp/2np2p1/2p5/4P1P1/2NPB2P/PPPQNP2/R3KB1R w KQ - 1 9
r1b1k3/ppq1bp1r/2pp1n2/4p1pp/2BPPn2/1QP1B1N1/PP1N1PPP/R4RK1 w q - 0 15
r2q1rk1/2pbb1pp/p2p1n2/3Ppp2/2Q1P3/5N2/PP1N1PPP/R1B1R1K1 w - - 1 15
r2qkb1r/1p3ppp/p1n1b3/3pPp2/3P4/2N2N2/PP3PPP/R1BQ1RK1 w kq - 0 11
r1b1k2r/3p2pp/pp1bp3/2p2n2/P1P5/1PN2N1P/2PB1PP1/R3K2R w KQkq - 0 15
r2qk2r/1p1bnppp/p3p3/2bpP3/8/2N2N2/PPP2PPP/R1BQ1RK1 w kq - 2 10
r1bq1rk1/pp2ppbp/2n2np1/1B1p4/3PP3/5N2/PP3PPP/RNBQR1K1 w - - 0 9
5rk1/4bp1p/2p2np1/2Pp1b2/QP6/B3P2N/5PPP/qN3RK1 w - - 2 17
r2q1rk1/2p1bppp/p1p2n2/3p1PB1/8/2N2Q2/PPP2PPP/R4RK1 w - - 0 13
r1b1k2r/pp2bpp1/2qppn1p/2p5/4P3/2NP1N1P/PPP2PP1/R1BQK2R w KQkq - 1 10
r1b2rk1/ppqn1ppp/2pb1n2/3pp3/3PP3/2NQ2P1/PPP1NPBP/R1B1K2R w KQ - 1 9
r2q1rk1/pbpnppbp/1p1p1np1/3P4/4P3/2NB1N2/PPP1QPPP/R1B2RK1 w - - 6 9
r1bq1rk1/ppp1nppp/1bnp4/1B6/3PP3/5N1P/PP3PP1/RNBQ1RK1 w - - 1 9
2rbk2r/p3npp1/2n1p1b1/1p1pP2p/q1pP1PP1/2P1BN1P/PP1NQ1B1/R3R1K1 w k - 0 17
rn1qr1k1/pp2ppbp/2p3p1/8/2pP4/1P1QPN1P/PB3PP1/R4RK1 w - - 0 14
rn2kb1r/1b1p1ppp/pq2p1n1/1pp5/4P3/P2P1N2/NPPBBPPP/R2Q1RK1 w kq - 10 12
r5k1/ppr2ppp/4p3/3pPn2/3P4/qP3N1P/P1bQBPP1/R4RK1 w - - 9 18
2kr3r/pp1bq2p/1np1p1p1/3pPp2/3Pn2P/2PBPNP1/PP4Q1/R1B1K2R w KQ - 1 15
r2q1rk1/3nbpp1/2pp1n1p/1p2p3/4P2B/1Q1P1N2/1PPN1PPP/R4RK1 w - - 0 14
rnb2rk1/pp3ppp/5n2/3p4/P2Pp3/NP2PP2/3q2PP/2R1KBNR w K - 0 12
r3k2r/pp3ppp/2p2n2/q3p3/3n2b1/PPb2N2/1BPPBPPP/R2Q1RK1 w kq - 0 12
3r1rk1/ppp1ppbp/6p1/8/2Pnq3/1Q2BN2/PP3PPP/2R2RK1 w - - 0 14
r2qkb1r/5ppp/bpn1pn2/p2p4/3P4/P2B1P2/1PP1N1PP/RNBQ1RK1 w kq - 1 10
r1b1kb1r/3q2p1/p1n4p/1pp5/3ppPn1/NP4PN/PBPQP1BP/R4RK1 w kq - 0 16
r2q1rk1/ppp2pp1/2n2b1p/3p3b/3P4/2PB1N1P/PP3PP1/RN1QR1K1 w - - 0 12
r1q2rk1/1b1n1pbp/p3pnp1/1p1p4/3P1PPB/P2BPN2/1P5P/RN1Q1RK1 w - - 1 14
r1b1k2r/ppq1bp2/2p2nnp/4p1p1/2B1P3/2N1BN2/PPPRQPPP/3R2K1 w kq - 2 13
r1bq1rk1/p1p1bppn/2pp3p/8/3PP3/2N2N2/PP3PPP/R1BQR1K1 w - - 2 11
r1bq1rk1/pppn1pbp/3p1np1/3Pp1B1/4P3/2N2N2/PPP2PPP/R1Q1KB1R w KQ - 3 10
rn2k2r/5p2/2pp2pp/ppb1p3/4P3/PB1P1P2/1PP2P1P/R1B1K1R1 w Qkq - 0 14
r2qk2r/1p3pp1/1np1p1p1/p2nP1b1/P1pP4/2N2B1P/1P3PP1/R1BQ1RK1 w kq - 0 15
2rq1rk1/1p3pp1/p2pbn1p/4p3/2P1P3/5P2/n1PNBBPP/1R1QK2R w K - 0 16
3q1rk1/2pp1pbp/2n3p1/1r1Bp3/8/4P3/1P1P1PPP/R1BQ1RK1 w - - 0 17
r2q1rk1/pppb1ppp/2nbpn2/3p4/8/P1NPPN2/1PPBBPPP/R2Q1RK1 w - - 3 9
r3k1nr/pb1qpp1p/1ppp2p1/1B6/3bP3/PPN5/1BPPQPPP/R3K2R w KQkq - 0 11
3rr1k1/pppq1ppp/2n2b2/3np3/8/2PPBNNP/PP3PP1/R2Q1RK1 w - - 4 15
r2q1rk1/pp2bppp/3pbn2/2p3B1/3QP3/2NB4/PPP2PPP/R4RK1 w - - 0 11
r2q1rk1/ppp1b1pn/2np3p/1B2pb2/8/2PP1N1P/PP1N1PP1/R1BQR1K1 w - - 0 11
rnb2rk1/2q2ppp/p4n2/2pp4/8/2PBBN2/P1Q2PPP/R3R1K1 w - - 0 18
r1bqk2r/bppp1ppp/p1n2n2/3Np3/1P2P3/P2B1N2/2PP1PPP/R1BQ1RK1 w kq - 1 9
rn2k1nr/pp2q1pp/2p1p3/2Pp1p2/4bP2/3BP3/PPP3PP/RNBQ1RK1 w kq - 1 11
r2q1rk1/pp2bpp1/4bn1p/3pn3/3P4/2N3P1/PP3PBP/R1BQ1R1K w - - 0 13
r4rk1/ppp1npp1/5q1p/2bpp3/PPB1P3/2PP1P2/5P1P/R1BQ1RK1 w - - 0 13
2kr3r/pp2np2/1q2p2b/n2pP2p/2pP2pN/P1P5/1P2QPPP/R1B1RNK1 w - - 4 17
r2qk2r/pbppbppp/1pn1p3/4P3/2BP4/2P2N2/P1P2PPP/R1BQ1RK1 w kq - 2 9
r1b2rk1/pp3ppp/2n2B2/8/8/2P2q2/P1N1B1PP/R3K2R w KQ - 0 15
rn1q1rk1/ppp1bpp1/5n1p/3p2B1/3P2b1/3B1N2/PPP2PPP/RN1QR1K1 w - - 0 9
r1bqkb1r/ppp4p/2np4/4pp2/8/3PBP2/PPP1N1PP/R2QKB1R w KQkq - 0 9
r3kbnr/ppp3p1/3pp2p/8/3qP3/2N1B3/PPP2PPP/2KR3R w kq - 0 11
r2q1rk1/pp3ppp/2n1pn2/8/2P5/P4N2/P2PQPPP/R1B1K2R w KQ - 1 10
r1q2r2/pp2ppbk/3p2pp/2pP4/3n4/P2P1NPb/1PPB1PBP/R1Q2RK1 w - - 1 15
rn1qk2r/1bp1bppp/p3pn2/1p6/3P4/1BN1PN2/PP3PPP/R1BQ1RK1 w kq - 6 9
r1bq1rk1/pp1n1pbp/3p1np1/2p5/1P1B4/P3PNP1/2PN1P1P/R2QKB1R w KQ - 0 10
r1bqkb1r/5p1p/p1np1p2/1p2p3/4P3/N1N5/PPP2PPP/R2QKB1R w KQkq - 0 10
rn1qkb1r/1p3ppp/p3pn2/3p4/N2P4/3Q4/PPP2PPP/R1B1K1NR w KQkq - 0 9
r1bqk2r/3n1ppp/p2b1n2/2pp4/1p1P4/2N1PN2/PPB2PPP/R1BQK2R w KQkq - 0 11
r4rk1/1p2bppp/p1np1n2/2p5/8/2NP1N1P/PPP2PP1/R1B1K2R w KQ - 0 12
r1bq1rk1/3n1pp1/1p2pn1p/p2p4/1b1P4/1P2PN2/PBQNBPPP/R4RK1 w - - 0 12
r1b2rk1/pp1np1bp/2p2np1/3pNpB1/3P1P1P/q2BPN2/2P3P1/1R1Q1RK1 w - - 1 13
r1b2rk1/ppqn1pbp/2pp1np1/3Pp3/2P5/2N1PNP1/PP3PBP/R1BQ1RK1 w - - 1 10
r2q1r2/3n1pkp/p3p1p1/1ppnN3/8/2NP4/PPP2PPP/R1Q1R1K1 w - - 1 15
rn1q1rk1/pp2bppp/2p1pn2/5bB1/3P4/5B2/PPP1NPPP/RN1Q1RK1 w - - 4 9
r2q1rk1/1p2ppbp/p1np1np1/2p5/4PPb1/2PP1NP1/PP2Q1BP/RNB2RK1 w - - 2 10
r1b2rk1/1p3p1p/p3pnp1/4q3/P2n4/2N2Q2/BP1P1PPP/R1B2RK1 w - - 2 16
r2qk2r/pb1pnpbp/1pn1p1p1/2p5/2P1P3/2NP2PP/PP2NPB1/R1BQK2R w KQkq - 2 9
r1bq1rk1/3nppbp/p2p1np1/2p5/3P4/P3PNP1/1BPN1PBP/R2QK2R w KQ - 0 11
r3k2r/5ppp/p1npbb2/qp1Np3/2P1P3/N7/PP3PPP/R2QKB1R w KQkq - 1 13
r2qkb1r/ppp2ppp/2np4/8/4P1b1/2P2N2/PP3PPP/RNBQK2R w KQkq - 2 9
r1bqk2r/1p3pbp/2n1pnp1/p2p4/3P4/BP2PN2/P3BPPP/RN1Q1RK1 w kq - 0 10
r1b2rk1/ppq2pbp/1n1p1np1/2pPp3/QPP1P3/3B1N2/P2N1PPP/R1B2RK1 w - - 1 12
r1b2rk1/pp1nqppp/2p1p3/8/2BPn3/5N2/PPP2PPP/R2QR1K1 w - - 0 12
r2qr1k1/pbpp1p1p/1p1b1npB/8/4P3/2NB1P1P/PPP2P2/R2QK1R1 w Q - 2 12
r2qk2r/pbpn1pbp/1p1ppnp1/8/2PP1B2/2NBPN2/PPQ2PPP/R3K2R w KQkq - 2 9
rnb2rk1/ppq3pp/2pbpn2/3p1pB1/3P4/2P2NP1/PP2PPBP/RN1QR1K1 w - - 5 9
r1b2rk1/ppq3pp/2nb1n2/3p4/2PPpp2/1P4P1/PB1NNPBP/R2Q1RK1 w - - 0 13
r1bq1rk1/2b3pp/p2p1p2/1p1Pp1P1/3pP2P/P2P4/1P1B1P2/R2QKB1R w KQ - 0 16
r1bq1rk1/1p1nbppp/p1p1pn2/3p4/1P1P4/P3PNP1/1BPN1P1P/R2QKB1R w KQ - 1 9
r4rk1/1pbn1pp1/p1p1pn1p/2Pp1bB1/1P1P4/2N1PN2/1P1K1PPP/2R2B1R w - - 0 14
r2q1rk1/ppp1npb1/3p1npp/3Pp1B1/4P1b1/3B1N2/PPPN1PPP/R3QRK1 w - - 0 11
rnb2rk1/6pp/1npbpp2/pp6/3PB3/P3BN2/1PPN1PPP/R3R1K1 w - - 7 14
rnb2rk1/ppp2ppp/8/8/1bPN4/4B3/PP2BPPP/R3K2R w KQ - 5 12
r1b1k1nr/pppp1ppp/8/3N4/5b2/8/PPP1PPPP/R3KB1R w KQkq - 0 9
r2qkb1r/pQ4pp/3p1n2/3pp3/4P3/2P2P2/PP5P/RNB1K2R w KQkq - 0 13
r1b1k2r/pp1p2pp/2n1p3/q1p2p2/2PP4/2P3P1/P2QPPBP/R3K1NR w KQkq - 1 11
r1b1kbnr/p4ppp/2p1q3/2pp4/4P3/2N2NR1/PPPP1P1P/R1BQK3 w Qkq - 0 10
2kr3r/p1pbqpb1/Npn1p1pp/2P1P3/3P4/3n1N2/PP4PP/R1BQK2R w KQ - 0 16
r2q1rk1/ppp2ppp/2nb4/3pp3/1P1P2n1/P1P1PN2/5PPP/RNBQ1RK1 w - - 0 11
r2qk2r/1pp2pp1/p2p1n1p/2b1p3/2bnP3/P1NPBN1P/1PPQ1PP1/2KR3R w kq - 0 11
r2qkbnr/1p2ppp1/p1n3bp/3p4/1P4P1/P1NP1N1P/4PP2/R1BQKB1R w KQkq - 0 10
r3k1r1/1p1nbp2/p1p1pp1p/2Pp4/1P1P3N/2N5/1Pb1PPPP/R3KB1R w KQq - 3 15
r4rk1/pbp2pp1/1p2pq1p/3n4/3P4/P1PB1N2/2PQ1PPP/R3R1K1 w - - 1 15
rn1qk2r/pp5p/2p1pnp1/3pp3/4P3/3PQ3/PPP2PPP/RN2K1NR w KQkq - 0 11
rn1qk1nr/4bppp/p1b1p3/1pp5/2P5/P2P1N2/BP3PPP/RNBQ1RK1 w kq - 3 10
rn1q1rk1/pp2npbp/2p1b1p1/3p4/3P4/1PN1PN2/PB2BPPP/R2Q1RK1 w - - 3 11
r2qk1nr/pp2bppp/2pp4/4n3/4P3/1BN5/PPP1QP1P/R1B2K1R w kq - 2 14
r1bqk2r/pp3pp1/5n1p/2bpN3/2Bn4/2NP4/PPP2PPP/R1BQK2R w KQkq - 0 10
rnb2rk1/pp3ppp/2p1p3/q7/2BP4/2b1PN2/PPQ2PPP/R4RK1 w - - 0 12
rnbq1rk1/ppp3bp/4ppp1/3pPn2/3P4/2P1BN1P/PP1Q1PP1/RN2KB1R w KQ - 2 9
r2q1rk1/ppp2pbp/2np1np1/4p3/3PP1b1/3B1N2/PPP1NPPP/R1BQR1K1 w - - 2 9
r2q1rk1/1p1n1pp1/p1pbpn1p/5b2/1PBP4/PN2PN1P/1B3PP1/R2QK2R w KQ - 5 12
r2q1rk1/pppb1ppn/3p3p/8/4Pb2/1PNP2QP/1PP3PN/R4RK1 w - - 0 15
r1bqr1k1/pp3pp1/3p1nnp/2pP4/2P1PP2/2PN4/P5BP/R1BQ1RK1 w - - 1 15
r3k1nr/pbpn1pbp/1p1qp1p1/8/2BP4/5N2/PPP2PPP/RNBQ1RK1 w kq - 0 9
r1bqk2r/pp2bppp/2n1p3/3n4/2BP4/2N2N2/PP3PPP/R1BQK2R w KQkq - 2 9
r3k1nr/ppp2ppp/2bp4/8/4P3/2qB1P2/PPP3PP/RN3RK1 w kq - 0 12
rnb1kb1r/pppq3p/3ppp2/8/2P1P3/3B4/PP3PPP/RN1QK1NR w KQkq - 0 9
r2qkb1r/pp3ppp/2n1pn2/1B1p2B1/3P4/2NQ1b2/PPP2PPP/R3K2R w KQkq - 0 9
r2qk2r/pp3ppp/2nbpn2/3p1b2/3P4/1BP2N2/PP3PPP/RNBQ1RK1 w kq - 4 9
r4rk1/p2b1pp1/1p1qpn1p/3p4/3P4/4P3/PP1B1PPP/R2QKB1R w KQ - 0 13
r1bqk2r/pp3ppp/2n2n2/3p4/1b1N4/1P2P3/PB3PPP/RN1QKB1R w KQkq - 1 9
r4rk1/1p2bppp/p1b1p3/3n4/3P4/2N2B1P/PP3PP1/R1B2RK1 w - - 6 16
1rbq1rk1/pp3ppp/3p1b2/3Bp1B1/3pP3/3P1Q1P/PPP2PP1/R3R1K1 w - - 5 14
1rbq1rk1/2pn1ppp/p4n2/4p3/P1Pp4/R2P1NP1/3NPPBP/3Q1RK1 w - - 0 14
r4rk1/1pqbbppp/p1nppn2/8/3NP3/2PB1N1P/PP2QPP1/R1B2RK1 w - - 1 12
r1b1k2r/ppppnppp/5q2/8/3bP3/2P5/PP2BPPP/RN1QK2R w KQkq - 0 9
r2qk2r/3n1ppp/p2bpn2/1p1p4/3P1Pb1/P1NBPN2/1P4PP/R1BQ1RK1 w kq - 2 11
r3k2r/2p1q1p1/p2ppn1p/1p2p3/1P1bP3/P1NP2QP/2P1KPP1/1RB4R w kq - 1 17
rnb1kb1r/3n1p2/2pp2pp/pp2p3/1P2P3/1B1P4/PBP2PPP/RN2K1NR w KQkq - 0 11
r1b1k2r/ppp1qppp/4p3/4n3/3P4/2nB3P/PP1Q1PP1/R1B1R1K1 w kq - 0 16
r2q1rk1/pppb1pp1/2nbpn1p/3p4/1P1P4/P1NBPN2/2PB1PPP/R2QK2R w KQ - 1 9
r2qk2r/1b3ppp/p3pn2/1pb5/8/3BPN2/PP3PPP/R1BQ1RK1 w kq - 0 13
1rbq1rk1/pp1pnpbp/2n1p1p1/2p5/2P5/2NPP1P1/PP2NPBP/R1BQ1RK1 w - - 3 9

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 734 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1014 B

BIN
cpp/res/pieces/trimmed.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -1,23 +0,0 @@
#pragma once
#include "../board.hpp"
#include <string>
#define DECLARE_AI(x) \
struct x : public AI { \
std::string search(std::string, int) override; \
int minimax(const Board&, int) override; \
int eval(const Board&) override; \
};
namespace ai {
struct AI {
virtual std::string search(std::string, int) = 0;
virtual int minimax(const Board&, int) = 0;
virtual int eval(const Board&) = 0;
};
DECLARE_AI(v0_random)
DECLARE_AI(v1_simple)
} // namespace ai

View File

@ -1,8 +0,0 @@
#include "ai.hpp"
std::string ai::v1_simple::search(std::string pos, int depth) {
Board b = Board::setup_fen_position(pos);
std::vector<Move> moves = b.all_legal_moves();
return moves[rand() % moves.size()].to_string();
}

View File

@ -1,97 +0,0 @@
#include "../pieces/piece.hpp"
#include "../threadpool.hpp"
#include "ai.hpp"
#include <future>
#include <map>
static int INFINITY = std::numeric_limits<int>::max();
std::string ai::v1_simple::search(std::string pos, int depth) {
Board b = Board::setup_fen_position(pos);
ThreadPool pool(std::thread::hardware_concurrency());
std::vector<Move> moves = b.all_legal_moves();
std::map<std::string, std::future<int>> futures;
for (const Move& move : moves) {
Board tmp_board = b.make_move(move);
futures.insert(
{move.to_string(), pool.enqueue([this, tmp_board, depth]() {
return minimax(tmp_board, depth - 1);
})}
);
}
std::string best_move;
int best_eval = -INFINITY;
for (auto& [move, future] : futures) {
int eval = future.get();
if (eval > best_eval) {
best_eval = eval;
best_move = move;
}
}
return best_move;
}
int ai::v1_simple::minimax(const Board& b, int depth) {
if (b.is_checkmate_for(b.white_to_play ? White : Black))
return -INFINITY;
if (depth == 0)
return eval(b);
std::vector<Move> moves = b.all_legal_moves();
int best_evaluation = 0;
Move best_move;
for (const Move& move : moves) {
Board tmp_board = b.make_move(move);
int tmp_eval = -minimax(tmp_board, depth - 1);
best_evaluation = std::max(best_evaluation, tmp_eval);
}
return best_evaluation;
}
static int PawnValue = 100;
static int KnightValue = 300;
static int BishopValue = 320;
static int RookValue = 500;
static int QueenValue = 900;
int count_material(const Board& b, int8_t colour) {
int ret = 0;
for (int i = 0; i < 64; i++) {
if (b.colour_at(i) == colour)
switch (b.squares[i] & 0b111) {
case Piece::Pawn:
ret += PawnValue;
break;
case Piece::Knigt:
ret += KnightValue;
break;
case Piece::Bishop:
ret += BishopValue;
break;
case Piece::Rook:
ret += RookValue;
break;
case Piece::Queen:
ret += QueenValue;
break;
}
}
return ret;
}
int ai::v1_simple::eval(const Board& b) {
int white_eval = count_material(b, Colour::White);
int black_eval = count_material(b, Colour::Black);
int evaluation = white_eval - black_eval;
int perspective = b.white_to_play ? 1 : -1;
return perspective * evaluation;
}

View File

@ -1,51 +0,0 @@
#pragma once
#include "coords.hpp"
#include "move.hpp"
#include "pieces/piece.hpp"
#include <string>
struct Board {
private:
int8_t get_king_of(int8_t) const;
bool no_legal_moves_for(int8_t) const;
public:
int8_t squares[64] = {Piece::None};
bool white_to_play = true;
int8_t w_castle_rights = CastleSide::NeitherSide;
int8_t b_castle_rights = CastleSide::NeitherSide;
int8_t en_passant_target = -1;
uint8_t n_half_moves = 0;
uint8_t n_full_moves = 0;
static Board setup_fen_position(std::string fen);
Board make_move(Move) const;
std::string to_fen() const;
bool is_check_for(int8_t) const;
std::vector<Move> all_legal_moves() const;
bool is_checkmate_for(int8_t colour) const {
return is_check_for(colour) && no_legal_moves_for(colour);
}
bool is_stalemate_for(int8_t colour) const {
return !is_check_for(colour) && no_legal_moves_for(colour);
}
bool is_terminal() const {
return is_checkmate_for(White) || is_checkmate_for(Black)
|| is_stalemate_for(White) || is_stalemate_for(Black);
}
int8_t colour_at(int8_t idx) const {
return squares[idx] & 0b11000;
}
int8_t colour_at(Coords xy) const {
return colour_at(xy.to_index());
}
};

View File

@ -0,0 +1,38 @@
#include "ai_vs_ai.hpp"
#include "controller.hpp"
#include <thread>
AIvsAIController::AIvsAIController(Board b, View& v, ai::AI& p1, ai::AI& p2)
: Controller(b, v),
p1(p1),
p2(p2) {}
void AIvsAIController::start() {
std::thread view_thread([&]() { view.show(); });
ai::AI* current_player;
while (!board.is_terminal()) {
current_player = board.white_to_play ? &p1 : &p2;
std::cout << typeid(*current_player).name() << " to play" << std::endl;
Move move = current_player->search(board);
make_move(move);
}
view_thread.join();
}
void AIvsAIController::make_move(Move move) {
board = board.make_move(move);
std::cout << "Made move: " << move << std::endl;
view.update_board(board, -1, {});
Colour current_colour = board.white_to_play ? White : Black;
if (board.is_checkmate())
view.notify_checkmate(current_colour);
if (board.is_stalemate())
view.notify_stalemate(current_colour);
}
void AIvsAIController::on_tile_selected(int, int) {}

View File

@ -0,0 +1,19 @@
#pragma once
#include "../model/ais/ai.hpp"
#include "../model/utils/coords.hpp"
#include "../model/utils/move.hpp"
#include "../view/view.hpp"
#include "controller.hpp"
class AIvsAIController : public Controller {
ai::AI &p1, &p2;
protected:
void make_move(Move) override;
public:
AIvsAIController(Board, View&, ai::AI&, ai::AI&);
void on_tile_selected(int, int) override;
void start() override;
};

View File

@ -0,0 +1,7 @@
#include "controller.hpp"
#include "../view/view.hpp"
Controller::Controller(Board b, View& v): board(b), view(v) {
v.set_controller(this);
}

View File

@ -0,0 +1,17 @@
#pragma once
#include "../model/board/board.hpp"
class View;
class Controller {
protected:
Board board;
View& view;
virtual void make_move(Move) = 0;
public:
Controller(Board, View&);
virtual void start() = 0;
virtual void on_tile_selected(int, int) = 0;
};

View File

@ -0,0 +1,29 @@
#include "human_vs_ai.hpp"
#include <algorithm>
HumanVsAIController::HumanVsAIController(Board b, View& v, ai::AI& ai)
: ManualController(b, v),
ai(ai) {}
void HumanVsAIController::on_tile_selected(int x, int y) {
Coords c{x, y};
Piece piece = board.piece_at(c);
if (selected_index == -1
|| (piece != Piece::None && piece != selected_piece
&& (piece & 0b11000) != (selected_piece & 0b11000))) {
show_legal_moves(c);
} else {
auto boh = std::find(targets.begin(), targets.end(), c.to_index());
if (boh != targets.end()) {
make_move(Move{selected_index, c.to_index()});
if (board.is_terminal())
return;
Move ai_move = ai.search(board);
make_move(ai_move);
} else
reset_selection();
}
}

View File

@ -0,0 +1,14 @@
#pragma once
#include "../model/ais/ai.hpp"
#include "../view/view.hpp"
#include "manual.hpp"
class HumanVsAIController : public ManualController {
protected:
ai::AI& ai;
public:
HumanVsAIController(Board, View&, ai::AI&);
void on_tile_selected(int, int) override;
};

View File

@ -0,0 +1,74 @@
#include "manual.hpp"
#include "../model/utils/utils.hpp"
#include <algorithm>
ManualController::ManualController(Board b, View& v): Controller(b, v) {
reset_selection();
}
void ManualController::start() {
reset_selection();
view.show();
}
void ManualController::on_tile_selected(int x, int y) {
Coords c{x, y};
Piece piece = board.piece_at(c);
if (selected_index == -1
|| (piece != Piece::None && piece != selected_piece
&& (piece & 0b11000) != (selected_piece & 0b11000))) {
show_legal_moves(c);
} else {
auto boh = std::find(targets.begin(), targets.end(), c.to_index());
if (boh != targets.end())
make_move(Move{selected_index, c.to_index()});
else
reset_selection();
}
}
void ManualController::reset_selection() {
selected_index = -1;
selected_piece = Piece::None;
targets = {};
view.update_board(board, selected_index, targets);
}
void ManualController::show_legal_moves(Coords xy) {
Colour colour = board.colour_at(xy);
if (colour) {
Colour to_play = board.white_to_play ? White : Black;
if (colour != to_play)
return;
selected_index = xy.to_index();
selected_piece = board.piece_at(xy);
targets = to_target_square(legal_moves(selected_piece, board, xy));
view.update_board(board, xy.to_index(), targets);
}
}
void ManualController::make_move(Move move) {
// handle promotion before making the move
Colour colour = board.white_to_play ? White : Black;
Coords source = Coords::from_index(move.source_square);
if (board.piece_at(move.source_square) == Piece::Pawn
&& board.colour_at(move.source_square) == White && source.y == 6) {
Piece promotion_piece = (Piece) (colour | view.ask_about_promotion());
move.promoting_to = promotion_piece;
}
std::cout << "Move made: " << move << std::endl;
board = board.make_move(move);
reset_selection();
Colour current_colour = board.white_to_play ? White : Black;
if (board.is_checkmate())
view.notify_checkmate(current_colour);
if (board.is_stalemate())
view.notify_stalemate(current_colour);
}

View File

@ -0,0 +1,22 @@
#pragma once
#include "../model/utils/coords.hpp"
#include "../model/utils/move.hpp"
#include "../view/view.hpp"
#include "controller.hpp"
class ManualController : public Controller {
protected:
int8_t selected_index;
Piece selected_piece;
std::vector<int8_t> targets;
void reset_selection();
void show_legal_moves(Coords);
void make_move(Move) override;
public:
ManualController(Board, View&);
void on_tile_selected(int, int) override;
void start() override;
};

View File

@ -1,14 +1,41 @@
#include "ais/ai.hpp"
#include "controller/ai_vs_ai.hpp"
#include "controller/controller.hpp"
#include "controller/human_vs_ai.hpp"
#include "controller/manual.hpp"
#include "model/ais/ai.hpp"
#include "model/perft/perft.hpp"
#include "view/gui.hpp"
#include "view/noop.hpp"
#include "view/view.hpp"
#include <iostream>
#include <chrono>
int main(int argc, char* argv[]) {
// std::string pos =
// "r2qkb1r/2p1pppp/p1n1b3/1p6/B2P4/2P1P3/P4PPP/R1BQK1NR w KQkq - 0 9 ";
// std::string pos = "8/6K1/5P2/8/1k6/8/8/8 w - - 0 1";
// pos for ai timing<
std::string pos =
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
"r3k2r/p1ppqpb1/Bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPB1PPP/R3K2R b KQkq - 0 3";
ai::v1_simple ai;
Board b = Board::setup_fen_position(pos);
std::string move = ai.search(pos, 4);
std::cout << move << std::endl;
ai::v0_random p1(true, std::chrono::milliseconds(1000));
// ai::v1_pure_minimax p2(false, std::chrono::milliseconds(20000));
// ai::v2_alpha_beta p2(false, std::chrono::milliseconds(20000));
ai::v3_AB_ordering p2(false, std::chrono::milliseconds(20000));
// ai::v4_search_captures p2(false, std::chrono::milliseconds(20000));
// GUI gui;
NoOpView gui;
AIvsAIController manual(b, gui, p1, p2);
// HumanVsAIController manual(b, gui, p2);
Controller& controller = manual;
controller.start();
// perft();
return 0;
}

52
cpp/src/model/ais/ai.cpp Normal file
View File

@ -0,0 +1,52 @@
#include "ai.hpp"
#include <condition_variable>
#include <ostream>
#include <thread>
Move ai::AI::search(const Board& b) {
Move result;
std::condition_variable cv;
std::mutex cv_mutex;
double elapsed;
stop_computation = false;
// Start computation in a separate thread
std::thread computation_thread([&]() {
auto start = std::chrono::steady_clock::now();
result = _search(b);
auto end = std::chrono::steady_clock::now();
elapsed =
std::chrono::duration_cast<std::chrono::milliseconds>(end - start)
.count();
// Notify the timer thread that computation is done
{
std::lock_guard<std::mutex> lock(cv_mutex);
stop_computation = true;
cv.notify_one();
}
});
// Start a timer thread to stop computation after given time
std::thread timer_thread([&]() {
std::unique_lock<std::mutex> lock(cv_mutex);
if (!cv.wait_for(lock, thinking_time, [&] {
return stop_computation.load();
})) {
// Timeout reached; set stop flag
stop_computation = true;
}
});
// Wait for computation thread to finish
computation_thread.join();
// Ensure timer thread is also stopped
timer_thread.join();
std::cout << "Took " << elapsed << " ms" << std::endl;
return result;
}

79
cpp/src/model/ais/ai.hpp Normal file
View File

@ -0,0 +1,79 @@
#pragma once
#include "../board/board.hpp"
#include <atomic>
#include <chrono>
namespace ai {
class AI {
protected:
bool am_white;
std::chrono::milliseconds thinking_time;
virtual Move _search(const Board&) = 0;
public:
AI(bool am_white, std::chrono::milliseconds tt)
: am_white(am_white),
thinking_time(tt) {}
std::atomic<bool> stop_computation = false;
Move search(const Board& b);
virtual int eval(const Board&) = 0;
};
struct v0_random : public AI {
v0_random(bool w, std::chrono::milliseconds tt): AI(w, tt) {}
Move _search(const Board&) override;
int eval(const Board&) override {
return 0;
};
};
class v1_pure_minimax : public AI { // looks two moves ahead
int _search(const Board&, int);
public:
v1_pure_minimax(bool w, std::chrono::milliseconds tt): AI(w, tt) {}
Move _search(const Board&) override;
int eval(const Board&) override;
};
class v2_alpha_beta : public AI {
// looks two moves ahead, with alpha-beta pruning (no move ordering)
int _search(const Board&, int, int, int);
public:
v2_alpha_beta(bool w, std::chrono::milliseconds tt): AI(w, tt) {}
Move _search(const Board&) override;
int eval(const Board&) override;
};
class v3_AB_ordering : public AI {
// looks two moves ahead, with alpha-beta pruning, with move ordering
virtual int _search(const Board&, int, int, int);
public:
v3_AB_ordering(bool w, std::chrono::milliseconds tt): AI(w, tt) {}
Move _search(const Board&) override;
int eval(const Board&) override;
};
class v4_search_captures : public v3_AB_ordering {
// same as v3, but looking at only at captures when leaf is reached,
// until no captures are left
int _search(const Board&, int, int, int) override;
int _search_captures(const Board&, int, int);
public:
v4_search_captures(bool w, std::chrono::milliseconds tt)
: v3_AB_ordering(w, tt) {}
};
} // namespace ai

View File

@ -0,0 +1,13 @@
#include "ai.hpp"
#include <thread>
Move ai::v0_random::_search(const Board& b) {
std::vector<Move> moves = b.all_legal_moves();
std::this_thread::sleep_for(std::chrono::milliseconds(thinking_time)
); // Simulate work
return moves[rand() % moves.size()];
}

View File

@ -0,0 +1,91 @@
#include "../pieces/piece.hpp"
#include "../utils/threadpool.hpp"
#include "../utils/utils.hpp"
#include "ai.hpp"
#include <map>
#define MULTITHREADED 1
static int position_counter = 0;
Move ai::v1_pure_minimax::_search(const Board& b) {
position_counter = 0;
std::vector<Move> moves = b.all_legal_moves();
Move best_move;
int best_eval = -INFINITY;
#if MULTITHREADED
ThreadPool pool(std::thread::hardware_concurrency());
std::cout << "Have to look at " << moves.size() << " moves" << std::endl;
std::map<Move, std::future<int>> futures;
for (const Move& move : moves) {
Board tmp_board = b.make_move(move);
futures.insert({move, pool.enqueue([&, tmp_board]() {
return _search(tmp_board, 3);
})});
}
int counter = 0;
for (auto& [move, future] : futures) {
int eval = future.get();
counter++;
if (!am_white)
eval *= -1;
if (eval > best_eval) {
best_eval = eval;
best_move = move;
}
}
#else
for (const Move& move : moves) {
Board tmp_board = b.make_move(move);
std::cout << "Looking at " << move << std::endl;
int eval = _search(tmp_board, 3);
if (!am_white)
eval *= -1;
if (eval > best_eval) {
best_eval = eval;
best_move = move;
}
}
#endif
std::cout << "Looked at " << position_counter << " positions" << std::endl;
return best_move;
}
int ai::v1_pure_minimax::_search(const Board& b, int depth) {
if (depth == 0 || stop_computation)
return eval(b);
if (b.no_legal_moves()) {
if (b.is_check())
return -INFINITY;
return 0;
}
std::vector<Move> moves = b.all_legal_moves();
int best_evaluation = -INFINITY;
Move best_move;
for (const Move& move : moves) {
Board tmp_board = b.make_move(move);
int tmp_eval = -_search(tmp_board, depth - 1);
best_evaluation = std::max(best_evaluation, tmp_eval);
}
return best_evaluation;
}
int ai::v1_pure_minimax::eval(const Board& b) {
position_counter++;
int white_eval = count_material(b, Colour::White);
int black_eval = count_material(b, Colour::Black);
int evaluation = white_eval - black_eval;
int perspective = b.white_to_play ? 1 : -1;
return perspective * evaluation;
}

View File

@ -0,0 +1,92 @@
#include "../pieces/piece.hpp"
#include "../utils/threadpool.hpp"
#include "../utils/utils.hpp"
#include "ai.hpp"
#include <map>
#define MULTITHREADED 1
static int position_counter = 0;
Move ai::v2_alpha_beta::_search(const Board& b) {
position_counter = 0;
std::vector<Move> moves = b.all_legal_moves();
Move best_move;
int best_eval = -INFINITY;
#if MULTITHREADED
ThreadPool pool(std::thread::hardware_concurrency());
std::cout << "Have to look at " << moves.size() << " moves" << std::endl;
std::map<Move, std::future<int>> futures;
for (const Move& move : moves) {
Board tmp_board = b.make_move(move);
futures.insert({move, pool.enqueue([&, tmp_board]() {
return _search(tmp_board, 3, -INFINITY, INFINITY);
})});
}
int counter = 0;
for (auto& [move, future] : futures) {
int eval = future.get();
counter++;
if (!am_white)
eval *= -1;
if (eval > best_eval) {
best_eval = eval;
best_move = move;
}
}
#else
for (const Move& move : moves) {
Board tmp_board = b.make_move(move);
std::cout << "Looking at " << move << std::endl;
int eval = _search(tmp_board, 3);
if (!am_white)
eval *= -1;
if (eval > best_eval) {
best_eval = eval;
best_move = move;
}
}
#endif
std::cout << "Looked at " << position_counter << " positions" << std::endl;
return best_move;
}
int ai::v2_alpha_beta::_search(const Board& b, int depth, int alpha, int beta) {
if (depth == 0 || stop_computation)
return eval(b);
if (b.no_legal_moves()) {
if (b.is_check())
return -INFINITY;
return 0;
}
std::vector<Move> moves = b.all_legal_moves();
for (const Move& move : moves) {
Board tmp_board = b.make_move(move);
int tmp_eval = -_search(tmp_board, depth - 1, -beta, -alpha);
if (tmp_eval >= beta)
return beta;
alpha = std::max(alpha, tmp_eval);
}
return alpha;
}
int ai::v2_alpha_beta::eval(const Board& b) {
position_counter++;
int white_eval = count_material(b, Colour::White);
int black_eval = count_material(b, Colour::Black);
int evaluation = white_eval - black_eval;
int perspective = b.white_to_play ? 1 : -1;
return perspective * evaluation;
}

View File

@ -0,0 +1,99 @@
#include "../pieces/piece.hpp"
#include "../utils/threadpool.hpp"
#include "../utils/utils.hpp"
#include "ai.hpp"
#include <algorithm>
#include <map>
#define MULTITHREADED 1
static int position_counter;
Move ai::v3_AB_ordering::_search(const Board& b) {
position_counter = 0;
std::vector<Move> moves = b.all_legal_moves();
Move best_move;
int best_eval = -INFINITY;
#if MULTITHREADED
ThreadPool pool(std::thread::hardware_concurrency());
std::cout << "Have to look at " << moves.size() << " moves" << std::endl;
std::map<Move, std::future<int>> futures;
for (const Move& move : moves) {
Board tmp_board = b.make_move(move);
futures.insert({move, pool.enqueue([&, tmp_board]() {
return _search(tmp_board, 3, -INFINITY, INFINITY);
})});
}
int counter = 0;
for (auto& [move, future] : futures) {
int eval = future.get();
counter++;
if (!am_white)
eval *= -1;
if (eval > best_eval) {
best_eval = eval;
best_move = move;
}
}
#else
for (const Move& move : moves) {
Board tmp_board = b.make_move(move);
std::cout << "Looking at " << move << std::endl;
int eval = _search(tmp_board, 3);
if (!am_white)
eval *= -1;
if (eval > best_eval) {
best_eval = eval;
best_move = move;
}
}
#endif
std::cout << "Looked at " << position_counter << " positions" << std::endl;
return best_move;
}
int ai::v3_AB_ordering::_search(
const Board& b, int depth, int alpha, int beta
) {
if (depth == 0 || stop_computation)
return eval(b);
if (b.no_legal_moves()) {
if (b.is_check())
return -INFINITY;
return 0;
}
std::vector<Move> moves = b.all_legal_moves();
std::sort(moves.begin(), moves.end(), [&](Move& m1, Move& m2) {
return m1.score_guess(b) > m2.score_guess(b);
});
Move best_move;
for (const Move& move : moves) {
Board tmp_board = b.make_move(move);
int tmp_eval = -_search(tmp_board, depth - 1, -beta, -alpha);
if (tmp_eval >= beta)
return beta;
alpha = std::max(alpha, tmp_eval);
}
return alpha;
}
int ai::v3_AB_ordering::eval(const Board& b) {
position_counter++;
int white_eval = count_material(b, Colour::White);
int black_eval = count_material(b, Colour::Black);
int evaluation = white_eval - black_eval;
int perspective = b.white_to_play ? 1 : -1;
return perspective * evaluation;
}

View File

@ -0,0 +1,61 @@
#include "../pieces/piece.hpp"
#include "../utils/utils.hpp"
#include "ai.hpp"
#include <algorithm>
#define MULTITHREADED 1
static int position_counter;
int ai::v4_search_captures::_search(
const Board& b, int depth, int alpha, int beta
) {
if (depth == 0 || stop_computation)
return _search_captures(b, alpha, beta);
if (b.no_legal_moves()) {
if (b.is_check())
return -INFINITY;
return 0;
}
std::vector<Move> moves = b.all_legal_moves();
std::sort(moves.begin(), moves.end(), [&](Move& m1, Move& m2) {
return m1.score_guess(b) > m2.score_guess(b);
});
Move best_move;
for (const Move& move : moves) {
Board tmp_board = b.make_move(move);
int tmp_eval = -_search(tmp_board, depth - 1, -beta, -alpha);
if (tmp_eval >= beta)
return beta;
alpha = std::max(alpha, tmp_eval);
}
return alpha;
}
int ai::v4_search_captures::_search_captures(
const Board& b, int alpha, int beta
) {
int evaluation = eval(b);
if (evaluation >= beta)
return beta;
alpha = std::max(evaluation, alpha);
std::vector<Move> moves = b.all_capturing_moves();
std::sort(moves.begin(), moves.end(), [&](Move& m1, Move& m2) {
return m1.score_guess(b) > m2.score_guess(b);
});
for (const Move& move : moves) {
Board tmp_board = b.make_move(move);
int tmp_eval = -_search_captures(tmp_board, -beta, -alpha);
if (tmp_eval >= beta)
return beta;
alpha = std::max(alpha, tmp_eval);
}
return alpha;
}

View File

@ -1,12 +1,15 @@
#include "board.hpp"
#include "coords.hpp"
#include "move.hpp"
#include "pieces/piece.hpp"
#include "../pieces/piece.hpp"
#include "../utils/coords.hpp"
#include "../utils/move.hpp"
#include "../utils/utils.hpp"
#include <SFML/Graphics/BlendMode.hpp>
#include <algorithm>
#include <cctype>
#include <map>
#include <sstream>
#include <stdexcept>
Board Board::setup_fen_position(std::string fen) {
@ -91,6 +94,8 @@ Board Board::setup_fen_position(std::string fen) {
index = fen.find(' ', index) + 1;
board.n_full_moves = std::stoi(fen.substr(index));
board.check = board._is_check_for(board.white_to_play ? White : Black);
board.nlm = board._no_legal_moves_for(board.white_to_play ? White : Black);
return board;
}
@ -110,14 +115,14 @@ std::string Board::to_fen() const {
for (int rank = 7; rank >= 0; rank--) {
int empty_cell_counter = 0;
for (int file = 0; file < 8; file++) {
if (squares[rank * 8 + file] == Piece::None) {
if (piece_at({file, rank}) == Piece::None) {
empty_cell_counter++;
continue;
}
int full_piece = squares[rank * 8 + file];
char piece = p2c[full_piece & 0b111];
int8_t colour = colour_at({file, rank});
Colour colour = colour_at({file, rank});
if (empty_cell_counter > 0) {
ret += std::to_string(empty_cell_counter);
@ -168,7 +173,14 @@ std::string Board::to_fen() const {
return ret;
}
Board Board::make_move(Move move) const {
Board Board::skip_turn() const {
Board ret = *this;
ret.white_to_play = !ret.white_to_play;
ret.check = ret._is_check_for(ret.white_to_play ? White : Black);
return ret;
}
Board Board::make_move(Move move, bool recurse_call) const {
Board ret;
std::copy(
std::begin(this->squares),
@ -181,10 +193,12 @@ Board Board::make_move(Move move) const {
ret.squares[move.source_square] = Piece::None;
ret.squares[move.target_square] = this->squares[move.source_square];
Piece source_piece = piece_at(move.source_square);
Piece target_piece = piece_at(move.target_square);
// -- Handle en passant target being eaten
if (en_passant_target != -1
&& (squares[move.source_square] & 0b111) == Piece::Pawn
&& squares[move.target_square] == Piece::None)
if (en_passant_target != -1 && source_piece == Piece::Pawn
&& target_piece == Piece::None)
ret.squares[move.target_square + (white_to_play ? -8 : 8)] =
Piece::None;
@ -193,7 +207,7 @@ Board Board::make_move(Move move) const {
ret.squares[move.target_square] = move.promoting_to;
// -- Set en passant target if need
if ((squares[move.source_square] & 0b111) == Piece::Pawn
if (source_piece == Piece::Pawn
&& std::abs(move.target_square - move.source_square) == 16) {
if (white_to_play)
ret.en_passant_target = move.target_square - 8;
@ -205,7 +219,7 @@ Board Board::make_move(Move move) const {
// -- Handle castling (just move the rook over)
Coords c = Coords::from_index(move.source_square);
if ((squares[move.source_square] & 0b111) == Piece::King) {
if (source_piece == Piece::King) {
if (move.target_square - move.source_square == 2) { // king side castle
Coords rook_source{7, c.y};
int8_t old_rook = ret.squares[rook_source.to_index()];
@ -226,10 +240,10 @@ Board Board::make_move(Move move) const {
ret.b_castle_rights = b_castle_rights;
bool is_capturing = squares[move.target_square] != Piece::None;
if (white_to_play) {
if ((squares[move.source_square] & 0b111) == King)
if (source_piece == King)
ret.w_castle_rights = NeitherSide;
if ((squares[move.source_square] & 0b111) == Rook) {
if (source_piece == Rook) {
if (c.x == 0 && (ret.w_castle_rights & QueenSide))
ret.w_castle_rights &= ~(QueenSide);
if (c.x == 7 && (ret.w_castle_rights & KingSide))
@ -237,18 +251,17 @@ Board Board::make_move(Move move) const {
}
Coords target = Coords::from_index(move.target_square);
if (is_capturing && target.y == 7
&& (squares[move.target_square] & 0b111) == Rook) {
if (is_capturing && target.y == 7 && target_piece == Rook) {
if (target.x == 0 && (ret.b_castle_rights & QueenSide))
ret.b_castle_rights &= ~(QueenSide);
if (target.x == 7 && (ret.b_castle_rights & KingSide))
ret.b_castle_rights &= ~(KingSide);
}
} else {
if ((squares[move.source_square] & 0b111) == King)
if (source_piece == King)
ret.b_castle_rights = NeitherSide;
if ((squares[move.source_square] & 0b111) == Rook) {
if (source_piece == Rook) {
if (c.x == 0 && (ret.b_castle_rights & QueenSide))
ret.b_castle_rights &= ~(QueenSide);
if (c.x == 7 && (ret.b_castle_rights & KingSide))
@ -256,8 +269,7 @@ Board Board::make_move(Move move) const {
}
Coords target = Coords::from_index(move.target_square);
if (is_capturing && target.y == 0
&& (squares[move.target_square] & 0b111) == Rook) {
if (is_capturing && target.y == 0 && target_piece == Rook) {
if (target.x == 0 && (ret.w_castle_rights & QueenSide))
ret.w_castle_rights &= ~(QueenSide);
if (target.x == 7 && (ret.w_castle_rights & KingSide))
@ -265,32 +277,65 @@ Board Board::make_move(Move move) const {
}
}
ret.n_half_moves = n_half_moves + 1;
if (is_capturing || piece_at(move.source_square) == Piece::Pawn)
ret.n_half_moves = 0;
if (!white_to_play)
ret.n_full_moves = n_full_moves + 1;
if (ret.n_half_moves > 150) {
std::cerr << "too many recursions" << std::endl;
exit(1);
}
if (recurse_call) {
ret.check = ret._is_check_for(ret.white_to_play ? White : Black);
ret.nlm = ret._no_legal_moves_for(ret.white_to_play ? White : Black);
}
return ret;
}
bool Board::insufficient_material_for(Colour current_colour) const {
int n_bishop = 0, n_knight = 0;
for (int i = 0; i < 64; i++) {
Colour colour = colour_at(i);
if (colour != current_colour)
continue;
Piece piece = piece_at(i);
if (piece == Piece::Pawn || piece == Piece::Queen
|| piece == Piece::Rook)
return false;
if (piece == Piece::Bishop)
n_bishop++;
if (piece == Piece::Knigt && colour == Colour::White)
n_knight++;
}
return (n_bishop == 0 && n_knight == 0) || (n_bishop == 1 && n_knight == 0)
|| (n_bishop == 0 && n_knight == 1);
}
int8_t Board::get_king_of(int8_t colour) const {
for (int i = 0; i < 64; i++)
if (squares[i] == (colour | Piece::King))
return i;
throw std::domain_error(
"Apparently there no kings of the such color in this board"
);
std::stringstream ss;
ss << "Apparently there no kings of the such color in this board: "
<< std::endl;
ss << to_fen();
throw std::domain_error(ss.str());
}
std::vector<int8_t> to_target_square(std::vector<Move> moves) {
std::vector<int8_t> ret;
for (Move move : moves)
ret.push_back(move.target_square);
return ret;
}
bool Board::is_check_for(int8_t colour) const {
bool Board::_is_check_for(Colour colour) const {
int8_t king_idx = this->get_king_of(colour);
for (int i = 0; i < 64; i++) {
std::vector<Move> all_moves;
all_moves.reserve(50);
for (int8_t i = 0; i < 64; i++) {
if (this->squares[i] == Piece::None || colour_at(i) == colour)
continue;
std::vector<int8_t> targets;
if ((squares[i] & 0b00111) == King) {
if (piece_at(i) == King) {
// special case for the king, because it creates infinite recursion
// (since he looks if he's walking into a check)
Coords king_pos = Coords::from_index(i);
@ -298,7 +343,7 @@ bool Board::is_check_for(int8_t colour) const {
for (int dy = -1; dy <= 1; dy++) {
Coords c{king_pos.x + dx, king_pos.y + dy};
if (c.is_within_bounds())
targets.push_back(c.to_index());
all_moves.push_back(Move{i, c.to_index()});
}
}
} else {
@ -308,27 +353,51 @@ bool Board::is_check_for(int8_t colour) const {
Coords::from_index(i),
true
);
targets = to_target_square(moves);
all_moves.insert(all_moves.end(), moves.begin(), moves.end());
}
if (std::find(targets.begin(), targets.end(), king_idx)
!= targets.end())
return true;
for (const Move& move : all_moves)
if (move.target_square == king_idx)
return true;
all_moves.clear();
}
return false;
}
bool Board::no_legal_moves_for(int8_t colour) const {
bool Board::_no_legal_moves_for(Colour colour) const {
for (int i = 0; i < 64; i++) {
if (colour_at(i) == colour) {
std::vector<Move> moves =
legal_moves(squares[i], *this, Coords::from_index(i));
if (moves.size() > 0)
return false;
}
if (squares[i] == Piece::None || colour_at(i) != colour)
continue;
std::vector<Move> moves;
moves = legal_moves(squares[i], *this, Coords::from_index(i));
if (moves.size() > 0)
return false;
}
return true;
}
bool Board::no_legal_moves() const {
return nlm;
}
bool Board::is_check() const {
return check;
}
bool Board::is_checkmate() const {
return check && nlm;
}
bool Board::is_stalemate() const {
return !check && nlm;
}
bool Board::is_terminal() const {
return n_half_moves == 100 || insufficient_material() || is_checkmate()
|| is_stalemate();
}
std::vector<Move> Board::all_legal_moves() const {
std::vector<Move> ret;
for (int i = 0; i < 64; i++) {
@ -341,3 +410,28 @@ std::vector<Move> Board::all_legal_moves() const {
}
return ret;
}
std::vector<Move> Board::all_capturing_moves() const {
std::vector<Move> moves = all_legal_moves();
std::vector<Move> ret;
ret.reserve(moves.size());
for (const Move& move : moves)
if (piece_at(move.target_square) != Piece::None)
ret.push_back(move);
return ret;
}
std::vector<int8_t> Board::opponent_pawn_attack_map() const {
std::vector<int8_t> ret;
for (int i = 0; i < 64; i++) {
if (piece_at(i) == Piece::Pawn
&& ((colour_at(i) == White && !white_to_play)
|| (colour_at(i) == Black && white_to_play))) {
std::vector<int8_t> attack_map =
pawn_attack_map(*this, Coords::from_index(i));
ret.insert(ret.end(), attack_map.begin(), attack_map.end());
}
}
return ret;
}

View File

@ -0,0 +1,70 @@
#pragma once
#include "../pieces/piece.hpp"
#include "../utils/coords.hpp"
#include "../utils/move.hpp"
#include <string>
struct Board {
private:
int8_t get_king_of(int8_t) const;
bool _no_legal_moves_for(Colour) const;
bool _is_check_for(Colour) const;
bool nlm = false, check = false;
public:
int8_t squares[64] = {Piece::None};
bool white_to_play = true;
int8_t w_castle_rights = CastleSide::NeitherSide;
int8_t b_castle_rights = CastleSide::NeitherSide;
int8_t en_passant_target = -1;
int n_half_moves = 0;
int n_full_moves = 0;
static Board setup_fen_position(std::string fen);
Board skip_turn() const;
Board make_move(Move, bool = true) const;
std::string to_fen() const;
bool no_legal_moves() const;
bool is_check() const;
bool insufficient_material_for(Colour) const;
bool insufficient_material() const {
return insufficient_material_for(White)
&& insufficient_material_for(Black);
};
std::vector<Move> all_legal_moves() const;
std::vector<Move> all_capturing_moves() const;
std::vector<int8_t> opponent_pawn_attack_map() const;
bool is_checkmate() const;
bool is_stalemate() const;
bool is_terminal() const;
inline Piece piece_at(int8_t idx) const {
return (Piece) (squares[idx] & 0b00111);
}
inline Piece piece_at(Coords xy) const {
return piece_at(xy.to_index());
}
inline Colour colour_at(int8_t idx) const {
return (Colour) (squares[idx] & 0b11000);
}
inline Colour colour_at(Coords xy) const {
return colour_at(xy.to_index());
}
};
inline bool operator<(const Board& m1, const Board& m2) {
return m1.to_fen() < m2.to_fen(
); // TODO: make this the comparison between the hash of the board
}

View File

@ -1,8 +1,8 @@
#include "perft.hpp"
#include "board.hpp"
#include "move.hpp"
#include "threadpool.hpp"
#include "../board/board.hpp"
#include "../utils/move.hpp"
#include "../utils/threadpool.hpp"
#include <chrono>
#include <map>
@ -47,7 +47,7 @@ static std::map<std::string, std::map<int, int>> pos2expected{
{3, 2812}, // 11
{4, 43238}, // 157
{5, 674624}, // 2199
// {6, 11030083},
{6, 11030083},
},
},
@ -55,11 +55,11 @@ static std::map<std::string, std::map<int, int>> pos2expected{
{
"r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 4",
{
{1, 6}, // 0
{2, 264}, // 1
{3, 9467}, // 69
{4, 422333}, // 3085
// {5, 15833292}, // 124452
{1, 6}, // 0
{2, 264}, // 1
{3, 9467}, // 69
{4, 422333}, // 3085
{5, 15833292}, // 124452
},
},
@ -67,11 +67,11 @@ static std::map<std::string, std::map<int, int>> pos2expected{
{
"r2q1rk1/pP1p2pp/Q4n2/bbp1p3/Np6/1B3NBn/pPPP1PPP/R3K2R b KQ - 0 5",
{
{1, 6}, // 0
{2, 264}, // 2
{3, 9467}, // 104
{4, 422333}, // 3742
// {5, 15833292}, // 136784
{1, 6}, // 0
{2, 264}, // 2
{3, 9467}, // 104
{4, 422333}, // 3742
{5, 15833292}, // 136784
},
},
@ -79,10 +79,10 @@ static std::map<std::string, std::map<int, int>> pos2expected{
{
"rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 6",
{
{1, 44}, // 0
{2, 1486}, // 12
{3, 62379}, // 357
// {4, 2103487}, // 13804
{1, 44}, // 0
{2, 1486}, // 12
{3, 62379}, // 357
{4, 2103487}, // 13804
// {5, 89941194}, // 1230428
},
},
@ -92,10 +92,10 @@ static std::map<std::string, std::map<int, int>> pos2expected{
"r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 "
"7",
{
{1, 46}, // 0
{2, 2079}, // 16
{3, 89890}, // 602
// {4, 3894594}, // 26612
{1, 46}, // 0
{2, 2079}, // 16
{3, 89890}, // 602
{4, 3894594}, // 26612
// {5, 164075551}, // 1230428
},
},
@ -141,6 +141,7 @@ int move_generation_test(
} else {
// Regular sequential execution
for (const Move& move : moves) {
// std::cout << "Looking at " << move << std::endl;
Board tmp_board = b.make_move(move);
int n = move_generation_test(tmp_board, depth - 1, max_depth, pool);
if (depth == max_depth)

View File

@ -1,6 +1,6 @@
#include "../board.hpp"
#include "../coords.hpp"
#include "../move.hpp"
#include "../board/board.hpp"
#include "../utils/coords.hpp"
#include "../utils/move.hpp"
#include "piece.hpp"
#include <vector>

View File

@ -1,5 +1,6 @@
#include "../board.hpp"
#include "../coords.hpp"
#include "../board/board.hpp"
#include "../utils/coords.hpp"
#include "../utils/move.hpp"
#include "piece.hpp"
static bool is_clear_king_side(const Board& b, const Coords xy) {
@ -9,8 +10,9 @@ static bool is_clear_king_side(const Board& b, const Coords xy) {
return false;
std::optional<Move> move = move_for_position(b, xy, c);
Board board_after_move = b.make_move(move.value());
if (board_after_move.is_check_for(b.colour_at(xy)))
Board board_after_move = b.make_move(move.value(), false);
board_after_move = board_after_move.skip_turn();
if (board_after_move.is_check())
return false;
}
return true;
@ -23,8 +25,9 @@ static bool is_clear_queen_side(const Board& b, const Coords xy) {
return false;
std::optional<Move> move = move_for_position(b, xy, c);
Board board_after_move = b.make_move(move.value());
if (dx < 3 && board_after_move.is_check_for(b.colour_at(xy)))
Board board_after_move = b.make_move(move.value(), false);
board_after_move = board_after_move.skip_turn();
if (dx < 3 && board_after_move.is_check())
return false;
}
return true;
@ -45,7 +48,8 @@ std::vector<Move> king_moves(const Board& b, const Coords xy) {
}
}
if (b.is_check_for(b.colour_at(xy)))
if (b.is_check())
return keep_only_blocking(ret, b);
// -- Castles

View File

@ -1,6 +1,6 @@
#include "../board.hpp"
#include "../coords.hpp"
#include "../move.hpp"
#include "../board/board.hpp"
#include "../utils/coords.hpp"
#include "../utils/move.hpp"
#include "piece.hpp"
#include <vector>

View File

@ -0,0 +1,102 @@
#include "../board/board.hpp"
#include "../utils/coords.hpp"
#include "../utils/move.hpp"
#include "piece.hpp"
std::vector<Move> pawn_moves(const Board& b, const Coords xy) {
std::vector<Move> ret{};
Colour my_colour = b.colour_at(xy);
// -- Capture to the left
if (xy.x > 0) {
int dy = my_colour == Colour::White ? 1 : -1;
Coords left{xy.x - 1, xy.y + dy};
int8_t capturable_piece = b.squares[left.to_index()];
if (capturable_piece != 0 && my_colour != b.colour_at(left)) {
if ((my_colour == White && left.y == 7)
|| (my_colour == Black && left.y == 0))
for (auto piece : {Rook, Knigt, Bishop, Queen})
ret.push_back(Move{
xy.to_index(),
left.to_index(),
(Piece) (my_colour | piece)
});
else
ret.push_back(Move{xy.to_index(), left.to_index()});
}
}
// -- Capture to the right
if (xy.x < 7) {
int dy = my_colour == Colour::White ? 1 : -1;
Coords right{xy.x + 1, xy.y + dy};
int8_t capturable_piece = b.squares[right.to_index()];
if (capturable_piece != 0 && my_colour != b.colour_at(right)) {
if ((my_colour == White && right.y == 7)
|| (my_colour == Black && right.y == 0))
for (auto piece : {Rook, Knigt, Bishop, Queen})
ret.push_back(Move{
xy.to_index(),
right.to_index(),
(Piece) (my_colour | piece)
});
else
ret.push_back(Move{xy.to_index(), right.to_index()});
}
}
// -- Capture en passant
if (b.en_passant_target != -1) {
Coords c = Coords::from_index(b.en_passant_target);
int dy = my_colour == Colour::White ? 1 : -1;
if (c.y == xy.y + dy && (c.x == xy.x - 1 || c.x == xy.x + 1))
ret.push_back(Move{xy.to_index(), c.to_index()});
}
// -- Normal move + promotion
bool is_on_starting_rank =
my_colour == Colour::White ? xy.y == 1 : xy.y == 6;
int max_dy = is_on_starting_rank ? 3 : 2;
for (int dy = 1; dy < max_dy; dy++) {
int actual_dy = my_colour == Colour::White ? dy : -dy;
Coords new_xy{xy.x, xy.y + actual_dy};
if (b.squares[new_xy.to_index()] != Piece::None)
break;
if (new_xy.y == 7 || new_xy.y == 0)
for (auto piece : {Rook, Knigt, Bishop, Queen})
ret.push_back(Move{
xy.to_index(),
new_xy.to_index(),
(Piece) (my_colour | piece)
});
else
ret.push_back(Move{
xy.to_index(),
new_xy.to_index(),
});
}
return ret;
}
std::vector<int8_t> pawn_attack_map(const Board& b, Coords xy) {
std::vector<int8_t> ret{};
Colour my_colour = b.colour_at(xy);
// -- Capture to the left
if (xy.x > 0) {
int dy = my_colour == Colour::White ? 1 : -1;
Coords left{xy.x - 1, xy.y + dy};
ret.push_back(left.to_index());
}
// -- Capture to the right
if (xy.x < 7) {
int dy = my_colour == Colour::White ? 1 : -1;
Coords right{xy.x + 1, xy.y + dy};
ret.push_back(right.to_index());
}
return ret;
}

View File

@ -1,18 +1,20 @@
#include "piece.hpp"
#include "../board.hpp"
#include "../coords.hpp"
#include "../board/board.hpp"
#include "../utils/coords.hpp"
#include "../utils/move.hpp"
std::vector<Move>
keep_only_blocking(const std::vector<Move> candidates, const Board& board) {
if (candidates.size() == 0)
return {};
int8_t my_colour = board.colour_at(candidates[0].source_square);
std::vector<Move> ret;
for (Move move : candidates) {
Board board_after_move = board.make_move(move);
if (!board_after_move.is_check_for(my_colour))
Board board_after_move = board.make_move(move, false);
board_after_move = board_after_move.skip_turn();
if (!board_after_move.is_check())
ret.push_back(move);
}
return ret;

View File

@ -20,7 +20,42 @@ enum Colour : int8_t {
Black = 16,
};
inline std::ostream& operator<<(std::ostream& os, const int8_t& i) {
inline const char* to_string(Colour c) {
switch (c) {
case White:
return "White";
case Black:
return "Black";
default:
return "[Unknown Colour]";
}
}
inline const char* to_string(Piece c) {
switch (c) {
case Pawn:
return "Pawn";
case Rook:
return "Rook";
case Bishop:
return "Bishop";
case Knigt:
return "Knight";
case Queen:
return "Queen";
case King:
return "King";
default:
return "[Unknown Colour]";
}
}
inline std::ostream& operator<<(std::ostream& os, const Colour& i) {
os << std::to_string(i);
return os;
}
inline std::ostream& operator<<(std::ostream& os, const Piece& i) {
os << std::to_string(i);
return os;
}
@ -34,6 +69,7 @@ std::vector<Move> keep_only_blocking(const std::vector<Move>, const Board&);
std::optional<Move> move_for_position(const Board&, const Coords, const Coords);
std::vector<Move> look_direction(const Board&, const Coords, int, int);
std::vector<int8_t> pawn_attack_map(const Board&, const Coords);
std::vector<Move> pawn_moves(const Board&, const Coords);
std::vector<Move> rook_moves(const Board&, const Coords);
std::vector<Move> knight_moves(const Board&, const Coords);

View File

@ -1,6 +1,6 @@
#include "../board.hpp"
#include "../coords.hpp"
#include "../move.hpp"
#include "../board/board.hpp"
#include "../utils/coords.hpp"
#include "../utils/move.hpp"
#include "piece.hpp"
#include <vector>

View File

@ -1,6 +1,6 @@
#include "../board.hpp"
#include "../coords.hpp"
#include "../move.hpp"
#include "../board/board.hpp"
#include "../utils/coords.hpp"
#include "../utils/move.hpp"
#include "piece.hpp"
#include <vector>

View File

@ -0,0 +1,26 @@
#include "move.hpp"
#include "../board/board.hpp"
#include "utils.hpp"
#include <algorithm>
int Move::score_guess(const Board& b) const {
int ret = 0;
Piece me_piece = b.piece_at(source_square);
Piece captured_piece = b.piece_at(target_square);
if (captured_piece != Piece::None)
ret += 10 * piece_value(captured_piece) - piece_value(me_piece);
if (promoting_to != Piece::None)
ret += piece_value(promoting_to);
std::vector<int8_t> pawn_attack_map = b.opponent_pawn_attack_map();
if (std::find(pawn_attack_map.begin(), pawn_attack_map.end(), target_square)
!= pawn_attack_map.end())
ret -= me_piece;
return ret;
}

View File

@ -1,8 +1,8 @@
#pragma once
#include "castle_side.hpp"
#include "../board/castle_side.hpp"
#include "../pieces/piece.hpp"
#include "coords.hpp"
#include "pieces/piece.hpp"
#include <cstdint>
#include <sstream>
@ -11,7 +11,9 @@ struct Move {
int8_t source_square;
int8_t target_square;
int8_t promoting_to = Piece::None;
Piece promoting_to = Piece::None;
int score_guess(const Board&) const;
std::string to_string() const {
std::stringstream ss;
@ -39,6 +41,10 @@ struct Move {
}
};
inline bool operator<(const Move& m1, const Move& m2) {
return m1.to_string() < m2.to_string();
}
inline std::ostream& operator<<(std::ostream& os, const Move& m) {
os << m.to_string();
return os;

View File

@ -0,0 +1,35 @@
#include "utils.hpp"
#include "../board/board.hpp"
std::vector<int8_t> to_target_square(std::vector<Move> moves) {
std::vector<int8_t> ret;
for (Move move : moves)
ret.push_back(move.target_square);
return ret;
}
int piece_value(Piece p) {
switch (p) {
case Piece::Pawn:
return PawnValue;
case Piece::Knigt:
return KnightValue;
case Piece::Bishop:
return BishopValue;
case Piece::Rook:
return RookValue;
case Piece::Queen:
return QueenValue;
default:
return 0;
}
}
int count_material(const Board& b, int8_t colour) {
int ret = 0;
for (int i = 0; i < 64; i++)
if (b.colour_at(i) == colour)
ret += piece_value(b.piece_at(i));
return ret;
}

View File

@ -0,0 +1,19 @@
#pragma once
#include "move.hpp"
#include <cstdint>
#include <limits>
#include <vector>
std::vector<int8_t> to_target_square(std::vector<Move>);
int count_material(const Board&, int8_t);
int piece_value(Piece);
const int INFINITY = std::numeric_limits<int>::max();
const int PawnValue = 100;
const int KnightValue = 300;
const int BishopValue = 320;
const int RookValue = 500;
const int QueenValue = 900;

View File

@ -1,84 +0,0 @@
#include "../board.hpp"
#include "../coords.hpp"
#include "../move.hpp"
#include "piece.hpp"
std::vector<Move> pawn_moves(const Board& b, const Coords xy) {
std::vector<Move> ret{};
int8_t my_colour = b.colour_at(xy);
// -- Capture to the left
if (xy.x > 0) {
int dy = my_colour == Colour::White ? 1 : -1;
Coords left{xy.x - 1, xy.y + dy};
int8_t capturable_piece = b.squares[left.to_index()];
if (capturable_piece != 0) {
if (my_colour != b.colour_at(left))
if ((my_colour == White && left.y == 7)
|| (my_colour == Black && left.y == 0))
for (auto piece : {Rook, Knigt, Bishop, Queen})
ret.push_back(Move{
xy.to_index(),
left.to_index(),
.promoting_to = (int8_t) (my_colour | piece)
});
else
ret.push_back(Move{xy.to_index(), left.to_index()});
}
}
// -- Capture to the right
if (xy.x < 7) {
int dy = my_colour == Colour::White ? 1 : -1;
Coords right{xy.x + 1, xy.y + dy};
int8_t capturable_piece = b.squares[right.to_index()];
if (capturable_piece != 0) {
if (my_colour != b.colour_at(right))
if ((my_colour == White && right.y == 7)
|| (my_colour == Black && right.y == 0))
for (auto piece : {Rook, Knigt, Bishop, Queen})
ret.push_back(Move{
xy.to_index(),
right.to_index(),
.promoting_to = (int8_t) (my_colour | piece)
});
else
ret.push_back(Move{xy.to_index(), right.to_index()});
}
}
// -- Capture en passant
if (b.en_passant_target != -1) {
Coords c = Coords::from_index(b.en_passant_target);
int dy = my_colour == Colour::White ? 1 : -1;
if (c.y == xy.y + dy && (c.x == xy.x - 1 || c.x == xy.x + 1))
ret.push_back(Move{xy.to_index(), c.to_index()});
}
// -- Normal move + promotion
bool is_on_starting_rank =
my_colour == Colour::White ? xy.y == 1 : xy.y == 6;
int max_dy = is_on_starting_rank ? 3 : 2;
for (int dy = 1; dy < max_dy; dy++) {
int actual_dy = my_colour == Colour::White ? dy : -dy;
Coords new_xy{xy.x, xy.y + actual_dy};
if (b.squares[new_xy.to_index()] != Piece::None)
break;
if (new_xy.y == 7 || new_xy.y == 0)
for (auto piece : {Rook, Knigt, Bishop, Queen})
ret.push_back(Move{
xy.to_index(),
new_xy.to_index(),
.promoting_to = (int8_t) (my_colour | piece)
});
else
ret.push_back(Move{
xy.to_index(),
new_xy.to_index(),
});
}
return ret;
}

215
cpp/src/view/gui.cpp Normal file
View File

@ -0,0 +1,215 @@
#include "gui.hpp"
#include "../model/utils/utils.hpp"
#include <SFML/Graphics/Color.hpp>
#include <SFML/System/Vector2.hpp>
GUI::GUI() {
window.create(sf::VideoMode(WINDOW_SIZE, WINDOW_SIZE), "Chess Board");
load_textures();
font.loadFromFile("res/arial.ttf");
}
void GUI::update_board(
const Board& b, int8_t selected_square, std::vector<int8_t> targets
) {
window.clear();
draw_board(selected_square, targets);
draw_pieces(b);
window.display();
}
void GUI::notify_stalemate(Colour col) {
std::cout << "Stalemate for " << to_string(col) << std::endl;
}
void GUI::notify_checkmate(Colour col) {
std::cout << "Checkmate for " << to_string(col) << std::endl;
}
void GUI::handle_events() {
sf::Event event;
while (window.pollEvent(event))
if (event.type == sf::Event::Closed)
window.close();
else if (event.type == sf::Event::MouseButtonPressed)
handle_click(event.mouseButton.x, event.mouseButton.y);
}
void GUI::load_textures() {
const std::string names[6] =
{"rook", "knight", "bishop", "queen", "king", "pawn"
}; // don't touch the order, it's reflecting the one in the Piece enum
for (int i = 0; i < 6; ++i) {
textures[i][0].loadFromFile("res/pieces/white-" + names[i] + ".png");
textures[i][1].loadFromFile("res/pieces/black-" + names[i] + ".png");
}
}
void GUI::handle_click(int x, int y) {
int file = x / TILE_SIZE;
int rank = 7 - (y / TILE_SIZE);
controller->on_tile_selected(file, rank);
}
void GUI::draw_annotation(int file, int rank) {
if (file == 0) {
sf::Text annotation(std::to_string(rank + 1), font);
annotation.setStyle(sf::Text::Bold);
annotation.setCharacterSize(16);
annotation.setFillColor(rank % 2 == 0 ? colours[1] : colours[0]);
annotation.setPosition(
(file + .05) * TILE_SIZE,
(7 - rank + .05) * TILE_SIZE
);
window.draw(annotation);
}
if (rank == 0) {
sf::Text annotation("abcdefgh"[file], font);
annotation.setCharacterSize(16);
annotation.setOrigin(16, 16);
annotation.setStyle(sf::Text::Bold);
annotation.setFillColor(file % 2 == 0 ? colours[1] : colours[0]);
annotation.setPosition(
(file + 1) * TILE_SIZE,
(7 - rank + .95) * TILE_SIZE
);
window.draw(annotation);
}
}
void GUI::draw_board(int selected_square, std::vector<int8_t> targets) {
sf::RectangleShape square(sf::Vector2f(TILE_SIZE, TILE_SIZE));
for (int rank = 0; rank < 8; ++rank) {
for (int file = 0; file < 8; ++file) {
int8_t index = Coords{file, rank}.to_index();
square.setPosition(file * TILE_SIZE, (7 - rank) * TILE_SIZE);
if (index == selected_square)
square.setFillColor(
(file + rank) % 2 == 0 ? alt_colours[0] : alt_colours[1]
);
else
square.setFillColor(
(file + rank) % 2 == 0 ? colours[0] : colours[1]
);
window.draw(square);
draw_annotation(file, rank);
if (std::find(targets.begin(), targets.end(), index)
!= targets.end()) {
float r = .15 * TILE_SIZE;
sf::CircleShape circle{r};
sf::Color c(0x00000055);
circle.setFillColor(c);
circle.setOrigin(r, r);
circle.setPosition(
(file + .5) * TILE_SIZE,
(7 - rank + .5) * TILE_SIZE
);
window.draw(circle);
}
}
}
}
void GUI::draw_pieces(const Board& board) {
for (int i = 0; i < 64; ++i) {
int piece = board.piece_at(i);
if (piece != Piece::None) {
int colour = board.colour_at(i) == Colour::White ? 0 : 1;
pieces[i].setTexture(textures[piece - 1][colour]);
sf::Vector2 center = textures[piece - 1][colour].getSize() / 2u;
pieces[i].setOrigin(center.x, center.y);
pieces[i].setPosition(
(i % 8 + .5) * TILE_SIZE,
(7 - (int) (i / 8) + .5) * TILE_SIZE
);
window.draw(pieces[i]);
}
}
}
int GUI::show_popup(
const std::string& message, const std::vector<std::string>& options
) {
sf::RenderWindow popup(sf::VideoMode(300, 200), "Choice");
sf::Font font;
if (!font.loadFromFile("res/arial.ttf")) {
std::cerr << "Error: Could not load font!" << std::endl;
return -1;
}
sf::Text text(message, font, 20);
text.setPosition(20, 20);
text.setFillColor(sf::Color::Black);
std::vector<sf::RectangleShape> buttonShapes;
std::vector<sf::Text> buttonTexts;
for (size_t i = 0; i < options.size(); ++i) {
sf::RectangleShape button(sf::Vector2f(200, 30));
button.setPosition(50, 70 + i * 40);
button.setFillColor(sf::Color(150, 150, 150));
buttonShapes.push_back(button);
sf::Text buttonText(options[i], font, 18);
buttonText.setPosition(60, 75 + i * 40);
buttonText.setFillColor(sf::Color::Black);
buttonTexts.push_back(buttonText);
}
while (popup.isOpen()) {
sf::Event event;
while (popup.pollEvent(event)) {
if (event.type == sf::Event::Closed)
popup.close();
else if (event.type == sf::Event::MouseButtonPressed) {
for (size_t i = 0; i < buttonShapes.size(); ++i) {
if (buttonShapes[i].getGlobalBounds().contains(
event.mouseButton.x,
event.mouseButton.y
)) {
popup.close();
return i;
}
}
}
}
popup.clear(sf::Color::White);
popup.draw(text);
for (size_t i = 0; i < buttonShapes.size(); ++i) {
popup.draw(buttonShapes[i]);
popup.draw(buttonTexts[i]);
}
popup.display();
}
return -1;
}
Piece GUI::ask_about_promotion() {
std::vector<std::string> options = {"Queen", "Rook", "Bishop", "Knight"};
int idx = show_popup("Please choose a promotion for your pawn", options);
switch (idx) {
case 0:
return Queen;
case 1:
return Rook;
case 2:
return Bishop;
case 3:
return Knigt;
};
return Piece::None;
}
void GUI::show() {
while (window.isOpen())
handle_events();
}

41
cpp/src/view/gui.hpp Normal file
View File

@ -0,0 +1,41 @@
#pragma once
#include "../model/board/board.hpp"
#include "view.hpp"
#include <SFML/Graphics.hpp>
const int TILE_SIZE = 80;
const int BOARD_SIZE = 8;
const int WINDOW_SIZE = TILE_SIZE * BOARD_SIZE;
class GUI : public View {
public:
GUI();
void show() override;
Piece ask_about_promotion();
void update_board(const Board&, int8_t, std::vector<int8_t>) override;
void notify_checkmate(Colour) override;
void notify_stalemate(Colour) override;
private:
sf::RenderWindow window;
sf::Texture textures[6][2];
sf::Sprite pieces[64];
sf::Font font;
sf::Color colours[2] = {sf::Color(0xB88762FF), sf::Color(0xEDD6B0FF)};
sf::Color alt_colours[2] = {sf::Color(0xDCC34BFF), sf::Color(0xF6EB72FF)};
int show_popup(
const std::string& message, const std::vector<std::string>& options
);
void load_textures();
void handle_events();
void handle_click(int, int);
void draw_board(int, std::vector<int8_t>);
void draw_pieces(const Board&);
void draw_annotation(int, int);
};

16
cpp/src/view/noop.hpp Normal file
View File

@ -0,0 +1,16 @@
#include "../model/board/board.hpp"
#include "view.hpp"
class NoOpView : public View {
public:
NoOpView() {};
void show() override {};
void update_board(const Board&, int8_t, std::vector<int8_t>) override {};
void notify_checkmate(Colour) override{};
void notify_stalemate(Colour) override{};
Piece ask_about_promotion() override {
return Queen;
};
};

22
cpp/src/view/view.hpp Normal file
View File

@ -0,0 +1,22 @@
#pragma once
#include "../controller/controller.hpp"
#include "../model/board/board.hpp"
#include "../model/pieces/piece.hpp"
#include "../model/utils/move.hpp"
class View {
protected:
Controller* controller;
public:
void set_controller(Controller* c) {
controller = c;
}
virtual void show() = 0;
virtual Piece ask_about_promotion() = 0;
virtual void update_board(const Board&, int8_t, std::vector<int8_t>) = 0;
virtual void notify_checkmate(Colour) = 0;
virtual void notify_stalemate(Colour) = 0;
};

View File

@ -1,4 +1,4 @@
#include "../src/board.hpp"
#include "../src/model/board/board.hpp"
#include "lib.hpp"
int main() {

View File

@ -1,4 +1,4 @@
#include "../src/coords.hpp"
#include "../src/model/utils/coords.hpp"
#include "lib.hpp"
int main() {