summaryrefslogtreecommitdiff
path: root/apps/plugins/goban/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/goban/util.c')
-rw-r--r--apps/plugins/goban/util.c885
1 files changed, 885 insertions, 0 deletions
diff --git a/apps/plugins/goban/util.c b/apps/plugins/goban/util.c
new file mode 100644
index 0000000000..e9966311ef
--- /dev/null
+++ b/apps/plugins/goban/util.c
@@ -0,0 +1,885 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2007-2009 Joshua Simmons <mud at majidejima dot com>
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "util.h"
23#include "game.h"
24
25
26void metadata_summary (void)
27{
28 char buffer[256] = "";
29
30 if (rb->strlen (header.black) ||
31 rb->strlen (header.white) ||
32 rb->strlen (header.black_rank) ||
33 rb->strlen (header.white_rank))
34 rb->snprintf (buffer, sizeof(buffer),
35 "%s [%s] v. %s [%s] ",
36 header.black, header.black_rank,
37 header.white, header.white_rank);
38
39 if (header.handicap > 1)
40 {
41 rb->snprintf (buffer + rb->strlen(buffer),
42 sizeof (buffer) - rb->strlen (buffer),
43 "%d stones ", header.handicap);
44 }
45
46 if (header.komi != 0 && !(header.komi == 1 && header.handicap > 1))
47 {
48 snprint_fixed (buffer + rb->strlen(buffer),
49 sizeof (buffer) - rb->strlen (buffer),
50 header.komi);
51 rb->snprintf (buffer + rb->strlen(buffer),
52 sizeof (buffer) - rb->strlen (buffer),
53 " komi ");
54 }
55
56 if (rb->strlen(header.result))
57 {
58 rb->snprintf (buffer + rb->strlen(buffer),
59 sizeof (buffer) - rb->strlen (buffer),
60 "(%s)", header.result);
61 }
62
63 /* waiting for user input messes up the testing code, so ifdef it*/
64#if !defined(GBN_TEST)
65 if (rb->strlen(buffer))
66 {
67 rb->splash(0, buffer);
68 rb->action_userabort(TIMEOUT_BLOCK);
69 }
70#endif
71}
72
73void *
74align_buffer (void *buffer, size_t * buffer_size)
75{
76 unsigned int wasted = (-(long) buffer) & 3;
77
78 if (!buffer || !buffer_size)
79 {
80 return NULL;
81 }
82
83 if (*buffer_size <= wasted)
84 {
85 *buffer_size = 0;
86 return NULL;
87 }
88
89 *buffer_size -= wasted;
90
91 return (void *) (((char *) buffer) + wasted);
92}
93
94
95
96bool
97setup_stack (struct stack_t *stack, void *buffer, size_t buffer_size)
98{
99 if (!stack || !buffer || !buffer_size)
100 {
101 DEBUGF ("INVALID STACK SETUP!!\n");
102 return false;
103 }
104
105 buffer = align_buffer (buffer, &buffer_size);
106
107 if (!buffer || !buffer_size)
108 {
109 DEBUGF ("Buffer disappeared after alignment!\n");
110 return false;
111 }
112
113 stack->buffer = buffer;
114 stack->size = buffer_size;
115 stack->sp = 0;
116
117 return true;
118}
119
120bool
121push_stack (struct stack_t * stack, void *buffer, size_t buffer_size)
122{
123 if (stack->sp + buffer_size > stack->size)
124 {
125 DEBUGF ("stack full!!\n");
126 return false;
127 }
128
129 rb->memcpy (&stack->buffer[stack->sp], buffer, buffer_size);
130
131 stack->sp += buffer_size;
132
133 return true;
134}
135
136bool
137pop_stack (struct stack_t * stack, void *buffer, size_t buffer_size)
138{
139 if (!peek_stack (stack, buffer, buffer_size))
140 {
141 return false;
142 }
143
144 stack->sp -= buffer_size;
145
146 return true;
147}
148
149bool
150peek_stack (struct stack_t * stack, void *buffer, size_t buffer_size)
151{
152 if (stack->sp < buffer_size)
153 {
154 return false;
155 }
156
157 rb->memcpy (buffer, &stack->buffer[stack->sp - buffer_size], buffer_size);
158
159 return true;
160}
161
162void
163empty_stack (struct stack_t *stack)
164{
165 stack->sp = 0;
166}
167
168bool
169push_pos_stack (struct stack_t *stack, unsigned short pos)
170{
171 return push_stack (stack, &pos, sizeof (pos));
172}
173
174bool
175push_int_stack (struct stack_t *stack, int num)
176{
177 return push_stack (stack, &num, sizeof (num));
178}
179
180bool
181push_char_stack (struct stack_t *stack, char num)
182{
183 return push_stack (stack, &num, sizeof (num));
184}
185
186
187
188/* IMPORTANT: keep in sync with the enum prop_type_t enum in types.h */
189char *prop_names[] = {
190 /* look up the SGF specification for the meaning of these */
191 "B", "W",
192 "AB", "AW", "AE",
193
194 "PL", "C",
195
196 "DM", "GB", "GW", "HO", "UC", "V",
197
198 "BM", "DO", "IT", "TE",
199
200 "CR", "SQ", "TR", "DD", "MA", "SL", "LB", "N",
201
202 "AP", "CA", "FF", "GM", "ST", "SZ",
203
204 "AN", "PB", "PW", "HA", "KM", "TB", "TW", "BR", "WR",
205 "BT", "WT", "CP", "DT", "EV", "RO", "GN", "GC", "ON",
206 "OT", "PC", "RE", "RU", "SO", "TM", "US",
207
208 "BL", "WL", "OB", "OW", "FG", "PM", "VW"
209};
210
211/* These seems to be specified by the SGF specification. You can do free
212 form ones as well, but I haven't implemented that (and don't plan to) */
213char *ruleset_names[] = { "AGA", "Japanese", "Chinese", "NZ", "GOE" };
214
215
216
217int
218create_or_open_file (const char *filename)
219{
220 int fd;
221
222 if (!rb->file_exists (filename))
223 {
224 fd = rb->creat (filename);
225 }
226 else
227 {
228 fd = rb->open (filename, O_RDWR);
229 }
230
231 return fd;
232}
233
234
235int
236snprint_fixed (char *buffer, int buffer_size, int fixed)
237{
238 return rb->snprintf (buffer, buffer_size, "%s%d.%d",
239 fixed < 0 ? "-" : "",
240 abs (fixed) >> 1, 5 * (fixed & 1));
241}
242
243
244int
245peek_char (int fd)
246{
247 char peeked_char;
248
249 int result = rb->read (fd, &peeked_char, 1);
250
251 if (result != 1)
252 {
253 return -1;
254 }
255
256 result = rb->lseek (fd, -1, SEEK_CUR);
257
258 if (result < 0)
259 {
260 return -1;
261 }
262
263 return peeked_char;
264}
265
266
267int
268read_char (int fd)
269{
270 char read_char;
271
272 int result = rb->read (fd, &read_char, 1);
273
274 if (result != 1)
275 {
276 return -1;
277 }
278
279 return read_char;
280}
281
282
283bool
284write_char (int fd, char to_write)
285{
286 int result = write_file (fd, &to_write, 1);
287
288 if (result != 1)
289 {
290 return false;
291 }
292
293 return true;
294}
295
296ssize_t
297write_file (int fd, const void *buf, size_t count)
298{
299 const char *buffer = buf;
300 int result;
301 int ret_val = count;
302
303 while (count)
304 {
305 result = rb->write (fd, buffer, count);
306
307 if (result < 0)
308 {
309 return -1;
310 }
311
312 count -= result;
313 buffer += result;
314 }
315
316 return ret_val;
317}
318
319ssize_t
320read_file (int fd, void *buf, size_t count)
321{
322 char *buffer = buf;
323 int result;
324 int ret_val = count;
325
326 while (count)
327 {
328 result = rb->read (fd, buffer, count);
329
330 if (result <= 0)
331 {
332 return -1;
333 }
334
335 count -= result;
336 buffer += result;
337 }
338
339 return ret_val;
340}
341
342int
343read_char_no_whitespace (int fd)
344{
345 int result = peek_char_no_whitespace (fd);
346
347 read_char (fd);
348
349 return result;
350}
351
352int
353peek_char_no_whitespace (int fd)
354{
355 int result;
356
357 while (is_whitespace (result = peek_char (fd)))
358 {
359 read_char (fd);
360 }
361
362 return result;
363}
364
365
366void
367close_file (int *fd)
368{
369 if (*fd >= 0)
370 {
371 rb->close (*fd);
372 }
373
374 *fd = -1;
375}
376
377bool
378is_whitespace (int value)
379{
380 if (value == ' ' ||
381 value == '\t' ||
382 value == '\n' || value == '\r' || value == '\f' || value == '\v')
383 {
384 return true;
385 }
386 else
387 {
388 return false;
389 }
390}
391
392void
393sanitize_string (char *string)
394{
395 bool escaped = false;
396
397 if (!string)
398 {
399 return;
400 }
401
402 while (1)
403 {
404 switch (*string)
405 {
406 case '\0':
407 return;
408 case '\\':
409 escaped = !escaped;
410 break;
411 case ']':
412 if (!escaped)
413 {
414 *string = ']';
415 }
416 escaped = false;
417 break;
418 default:
419 break;
420 };
421 ++string;
422 }
423}
424
425
426bool
427get_header_string_and_size (struct header_t *header,
428 enum prop_type_t type, char **buffer, int *size)
429{
430 if (buffer == 0 || header == 0)
431 {
432 return false;
433 }
434
435 if (type == PROP_BLACK_NAME)
436 {
437 *buffer = header->black;
438 *size = MAX_NAME;
439 }
440 else if (type == PROP_WHITE_NAME)
441 {
442 *buffer = header->white;
443 *size = MAX_NAME;
444 }
445 else if (type == PROP_BLACK_RANK)
446 {
447 *buffer = header->black_rank;
448 *size = MAX_RANK;
449 }
450 else if (type == PROP_WHITE_RANK)
451 {
452 *buffer = header->white_rank;
453 *size = MAX_RANK;
454 }
455 else if (type == PROP_BLACK_TEAM)
456 {
457 *buffer = header->black_team;
458 *size = MAX_TEAM;
459 }
460 else if (type == PROP_WHITE_TEAM)
461 {
462 *buffer = header->white_team;
463 *size = MAX_TEAM;
464 }
465 else if (type == PROP_DATE)
466 {
467 *buffer = header->date;
468 *size = MAX_DATE;
469 }
470 else if (type == PROP_ROUND)
471 {
472 *buffer = header->round;
473 *size = MAX_ROUND;
474 }
475 else if (type == PROP_EVENT)
476 {
477 *buffer = header->event;
478 *size = MAX_EVENT;
479 }
480 else if (type == PROP_PLACE)
481 {
482 *buffer = header->place;
483 *size = MAX_PLACE;
484 }
485 else if (type == PROP_OVERTIME)
486 {
487 *buffer = header->overtime;
488 *size = MAX_OVERTIME;
489 }
490 else if (type == PROP_RESULT)
491 {
492 *buffer = header->result;
493 *size = MAX_RESULT;
494 }
495 else if (type == PROP_RULESET)
496 {
497 *buffer = header->ruleset;
498 *size = MAX_RULESET;
499 }
500 else
501 {
502 return false;
503 }
504
505 return true;
506}
507
508
509/* TEST CODE BEGINS HERE define GBN_TEST to run this, either in goban.h or
510 in the CFLAGS. The tests will be run when the plugin starts, after
511 which the plugin will exit. Any error stops testing since many tests
512 depend on previous setup. Note: The testing can take a while as there
513 are some big loops. Be patient. */
514
515#ifdef GBN_TEST
516
517#include "goban.h"
518#include "types.h"
519#include "board.h"
520#include "game.h"
521#include "sgf.h"
522#include "sgf_storage.h"
523
524/* If this isn't on a single line, the line numbers it reports will be wrong.
525 *
526 * I'm sure there's a way to make it better, but it's not really worth it.
527 */
528#define gbn_assert(test) if (test) {DEBUGF("%d passed\n", __LINE__);} else {DEBUGF("%d FAILED!\n", __LINE__); rb->splashf(10 * HZ, "Test on line %d of util.c failed!", __LINE__); return;}
529
530void
531run_tests (void)
532{
533 rb->splash (3 * HZ, "Running tests. Failures will stop testing.");
534
535
536
537 /* allocating and freeing storage units */
538
539 gbn_assert (alloc_storage_sgf ());
540
541 int prevent_infinite = 100000000;
542
543 int count = 1;
544 while (alloc_storage_sgf () >= 0 && --prevent_infinite)
545 {
546 ++count;
547 }
548
549 gbn_assert (prevent_infinite);
550 gbn_assert (count > 100);
551
552 /* make sure it fails a few times */
553 gbn_assert (alloc_storage_sgf () < 0);
554 gbn_assert (alloc_storage_sgf () < 0);
555 gbn_assert (alloc_storage_sgf () < 0);
556
557 free_storage_sgf (0);
558
559 gbn_assert (alloc_storage_sgf () == 0);
560
561 gbn_assert (alloc_storage_sgf () < 0);
562
563 int i;
564 for (i = 0; i <= count; ++i)
565 {
566 free_storage_sgf (i);
567 }
568
569 gbn_assert (alloc_storage_sgf () >= 0);
570 --count;
571
572 for (i = 0; i < count; ++i)
573 {
574 gbn_assert (alloc_storage_sgf () >= 0);
575 }
576
577 free_tree_sgf ();
578
579
580
581 /* setting up, saving and loading */
582 gbn_assert (setup_game (MAX_BOARD_SIZE, MAX_BOARD_SIZE, 0, 15));
583 gbn_assert (setup_game (MAX_BOARD_SIZE, MAX_BOARD_SIZE, 0, -30));
584 gbn_assert (setup_game (MAX_BOARD_SIZE, MAX_BOARD_SIZE, 4, 1));
585 gbn_assert (setup_game (MIN_BOARD_SIZE, MIN_BOARD_SIZE, 1, 1));
586
587 gbn_assert (setup_game (MIN_BOARD_SIZE, MAX_BOARD_SIZE, 1, 1));
588 gbn_assert (setup_game (MAX_BOARD_SIZE, MIN_BOARD_SIZE, 1, 1));
589
590 gbn_assert (!setup_game (MAX_BOARD_SIZE + 1, MAX_BOARD_SIZE + 1, 0, 15));
591 gbn_assert (!setup_game (MIN_BOARD_SIZE - 1, MIN_BOARD_SIZE - 1, 0, 15));
592 gbn_assert (!setup_game (MAX_BOARD_SIZE, MAX_BOARD_SIZE, -1, 15));
593
594 gbn_assert (setup_game (MAX_BOARD_SIZE, MAX_BOARD_SIZE, 1, 1));
595 gbn_assert (save_game (DEFAULT_SAVE_DIR "/t1.sgf"));
596 gbn_assert (load_game (DEFAULT_SAVE_DIR "/t1.sgf"));
597 gbn_assert (save_game (DEFAULT_SAVE_DIR "/t2.sgf"));
598 gbn_assert (load_game (DEFAULT_SAVE_DIR "/t2.sgf"));
599
600 gbn_assert (!save_game ("/DIR_DOESNT_EXIST/blah.sgf"));
601 gbn_assert (!load_game ("/DIR_DOESNT_EXIST/blah.sgf"));
602 gbn_assert (!load_game (DEFAULT_SAVE_DIR "/DOESNT_EXIST.sgf"));
603
604
605
606 /* test of a long game, captures, illegal moves */
607 gbn_assert (load_game (DEFAULT_SAVE_DIR "/long.sgf"));
608 while (move_num < 520)
609 {
610 gbn_assert (num_variations_sgf () == 1);
611 gbn_assert (redo_node_sgf ());
612 }
613
614 gbn_assert (play_move_sgf (POS (2, 0), BLACK));
615 gbn_assert (play_move_sgf (POS (2, 1), WHITE));
616
617 gbn_assert (move_num == 522);
618
619 gbn_assert (white_captures == 261 && black_captures == 0);
620
621 gbn_assert (play_move_sgf (PASS_POS, BLACK));
622 gbn_assert (play_move_sgf (PASS_POS, WHITE));
623
624 gbn_assert (move_num == 524);
625
626 int x, y;
627 int b_count, w_count, e_count;
628 b_count = w_count = e_count = 0;
629 for (x = 0; x < 19; ++x)
630 {
631 for (y = 0; y < 19; ++y)
632 {
633 gbn_assert (!legal_move_board (POS (x, y), BLACK, false));
634 gbn_assert (!play_move_sgf (POS (x, y), BLACK));
635 switch (get_point_board (POS (x, y)))
636 {
637 case BLACK:
638 ++b_count;
639 break;
640 case WHITE:
641 ++w_count;
642 break;
643 case EMPTY:
644 ++e_count;
645 break;
646 default:
647 gbn_assert (false);
648 }
649 }
650 }
651
652 gbn_assert (b_count == 0 && w_count == 261 && e_count == 19 * 19 - 261);
653
654 gbn_assert (undo_node_sgf ());
655 gbn_assert (move_num == 523);
656
657 int infinite_prevention = 0;
658 while (move_num > 0)
659 {
660 gbn_assert (undo_node_sgf ());
661
662 ++infinite_prevention;
663 gbn_assert (infinite_prevention < 100000);
664 }
665
666 gbn_assert (save_game (DEFAULT_SAVE_DIR "/long_out.sgf"));
667
668
669 /* test of basic moves, legal moves, adding and removing stones */
670 gbn_assert (setup_game (MAX_BOARD_SIZE, MAX_BOARD_SIZE, 0, 0));
671 gbn_assert (play_move_sgf
672 (POS (MAX_BOARD_SIZE / 2, MAX_BOARD_SIZE / 2), BLACK));
673 gbn_assert (move_num == 1 && current_player == WHITE);
674 gbn_assert (!legal_move_board
675 (POS (MAX_BOARD_SIZE / 2, MAX_BOARD_SIZE / 2), WHITE, true));
676
677 int saved_node = current_node;
678 gbn_assert (add_stone_sgf (POS (0, 0), BLACK));
679 gbn_assert (current_node != saved_node);
680 gbn_assert (get_point_board (POS (0, 0)) == BLACK);
681 gbn_assert (move_num == 1 && current_player == WHITE);
682
683 saved_node = current_node;
684 gbn_assert (add_stone_sgf (POS (0, 1), WHITE));
685 gbn_assert (current_node == saved_node);
686 gbn_assert (get_point_board (POS (0, 1)) == WHITE);
687
688 gbn_assert (add_stone_sgf (POS (0, 0), EMPTY));
689 gbn_assert (add_stone_sgf (POS (0, 1), EMPTY));
690 gbn_assert (get_point_board (POS (0, 0)) == EMPTY);
691 gbn_assert (get_point_board (POS (0, 1)) == EMPTY);
692
693
694 /* test captures */
695 gbn_assert (load_game (DEFAULT_SAVE_DIR "/cap.sgf"));
696 gbn_assert (play_move_sgf (POS (0, 0), BLACK));
697 gbn_assert (black_captures == 8);
698 gbn_assert (undo_node_sgf ());
699 gbn_assert (black_captures == 0);
700
701 gbn_assert (!play_move_sgf (POS (0, 0), WHITE));
702 play_mode = MODE_FORCE_PLAY;
703 gbn_assert (play_move_sgf (POS (0, 0), WHITE));
704 play_mode = MODE_PLAY;
705
706 gbn_assert (black_captures == 9);
707 gbn_assert (get_point_board (POS (0, 0)) == EMPTY);
708 gbn_assert (undo_node_sgf ());
709 gbn_assert (black_captures == 0);
710
711 gbn_assert (play_move_sgf (POS (9, 9), BLACK));
712 gbn_assert (black_captures == 44);
713
714 for (x = 0; x < 19; ++x)
715 {
716 for (y = 0; y < 19; ++y)
717 {
718 gbn_assert (get_point_board (POS (x, y)) == BLACK ||
719 add_stone_sgf (POS (x, y), BLACK));
720 }
721 }
722
723 gbn_assert (get_point_board (POS (0, 0)) == BLACK);
724 gbn_assert (add_stone_sgf (POS (9, 9), EMPTY));
725 gbn_assert (play_move_sgf (POS (9, 9), WHITE));
726 gbn_assert (white_captures == 360);
727
728 gbn_assert (undo_node_sgf ());
729 gbn_assert (white_captures == 0);
730
731 play_mode = MODE_FORCE_PLAY;
732 gbn_assert (play_move_sgf (POS (9, 9), BLACK));
733 play_mode = MODE_PLAY;
734 gbn_assert (white_captures == 361);
735
736 for (x = 0; x < 19; ++x)
737 {
738 for (y = 0; y < 19; ++y)
739 {
740 gbn_assert (get_point_board (POS (x, y)) == EMPTY);
741 }
742 }
743
744
745 /* test ko */
746 gbn_assert (setup_game (MAX_BOARD_SIZE, MAX_BOARD_SIZE, 0, 15));
747
748 /*
749 * Set up the board to look like this:
750 * -X------
751 * XO------
752 * O-------
753 * --------
754 */
755 gbn_assert (add_stone_sgf (POS (0, 1), BLACK));
756 gbn_assert (add_stone_sgf (POS (1, 0), BLACK));
757 gbn_assert (add_stone_sgf (POS (1, 1), WHITE));
758 gbn_assert (add_stone_sgf (POS (0, 2), WHITE));
759
760 /* take the ko and make sure black can't take back */
761 gbn_assert (play_move_sgf (POS (0, 0), WHITE));
762 gbn_assert (!play_move_sgf (POS (0, 1), BLACK));
763
764 /* make sure white can fill, even with the ko_pos set */
765 gbn_assert (play_move_sgf (POS (0, 1), WHITE));
766 /* and make sure undo sets the ko again */
767 gbn_assert (undo_node_sgf ());
768 gbn_assert (!play_move_sgf (POS (0, 1), BLACK));
769
770 /* make sure ko threats clear the ko */
771 gbn_assert (play_move_sgf (POS (2, 2), BLACK)); /* ko threat */
772 gbn_assert (play_move_sgf (POS (2, 3), WHITE)); /* response */
773 gbn_assert (play_move_sgf (POS (0, 1), BLACK)); /* take ko */
774
775 gbn_assert (undo_node_sgf ());
776 gbn_assert (undo_node_sgf ());
777 gbn_assert (undo_node_sgf ());
778
779 /* make sure a pass is counted as a ko threat */
780 gbn_assert (!play_move_sgf (POS (0, 1), BLACK));
781 gbn_assert (play_move_sgf (PASS_POS, BLACK));
782 gbn_assert (play_move_sgf (PASS_POS, WHITE));
783 gbn_assert (play_move_sgf (POS (0, 1), BLACK));
784
785 /* and finally let's make sure that white can't directly retake */
786 gbn_assert (!play_move_sgf (POS (0, 0), WHITE));
787
788
789
790 /* test some header information saving/loading as well as comment
791 saving loading */
792 char some_comment[] =
793 "blah blah blah i am a stupid comment. here's some annoying characters: 01234567890!@#$%^&*()[[[[\\\\\\]ABCDEFGHIJKLMNOPQRSTUVWXYZ";
794 /* that bit near the end is literally this: \\\] which tests escaping
795 of ]s */
796 char read_buffer[256];
797
798 gbn_assert (setup_game (MAX_BOARD_SIZE, MAX_BOARD_SIZE, 5, -20));
799
800 /* this also tests that ko_pos is reset by setuping up a new game */
801 gbn_assert (play_move_sgf (POS (0, 0), WHITE));
802 gbn_assert (write_comment_sgf (some_comment) > 0);
803 gbn_assert (play_move_sgf (POS (0, 1), BLACK));
804 rb->strcpy (header.black, "Jack Black");
805 rb->strcpy (header.white, "Jill White");
806
807 gbn_assert (save_game (DEFAULT_SAVE_DIR "/head.sgf"));
808
809 gbn_assert (setup_game (MIN_BOARD_SIZE, MIN_BOARD_SIZE, 1, 1));
810 gbn_assert (load_game (DEFAULT_SAVE_DIR "/head.sgf"));
811
812 gbn_assert (header.komi == -20 && header.handicap == 5);
813 gbn_assert (board_width == MAX_BOARD_SIZE
814 && board_height == MAX_BOARD_SIZE);
815 gbn_assert (rb->strcmp (header.black, "Jack Black") == 0);
816 gbn_assert (rb->strcmp (header.white, "Jill White") == 0);
817 gbn_assert (redo_node_sgf ());
818 gbn_assert (read_comment_sgf (read_buffer, sizeof (read_buffer)));
819 gbn_assert (rb->strcmp (read_buffer, some_comment) == 0);
820 gbn_assert (redo_node_sgf ());
821 gbn_assert (get_point_board (POS (0, 0)) == WHITE);
822 gbn_assert (get_point_board (POS (0, 1)) == BLACK);
823
824
825
826 /* test saving and loading a file with unhandled SGF properties. this
827 test requires that the user diff unhnd.sgf with unhnd_out.sgf (any
828 substantial difference is a bug and should be reported) the
829 following are NOT substantial differences: - reordering of
830 properties in a node - whitespace changes outside of a comment
831 value or other property value - reordering of property values */
832 gbn_assert (load_game (DEFAULT_SAVE_DIR "/unhnd.sgf"));
833 gbn_assert (save_game (DEFAULT_SAVE_DIR "/unhnd_out.sgf"));
834
835
836
837 /* Test variations a bit */
838 gbn_assert (setup_game (MAX_BOARD_SIZE, MAX_BOARD_SIZE, 0, 13));
839 /* start at a move, otherwise add_stone won't create a variation */
840 gbn_assert (play_move_sgf (POS (5, 5), BLACK));
841 /* make sure it doesn't */
842 gbn_assert (undo_node_sgf ());
843 gbn_assert (add_stone_sgf (POS (4, 5), WHITE));
844 gbn_assert (!undo_node_sgf ());
845 gbn_assert (num_variations_sgf () == 1);
846 gbn_assert (play_move_sgf (POS (5, 5), BLACK));
847
848 gbn_assert (play_move_sgf (POS (0, 0), BLACK));
849 gbn_assert (num_variations_sgf () == 1);
850 gbn_assert (undo_node_sgf ());
851 gbn_assert (play_move_sgf (POS (0, 1), BLACK));
852 gbn_assert (num_variations_sgf () == 2);
853 gbn_assert (undo_node_sgf ());
854 gbn_assert (play_move_sgf (POS (0, 1), BLACK));
855 gbn_assert (num_variations_sgf () == 2);
856 gbn_assert (undo_node_sgf ());
857 gbn_assert (play_move_sgf (POS (0, 2), BLACK));
858 gbn_assert (num_variations_sgf () == 3);
859 gbn_assert (undo_node_sgf ());
860 gbn_assert (play_move_sgf (POS (0, 3), WHITE));
861 gbn_assert (num_variations_sgf () == 4);
862 gbn_assert (undo_node_sgf ());
863 gbn_assert (play_move_sgf (PASS_POS, BLACK));
864 gbn_assert (num_variations_sgf () == 5);
865 gbn_assert (undo_node_sgf ());
866 gbn_assert (add_stone_sgf (POS (1, 1), BLACK));
867 gbn_assert (add_stone_sgf (POS (1, 2), BLACK));
868 gbn_assert (add_stone_sgf (POS (1, 3), WHITE));
869 gbn_assert (num_variations_sgf () == 6);
870 gbn_assert (undo_node_sgf ());
871 gbn_assert (add_stone_sgf (POS (1, 1), BLACK));
872 gbn_assert (add_stone_sgf (POS (1, 2), BLACK));
873 gbn_assert (add_stone_sgf (POS (1, 3), WHITE));
874 gbn_assert (num_variations_sgf () == 7);
875 gbn_assert (next_variation_sgf ());
876 gbn_assert (get_point_board (POS (0, 0)) == BLACK);
877 gbn_assert (get_point_board (POS (0, 1)) == EMPTY);
878 gbn_assert (get_point_board (POS (0, 2)) == EMPTY);
879 gbn_assert (get_point_board (POS (1, 1)) == EMPTY);
880 gbn_assert (get_point_board (POS (1, 2)) == EMPTY);
881 gbn_assert (get_point_board (POS (1, 3)) == EMPTY);
882
883 rb->splash (10 * HZ, "All tests passed. Exiting");
884}
885#endif /* GBN_TEST */