diff options
author | Mustapha Senhaji <moos@rockbox.org> | 2009-02-11 16:03:17 +0000 |
---|---|---|
committer | Mustapha Senhaji <moos@rockbox.org> | 2009-02-11 16:03:17 +0000 |
commit | f2d5c3532fd21c04e77aa86732742b578283b697 (patch) | |
tree | 1c55cb7e69ed11391f77187c86ff8c435ed85877 /apps/plugins/goban/util.c | |
parent | 21f0c9a2829415f52b64cbdf965b01525e78f17a (diff) |
New game plugin by Joshua Simmons FS#7369: Goban plugin, Go/Igo/Weiqi/Baduk game recorder and viewer.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@19972 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/goban/util.c')
-rw-r--r-- | apps/plugins/goban/util.c | 885 |
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 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2007-2009 Joshua Simmons <mud at majidejima dot com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "util.h" +#include "game.h" + + +void metadata_summary (void) +{ + char buffer[256] = ""; + + if (rb->strlen (header.black) || + rb->strlen (header.white) || + rb->strlen (header.black_rank) || + rb->strlen (header.white_rank)) + rb->snprintf (buffer, sizeof(buffer), + "%s [%s] v. %s [%s] ", + header.black, header.black_rank, + header.white, header.white_rank); + + if (header.handicap > 1) + { + rb->snprintf (buffer + rb->strlen(buffer), + sizeof (buffer) - rb->strlen (buffer), + "%d stones ", header.handicap); + } + + if (header.komi != 0 && !(header.komi == 1 && header.handicap > 1)) + { + snprint_fixed (buffer + rb->strlen(buffer), + sizeof (buffer) - rb->strlen (buffer), + header.komi); + rb->snprintf (buffer + rb->strlen(buffer), + sizeof (buffer) - rb->strlen (buffer), + " komi "); + } + + if (rb->strlen(header.result)) + { + rb->snprintf (buffer + rb->strlen(buffer), + sizeof (buffer) - rb->strlen (buffer), + "(%s)", header.result); + } + + /* waiting for user input messes up the testing code, so ifdef it*/ +#if !defined(GBN_TEST) + if (rb->strlen(buffer)) + { + rb->splash(0, buffer); + rb->action_userabort(TIMEOUT_BLOCK); + } +#endif +} + +void * +align_buffer (void *buffer, size_t * buffer_size) +{ + unsigned int wasted = (-(long) buffer) & 3; + + if (!buffer || !buffer_size) + { + return NULL; + } + + if (*buffer_size <= wasted) + { + *buffer_size = 0; + return NULL; + } + + *buffer_size -= wasted; + + return (void *) (((char *) buffer) + wasted); +} + + + +bool +setup_stack (struct stack_t *stack, void *buffer, size_t buffer_size) +{ + if (!stack || !buffer || !buffer_size) + { + DEBUGF ("INVALID STACK SETUP!!\n"); + return false; + } + + buffer = align_buffer (buffer, &buffer_size); + + if (!buffer || !buffer_size) + { + DEBUGF ("Buffer disappeared after alignment!\n"); + return false; + } + + stack->buffer = buffer; + stack->size = buffer_size; + stack->sp = 0; + + return true; +} + +bool +push_stack (struct stack_t * stack, void *buffer, size_t buffer_size) +{ + if (stack->sp + buffer_size > stack->size) + { + DEBUGF ("stack full!!\n"); + return false; + } + + rb->memcpy (&stack->buffer[stack->sp], buffer, buffer_size); + + stack->sp += buffer_size; + + return true; +} + +bool +pop_stack (struct stack_t * stack, void *buffer, size_t buffer_size) +{ + if (!peek_stack (stack, buffer, buffer_size)) + { + return false; + } + + stack->sp -= buffer_size; + + return true; +} + +bool +peek_stack (struct stack_t * stack, void *buffer, size_t buffer_size) +{ + if (stack->sp < buffer_size) + { + return false; + } + + rb->memcpy (buffer, &stack->buffer[stack->sp - buffer_size], buffer_size); + + return true; +} + +void +empty_stack (struct stack_t *stack) +{ + stack->sp = 0; +} + +bool +push_pos_stack (struct stack_t *stack, unsigned short pos) +{ + return push_stack (stack, &pos, sizeof (pos)); +} + +bool +push_int_stack (struct stack_t *stack, int num) +{ + return push_stack (stack, &num, sizeof (num)); +} + +bool +push_char_stack (struct stack_t *stack, char num) +{ + return push_stack (stack, &num, sizeof (num)); +} + + + +/* IMPORTANT: keep in sync with the enum prop_type_t enum in types.h */ +char *prop_names[] = { + /* look up the SGF specification for the meaning of these */ + "B", "W", + "AB", "AW", "AE", + + "PL", "C", + + "DM", "GB", "GW", "HO", "UC", "V", + + "BM", "DO", "IT", "TE", + + "CR", "SQ", "TR", "DD", "MA", "SL", "LB", "N", + + "AP", "CA", "FF", "GM", "ST", "SZ", + + "AN", "PB", "PW", "HA", "KM", "TB", "TW", "BR", "WR", + "BT", "WT", "CP", "DT", "EV", "RO", "GN", "GC", "ON", + "OT", "PC", "RE", "RU", "SO", "TM", "US", + + "BL", "WL", "OB", "OW", "FG", "PM", "VW" +}; + +/* These seems to be specified by the SGF specification. You can do free + form ones as well, but I haven't implemented that (and don't plan to) */ +char *ruleset_names[] = { "AGA", "Japanese", "Chinese", "NZ", "GOE" }; + + + +int +create_or_open_file (const char *filename) +{ + int fd; + + if (!rb->file_exists (filename)) + { + fd = rb->creat (filename); + } + else + { + fd = rb->open (filename, O_RDWR); + } + + return fd; +} + + +int +snprint_fixed (char *buffer, int buffer_size, int fixed) +{ + return rb->snprintf (buffer, buffer_size, "%s%d.%d", + fixed < 0 ? "-" : "", + abs (fixed) >> 1, 5 * (fixed & 1)); +} + + +int +peek_char (int fd) +{ + char peeked_char; + + int result = rb->read (fd, &peeked_char, 1); + + if (result != 1) + { + return -1; + } + + result = rb->lseek (fd, -1, SEEK_CUR); + + if (result < 0) + { + return -1; + } + + return peeked_char; +} + + +int +read_char (int fd) +{ + char read_char; + + int result = rb->read (fd, &read_char, 1); + + if (result != 1) + { + return -1; + } + + return read_char; +} + + +bool +write_char (int fd, char to_write) +{ + int result = write_file (fd, &to_write, 1); + + if (result != 1) + { + return false; + } + + return true; +} + +ssize_t +write_file (int fd, const void *buf, size_t count) +{ + const char *buffer = buf; + int result; + int ret_val = count; + + while (count) + { + result = rb->write (fd, buffer, count); + + if (result < 0) + { + return -1; + } + + count -= result; + buffer += result; + } + + return ret_val; +} + +ssize_t +read_file (int fd, void *buf, size_t count) +{ + char *buffer = buf; + int result; + int ret_val = count; + + while (count) + { + result = rb->read (fd, buffer, count); + + if (result <= 0) + { + return -1; + } + + count -= result; + buffer += result; + } + + return ret_val; +} + +int +read_char_no_whitespace (int fd) +{ + int result = peek_char_no_whitespace (fd); + + read_char (fd); + + return result; +} + +int +peek_char_no_whitespace (int fd) +{ + int result; + + while (is_whitespace (result = peek_char (fd))) + { + read_char (fd); + } + + return result; +} + + +void +close_file (int *fd) +{ + if (*fd >= 0) + { + rb->close (*fd); + } + + *fd = -1; +} + +bool +is_whitespace (int value) +{ + if (value == ' ' || + value == '\t' || + value == '\n' || value == '\r' || value == '\f' || value == '\v') + { + return true; + } + else + { + return false; + } +} + +void +sanitize_string (char *string) +{ + bool escaped = false; + + if (!string) + { + return; + } + + while (1) + { + switch (*string) + { + case '\0': + return; + case '\\': + escaped = !escaped; + break; + case ']': + if (!escaped) + { + *string = ']'; + } + escaped = false; + break; + default: + break; + }; + ++string; + } +} + + +bool +get_header_string_and_size (struct header_t *header, + enum prop_type_t type, char **buffer, int *size) +{ + if (buffer == 0 || header == 0) + { + return false; + } + + if (type == PROP_BLACK_NAME) + { + *buffer = header->black; + *size = MAX_NAME; + } + else if (type == PROP_WHITE_NAME) + { + *buffer = header->white; + *size = MAX_NAME; + } + else if (type == PROP_BLACK_RANK) + { + *buffer = header->black_rank; + *size = MAX_RANK; + } + else if (type == PROP_WHITE_RANK) + { + *buffer = header->white_rank; + *size = MAX_RANK; + } + else if (type == PROP_BLACK_TEAM) + { + *buffer = header->black_team; + *size = MAX_TEAM; + } + else if (type == PROP_WHITE_TEAM) + { + *buffer = header->white_team; + *size = MAX_TEAM; + } + else if (type == PROP_DATE) + { + *buffer = header->date; + *size = MAX_DATE; + } + else if (type == PROP_ROUND) + { + *buffer = header->round; + *size = MAX_ROUND; + } + else if (type == PROP_EVENT) + { + *buffer = header->event; + *size = MAX_EVENT; + } + else if (type == PROP_PLACE) + { + *buffer = header->place; + *size = MAX_PLACE; + } + else if (type == PROP_OVERTIME) + { + *buffer = header->overtime; + *size = MAX_OVERTIME; + } + else if (type == PROP_RESULT) + { + *buffer = header->result; + *size = MAX_RESULT; + } + else if (type == PROP_RULESET) + { + *buffer = header->ruleset; + *size = MAX_RULESET; + } + else + { + return false; + } + + return true; +} + + +/* TEST CODE BEGINS HERE define GBN_TEST to run this, either in goban.h or + in the CFLAGS. The tests will be run when the plugin starts, after + which the plugin will exit. Any error stops testing since many tests + depend on previous setup. Note: The testing can take a while as there + are some big loops. Be patient. */ + +#ifdef GBN_TEST + +#include "goban.h" +#include "types.h" +#include "board.h" +#include "game.h" +#include "sgf.h" +#include "sgf_storage.h" + +/* If this isn't on a single line, the line numbers it reports will be wrong. + * + * I'm sure there's a way to make it better, but it's not really worth it. + */ +#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;} + +void +run_tests (void) +{ + rb->splash (3 * HZ, "Running tests. Failures will stop testing."); + + + + /* allocating and freeing storage units */ + + gbn_assert (alloc_storage_sgf ()); + + int prevent_infinite = 100000000; + + int count = 1; + while (alloc_storage_sgf () >= 0 && --prevent_infinite) + { + ++count; + } + + gbn_assert (prevent_infinite); + gbn_assert (count > 100); + + /* make sure it fails a few times */ + gbn_assert (alloc_storage_sgf () < 0); + gbn_assert (alloc_storage_sgf () < 0); + gbn_assert (alloc_storage_sgf () < 0); + + free_storage_sgf (0); + + gbn_assert (alloc_storage_sgf () == 0); + + gbn_assert (alloc_storage_sgf () < 0); + + int i; + for (i = 0; i <= count; ++i) + { + free_storage_sgf (i); + } + + gbn_assert (alloc_storage_sgf () >= 0); + --count; + + for (i = 0; i < count; ++i) + { + gbn_assert (alloc_storage_sgf () >= 0); + } + + free_tree_sgf (); + + + + /* setting up, saving and loading */ + gbn_assert (setup_game (MAX_BOARD_SIZE, MAX_BOARD_SIZE, 0, 15)); + gbn_assert (setup_game (MAX_BOARD_SIZE, MAX_BOARD_SIZE, 0, -30)); + gbn_assert (setup_game (MAX_BOARD_SIZE, MAX_BOARD_SIZE, 4, 1)); + gbn_assert (setup_game (MIN_BOARD_SIZE, MIN_BOARD_SIZE, 1, 1)); + + gbn_assert (setup_game (MIN_BOARD_SIZE, MAX_BOARD_SIZE, 1, 1)); + gbn_assert (setup_game (MAX_BOARD_SIZE, MIN_BOARD_SIZE, 1, 1)); + + gbn_assert (!setup_game (MAX_BOARD_SIZE + 1, MAX_BOARD_SIZE + 1, 0, 15)); + gbn_assert (!setup_game (MIN_BOARD_SIZE - 1, MIN_BOARD_SIZE - 1, 0, 15)); + gbn_assert (!setup_game (MAX_BOARD_SIZE, MAX_BOARD_SIZE, -1, 15)); + + gbn_assert (setup_game (MAX_BOARD_SIZE, MAX_BOARD_SIZE, 1, 1)); + gbn_assert (save_game (DEFAULT_SAVE_DIR "/t1.sgf")); + gbn_assert (load_game (DEFAULT_SAVE_DIR "/t1.sgf")); + gbn_assert (save_game (DEFAULT_SAVE_DIR "/t2.sgf")); + gbn_assert (load_game (DEFAULT_SAVE_DIR "/t2.sgf")); + + gbn_assert (!save_game ("/DIR_DOESNT_EXIST/blah.sgf")); + gbn_assert (!load_game ("/DIR_DOESNT_EXIST/blah.sgf")); + gbn_assert (!load_game (DEFAULT_SAVE_DIR "/DOESNT_EXIST.sgf")); + + + + /* test of a long game, captures, illegal moves */ + gbn_assert (load_game (DEFAULT_SAVE_DIR "/long.sgf")); + while (move_num < 520) + { + gbn_assert (num_variations_sgf () == 1); + gbn_assert (redo_node_sgf ()); + } + + gbn_assert (play_move_sgf (POS (2, 0), BLACK)); + gbn_assert (play_move_sgf (POS (2, 1), WHITE)); + + gbn_assert (move_num == 522); + + gbn_assert (white_captures == 261 && black_captures == 0); + + gbn_assert (play_move_sgf (PASS_POS, BLACK)); + gbn_assert (play_move_sgf (PASS_POS, WHITE)); + + gbn_assert (move_num == 524); + + int x, y; + int b_count, w_count, e_count; + b_count = w_count = e_count = 0; + for (x = 0; x < 19; ++x) + { + for (y = 0; y < 19; ++y) + { + gbn_assert (!legal_move_board (POS (x, y), BLACK, false)); + gbn_assert (!play_move_sgf (POS (x, y), BLACK)); + switch (get_point_board (POS (x, y))) + { + case BLACK: + ++b_count; + break; + case WHITE: + ++w_count; + break; + case EMPTY: + ++e_count; + break; + default: + gbn_assert (false); + } + } + } + + gbn_assert (b_count == 0 && w_count == 261 && e_count == 19 * 19 - 261); + + gbn_assert (undo_node_sgf ()); + gbn_assert (move_num == 523); + + int infinite_prevention = 0; + while (move_num > 0) + { + gbn_assert (undo_node_sgf ()); + + ++infinite_prevention; + gbn_assert (infinite_prevention < 100000); + } + + gbn_assert (save_game (DEFAULT_SAVE_DIR "/long_out.sgf")); + + + /* test of basic moves, legal moves, adding and removing stones */ + gbn_assert (setup_game (MAX_BOARD_SIZE, MAX_BOARD_SIZE, 0, 0)); + gbn_assert (play_move_sgf + (POS (MAX_BOARD_SIZE / 2, MAX_BOARD_SIZE / 2), BLACK)); + gbn_assert (move_num == 1 && current_player == WHITE); + gbn_assert (!legal_move_board + (POS (MAX_BOARD_SIZE / 2, MAX_BOARD_SIZE / 2), WHITE, true)); + + int saved_node = current_node; + gbn_assert (add_stone_sgf (POS (0, 0), BLACK)); + gbn_assert (current_node != saved_node); + gbn_assert (get_point_board (POS (0, 0)) == BLACK); + gbn_assert (move_num == 1 && current_player == WHITE); + + saved_node = current_node; + gbn_assert (add_stone_sgf (POS (0, 1), WHITE)); + gbn_assert (current_node == saved_node); + gbn_assert (get_point_board (POS (0, 1)) == WHITE); + + gbn_assert (add_stone_sgf (POS (0, 0), EMPTY)); + gbn_assert (add_stone_sgf (POS (0, 1), EMPTY)); + gbn_assert (get_point_board (POS (0, 0)) == EMPTY); + gbn_assert (get_point_board (POS (0, 1)) == EMPTY); + + + /* test captures */ + gbn_assert (load_game (DEFAULT_SAVE_DIR "/cap.sgf")); + gbn_assert (play_move_sgf (POS (0, 0), BLACK)); + gbn_assert (black_captures == 8); + gbn_assert (undo_node_sgf ()); + gbn_assert (black_captures == 0); + + gbn_assert (!play_move_sgf (POS (0, 0), WHITE)); + play_mode = MODE_FORCE_PLAY; + gbn_assert (play_move_sgf (POS (0, 0), WHITE)); + play_mode = MODE_PLAY; + + gbn_assert (black_captures == 9); + gbn_assert (get_point_board (POS (0, 0)) == EMPTY); + gbn_assert (undo_node_sgf ()); + gbn_assert (black_captures == 0); + + gbn_assert (play_move_sgf (POS (9, 9), BLACK)); + gbn_assert (black_captures == 44); + + for (x = 0; x < 19; ++x) + { + for (y = 0; y < 19; ++y) + { + gbn_assert (get_point_board (POS (x, y)) == BLACK || + add_stone_sgf (POS (x, y), BLACK)); + } + } + + gbn_assert (get_point_board (POS (0, 0)) == BLACK); + gbn_assert (add_stone_sgf (POS (9, 9), EMPTY)); + gbn_assert (play_move_sgf (POS (9, 9), WHITE)); + gbn_assert (white_captures == 360); + + gbn_assert (undo_node_sgf ()); + gbn_assert (white_captures == 0); + + play_mode = MODE_FORCE_PLAY; + gbn_assert (play_move_sgf (POS (9, 9), BLACK)); + play_mode = MODE_PLAY; + gbn_assert (white_captures == 361); + + for (x = 0; x < 19; ++x) + { + for (y = 0; y < 19; ++y) + { + gbn_assert (get_point_board (POS (x, y)) == EMPTY); + } + } + + + /* test ko */ + gbn_assert (setup_game (MAX_BOARD_SIZE, MAX_BOARD_SIZE, 0, 15)); + + /* + * Set up the board to look like this: + * -X------ + * XO------ + * O------- + * -------- + */ + gbn_assert (add_stone_sgf (POS (0, 1), BLACK)); + gbn_assert (add_stone_sgf (POS (1, 0), BLACK)); + gbn_assert (add_stone_sgf (POS (1, 1), WHITE)); + gbn_assert (add_stone_sgf (POS (0, 2), WHITE)); + + /* take the ko and make sure black can't take back */ + gbn_assert (play_move_sgf (POS (0, 0), WHITE)); + gbn_assert (!play_move_sgf (POS (0, 1), BLACK)); + + /* make sure white can fill, even with the ko_pos set */ + gbn_assert (play_move_sgf (POS (0, 1), WHITE)); + /* and make sure undo sets the ko again */ + gbn_assert (undo_node_sgf ()); + gbn_assert (!play_move_sgf (POS (0, 1), BLACK)); + + /* make sure ko threats clear the ko */ + gbn_assert (play_move_sgf (POS (2, 2), BLACK)); /* ko threat */ + gbn_assert (play_move_sgf (POS (2, 3), WHITE)); /* response */ + gbn_assert (play_move_sgf (POS (0, 1), BLACK)); /* take ko */ + + gbn_assert (undo_node_sgf ()); + gbn_assert (undo_node_sgf ()); + gbn_assert (undo_node_sgf ()); + + /* make sure a pass is counted as a ko threat */ + gbn_assert (!play_move_sgf (POS (0, 1), BLACK)); + gbn_assert (play_move_sgf (PASS_POS, BLACK)); + gbn_assert (play_move_sgf (PASS_POS, WHITE)); + gbn_assert (play_move_sgf (POS (0, 1), BLACK)); + + /* and finally let's make sure that white can't directly retake */ + gbn_assert (!play_move_sgf (POS (0, 0), WHITE)); + + + + /* test some header information saving/loading as well as comment + saving loading */ + char some_comment[] = + "blah blah blah i am a stupid comment. here's some annoying characters: 01234567890!@#$%^&*()[[[[\\\\\\]ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + /* that bit near the end is literally this: \\\] which tests escaping + of ]s */ + char read_buffer[256]; + + gbn_assert (setup_game (MAX_BOARD_SIZE, MAX_BOARD_SIZE, 5, -20)); + + /* this also tests that ko_pos is reset by setuping up a new game */ + gbn_assert (play_move_sgf (POS (0, 0), WHITE)); + gbn_assert (write_comment_sgf (some_comment) > 0); + gbn_assert (play_move_sgf (POS (0, 1), BLACK)); + rb->strcpy (header.black, "Jack Black"); + rb->strcpy (header.white, "Jill White"); + + gbn_assert (save_game (DEFAULT_SAVE_DIR "/head.sgf")); + + gbn_assert (setup_game (MIN_BOARD_SIZE, MIN_BOARD_SIZE, 1, 1)); + gbn_assert (load_game (DEFAULT_SAVE_DIR "/head.sgf")); + + gbn_assert (header.komi == -20 && header.handicap == 5); + gbn_assert (board_width == MAX_BOARD_SIZE + && board_height == MAX_BOARD_SIZE); + gbn_assert (rb->strcmp (header.black, "Jack Black") == 0); + gbn_assert (rb->strcmp (header.white, "Jill White") == 0); + gbn_assert (redo_node_sgf ()); + gbn_assert (read_comment_sgf (read_buffer, sizeof (read_buffer))); + gbn_assert (rb->strcmp (read_buffer, some_comment) == 0); + gbn_assert (redo_node_sgf ()); + gbn_assert (get_point_board (POS (0, 0)) == WHITE); + gbn_assert (get_point_board (POS (0, 1)) == BLACK); + + + + /* test saving and loading a file with unhandled SGF properties. this + test requires that the user diff unhnd.sgf with unhnd_out.sgf (any + substantial difference is a bug and should be reported) the + following are NOT substantial differences: - reordering of + properties in a node - whitespace changes outside of a comment + value or other property value - reordering of property values */ + gbn_assert (load_game (DEFAULT_SAVE_DIR "/unhnd.sgf")); + gbn_assert (save_game (DEFAULT_SAVE_DIR "/unhnd_out.sgf")); + + + + /* Test variations a bit */ + gbn_assert (setup_game (MAX_BOARD_SIZE, MAX_BOARD_SIZE, 0, 13)); + /* start at a move, otherwise add_stone won't create a variation */ + gbn_assert (play_move_sgf (POS (5, 5), BLACK)); + /* make sure it doesn't */ + gbn_assert (undo_node_sgf ()); + gbn_assert (add_stone_sgf (POS (4, 5), WHITE)); + gbn_assert (!undo_node_sgf ()); + gbn_assert (num_variations_sgf () == 1); + gbn_assert (play_move_sgf (POS (5, 5), BLACK)); + + gbn_assert (play_move_sgf (POS (0, 0), BLACK)); + gbn_assert (num_variations_sgf () == 1); + gbn_assert (undo_node_sgf ()); + gbn_assert (play_move_sgf (POS (0, 1), BLACK)); + gbn_assert (num_variations_sgf () == 2); + gbn_assert (undo_node_sgf ()); + gbn_assert (play_move_sgf (POS (0, 1), BLACK)); + gbn_assert (num_variations_sgf () == 2); + gbn_assert (undo_node_sgf ()); + gbn_assert (play_move_sgf (POS (0, 2), BLACK)); + gbn_assert (num_variations_sgf () == 3); + gbn_assert (undo_node_sgf ()); + gbn_assert (play_move_sgf (POS (0, 3), WHITE)); + gbn_assert (num_variations_sgf () == 4); + gbn_assert (undo_node_sgf ()); + gbn_assert (play_move_sgf (PASS_POS, BLACK)); + gbn_assert (num_variations_sgf () == 5); + gbn_assert (undo_node_sgf ()); + gbn_assert (add_stone_sgf (POS (1, 1), BLACK)); + gbn_assert (add_stone_sgf (POS (1, 2), BLACK)); + gbn_assert (add_stone_sgf (POS (1, 3), WHITE)); + gbn_assert (num_variations_sgf () == 6); + gbn_assert (undo_node_sgf ()); + gbn_assert (add_stone_sgf (POS (1, 1), BLACK)); + gbn_assert (add_stone_sgf (POS (1, 2), BLACK)); + gbn_assert (add_stone_sgf (POS (1, 3), WHITE)); + gbn_assert (num_variations_sgf () == 7); + gbn_assert (next_variation_sgf ()); + gbn_assert (get_point_board (POS (0, 0)) == BLACK); + gbn_assert (get_point_board (POS (0, 1)) == EMPTY); + gbn_assert (get_point_board (POS (0, 2)) == EMPTY); + gbn_assert (get_point_board (POS (1, 1)) == EMPTY); + gbn_assert (get_point_board (POS (1, 2)) == EMPTY); + gbn_assert (get_point_board (POS (1, 3)) == EMPTY); + + rb->splash (10 * HZ, "All tests passed. Exiting"); +} +#endif /* GBN_TEST */ |