Make the formatter functions used by the settings return a pointer to avoid usless...
[kugel-rb.git] / apps / plugins / goban / util.c
blob0e83173f405c0b446ae9ee1d17393d5202e77290
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2007-2009 Joshua Simmons <mud at majidejima dot com>
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.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include "util.h"
23 #include "game.h"
26 void metadata_summary (void)
28 char buffer[256] = "";
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);
39 if (header.handicap > 1)
41 rb->snprintf (buffer + rb->strlen(buffer),
42 sizeof (buffer) - rb->strlen (buffer),
43 "%d stones ", header.handicap);
46 if (header.komi != 0 && !(header.komi == 1 && header.handicap > 1))
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 ");
56 if (rb->strlen(header.result))
58 rb->snprintf (buffer + rb->strlen(buffer),
59 sizeof (buffer) - rb->strlen (buffer),
60 "(%s)", header.result);
63 /* waiting for user input messes up the testing code, so ifdef it*/
64 #if !defined(GBN_TEST)
65 if (rb->strlen(buffer))
67 rb->splash(0, buffer);
68 rb->action_userabort(TIMEOUT_BLOCK);
70 #endif
73 void *
74 align_buffer (void *buffer, size_t * buffer_size)
76 unsigned int wasted = (-(long) buffer) & 3;
78 if (!buffer || !buffer_size)
80 return NULL;
83 if (*buffer_size <= wasted)
85 *buffer_size = 0;
86 return NULL;
89 *buffer_size -= wasted;
91 return (void *) (((char *) buffer) + wasted);
96 bool
97 setup_stack (struct stack_t *stack, void *buffer, size_t buffer_size)
99 if (!stack || !buffer || !buffer_size)
101 DEBUGF ("INVALID STACK SETUP!!\n");
102 return false;
105 buffer = align_buffer (buffer, &buffer_size);
107 if (!buffer || !buffer_size)
109 DEBUGF ("Buffer disappeared after alignment!\n");
110 return false;
113 stack->buffer = buffer;
114 stack->size = buffer_size;
115 stack->sp = 0;
117 return true;
120 bool
121 push_stack (struct stack_t * stack, void *buffer, size_t buffer_size)
123 if (stack->sp + buffer_size > stack->size)
125 DEBUGF ("stack full!!\n");
126 return false;
129 rb->memcpy (&stack->buffer[stack->sp], buffer, buffer_size);
131 stack->sp += buffer_size;
133 return true;
136 bool
137 pop_stack (struct stack_t * stack, void *buffer, size_t buffer_size)
139 if (!peek_stack (stack, buffer, buffer_size))
141 return false;
144 stack->sp -= buffer_size;
146 return true;
149 bool
150 peek_stack (struct stack_t * stack, void *buffer, size_t buffer_size)
152 if (stack->sp < buffer_size)
154 return false;
157 rb->memcpy (buffer, &stack->buffer[stack->sp - buffer_size], buffer_size);
159 return true;
162 void
163 empty_stack (struct stack_t *stack)
165 stack->sp = 0;
168 bool
169 push_pos_stack (struct stack_t *stack, unsigned short pos)
171 return push_stack (stack, &pos, sizeof (pos));
174 bool
175 push_int_stack (struct stack_t *stack, int num)
177 return push_stack (stack, &num, sizeof (num));
180 bool
181 push_char_stack (struct stack_t *stack, char num)
183 return push_stack (stack, &num, sizeof (num));
188 /* IMPORTANT: keep in sync with the enum prop_type_t enum in types.h */
189 char *prop_names[] = {
190 /* look up the SGF specification for the meaning of these */
191 "B", "W",
192 "AB", "AW", "AE",
194 "PL", "C",
196 "DM", "GB", "GW", "HO", "UC", "V",
198 "BM", "DO", "IT", "TE",
200 "CR", "SQ", "TR", "DD", "MA", "SL", "LB", "N",
202 "AP", "CA", "FF", "GM", "ST", "SZ",
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",
208 "BL", "WL", "OB", "OW", "FG", "PM", "VW"
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) */
213 const char *ruleset_names[] = { "AGA", "Japanese", "Chinese", "NZ", "GOE" };
218 create_or_open_file (const char *filename)
220 int fd;
222 if (!rb->file_exists (filename))
224 fd = rb->creat (filename);
226 else
228 fd = rb->open (filename, O_RDWR);
231 return fd;
236 snprint_fixed (char *buffer, int buffer_size, int fixed)
238 return rb->snprintf (buffer, buffer_size, "%s%d.%d",
239 fixed < 0 ? "-" : "",
240 abs (fixed) >> 1, 5 * (fixed & 1));
245 peek_char (int fd)
247 char peeked_char;
249 int result = rb->read (fd, &peeked_char, 1);
251 if (result != 1)
253 return -1;
256 result = rb->lseek (fd, -1, SEEK_CUR);
258 if (result < 0)
260 return -1;
263 return peeked_char;
268 read_char (int fd)
270 char read_char;
272 int result = rb->read (fd, &read_char, 1);
274 if (result != 1)
276 return -1;
279 return read_char;
283 bool
284 write_char (int fd, char to_write)
286 int result = write_file (fd, &to_write, 1);
288 if (result != 1)
290 return false;
293 return true;
296 ssize_t
297 write_file (int fd, const void *buf, size_t count)
299 const char *buffer = buf;
300 int result;
301 int ret_val = count;
303 while (count)
305 result = rb->write (fd, buffer, count);
307 if (result < 0)
309 return -1;
312 count -= result;
313 buffer += result;
316 return ret_val;
319 ssize_t
320 read_file (int fd, void *buf, size_t count)
322 char *buffer = buf;
323 int result;
324 int ret_val = count;
326 while (count)
328 result = rb->read (fd, buffer, count);
330 if (result <= 0)
332 return -1;
335 count -= result;
336 buffer += result;
339 return ret_val;
343 read_char_no_whitespace (int fd)
345 int result = peek_char_no_whitespace (fd);
347 read_char (fd);
349 return result;
353 peek_char_no_whitespace (int fd)
355 int result;
357 while (is_whitespace (result = peek_char (fd)))
359 read_char (fd);
362 return result;
366 void
367 close_file (int *fd)
369 if (*fd >= 0)
371 rb->close (*fd);
374 *fd = -1;
377 bool
378 is_whitespace (int value)
380 if (value == ' ' ||
381 value == '\t' ||
382 value == '\n' || value == '\r' || value == '\f' || value == '\v')
384 return true;
386 else
388 return false;
392 void
393 sanitize_string (char *string)
395 bool escaped = false;
397 if (!string)
399 return;
402 while (1)
404 switch (*string)
406 case '\0':
407 return;
408 case '\\':
409 escaped = !escaped;
410 break;
411 case ']':
412 if (!escaped)
414 *string = ']';
416 escaped = false;
417 break;
418 default:
419 break;
421 ++string;
426 bool
427 get_header_string_and_size (struct header_t *header,
428 enum prop_type_t type, char **buffer, int *size)
430 if (buffer == 0 || header == 0)
432 return false;
435 if (type == PROP_BLACK_NAME)
437 *buffer = header->black;
438 *size = MAX_NAME;
440 else if (type == PROP_WHITE_NAME)
442 *buffer = header->white;
443 *size = MAX_NAME;
445 else if (type == PROP_BLACK_RANK)
447 *buffer = header->black_rank;
448 *size = MAX_RANK;
450 else if (type == PROP_WHITE_RANK)
452 *buffer = header->white_rank;
453 *size = MAX_RANK;
455 else if (type == PROP_BLACK_TEAM)
457 *buffer = header->black_team;
458 *size = MAX_TEAM;
460 else if (type == PROP_WHITE_TEAM)
462 *buffer = header->white_team;
463 *size = MAX_TEAM;
465 else if (type == PROP_DATE)
467 *buffer = header->date;
468 *size = MAX_DATE;
470 else if (type == PROP_ROUND)
472 *buffer = header->round;
473 *size = MAX_ROUND;
475 else if (type == PROP_EVENT)
477 *buffer = header->event;
478 *size = MAX_EVENT;
480 else if (type == PROP_PLACE)
482 *buffer = header->place;
483 *size = MAX_PLACE;
485 else if (type == PROP_OVERTIME)
487 *buffer = header->overtime;
488 *size = MAX_OVERTIME;
490 else if (type == PROP_RESULT)
492 *buffer = header->result;
493 *size = MAX_RESULT;
495 else if (type == PROP_RULESET)
497 *buffer = header->ruleset;
498 *size = MAX_RULESET;
500 else
502 return false;
505 return true;
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. */
515 #ifdef GBN_TEST
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"
524 /* If this isn't on a single line, the line numbers it reports will be wrong.
526 * I'm sure there's a way to make it better, but it's not really worth it.
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;}
530 void
531 run_tests (void)
533 rb->splash (3 * HZ, "Running tests. Failures will stop testing.");
537 /* allocating and freeing storage units */
539 gbn_assert (alloc_storage_sgf ());
541 int prevent_infinite = 100000000;
543 int count = 1;
544 while (alloc_storage_sgf () >= 0 && --prevent_infinite)
546 ++count;
549 gbn_assert (prevent_infinite);
550 gbn_assert (count > 100);
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);
557 free_storage_sgf (0);
559 gbn_assert (alloc_storage_sgf () == 0);
561 gbn_assert (alloc_storage_sgf () < 0);
563 int i;
564 for (i = 0; i <= count; ++i)
566 free_storage_sgf (i);
569 gbn_assert (alloc_storage_sgf () >= 0);
570 --count;
572 for (i = 0; i < count; ++i)
574 gbn_assert (alloc_storage_sgf () >= 0);
577 free_tree_sgf ();
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));
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));
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));
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"));
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"));
606 /* test of a long game, captures, illegal moves */
607 gbn_assert (load_game (DEFAULT_SAVE_DIR "/long.sgf"));
608 while (move_num < 520)
610 gbn_assert (num_variations_sgf () == 1);
611 gbn_assert (redo_node_sgf ());
614 gbn_assert (play_move_sgf (POS (2, 0), BLACK));
615 gbn_assert (play_move_sgf (POS (2, 1), WHITE));
617 gbn_assert (move_num == 522);
619 gbn_assert (white_captures == 261 && black_captures == 0);
621 gbn_assert (play_move_sgf (PASS_POS, BLACK));
622 gbn_assert (play_move_sgf (PASS_POS, WHITE));
624 gbn_assert (move_num == 524);
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)
631 for (y = 0; y < 19; ++y)
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)))
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);
652 gbn_assert (b_count == 0 && w_count == 261 && e_count == 19 * 19 - 261);
654 gbn_assert (undo_node_sgf ());
655 gbn_assert (move_num == 523);
657 int infinite_prevention = 0;
658 while (move_num > 0)
660 gbn_assert (undo_node_sgf ());
662 ++infinite_prevention;
663 gbn_assert (infinite_prevention < 100000);
666 gbn_assert (save_game (DEFAULT_SAVE_DIR "/long_out.sgf"));
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));
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);
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);
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);
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);
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;
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);
711 gbn_assert (play_move_sgf (POS (9, 9), BLACK));
712 gbn_assert (black_captures == 44);
714 for (x = 0; x < 19; ++x)
716 for (y = 0; y < 19; ++y)
718 gbn_assert (get_point_board (POS (x, y)) == BLACK ||
719 add_stone_sgf (POS (x, y), BLACK));
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);
728 gbn_assert (undo_node_sgf ());
729 gbn_assert (white_captures == 0);
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);
736 for (x = 0; x < 19; ++x)
738 for (y = 0; y < 19; ++y)
740 gbn_assert (get_point_board (POS (x, y)) == EMPTY);
745 /* test ko */
746 gbn_assert (setup_game (MAX_BOARD_SIZE, MAX_BOARD_SIZE, 0, 15));
749 * Set up the board to look like this:
750 * -X------
751 * XO------
752 * O-------
753 * --------
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));
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));
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));
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 */
775 gbn_assert (undo_node_sgf ());
776 gbn_assert (undo_node_sgf ());
777 gbn_assert (undo_node_sgf ());
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));
785 /* and finally let's make sure that white can't directly retake */
786 gbn_assert (!play_move_sgf (POS (0, 0), WHITE));
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];
798 gbn_assert (setup_game (MAX_BOARD_SIZE, MAX_BOARD_SIZE, 5, -20));
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");
807 gbn_assert (save_game (DEFAULT_SAVE_DIR "/head.sgf"));
809 gbn_assert (setup_game (MIN_BOARD_SIZE, MIN_BOARD_SIZE, 1, 1));
810 gbn_assert (load_game (DEFAULT_SAVE_DIR "/head.sgf"));
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);
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"));
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));
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);
883 rb->splash (10 * HZ, "All tests passed. Exiting");
885 #endif /* GBN_TEST */