MrSimple07 commited on
Commit
054c349
Β·
1 Parent(s): 68b94c6

new version with csv

Browse files
Files changed (4) hide show
  1. Chess Opening Reference - Sheet1.csv +501 -0
  2. app.py +60 -194
  3. app_1.py +645 -234
  4. openings.py +3 -0
Chess Opening Reference - Sheet1.csv ADDED
@@ -0,0 +1,501 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ECO Code,Name,Opening Moves
2
+ A00,Uncommon Opening,"1 g4, a3, h3, etc."
3
+ A01,Nimzovich-Larsen Attack,1 b3
4
+ A02,Bird's Opening,1 f4
5
+ A03,Bird's Opening,1 f4 d5
6
+ A04,Reti Opening,1 Nf3
7
+ A05,Reti Opening,1 Nf3 Nf6
8
+ A06,Reti Opening,1 Nf3 d5
9
+ A07,King's Indian Attack,1 Nf3 d5 2 g3
10
+ A08,King's Indian Attack,1 Nf3 d5 2 g3 c5 3 Bg2
11
+ A09,Reti Opening,1 Nf3 d5 2 c4
12
+ A10,English,1 c4
13
+ A11,"English, Caro-Kann Defensive System",1 c4 c6
14
+ A12,English with b3,1 c4 c6 2 Nf3 d5 3 b3
15
+ A13,English,1 c4 e6
16
+ A14,English,1 c4 e6 2 Nf3 d5 3 g3 Nf6 4 Bg2 Be7 5 O-O
17
+ A15,English,1 c4 Nf6
18
+ A16,English,1 c4 Nf6 2 Nc3
19
+ A17,English,1 c4 Nf6 2 Nc3 e6
20
+ A18,"English, Mikenas-Carls",1 c4 Nf6 2 Nc3 e6 3 e4
21
+ A19,"English, Mikenas-Carls, Sicilian Variation",1 c4 Nf6 2 Nc3 e6 3 e4 c5
22
+ A20,English,1 c4 e5
23
+ A21,English,1 c4 e5 2 Nc3
24
+ A22,English,1 c4 e5 2 Nc3 Nf6
25
+ A23,"English, Bremen System, Keres Variation",1 c4 e5 2 Nc3 Nf6 3 g3 c6
26
+ A24,"English, Bremen System with ...g6",1 c4 e5 2 Nc3 Nf6 3 g3 g6
27
+ A25,English,1 c4 e5 2 Nc3 Nc6
28
+ A26,English,1 c4 e5 2 Nc3 Nc6 3 g3 g6 4 Bg2 Bg7 5 d3 d6
29
+ A27,"English, Three Knights System",1 c4 e5 2 Nc3 Nc6 3 Nf3
30
+ A28,English,1 c4 e5 2 Nc3 Nc6 3 Nf3 Nf6
31
+ A29,"English, Four Knights, Kingside Fianchetto",1 c4 e5 2 Nc3 Nc6 3 Nf3 Nf6 4 g3
32
+ A30,"English, Symmetrical",1 c4 c5
33
+ A31,"English, Symmetrical, Benoni Formation",1 c4 c5 2 Nf3 Nf6 3 d4
34
+ A32,"English, Symmetrical Variation",1 c4 c5 2 Nf3 Nf6 3 d4 cxd4 4 Nxd4 e6
35
+ A33,"English, Symmetrical",1 c4 c5 2 Nf3 Nf6 3 d4 cxd4 4 Nxd4 e6 5 Nc3 Nc6
36
+ A34,"English, Symmetrical",1 c4 c5 2 Nc3
37
+ A35,"English, Symmetrical",1 c4 c5 2 Nc3 Nc6
38
+ A36,English,1 c4 c5 2 Nc3 Nc6 3 g3
39
+ A37,"English, Symmetrical",1 c4 c5 2 Nc3 Nc6 3 g3 g6 4 Bg2 Bg7 5 Nf3
40
+ A38,"English, Symmetrical",1 c4 c5 2 Nc3 Nc6 3 g3 g6 4 Bg2 Bg7 5 Nf3 Nf6
41
+ A39,"English, Symmetrical, Main line with d4",1 c4 c5 2 Nc3 Nc6 3 g3 g6 4 Bg2 Bg7 5 Nf3 Nf6 6 O-O O-O 7 d4
42
+ A40,Queen's Pawn Game,1 d4
43
+ A41,Queen's Pawn Game (with ...d6),1 d4 d6
44
+ A42,"Modern Defense, Averbakh System",1 d4 d6 2 c4 g6 3 Nc3 Bg7 4 e4
45
+ A43,Old Benoni,1 d4 c5
46
+ A44,Old Benoni Defense,1 d4 c5 2 d5 e5
47
+ A45,Queen's Pawn Game,1 d4 Nf6
48
+ A46,Queen's Pawn Game,1 d4 Nf6 2 Nf3
49
+ A47,Queen's Indian,1 d4 Nf6 2 Nf3 b6
50
+ A48,King's Indian,1 d4 Nf6 2 Nf3 g6
51
+ A49,"King's Indian, Fianchetto without c4",1 d4 Nf6 2 Nf3 g6 3 g3
52
+ A50,Queen's Pawn Game,1 d4 Nf6 2 c4
53
+ A51,Budapest Gambit,1 d4 Nf6 2 c4 e5
54
+ A52,Budapest Gambit,1 d4 Nf6 2 c4 e5 3 dxe5 Ng4
55
+ A53,Old Indian,1 d4 Nf6 2 c4 d6
56
+ A54,"Old Indian, Ukrainian Variation, 4.Nf3",1 d4 Nf6 2 c4 d6 3 Nc3 e5 4 Nf3
57
+ A55,"Old Indian, Main line",1 d4 Nf6 2 c4 d6 3 Nc3 e5 4 Nf3 Nbd7 5 e4
58
+ A56,Benoni Defense,1 d4 Nf6 2 c4 c5
59
+ A57,Benko Gambit,1 d4 Nf6 2 c4 c5 3 d5 b5
60
+ A58,Benko Gambit,1 d4 Nf6 2 c4 c5 3 d5 b5 4 cxb5 a6 5 bxa6
61
+ A59,Benko Gambit,1 d4 Nf6 2 c4 c5 3 d5 b5 4 cxb5 a6 5 bxa6 Bxa6 6 Nc3 d6 7 e4
62
+ A60,Benoni Defense,1 d4 Nf6 2 c4 c5 3 d5 e6
63
+ A61,Benoni,1 d4 Nf6 2 c4 c5 3 d5 e6 4 Nc3 exd5 5 cxd5 d6 6 Nf3 g6
64
+ A62,"Benoni, Fianchetto Variation",1 d4 Nf6 2 c4 c5 3 d5 e6 4 Nc3 exd5 5 cxd5 d6 6 Nf3 g6 7 g3 Bg7 8 Bg2 O-O
65
+ A63,"Benoni, Fianchetto, 9...Nbd7",1 d4 Nf6 2 c4 c5 3 d5 e6 4 Nc3 exd5 5 cxd5 d6 6 Nf3 g6 7 g3 Bg7 8 Bg2 O-O 9
66
+ A64,"Benoni, Fianchetto, 11...Re8",1 d4 Nf6 2 c4 c5 3 d5 e6 4 Nc3 exd5 5 cxd5 d6 6 Nf3 g6 7 g3 Bg7 8 Bg2 O-O 9
67
+ A65,"Benoni, 6.e4",1 d4 Nf6 2 c4 c5 3 d5 e6 4 Nc3 exd5 5 cxd5 d6 6 e4
68
+ A66,Benoni,1 d4 Nf6 2 c4 c5 3 d5 e6 4 Nc3 exd5 5 cxd5 d6 6 e4 g6 7 f4
69
+ A67,"Benoni, Taimanov Variation",1 d4 Nf6 2 c4 c5 3 d5 e6 4 Nc3 exd5 5 cxd5 d6 6 e4 g6 7 f4 Bg7 8 Bb5+
70
+ A68,"Benoni, Four Pawns Attack",1 d4 Nf6 2 c4 c5 3 d5 e6 4 Nc3 exd5 5 cxd5 d6 6 e4 g6 7 f4 Bg7 8 Nf3 O-O
71
+ A69,"Benoni, Four Pawns Attack, Main line",1 d4 Nf6 2 c4 c5 3 d5 e6 4 Nc3 exd5 5 cxd5 d6 6 e4 g6 7 f4 Bg7 8 Nf3 O-O 9
72
+ A70,"Benoni, Classical with 7.Nf3",1 d4 Nf6 2 c4 c5 3 d5 e6 4 Nc3 exd5 5 cxd5 d6 6 e4 g6 7 Nf3
73
+ A71,"Benoni, Classical, 8.Bg5",1 d4 Nf6 2 c4 c5 3 d5 e6 4 Nc3 exd5 5 cxd5 d6 6 e4 g6 7 Nf3 Bg7 8 Bg5
74
+ A72,"Benoni, Classical without 9.O-O",1 d4 Nf6 2 c4 c5 3 d5 e6 4 Nc3 exd5 5 cxd5 d6 6 e4 g6 7 Nf3 Bg7 8 Be2 O-O
75
+ A73,"Benoni, Classical, 9.O-O",1 d4 Nf6 2 c4 c5 3 d5 e6 4 Nc3 exd5 5 cxd5 d6 6 e4 g6 7 Nf3 Bg7 8 Be2 O-O 9
76
+ A74,"Benoni, Classical, 9...a6, 10.a4",1 d4 Nf6 2 c4 c5 3 d5 e6 4 Nc3 exd5 5 cxd5 d6 6 e4 g6 7 Nf3 Bg7 8 Be2 O-O 9
77
+ A75,"Benoni, Classical with ...a6 and 10...Bg4",1 d4 Nf6 2 c4 c5 3 d5 e6 4 Nc3 exd5 5 cxd5 d6 6 e4 g6 7 Nf3 Bg7 8 Be2 O-O 9
78
+ A76,"Benoni, Classical, 9...Re8",1 d4 Nf6 2 c4 c5 3 d5 e6 4 Nc3 exd5 5 cxd5 d6 6 e4 g6 7 Nf3 Bg7 8 Be2 O-O 9
79
+ A77,"Benoni, Classical, 9...Re8, 10.Nd2",1 d4 Nf6 2 c4 c5 3 d5 e6 4 Nc3 exd5 5 cxd5 d6 6 e4 g6 7 Nf3 Bg7 8 Be2 O-O 9
80
+ A78,"Benoni, Classical with ...Re8 and ...Na6",1 d4 Nf6 2 c4 c5 3 d5 e6 4 Nc3 exd5 5 cxd5 d6 6 e4 g6 7 Nf3 Bg7 8 Be2 O-O 9
81
+ A79,"Benoni, Classical, 11.f3",1 d4 Nf6 2 c4 c5 3 d5 e6 4 Nc3 exd5 5 cxd5 d6 6 e4 g6 7 Nf3 Bg7 8 Be2 O-O 9
82
+ A80,Dutch,1 d4 f5
83
+ A81,Dutch,1 d4 f5 2 g3
84
+ A82,"Dutch, Staunton Gambit",1 d4 f5 2 e4
85
+ A83,"Dutch, Staunton Gambit",1 d4 f5 2 e4 fxe4 3 Nc3 Nf6 4 Bg5
86
+ A84,Dutch,1 d4 f5 2 c4
87
+ A85,"Dutch, with c4 & Nc3",1 d4 f5 2 c4 Nf6 3 Nc3
88
+ A86,Dutch,1 d4 f5 2 c4 Nf6 3 g3
89
+ A87,"Dutch, Leningrad, Main Variation",1 d4 f5 2 c4 Nf6 3 g3 g6 4 Bg2 Bg7 5 Nf3
90
+ A88,"Dutch, Leningrad, Main Variation with c6",1 d4 f5 2 c4 Nf6 3 g3 g6 4 Bg2 Bg7 5 Nf3 O-O 6 O-O d6 7 Nc3 c6
91
+ A89,"Dutch, Leningrad, Main Variation with Nc6",1 d4 f5 2 c4 Nf6 3 g3 g6 4 Bg2 Bg7 5 Nf3 O-O 6 O-O d6 7 Nc3 Nc6
92
+ A90,Dutch,1 d4 f5 2 c4 Nf6 3 g3 e6 4 Bg2
93
+ A91,Dutch Defense,1 d4 f5 2 c4 Nf6 3 g3 e6 4 Bg2 Be7
94
+ A92,Dutch,1 d4 f5 2 c4 Nf6 3 g3 e6 4 Bg2 Be7 5 Nf3 O-O
95
+ A93,"Dutch, Stonewall, Botvinnik Variation",1 d4 f5 2 c4 Nf6 3 g3 e6 4 Bg2 Be7 5 Nf3 O-O 6 O-O d5 7 b3
96
+ A94,"Dutch, Stonewall with Ba3",1 d4 f5 2 c4 Nf6 3 g3 e6 4 Bg2 Be7 5 Nf3 O-O 6 O-O d5 7 b3 c6 8 Ba3
97
+ A95,"Dutch, Stonewall",1 d4 f5 2 c4 Nf6 3 g3 e6 4 Bg2 Be7 5 Nf3 O-O 6 O-O d5 7 Nc3 c6
98
+ A96,"Dutch, Classical Variation",1 d4 f5 2 c4 Nf6 3 g3 e6 4 Bg2 Be7 5 Nf3 O-O 6 O-O d6
99
+ A97,"Dutch, Ilyin-Genevsky",1 d4 f5 2 c4 Nf6 3 g3 e6 4 Bg2 Be7 5 Nf3 O-O 6 O-O d6 7 Nc3 Qe8
100
+ A98,"Dutch, Ilyin-Genevsky Variation with Qc2",1 d4 f5 2 c4 Nf6 3 g3 e6 4 Bg2 Be7 5 Nf3 O-O 6 O-O d6 7 Nc3 Qe8 8 Qc2
101
+ A99,"Dutch, Ilyin-Genevsky Variation with b3",1 d4 f5 2 c4 Nf6 3 g3 e6 4 Bg2 Be7 5 Nf3 O-O 6 O-O d6 7 Nc3 Qe8 8 b3
102
+ B00,Uncommon King's Pawn Opening,1 e4
103
+ B01,Scandinavian,1 e4 d5
104
+ B02,Alekhine's Defense,1 e4 Nf6
105
+ B03,Alekhine's Defense,1 e4 Nf6 2 e5 Nd5 3 d4
106
+ B04,"Alekhine's Defense, Modern",1 e4 Nf6 2 e5 Nd5 3 d4 d6 4 Nf3
107
+ B05,"Alekhine's Defense, Modern",1 e4 Nf6 2 e5 Nd5 3 d4 d6 4 Nf3 Bg4
108
+ B06,Robatsch,1 e4 g6
109
+ B07,Pirc,1 e4 d6 2 d4 Nf6
110
+ B08,"Pirc, Classical",1 e4 d6 2 d4 Nf6 3 Nc3 g6 4 Nf3
111
+ B09,"Pirc, Austrian Attack",1 e4 d6 2 d4 Nf6 3 Nc3 g6 4 f4
112
+ B10,Caro-Kann,1 e4 c6
113
+ B11,"Caro-Kann, Two Knights, 3...Bg4",1 e4 c6 2 Nc3 d5 3 Nf3 Bg4
114
+ B12,Caro-Kann Defense,1 e4 c6 2 d4
115
+ B13,"Caro-Kann, Exchange",1 e4 c6 2 d4 d5 3 exd5 cxd5
116
+ B14,"Caro-Kann, Panov-Botvinnik Attack",1 e4 c6 2 d4 d5 3 exd5 cxd5 4 c4 Nf6 5 Nc3 e6
117
+ B15,Caro-Kann,1 e4 c6 2 d4 d5 3 Nc3
118
+ B16,"Caro-Kann, Bronstein-Larsen Variation",1 e4 c6 2 d4 d5 3 Nc3 dxe4 4 Nxe4 Nf6 5 Nxf6+ gxf6
119
+ B17,"Caro-Kann, Steinitz Variation",1 e4 c6 2 d4 d5 3 Nc3 dxe4 4 Nxe4 Nd7
120
+ B18,"Caro-Kann, Classical",1 e4 c6 2 d4 d5 3 Nc3 dxe4 4 Nxe4 Bf5
121
+ B19,"Caro-Kann, Classical",1 e4 c6 2 d4 d5 3 Nc3 dxe4 4 Nxe4 Bf5 5 Ng3 Bg6 6 h4 h6 7 Nf3 Nd7
122
+ B20,Sicilian,1 e4 c5
123
+ B21,"Sicilian, 2.f4 and 2.d4",1 e4 c5 2 f4
124
+ B22,"Sicilian, Alapin",1 e4 c5 2 c3
125
+ B23,"Sicilian, Closed",1 e4 c5 2 Nc3
126
+ B24,"Sicilian, Closed",1 e4 c5 2 Nc3 Nc6 3 g3
127
+ B25,"Sicilian, Closed",1 e4 c5 2 Nc3 Nc6 3 g3 g6 4 Bg2 Bg7 5 d3 d6
128
+ B26,"Sicilian, Closed, 6.Be3",1 e4 c5 2 Nc3 Nc6 3 g3 g6 4 Bg2 Bg7 5 d3 d6 6 Be3
129
+ B27,Sicilian,1 e4 c5 2 Nf3
130
+ B28,"Sicilian, O'Kelly Variation",1 e4 c5 2 Nf3 a6
131
+ B29,"Sicilian, Nimzovich-Rubinstein",1 e4 c5 2 Nf3 Nf6
132
+ B30,Sicilian,1 e4 c5 2 Nf3 Nc6
133
+ B31,"Sicilian, Rossolimo Variation",1 e4 c5 2 Nf3 Nc6 3 Bb5 g6
134
+ B32,Sicilian,1 e4 c5 2 Nf3 Nc6 3 d4 cxd4 4 Nxd4 e5
135
+ B33,Sicilian,1 e4 c5 2 Nf3 Nc6 3 d4 cxd4 4 Nxd4
136
+ B34,"Sicilian, Accelerated Fianchetto",1 e4 c5 2 Nf3 Nc6 3 d4 cxd4 4 Nxd4 g6 5 Nxc6
137
+ B35,"Sicilian, Accelerated Fianchetto, Modern Variation with Bc4",1 e4 c5 2 Nf3 Nc6 3 d4 cxd4 4 Nxd4 g6 5 Nc3 Bg7 6 Be3 Nf6 7 Bc4
138
+ B36,"Sicilian, Accelerated Fianchetto",1 e4 c5 2 Nf3 Nc6 3 d4 cxd4 4 Nxd4 g6 5 c4
139
+ B37,"Sicilian, Accelerated Fianchetto",1 e4 c5 2 Nf3 Nc6 3 d4 cxd4 4 Nxd4 g6 5 c4 Bg7
140
+ B38,"Sicilian, Accelerated Fianchetto, Maroczy Bind, 6.Be3",1 e4 c5 2 Nf3 Nc6 3 d4 cxd4 4 Nxd4 g6 5 c4 Bg7 6 Be3
141
+ B39,"Sicilian, Accelerated Fianchetto, Breyer Variation",1 e4 c5 2 Nf3 Nc6 3 d4 cxd4 4 Nxd4 g6 5 c4 Bg7 6 Be3 Nf6 7 Nc3 Ng4
142
+ B40,Sicilian,1 e4 c5 2 Nf3 e6
143
+ B41,"Sicilian, Kan",1 e4 c5 2 Nf3 e6 3 d4 cxd4 4 Nxd4 a6
144
+ B42,"Sicilian, Kan",1 e4 c5 2 Nf3 e6 3 d4 cxd4 4 Nxd4 a6 5 Bd3
145
+ B43,"Sicilian, Kan, 5.Nc3",1 e4 c5 2 Nf3 e6 3 d4 cxd4 4 Nxd4 a6 5 Nc3
146
+ B44,Sicilian,1 e4 c5 2 Nf3 e6 3 d4 cxd4 4 Nxd4 Nc6
147
+ B45,"Sicilian, Taimanov",1 e4 c5 2 Nf3 e6 3 d4 cxd4 4 Nxd4 Nc6 5 Nc3
148
+ B46,"Sicilian, Taimanov Variation",1 e4 c5 2 Nf3 e6 3 d4 cxd4 4 Nxd4 Nc6 5 Nc3 a6
149
+ B47,"Sicilian, Taimanov (Bastrikov) Variation",1 e4 c5 2 Nf3 e6 3 d4 cxd4 4 Nxd4 Nc6 5 Nc3 Qc7
150
+ B48,"Sicilian, Taimanov Variation",1 e4 c5 2 Nf3 e6 3 d4 cxd4 4 Nxd4 Nc6 5 Nc3 Qc7 6 Be3
151
+ B49,"Sicilian, Taimanov Variation",1 e4 c5 2 Nf3 e6 3 d4 cxd4 4 Nxd4 Nc6 5 Nc3 Qc7 6 Be3 a6 7 Be2
152
+ B50,Sicilian,1 e4 c5 2 Nf3 d6
153
+ B51,"Sicilian, Canal-Sokolsky (Rossolimo) Attack",1 e4 c5 2 Nf3 d6 3 Bb5+
154
+ B52,"Sicilian, Canal-Sokolsky (Rossolimo) Attack",1 e4 c5 2 Nf3 d6 3 Bb5+ Bd7
155
+ B53,Sicilian,1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Qxd4
156
+ B54,Sicilian,1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4
157
+ B55,"Sicilian, Prins Variation, Venice Attack",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 f3 e5 6 Bb5+
158
+ B56,Sicilian,1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3
159
+ B57,Sicilian,1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 Nc6 6 Bc4
160
+ B58,Sicilian,1 e4 c5 2 Nf3 Nc6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 d6 6 Be2
161
+ B59,"Sicilian, Boleslavsky Variation, 7.Nb3",1 e4 c5 2 Nf3 Nc6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 d6 6 Be2 e5 7 Nb3
162
+ B60,"Sicilian, Richter-Rauzer",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 Nc6 6 Bg5
163
+ B61,"Sicilian, Richter-Rauzer, Larsen Variation, 7.Qd2",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 Nc6 6 Bg5 Bd7 7 Qd2
164
+ B62,"Sicilian, Richter-Rauzer",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 Nc6 6 Bg5 e6
165
+ B63,"Sicilian, Richter-Rauzer Attack",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 Nc6 6 Bg5 e6 7 Qd2
166
+ B64,"Sicilian, Richter-Rauzer Attack",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 Nc6 6 Bg5 e6 7 Qd2 Be7 8 O-O-O O-O 9 f4
167
+ B65,"Sicilian, Richter-Rauzer Attack, 7...Be7 Defense, 9...Nxd4",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 Nc6 6 Bg5 e6 7 Qd2 Be7 8 O-O-O O-O 9 f4 Nxd4 10 Qxd4
168
+ B66,"Sicilian, Richter-Rauzer Attack, 7...a6",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 Nc6 6 Bg5 e6 7 Qd2 a6
169
+ B67,"Sicilian, Richter-Rauzer Attack, 7...a6 Defense, 8...Bd7",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 Nc6 6 Bg5 e6 7 Qd2 a6 8 O-O-O Bd7
170
+ B68,"Sicilian, Richter-Rauzer Attack, 7...a6 Defense, 9...Be7",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 Nc6 6 Bg5 e6 7 Qd2 a6 8 O-O-O Bd7 9 f4 Be7
171
+ B69,"Sicilian, Richter-Rauzer Attack, 7...a6 Defense, 11.Bxf6",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 Nc6 6 Bg5 e6 7 Qd2 a6 8 O-O-O Bd7 9 f4 Be7 10 Nf3 b5 11 Bxf6
172
+ B70,"Sicilian, Dragon Variation",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 g6
173
+ B71,"Sicilian, Dragon, Levenfish Variation",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 g6 6 f4
174
+ B72,"Sicilian, Dragon",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 g6 6 Be3
175
+ B73,"Sicilian, Dragon, Classical",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 g6 6 Be3 Bg7 7 Be2 Nc6 8 O-O
176
+ B74,"Sicilian, Dragon, Classical",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 g6 6 Be3 Bg7 7 Be2 Nc6 8 O-O O-O 9 Nb3
177
+ B75,"Sicilian, Dragon, Yugoslav Attack",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 g6 6 Be3 Bg7 7 f3
178
+ B76,"Sicilian, Dragon, Yugoslav Attack",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 g6 6 Be3 Bg7 7 f3 O-O
179
+ B77,"Sicilian, Dragon, Yugoslav Attack",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 g6 6 Be3 Bg7 7 f3 O-O 8 Qd2 Nc6 9 Bc4
180
+ B78,"Sicilian, Dragon, Yugoslav Attack, 10.castle long",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 g6 6 Be3 Bg7 7 f3 O-O 8 Qd2 Nc6 9 Bc4 Bd7 10 O-O-O
181
+ B79,"Sicilian, Dragon, Yugoslav Attack, 12.h4",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 g6 6 Be3 Bg7 7 f3 O-O 8 Qd2 Nc6 9 Bc4 Bd7 10 O-O-O Qa5 11 Bb3 Rfc8 12 h4
182
+ B80,"Sicilian, Scheveningen",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 e6
183
+ B81,"Sicilian, Scheveningen, Keres Attack",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 e6 6 g4
184
+ B82,"Sicilian, Scheveningen",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 e6 6 f4
185
+ B83,Sicilian,1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 e6 6 Be2
186
+ B84,"Sicilian, Scheveningen",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 e6 6 Be2 a6
187
+ B85,"Sicilian, Scheveningen, Classical",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 e6 6 Be2 a6 7 O-O Qc7 8 f4 Nc6
188
+ B86,"Sicilian, Fischer-Sozin Attack",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 e6 6 Bc4
189
+ B87,"Sicilian, Fischer-Sozin with ...a6 and ...b5",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 e6 6 Bc4 a6 7 Bb3 b5
190
+ B88,"Sicilian, Fischer-Sozin Attack",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 e6 6 Bc4 Nc6
191
+ B89,Sicilian,1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 e6 6 Bc4 Nc6 7 Be3
192
+ B90,"Sicilian, Najdorf",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 a6
193
+ B91,"Sicilian, Najdorf, Zagreb (Fianchetto) Variation",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 a6 6 g3
194
+ B92,"Sicilian, Najdorf, Opocensky Variation",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 a6 6 Be2
195
+ B93,"Sicilian, Najdorf, 6.f4",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 a6 6 f4
196
+ B94,"Sicilian, Najdorf",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 a6 6 Bg5
197
+ B95,"Sicilian, Najdorf, 6...e6",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 a6 6 Bg5 e6
198
+ B96,"Sicilian, Najdorf",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 a6 6 Bg5 e6 7 f4
199
+ B97,"Sicilian, Najdorf",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 a6 6 Bg5 e6 7 f4 Qb6
200
+ B98,"Sicilian, Najdorf",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 a6 6 Bg5 e6 7 f4 Be7
201
+ B99,"Sicilian, Najdorf, 7...Be7 Main line",1 e4 c5 2 Nf3 d6 3 d4 cxd4 4 Nxd4 Nf6 5 Nc3 a6 6 Bg5 e6 7 f4 Be7 8 Qf3 Qc7 9 O-O-O Nbd7
202
+ C00,French Defense,1 e4 e6
203
+ C01,"French, Exchange",1 e4 e6 2 d4 d5 3 exd5 exd5 4 Nc3 Nf6 5 Bg5
204
+ C02,"French, Advance",1 e4 e6 2 d4 d5 3 e5
205
+ C03,"French, Tarrasch",1 e4 e6 2 d4 d5 3 Nd2
206
+ C04,"French, Tarrasch, Guimard Main line",1 e4 e6 2 d4 d5 3 Nd2 Nc6 4 Ngf3 Nf6
207
+ C05,"French, Tarrasch",1 e4 e6 2 d4 d5 3 Nd2 Nf6
208
+ C06,"French, Tarrasch",1 e4 e6 2 d4 d5 3 Nd2 Nf6 4 e5 Nfd7 5 Bd3 c5 6 c3 Nc6 7 Ne2 cxd4 8 cxd4
209
+ C07,"French, Tarrasch",1 e4 e6 2 d4 d5 3 Nd2 c5
210
+ C08,"French, Tarrasch, Open, 4.ed ed",1 e4 e6 2 d4 d5 3 Nd2 c5 4 exd5 exd5
211
+ C09,"French, Tarrasch, Open Variation, Main line",1 e4 e6 2 d4 d5 3 Nd2 c5 4 exd5 exd5 5 Ngf3 Nc6
212
+ C10,French,1 e4 e6 2 d4 d5 3 Nc3
213
+ C11,French,1 e4 e6 2 d4 d5 3 Nc3 Nf6
214
+ C12,"French, McCutcheon",1 e4 e6 2 d4 d5 3 Nc3 Nf6 4 Bg5 Bb4
215
+ C13,French,1 e4 e6 2 d4 d5 3 Nc3 Nf6 4 Bg5 Be7
216
+ C14,"French, Classical",1 e4 e6 2 d4 d5 3 Nc3 Nf6 4 Bg5 Be7 5 e5 Nfd7 6 Bxe7 Qxe7
217
+ C15,"French, Winawer",1 e4 e6 2 d4 d5 3 Nc3 Bb4
218
+ C16,"French, Winawer",1 e4 e6 2 d4 d5 3 Nc3 Bb4 4 e5
219
+ C17,"French, Winawer, Advance",1 e4 e6 2 d4 d5 3 Nc3 Bb4 4 e5 c5
220
+ C18,"French, Winawer",1 e4 e6 2 d4 d5 3 Nc3 Bb4 4 e5 c5 5 a3 Bxc3+ 6 bxc3
221
+ C19,"French, Winawer, Advance",1 e4 e6 2 d4 d5 3 Nc3 Bb4 4 e5 c5 5 a3 Bxc3+ 6 bxc3 Ne7
222
+ C20,King's Pawn Game,1 e4 e5
223
+ C21,Center Game,1 e4 e5 2 d4 exd4
224
+ C22,Center Game,1 e4 e5 2 d4 exd4 3 Qxd4 Nc6
225
+ C23,Bishop's Opening,1 e4 e5 2 Bc4
226
+ C24,Bishop's Opening,1 e4 e5 2 Bc4 Nf6
227
+ C25,Vienna,1 e4 e5 2 Nc3
228
+ C26,Vienna,1 e4 e5 2 Nc3 Nf6
229
+ C27,Vienna Game,1 e4 e5 2 Nc3 Nf6 3 Bc4 Nxe4
230
+ C28,Vienna Game,1 e4 e5 2 Nc3 Nf6 3 Bc4 Nc6
231
+ C29,Vienna Gambit,1 e4 e5 2 Nc3 Nf6 3 f4
232
+ C30,King's Gambit Declined,1 e4 e5 2 f4
233
+ C31,"King's Gambit Declined, Falkbeer Counter Gambit",1 e4 e5 2 f4 d5
234
+ C32,"King's Gambit Declined, Falkbeer Counter Gambit",1 e4 e5 2 f4 d5 3 exd5 e4 4 d3 Nf6
235
+ C33,King's Gambit Accepted,1 e4 e5 2 f4 exf4
236
+ C34,King's Gambit Accepted,1 e4 e5 2 f4 exf4 3 Nf3
237
+ C35,"King's Gambit Accepted, Cunningham",1 e4 e5 2 f4 exf4 3 Nf3 Be7
238
+ C36,"King's Gambit Accepted, Abbazia Defense",1 e4 e5 2 f4 exf4 3 Nf3 d5
239
+ C37,King's Gambit Accepted,1 e4 e5 2 f4 exf4 3 Nf3 g5 4 Nc3
240
+ C38,King's Gambit Accepted,1 e4 e5 2 f4 exf4 3 Nf3 g5 4 Bc4 Bg7
241
+ C39,King's Gambit Accepted,1 e4 e5 2 f4 exf4 3 Nf3 g5 4 h4
242
+ C40,King's Knight Opening,1 e4 e5 2 Nf3
243
+ C41,Philidor Defense,1 e4 e5 2 Nf3 d6
244
+ C42,Petrov Defense,1 e4 e5 2 Nf3 Nf6
245
+ C43,"Petrov, Modern Attack",1 e4 e5 2 Nf3 Nf6 3 d4 exd4 4 e5 Ne4 5 Qxd4
246
+ C44,King's Pawn Game,1 e4 e5 2 Nf3 Nc6
247
+ C45,Scotch Game,1 e4 e5 2 Nf3 Nc6 3 d4 exd4 4 Nxd4
248
+ C46,Three Knights,1 e4 e5 2 Nf3 Nc6 3 Nc3
249
+ C47,Four Knights,1 e4 e5 2 Nf3 Nc6 3 Nc3 Nf6
250
+ C48,Four Knights,1 e4 e5 2 Nf3 Nc6 3 Nc3 Nf6 4 Bb5
251
+ C49,Four Knights,1 e4 e5 2 Nf3 Nc6 3 Nc3 Nf6 4 Bb5 Bb4
252
+ C50,Giuoco Piano,1 e4 e5 2 Nf3 Nc6 3 Bc4 Bc5
253
+ C51,Evans Gambit,1 e4 e5 2 Nf3 Nc6 3 Bc4 Bc5 4 b4
254
+ C52,Evans Gambit,1 e4 e5 2 Nf3 Nc6 3 Bc4 Bc5 4 b4 Bxb4 5 c3 Ba5
255
+ C53,Giuoco Piano,1 e4 e5 2 Nf3 Nc6 3 Bc4 Bc5 4 c3
256
+ C54,Giuoco Piano,1 e4 e5 2 Nf3 Nc6 3 Bc4 Bc5 4 c3 Nf6 5 d4 exd4 6 cxd4
257
+ C55,Two Knights Defense,1 e4 e5 2 Nf3 Nc6 3 Bc4 Nf6
258
+ C56,Two Knights,1 e4 e5 2 Nf3 Nc6 3 Bc4 Nf6 4 d4 exd4 5 O-O Nxe4
259
+ C57,Two Knights,1 e4 e5 2 Nf3 Nc6 3 Bc4 Nf6 4 Ng5
260
+ C58,Two Knights,1 e4 e5 2 Nf3 Nc6 3 Bc4 Nf6 4 Ng5 d5 5 exd5 Na5
261
+ C59,Two Knights,1 e4 e5 2 Nf3 Nc6 3 Bc4 Nf6 4 Ng5 d5 5 exd5 Na5 6 Bb5+ c6 7 dxc6 bxc6 8 Be2 h6
262
+ C60,Ruy Lopez,1 e4 e5 2 Nf3 Nc6 3 Bb5
263
+ C61,"Ruy Lopez, Bird's Defense",1 e4 e5 2 Nf3 Nc6 3 Bb5 Nd4
264
+ C62,"Ruy Lopez, Old Steinitz Defense",1 e4 e5 2 Nf3 Nc6 3 Bb5 d6
265
+ C63,"Ruy Lopez, Schliemann Defense",1 e4 e5 2 Nf3 Nc6 3 Bb5 f5
266
+ C64,"Ruy Lopez, Classical",1 e4 e5 2 Nf3 Nc6 3 Bb5 Bc5
267
+ C65,"Ruy Lopez, Berlin Defense",1 e4 e5 2 Nf3 Nc6 3 Bb5 Nf6
268
+ C66,Ruy Lopez,1 e4 e5 2 Nf3 Nc6 3 Bb5 Nf6 4 O-O d6
269
+ C67,Ruy Lopez,1 e4 e5 2 Nf3 Nc6 3 Bb5 Nf6 4 O-O Nxe4
270
+ C68,"Ruy Lopez, Exchange",1 e4 e5 2 Nf3 Nc6 3 Bb5 a6 4 Bxc6
271
+ C69,"Ruy Lopez, Exchange, Gligoric Variation",1 e4 e5 2 Nf3 Nc6 3 Bb5 a6 4 Bxc6 dc 5 O-O f6
272
+ C70,Ruy Lopez,1 e4 e5 2 Nf3 Nc6 3 Bb5 a6 4 Ba4
273
+ C71,Ruy Lopez,1 e4 e5 2 Nf3 Nc6 3 Bb5 a6 4 Ba4 d6
274
+ C72,"Ruy Lopez, Modern Steinitz Defense, 5.O-O",1 e4 e5 2 Nf3 Nc6 3 Bb5 a6 4 Ba4 d6 5 O-O
275
+ C73,"Ruy Lopez, Modern Steinitz Defense",1 e4 e5 2 Nf3 Nc6 3 Bb5 a6 4 Ba4 d6 5 Bxc6+ bxc6 6 d4
276
+ C74,"Ruy Lopez, Modern Steinitz Defense",1 e4 e5 2 Nf3 Nc6 3 Bb5 a6 4 Ba4 d6 5 c3
277
+ C75,"Ruy Lopez, Modern Steinitz Defense",1 e4 e5 2 Nf3 Nc6 3 Bb5 a6 4 Ba4 d6 5 c3 Bd7
278
+ C76,"Ruy Lopez, Modern Steinitz Defense, Fianchetto Variation",1 e4 e5 2 Nf3 Nc6 3 Bb5 a6 4 Ba4 d6 5 c3 Bd7 6 d4 g6
279
+ C77,Ruy Lopez,1 e4 e5 2 Nf3 Nc6 3 Bb5 a6 4 Ba4 Nf6
280
+ C78,Ruy Lopez,1 e4 e5 2 Nf3 Nc6 3 Bb5 a6 4 Ba4 Nf6 5 O-O
281
+ C79,"Ruy Lopez, Steinitz Defense Deferred",1 e4 e5 2 Nf3 Nc6 3 Bb5 a6 4 Ba4 Nf6 5 O-O d6
282
+ C80,"Ruy Lopez, Open",1 e4 e5 2 Nf3 Nc6 3 Bb5 a6 4 Ba4 Nf6 5 O-O Nxe4
283
+ C81,"Ruy Lopez, Open, Howell Attack",1 e4 e5 2 Nf3 Nc6 3 Bb5 a6 4 Ba4 Nf6 5 O-O Nxe4 6 d4 b5 7 Bb3 d5 8 dxe5 Be6 9 Qe2
284
+ C82,"Ruy Lopez, Open",1 e4 e5 2 Nf3 Nc6 3 Bb5 a6 4 Ba4 Nf6 5 O-O Nxe4 6 d4 b5 7 Bb3 d5 8 dxe5 Be6 9 c3
285
+ C83,"Ruy Lopez, Open",1 e4 e5 2 Nf3 Nc6 3 Bb5 a6 4 Ba4 Nf6 5 O-O Nxe4 6 d4 b5 7 Bb3 d5 8 dxe5 Be6
286
+ C84,"Ruy Lopez, Closed",1 e4 e5 2 Nf3 Nc6 3 Bb5 a6 4 Ba4 Nf6 5 O-O Be7
287
+ C85,"Ruy Lopez, Exchange Variation Doubly Deferred (DERLD)",1 e4 e5 2 Nf3 Nc6 3 Bb5 a6 4 Ba4 Nf6 5 O-O Be7 6 Bxc6 dxc6
288
+ C86,"Ruy Lopez, Worrall Attack",1 e4 e5 2 Nf3 Nc6 3 Bb5 a6 4 Ba4 Nf6 5 O-O Be7 6 Qe2
289
+ C87,Ruy Lopez,1 e4 e5 2 Nf3 Nc6 3 Bb5 a6 4 Ba4 Nf6 5 O-O Be7 6 Re1 d6
290
+ C88,Ruy Lopez,1 e4 e5 2 Nf3 Nc6 3 Bb5 a6 4 Ba4 Nf6 5 O-O Be7 6 Re1 b5 7 Bb3
291
+ C89,"Ruy Lopez, Marshall",1 e4 e5 2 Nf3 Nc6 3 Bb5 a6 4 Ba4 Nf6 5 O-O Be7 6 Re1 b5 7 Bb3 O-O 8 c3 d5
292
+ C90,"Ruy Lopez, Closed",1 e4 e5 2 Nf3 Nc6 3 Bb5 a6 4 Ba4 Nf6 5 O-O Be7 6 Re1 b5 7 Bb3 O-O 8 c3 d6
293
+ C91,"Ruy Lopez, Closed",1 e4 e5 2 Nf3 Nc6 3 Bb5 a6 4 Ba4 Nf6 5 O-O Be7 6 Re1 b5 7 Bb3 O-O 8 c3 d6 9 d4
294
+ C92,"Ruy Lopez, Closed",1 e4 e5 2 Nf3 Nc6 3 Bb5 a6 4 Ba4 Nf6 5 O-O Be7 6 Re1 b5 7 Bb3 O-O 8 c3 d6 9 h3
295
+ C93,"Ruy Lopez, Closed, Smyslov Defense",1 e4 e5 2 Nf3 Nc6 3 Bb5 a6 4 Ba4 Nf6 5 O-O Be7 6 Re1 b5 7 Bb3 O-O 8 c3 d6 9 h3 h6
296
+ C94,"Ruy Lopez, Closed, Breyer Defense",1 e4 e5 2 Nf3 Nc6 3 Bb5 a6 4 Ba4 Nf6 5 O-O Be7 6 Re1 b5 7 Bb3 O-O 8 c3 d6 9 h3 Nb8
297
+ C95,"Ruy Lopez, Closed, Breyer",1 e4 e5 2 Nf3 Nc6 3 Bb5 a6 4 Ba4 Nf6 5 O-O Be7 6 Re1 b5 7 Bb3 O-O 8 c3 d6 9 h3 Nb8 10 d4
298
+ C96,"Ruy Lopez, Closed",1 e4 e5 2 Nf3 Nc6 3 Bb5 a6 4 Ba4 Nf6 5 O-O Be7 6 Re1 b5 7 Bb3 O-O 8 c3 d6 9 h3 Na5 10 Bc2
299
+ C97,"Ruy Lopez, Closed, Chigorin",1 e4 e5 2 Nf3 Nc6 3 Bb5 a6 4 Ba4 Nf6 5 O-O Be7 6 Re1 b5 7 Bb3 O-O 8 c3 d6 9 h3 Na5 10 Bc2 c5 11 d4 Qc7
300
+ C98,"Ruy Lopez, Closed, Chigorin",1 e4 e5 2 Nf3 Nc6 3 Bb5 a6 4 Ba4 Nf6 5 O-O Be7 6 Re1 b5 7 Bb3 O-O 8 c3 d6 9 h3 Na5 10 Bc2 c5 11 d4 Qc7 12 Nbd2 Nc6
301
+ C99,"Ruy Lopez, Closed, Chigorin, 12...cd",1 e4 e5 2 Nf3 Nc6 3 Bb5 a6 4 Ba4 Nf6 5 O-O Be7 6 Re1 b5 7 Bb3 O-O 8 c3 d6 9 h3 Na5 10 Bc2 c5 11 d4 Qc7 12 Nbd2 cxd4 13 cxd4
302
+ D00,Queen's Pawn Game,1 d4 d5
303
+ D01,Richter-Veresov Attack,1 d4 d5 2 Nc3 Nf6 3 Bg5
304
+ D02,Queen's Pawn Game,1 d4 d5 2 Nf3
305
+ D03,Torre Attack (Tartakower Variation),1 d4 d5 2 Nf3 Nf6 3 Bg5
306
+ D04,Queen's Pawn Game,1 d4 d5 2 Nf3 Nf6 3 e3
307
+ D05,Queen's Pawn Game,1 d4 d5 2 Nf3 Nf6 3 e3 e6
308
+ D06,Queen's Gambit Declined,1 d4 d5 2 c4
309
+ D07,"Queen's Gambit Declined, Chigorin Defense",1 d4 d5 2 c4 Nc6
310
+ D08,"Queen's Gambit Declined, Albin Counter Gambit",1 d4 d5 2 c4 e5
311
+ D09,"Queen's Gambit Declined, Albin Counter Gambit, 5.g3",1 d4 d5 2 c4 e5 3 dxe5 d4 4 Nf3 Nc6 5 g3
312
+ D10,Queen's Gambit Declined Slav,1 d4 d5 2 c4 c6
313
+ D11,Queen's Gambit Declined Slav,1 d4 d5 2 c4 c6 3 Nf3
314
+ D12,Queen's Gambit Declined Slav,1 d4 d5 2 c4 c6 3 Nf3 Nf6 4 e3 Bf5
315
+ D13,"Queen's Gambit Declined Slav, Exchange Variation",1 d4 d5 2 c4 c6 3 Nf3 Nf6 4 cxd5 cxd5
316
+ D14,"Queen's Gambit Declined Slav, Exchange Variation",1 d4 d5 2 c4 c6 3 Nf3 Nf6 4 cxd5 cxd5 5 Nc3 Nc6 6 Bf4 Bf5
317
+ D15,Queen's Gambit Declined Slav,1 d4 d5 2 c4 c6 3 Nf3 Nf6 4 Nc3
318
+ D16,Queen's Gambit Declined Slav,1 d4 d5 2 c4 c6 3 Nf3 Nf6 4 Nc3 dxc4 5 a4
319
+ D17,Queen's Gambit Declined Slav,1 d4 d5 2 c4 c6 3 Nf3 Nf6 4 Nc3 dxc4 5 a4 Bf5
320
+ D18,"Queen's Gambit Declined Slav, Dutch",1 d4 d5 2 c4 c6 3 Nf3 Nf6 4 Nc3 dxc4 5 a4 Bf5 6 e3
321
+ D19,"Queen's Gambit Declined Slav, Dutch",1 d4 d5 2 c4 c6 3 Nf3 Nf6 4 Nc3 dxc4 5 a4 Bf5 6 e3 e6 7 Bxc4 Bb4 8 O-O O-O 9 Qe2
322
+ D20,Queen's Gambit Accepted,1 d4 d5 2 c4 dxc4
323
+ D21,Queen's Gambit Accepted,1 d4 d5 2 c4 dxc4 3 Nf3
324
+ D22,Queen's Gambit Accepted,1 d4 d5 2 c4 dxc4 3 Nf3 a6 4 e3 Bg4 5 Bxc4 e6 6 d5
325
+ D23,Queen's Gambit Accepted,1 d4 d5 2 c4 dxc4 3 Nf3 Nf6
326
+ D24,Queen's Gambit Accepted,1 d4 d5 2 c4 dxc4 3 Nf3 Nf6 4 Nc3
327
+ D25,Queen's Gambit Accepted,1 d4 d5 2 c4 dxc4 3 Nf3 Nf6 4 e3
328
+ D26,Queen's Gambit Accepted,1 d4 d5 2 c4 dxc4 3 Nf3 Nf6 4 e3 e6
329
+ D27,"Queen's Gambit Accepted, Classical",1 d4 d5 2 c4 dxc4 3 Nf3 Nf6 4 e3 e6 5 Bxc4 c5 6 O-O a6
330
+ D28,"Queen's Gambit Accepted, Classical",1 d4 d5 2 c4 dxc4 3 Nf3 Nf6 4 e3 e6 5 Bxc4 c5 6 O-O a6 7 Qe2
331
+ D29,"Queen's Gambit Accepted, Classical",1 d4 d5 2 c4 dxc4 3 Nf3 Nf6 4 e3 e6 5 Bxc4 c5 6 O-O a6 7 Qe2 b5 8 Bb3 Bb7
332
+ D30,Queen's Gambit Declined,1 d4 d5 2 c4 e6
333
+ D31,Queen's Gambit Declined,1 d4 d5 2 c4 e6 3 Nc3
334
+ D32,"Queen's Gambit Declined, Tarrasch",1 d4 d5 2 c4 e6 3 Nc3 c5
335
+ D33,"Queen's Gambit Declined, Tarrasch",1 d4 d5 2 c4 e6 3 Nc3 c5 4 cxd5 exd5 5 Nf3 Nc6 6 g3
336
+ D34,"Queen's Gambit Declined, Tarrasch",1 d4 d5 2 c4 e6 3 Nc3 c5 4 cxd5 exd5 5 Nf3 Nc6 6 g3 Nf6 7 Bg2 Be7
337
+ D35,Queen's Gambit Declined,1 d4 d5 2 c4 e6 3 Nc3 Nf6
338
+ D36,"Queen's Gambit Declined, Exchange, Positional line, 6.Qc2",1 d4 d5 2 c4 e6 3 Nc3 Nf6 4 cxd5 exd5 5 Bg5 c6 6 Qc2
339
+ D37,Queen's Gambit Declined,1 d4 d5 2 c4 e6 3 Nc3 Nf6 4 Nf3
340
+ D38,"Queen's Gambit Declined, Ragozin Variation",1 d4 d5 2 c4 e6 3 Nc3 Nf6 4 Nf3 Bb4
341
+ D39,"Queen's Gambit Declined, Ragozin, Vienna Variation",1 d4 d5 2 c4 e6 3 Nc3 Nf6 4 Nf3 Bb4 5 Bg5 dxc4
342
+ D40,"Queen's Gambit Declined, Semi-Tarrasch",1 d4 d5 2 c4 e6 3 Nc3 Nf6 4 Nf3 c5
343
+ D41,"Queen's Gambit Declined, Semi-Tarrasch",1 d4 d5 2 c4 e6 3 Nc3 Nf6 4 Nf3 c5 5 cxd5
344
+ D42,"Queen's Gambit Declined, Semi-Tarrasch, 7.Bd3",1 d4 d5 2 c4 e6 3 Nc3 Nf6 4 Nf3 c5 5 cxd5 Nxd5 6 e3 Nc6 7 Bd3
345
+ D43,Queen's Gambit Declined Semi-Slav,1 d4 d5 2 c4 e6 3 Nc3 Nf6 4 Nf3 c6
346
+ D44,Queen's Gambit Declined Semi-Slav,1 d4 d5 2 c4 e6 3 Nc3 Nf6 4 Nf3 c6 5 Bg5 dxc4
347
+ D45,Queen's Gambit Declined Semi-Slav,1 d4 d5 2 c4 e6 3 Nc3 Nf6 4 Nf3 c6 5 e3
348
+ D46,Queen's Gambit Declined Semi-Slav,1 d4 d5 2 c4 e6 3 Nc3 Nf6 4 Nf3 c6 5 e3 Nbd7 6 Bd3
349
+ D47,Queen's Gambit Declined Semi-Slav,1 d4 d5 2 c4 e6 3 Nc3 Nf6 4 Nf3 c6 5 e3 Nbd7 6 Bd3 dxc4 7 Bxc4
350
+ D48,"Queen's Gambit Declined Semi-Slav, Meran",1 d4 d5 2 c4 e6 3 Nc3 Nf6 4 Nf3 c6 5 e3 Nbd7 6 Bd3 dxc4 7 Bxc4 b5 8 Bd3 a6
351
+ D49,"Queen's Gambit Declined Semi-Slav, Meran",1 d4 d5 2 c4 e6 3 Nc3 Nf6 4 Nf3 c6 5 e3 Nbd7 6 Bd3 dxc4 7 Bxc4 b5 8 Bd3 a6 9 e4 c5 10 e5 cxd4 11 Nxb5
352
+ D50,Queen's Gambit Declined,1 d4 d5 2 c4 e6 3 Nc3 Nf6 4 Bg5
353
+ D51,Queen's Gambit Declined,1 d4 d5 2 c4 e6 3 Nc3 Nf6 4 Bg5 Nbd7
354
+ D52,Queen's Gambit Declined,1 d4 d5 2 c4 e6 3 Nc3 Nf6 4 Bg5 Nbd7 5 e3 c6 6 Nf3
355
+ D53,Queen's Gambit Declined,1 d4 d5 2 c4 e6 3 Nc3 Nf6 4 Bg5 Be7
356
+ D54,"Queen's Gambit Declined, Anti-Neo-Orthodox Variation",1 d4 d5 2 c4 e6 3 Nc3 Nf6 4 Bg5 Be7 5 e3 O-O 6 Rc1
357
+ D55,Queen's Gambit Declined,1 d4 d5 2 c4 e6 3 Nc3 Nf6 4 Bg5 Be7 5 e3 O-O 6 Nf3
358
+ D56,Queen's Gambit Declined,1 d4 d5 2 c4 e6 3 Nc3 Nf6 4 Bg5 Be7 5 e3 O-O 6 Nf3 h6 7 Bh4
359
+ D57,"Queen's Gambit Declined, Lasker Defense",1 d4 d5 2 c4 e6 3 Nc3 Nf6 4 Bg5 Be7 5 e3 O-O 6 Nf3 h6 7 Bh4 Ne4 8 Bxe7 Qxe7
360
+ D58,"Queen's Gambit Declined, Tartakower (Makagonov-Bondarevsky) System",1 d4 d5 2 c4 e6 3 Nc3 Nf6 4 Bg5 Be7 5 e3 O-O 6 Nf3 h6 7 Bh4 b6
361
+ D59,"Queen's Gambit Declined, Tartakower",1 d4 d5 2 c4 e6 3 Nc3 Nf6 4 Bg5 Be7 5 e3 O-O 6 Nf3 h6 7 Bh4 b6 8 cxd5 Nxd5
362
+ D60,"Queen's Gambit Declined, Orthodox Defense",1 d4 d5 2 c4 e6 3 Nc3 Nf6 4 Bg5 Be7 5 e3 O-O 6 Nf3 Nbd7
363
+ D61,"Queen's Gambit Declined, Orthodox, Rubinstein Attack",1 d4 d5 2 c4 e6 3 Nc3 Nf6 4 Bg5 Be7 5 e3 O-O 6 Nf3 Nbd7 7 Qc2
364
+ D62,"Queen's Gambit Declined, Orthodox, Rubinstein Attack",1 d4 d5 2 c4 e6 3 Nc3 Nf6 4 Bg5 Be7 5 e3 O-O 6 Nf3 Nbd7 7 Qc2 c5 8 cxd5
365
+ D63,"Queen's Gambit Declined, Orthodox Defense",1 d4 d5 2 c4 e6 3 Nc3 Nf6 4 Bg5 Be7 5 e3 O-O 6 Nf3 Nbd7 7 Rc1
366
+ D64,"Queen's Gambit Declined, Orthodox, Rubinstein Attack",1 d4 d5 2 c4 e6 3 Nc3 Nf6 4 Bg5 Be7 5 e3 O-O 6 Nf3 Nbd7 7 Rc1 c6 8 Qc2
367
+ D65,"Queen's Gambit Declined, Orthodox, Rubinstein Attack, Main line",1 d4 d5 2 c4 e6 3 Nc3 Nf6 4 Bg5 Be7 5 e3 O-O 6 Nf3 Nbd7 7 Rc1 c6 8 Qc2 a6 9 cxd5
368
+ D66,"Queen's Gambit Declined, Orthodox Defense, Bd3 line",1 d4 d5 2 c4 e6 3 Nc3 Nf6 4 Bg5 Be7 5 e3 O-O 6 Nf3 Nbd7 7 Rc1 c6 8 Bd3
369
+ D67,"Queen's Gambit Declined, Orthodox Defense, Bd3 line",1 d4 d5 2 c4 e6 3 Nc3 Nf6 4 Bg5 Be7 5 e3 O-O 6 Nf3 Nbd7 7 Rc1 c6 8 Bd3 dxc4 9 Bxc4 Nd5
370
+ D68,"Queen's Gambit Declined, Orthodox Defense, Classical",1 d4 d5 2 c4 e6 3 Nc3 Nf6 4 Bg5 Be7 5 e3 O-O 6 Nf3 Nbd7 7 Rc1 c6 8 Bd3 dxc4
371
+ D69,"Queen's Gambit Declined, Orthodox Defense, Classical, 13.de",1 d4 d5 2 c4 e6 3 Nc3 Nf6 4 Bg5 Be7 5 e3 O-O 6 Nf3 Nbd7 7 Rc1 c6 8 Bd3 dxc4
372
+ D70,Neo-Grunfeld Defense,1 d4 Nf6 2 c4 g6 3 f3 d5
373
+ D71,Neo-Grunfeld,1 d4 Nf6 2 c4 g6 3 g3 d5
374
+ D72,"Neo-Grunfeld, 5.cd, Main line",1 d4 Nf6 2 c4 g6 3 g3 d5 4 Bg2 Bg7 5 cxd5 Nxd5 6 e4 Nb6 7 Ne2
375
+ D73,"Neo-Grunfeld, 5.Nf3",1 d4 Nf6 2 c4 g6 3 g3 d5 4 Bg2 Bg7 5 Nf3
376
+ D74,"Neo-Grunfeld, 6.cd Nxd5, 7.O-O",1 d4 Nf6 2 c4 g6 3 g3 d5 4 Bg2 Bg7 5 Nf3 O-O 6 cxd5 Nxd5 7 O-O
377
+ D75,"Neo-Grunfeld, 6.cd Nxd5, 7.O-O c5, 8.dxc5",1 d4 Nf6 2 c4 g6 3 g3 d5 4 Bg2 Bg7 5 Nf3 O-O 6 cxd5 Nxd5 7 O-O c5 8 dxc5
378
+ D76,"Neo-Grunfeld, 6.cd Nxd5, 7.O-O Nb6",1 d4 Nf6 2 c4 g6 3 g3 d5 4 Bg2 Bg7 5 Nf3 O-O 6 cxd5 Nxd5 7 O-O Nb6
379
+ D77,"Neo-Grunfeld, 6.O-O",1 d4 Nf6 2 c4 g6 3 g3 d5 4 Bg2 Bg7 5 Nf3 O-O 6 O-O
380
+ D78,"Neo-Grunfeld, 6.O-O c6",1 d4 Nf6 2 c4 g6 3 g3 d5 4 Bg2 Bg7 5 Nf3 O-O 6 O-O c6
381
+ D79,"Neo-Grunfeld, 6.O-O, Main line",1 d4 Nf6 2 c4 g6 3 g3 d5 4 Bg2 Bg7 5 Nf3 O-O 6 O-O c6 7 cxd5 cxd5
382
+ D80,Grunfeld,1 d4 Nf6 2 c4 g6 3 Nc3 d5
383
+ D81,"Grunfeld, Russian Variation",1 d4 Nf6 2 c4 g6 3 Nc3 d5 4 Qb3
384
+ D82,"Grunfeld, 4.Bf4",1 d4 Nf6 2 c4 g6 3 Nc3 d5 4 Bf4
385
+ D83,"Grunfeld, Grunfeld Gambit",1 d4 Nf6 2 c4 g6 3 Nc3 d5 4 Bf4 Bg7 5 e3 O-O
386
+ D84,"Grunfeld, Grunfeld Gambit Accepted",1 d4 Nf6 2 c4 g6 3 Nc3 d5 4 Bf4 Bg7 5 e3 O-O 6 cxd5 Nxd5 7 Nxd5 Qxd5 8 Bxc7
387
+ D85,Grunfeld,1 d4 Nf6 2 c4 g6 3 Nc3 d5 4 cxd5 Nxd5
388
+ D86,"Grunfeld, Exchange",1 d4 Nf6 2 c4 g6 3 Nc3 d5 4 cxd5 Nxd5 5 e4 Nxc3 6 bxc3 Bg7 7 Bc4
389
+ D87,"Grunfeld, Exchange",1 d4 Nf6 2 c4 g6 3 Nc3 d5 4 cxd5 Nxd5 5 e4 Nxc3 6 bxc3 Bg7 7 Bc4 O-O 8 Ne2 c5
390
+ D88,"Grunfeld, Spassky Variation, Main line, 10...cd, 11.cd",1 d4 Nf6 2 c4 g6 3 Nc3 d5 4 cxd5 Nxd5 5 e4 Nxc3 6 bxc3 Bg7 7 Bc4 O-O 8 Ne2
391
+ D89,Grunfeld,1 d4 Nf6 2 c4 g6 3 Nc3 d5 4 cxd5 Nxd5 5 e4 Nxc3 6 bxc3 Bg7 7 Bc4 O-O 8 Ne2
392
+ D90,Grunfeld,1 d4 Nf6 2 c4 g6 3 Nc3 d5 4 Nf3
393
+ D91,"Grunfeld, 5.Bg5",1 d4 Nf6 2 c4 g6 3 Nc3 d5 4 Nf3 Bg7 5 Bg5
394
+ D92,"Grunfeld, 5.Bf4",1 d4 Nf6 2 c4 g6 3 Nc3 d5 4 Nf3 Bg7 5 Bf4
395
+ D93,"Grunfeld, with Bf4 & e3",1 d4 Nf6 2 c4 g6 3 Nc3 d5 4 Nf3 Bg7 5 Bf4 O-O 6 e3
396
+ D94,Grunfeld,1 d4 Nf6 2 c4 g6 3 Nc3 d5 4 Nf3 Bg7 5 e3
397
+ D95,Grunfeld,1 d4 Nf6 2 c4 g6 3 Nc3 d5 4 Nf3 Bg7 5 e3 O-O 6 Qb3
398
+ D96,"Grunfeld, Russian Variation",1 d4 Nf6 2 c4 g6 3 Nc3 d5 4 Nf3 Bg7 5 Qb3
399
+ D97,"Grunfeld, Russian",1 d4 Nf6 2 c4 g6 3 Nc3 d5 4 Nf3 Bg7 5 Qb3 dxc4 6 Qxc4 O-O 7 e4
400
+ D98,"Grunfeld, Russian",1 d4 Nf6 2 c4 g6 3 Nc3 d5 4 Nf3 Bg7 5 Qb3 dxc4 6 Qxc4 O-O 7 e4 Bg4
401
+ D99,"Grunfeld Defense, Smyslov",1 d4 Nf6 2 c4 g6 3 Nc3 d5 4 Nf3 Bg7 5 Qb3 dxc4 6 Qxc4 O-O 7 e4 Bg4 8 Be3
402
+ E00,Queen's Pawn Game,1 d4 Nf6 2 c4 e6
403
+ E01,"Catalan, Closed",1 d4 Nf6 2 c4 e6 3 g3 d5 4 Bg2
404
+ E02,"Catalan, Open, 5.Qa4",1 d4 Nf6 2 c4 e6 3 g3 d5 4 Bg2 dxc4 5 Qa4+
405
+ E03,"Catalan, Open",1 d4 Nf6 2 c4 e6 3 g3 d5 4 Bg2 dxc4 5 Qa4+ Nbd7 6 Qxc4
406
+ E04,"Catalan, Open, 5.Nf3",1 d4 Nf6 2 c4 e6 3 g3 d5 4 Bg2 dxc4 5 Nf3
407
+ E05,"Catalan, Open, Classical line",1 d4 Nf6 2 c4 e6 3 g3 d5 4 Bg2 dxc4 5 Nf3 Be7
408
+ E06,"Catalan, Closed, 5.Nf3",1 d4 Nf6 2 c4 e6 3 g3 d5 4 Bg2 Be7 5 Nf3
409
+ E07,"Catalan, Closed",1 d4 Nf6 2 c4 e6 3 g3 d5 4 Bg2 Be7 5 Nf3 O-O 6 O-O Nbd7
410
+ E08,"Catalan, Closed",1 d4 Nf6 2 c4 e6 3 g3 d5 4 Bg2 Be7 5 Nf3 O-O 6 O-O Nbd7 7 Qc2
411
+ E09,"Catalan, Closed",1 d4 Nf6 2 c4 e6 3 g3 d5 4 Bg2 Be7 5 Nf3 O-O 6 O-O Nbd7 7 Qc2 c6 8 Nbd2
412
+ E10,Queen's Pawn Game,1 d4 Nf6 2 c4 e6 3 Nf3
413
+ E11,Bogo-Indian Defense,1 d4 Nf6 2 c4 e6 3 Nf3 Bb4+
414
+ E12,Queen's Indian,1 d4 Nf6 2 c4 e6 3 Nf3 b6
415
+ E13,"Queen's Indian, 4.Nc3, Main line",1 d4 Nf6 2 c4 e6 3 Nf3 b6 4 Nc3 Bb7 5 Bg5 h6 6 Bh4 Bb4
416
+ E14,Queen's Indian,1 d4 Nf6 2 c4 e6 3 Nf3 b6 4 e3
417
+ E15,Queen's Indian,1 d4 Nf6 2 c4 e6 3 Nf3 b6 4 g3
418
+ E16,Queen's Indian,1 d4 Nf6 2 c4 e6 3 Nf3 b6 4 g3 Bb7 5 Bg2 Bb4+
419
+ E17,Queen's Indian,1 d4 Nf6 2 c4 e6 3 Nf3 b6 4 g3 Bb7 5 Bg2 Be7
420
+ E18,"Queen's Indian, Old Main line, 7.Nc3",1 d4 Nf6 2 c4 e6 3 Nf3 b6 4 g3 Bb7 5 Bg2 Be7 6 O-O O-O 7 Nc3
421
+ E19,"Queen's Indian, Old Main line, 9.Qxc3",1 d4 Nf6 2 c4 e6 3 Nf3 b6 4 g3 Bb7 5 Bg2 Be7 6 O-O O-O 7 Nc3 Ne4 8 Qc2 Nxc3
422
+ E20,Nimzo-Indian,1 d4 Nf6 2 c4 e6 3 Nc3 Bb4
423
+ E21,"Nimzo-Indian, Three Knights",1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 Nf3
424
+ E22,"Nimzo-Indian, Spielmann Variation",1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 Qb3
425
+ E23,"Nimzo-Indian, Spielmann",1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 Qb3 c5 5 dxc5 Nc6
426
+ E24,"Nimzo-Indian, Samisch",1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 a3 Bxc3+ 5 bxc3
427
+ E25,"Nimzo-Indian, Samisch",1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 a3 Bxc3+ 5 bxc3 c5 6 f3 d5 7 cxd5
428
+ E26,"Nimzo-Indian, Samisch",1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 a3 Bxc3+ 5 bxc3 c5 6 e3
429
+ E27,"Nimzo-Indian, Samisch Variation",1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 a3 Bxc3+ 5 bxc3 O-O
430
+ E28,"Nimzo-Indian, Samisch Variation",1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 a3 Bxc3+ 5 bxc3 O-O 6 e3
431
+ E29,"Nimzo-Indian, Samisch",1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 a3 Bxc3+ 5 bxc3 O-O 6 e3 c5 7 Bd3 Nc6
432
+ E30,"Nimzo-Indian, Leningrad",1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 Bg5
433
+ E31,"Nimzo-Indian, Leningrad, Main line",1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 Bg5 h6 5 Bh4 c5 6 d5 d6
434
+ E32,"Nimzo-Indian, Classical",1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 Qc2
435
+ E33,"Nimzo-Indian, Classical",1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 Qc2 Nc6
436
+ E34,"Nimzo-Indian, Classical, Noa Variation",1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 Qc2 d5
437
+ E35,"Nimzo-Indian, Classical, Noa Variation, 5.cd ed",1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 Qc2 d5 5 cxd5 exd5
438
+ E36,"Nimzo-Indian, Classical",1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 Qc2 d5 5 a3
439
+ E37,"Nimzo-Indian, Classical",1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 Qc2 d5 5 a3 Bxc3+ 6 Qxc3 Ne4 7 Qc2
440
+ E38,"Nimzo-Indian, Classical, 4...c5",1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 Qc2 c5
441
+ E39,"Nimzo-Indian, Classical, Pirc Variation",1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 Qc2 c5 5 dxc5 O-O
442
+ E40,"Nimzo-Indian, 4.e3",1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 e3
443
+ E41,Nimzo-Indian,1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 e3 c5
444
+ E42,"Nimzo-Indian, 4.e3 c5, 5.Ne2 (Rubinstein)",1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 e3 c5 5 Ne2
445
+ E43,"Nimzo-Indian, Fischer Variation",1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 e3 b6
446
+ E44,"Nimzo-Indian, Fischer Variation, 5.Ne2",1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 e3 b6 5 Ne2
447
+ E45,"Nimzo-Indian, 4.e3, Bronstein (Byrne) Variation",1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 e3 b6 5 Ne2 Ba6
448
+ E46,Nimzo-Indian,1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 e3 O-O
449
+ E47,"Nimzo-Indian, 4.e3 O-O 5.Bd3",1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 e3 O-O 5 Bd3
450
+ E48,"Nimzo-Indian, 4.e3 O-O 5.Bd3 d5",1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 e3 O-O 5 Bd3 d5
451
+ E49,"Nimzo-Indian, 4.e3, Botvinnik System",1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 e3 O-O 5 Bd3 d5 6 a3 Bxc3+ 7 bxc3
452
+ E50,"Nimzo-Indian, 4.e3 O-O 5.Nf3, without ...d5",1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 e3 O-O 5 Nf3
453
+ E51,"Nimzo-Indian, 4.e3",1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 e3 O-O 5 Nf3 d5
454
+ E52,"Nimzo-Indian, 4.e3, Main line with ...b6",1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 e3 O-O 5 Nf3 d5 6 Bd3 b6
455
+ E53,"Nimzo-Indian, 4.e3",1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 e3 O-O 5 Nf3 d5 6 Bd3 c5
456
+ E54,"Nimzo-Indian, 4.e3, Gligoric System",1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 e3 O-O 5 Nf3 d5 6 Bd3 c5 7 O-O dxc4 8 Bxc4
457
+ E55,"Nimzo-Indian, 4.e3, Gligoric System, Bronstein Variation",1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 e3 O-O 5 Nf3 d5 6 Bd3 c5 7 O-O dxc4 8 Bxc4 Nbd7
458
+ E56,"Nimzo-Indian, 4.e3, Main line with 7...Nc6",1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 e3 O-O 5 Nf3 d5 6 Bd3 c5 7 O-O Nc6
459
+ E57,"Nimzo-Indian, 4.e3, Main line with 8...dc and 9...cd",1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 e3 O-O 5 Nf3 d5 6 Bd3 c5 7 O-O Nc6 8 a3 dxc4 9 Bxc4
460
+ E58,"Nimzo-Indian, 4.e3, Main line with 8...Bxc3",1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 e3 O-O 5 Nf3 d5 6 Bd3 c5 7 O-O Nc6 8 a3 Bxc3 9 bxc3
461
+ E59,"Nimzo-Indian, 4.e3, Main line",1 d4 Nf6 2 c4 e6 3 Nc3 Bb4 4 e3 O-O 5 Nf3 d5 6 Bd3 c5 7 O-O Nc6 8 a3 Bxc3 9 bxc3 dxc4 10 Bxc4
462
+ E60,King's Indian Defense,1 d4 Nf6 2 c4 g6
463
+ E61,King's Indian,1 d4 Nf6 2 c4 g6 3 Nc3
464
+ E62,"King's Indian, Fianchetto",1 d4 Nf6 2 c4 g6 3 Nc3 Bg7 4 Nf3 d6 5 g3
465
+ E63,"King's Indian, Fianchetto, Panno Variation",1 d4 Nf6 2 c4 g6 3 Nc3 Bg7 4 Nf3 d6 5 g3 O-O 6 Bg2 Nc6 7 O-O a6
466
+ E64,"King's Indian, Fianchetto, Yugoslav System",1 d4 Nf6 2 c4 g6 3 Nc3 Bg7 4 Nf3 d6 5 g3 O-O 6 Bg2 c5
467
+ E65,"King's Indian, Fianchetto, Yugoslav, 7.O-O",1 d4 Nf6 2 c4 g6 3 Nc3 Bg7 4 Nf3 d6 5 g3 O-O 6 Bg2 c5 7 O-O
468
+ E66,"King's Indian, Fianchetto, Yugoslav Panno",1 d4 Nf6 2 c4 g6 3 Nc3 Bg7 4 Nf3 d6 5 g3 O-O 6 Bg2 c5 7 O-O Nc6 8 d5
469
+ E67,"King's Indian, Fianchetto",1 d4 Nf6 2 c4 g6 3 Nc3 Bg7 4 Nf3 d6 5 g3 O-O 6 Bg2 Nbd7
470
+ E68,"King's Indian, Fianchetto, Classical Variation, 8.e4",1 d4 Nf6 2 c4 g6 3 Nc3 Bg7 4 Nf3 d6 5 g3 O-O 6 Bg2 Nbd7 7 O-O e5 8 e4
471
+ E69,"King's Indian, Fianchetto, Classical Main line",1 d4 Nf6 2 c4 g6 3 Nc3 Bg7 4 Nf3 d6 5 g3 O-O 6 Bg2 Nbd7 7 O-O e5 8 e4 c6 9 h3
472
+ E70,King's Indian,1 d4 Nf6 2 c4 g6 3 Nc3 Bg7 4 e4
473
+ E71,"King's Indian, Makagonov System (5.h3)",1 d4 Nf6 2 c4 g6 3 Nc3 Bg7 4 e4 d6 5 h3
474
+ E72,King's Indian,1 d4 Nf6 2 c4 g6 3 Nc3 Bg7 4 e4 d6 5 g3
475
+ E73,King's Indian,1 d4 Nf6 2 c4 g6 3 Nc3 Bg7 4 e4 d6 5 Be2
476
+ E74,"King's Indian, Averbakh, 6...c5",1 d4 Nf6 2 c4 g6 3 Nc3 Bg7 4 e4 d6 5 Be2 O-O 6 Bg5 c5
477
+ E75,"King's Indian, Averbakh, Main line",1 d4 Nf6 2 c4 g6 3 Nc3 Bg7 4 e4 d6 5 Be2 O-O 6 Bg5 c5 7 d5 e6
478
+ E76,"King's Indian, Four Pawns Attack",1 d4 Nf6 2 c4 g6 3 Nc3 Bg7 4 e4 d6 5 f4
479
+ E77,King's Indian,1 d4 Nf6 2 c4 g6 3 Nc3 Bg7 4 e4 d6 5 f4 O-O 6 Be2
480
+ E78,"King's Indian, Four Pawns Attack, with Be2 and Nf3",1 d4 Nf6 2 c4 g6 3 Nc3 Bg7 4 e4 d6 5 f4 O-O 6 Be2 c5 7 Nf3
481
+ E79,"King's Indian, Four Pawns Attack, Main line",1 d4 Nf6 2 c4 g6 3 Nc3 Bg7 4 e4 d6 5 f4 O-O 6 Be2 c5 7 Nf3 cxd4 8 Nxd4 Nc6 9 Be3
482
+ E80,"King's Indian, Samisch Variation",1 d4 Nf6 2 c4 g6 3 Nc3 Bg7 4 e4 d6 5 f3
483
+ E81,"King's Indian, Samisch",1 d4 Nf6 2 c4 g6 3 Nc3 Bg7 4 e4 d6 5 f3 O-O
484
+ E82,"King's Indian, Samisch, double Fianchetto Variation",1 d4 Nf6 2 c4 g6 3 Nc3 Bg7 4 e4 d6 5 f3 O-O 6 Be3 b6
485
+ E83,"King's Indian, Samisch",1 d4 Nf6 2 c4 g6 3 Nc3 Bg7 4 e4 d6 5 f3 O-O 6 Be3 Nc6
486
+ E84,"King's Indian, Samisch, Panno Main line",1 d4 Nf6 2 c4 g6 3 Nc3 Bg7 4 e4 d6 5 f3 O-O 6 Be3 Nc6 7 Nge2 a6 8 Qd2 Rb8
487
+ E85,"King's Indian, Samisch, Orthodox Variation",1 d4 Nf6 2 c4 g6 3 Nc3 Bg7 4 e4 d6 5 f3 O-O 6 Be3 e5
488
+ E86,"King's Indian, Samisch, Orthodox, 7.Nge2 c6",1 d4 Nf6 2 c4 g6 3 Nc3 Bg7 4 e4 d6 5 f3 O-O 6 Be3 e5 7 Nge2 c6
489
+ E87,"King's Indian, Samisch, Orthodox",1 d4 Nf6 2 c4 g6 3 Nc3 Bg7 4 e4 d6 5 f3 O-O 6 Be3 e5 7 d5
490
+ E88,"King's Indian, Samisch, Orthodox, 7.d5 c6",1 d4 Nf6 2 c4 g6 3 Nc3 Bg7 4 e4 d6 5 f3 O-O 6 Be3 e5 7 d5 c6
491
+ E89,"King's Indian, Samisch, Orthodox Main line",1 d4 Nf6 2 c4 g6 3 Nc3 Bg7 4 e4 d6 5 f3 O-O 6 Be3 e5 7 d5 c6 8 Nge2 cxd5
492
+ E90,King's Indian,1 d4 Nf6 2 c4 g6 3 Nc3 Bg7 4 e4 d6 5 Nf3
493
+ E91,King's Indian,1 d4 Nf6 2 c4 g6 3 Nc3 Bg7 4 e4 d6 5 Nf3 O-O 6 Be2
494
+ E92,King's Indian,1 d4 Nf6 2 c4 g6 3 Nc3 Bg7 4 e4 d6 5 Nf3 O-O 6 Be2 e5
495
+ E93,"King's Indian, Petrosian System",1 d4 Nf6 2 c4 g6 3 Nc3 Bg7 4 e4 d6 5 Nf3 O-O 6 Be2 e5 7 d5 Nbd7
496
+ E94,"King's Indian, Orthodox",1 d4 Nf6 2 c4 g6 3 Nc3 Bg7 4 e4 d6 5 Nf3 O-O 6 Be2 e5 7 O-O
497
+ E95,"King's Indian, Orthodox, 7...Nbd7, 8.Re1",1 d4 Nf6 2 c4 g6 3 Nc3 Bg7 4 e4 d6 5 Nf3 O-O 6 Be2 e5 7 O-O Nbd7 8 Re1
498
+ E96,"King's Indian, Orthodox, 7...Nbd7, Main line",1 d4 Nf6 2 c4 g6 3 Nc3 Bg7 4 e4 d6 5 Nf3 O-O 6 Be2 e5 7 O-O Nbd7 8 Re1 c6 9 Bf1 a5
499
+ E97,King's Indian,1 d4 Nf6 2 c4 g6 3 Nc3 Bg7 4 e4 d6 5 Nf3 O-O 6 Be2 e5 7 O-O Nc6
500
+ E98,"King's Indian, Orthodox, Taimanov, 9.Ne1",1 d4 Nf6 2 c4 g6 3 Nc3 Bg7 4 e4 d6 5 Nf3 O-O 6 Be2 e5 7 O-O Nc6 8 d5 Ne7 9 Ne1
501
+ E99,"King's Indian, Orthodox, Taimanov",1 d4 Nf6 2 c4 g6 3 Nc3 Bg7 4 e4 d6 5 Nf3 O-O 6 Be2 e5 7 O-O Nc6 8 d5 Ne7 9 Ne1 Nd7 10 f3 f5
app.py CHANGED
@@ -1,17 +1,14 @@
1
  import gradio as gr
2
  import chess
3
  import chess.pgn
4
- import chess.svg
5
  import io
6
  import requests
7
  import google.generativeai as genai
8
- from collections import Counter, defaultdict
9
  import os
10
  import time
11
- import re
12
- import chess.polyglot
13
  import logging
14
- from openings import get_opening_name_from_eco, detect_opening
15
 
16
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
17
  logger = logging.getLogger(__name__)
@@ -20,34 +17,54 @@ GEMINI_API_KEY = os.environ.get('GEMINI_API_KEY')
20
  genai.configure(api_key=GEMINI_API_KEY)
21
  model = genai.GenerativeModel('gemini-2.0-flash-exp')
22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  def get_user_games_from_chess_com(username):
24
  try:
25
- logger.info(f"Starting to fetch games for user: {username}")
26
- username_original = username.strip()
27
- username = username_original.lower()
28
 
29
  user_url = f"https://api.chess.com/pub/player/{username}"
30
  response = requests.get(user_url, timeout=10, headers={'User-Agent': 'Mozilla/5.0'})
31
 
32
  if response.status_code != 200:
33
- logger.error(f"User not found: {username}")
34
- return None, f"❌ Foydalanuvchi topilmadi: {username}. Chess.com'da mavjudligini tekshiring."
35
 
36
- logger.info(f"User found: {username}")
37
  archives_url = f"https://api.chess.com/pub/player/{username}/games/archives"
38
  response = requests.get(archives_url, timeout=10, headers={'User-Agent': 'Mozilla/5.0'})
39
 
40
  if response.status_code != 200:
41
- logger.error("Archives not found")
42
  return None, "❌ O'yinlar arxivi topilmadi."
43
 
44
  archives = response.json()['archives']
45
  if not archives:
46
- logger.error("No archives available")
47
  return None, "❌ O'yinlar topilmadi."
48
 
49
- logger.info(f"Found {len(archives)} archives")
50
-
51
  all_games = []
52
  for archive_url in reversed(archives[-3:]):
53
  time.sleep(0.3)
@@ -55,22 +72,16 @@ def get_user_games_from_chess_com(username):
55
  if response.status_code == 200:
56
  games = response.json()['games']
57
  all_games.extend(games)
58
- logger.info(f"Fetched {len(games)} games from archive")
59
  if len(all_games) >= 50:
60
  break
61
 
62
- logger.info(f"Total games fetched: {len(all_games)}")
63
-
64
  rapid_games = [g for g in all_games if g.get('time_class') in ['rapid', 'blitz']]
65
  if not rapid_games:
66
  rapid_games = all_games[:50]
67
 
68
  pgn_list = [g['pgn'] for g in rapid_games[:50] if 'pgn' in g]
69
 
70
- logger.info(f"Total PGN games prepared: {len(pgn_list)}")
71
-
72
  if not pgn_list:
73
- logger.error("No PGN games found")
74
  return None, "❌ PGN formatdagi o'yinlar topilmadi."
75
 
76
  return pgn_list, None
@@ -80,39 +91,31 @@ def get_user_games_from_chess_com(username):
80
  return None, f"❌ Xatolik: {str(e)}"
81
 
82
  def parse_pgn_content(pgn_content):
83
- logger.info("Starting to parse PGN content")
84
  games = []
85
  if isinstance(pgn_content, list):
86
- for idx, pgn_text in enumerate(pgn_content):
87
  try:
88
  game = chess.pgn.read_game(io.StringIO(pgn_text))
89
  if game:
90
  games.append(game)
91
- except Exception as e:
92
- logger.warning(f"Failed to parse game {idx}: {str(e)}")
93
  pass
94
  else:
95
  pgn_io = io.StringIO(pgn_content)
96
- idx = 0
97
  while True:
98
  try:
99
  game = chess.pgn.read_game(pgn_io)
100
  if game is None:
101
  break
102
  games.append(game)
103
- idx += 1
104
- except Exception as e:
105
- logger.warning(f"Failed to parse game {idx}: {str(e)}")
106
  break
107
 
108
- logger.info(f"Successfully parsed {len(games)} games")
109
  return games
110
 
111
-
112
  def analyze_game_detailed(game, username):
113
  board = game.board()
114
  mistakes = []
115
-
116
  move_number = 0
117
 
118
  white_player = game.headers.get("White", "").strip().lower()
@@ -128,15 +131,12 @@ def analyze_game_detailed(game, username):
128
  result = game.headers.get("Result", "*")
129
  opening = detect_opening(game)
130
 
131
- user_won = None
132
  user_result = None
133
  if user_color is not None and result != "*":
134
  if result == "1-0":
135
- user_won = (user_color == chess.WHITE)
136
- user_result = "win" if user_won else "loss"
137
  elif result == "0-1":
138
- user_won = (user_color == chess.BLACK)
139
- user_result = "win" if user_won else "loss"
140
  elif result == "1/2-1/2":
141
  user_result = "draw"
142
 
@@ -198,10 +198,7 @@ def analyze_game_detailed(game, username):
198
  }
199
 
200
  def categorize_mistakes(all_analyses):
201
- logger.info("Categorizing mistakes from all games")
202
-
203
  if not all_analyses:
204
- logger.warning("No analyses provided for categorization")
205
  return []
206
 
207
  blunders = 0
@@ -232,12 +229,7 @@ def categorize_mistakes(all_analyses):
232
 
233
  total = blunders + regular_mistakes + hanging + opening + middlegame + endgame
234
 
235
- logger.info(f"Total mistakes found: {total}")
236
- logger.info(f"Blunders: {blunders}, Mistakes: {regular_mistakes}, Hanging: {hanging}")
237
- logger.info(f"Opening: {opening}, Middlegame: {middlegame}, Endgame: {endgame}")
238
-
239
  if total == 0:
240
- logger.warning("No mistakes found in any game")
241
  return []
242
 
243
  weaknesses = []
@@ -286,125 +278,26 @@ def categorize_mistakes(all_analyses):
286
 
287
  weaknesses.sort(key=lambda x: x['count'], reverse=True)
288
 
289
- logger.info(f"Total weakness categories: {len(weaknesses)}")
290
  return weaknesses
291
 
292
- import json
293
-
294
  def fetch_lichess_puzzles(themes, count=5):
295
- logger.info(f"Fetching {count} puzzles for themes: {themes}")
296
  puzzles = []
297
 
298
- theme_map = {
299
- "Qo'pol xatolar": ['hangingPiece', 'discoveredAttack', 'fork'],
300
- 'Kichik xatolar': ['advantage', 'crushing', 'attackingF2F7'],
301
- 'Himoyasiz qoldirish': ['hangingPiece', 'pin', 'skewer'],
302
- 'Debyut xatolari': ['opening', 'short', 'middlegame'],
303
- "O'rta o'yin xatolari": ['middlegame', 'attackingF2F7', 'advancedPawn'],
304
- 'Endshpil xatolari': ['endgame', 'queenEndgame', 'rookEndgame']
305
- }
306
-
307
- lichess_themes = []
308
- for theme_name in themes:
309
- if theme_name in theme_map:
310
- lichess_themes.extend(theme_map[theme_name])
311
-
312
- lichess_themes = list(set(lichess_themes))[:3]
313
- logger.info(f"Selected Lichess themes: {lichess_themes}")
314
-
315
  try:
316
- # Fetch puzzles using the daily puzzle API and database
317
- for theme in lichess_themes:
318
- if len(puzzles) >= count:
319
- break
320
-
321
- # Use Lichess puzzle database API
322
- url = f"https://lichess.org/api/puzzle/batch/mix?nb=2&themes={theme}"
323
- response = requests.get(url, timeout=10, headers={
324
- 'User-Agent': 'Mozilla/5.0',
325
- 'Accept': 'application/x-ndjson'
326
  })
327
-
328
- if response.status_code == 200:
329
- # Parse NDJSON (newline-delimited JSON)
330
- lines = response.text.strip().split('\n')
331
- for line in lines:
332
- if len(puzzles) >= count:
333
- break
334
- if not line.strip():
335
- continue
336
- try:
337
- puzzle_data = json.loads(line) # Use json.loads instead of eval
338
- game_data = puzzle_data.get('game', {})
339
- puzzle_info = puzzle_data.get('puzzle', {})
340
-
341
- puzzle_id = puzzle_info.get('id', '')
342
-
343
- if puzzle_id and not any(p['id'] == puzzle_id for p in puzzles):
344
- puzzles.append({
345
- 'id': puzzle_id,
346
- 'fen': game_data.get('fen', ''),
347
- 'moves': ' '.join(puzzle_info.get('solution', [])),
348
- 'solution': puzzle_info.get('solution', []),
349
- 'rating': puzzle_info.get('rating', 1500),
350
- 'themes': puzzle_info.get('themes', []),
351
- 'url': f"https://lichess.org/training/{puzzle_id}"
352
- })
353
- logger.info(f"Added puzzle {puzzle_id} with rating {puzzle_info.get('rating')}")
354
- except json.JSONDecodeError as e:
355
- logger.warning(f"Failed to parse puzzle line: {str(e)}")
356
- except Exception as e:
357
- logger.warning(f"Error processing puzzle: {str(e)}")
358
-
359
- time.sleep(0.3)
360
  except Exception as e:
361
- logger.error(f"Error fetching puzzles: {str(e)}")
362
-
363
- # Fill remaining with daily puzzle if needed
364
- if len(puzzles) < count:
365
- try:
366
- url = "https://lichess.org/api/puzzle/daily"
367
- response = requests.get(url, timeout=10, headers={'User-Agent': 'Mozilla/5.0'})
368
-
369
- if response.status_code == 200:
370
- daily_data = response.json()
371
- game_data = daily_data.get('game', {})
372
- puzzle_info = daily_data.get('puzzle', {})
373
- puzzle_id = puzzle_info.get('id', '')
374
-
375
- if puzzle_id and not any(p['id'] == puzzle_id for p in puzzles):
376
- puzzles.append({
377
- 'id': puzzle_id,
378
- 'fen': game_data.get('fen', ''),
379
- 'moves': ' '.join(puzzle_info.get('solution', [])),
380
- 'solution': puzzle_info.get('solution', []),
381
- 'rating': puzzle_info.get('rating', 1500),
382
- 'themes': puzzle_info.get('themes', []),
383
- 'url': f"https://lichess.org/training/{puzzle_id}"
384
- })
385
- logger.info(f"Added daily puzzle {puzzle_id}")
386
- except Exception as e:
387
- logger.error(f"Error fetching daily puzzle: {str(e)}")
388
-
389
- # Fill with fallback training links if still not enough
390
- while len(puzzles) < count:
391
- puzzles.append({
392
- 'id': f'training_{len(puzzles)+1}',
393
- 'fen': '',
394
- 'moves': '',
395
- 'solution': [],
396
- 'rating': 1500,
397
- 'themes': ['Mixed'],
398
- 'url': "https://lichess.org/training"
399
- })
400
- logger.info(f"Added fallback puzzle link {len(puzzles)}")
401
 
402
- logger.info(f"Total puzzles prepared: {len(puzzles)}")
403
- return puzzles[:count]
404
 
405
  def get_comprehensive_analysis(weaknesses, opening_stats, color_stats, total_games):
406
- logger.info("Generating AI comprehensive analysis")
407
-
408
  weakness_text = "\n".join([f"- {w['category']}: {w['count']} marta ({w['percentage']:.1f}%)" for w in weaknesses])
409
 
410
  opening_text = "\n".join([f"- {opening}: {stats['total']} o'yin (G'alabalar: {stats['wins']}, Yutqazishlar: {stats['losses']}, Duranglar: {stats['draws']})"
@@ -450,33 +343,27 @@ MUHIM: Javobni FAQAT O'ZBEK TILIDA yozing! Aniq va amaliy maslahatlar bering."""
450
 
451
  try:
452
  response = model.generate_content(prompt)
453
- logger.info("AI analysis generated successfully")
454
  return response.text
455
  except Exception as e:
456
  logger.error(f"AI analysis failed: {str(e)}")
457
  return f"AI tahlil hozircha mavjud emas: {str(e)}"
458
 
459
  def analyze_games(username_chesscom, pgn_file, username_pgn):
460
- logger.info("=== Starting game analysis ===")
461
  actual_username = None
462
  pgn_content = None
463
 
464
  if username_chesscom:
465
  pgn_content, error = get_user_games_from_chess_com(username_chesscom)
466
  if error:
467
- logger.error(f"Failed to fetch games: {error}")
468
  return error, "", "", "", None, None, None, None, None
469
  actual_username = username_chesscom
470
 
471
- # PGN file upload
472
  elif pgn_file:
473
- logger.info("Processing uploaded PGN file")
474
  pgn_content = pgn_file.decode('utf-8') if isinstance(pgn_file, bytes) else pgn_file
475
 
476
  if username_pgn and username_pgn.strip():
477
  actual_username = username_pgn.strip()
478
  else:
479
- # Try to extract username from first game headers
480
  try:
481
  first_game = chess.pgn.read_game(io.StringIO(pgn_content))
482
  if first_game:
@@ -487,21 +374,15 @@ def analyze_games(username_chesscom, pgn_file, username_pgn):
487
  actual_username = "Player"
488
  except:
489
  actual_username = "Player"
490
-
491
- logger.info(f"Extracted username from PGN: {actual_username}")
492
 
493
  else:
494
- logger.error("No username or file provided")
495
  return "❌ Chess.com foydalanuvchi nomini kiriting yoki PGN faylni yuklang", "", "", "", None, None, None, None, None
496
 
497
  games = parse_pgn_content(pgn_content)
498
 
499
  if not games:
500
- logger.error("No games parsed")
501
  return "❌ O'yinlar topilmadi yoki tahlil qilinmadi", "", "", "", None, None, None, None, None
502
 
503
- logger.info(f"Analyzing {len(games)} games")
504
-
505
  all_analyses = []
506
  opening_stats = defaultdict(lambda: {'wins': 0, 'losses': 0, 'draws': 0, 'total': 0})
507
  color_stats = {
@@ -509,8 +390,7 @@ def analyze_games(username_chesscom, pgn_file, username_pgn):
509
  'black': {'wins': 0, 'losses': 0, 'draws': 0}
510
  }
511
 
512
- for idx, game in enumerate(games):
513
- logger.info(f"Analyzing game {idx + 1}/{len(games)}")
514
  analysis = analyze_game_detailed(game, actual_username)
515
  all_analyses.append(analysis)
516
 
@@ -518,8 +398,6 @@ def analyze_games(username_chesscom, pgn_file, username_pgn):
518
  user_result = analysis.get('user_result')
519
  user_color = analysis['user_color']
520
 
521
- logger.info(f"Game {idx + 1}: {opening}, Result: {user_result}, Color: {user_color}")
522
-
523
  if user_color is not None:
524
  opening_stats[opening]['total'] += 1
525
 
@@ -536,15 +414,12 @@ def analyze_games(username_chesscom, pgn_file, username_pgn):
536
  color_key = 'white' if user_color == chess.WHITE else 'black'
537
  color_stats[color_key]['draws'] += 1
538
 
539
- logger.info("Categorizing mistakes")
540
  weaknesses = categorize_mistakes(all_analyses)
541
 
542
  all_mistakes = []
543
  for analysis in all_analyses:
544
  all_mistakes.extend(analysis.get('mistakes', []))
545
 
546
- logger.info(f"Total mistakes collected: {len(all_mistakes)}")
547
-
548
  stats_report = f"## πŸ“Š {len(games)} ta o'yin tahlili\n\n"
549
  stats_report += f"**Jami xatolar:** {len(all_mistakes)} ta\n\n"
550
 
@@ -589,28 +464,19 @@ def analyze_games(username_chesscom, pgn_file, username_pgn):
589
 
590
  full_report = stats_report + opening_report + color_report
591
 
592
- logger.info("Generating AI analysis")
593
  ai_analysis = get_comprehensive_analysis(weaknesses, opening_stats, color_stats, len(games))
594
  ai_report = f"## πŸ€– AI Murabbiy: To'liq Tahlil va O'quv Rejasi\n\n{ai_analysis}"
595
 
596
  weakness_themes = [w['category'] for w in weaknesses[:3]]
597
- logger.info(f"Fetching puzzles for themes: {weakness_themes}")
598
  puzzles = fetch_lichess_puzzles(weakness_themes, count=5)
599
 
600
  puzzle_text = "## 🧩 Sizning shaxsiy masalalaringiz\n\n"
601
- if puzzles:
602
- for i, puzzle in enumerate(puzzles, 1):
603
- theme = puzzle.get('themes', ['Tactics'])[0].title() if puzzle.get('themes') else 'Tactics'
604
- rating = puzzle.get('rating', 1500)
605
- url = puzzle.get('url', 'https://lichess.org/training')
606
- fen = puzzle.get('fen', '')[:40] if puzzle.get('fen') else 'N/A'
607
- puzzle_text += f"**Puzzle {i}: {theme}** (Rating: {rating})\n"
608
- puzzle_text += f"- [Solve on Lichess]({url})\n"
609
- puzzle_text += f"- Position: `{fen}...`\n\n"
610
- else:
611
- puzzle_text += "- Masalalarni [Lichess.org](https://lichess.org/training) saytidan ishlang\n"
612
-
613
- logger.info("=== Analysis completed successfully ===")
614
 
615
  return (
616
  full_report,
@@ -633,14 +499,14 @@ with gr.Blocks(title="Chess Study Plan Pro", theme=gr.themes.Soft()) as demo:
633
  - 🎯 Zaif tomonlar tahlili
634
  - πŸ€– AI murabbiy tavsiyalari
635
  - πŸ“š Kitoblar va kurslar tavsiyasi
636
- - 🧩 Interaktiv masalalar (gradio interfeysi ichida)
637
  """)
638
 
639
  with gr.Row():
640
  with gr.Column():
641
- gr.Markdown("### 🌐 Uzchess.com dan tahlil")
642
  username_chesscom = gr.Textbox(
643
- label="Uzchess.com foydalanuvchi nomi",
644
  placeholder="Foydalanuvchi nomini kiriting",
645
  )
646
 
@@ -701,14 +567,14 @@ with gr.Blocks(title="Chess Study Plan Pro", theme=gr.themes.Soft()) as demo:
701
  gr.Markdown("""
702
  ---
703
  ### πŸ“ Qanday foydalanish:
704
- - **Uzchess.com:** Foydalanuvchi nomingizni kiriting (oxirgi 30-50 ta o'yin tahlil qilinadi)
705
  - **Lichess:** Profile β†’ Games β†’ Export orqali PGN faylni yuklang
706
- - **Masalalar:** Har bir masalani tahlil qiling va eng yaxshi yurishni toping
707
 
708
- ### 🎯 Yangi xususiyatlar:
709
  - βœ… Debyut statistikasi (qaysi debyutlarda yaxshi/yomon o'ynaysiz)
710
  - βœ… Oq/Qora rang bo'yicha natijalar
711
- - βœ… Interaktiv masalalar (gradio interfeysi ichida)
712
  - βœ… Shaxsiy o'quv rejasi (kundalik mashg'ulotlar)
713
  - βœ… Kitoblar va kurslar tavsiyasi
714
  """)
 
1
  import gradio as gr
2
  import chess
3
  import chess.pgn
 
4
  import io
5
  import requests
6
  import google.generativeai as genai
7
+ from collections import defaultdict
8
  import os
9
  import time
 
 
10
  import logging
11
+ import csv
12
 
13
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
14
  logger = logging.getLogger(__name__)
 
17
  genai.configure(api_key=GEMINI_API_KEY)
18
  model = genai.GenerativeModel('gemini-2.0-flash-exp')
19
 
20
+ def load_opening_database():
21
+ openings = {}
22
+ try:
23
+ with open('Chess Opening Reference - Sheet1.csv', 'r', encoding='utf-8') as f:
24
+ reader = csv.DictReader(f)
25
+ for row in reader:
26
+ eco = row.get('ECO Code', '').strip()
27
+ name = row.get('Name', '').strip()
28
+ if eco and name:
29
+ openings[eco] = name
30
+ except Exception as e:
31
+ logger.error(f"Failed to load openings CSV: {e}")
32
+ return openings
33
+
34
+ OPENING_DB = load_opening_database()
35
+
36
+ def detect_opening(game):
37
+ eco = game.headers.get("ECO", "")
38
+ opening = game.headers.get("Opening", "")
39
+
40
+ if eco and eco in OPENING_DB:
41
+ return OPENING_DB[eco]
42
+ elif opening:
43
+ return opening
44
+ else:
45
+ return "Unknown Opening"
46
+
47
  def get_user_games_from_chess_com(username):
48
  try:
49
+ logger.info(f"Fetching games for: {username}")
50
+ username = username.strip().lower()
 
51
 
52
  user_url = f"https://api.chess.com/pub/player/{username}"
53
  response = requests.get(user_url, timeout=10, headers={'User-Agent': 'Mozilla/5.0'})
54
 
55
  if response.status_code != 200:
56
+ return None, f"❌ Foydalanuvchi topilmadi: {username}"
 
57
 
 
58
  archives_url = f"https://api.chess.com/pub/player/{username}/games/archives"
59
  response = requests.get(archives_url, timeout=10, headers={'User-Agent': 'Mozilla/5.0'})
60
 
61
  if response.status_code != 200:
 
62
  return None, "❌ O'yinlar arxivi topilmadi."
63
 
64
  archives = response.json()['archives']
65
  if not archives:
 
66
  return None, "❌ O'yinlar topilmadi."
67
 
 
 
68
  all_games = []
69
  for archive_url in reversed(archives[-3:]):
70
  time.sleep(0.3)
 
72
  if response.status_code == 200:
73
  games = response.json()['games']
74
  all_games.extend(games)
 
75
  if len(all_games) >= 50:
76
  break
77
 
 
 
78
  rapid_games = [g for g in all_games if g.get('time_class') in ['rapid', 'blitz']]
79
  if not rapid_games:
80
  rapid_games = all_games[:50]
81
 
82
  pgn_list = [g['pgn'] for g in rapid_games[:50] if 'pgn' in g]
83
 
 
 
84
  if not pgn_list:
 
85
  return None, "❌ PGN formatdagi o'yinlar topilmadi."
86
 
87
  return pgn_list, None
 
91
  return None, f"❌ Xatolik: {str(e)}"
92
 
93
  def parse_pgn_content(pgn_content):
 
94
  games = []
95
  if isinstance(pgn_content, list):
96
+ for pgn_text in pgn_content:
97
  try:
98
  game = chess.pgn.read_game(io.StringIO(pgn_text))
99
  if game:
100
  games.append(game)
101
+ except:
 
102
  pass
103
  else:
104
  pgn_io = io.StringIO(pgn_content)
 
105
  while True:
106
  try:
107
  game = chess.pgn.read_game(pgn_io)
108
  if game is None:
109
  break
110
  games.append(game)
111
+ except:
 
 
112
  break
113
 
 
114
  return games
115
 
 
116
  def analyze_game_detailed(game, username):
117
  board = game.board()
118
  mistakes = []
 
119
  move_number = 0
120
 
121
  white_player = game.headers.get("White", "").strip().lower()
 
131
  result = game.headers.get("Result", "*")
132
  opening = detect_opening(game)
133
 
 
134
  user_result = None
135
  if user_color is not None and result != "*":
136
  if result == "1-0":
137
+ user_result = "win" if user_color == chess.WHITE else "loss"
 
138
  elif result == "0-1":
139
+ user_result = "win" if user_color == chess.BLACK else "loss"
 
140
  elif result == "1/2-1/2":
141
  user_result = "draw"
142
 
 
198
  }
199
 
200
  def categorize_mistakes(all_analyses):
 
 
201
  if not all_analyses:
 
202
  return []
203
 
204
  blunders = 0
 
229
 
230
  total = blunders + regular_mistakes + hanging + opening + middlegame + endgame
231
 
 
 
 
 
232
  if total == 0:
 
233
  return []
234
 
235
  weaknesses = []
 
278
 
279
  weaknesses.sort(key=lambda x: x['count'], reverse=True)
280
 
 
281
  return weaknesses
282
 
 
 
283
  def fetch_lichess_puzzles(themes, count=5):
 
284
  puzzles = []
285
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
286
  try:
287
+ url = "https://lichess.org/training"
288
+ for i in range(count):
289
+ puzzles.append({
290
+ 'id': f'puzzle_{i+1}',
291
+ 'url': url,
292
+ 'theme': themes[0] if themes else 'Tactics',
293
+ 'rating': 1500
 
 
 
294
  })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
295
  except Exception as e:
296
+ logger.error(f"Error generating puzzle links: {str(e)}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
297
 
298
+ return puzzles
 
299
 
300
  def get_comprehensive_analysis(weaknesses, opening_stats, color_stats, total_games):
 
 
301
  weakness_text = "\n".join([f"- {w['category']}: {w['count']} marta ({w['percentage']:.1f}%)" for w in weaknesses])
302
 
303
  opening_text = "\n".join([f"- {opening}: {stats['total']} o'yin (G'alabalar: {stats['wins']}, Yutqazishlar: {stats['losses']}, Duranglar: {stats['draws']})"
 
343
 
344
  try:
345
  response = model.generate_content(prompt)
 
346
  return response.text
347
  except Exception as e:
348
  logger.error(f"AI analysis failed: {str(e)}")
349
  return f"AI tahlil hozircha mavjud emas: {str(e)}"
350
 
351
  def analyze_games(username_chesscom, pgn_file, username_pgn):
 
352
  actual_username = None
353
  pgn_content = None
354
 
355
  if username_chesscom:
356
  pgn_content, error = get_user_games_from_chess_com(username_chesscom)
357
  if error:
 
358
  return error, "", "", "", None, None, None, None, None
359
  actual_username = username_chesscom
360
 
 
361
  elif pgn_file:
 
362
  pgn_content = pgn_file.decode('utf-8') if isinstance(pgn_file, bytes) else pgn_file
363
 
364
  if username_pgn and username_pgn.strip():
365
  actual_username = username_pgn.strip()
366
  else:
 
367
  try:
368
  first_game = chess.pgn.read_game(io.StringIO(pgn_content))
369
  if first_game:
 
374
  actual_username = "Player"
375
  except:
376
  actual_username = "Player"
 
 
377
 
378
  else:
 
379
  return "❌ Chess.com foydalanuvchi nomini kiriting yoki PGN faylni yuklang", "", "", "", None, None, None, None, None
380
 
381
  games = parse_pgn_content(pgn_content)
382
 
383
  if not games:
 
384
  return "❌ O'yinlar topilmadi yoki tahlil qilinmadi", "", "", "", None, None, None, None, None
385
 
 
 
386
  all_analyses = []
387
  opening_stats = defaultdict(lambda: {'wins': 0, 'losses': 0, 'draws': 0, 'total': 0})
388
  color_stats = {
 
390
  'black': {'wins': 0, 'losses': 0, 'draws': 0}
391
  }
392
 
393
+ for game in games:
 
394
  analysis = analyze_game_detailed(game, actual_username)
395
  all_analyses.append(analysis)
396
 
 
398
  user_result = analysis.get('user_result')
399
  user_color = analysis['user_color']
400
 
 
 
401
  if user_color is not None:
402
  opening_stats[opening]['total'] += 1
403
 
 
414
  color_key = 'white' if user_color == chess.WHITE else 'black'
415
  color_stats[color_key]['draws'] += 1
416
 
 
417
  weaknesses = categorize_mistakes(all_analyses)
418
 
419
  all_mistakes = []
420
  for analysis in all_analyses:
421
  all_mistakes.extend(analysis.get('mistakes', []))
422
 
 
 
423
  stats_report = f"## πŸ“Š {len(games)} ta o'yin tahlili\n\n"
424
  stats_report += f"**Jami xatolar:** {len(all_mistakes)} ta\n\n"
425
 
 
464
 
465
  full_report = stats_report + opening_report + color_report
466
 
 
467
  ai_analysis = get_comprehensive_analysis(weaknesses, opening_stats, color_stats, len(games))
468
  ai_report = f"## πŸ€– AI Murabbiy: To'liq Tahlil va O'quv Rejasi\n\n{ai_analysis}"
469
 
470
  weakness_themes = [w['category'] for w in weaknesses[:3]]
 
471
  puzzles = fetch_lichess_puzzles(weakness_themes, count=5)
472
 
473
  puzzle_text = "## 🧩 Sizning shaxsiy masalalaringiz\n\n"
474
+ puzzle_text += "Masalalarni yechish uchun quyidagi havoladan foydalaning:\n\n"
475
+ for i, puzzle in enumerate(puzzles, 1):
476
+ theme = puzzle.get('theme', 'Tactics')
477
+ url = puzzle.get('url', 'https://lichess.org/training')
478
+ puzzle_text += f"**Puzzle {i}: {theme}**\n"
479
+ puzzle_text += f"- [Lichess Training]({url})\n\n"
 
 
 
 
 
 
 
480
 
481
  return (
482
  full_report,
 
499
  - 🎯 Zaif tomonlar tahlili
500
  - πŸ€– AI murabbiy tavsiyalari
501
  - πŸ“š Kitoblar va kurslar tavsiyasi
502
+ - 🧩 Lichess mashq masalalari
503
  """)
504
 
505
  with gr.Row():
506
  with gr.Column():
507
+ gr.Markdown("### 🌐 Chess.com dan tahlil")
508
  username_chesscom = gr.Textbox(
509
+ label="Chess.com foydalanuvchi nomi",
510
  placeholder="Foydalanuvchi nomini kiriting",
511
  )
512
 
 
567
  gr.Markdown("""
568
  ---
569
  ### πŸ“ Qanday foydalanish:
570
+ - **Chess.com:** Foydalanuvchi nomingizni kiriting (oxirgi 30-50 ta o'yin tahlil qilinadi)
571
  - **Lichess:** Profile β†’ Games β†’ Export orqali PGN faylni yuklang
572
+ - **Masalalar:** Lichess.org saytida mashq qiling
573
 
574
+ ### 🎯 Xususiyatlar:
575
  - βœ… Debyut statistikasi (qaysi debyutlarda yaxshi/yomon o'ynaysiz)
576
  - βœ… Oq/Qora rang bo'yicha natijalar
577
+ - βœ… Lichess mashq havolalari
578
  - βœ… Shaxsiy o'quv rejasi (kundalik mashg'ulotlar)
579
  - βœ… Kitoblar va kurslar tavsiyasi
580
  """)
app_1.py CHANGED
@@ -1,305 +1,716 @@
1
  import gradio as gr
2
  import chess
3
  import chess.pgn
 
4
  import io
5
  import requests
6
  import google.generativeai as genai
7
- from collections import Counter
8
- import json
9
  import os
 
 
 
 
 
 
 
 
10
 
11
- # Configure Gemini API
12
  GEMINI_API_KEY = os.environ.get('GEMINI_API_KEY')
13
  genai.configure(api_key=GEMINI_API_KEY)
14
- model = genai.GenerativeModel('gemini-2.5-flash')
15
 
16
- # ============= GAME ANALYSIS =============
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
- def parse_pgn_file(pgn_content):
19
- """Parse PGN file and return list of games"""
20
  games = []
21
- pgn_io = io.StringIO(pgn_content)
22
-
23
- while True:
24
- game = chess.pgn.read_game(pgn_io)
25
- if game is None:
26
- break
27
- games.append(game)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
 
29
  return games
30
 
31
- def analyze_single_game(game):
32
- """Analyze a single game and extract mistakes"""
33
  board = game.board()
34
  mistakes = []
 
35
  move_number = 0
36
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  for move in game.mainline_moves():
38
  move_number += 1
39
- position_fen = board.fen()
40
 
41
- # Apply the move
 
 
 
 
42
  board.push(move)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
 
44
- # Simple heuristic-based mistake detection
45
- mistake_type = detect_mistake_simple(board, move, position_fen)
46
  if mistake_type:
47
  mistakes.append({
48
- 'move_number': move_number,
49
- 'move': move.uci(),
50
  'type': mistake_type,
51
- 'fen': position_fen
 
52
  })
53
 
54
- return mistakes
55
-
56
- def detect_mistake_simple(board, move, position_fen):
57
- """Simple rule-based mistake detection"""
58
- # Check if piece was hung (left undefended)
59
- if board.is_check():
60
- return None
61
-
62
- # Count material before and after
63
- piece_values = {
64
- chess.PAWN: 1,
65
- chess.KNIGHT: 3,
66
- chess.BISHOP: 3,
67
- chess.ROOK: 5,
68
- chess.QUEEN: 9,
69
- chess.KING: 0
70
  }
71
-
72
- # Detect common tactical mistakes
73
- from_square = move.from_square
74
- to_square = move.to_square
75
-
76
- # Check if moved piece is now attacked and undefended
77
- moved_piece = board.piece_at(to_square)
78
- if moved_piece and board.is_attacked_by(not board.turn, to_square):
79
- attackers = len(board.attackers(not board.turn, to_square))
80
- defenders = len(board.attackers(board.turn, to_square))
81
- if attackers > defenders:
82
- return "hanging_piece"
83
-
84
- # Check if move allows opponent tactics
85
- if moved_piece and moved_piece.piece_type == chess.KNIGHT:
86
- # Simple check for knight positioning
87
- return "knight_positioning"
88
-
89
- # Detect pawn structure issues
90
- if moved_piece and moved_piece.piece_type == chess.PAWN:
91
- return "pawn_structure"
92
-
93
- # Endgame detection
94
- total_pieces = len(board.piece_map())
95
- if total_pieces <= 10:
96
- return "endgame_technique"
97
-
98
- return None
99
 
100
- def categorize_mistakes(all_mistakes):
101
- """Categorize and count mistake types"""
102
- mistake_types = [m['type'] for m in all_mistakes if m['type']]
103
- mistake_counts = Counter(mistake_types)
104
-
105
- # Map to readable categories
106
- category_map = {
107
- 'hanging_piece': 'Hanging Pieces / Undefended Material',
108
- 'knight_positioning': 'Knight Tactics & Positioning',
109
- 'pawn_structure': 'Pawn Structure Weaknesses',
110
- 'endgame_technique': 'Endgame Technique Issues'
111
- }
 
112
 
113
- categorized = []
114
- for mistake_type, count in mistake_counts.most_common(3):
115
- readable_name = category_map.get(mistake_type, mistake_type)
116
- categorized.append({
117
- 'category': readable_name,
118
- 'count': count,
119
- 'percentage': (count / len(all_mistakes) * 100) if all_mistakes else 0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  })
121
 
122
- return categorized
123
-
124
- # ============= GEMINI AI EXPLANATION =============
125
-
126
- def get_ai_explanation(weaknesses):
127
- """Use Gemini to explain weaknesses in plain language"""
128
- weakness_text = "\n".join([f"- {w['category']}: {w['percentage']:.1f}%" for w in weaknesses])
129
 
130
- prompt = f"""You are a chess coach. A player has these top weaknesses based on their recent games:
131
-
132
- {weakness_text}
133
-
134
- Explain each weakness in simple, encouraging language (2-3 sentences each). Give practical advice on how to improve. Be friendly and motivating."""
 
135
 
136
- try:
137
- response = model.generate_content(prompt)
138
- return response.text
139
- except Exception as e:
140
- return f"AI explanation unavailable: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
141
 
142
- # ============= PUZZLE FETCHING =============
143
 
144
  def fetch_lichess_puzzles(themes, count=5):
145
- """Fetch puzzles from Lichess based on themes"""
146
- # Map our categories to Lichess puzzle themes
 
147
  theme_map = {
148
- 'Hanging Pieces / Undefended Material': 'hangingPiece',
149
- 'Knight Tactics & Positioning': 'knightEndgame',
150
- 'Pawn Structure Weaknesses': 'pawnEndgame',
151
- 'Endgame Technique Issues': 'endgame'
 
 
152
  }
153
 
154
- puzzles = []
155
-
156
  for theme_name in themes:
157
- lichess_theme = theme_map.get(theme_name, 'mix')
158
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
159
  try:
160
- # Lichess puzzle database API
161
- url = f"https://lichess.org/api/puzzle/daily"
162
- response = requests.get(url, timeout=10)
163
 
164
  if response.status_code == 200:
165
- puzzle_data = response.json()
166
- puzzles.append({
167
- 'id': puzzle_data['puzzle']['id'],
168
- 'fen': puzzle_data['game']['fen'],
169
- 'moves': puzzle_data['puzzle']['solution'],
170
- 'rating': puzzle_data['puzzle']['rating'],
171
- 'theme': theme_name,
172
- 'url': f"https://lichess.org/training/{puzzle_data['puzzle']['id']}"
173
- })
 
 
 
 
 
 
 
174
  except Exception as e:
175
- print(f"Error fetching puzzle: {e}")
176
 
177
- # If we couldn't fetch enough, add some backup puzzles
178
  while len(puzzles) < count:
179
  puzzles.append({
180
- 'id': f'backup_{len(puzzles)}',
181
- 'fen': 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1',
182
- 'moves': ['e2e4'],
 
183
  'rating': 1500,
184
- 'theme': 'Practice',
185
- 'url': 'https://lichess.org/training'
186
  })
 
187
 
 
188
  return puzzles[:count]
189
 
190
- # ============= MAIN PROCESSING FUNCTION =============
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
191
 
192
- def process_chess_games(pgn_file, username=""):
193
- """Main function to process games and generate study plan"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
194
  try:
195
- # Read PGN content
196
- if pgn_file is None:
197
- return "❌ Please upload a PGN file", "", ""
198
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
199
  pgn_content = pgn_file.decode('utf-8') if isinstance(pgn_file, bytes) else pgn_file
200
 
201
- # Parse games
202
- games = parse_pgn_file(pgn_content)
203
-
204
- if not games:
205
- return "❌ No games found in PGN file", "", ""
206
-
207
- # Analyze all games
208
- all_mistakes = []
209
- for game in games[:10]: # Limit to 10 games for demo
210
- mistakes = analyze_single_game(game)
211
- all_mistakes.extend(mistakes)
212
-
213
- if not all_mistakes:
214
- return "βœ… Great! No major mistakes detected in your games!", "", ""
215
-
216
- # Categorize mistakes
217
- top_weaknesses = categorize_mistakes(all_mistakes)
218
-
219
- # Format weakness report
220
- weakness_report = f"## πŸ“Š Analysis of {len(games)} Games\n\n"
221
- weakness_report += f"**Total Mistakes Detected:** {len(all_mistakes)}\n\n"
222
- weakness_report += "### 🎯 Your Top 3 Weaknesses:\n\n"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
223
 
224
- for i, weakness in enumerate(top_weaknesses, 1):
225
- weakness_report += f"**{i}. {weakness['category']}**\n"
226
- weakness_report += f" - Occurred {weakness['count']} times ({weakness['percentage']:.1f}%)\n\n"
227
 
228
- # Get AI explanation
229
- ai_explanation = get_ai_explanation(top_weaknesses)
230
- explanation_text = f"## πŸ€– AI Coach Analysis\n\n{ai_explanation}"
231
 
232
- # Fetch puzzles
233
- theme_names = [w['category'] for w in top_weaknesses]
234
- puzzles = fetch_lichess_puzzles(theme_names, count=5)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
235
 
236
- # Format puzzle recommendations
237
- puzzle_text = "## 🧩 Your Personalized Study Plan (5 Puzzles)\n\n"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
238
  for i, puzzle in enumerate(puzzles, 1):
239
- puzzle_text += f"**Puzzle {i}: {puzzle['theme']}** (Rating: {puzzle['rating']})\n"
240
- puzzle_text += f"- [Solve on Lichess]({puzzle['url']})\n"
241
- puzzle_text += f"- Position: `{puzzle['fen'][:40]}...`\n\n"
242
-
243
- return weakness_report, explanation_text, puzzle_text
244
-
245
- except Exception as e:
246
- return f"❌ Error: {str(e)}", "", ""
247
-
248
- # ============= GRADIO INTERFACE =============
 
 
 
 
 
 
 
 
 
 
 
 
 
249
 
250
- def create_interface():
251
- """Create Gradio interface"""
 
252
 
253
- with gr.Blocks(title="Chess AI Study Plan", theme=gr.themes.Soft()) as demo:
254
- gr.Markdown("""
255
- # β™ŸοΈ Personalized Chess Study Plan Generator
256
-
257
- Upload your chess games (PGN format) and get:
258
- - πŸ“Š Analysis of your top 3 weaknesses
259
- - πŸ€– AI coach explanations
260
- - 🧩 5 personalized puzzles to improve
261
- """)
262
-
263
- with gr.Row():
264
- with gr.Column():
265
- pgn_upload = gr.File(
266
- label="πŸ“ Upload PGN File",
267
- file_types=[".pgn"],
268
- type="binary"
269
- )
270
- username_input = gr.Textbox(
271
- label="Chess.com Username (optional)",
272
- placeholder="Enter username to fetch games"
273
- )
274
- analyze_btn = gr.Button("πŸ” Analyze Games", variant="primary", size="lg")
275
-
276
- with gr.Row():
277
- weakness_output = gr.Markdown(label="Weaknesses")
278
-
279
- with gr.Row():
280
- explanation_output = gr.Markdown(label="AI Explanation")
281
 
282
- with gr.Row():
283
- puzzle_output = gr.Markdown(label="Study Plan")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
284
 
285
- # Connect button
286
- analyze_btn.click(
287
- fn=process_chess_games,
288
- inputs=[pgn_upload, username_input],
289
- outputs=[weakness_output, explanation_output, puzzle_output]
290
- )
291
 
292
- gr.Markdown("""
293
- ---
294
- ### πŸ“ How to get your PGN file:
295
- - **Lichess**: Go to your profile β†’ Games β†’ Export
296
- - **Chess.com**: Go to Archive β†’ Download games
297
- """)
298
-
299
- return demo
300
-
301
- # ============= LAUNCH =============
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
302
 
303
- if __name__ == "__main__":
304
- demo = create_interface()
305
- demo.launch()
 
1
  import gradio as gr
2
  import chess
3
  import chess.pgn
4
+ import chess.svg
5
  import io
6
  import requests
7
  import google.generativeai as genai
8
+ from collections import Counter, defaultdict
 
9
  import os
10
+ import time
11
+ import re
12
+ import chess.polyglot
13
+ import logging
14
+ from openings import get_opening_name_from_eco, detect_opening
15
+
16
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
17
+ logger = logging.getLogger(__name__)
18
 
 
19
  GEMINI_API_KEY = os.environ.get('GEMINI_API_KEY')
20
  genai.configure(api_key=GEMINI_API_KEY)
21
+ model = genai.GenerativeModel('gemini-2.0-flash-exp')
22
 
23
+ def get_user_games_from_chess_com(username):
24
+ try:
25
+ logger.info(f"Starting to fetch games for user: {username}")
26
+ username_original = username.strip()
27
+ username = username_original.lower()
28
+
29
+ user_url = f"https://api.chess.com/pub/player/{username}"
30
+ response = requests.get(user_url, timeout=10, headers={'User-Agent': 'Mozilla/5.0'})
31
+
32
+ if response.status_code != 200:
33
+ logger.error(f"User not found: {username}")
34
+ return None, f"❌ Foydalanuvchi topilmadi: {username}. Chess.com'da mavjudligini tekshiring."
35
+
36
+ logger.info(f"User found: {username}")
37
+ archives_url = f"https://api.chess.com/pub/player/{username}/games/archives"
38
+ response = requests.get(archives_url, timeout=10, headers={'User-Agent': 'Mozilla/5.0'})
39
+
40
+ if response.status_code != 200:
41
+ logger.error("Archives not found")
42
+ return None, "❌ O'yinlar arxivi topilmadi."
43
+
44
+ archives = response.json()['archives']
45
+ if not archives:
46
+ logger.error("No archives available")
47
+ return None, "❌ O'yinlar topilmadi."
48
+
49
+ logger.info(f"Found {len(archives)} archives")
50
+
51
+ all_games = []
52
+ for archive_url in reversed(archives[-3:]):
53
+ time.sleep(0.3)
54
+ response = requests.get(archive_url, timeout=10, headers={'User-Agent': 'Mozilla/5.0'})
55
+ if response.status_code == 200:
56
+ games = response.json()['games']
57
+ all_games.extend(games)
58
+ logger.info(f"Fetched {len(games)} games from archive")
59
+ if len(all_games) >= 50:
60
+ break
61
+
62
+ logger.info(f"Total games fetched: {len(all_games)}")
63
+
64
+ rapid_games = [g for g in all_games if g.get('time_class') in ['rapid', 'blitz']]
65
+ if not rapid_games:
66
+ rapid_games = all_games[:50]
67
+
68
+ pgn_list = [g['pgn'] for g in rapid_games[:50] if 'pgn' in g]
69
+
70
+ logger.info(f"Total PGN games prepared: {len(pgn_list)}")
71
+
72
+ if not pgn_list:
73
+ logger.error("No PGN games found")
74
+ return None, "❌ PGN formatdagi o'yinlar topilmadi."
75
+
76
+ return pgn_list, None
77
+
78
+ except Exception as e:
79
+ logger.error(f"Error fetching games: {str(e)}")
80
+ return None, f"❌ Xatolik: {str(e)}"
81
 
82
+ def parse_pgn_content(pgn_content):
83
+ logger.info("Starting to parse PGN content")
84
  games = []
85
+ if isinstance(pgn_content, list):
86
+ for idx, pgn_text in enumerate(pgn_content):
87
+ try:
88
+ game = chess.pgn.read_game(io.StringIO(pgn_text))
89
+ if game:
90
+ games.append(game)
91
+ except Exception as e:
92
+ logger.warning(f"Failed to parse game {idx}: {str(e)}")
93
+ pass
94
+ else:
95
+ pgn_io = io.StringIO(pgn_content)
96
+ idx = 0
97
+ while True:
98
+ try:
99
+ game = chess.pgn.read_game(pgn_io)
100
+ if game is None:
101
+ break
102
+ games.append(game)
103
+ idx += 1
104
+ except Exception as e:
105
+ logger.warning(f"Failed to parse game {idx}: {str(e)}")
106
+ break
107
 
108
+ logger.info(f"Successfully parsed {len(games)} games")
109
  return games
110
 
111
+
112
+ def analyze_game_detailed(game, username):
113
  board = game.board()
114
  mistakes = []
115
+
116
  move_number = 0
117
 
118
+ white_player = game.headers.get("White", "").strip().lower()
119
+ black_player = game.headers.get("Black", "").strip().lower()
120
+ username_lower = username.strip().lower()
121
+
122
+ user_color = None
123
+ if username_lower == white_player:
124
+ user_color = chess.WHITE
125
+ elif username_lower == black_player:
126
+ user_color = chess.BLACK
127
+
128
+ result = game.headers.get("Result", "*")
129
+ opening = detect_opening(game)
130
+
131
+ user_won = None
132
+ user_result = None
133
+ if user_color is not None and result != "*":
134
+ if result == "1-0":
135
+ user_won = (user_color == chess.WHITE)
136
+ user_result = "win" if user_won else "loss"
137
+ elif result == "0-1":
138
+ user_won = (user_color == chess.BLACK)
139
+ user_result = "win" if user_won else "loss"
140
+ elif result == "1/2-1/2":
141
+ user_result = "draw"
142
+
143
+ material_values = {chess.PAWN: 1, chess.KNIGHT: 3, chess.BISHOP: 3, chess.ROOK: 5, chess.QUEEN: 9}
144
+
145
+ def count_material(board):
146
+ total = 0
147
+ for piece_type in material_values:
148
+ total += len(board.pieces(piece_type, chess.WHITE)) * material_values[piece_type]
149
+ total -= len(board.pieces(piece_type, chess.BLACK)) * material_values[piece_type]
150
+ return total
151
+
152
  for move in game.mainline_moves():
153
  move_number += 1
 
154
 
155
+ if user_color is not None and board.turn != user_color:
156
+ board.push(move)
157
+ continue
158
+
159
+ material_before = count_material(board)
160
  board.push(move)
161
+ material_after = count_material(board)
162
+
163
+ material_loss = abs(material_after - material_before) if board.turn == chess.WHITE else abs(material_before - material_after)
164
+
165
+ moved_piece = board.piece_at(move.to_square)
166
+ mistake_type = None
167
+
168
+ if material_loss >= 3:
169
+ mistake_type = 'blunder'
170
+ elif material_loss >= 1:
171
+ mistake_type = 'mistake'
172
+ elif moved_piece and board.is_attacked_by(not board.turn, move.to_square):
173
+ attackers = len(board.attackers(not board.turn, move.to_square))
174
+ defenders = len(board.attackers(board.turn, move.to_square))
175
+ if attackers > defenders:
176
+ mistake_type = 'hanging_piece'
177
+
178
+ if move_number <= 10:
179
+ phase = 'opening'
180
+ elif len(board.piece_map()) <= 10:
181
+ phase = 'endgame'
182
+ else:
183
+ phase = 'middlegame'
184
 
 
 
185
  if mistake_type:
186
  mistakes.append({
 
 
187
  'type': mistake_type,
188
+ 'phase': phase,
189
+ 'move_number': move_number
190
  })
191
 
192
+ return {
193
+ 'mistakes': mistakes,
194
+ 'opening': opening,
195
+ 'result': result,
196
+ 'user_color': user_color,
197
+ 'user_result': user_result
 
 
 
 
 
 
 
 
 
 
198
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
199
 
200
+ def categorize_mistakes(all_analyses):
201
+ logger.info("Categorizing mistakes from all games")
202
+
203
+ if not all_analyses:
204
+ logger.warning("No analyses provided for categorization")
205
+ return []
206
+
207
+ blunders = 0
208
+ regular_mistakes = 0
209
+ hanging = 0
210
+ opening = 0
211
+ middlegame = 0
212
+ endgame = 0
213
 
214
+ for analysis in all_analyses:
215
+ for mistake in analysis.get('mistakes', []):
216
+ mistake_type = mistake.get('type')
217
+ phase = mistake.get('phase')
218
+
219
+ if mistake_type == 'blunder':
220
+ blunders += 1
221
+ elif mistake_type == 'mistake':
222
+ regular_mistakes += 1
223
+ elif mistake_type == 'hanging_piece':
224
+ hanging += 1
225
+
226
+ if phase == 'opening':
227
+ opening += 1
228
+ elif phase == 'middlegame':
229
+ middlegame += 1
230
+ elif phase == 'endgame':
231
+ endgame += 1
232
+
233
+ total = blunders + regular_mistakes + hanging + opening + middlegame + endgame
234
+
235
+ logger.info(f"Total mistakes found: {total}")
236
+ logger.info(f"Blunders: {blunders}, Mistakes: {regular_mistakes}, Hanging: {hanging}")
237
+ logger.info(f"Opening: {opening}, Middlegame: {middlegame}, Endgame: {endgame}")
238
+
239
+ if total == 0:
240
+ logger.warning("No mistakes found in any game")
241
+ return []
242
+
243
+ weaknesses = []
244
+
245
+ if blunders > 0:
246
+ weaknesses.append({
247
+ 'category': "Qo'pol xatolar",
248
+ 'count': blunders,
249
+ 'percentage': (blunders / total * 100)
250
  })
251
 
252
+ if regular_mistakes > 0:
253
+ weaknesses.append({
254
+ 'category': 'Kichik xatolar',
255
+ 'count': regular_mistakes,
256
+ 'percentage': (regular_mistakes / total * 100)
257
+ })
 
258
 
259
+ if hanging > 0:
260
+ weaknesses.append({
261
+ 'category': 'Himoyasiz qoldirish',
262
+ 'count': hanging,
263
+ 'percentage': (hanging / total * 100)
264
+ })
265
 
266
+ if opening > 0:
267
+ weaknesses.append({
268
+ 'category': 'Debyut xatolari',
269
+ 'count': opening,
270
+ 'percentage': (opening / total * 100)
271
+ })
272
+
273
+ if middlegame > 0:
274
+ weaknesses.append({
275
+ 'category': "O'rta o'yin xatolari",
276
+ 'count': middlegame,
277
+ 'percentage': (middlegame / total * 100)
278
+ })
279
+
280
+ if endgame > 0:
281
+ weaknesses.append({
282
+ 'category': 'Endshpil xatolari',
283
+ 'count': endgame,
284
+ 'percentage': (endgame / total * 100)
285
+ })
286
+
287
+ weaknesses.sort(key=lambda x: x['count'], reverse=True)
288
+
289
+ logger.info(f"Total weakness categories: {len(weaknesses)}")
290
+ return weaknesses
291
 
292
+ import json
293
 
294
  def fetch_lichess_puzzles(themes, count=5):
295
+ logger.info(f"Fetching {count} puzzles for themes: {themes}")
296
+ puzzles = []
297
+
298
  theme_map = {
299
+ "Qo'pol xatolar": ['hangingPiece', 'discoveredAttack', 'fork'],
300
+ 'Kichik xatolar': ['advantage', 'crushing', 'attackingF2F7'],
301
+ 'Himoyasiz qoldirish': ['hangingPiece', 'pin', 'skewer'],
302
+ 'Debyut xatolari': ['opening', 'short', 'middlegame'],
303
+ "O'rta o'yin xatolari": ['middlegame', 'attackingF2F7', 'advancedPawn'],
304
+ 'Endshpil xatolari': ['endgame', 'queenEndgame', 'rookEndgame']
305
  }
306
 
307
+ lichess_themes = []
 
308
  for theme_name in themes:
309
+ if theme_name in theme_map:
310
+ lichess_themes.extend(theme_map[theme_name])
311
+
312
+ lichess_themes = list(set(lichess_themes))[:3]
313
+ logger.info(f"Selected Lichess themes: {lichess_themes}")
314
+
315
+ try:
316
+ # Fetch puzzles using the daily puzzle API and database
317
+ for theme in lichess_themes:
318
+ if len(puzzles) >= count:
319
+ break
320
+
321
+ # Use Lichess puzzle database API
322
+ url = f"https://lichess.org/api/puzzle/batch/mix?nb=2&themes={theme}"
323
+ response = requests.get(url, timeout=10, headers={
324
+ 'User-Agent': 'Mozilla/5.0',
325
+ 'Accept': 'application/x-ndjson'
326
+ })
327
+
328
+ if response.status_code == 200:
329
+ # Parse NDJSON (newline-delimited JSON)
330
+ lines = response.text.strip().split('\n')
331
+ for line in lines:
332
+ if len(puzzles) >= count:
333
+ break
334
+ if not line.strip():
335
+ continue
336
+ try:
337
+ puzzle_data = json.loads(line) # Use json.loads instead of eval
338
+ game_data = puzzle_data.get('game', {})
339
+ puzzle_info = puzzle_data.get('puzzle', {})
340
+
341
+ puzzle_id = puzzle_info.get('id', '')
342
+
343
+ if puzzle_id and not any(p['id'] == puzzle_id for p in puzzles):
344
+ puzzles.append({
345
+ 'id': puzzle_id,
346
+ 'fen': game_data.get('fen', ''),
347
+ 'moves': ' '.join(puzzle_info.get('solution', [])),
348
+ 'solution': puzzle_info.get('solution', []),
349
+ 'rating': puzzle_info.get('rating', 1500),
350
+ 'themes': puzzle_info.get('themes', []),
351
+ 'url': f"https://lichess.org/training/{puzzle_id}"
352
+ })
353
+ logger.info(f"Added puzzle {puzzle_id} with rating {puzzle_info.get('rating')}")
354
+ except json.JSONDecodeError as e:
355
+ logger.warning(f"Failed to parse puzzle line: {str(e)}")
356
+ except Exception as e:
357
+ logger.warning(f"Error processing puzzle: {str(e)}")
358
+
359
+ time.sleep(0.3)
360
+ except Exception as e:
361
+ logger.error(f"Error fetching puzzles: {str(e)}")
362
+
363
+ # Fill remaining with daily puzzle if needed
364
+ if len(puzzles) < count:
365
  try:
366
+ url = "https://lichess.org/api/puzzle/daily"
367
+ response = requests.get(url, timeout=10, headers={'User-Agent': 'Mozilla/5.0'})
 
368
 
369
  if response.status_code == 200:
370
+ daily_data = response.json()
371
+ game_data = daily_data.get('game', {})
372
+ puzzle_info = daily_data.get('puzzle', {})
373
+ puzzle_id = puzzle_info.get('id', '')
374
+
375
+ if puzzle_id and not any(p['id'] == puzzle_id for p in puzzles):
376
+ puzzles.append({
377
+ 'id': puzzle_id,
378
+ 'fen': game_data.get('fen', ''),
379
+ 'moves': ' '.join(puzzle_info.get('solution', [])),
380
+ 'solution': puzzle_info.get('solution', []),
381
+ 'rating': puzzle_info.get('rating', 1500),
382
+ 'themes': puzzle_info.get('themes', []),
383
+ 'url': f"https://lichess.org/training/{puzzle_id}"
384
+ })
385
+ logger.info(f"Added daily puzzle {puzzle_id}")
386
  except Exception as e:
387
+ logger.error(f"Error fetching daily puzzle: {str(e)}")
388
 
389
+ # Fill with fallback training links if still not enough
390
  while len(puzzles) < count:
391
  puzzles.append({
392
+ 'id': f'training_{len(puzzles)+1}',
393
+ 'fen': '',
394
+ 'moves': '',
395
+ 'solution': [],
396
  'rating': 1500,
397
+ 'themes': ['Mixed'],
398
+ 'url': "https://lichess.org/training"
399
  })
400
+ logger.info(f"Added fallback puzzle link {len(puzzles)}")
401
 
402
+ logger.info(f"Total puzzles prepared: {len(puzzles)}")
403
  return puzzles[:count]
404
 
405
+ def get_comprehensive_analysis(weaknesses, opening_stats, color_stats, total_games):
406
+ logger.info("Generating AI comprehensive analysis")
407
+
408
+ weakness_text = "\n".join([f"- {w['category']}: {w['count']} marta ({w['percentage']:.1f}%)" for w in weaknesses])
409
+
410
+ opening_text = "\n".join([f"- {opening}: {stats['total']} o'yin (G'alabalar: {stats['wins']}, Yutqazishlar: {stats['losses']}, Duranglar: {stats['draws']})"
411
+ for opening, stats in list(opening_stats.items())[:5]])
412
+
413
+ color_text = f"Oq rangda: {color_stats['white']['wins']}G-{color_stats['white']['losses']}Y-{color_stats['white']['draws']}D\n"
414
+ color_text += f"Qora rangda: {color_stats['black']['wins']}G-{color_stats['black']['losses']}Y-{color_stats['black']['draws']}D"
415
+
416
+ prompt = f"""Siz professional ΡˆΠ°Ρ…ΠΌΠ°Ρ‚ murabbiy va tahlilchisiz. O'yinchining {total_games} ta o'yinini tahlil qildingiz.
417
+
418
+ STATISTIKA:
419
+
420
+ Zaif tomonlar:
421
+ {weakness_text}
422
 
423
+ Eng ko'p o'ynaladigan debyutlar:
424
+ {opening_text}
425
+
426
+ Rang bo'yicha natijalar:
427
+ {color_text}
428
+
429
+ Quyidagilarni taqdim eting:
430
+
431
+ 1. **ZAIF TOMONLAR TAHLILI**: Har bir zaif tomonni chuqur tahlil qiling va nima uchun bu muammo kelib chiqayotganini tushuntiring.
432
+
433
+ 2. **SHAXSIY O'QUV REJASI**: Kundalik mashg'ulotlar rejasini tuzing:
434
+ - Har kuni nechta masala yechish kerak va qanday turdagi masalalar
435
+ - Qaysi debyutlarni o'rganish kerak
436
+ - Qaysi o'yin bosqichiga ko'proq e'tibor berish kerak
437
+ - Kompyuter yoki botlar bilan qanday mashq qilish kerak
438
+
439
+ 3. **TAVSIYA ETILGAN RESURSLAR**:
440
+ - Kitoblar (muallif va nom bilan)
441
+ - Onlayn kurslar (Uzchess, Chess.com, Lichess)
442
+ - YouTube kanallari
443
+ - Mashq uchun maxsus botlar yoki dasturlar
444
+
445
+ 4. **DEBYUT TAVSIYALARI**: Statistikaga asoslanib, qaysi debyutlarni davom ettirish va qaysilarini o'zgartirish kerak.
446
+
447
+ 5. **MOTIVATSION XULOSA**: Qisqa va rag'batlantiruvchi xulosa.
448
+
449
+ MUHIM: Javobni FAQAT O'ZBEK TILIDA yozing! Aniq va amaliy maslahatlar bering."""
450
+
451
  try:
452
+ response = model.generate_content(prompt)
453
+ logger.info("AI analysis generated successfully")
454
+ return response.text
455
+ except Exception as e:
456
+ logger.error(f"AI analysis failed: {str(e)}")
457
+ return f"AI tahlil hozircha mavjud emas: {str(e)}"
458
+
459
+ def analyze_games(username_chesscom, pgn_file, username_pgn):
460
+ logger.info("=== Starting game analysis ===")
461
+ actual_username = None
462
+ pgn_content = None
463
+
464
+ if username_chesscom:
465
+ pgn_content, error = get_user_games_from_chess_com(username_chesscom)
466
+ if error:
467
+ logger.error(f"Failed to fetch games: {error}")
468
+ return error, "", "", "", None, None, None, None, None
469
+ actual_username = username_chesscom
470
+
471
+ # PGN file upload
472
+ elif pgn_file:
473
+ logger.info("Processing uploaded PGN file")
474
  pgn_content = pgn_file.decode('utf-8') if isinstance(pgn_file, bytes) else pgn_file
475
 
476
+ if username_pgn and username_pgn.strip():
477
+ actual_username = username_pgn.strip()
478
+ else:
479
+ # Try to extract username from first game headers
480
+ try:
481
+ first_game = chess.pgn.read_game(io.StringIO(pgn_content))
482
+ if first_game:
483
+ white = first_game.headers.get("White", "")
484
+ black = first_game.headers.get("Black", "")
485
+ actual_username = white if white else black if black else "Player"
486
+ else:
487
+ actual_username = "Player"
488
+ except:
489
+ actual_username = "Player"
490
+
491
+ logger.info(f"Extracted username from PGN: {actual_username}")
492
+
493
+ else:
494
+ logger.error("No username or file provided")
495
+ return "❌ Chess.com foydalanuvchi nomini kiriting yoki PGN faylni yuklang", "", "", "", None, None, None, None, None
496
+
497
+ games = parse_pgn_content(pgn_content)
498
+
499
+ if not games:
500
+ logger.error("No games parsed")
501
+ return "❌ O'yinlar topilmadi yoki tahlil qilinmadi", "", "", "", None, None, None, None, None
502
+
503
+ logger.info(f"Analyzing {len(games)} games")
504
+
505
+ all_analyses = []
506
+ opening_stats = defaultdict(lambda: {'wins': 0, 'losses': 0, 'draws': 0, 'total': 0})
507
+ color_stats = {
508
+ 'white': {'wins': 0, 'losses': 0, 'draws': 0},
509
+ 'black': {'wins': 0, 'losses': 0, 'draws': 0}
510
+ }
511
+
512
+ for idx, game in enumerate(games):
513
+ logger.info(f"Analyzing game {idx + 1}/{len(games)}")
514
+ analysis = analyze_game_detailed(game, actual_username)
515
+ all_analyses.append(analysis)
516
 
517
+ opening = analysis['opening']
518
+ user_result = analysis.get('user_result')
519
+ user_color = analysis['user_color']
520
 
521
+ logger.info(f"Game {idx + 1}: {opening}, Result: {user_result}, Color: {user_color}")
 
 
522
 
523
+ if user_color is not None:
524
+ opening_stats[opening]['total'] += 1
525
+
526
+ if user_result == 'win':
527
+ opening_stats[opening]['wins'] += 1
528
+ color_key = 'white' if user_color == chess.WHITE else 'black'
529
+ color_stats[color_key]['wins'] += 1
530
+ elif user_result == 'loss':
531
+ opening_stats[opening]['losses'] += 1
532
+ color_key = 'white' if user_color == chess.WHITE else 'black'
533
+ color_stats[color_key]['losses'] += 1
534
+ elif user_result == 'draw':
535
+ opening_stats[opening]['draws'] += 1
536
+ color_key = 'white' if user_color == chess.WHITE else 'black'
537
+ color_stats[color_key]['draws'] += 1
538
+
539
+ logger.info("Categorizing mistakes")
540
+ weaknesses = categorize_mistakes(all_analyses)
541
+
542
+ all_mistakes = []
543
+ for analysis in all_analyses:
544
+ all_mistakes.extend(analysis.get('mistakes', []))
545
+
546
+ logger.info(f"Total mistakes collected: {len(all_mistakes)}")
547
+
548
+ stats_report = f"## πŸ“Š {len(games)} ta o'yin tahlili\n\n"
549
+ stats_report += f"**Jami xatolar:** {len(all_mistakes)} ta\n\n"
550
+
551
+ stats_report += "### 🎯 Eng zaif 3 tomoningiz:\n\n"
552
+ if weaknesses:
553
+ for i, w in enumerate(weaknesses[:3], 1):
554
+ stats_report += f"**{i}. {w['category']}** - {w['count']} marta ({w['percentage']:.1f}%)\n"
555
+ else:
556
+ stats_report += "Xatolar topilmadi yoki tahlil qilinmadi.\n"
557
+
558
+ opening_report = "\n\n## 🎭 Debyut Statistikasi\n\n"
559
+ sorted_openings = sorted(opening_stats.items(), key=lambda x: x[1]['total'], reverse=True)[:10]
560
+
561
+ for opening, stats in sorted_openings:
562
+ total = stats['total']
563
+ wins = stats['wins']
564
+ losses = stats['losses']
565
+ draws = stats['draws']
566
+ win_rate = (wins / total * 100) if total > 0 else 0
567
 
568
+ opening_report += f"**{opening}** ({total} o'yin)\n"
569
+ opening_report += f"- G'alabalar: {wins} ({win_rate:.1f}%) | Yutqazishlar: {losses} | Duranglar: {draws}\n\n"
570
+
571
+ color_report = "\n\n## βšͺ⚫ Rang bo'yicha natijalar\n\n"
572
+
573
+ white_total = sum(color_stats['white'].values())
574
+ black_total = sum(color_stats['black'].values())
575
+
576
+ if white_total > 0:
577
+ white_wr = color_stats['white']['wins'] / white_total * 100
578
+ color_report += f"**Oq figuralar bilan:**\n"
579
+ color_report += f"- G'alabalar: {color_stats['white']['wins']} ({white_wr:.1f}%)\n"
580
+ color_report += f"- Yutqazishlar: {color_stats['white']['losses']}\n"
581
+ color_report += f"- Duranglar: {color_stats['white']['draws']}\n\n"
582
+
583
+ if black_total > 0:
584
+ black_wr = color_stats['black']['wins'] / black_total * 100
585
+ color_report += f"**Qora figuralar bilan:**\n"
586
+ color_report += f"- G'alabalar: {color_stats['black']['wins']} ({black_wr:.1f}%)\n"
587
+ color_report += f"- Yutqazishlar: {color_stats['black']['losses']}\n"
588
+ color_report += f"- Duranglar: {color_stats['black']['draws']}\n"
589
+
590
+ full_report = stats_report + opening_report + color_report
591
+
592
+ logger.info("Generating AI analysis")
593
+ ai_analysis = get_comprehensive_analysis(weaknesses, opening_stats, color_stats, len(games))
594
+ ai_report = f"## πŸ€– AI Murabbiy: To'liq Tahlil va O'quv Rejasi\n\n{ai_analysis}"
595
+
596
+ weakness_themes = [w['category'] for w in weaknesses[:3]]
597
+ logger.info(f"Fetching puzzles for themes: {weakness_themes}")
598
+ puzzles = fetch_lichess_puzzles(weakness_themes, count=5)
599
+
600
+ puzzle_text = "## 🧩 Sizning shaxsiy masalalaringiz\n\n"
601
+ if puzzles:
602
  for i, puzzle in enumerate(puzzles, 1):
603
+ theme = puzzle.get('themes', ['Tactics'])[0].title() if puzzle.get('themes') else 'Tactics'
604
+ rating = puzzle.get('rating', 1500)
605
+ url = puzzle.get('url', 'https://lichess.org/training')
606
+ fen = puzzle.get('fen', '')[:40] if puzzle.get('fen') else 'N/A'
607
+ puzzle_text += f"**Puzzle {i}: {theme}** (Rating: {rating})\n"
608
+ puzzle_text += f"- [Solve on Lichess]({url})\n"
609
+ puzzle_text += f"- Position: `{fen}...`\n\n"
610
+ else:
611
+ puzzle_text += "- Masalalarni [Lichess.org](https://lichess.org/training) saytidan ishlang\n"
612
+
613
+ logger.info("=== Analysis completed successfully ===")
614
+
615
+ return (
616
+ full_report,
617
+ ai_report,
618
+ puzzle_text,
619
+ "",
620
+ None,
621
+ "",
622
+ None,
623
+ "",
624
+ None
625
+ )
626
 
627
+ with gr.Blocks(title="Chess Study Plan Pro", theme=gr.themes.Soft()) as demo:
628
+ gr.Markdown("""
629
+ # β™ŸοΈ Professional Π¨Π°Ρ…ΠΌΠ°Ρ‚ O'quv Rejasi
630
 
631
+ ### To'liq tahlil va shaxsiy o'quv rejasi:
632
+ - πŸ“Š Batafsil statistika (debyutlar, ranglar, natijalar)
633
+ - 🎯 Zaif tomonlar tahlili
634
+ - πŸ€– AI murabbiy tavsiyalari
635
+ - πŸ“š Kitoblar va kurslar tavsiyasi
636
+ - 🧩 Interaktiv masalalar (gradio interfeysi ichida)
637
+ """)
638
+
639
+ with gr.Row():
640
+ with gr.Column():
641
+ gr.Markdown("### 🌐 Uzchess.com dan tahlil")
642
+ username_chesscom = gr.Textbox(
643
+ label="Uzchess.com foydalanuvchi nomi",
644
+ placeholder="Foydalanuvchi nomini kiriting",
645
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
646
 
647
+ with gr.Column():
648
+ gr.Markdown("### πŸ“ PGN fayl yuklash")
649
+ pgn_upload = gr.File(
650
+ label="PGN faylni yuklang",
651
+ file_types=[".pgn"],
652
+ type="binary"
653
+ )
654
+ username_pgn = gr.Textbox(
655
+ label="Foydalanuvchi nomi (PGN uchun)",
656
+ placeholder="PGN dagi o'yinchi nomi (ixtiyoriy)",
657
+ info="Bo'sh qoldiring, avtomatik aniqlanadi"
658
+ )
659
+
660
+ analyze_btn = gr.Button("πŸ” To'liq tahlil qilish", variant="primary", size="lg")
661
+
662
+ with gr.Row():
663
+ stats_output = gr.Markdown(label="Statistika")
664
+
665
+ with gr.Row():
666
+ ai_output = gr.Markdown(label="AI Tahlil")
667
+
668
+ gr.Markdown("---")
669
+
670
+ puzzle_header = gr.Markdown()
671
+
672
+ with gr.Row():
673
+ with gr.Column():
674
+ puzzle1_info = gr.Markdown()
675
+ puzzle1_board = gr.HTML()
676
 
677
+ with gr.Column():
678
+ puzzle2_info = gr.Markdown()
679
+ puzzle2_board = gr.HTML()
 
 
 
680
 
681
+ with gr.Column():
682
+ puzzle3_info = gr.Markdown()
683
+ puzzle3_board = gr.HTML()
684
+
685
+ analyze_btn.click(
686
+ fn=analyze_games,
687
+ inputs=[username_chesscom, pgn_upload, username_pgn],
688
+ outputs=[
689
+ stats_output,
690
+ ai_output,
691
+ puzzle_header,
692
+ puzzle1_info,
693
+ puzzle1_board,
694
+ puzzle2_info,
695
+ puzzle2_board,
696
+ puzzle3_info,
697
+ puzzle3_board
698
+ ]
699
+ )
700
+
701
+ gr.Markdown("""
702
+ ---
703
+ ### πŸ“ Qanday foydalanish:
704
+ - **Uzchess.com:** Foydalanuvchi nomingizni kiriting (oxirgi 30-50 ta o'yin tahlil qilinadi)
705
+ - **Lichess:** Profile β†’ Games β†’ Export orqali PGN faylni yuklang
706
+ - **Masalalar:** Har bir masalani tahlil qiling va eng yaxshi yurishni toping
707
+
708
+ ### 🎯 Yangi xususiyatlar:
709
+ - βœ… Debyut statistikasi (qaysi debyutlarda yaxshi/yomon o'ynaysiz)
710
+ - βœ… Oq/Qora rang bo'yicha natijalar
711
+ - βœ… Interaktiv masalalar (gradio interfeysi ichida)
712
+ - βœ… Shaxsiy o'quv rejasi (kundalik mashg'ulotlar)
713
+ - βœ… Kitoblar va kurslar tavsiyasi
714
+ """)
715
 
716
+ demo.launch()
 
 
openings.py CHANGED
@@ -36,6 +36,7 @@ def get_opening_name_from_eco(eco_code):
36
  'B50': 'Sicilian Defense: 2...d6',
37
  'B90': 'Sicilian Defense: Najdorf',
38
  'C00': 'French Defense',
 
39
  'C02': 'French Defense: Advance Variation',
40
  'C10': 'French Defense: Rubinstein Variation',
41
  'C20': 'King Pawn Game',
@@ -45,6 +46,8 @@ def get_opening_name_from_eco(eco_code):
45
  'C42': 'Russian Game (Petrov Defense)',
46
  'C44': 'Scotch Game',
47
  'C50': 'Italian Game',
 
 
48
  'C60': 'Spanish Opening (Ruy Lopez)',
49
  'C65': 'Spanish Opening: Berlin Defense',
50
  'C70': 'Spanish Opening',
 
36
  'B50': 'Sicilian Defense: 2...d6',
37
  'B90': 'Sicilian Defense: Najdorf',
38
  'C00': 'French Defense',
39
+ "C01": 'French Defense: Exchange Variation',
40
  'C02': 'French Defense: Advance Variation',
41
  'C10': 'French Defense: Rubinstein Variation',
42
  'C20': 'King Pawn Game',
 
46
  'C42': 'Russian Game (Petrov Defense)',
47
  'C44': 'Scotch Game',
48
  'C50': 'Italian Game',
49
+ "C54": "Italian Game: Giuoco Piano",
50
+ 'C55': 'Italian Game: Two Knights Defense',
51
  'C60': 'Spanish Opening (Ruy Lopez)',
52
  'C65': 'Spanish Opening: Berlin Defense',
53
  'C70': 'Spanish Opening',