1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.vectomatic.svg.chess;
19
20 import org.vectomatic.dom.svg.OMSVGSVGElement;
21 import org.vectomatic.dom.svg.utils.OMSVGParser;
22
23 import com.alonsoruibal.chess.Board;
24 import com.alonsoruibal.chess.Config;
25 import com.alonsoruibal.chess.Move;
26 import com.alonsoruibal.chess.search.SearchEngine;
27 import com.alonsoruibal.chess.search.SearchObserver;
28 import com.alonsoruibal.chess.search.SearchParameters;
29 import com.alonsoruibal.chess.search.SearchStatusInfo;
30 import com.google.gwt.core.client.EntryPoint;
31 import com.google.gwt.core.client.GWT;
32 import com.google.gwt.core.client.Scheduler;
33 import com.google.gwt.core.client.Scheduler.ScheduledCommand;
34 import com.google.gwt.dom.client.StyleInjector;
35 import com.google.gwt.event.dom.client.ChangeEvent;
36 import com.google.gwt.event.dom.client.ClickEvent;
37 import com.google.gwt.uibinder.client.UiBinder;
38 import com.google.gwt.uibinder.client.UiFactory;
39 import com.google.gwt.uibinder.client.UiField;
40 import com.google.gwt.uibinder.client.UiHandler;
41 import com.google.gwt.user.client.Element;
42 import com.google.gwt.user.client.Window;
43 import com.google.gwt.user.client.ui.Button;
44 import com.google.gwt.user.client.ui.DecoratedPopupPanel;
45 import com.google.gwt.user.client.ui.DialogBox;
46 import com.google.gwt.user.client.ui.DisclosurePanel;
47 import com.google.gwt.user.client.ui.HTML;
48 import com.google.gwt.user.client.ui.HorizontalPanel;
49 import com.google.gwt.user.client.ui.Image;
50 import com.google.gwt.user.client.ui.Label;
51 import com.google.gwt.user.client.ui.ListBox;
52 import com.google.gwt.user.client.ui.RootLayoutPanel;
53 import com.google.gwt.user.client.ui.SplitLayoutPanel;
54 import com.google.gwt.user.client.ui.TextArea;
55 import com.google.gwt.widgetideas.client.HSliderBar;
56 import com.google.gwt.widgetideas.client.SliderBar;
57 import com.google.gwt.widgetideas.client.SliderBar.LabelFormatter;
58 import com.google.gwt.widgetideas.client.SliderListenerAdapter;
59
60
61
62
63 public class Main implements EntryPoint, SearchObserver {
64 interface MainBinder extends UiBinder<SplitLayoutPanel, Main> {
65 }
66 private static MainBinder mainBinder = GWT.create(MainBinder.class);
67
68 @UiField(provided=true)
69 ChessConstants constants = ChessConstants.INSTANCE;
70 @UiField(provided=true)
71 ChessCss style = Resources.INSTANCE.getCss();
72
73 @UiField
74 HTML boardContainer;
75 @UiField
76 Button restartButton;
77 @UiField
78 Button fenButton;
79 @UiField
80 Button undoButton;
81 @UiField
82 Button redoButton;
83
84 @UiField
85 DisclosurePanel advancedPanel;
86
87 @UiField
88 Label modeLabel;
89 @UiField
90 Label reflectionLabel;
91 @UiField
92 Label fenLabel;
93 @UiField
94 Label currentPlayerLabel;
95 @UiField
96 Label historyLabel;
97
98 @UiField
99 ListBox modeListBox;
100 @UiField
101 HSliderBar reflectionSlider;
102 @UiField
103 TextArea fenArea;
104 @UiField
105 TextArea historyArea;
106 @UiField
107 Label currentPlayerValueLabel;
108 @UiField
109 HTML about;
110
111 DialogBox confirmBox;
112
113
114
115
116 SearchEngine engine;
117
118
119
120 Board board;
121
122
123
124 ChessBoard chessboard;
125
126
127
128 private Element boardDiv;
129
130
131
132 private OMSVGSVGElement boardElt;
133
134
135
136 private int[] moveTimes = new int[] {3000, 10000, 30000, 60000, 180000, 600000};
137
138
139
140 private int moveTimeIndex;
141
142
143
144 private HistoryManager historyManager;
145
146
147
148 int lastMoveNumber;
149
150
151
152 int firstMoveNumber;
153
154
155
156
157
158 @UiFactory
159 HSliderBar makeHSliderBar() {
160 final String[] labels = {
161 ChessConstants.INSTANCE.mt3s(),
162 ChessConstants.INSTANCE.mt10s(),
163 ChessConstants.INSTANCE.mt30s(),
164 ChessConstants.INSTANCE.mt1m(),
165 ChessConstants.INSTANCE.mt3m(),
166 ChessConstants.INSTANCE.mt10m()
167 };
168 HSliderBar sliderBar = new HSliderBar(0, 5, new LabelFormatter() {
169 protected String formatLabel(SliderBar slider, double value) {
170 return labels[(int)value];
171 }
172 });
173 sliderBar.setStepSize(1);
174 sliderBar.setNumTicks(5);
175 sliderBar.setNumLabels(5);
176 sliderBar.setCurrentValue(0);
177 sliderBar.addSliderListener(new SliderListenerAdapter() {
178 @Override
179 public void onValueChanged(SliderBar slider, double curValue) {
180 moveTimeIndex = (int)curValue;
181 }
182 });
183 return sliderBar;
184 }
185
186 public int getHeight() {
187 return (Window.getClientHeight() - 150);
188 }
189
190
191
192
193
194 public void onModuleLoad() {
195 final DecoratedPopupPanel initBox = new DecoratedPopupPanel();
196 HorizontalPanel hpanel = new HorizontalPanel();
197 hpanel.add(new Image(Resources.INSTANCE.getWaitImage()));
198 hpanel.add(new Label(ChessConstants.INSTANCE.waitMessage()));
199 initBox.add(hpanel);
200 initBox.center();
201 initBox.show();
202 Scheduler.get().scheduleDeferred(new ScheduledCommand() {
203 @Override
204 public void execute() {
205
206 StyleInjector.inject(Resources.INSTANCE.getCss().getText());
207
208
209 Config config = new Config();
210 config.setTranspositionTableSize(2);
211 config.setBook(new JSONBook());
212 engine = new SearchEngine(config);
213 engine.setObserver(Main.this);
214 board = engine.getBoard();
215
216
217 SplitLayoutPanel binderPanel = mainBinder.createAndBindUi(Main.this);
218 confirmBox = ConfirmBox.createConfirmBox(Main.this);
219 advancedPanel.getHeaderTextAccessor().setText(constants.advanced());
220
221 modeListBox.addItem(ChessMode.whitesVsComputer.getDescription(), ChessMode.whitesVsComputer.name());
222 modeListBox.addItem(ChessMode.blacksVsComputer.getDescription(), ChessMode.blacksVsComputer.name());
223 modeListBox.addItem(ChessMode.whitesVsBlacks.getDescription(), ChessMode.whitesVsBlacks.name());
224 modeListBox.addItem(ChessMode.computerVsComputer.getDescription(), ChessMode.computerVsComputer.name());
225 modeListBox.setSelectedIndex(0);
226
227 about.setHTML(ChessConstants.INSTANCE.about());
228 RootLayoutPanel.get().add(binderPanel);
229
230
231
232 boardDiv = boardContainer.getElement();
233 boardElt = OMSVGParser.parse(Resources.INSTANCE.getBoard().getText());
234 boardDiv.appendChild(boardElt.getElement());
235
236
237
238 chessboard = new ChessBoard(board, boardElt, Main.this);
239
240
241 historyManager = GWT.create(HistoryManager.class);
242 historyManager.initialize(Main.this);
243
244 moveTimeIndex = 0;
245 restart();
246 initBox.hide();
247 }
248 });
249 }
250
251
252
253
254 private void updateUI() {
255 StringBuffer buffer = new StringBuffer();
256 int count = board.getMoveNumber();
257 for (int i = firstMoveNumber; i < count; i++) {
258 String move = board.getSanMove(i);
259 assert move != null;
260 if (i > 0) {
261 buffer.append("\n");
262 }
263 buffer.append((i + 1) + ". " + move);
264 }
265 historyArea.setVisibleLines(count == 0 ? 1 : count);
266 historyArea.setText(buffer.toString());
267 fenArea.setText(board.getFen());
268 currentPlayerValueLabel.setText(board.getTurn() ? ChessConstants.INSTANCE.white() : ChessConstants.INSTANCE.black());
269 int moveNumber = board.getMoveNumber();
270
271 int firstPossibleMove = firstMoveNumber;
272 int lastPossibleMove = lastMoveNumber;
273 switch(getMode()) {
274 case whitesVsBlacks:
275 break;
276 case whitesVsComputer:
277 if (firstMoveNumber % 2 == 1) {
278 firstPossibleMove++;
279 }
280 if (lastPossibleMove % 2 == 1) {
281 lastPossibleMove--;
282 }
283 break;
284 case blacksVsComputer:
285 if (firstMoveNumber % 2 == 0) {
286 firstPossibleMove++;
287 }
288 if (lastPossibleMove % 2 == 0) {
289 lastPossibleMove--;
290 }
291 break;
292 case computerVsComputer:
293 firstPossibleMove = Integer.MAX_VALUE;
294 lastPossibleMove = Integer.MIN_VALUE;
295 break;
296 }
297 undoButton.setEnabled(moveNumber > firstPossibleMove);
298 redoButton.setEnabled(moveNumber < lastPossibleMove);
299 }
300 ChessMode getMode() {
301 return ChessMode.valueOf(modeListBox.getValue(modeListBox.getSelectedIndex()));
302 }
303
304
305
306
307 public void nextMove() {
308 updateUI();
309 switch (board.isEndGame()) {
310 case 1 :
311 Window.alert(ChessConstants.INSTANCE.whitesWin());
312 restart();
313 break;
314 case -1:
315 Window.alert(ChessConstants.INSTANCE.blacksWin());
316 restart();
317 break;
318 case 99:
319 Window.alert(ChessConstants.INSTANCE.draw());
320 restart();
321 break;
322 default:
323 switch(getMode()) {
324 case whitesVsBlacks:
325 break;
326 case whitesVsComputer:
327 if (!board.getTurn()) {
328 computerMove();
329 }
330 break;
331 case blacksVsComputer:
332 if (board.getTurn()) {
333 computerMove();
334 }
335 break;
336 case computerVsComputer:
337 computerMove();
338 break;
339 }
340 break;
341 }
342
343 }
344
345
346
347
348 private void computerMove() {
349 Scheduler.get().scheduleDeferred(new ScheduledCommand() {
350 @Override
351 public void execute() {
352 engine.go(SearchParameters.get(moveTimes[moveTimeIndex]));
353 }
354
355 });
356 }
357
358
359
360
361 public void bestMove(int bestMove, int ponder) {
362 GWT.log("Main.bestMove(" + Move.toStringExt(bestMove) + ", " + Move.toStringExt(ponder) + ")", null);
363 board.doMove(bestMove);
364 addMove();
365 chessboard.update(false);
366 nextMove();
367 }
368
369
370
371
372 public void info(SearchStatusInfo info) {
373 GWT.log("Main.info(" + info + ")", null);
374 }
375
376
377
378
379 public void restart() {
380 chessboard.update(true);
381 lastMoveNumber = 0;
382 historyManager.setMove(0);
383 board.startPosition();
384 firstMoveNumber = board.getMoveNumber();
385 chessboard.update(true);
386 nextMove();
387 }
388
389 @UiHandler("fenButton")
390 public void updateFen(ClickEvent event) {
391 GWT.log("Main.updateFen(" + fenArea.getText() + ")", null);
392 historyManager.setMove(0);
393 board.setFen(fenArea.getText());
394 lastMoveNumber = firstMoveNumber = board.getMoveNumber();
395 chessboard.update(true);
396 nextMove();
397 }
398
399 @UiHandler("modeListBox")
400 public void modeChange(ChangeEvent event) {
401 GWT.log("Main.modeChange(" + modeListBox.getSelectedIndex() + ")", null);
402 nextMove();
403 }
404
405 @UiHandler("restartButton")
406 public void confirmRestart(ClickEvent event) {
407 GWT.log("Main.confirmRestart()", null);
408 confirmBox.center();
409 confirmBox.show();
410 }
411
412 @UiHandler("undoButton")
413 public void undo(ClickEvent event) {
414 GWT.log("Main.undo()", null);
415 int moveNumber = board.getMoveNumber();
416 switch(getMode()) {
417 case whitesVsBlacks:
418 setMove(moveNumber - 1);
419 break;
420 case whitesVsComputer:
421 case blacksVsComputer:
422 setMove(moveNumber - 2);
423 break;
424 case computerVsComputer:
425 break;
426 }
427 nextMove();
428 }
429
430 @UiHandler("redoButton")
431 public void redo(ClickEvent event) {
432 GWT.log("Main.redo()", null);
433 int moveNumber = board.getMoveNumber();
434 switch(getMode()) {
435 case whitesVsBlacks:
436 setMove(moveNumber + 1);
437 break;
438 case whitesVsComputer:
439 case blacksVsComputer:
440 setMove(moveNumber + 2);
441 break;
442 case computerVsComputer:
443 break;
444 }
445 nextMove();
446 }
447
448
449
450
451 public void addMove() {
452 historyManager.addMove();
453 lastMoveNumber = board.getMoveNumber();
454 }
455
456 private void setMove(int moveNumber) {
457 historyManager.setMove(moveNumber);
458 board.undoMove(moveNumber);
459 chessboard.update(true);
460 }
461 }