]> git.sesse.net Git - remoteglot/blob - www/js/book.js
Add more columns, and hide Elo variables if we have less than 10 samples.
[remoteglot] / www / js / book.js
1 (function() {
2
3 var board = null;
4 var moves = [];
5 var move_override = 0;
6
7 var get_game = function() {
8         var game = new Chess();
9         for (var i = 0; i < move_override; ++i) {
10                 game.move(moves[i]);
11         }
12         return game;
13 }
14
15 var update = function() {
16         var game = get_game();
17         board.position(game.fen());
18         fetch_analysis();
19 }
20
21 var fetch_analysis = function() {
22         var game = get_game();
23         $.ajax({
24                 url: "/opening-stats.pl?fen=" + encodeURIComponent(game.fen())
25         }).done(function(data, textstatus, xhr) {
26                 show_lines(data, game);
27         });
28 }
29
30 var add_td = function(tr, value) {
31         var td = document.createElement("td");
32         tr.appendChild(td);
33         $(td).addClass("num");
34         $(td).text(value);
35 }
36
37 var show_lines = function(data, game) {
38         var moves = data['moves'];
39         $('#numviewers').text(data['opening']);
40         var total_num = 0;
41         for (var i = 0; i < moves.length; ++i) {
42                 var move = moves[i];
43                 total_num += parseInt(move['white']);
44                 total_num += parseInt(move['draw']);
45                 total_num += parseInt(move['black']);
46         }       
47
48         var tbl = $("#lines");
49         tbl.empty();
50
51         for (var i = 0; i < moves.length; ++i) {
52                 var move = moves[i];
53                 var tr = document.createElement("tr");
54
55                 var white = parseInt(move['white']);
56                 var draw = parseInt(move['draw']);
57                 var black = parseInt(move['black']);
58
59                 // Move.
60                 var move_td = document.createElement("td");
61                 tr.appendChild(move_td);
62                 $(move_td).addClass("move");
63
64                 var move_a = document.createElement("a");
65                 move_a.href = "javascript:make_move('" + move['move'] + "')";
66                 move_td.appendChild(move_a);
67                 $(move_a).text(move['move']);
68
69                 // N.
70                 var num = white + draw + black;
71                 add_td(tr, num);
72
73                 // %.
74                 add_td(tr, (100.0 * num / total_num).toFixed(1) + "%");
75
76                 // Win%.
77                 var white_win_ratio = (white + 0.5 * draw) / num;
78                 var win_ratio = (game.turn() == 'w') ? white_win_ratio : 1.0 - white_win_ratio;
79                 add_td(tr, ((100.0 * win_ratio).toFixed(1) + "%"));
80
81                 // WWin and %WW.
82                 add_td(tr, white);
83                 add_td(tr, (100.0 * white / num).toFixed(1) + "%");
84
85                 // BWin and %BW.
86                 add_td(tr, black);
87                 add_td(tr, (100.0 * black / num).toFixed(1) + "%");
88
89                 // Draw and %Draw.
90                 add_td(tr, draw);
91                 add_td(tr, ((100.0 * draw / num).toFixed(1) + "%"));
92
93                 if (move['num_elo'] >= 10) {
94                         // Elo.
95                         add_td(tr, move['white_avg_elo'].toFixed(1));
96                         add_td(tr, move['black_avg_elo'].toFixed(1));
97                         add_td(tr, (move['white_avg_elo'] - move['black_avg_elo']).toFixed(1));
98
99                         // Win% corrected for Elo.
100                         var win_elo = -400.0 * Math.log(1.0 / white_win_ratio - 1.0) / Math.LN10;
101                         win_elo -= (move['white_avg_elo'] - move['black_avg_elo']);
102                         white_win_ratio = 1.0 / (1.0 + Math.pow(10, win_elo / -400.0));
103                         win_ratio = (game.turn() == 'w') ? white_win_ratio : 1.0 - white_win_ratio;
104                         add_td(tr, ((100.0 * win_ratio).toFixed(1) + "%"));
105                 } else {
106                         add_td(tr, "");
107                         add_td(tr, "");
108                         add_td(tr, "");
109                         add_td(tr, "");
110                 }
111
112                 if (false) {
113                         // Win bars (W/D/B).
114                         var winbar_td = document.createElement("td");
115                         $(winbar_td).addClass("winbars");
116                         tr.appendChild(winbar_td);
117                         var winbar_table = document.createElement("table");
118                         winbar_td.appendChild(winbar_table);
119                         var winbar_tr = document.createElement("tr");
120                         winbar_table.appendChild(winbar_tr);
121
122                         if (white > 0) {
123                                 var white_percent = (100.0 * white / num).toFixed(0) + "%";
124                                 var white_td = document.createElement("td");
125                                 winbar_tr.appendChild(white_td);
126                                 $(white_td).addClass("white");
127                                 white_td.style.width = white_percent;
128                                 $(white_td).text(white_percent);
129                         }
130                         if (draw > 0) {
131                                 var draw_percent = (100.0 * draw / num).toFixed(0) + "%";
132                                 var draw_td = document.createElement("td");
133                                 winbar_tr.appendChild(draw_td);
134                                 $(draw_td).addClass("draw");
135                                 draw_td.style.width = draw_percent;
136                                 $(draw_td).text(draw_percent);
137                         }
138                         if (black > 0) {
139                                 var black_percent = (100.0 * black / num).toFixed(0) + "%";
140                                 var black_td = document.createElement("td");
141                                 winbar_tr.appendChild(black_td);
142                                 $(black_td).addClass("black");
143                                 black_td.style.width = black_percent;
144                                 $(black_td).text(black_percent);
145                         }
146                 }
147
148                 tbl.append(tr);
149         }
150 }
151
152 var make_move = function(move) {
153         moves.length = move_override;
154         moves.push(move);
155         move_override = moves.length;
156         update();
157 }
158 window['make_move'] = make_move;
159
160 var prev_move = function() {
161         if (move_override > 0) {
162                 --move_override;
163                 update();
164         }
165 }
166 window['prev_move'] = prev_move;
167
168 var next_move = function() {
169         if (move_override < moves.length) {
170                 ++move_override;
171                 update();
172         }
173 }
174 window['next_move'] = next_move;
175
176 // almost all of this stuff comes from the chessboard.js example page
177 var onDragStart = function(source, piece, position, orientation) {
178         var game = get_game();
179         if (game.game_over() === true ||
180             (game.turn() === 'w' && piece.search(/^b/) !== -1) ||
181             (game.turn() === 'b' && piece.search(/^w/) !== -1)) {
182                 return false;
183         }
184 }
185
186 var onDrop = function(source, target) {
187         // see if the move is legal
188         var game = get_game();
189         var move = game.move({
190                 from: source,
191                 to: target,
192                 promotion: 'q' // NOTE: always promote to a queen for example simplicity
193         });
194
195         // illegal move
196         if (move === null) return 'snapback';
197
198         moves = game.history({ verbose: true });
199         move_override = moves.length;
200 };
201
202 // update the board position after the piece snap 
203 // for castling, en passant, pawn promotion
204 var onSnapEnd = function() {
205         var game = get_game();
206         board.position(game.fen());
207         fetch_analysis();
208 };
209
210 var init = function() {
211         // Create board.
212         board = new window.ChessBoard('board', {
213                 draggable: true,
214                 position: 'start',
215                 onDragStart: onDragStart,
216                 onDrop: onDrop,
217                 onSnapEnd: onSnapEnd
218         });
219         update();
220
221         $(window).keyup(function(event) {
222                 if (event.which == 39) {
223                         next_move();
224                 } else if (event.which == 37) {
225                         prev_move();
226                 }
227         });
228 }
229
230
231 $(document).ready(init);
232
233 })();