#!/usr/bin/ruby -w # CGBG - the Critters Go Board Generator # Copyright 2008 by the Critters ############################################################################### ATTRIBUTE_LIST = [ # name default_value code # ------------------------------ -------------- ------------------------------ [ "reset", "", :RESET ], [ "generate", "", :GENERATE ], [ "name", "", :NAME ], [ "prefix", "gb_", :PREFIX ], [ "board_size", "19", :BOARD_SIZE ], [ "ko_rule", "setable", :KO_RULE ], [ "suicide_rule", "setable", :SUICIDE_RULE ], [ "check_internals", "true", :CHECK_INTERNALS ], [ "max_moves", "1000", :MAX_MOVES ], [ "hash_width", "8", :HASH_WIDTH ], [ "do_undo", "true", :DO_UNDO ], [ "do_get_liberties", "true", :DO_GET_LIBERTIES ], [ "do_get_adjacencies", "true", :DO_GET_ADJACENCIES ], [ "do_get_all_chains", "true", :DO_GET_ALL_CHAINS ], [ "do_checkpoint", "false", :DO_CHECKPOINT ], [ "do_instrumentation", "false", :DO_INSTRUMENTATION ], [ "do_track_empties", "true", :DO_TRACK_EMPTIES ], [ "border", "false", :BORDER ], [ "track_liberties", "dense_links", :TRACK_LIBERTIES ], [ "location_to_chain", "strict", :LOCATION_TO_CHAIN ], [ "border_type", "unique", :BORDER_TYPE ], [ "track_adjacencies", "search", :TRACK_ADJACENCIES ], [ "for_all_neighbors", "absolute", :FOR_ALL_NEIGHBORS ], [ "inline_capture_and_merge", "true", :INLINE_CAPTURE_AND_MERGE ], [ "unroll_in_capture_and_merge", "true", :UNROLL_IN_CAPTURE_AND_MERGE ], [ "lazy_chain_initialization", "false", :LAZY_CHAIN_INITIALIZATION ], [ "parallel_arrays_for_records", "false", :PARALLEL_ARRAYS_FOR_RECORDS ], [ "specialize_on_color", "false", :SPECIALIZE_ON_COLOR ], [ "alter_border_chains", "false", :ALTER_BORDER_CHAINS ], [ "unroll_in_play_and_suicide", "true", :UNROLL_IN_PLAY_AND_SUICIDE ], [ "unroll_in_legal", "true", :UNROLL_IN_LEGAL ], [ "normal_move", "1", :NORMAL_MOVE ], [ "invalid_code", "0", :INVALID_CODE ], [ "set_ko_loc", "2", :SET_KO_LOC ], [ "triple_ko", "none", :TRIPLE_KO ], [ "use_lro_structs", "false", :USE_LRO_STRUCTS ], [ "use_zro_structs", "false", :USE_ZRO_STRUCTS ], [ "use_board_structs", "false", :USE_BOARD_STRUCTS ], [ "interface", "simple", :INTERFACE ], [ "number_of_games", "1", :NUMBER_OF_GAMES ], [ "number_of_backups", "1", :NUMBER_OF_BACKUPS ], [ "unsigned_short", "false", :UNSIGNED_SHORT ], ] ############################################################################### # Inside here, the_block is the block passed to the method def block( &the_block ) the_block # return the block end ############################################################################### $current_attr_set = {} def is_present(token) ATTRIBUTE_LIST.each do |attr| if attr[0] == token return true end end return false end def find_symbol(token) ATTRIBUTE_LIST.each do |attr| if attr[0] == token return attr[2] end end return "" # should never get here end def reset_current_attr_set $current_attr_set = {} ATTRIBUTE_LIST.each do |attr| $current_attr_set[attr[0]] = attr[1] end end def store_in_current_attr_set(tokens) $current_attr_set[tokens[0]] = tokens[1] end def fetch_from_current_attr_set(token) if $current_attr_set[token] return $current_attr_set[token] end ATTRIBUTE_LIST.each do |attr| if attr[0] == token return attr[1] end end return "" # should never get here end ############################################################################### $generate_number = 0 def fetch_prefix value = fetch_from_current_attr_set("prefix") if value == '""' value = "" end return value.gsub(/%/, $generate_number.to_s) end # returns a boolean def fetch_border value = fetch_from_current_attr_set("border") return value != "false" end def logical_board_width size = fetch_from_current_attr_set("board_size") return size.to_i end def fetch_liberty_ds return fetch_from_current_attr_set("track_liberties") end def fetch_adjacencies_ds return fetch_from_current_attr_set("track_adjacencies") end def fetch_redirects_ds return fetch_from_current_attr_set("location_to_chain") end def fetch_ko_rule return fetch_from_current_attr_set("ko_rule") end def fetch_suicide_rule return fetch_from_current_attr_set("suicide_rule") end def fetch_check_internals return fetch_from_current_attr_set("check_internals") end def fetch_normal_move return fetch_from_current_attr_set("normal_move") end def fetch_invalid_code return fetch_from_current_attr_set("invalid_code") end def fetch_set_ko_loc return fetch_from_current_attr_set("set_ko_loc") end def fetch_track_empties return fetch_from_current_attr_set("do_track_empties") end def fetch_triple_ko return fetch_from_current_attr_set("triple_ko") end def fetch_use_lro_structs return fetch_from_current_attr_set("use_lro_structs") end def fetch_use_zro_structs return fetch_from_current_attr_set("use_zro_structs") end def fetch_use_board_structs return fetch_from_current_attr_set("use_board_structs") end def fetch_interface return fetch_from_current_attr_set("interface") end def fetch_number_of_games return fetch_from_current_attr_set("number_of_games") end def fetch_number_of_backups return fetch_from_current_attr_set("number_of_backups") end def fetch_do_undo return fetch_from_current_attr_set("do_undo") end def fetch_basic_type return "short" if fetch_from_current_attr_set("unsigned_short") == "false" return "unsigned short" end ############################################################################### # read-only variable def lrov(name) return lrov2(name, fetch_prefix) if fetch_use_lro_structs == "false" return fetch_prefix.downcase + "lro_data." + name end def zrov(name) if fetch_use_zro_structs == "false" return fetch_prefix.downcase + name if name[0..0].match(/[a-z]/) return fetch_prefix.upcase + name if name[0..0].match(/[A-Z]/) return "error" else return fetch_prefix.downcase + "zro_data." + name end end # game state variable def gv(name) return gv2(name, fetch_prefix) end # game state variable reference def gvr(name) prefix = fetch_prefix if fetch_use_board_structs == "true" if fetch_interface == "simple" || fetch_number_of_games == 1 return gv("board_data") + "." + name if name[0..0].match(/[a-z]/) return gv("board_data") + "." + name if name[0..0].match(/[A-Z]/) return "error % ^ & *" end if fetch_interface == "index" return gv("board_data") + "[hidden_index]." + name if name[0..0].match(/[a-z]/) return gv("board_data") + "[hidden_index]." + name if name[0..0].match(/[A-Z]/) return "error % ^ & *" end if fetch_interface == "pointer" return "hidden_pointer->" + name if name[0..0].match(/[a-z]/) return "hidden_pointer->" + name if name[0..0].match(/[A-Z]/) return "error % ^ & *" end return "error % ^ & *" end return prefix.downcase + name if name[0..0].match(/[a-z]/) return prefix.upcase + name if name[0..0].match(/[A-Z]/) return "error % ^ & *" end # location read-only variable def lrov2(name, prefix) return prefix.downcase + name if name[0..0].match(/[a-z]/) return prefix.upcase + name if name[0..0].match(/[A-Z]/) return "error" end # game state variable def gv2(name, prefix) return prefix.downcase + name if name[0..0].match(/[a-z]/) return prefix.upcase + name if name[0..0].match(/[A-Z]/) return "error" end def hidden_param return "" if fetch_use_board_structs != "true" return "" if fetch_interface == "simple" return "" if fetch_number_of_games == 1 return "int hidden_index, " if fetch_interface == "index" return "struct " + gv("board_data") + "* hidden_pointer, " if fetch_interface == "pointer" return " asd 8 ( 8 $ x @" end def hidden_param_only return "void" if fetch_use_board_structs != "true" return "" if fetch_interface == "simple" return "" if fetch_number_of_games == 1 return "int hidden_index" if fetch_interface == "index" return "struct " + gv("board_data") + "* hidden_pointer" if fetch_interface == "pointer" return " asd 8 ( 8 $ x @" end def hidden_var return "" if fetch_use_board_structs != "true" return "" if fetch_interface == "simple" return "" if fetch_number_of_games == 1 return "hidden_index, " if fetch_interface == "index" return "hidden_pointer, " if fetch_interface == "pointer" return " asd 8 ( 8 $ x @" end def hidden_var_only return "" if fetch_use_board_structs != "true" return "" if fetch_interface == "simple" return "" if fetch_number_of_games == 1 return "hidden_index" if fetch_interface == "index" return "hidden_pointer" if fetch_interface == "pointer" return " asd 8 ( 8 $ x @" end ############################################################################### def replace(text) text2 = text text2.gsub!(/(g|G)@(([a-zA-Z0-9_])+)/) { |x| gv(x[2..-1]) } text2.gsub!(/(gr|GR)@(([a-zA-Z0-9_])+)/) { |x| gvr(x[3..-1]) } text2.gsub!(/(l|L)@(([a-zA-Z0-9_])+)/) { |x| lrov(x[2..-1]) } text2.gsub!(/(z|Z)@(([a-zA-Z0-9_])+)/) { |x| zrov(x[2..-1]) } text2.gsub!(/(p|P)@\s*\)/) { |x| (hidden_param_only + x[2..-1]) } text2.gsub!(/(p|P)@/) { |x| (hidden_param) } text2.gsub!(/(v|V)@\s*\)/) { |x| (hidden_var_only + x[2..-1]) } text2.gsub!(/(v|V)@/) { |x| (hidden_var) } return text2 end ############################################################################### def physical_board_width size = fetch_from_current_attr_set("board_size") return size.to_i + 2 if fetch_border return size.to_i end def logical_board_size size = fetch_from_current_attr_set("board_size") return (size.to_i) ** 2 end def physical_board_size size = fetch_from_current_attr_set("board_size") border = fetch_border return (size.to_i + 2) ** 2 + 2 if border return (size.to_i) ** 2 + 2 end def next_power_of_2(number) i = 1 i *= 2 while i < number return i end def to_hex(number, digits) str = number.to_s(16) return "0x" + str.rjust(digits, "0") end ############################################################################### def generate_modifiers(is_extern, is_static, is_const) extern_text = (is_extern ? "extern " : "") static_text = (is_static ? "static " : "") const_text = (is_const ? "const " : "") return extern_text + static_text + const_text end def generate_var_decl(decl, is_struct, name_func) type = decl[0] name = (is_struct ? decl[1] : name_func.call(decl[1])) subscript0 = "" subscript0 = "[" + decl[2] + "]" if decl.size >= 3 && decl[2] != "" subscript1 = "" subscript1 = "[" + decl[3] + "]" if decl.size >= 4 && decl[3] != "" return type + " " + name + subscript0 + subscript1 end def generate_init(decl) data = decl[4] return data end ############################################################################### def generate_data(group, fields, is_code, is_struct) struct_name = group[0] variable_name = group[1] is_public = group[2] is_const = group[3] group_title = group[4] name_func = group[5] result = "" #... variables ........................................................ if (is_code || is_public) && !is_struct result += comment_seperator(group_title) result += "\n\n" for i in 0...fields.size if fields[i].size == 1 title = fields[i][0] result += "\n" result += comment_seperator(title + " Data") result += "\n\n" else mods = generate_modifiers(!is_code && is_public, is_code && !is_public, is_const) result += mods + generate_var_decl(fields[i], false, name_func) if is_const && is_code result += " = " result += generate_init(fields[i]) end result += ";\n" end end end #... structure ........................................................ if (is_code || is_public) && is_struct result += comment_seperator(group_title) result += "\n\n" if is_code != is_public result += "struct " + struct_name + " {\n" for i in 0...fields.size if fields[i].size == 1 title = fields[i][0] result += "\n" result += enum_comment(title + " Data") result += "\n\n" else result += "\t" + generate_var_decl(fields[i], true, name_func) result += ";\n" end end result += "};\n" end if variable_name != "" mods = generate_modifiers(!is_code && is_public, is_code && !is_public, is_const) result += mods + "struct " + struct_name + " " + variable_name if is_code && is_const result += " = {\n" for i in 0...fields.size if fields[i].size == 1 title = fields[i][0] result += "\n" result += enum_comment(title + " Data") result += "\n\n" else result += generate_init(fields[i]) result += ", " end end result += "\n}" end result += ";\n" end end return result end ############################################################################### def enum_comment(title) comment = "\t// " + "-" * 68 return comment if title == "" comment2 = " " + title + " " comment[8, comment2.length] = comment2 return comment end ############################################################################### def generate_enums(fields) result = "" result += "enum {\n" for i in 0...fields.size if fields[i].size == 1 title = fields[i][0] result += "\n" result += enum_comment(title + " Enums") result += "\n\n" else name = fields[i][0] value = fields[i][1] result += "\t" + name + " = " + value + ",\n" end end result += "};\n" return result end ############################################################################### def generate_makefile makefile_text = < err end end ############################################################################### def comment_seperator(comment) result = "// " + "-" * 76 return result if comment == "" comment2 = " " + comment + " " result[7, comment2.length] = comment2 return result end ############################################################################## $LOCATIONS_TOP = 0x001 $LOCATIONS_BOTTOM = 0x002 $LOCATIONS_LEFT = 0x004 $LOCATIONS_RIGHT = 0x008 $LOCATIONS_MIDDLE = 0x010 $LOCATIONS_EDGE = 0x020 $LOCATIONS_CORNER = 0x040 $LOCATIONS_HOSHI = 0x080 $LOCATIONS_BORDER = 0x100 ############################################################################### def generate_location_macros without_border = < #include #{comment_seperator("Common")} #ifndef NULL #define NULL ((void*)0) #endif #ifndef N_ELEMENTS_IN #define N_ELEMENTS_IN(array) (sizeof(array) / sizeof((array)[0])) #endif enum result_codes { SUCCESS = 0, BAD_COLOR = 1, BAD_LOCATION = 2, RETAKE_KO = 3, NOT_EMPTY = 4, STACK_OVERFLOW = 5, TOO_MANY_MOVES = 6, BAD_SUICIDE = 7, BAD_SUPERKO = 8, }; enum ko_rules { SIMPLE_KO, POSITIONAL_SUPERKO, SITUATIONAL_SUPERKO, }; typedef #{fetch_basic_type} BASIC; typedef #{fetch_basic_type} LOCATION; typedef #{fetch_basic_type} ADJACENCY; typedef #{fetch_basic_type} COLOR; typedef #{fetch_basic_type} CHAIN; typedef #{fetch_basic_type} COUNT; typedef #{fetch_basic_type} PLAYER; typedef unsigned short FLAGS; typedef unsigned long long HASH; enum { LOCATIONS_TOP = #{to_hex($LOCATIONS_TOP, 2)}, LOCATIONS_BOTTOM = #{to_hex($LOCATIONS_BOTTOM, 2)}, LOCATIONS_LEFT = #{to_hex($LOCATIONS_LEFT, 2)}, LOCATIONS_RIGHT = #{to_hex($LOCATIONS_RIGHT, 2)}, LOCATIONS_MIDDLE = #{to_hex($LOCATIONS_EDGE, 2)}, LOCATIONS_EDGE = #{to_hex($LOCATIONS_EDGE, 2)}, LOCATIONS_CORNER = #{to_hex($LOCATIONS_CORNER, 2)}, LOCATIONS_HOSHI = #{to_hex($LOCATIONS_HOSHI, 2)}, LOCATIONS_BORDER = #{to_hex($LOCATIONS_BORDER, 2)}, }; enum color { EMPTY = 0, BLACK = 1, WHITE = 2, BORDER = 3 }; extern char* color_to_string(const COLOR color); #define OPPONENT(x) ((x) ^ 0x3) // ------------------- #define COUNT_DOWN(i, number) for(i = (number) - 1; i >= 0; i--) #define IS_SET(vector, i) ((vector)[(i) >> 5] & (1 << ((i) & 0x1F))) #define SET(vector, i) ((vector)[(i) >> 5] |= (1 << ((i) & 0x1F))) struct location_set { COUNT count; LOCATION locs[625]; // larger than any set! // TODO: fix this! }; extern BASIC rand_get_range(const BASIC range); QQQQQ_04 #.............................................................................. begin $board_h_file.puts replace(header_text) rescue => err end end ############################################################################### # This should only be called from inside the .c def generate_board_enums enums = [] enums += generate_board_and_backup_enums enums += generate_history_enums enums += generate_undo_enums("i1_", 5000) enums += generate_undo_enums("i2_", 160000) enums += generate_undo_enums("i4_", 50000) enums += generate_hash_enums enums += generate_liberties_enums enums += generate_adjacencies_enums return generate_enums(enums) end ############################################################################### # This should only be called from inside the .c def generate_board_declarations group = [ "g@board_data", # struct name "", # variable name (don't create any) false, # publicly visible false, # read only init "Board Data", # title block { |x| gv(x) } # name prefix func ] fields = [] fields += generate_config_data fields += generate_core_data fields += generate_chains_data fields += generate_liberties_data fields += generate_adjacencies_data fields += generate_history_data fields += generate_undo_data("i1_", "char", 5000) fields += generate_undo_data("i2_", "BASIC", 160000) fields += generate_undo_data("i4_", "long", 50000) fields += generate_hash_data fields += generate_empties_data in_struct = (fetch_use_board_structs == "true") return generate_data(group, fields, true, in_struct) end ############################################################################### def generate_board_and_backup_enums enums = [ [ "Move History" ], [ "g@NUMBER_OF_GAMES", fetch_number_of_games ], [ "g@NUMBER_OF_BACKUPS", fetch_number_of_backups ], ] return enums end ############################################################################### def generate_board_variables #.............................................................................. decls1 = < 14 g@INVALID_LOCATION = #{fetch_invalid_code}, }; #{generate_location_read_only_data(false)} extern int g@location_computeZ(int x, int y); #define g@IS_TOP(loc) (L@location_flags[loc] & LOCATIONS_TOP) #define g@IS_BOTTOM(loc) (L@location_flags[loc] & LOCATIONS_BOTTOM) #define g@IS_LEFT(loc) (L@location_flags[loc] & LOCATIONS_LEFT) #define g@IS_RIGHT(loc) (L@location_flags[loc] & LOCATIONS_RIGHT) #define g@IS_TOP_OR_LEFT(loc) (L@location_flags[loc] & (LOCATIONS_TOP | LOCATIONS_LEFT)) #define g@IS_BOTTOM_OR_LEFT(loc) (L@location_flags[loc] & (LOCATIONS_BOTTOM | LOCATIONS_LEFT)) #define g@IS_TOP_OR_RIGHT(loc) (L@location_flags[loc] & (LOCATIONS_TOP | LOCATIONS_RIGHT)) #define g@IS_BOTTOM_OR_RIGHT(loc) (L@location_flags[loc] & (LOCATIONS_BOTTOM | LOCATIONS_RIGHT)) #define g@IS_MIDDLE(loc) (L@location_flags[loc] & LOCATIONS_MIDDLE) #define g@IS_EDGE(loc) (L@location_flags[loc] & LOCATIONS_EDGE) #define g@IS_CORNER(loc) (L@location_flags[loc] & LOCATIONS_CORNER) #define g@IS_HOSHI(loc) (L@location_flags[loc] & LOCATIONS_HOSHI) #define g@IS_BORDER(loc) (L@location_flags[loc] & LOCATIONS_BORDER) #define g@WEST(loc) ((loc) - 1) #define g@EAST(loc) ((loc) + 1) #define g@SOUTH(loc) ((loc) - g@PHYSICAL_BOARD_WIDTH) #define g@NORTH(loc) ((loc) + g@PHYSICAL_BOARD_WIDTH) #define g@NORTHWEST(loc) ((loc) + g@PHYSICAL_BOARD_WIDTH - 1) #define g@NORTHEAST(loc) ((loc) + g@PHYSICAL_BOARD_WIDTH + 1) #define g@SOUTHWEST(loc) ((loc) - g@PHYSICAL_BOARD_WIDTH - 1) #define g@SOUTHEAST(loc) ((loc) - g@PHYSICAL_BOARD_WIDTH + 1) #define g@WEST_OF(array, loc) (((array) - 1)[loc]) #define g@EAST_OF(array, loc) (((array) + 1)[loc]) #define g@SOUTH_OF(array, loc) (((array) - g@PHYSICAL_BOARD_WIDTH)[loc]) #define g@NORTH_OF(array, loc) (((array) + g@PHYSICAL_BOARD_WIDTH)[loc]) #{generate_location_macros} #define g@FOR_ALL_NEIGHBORS(neighbor, center, state) for(state = (LOCATION *)L@location_neighbors + ((center) << 3), neighbor = *(state++); neighbor != (LOCATION)g@INVALID_LOCATION; neighbor = *(state++)) #define g@FOR_ALL_NEIGHBORS_UR(neighbor, center, state) for(state = (LOCATION *)(L@location_neighbors + 5) + ((center) << 3), neighbor = *(state++); neighbor != (LOCATION)g@INVALID_LOCATION; neighbor = *(state++)) #define g@IS_PASS(loc) ((loc) == (LOCATION)(g@INVALID_LOCATION)) struct g@board_data; // This declarationis used for hidden param pointers extern struct g@board_data* g@get_board_pointer(const int index); extern void g@reset(p@); extern void g@set_config_ko(p@const enum ko_rules ko_type); extern void g@set_config_suicide(p@const bool suicide_is_legal); extern void g@set_config_komi(p@const float komi); extern bool g@self_test(p@); extern int g@play(p@const COLOR color, const LOCATION location); extern void g@pass(p@const COLOR color); extern void g@undo(p@); extern COUNT g@get_stone_count(p@const LOCATION loc); extern void g@get_stones(p@const LOCATION loc, LOCATION* result); extern COUNT g@get_liberty_count(p@const LOCATION loc); extern void g@get_liberties(p@const LOCATION loc, LOCATION* result); extern COUNT g@get_adjacency_count(p@const LOCATION loc); extern void g@get_adjacencies(p@const LOCATION loc, LOCATION* result); extern COLOR g@get_state(p@const LOCATION location); extern COUNT g@get_total_stone_count(p@const COLOR color); extern COUNT g@get_prisoner_count(p@const COLOR color); extern bool g@can_escape_from_ladder(p@const LOCATION loc); extern bool g@can_capture_in_ladder(p@const LOCATION loc); extern void g@board_to_string(p@char buffer[]); extern bool g@check_board(p@); extern void g@checkpoint(p@const int index); extern void g@restore(p@const int index); extern bool g@is_eyelike(p@const LOCATION x, const COLOR player); extern bool g@is_false_eye(p@const LOCATION x, const COLOR opponent); extern COLOR g@territory_of(p@const LOCATION x); extern COLOR g@winner(p@); QQQQQ_07 begin $board_h_file.puts replace(generate_color_decl + board_h_text) rescue => err end end ############################################################################### def generate_board_h_footer header_text = < err end end ############################################################################## def location_fill(array, n_elements, value) for i in 0...n_elements array[i] = value; end end ############################################################################## HOSHI_DATA = [ [0, -1], [0, -1], [0, -1], [0, -1], [0, -1], [0, -1], [0, -1], [1, 3], [4, 3], [5, 3], [4, 3], [5, 3], [4, 3], [5, 4], [4, 4], [5, 4], [4, 4], [5, 4], [4, 4], [9, 4], [4, 4], [9, 4], [4, 4], [9, 4], [4, 4], [9, 4], ] def is_hoshi(x, y) edgeDistance = HOSHI_DATA[logical_board_width][1] numberOfPoints = HOSHI_DATA[logical_board_width][0] if numberOfPoints == 0 return false; end if numberOfPoints == 1 return (x == logical_board_width / 2 && y == logical_board_width / 2); end if numberOfPoints == 4 return (x == edgeDistance - 1 || x == logical_board_width - edgeDistance) && (y == edgeDistance - 1 || y == logical_board_width - edgeDistance) end if numberOfPoints == 5 return (x == logical_board_width / 2 && y == logical_board_width / 2) || (x == edgeDistance - 1 || x == logical_board_width - edgeDistance) && (y == edgeDistance - 1 || y == logical_board_width - edgeDistance) end if numberOfPoints == 9 return (x == edgeDistance - 1 || x == logical_board_width - edgeDistance || x == logical_board_width / 2) && (y == edgeDistance - 1 || y == logical_board_width - edgeDistance || y == logical_board_width / 2) end # error return false end ############################################################################## def location_computeZ(x, y) if x < 0 || x >= logical_board_width || y < 0 || y >= logical_board_width return fetch_invalid_code end if fetch_border return (y + 1) * (physical_board_width) + (x + 1) + 1 else return y * physical_board_width + x + 1 end end ############################################################################## def format_hash_array(hashes, n_tabs) result = "" hashes.each { |value| result += ("\t" * n_tabs) + value + ",\n" } return result end def format_array(array, width, base) result = "" for i in 0...array.length if i % width == 0 result += "\n\t" end if base == 16 number = to_hex(array[i], 2) elsif base == 10 number = array[i].to_s else number = "&@)*&(" end result += number.rjust(4) + "," end return result end ############################################################################## def generate_location_read_only_data(in_code) xxx_location_flags = [] xxx_location_xs = [] xxx_location_ys = [] xxx_location_neighbors = [] xxx_all_locations = [] location_fill(xxx_location_flags, physical_board_size, $LOCATIONS_BORDER) location_fill(xxx_location_xs, physical_board_size, -1) location_fill(xxx_location_ys, physical_board_size, -1) for x in 0...logical_board_width for y in 0...logical_board_width z = location_computeZ(x, y) flags = 0 flags |= $LOCATIONS_LEFT if x == 0 flags |= $LOCATIONS_RIGHT if x == logical_board_width - 1 flags |= $LOCATIONS_BOTTOM if y == 0 flags |= $LOCATIONS_TOP if y == logical_board_width - 1 flags |= $LOCATIONS_MIDDLE if (x != 0 && x != logical_board_width - 1) && (y != 0 && y != logical_board_width - 1) flags |= $LOCATIONS_EDGE if (x == 0 || x == logical_board_width - 1) || (y == 0 || y == logical_board_width - 1) flags |= $LOCATIONS_CORNER if (x == 0 || x == logical_board_width - 1) && (y == 0 || y == logical_board_width - 1) flags |= $LOCATIONS_HOSHI if is_hoshi(x, y) xxx_location_flags[z] = flags xxx_location_xs[z] = x xxx_location_ys[z] = y end end location_fill(xxx_location_neighbors, physical_board_size * 8, fetch_invalid_code) for x in 0...logical_board_width for y in 0...logical_board_width loc = location_computeZ(x, y) place1 = loc << 3 if x != 0 xxx_location_neighbors[place1] = loc - 1 place1 += 1 end if x != logical_board_width - 1 xxx_location_neighbors[place1] = loc + 1 place1 += 1 end if y != 0 xxx_location_neighbors[place1] = loc - physical_board_width place1 += 1 end if y != logical_board_width - 1 xxx_location_neighbors[place1] = loc + physical_board_width place1 += 1 end end end for x in 0...logical_board_width for y in 0...logical_board_width loc = location_computeZ(x, y) place1 = (loc << 3) + 5 if x != logical_board_width - 1 xxx_location_neighbors[place1] = loc + 1 place1 += 1 end if y != logical_board_width - 1 xxx_location_neighbors[place1] = loc + physical_board_width place1 += 1 end end end i = 0 for x in 0...logical_board_width for y in 0...logical_board_width z = location_computeZ(x, y) xxx_all_locations[i] = z i += 1 end end xxx_all_locations[i] = fetch_invalid_code #.............................................................................. lrod_group = [ "g@location_read_only", # struct name "g@lro_data", # variable_name true, # publicly visible true, # read only init "Location Read-Only Data", # title block { |x| lrov(x) } # name func ] lrod_fields = [ [ "FLAGS", "location_flags", "g@PHYSICAL_BOARD_SIZE", "", "{" + format_array(xxx_location_flags, physical_board_width, 16) + "}" ], [ "char", "location_xs", "g@PHYSICAL_BOARD_SIZE", "", "{" + format_array(xxx_location_xs, physical_board_width, 10) + "}" ], [ "char", "location_ys", "g@PHYSICAL_BOARD_SIZE", "", "{" + format_array(xxx_location_ys, physical_board_width, 10) + "}" ], [ "LOCATION", "location_neighbors", "g@PHYSICAL_NEIGHBORS_SIZE", "", "{" + format_array(xxx_location_neighbors, 8, 10) + "}" ], [ "LOCATION", "location_all", "g@PHYSICAL_BOARD_SIZE", "", "{" + format_array(xxx_all_locations, physical_board_width, 10) + "}" ], ] in_struct = (fetch_use_lro_structs == "true") return generate_data(lrod_group, lrod_fields, in_code, in_struct) end ############################################################################### def generate_location_functions if fetch_border equation = "(y + 1) * g@PHYSICAL_BOARD_WIDTH + (x + 1) + 1;" else equation = "y * g@PHYSICAL_BOARD_WIDTH + x + 1;" end #.............................................................................. location_decls = <= g@LOGICAL_BOARD_WIDTH || y < 0 || y >= g@LOGICAL_BOARD_WIDTH) return g@INVALID_LOCATION; return #{equation} } char* g@color_to_string(const COLOR color) { switch(color) { case EMPTY: return "empty"; case BLACK: return "black"; case WHITE: return "white"; default: return "error"; } } QQQQQ_09 #.............................................................................. return location_decls end ############################################################################### def generate_zobrist_enums enums = [ [ "g@ZOBRIST_ARRAY_SIZE", next_power_of_2(physical_board_size).to_s + "/* next_power_of_2(g@PHYSICAL_BOARD_SIZE) */" ] ] return generate_enums(enums) end ############################################################################### def get_rand64 result = "0x" + rand(65536).to_s(16).rjust(4, "0") + rand(65536).to_s(16).rjust(4, "0") + rand(65536).to_s(16).rjust(4, "0") + rand(65536).to_s(16).rjust(4, "0") + "ul" return result end #.............................................................................. def generate_zobrist_read_only_data(in_code) srand(1234); # initialize the rng hash_base = get_rand64 black_base = get_rand64 white_base = get_rand64 black_hashes = [] white_hashes = [] ko_hashes = [] for i in 0...physical_board_size # only init what we will use black_hashes[i] = "0ul"; white_hashes[i] = "0ul"; ko_hashes[i] = "0ul"; end for x in 0...logical_board_width for y in 0...logical_board_width z = location_computeZ(x, y) black_hashes[z] = get_rand64 white_hashes[z] = get_rand64 ko_hashes[z] = get_rand64 end end #...................................................................... in_struct = (fetch_use_zro_structs == "true") indent = (in_struct ? "\t" : "" ) group = [ "g@zobrist_read_only", # struct name "g@zro_data", # variable_name false, # publicly visible true, # read only init "Zobrist Read-Only Data", # title block { |x| zrov(x) } # name func ] fields = [ [ "HASH", "zobrist_baseHash", "", "", indent + hash_base, ], [ "HASH", "zobrist_turnHashes", "3", "", "{\n" + indent + "\t0,\n" + indent + "\t" + black_base + ",\n" + indent + "\t" + white_base + ",\n" + indent + "}", ], [ "HASH", "zobrist_stoneHashes", "3", "g@ZOBRIST_ARRAY_SIZE", "{\n" + indent + "\t{\n" + indent + "\t\t0\n" + indent + "\t}, {\n" + format_hash_array(black_hashes, in_struct ? 3 : 2) + indent + "\t}, {\n" + format_hash_array(white_hashes, in_struct ? 3 : 2) + indent + "\t}\n" + indent + "}", ], [ "HASH", "zobrist_koHashes", "g@ZOBRIST_ARRAY_SIZE", "", "{\n" + format_hash_array(ko_hashes, in_struct ? 2 : 1) + indent + "}", ], ] return generate_data(group, fields, in_code, in_struct) end ############################################################################### # TODO: Make this code selectable # TODO: Make rand_mask static def rand_bits_code #.............................................................................. rand_bits_code1 = <> 1); mask |= (mask >> 2); mask |= (mask >> 4); mask |= (mask >> 8); BASIC possible; do { // possible = (get_random_word() & mask); possible = (rand() & mask); } while(possible >= range); return possible; } QQQQQ_10 #.............................................................................. rand_bits_code2 = <> 1); mask |= (mask >> 2); mask |= (mask >> 4); mask |= (mask >> 8); g@rand_mask[i] = mask; } } BASIC rand_get_range(const BASIC range) { const BASIC mask = g@rand_mask[range]; BASIC possible; do { possible = (g@get_random_word() & mask); } while(possible >= range); return possible; } QQQQQ_11 #.............................................................................. return rand_bits_code1 end ############################################################################### # TODO: split out chains data def generate_core_data fields = [ [ "LOCATION", "board_ko_loc", "", "", "", ], [ "HASH", "board_hash", "", "", "", ], [ "COUNT", "players_n_stones_of_color", "g@COLORS_COUNT", "", "", ], [ "COUNT", "players_n_prisoners_of_color", "g@COLORS_COUNT", "", "", ], [ "COLOR", "locations_color", "g@PHYSICAL_BOARD_SIZE", "", "", ], [ "LOCATION", "locations_next_stone", "g@PHYSICAL_BOARD_SIZE", "", "", ], [ "COUNT", "chains_n_stones", "g@PHYSICAL_BOARD_SIZE", "", "", ] ] return fields end ############################################################################### def generate_core_functions #.............................................................................. text = < 0; i--) { g@I2_UNDOABLE_ASSIGN(gr@liberties_chain[libertyPtr], g@INVALID_LOCATION); libertyPtr = gr@liberties_next[libertyPtr]; } g@I2_UNDOABLE_ASSIGN(gr@chains_n_liberties[chain], 0); // TODO: rethink all versions of this. } static void g@liberties_merge(p@const CHAIN bigger_chain, const CHAIN smaller_chain) { BASIC liberty_slot_ptr = gr@liberties_next[smaller_chain + g@LIBERTY_HEADER_OFFSET]; for(BASIC i = gr@chains_n_liberties[smaller_chain]; i > 0; i--) { const BASIC next_liberty_slot_ptr = gr@liberties_next[liberty_slot_ptr]; if(g@liberties_contains(bigger_chain, liberty_slot_ptr >> 2)) g@I2_UNDOABLE_ASSIGN(gr@liberties_chain[liberty_slot_ptr], g@INVALID_LOCATION); // TODO: explain why unlink not needed else g@liberties_move_into_chain(bigger_chain, liberty_slot_ptr); liberty_slot_ptr = next_liberty_slot_ptr; } g@I2_UNDOABLE_ASSIGN(gr@chains_n_liberties[smaller_chain], 0); } static inline bool g@liberties_none(const CHAIN chain) { return gr@chains_n_liberties[chain] == 0; } static inline bool g@liberties_atari(p@const CHAIN chain) { return gr@chains_n_liberties[chain] == 1; } static inline int g@liberties_count(p@const CHAIN chain) { return gr@chains_n_liberties[chain]; } static inline void g@liberties_fetch(p@const CHAIN chain, LOCATION *result) { BASIC ptr = gr@liberties_next[chain + g@LIBERTY_HEADER_OFFSET]; for(COUNT i = gr@chains_n_liberties[chain]; i > 0; i--) { *(result++) = ptr >> 2; ptr = gr@liberties_next[ptr]; } } static inline bool g@liberties_verify(p@CHAIN chain, struct location_set* libs) { if(g@liberties_atari(v@chain) != (libs->count == 1)) { printf("bad atari (dl): chain = %d, inc libs = %d, lump libs = %d\\n", chain, gr@chains_n_liberties[chain], libs->count); return false; } if(gr@chains_n_liberties[chain] != libs->count) { printf("wrong liberty count (dll) %d, %d\\n", gr@chains_n_liberties[chain], libs->count); return false; } return true; } QQQQQ_13 #.............................................................................. xxy = < 0; ) { i--; g@liberties_add(v@bigger, gr@liberties[smaller][i]); } g@I2_UNDOABLE_ASSIGN(gr@n_liberties[smaller], 0); } static inline void g@liberties_capture(p@const CHAIN chain) { g@I2_UNDOABLE_ASSIGN(gr@n_liberties[chain], 0); } static inline bool g@liberties_none(p@const CHAIN chain) { return gr@n_liberties[chain] == 0; } static inline bool g@liberties_atari(p@const CHAIN chain) { return gr@n_liberties[chain] == 1; } static inline int g@liberties_count(p@const CHAIN chain) { return gr@n_liberties[chain]; } static inline void g@liberties_fetch(p@const CHAIN chain, LOCATION *result) { for(int i = gr@n_liberties[chain] - 1; i >= 0; i--) { *(result++) = gr@liberties[chain][i]; } } static inline bool g@liberties_verify(p@CHAIN chain, struct location_set* libs) { if(g@liberties_atari(v@chain) != (libs->count == 1)) { printf("bad atari (al): chain = %d, inc libs = %d, lump libs = %d\\n", chain, gr@n_liberties[chain], libs->count); for(int i = 0; i < libs->count; i++) printf("\\t%d\\n", libs->locs[i]); return false; } if(gr@n_liberties[chain] != libs->count) { printf("wrong liberty count (al) %d, %d\\n", gr@n_liberties[chain], libs->count); return false; } return true; } QQQQQ_14 #.............................................................................. xxz = < 0; i--) { g@liberties_add(v@bigger, ptr); ptr = g@liberty_next[smaller][ptr]; } g@I2_UNDOABLE_ASSIGN(g@liberty_next[smaller][g@PHYSICAL_BOARD_SIZE], g@PHYSICAL_BOARD_SIZE); g@I2_UNDOABLE_ASSIGN(g@liberty_prev[smaller][g@PHYSICAL_BOARD_SIZE], g@PHYSICAL_BOARD_SIZE); g@I2_UNDOABLE_ASSIGN(gr@n_liberties[smaller], 0); } static inline void g@liberties_capture(const CHAIN chain) { g@I2_UNDOABLE_ASSIGN(g@liberty_next[chain][g@PHYSICAL_BOARD_SIZE], g@PHYSICAL_BOARD_SIZE); g@I2_UNDOABLE_ASSIGN(g@liberty_prev[chain][g@PHYSICAL_BOARD_SIZE], g@PHYSICAL_BOARD_SIZE); g@I2_UNDOABLE_ASSIGN(gr@n_liberties[chain], 0); } static inline bool g@liberties_none(p@const CHAIN chain) { return gr@n_liberties[chain] == 0; } static inline bool g@liberties_atari(p@const CHAIN chain) { return gr@n_liberties[chain] == 1; } static inline int g@liberties_count(p@const CHAIN chain) { return gr@n_liberties[chain]; } static inline void g@liberties_fetch(p@const CHAIN chain, LOCATION *result) { BASIC ptr = g@liberty_next[chain][g@PHYSICAL_BOARD_SIZE]; for(BASIC i = gr@n_liberties[chain]; i > 0; i--) { *(result++) = ptr; ptr = g@liberty_next[chain][ptr]; } } static inline bool g@liberties_verify(p@CHAIN chain, struct location_set* libs) { if(g@liberties_atari(v@chain) != (libs->count == 1)) { printf("bad atari (sl): chain = %d, inc libs = %d, lump libs = %d\\n", chain, gr@n_liberties[chain], libs->count); return false; } if(gr@n_liberties[chain] != libs->count) { printf("wrong liberty count (sll) %d, %d\\n", gr@n_liberties[chain], libs->count); return false; } return true; } QQQQQ_15 #.............................................................................. xxza = < 0; count--) { LOCATION neighbor, *state; g@FOR_ALL_NEIGHBORS(neighbor, ptr, state) { if(gr@locations_color[neighbor] == EMPTY) { if(!IS_SET(mask, neighbor)) { SET(mask, neighbor); liberty_count++; } } } ptr = gr@locations_next_stone[ptr]; } return liberty_count; } static inline void g@liberties_fetch(v@CHAIN chain, LOCATION* result) { unsigned long mask[g@BITSET_SIZE_IN_LONGS]; BASIC i; COUNT_DOWN(i, g@BITSET_SIZE_IN_LONGS) { mask[i] = 0; } BASIC ptr = chain; for(COUNT count = gr@chains_n_stones[chain]; count > 0; count--) { LOCATION neighbor, *state; g@FOR_ALL_NEIGHBORS(neighbor, ptr, state) { if(gr@locations_color[neighbor] == EMPTY) { if(!IS_SET(mask, neighbor)) { SET(mask, neighbor); *(result++) = neighbor; } } } ptr = gr@locations_next_stone[ptr]; } } static inline bool g@liberties_verify(p@CHAIN chain, struct location_set* libs) { if(g@liberties_atari(v@chain) != (libs->count == 1)) { printf("bad atari (b): chain = %d, libs = %d\\n", chain, libs->count); printf("\t: count = %d, sum = %d, sum squares = %d\\n", gr@n_liberties[chain], g@liberty_sum[chain], g@liberty_sum_squares[chain]); return false; } // if(gr@n_liberties[chain] != libs->count) { // printf("wrong liberty count %d, %d\\n", gr@n_liberties[chain], libs->count); // return false; // } return true; } QQQQQ_16 #.............................................................................. xxzb = < 0; count--) { LOCATION neighbor, *state; g@FOR_ALL_NEIGHBORS(neighbor, ptr, state) { if(gr@locations_color[neighbor] == EMPTY) { if(!IS_SET(mask, neighbor)) { SET(mask, neighbor); liberty_count++; } } } ptr = gr@locations_next_stone[ptr]; } return liberty_count; } static inline void g@liberties_fetch(p@CHAIN chain, LOCATION* result) { unsigned long mask[g@BITSET_SIZE_IN_LONGS]; BASIC i; COUNT_DOWN(i, g@BITSET_SIZE_IN_LONGS) { mask[i] = 0; } BASIC ptr = chain; for(COUNT count = gr@chains_n_stones[chain]; count > 0; count--) { LOCATION neighbor, *state; g@FOR_ALL_NEIGHBORS(neighbor, ptr, state) { if(gr@locations_color[neighbor] == EMPTY) { if(!IS_SET(mask, neighbor)) { SET(mask, neighbor); *(result++) = neighbor; } } } ptr = gr@locations_next_stone[ptr]; } } // ERROR: TODO: fix this! static inline bool g@liberties_verify(p@CHAIN chain, struct location_set* libs) { // if(g@liberties_atari(v@chain) != (libs->count == 1)) { // printf("bad atari (s): chain = %d, libs = %d\\n", chain, libs->count); // return false; // // } // if(gr@n_liberties[chain] != libs->count) { // printf("wrong liberty count %d, %d\\n", gr@n_liberties[chain], libs->count); // return false; // } return true; } QQQQQ_17 #.............................................................................. xxzc = <> 5], (1 << (liberty & 0x1F))); g@I2_UNDOABLE_ADD_TO(gr@n_liberties[chain], 1); } } static inline void g@liberties_remove(p@const CHAIN chain, const LOCATION liberty) { if(IS_SET(g@liberties_bits[chain], liberty)) { g@I4_UNDOABLE_AND_IN(g@liberties_bits[chain][liberty >> 5], ~(1 << (liberty & 0x1F))); g@I2_UNDOABLE_SUBTRACT_FROM(gr@n_liberties[chain], 1); } } static inline void g@liberties_capture(p@const CHAIN chain) { g@I2_UNDOABLE_ASSIGN(gr@n_liberties[chain], 0); BASIC i; COUNT_DOWN(i, g@BITSET_SIZE_IN_LONGS) { g@I4_UNDOABLE_ASSIGN(g@liberties_bits[chain][i], 0); } } static inline void g@liberties_merge(p@const CHAIN chain1, const CHAIN chain2) { COUNT bits = 0; g@I2_UNDOABLE_ADD_TO(gr@n_liberties[chain1], gr@n_liberties[chain2]); BASIC i; COUNT_DOWN(i, g@BITSET_SIZE_IN_LONGS) { g@I4_UNDOABLE_OR_IN(g@liberties_bits[chain1][i], g@liberties_bits[chain2][i]); bits += __builtin_popcountl ((unsigned long)g@liberties_bits[chain1][i]); } g@I2_UNDOABLE_ASSIGN(gr@n_liberties[chain1], bits); g@liberties_capture(chain2); } static inline bool g@liberties_none(p@const CHAIN chain) { return gr@n_liberties[chain] == 0; } // TODO: ERROR: This is wrong! static inline bool g@liberties_atari(p@const CHAIN chain) { return gr@n_liberties[chain] == 1; } static inline int g@liberties_count(p@const CHAIN chain) { unsigned long mask[g@BITSET_SIZE_IN_LONGS]; BASIC i; COUNT_DOWN(i, g@BITSET_SIZE_IN_LONGS) { mask[i] = 0; } int liberty_count = 0; BASIC ptr = chain; for(COUNT count = gr@chains_n_stones[chain]; count > 0; count--) { LOCATION neighbor, *state; g@FOR_ALL_NEIGHBORS(neighbor, ptr, state) { if(gr@locations_color[neighbor] == EMPTY) { if(!IS_SET(mask, neighbor)) { SET(mask, neighbor); liberty_count++; } } } ptr = gr@locations_next_stone[ptr]; } return liberty_count; } static inline void g@liberties_fetch(p@CHAIN chain, LOCATION* result) { unsigned long mask[g@BITSET_SIZE_IN_LONGS]; BASIC i; COUNT_DOWN(i, g@BITSET_SIZE_IN_LONGS) { mask[i] = 0; } BASIC ptr = chain; for(COUNT count = gr@chains_n_stones[chain]; count > 0; count--) { LOCATION neighbor, *state; g@FOR_ALL_NEIGHBORS(neighbor, ptr, state) { if(gr@locations_color[neighbor] == EMPTY) { if(!IS_SET(mask, neighbor)) { SET(mask, neighbor); *(result++) = neighbor; } } } ptr = gr@locations_next_stone[ptr]; } } // ERROR: TODO: fix this! static inline bool g@liberties_verify(p@CHAIN chain, struct location_set* libs) { if(g@liberties_atari(v@chain) != (libs->count == 1)) { printf("bad atari (s): chain = %d, libs = %d\\n", chain, libs->count); return false; } if(gr@n_liberties[chain] != libs->count) { printf("wrong liberty count %d, %d\\n", gr@n_liberties[chain], libs->count); return false; } return true; } QQQQQ_18 #.............................................................................. return xxx if fetch_liberty_ds == "dense_links" return xxy if fetch_liberty_ds == "arrays" return xxz if fetch_liberty_ds == "sparse_links" return xxza if fetch_liberty_ds == "boesch" return xxzb if fetch_liberty_ds == "simple" return xxzc if fetch_liberty_ds == "bitset" return "ERROR X Y Z Q" end ############################################################################### def generate_adjacencies_data aaa = [ [ "Adjacencies: Array List" ], [ "COUNT", "n_adjacencies", "g@PHYSICAL_BOARD_SIZE", "", "", ], [ "ADJACENCY", "adjacencies", "g@PHYSICAL_BOARD_SIZE", "#{next_power_of_2(physical_board_size * 1 / 3)}", # "g@PHYSICAL_BOARD_SIZE", "", ], ] #.............................................................................. bbb = [ [ "Adjacencies: Dense List" ] ] #.............................................................................. ccc = [ [ "Adjacencies: Sparse List" ], [ "COUNT", "chains_n_adjacencies", "g@PHYSICAL_BOARD_SIZE", "", "", ], [ "ADJACENCY", "adjacencies_next", "g@PHYSICAL_BOARD_SIZE", "g@ADJACENCIES_MAX", "", ], [ "ADJACENCY", "adjacencies_prev", "g@PHYSICAL_BOARD_SIZE", "g@ADJACENCIES_MAX", "", ], ] #.............................................................................. ddd = [ [ "Adjacencies: Search" ] ] #.............................................................................. return aaa if fetch_adjacencies_ds == "arrays" return bbb if fetch_adjacencies_ds == "dense_links" return ccc if fetch_adjacencies_ds == "sparse_links" return ddd if fetch_adjacencies_ds == "search" return [] end ############################################################################### # adjacencies_reset # adjacencies_add # adjacencies_remove # adjacencies_merge # adjacencies_capture # adjacencies_count # adjacencies_fetch def generate_adjacencies_functions #.............................................................................. aaa = < 0; ) { i--; g@adjacencies_add(v@bigger, gr@adjacencies[smaller][i]); } g@I2_UNDOABLE_ASSIGN(gr@n_adjacencies[smaller], 0); } static inline void g@adjacencies_capture(p@const CHAIN chain) { g@I2_UNDOABLE_ASSIGN(gr@n_adjacencies[chain], 0); } static inline int g@adjacencies_count(p@const CHAIN chain) { return gr@n_adjacencies[chain]; } static inline void g@adjacencies_fetch(p@const CHAIN chain, LOCATION result[]) { for(int i = gr@n_adjacencies[chain] - 1; i >= 0; i--) { result[i] = gr@adjacencies[chain][i]; } } QQQQQ_19 #.............................................................................. bbb = < 0; i--) { BASIC nextAdjacencyPtr = g@adjacencies_next[chain][adjacencyPtr]; g@adjacencies_remove(chain, adjacencyPtr); adjacencyPtr = nextAdjacencyPtr; } // TODO: rethink all versions of this. g@I2_UNDOABLE_ASSIGN(gr@chains_n_adjacencies[chain], 0); } static inline void g@adjacencies_merge(p@const CHAIN bigger_chain, const CHAIN smaller_chain) { BASIC adjacencyPtr = g@adjacencies_next[smaller_chain][g@ADJACENT_HEADER_OFFSET]; for(BASIC i = gr@chains_n_adjacencies[smaller_chain]; i > 0; i--) { BASIC nextAdjacencyPtr = g@adjacencies_next[smaller_chain][adjacencyPtr]; g@adjacencies_add(v@bigger_chain, adjacencyPtr); g@adjacencies_remove(v@smaller_chain, adjacencyPtr); adjacencyPtr = nextAdjacencyPtr; } g@adjacencies_capture(smaller_chain); } static inline int g@adjacencies_count(p@const CHAIN chain) { return gr@chains_n_adjacencies[chain]; } static inline void g@adjacencies_fetch(p@const CHAIN chain, LOCATION *result) { BASIC ptr = g@adjacencies_next[chain][g@ADJACENT_HEADER_OFFSET]; for(BASIC i = gr@chains_n_adjacencies[chain]; i > 0; i--) { *(result++) = ptr; ptr = g@adjacencies_next[chain][ptr]; } } QQQQQ_21 #.............................................................................. ddd = < 0; count--) { LOCATION neighbor, *state; g@FOR_ALL_NEIGHBORS(neighbor, chain, state) { if(gr@locations_color[neighbor] == opponent) { // TODO: uning normal redirect causes crash! EXPLAIN CHAIN chain_id = g@redirect_find_2(v@neighbor); if(!IS_SET(mask, chain_id)) { SET(mask, chain_id); adj_count++; } } } ptr = gr@locations_next_stone[ptr]; } return adj_count; } static inline void g@adjacencies_fetch(p@const CHAIN chain, LOCATION *result) { unsigned long mask[g@BITSET_SIZE_IN_LONGS]; COUNT i; COUNT_DOWN(i, g@BITSET_SIZE_IN_LONGS) { mask[i] = 0; } int adj_count = 0; COLOR opponent = OPPONENT(gr@locations_color[chain]); CHAIN ptr = chain; for(COUNT count = gr@chains_n_stones[chain]; count > 0; count--) { LOCATION neighbor, *state; g@FOR_ALL_NEIGHBORS(neighbor, ptr, state) { if(gr@locations_color[neighbor] == opponent) { // TODO: uning normal redirect causes crash! EXPLAIN CHAIN chain_id = g@redirect_find_2(v@neighbor); if(!IS_SET(mask, chain_id)) { SET(mask, chain_id); result[adj_count++] = chain_id; } } } ptr = gr@locations_next_stone[ptr]; } } /* void get_adjacencies(p@const CHAIN chain, struct location_set* result) { unsigned long mask[g@BITSET_SIZE_IN_LONGS]; COUNT i; COUNT_DOWN(i, g@BITSET_SIZE_IN_LONGS) { mask[i] = 0; } result->count = 0; const COLOR opponent = OPPONENT(gr@locations_color[chain]); CHAIN ptr = chain; for(COUNT count = gr@chains_n_stones[chain]; count > 0; count--) { LOCATION neighbor, *state; g@FOR_ALL_NEIGHBORS(neighbor, ptr, state) { if(gr@locations_color[neighbor] == opponent) { CHAIN chain_id = to_chain[neighbor]; if(!IS_SET(mask, chain_id)) { SET(mask, chain_id); result->locs[result->count++] = chain_id; } } } ptr = gr@locations_next_stone[ptr]; } } */ QQQQQ_22 #.............................................................................. return aaa if fetch_adjacencies_ds == "arrays" return bbb if fetch_adjacencies_ds == "dense_links" return ccc if fetch_adjacencies_ds == "sparse_links" return ddd if fetch_adjacencies_ds == "search" return "ERROR A B C Q" end ############################################################################### def generate_chains_data fields = [ [ "Location to Chain" ], [ "CHAIN", "locations_to_chain", "g@PHYSICAL_BOARD_SIZE", "", "", ] ] return fields end ############################################################################### # chains_reset # chains_redirect # chains_find def generate_chains_functions #.............................................................................. aaa = < 0; i--) { BASIC next_stone_ptr = gr@locations_next_stone[stone_ptr]; g@I2_UNDOABLE_ASSIGN(gr@locations_to_chain[stone_ptr], bigger_chain); stone_ptr = next_stone_ptr; } } static inline CHAIN g@redirect_find(p@const LOCATION loc) { return gr@locations_to_chain[loc]; } static inline CHAIN g@redirect_find_2(p@const LOCATION loc) { return gr@locations_to_chain[loc]; } QQQQQ_23 #.............................................................................. bbb = < #include #include #include #include "board.h" #include "SFMT.h" QQQQQ_25 begin $board_c_file.puts replace(board_c_header_text) $board_c_file.puts replace(rand_bits_code) rescue => err end end ############################################################################### # TODO: find a rationale for these numbers def generate_undo_enums(prefix, size) enums = [ [ "Undo" ], [ "g@" + prefix.upcase + "MAX_SL_HISTORY", size.to_s ], [ "g@" + prefix.upcase + "SL_MARGIN", (size / 4).to_s ], ] return [] if fetch_do_undo == "false" return enums end ############################################################################### def generate_undo_data(prefix, type, size) fields = [ [ "Undo" ], [ type + "*", prefix + "undo_log_addresses", "g@" + prefix.upcase + "MAX_SL_HISTORY", "", "", ], [ type, prefix + "undo_log_values", "g@" + prefix.upcase + "MAX_SL_HISTORY", "", "", ], [ "int", prefix + "undo_log_top", "", "", "", ], ] return [] if fetch_do_undo == "false" return fields end ############################################################################### def generate_undo_functions(prefix, type, size) p = prefix.upcase #.............................................................................. text1 = <= 0 && gr@#{prefix}undo_log_addresses[gr@#{prefix}undo_log_top] != NULL) { *gr@#{prefix}undo_log_addresses[gr@#{prefix}undo_log_top] = gr@#{prefix}undo_log_values[gr@#{prefix}undo_log_top]; gr@#{prefix}undo_log_top--; } gr@#{prefix}undo_log_top--; // skip separator } static inline bool g@#{prefix}undo_log_overflow(p@) { return gr@#{prefix}undo_log_top >= g@#{prefix.upcase}MAX_SL_HISTORY - g@#{prefix.upcase}SL_MARGIN; } #define g@#{p}UNDOABLE_ASSIGN(x, y) do { g@#{prefix}undo_log_save(v@&(x), (x)); (x) = (y); } while(0) #define g@#{p}UNDOABLE_ADD_TO(x, y) do { g@#{prefix}undo_log_save(v@&(x), (x)); (x) += (y); } while(0) #define g@#{p}UNDOABLE_SUBTRACT_FROM(x, y) do { g@#{prefix}undo_log_save(v@&(x), (x)); (x) -= (y); } while(0) #define g@#{p}UNDOABLE_OR_IN(x, y) do { g@#{prefix}undo_log_save(v@&(x), (x)); (x) |= (y); } while(0) #define g@#{p}UNDOABLE_AND_IN(x, y) do { g@#{prefix}undo_log_save(v@&(x), (x)); (x) &= (y); } while(0) QQQQQ_26 #.............................................................................. text2 = < 0); gr@moveHistory_nextMoveNumber--; gr@board_hash = gr@moveHistory_boardHash[gr@moveHistory_nextMoveNumber]; gr@board_ko_loc = gr@moveHistory_koLocation[gr@moveHistory_nextMoveNumber]; } #if 0 static COLOR g@moveHistory_getLastPlayer(p@) { return (g@moveHistory_nextMovePointer <= 0) ? EMPTY : g@moveHistory_moveHistoryA[nextMovePointer - 1].color(); } static LOCATION g@moveHistory_getLastMove(p@) { return (g@moveHistory_nextMovePointer <= 0) ? null : g@moveHistory_moveHistoryA[nextMovePointer - 1]; } static LOCATION g@moveHistory_getLastMoveBy(p@const COLOR color) { for(int i = g@moveHistory_nextMovePointer; ; i--) { if(i <= 0) return -4; if(g@moveHistory_moveHistoryA[i - 1].color() == color) return g@moveHistory_moveHistoryA[i - 1]; } } #endif QQQQQ_28 return text end ############################################################################### def generate_hash_enums enums = [ [ "Hash Set" ], [ "g@HASH_TABLE_SIZE", "1024" ], [ "g@HASH_MASK", "0x3FF" ], ] return enums end ############################################################################### # hash_slot_used_* could be chars or bits def generate_hash_data fields = [ [ "Superko Hash" ], [ "BASIC", "hash_slot_used_0", "g@HASH_TABLE_SIZE", "", "", ], [ "BASIC", "hash_slot_used_1", "g@HASH_TABLE_SIZE", "", "", ], [ "BASIC", "hash_slot_used_2", "g@HASH_TABLE_SIZE", "", "", ], [ "BASIC", "hash_slot_used_3", "g@HASH_TABLE_SIZE", "", "", ], [ "HASH", "hash_slot_0", "g@HASH_TABLE_SIZE", "", "", ], [ "HASH", "hash_slot_1", "g@HASH_TABLE_SIZE", "", "", ], [ "HASH", "hash_slot_2", "g@HASH_TABLE_SIZE", "", "", ], [ "HASH", "hash_slot_3", "g@HASH_TABLE_SIZE", "", "", ], [ "HASH", "hash_overflow", "g@HASH_TABLE_SIZE", "", "", ], [ "BASIC", "hash_overflow_count", "", "", "", ], ] return fields end ############################################################################### def generate_hash_functions #.............................................................................. text = <> 0) & g@HASH_MASK; if(!gr@hash_slot_used_0[slot]) { g@I2_UNDOABLE_ASSIGN(gr@hash_slot_used_0[slot], true); gr@hash_slot_0[slot] = code; return true; } if(gr@hash_slot_0[slot] == code) return false; slot = (code >> 16) & g@HASH_MASK; if(!gr@hash_slot_used_1[slot]) { g@I2_UNDOABLE_ASSIGN(gr@hash_slot_used_1[slot], true); gr@hash_slot_1[slot] = code; return true; } if(gr@hash_slot_1[slot] == code) return false; slot = (code >> 32) & g@HASH_MASK; if(!gr@hash_slot_used_2[slot]) { g@I2_UNDOABLE_ASSIGN(gr@hash_slot_used_2[slot], true); gr@hash_slot_2[slot] = code; return true; } if(gr@hash_slot_2[slot] == code) return false; slot = (code >> 48) & g@HASH_MASK; if(!gr@hash_slot_used_3[slot]) { g@I2_UNDOABLE_ASSIGN(gr@hash_slot_used_3[slot], true); gr@hash_slot_3[slot] = code; return true; } if(gr@hash_slot_3[slot] == code) return false; // overflow processing, very rare for(int i = 0; i < gr@hash_overflow_count; i++) { if(gr@hash_overflow[i] == code) return false; } gr@hash_overflow[gr@hash_overflow_count] = code; g@I2_UNDOABLE_ADD_TO(gr@hash_overflow_count, 1); return true; } QQQQQ_29 #.............................................................................. return text end ############################################################################### # TODO: Rethink the title def generate_location_pseudo_liberty_ops #.............................................................................. text1 = < 1; } if(!g@IS_TOP_OR_RIGHT(x)) counts[gr@locations_color[g@NORTHEAST(x)]]++; if(!g@IS_BOTTOM_OR_RIGHT(x)) counts[gr@locations_color[g@SOUTHEAST(x)]]++; if(!g@IS_BOTTOM_OR_LEFT(x)) counts[gr@locations_color[g@SOUTHWEST(x)]]++; if(!g@IS_TOP_OR_LEFT(x)) counts[gr@locations_color[g@NORTHWEST(x)]]++; return counts[opponent] > 0; } // assume that loc is an eye COLOR g@territory_of(p@const LOCATION x) { COUNT counts[4]; counts[EMPTY] = 0; counts[BLACK] = 0; counts[WHITE] = 0; counts[BORDER] = 0; if(g@IS_MIDDLE(x)) { counts[gr@locations_color[g@NORTH(x)]]++; counts[gr@locations_color[g@SOUTH(x)]]++; counts[gr@locations_color[g@EAST(x)]]++; counts[gr@locations_color[g@WEST(x)]]++; } else { if(!g@IS_TOP(x)) counts[gr@locations_color[g@NORTH(x)]]++; if(!g@IS_BOTTOM(x)) counts[gr@locations_color[g@SOUTH(x)]]++; if(!g@IS_RIGHT(x)) counts[gr@locations_color[g@EAST(x)]]++; if(!g@IS_LEFT(x)) counts[gr@locations_color[g@WEST(x)]]++; } if(counts[BLACK] == 0) return WHITE; if(counts[WHITE] == 0) return BLACK; return EMPTY; } QQQQQ_30 #.............................................................................. text2 = < 1; return counts[opponent] > 0; } // assume that loc is an eye COLOR g@territory_of(p@const LOCATION x) { COUNT counts[4]; counts[EMPTY] = 0; counts[BLACK] = 0; counts[WHITE] = 0; counts[BORDER] = 0; counts[gr@locations_color[g@NORTH(x)]]++; counts[gr@locations_color[g@SOUTH(x)]]++; counts[gr@locations_color[g@EAST(x)]]++; counts[gr@locations_color[g@WEST(x)]]++; if(counts[BLACK] == 0) return WHITE; if(counts[WHITE] == 0) return BLACK; return EMPTY; } QQQQQ_31 #.............................................................................. text3 = <= counts[BLACK] + gr@players_n_stones_of_color[BLACK]) ? WHITE : BLACK; } QQQQQ_32 #.............................................................................. # TODO: Consider special cases for each case (middle, edge, corner) if fetch_border return text2 + text3 else return text1 + text3 end end ############################################################################### # position is the positin of the loc in the empties array def generate_empties_data fields = [ [ "Tracking Empties" ], [ "LOCATION", "empties_locations", "g@LOGICAL_BOARD_SIZE", "", "", ], [ "LOCATION", "empties_position", "g@PHYSICAL_BOARD_SIZE", "", "", ], [ "COUNT", "empties_remaining", "", "", "", ], [ "COUNT", "empties_valid_remaining", "", "", "", ] ] return fields if fetch_track_empties == "true" return [] end ############################################################################### def generate_track_empties_functions #.............................................................................. text1 = <= 12 && loc == gr@moveHistory_moveLocation[i - 6] && gr@moveHistory_moveLocation[i - 1] == gr@moveHistory_moveLocation[i - 7] && gr@moveHistory_moveLocation[i - 2] == gr@moveHistory_moveLocation[i - 8] && gr@moveHistory_moveLocation[i - 3] == gr@moveHistory_moveLocation[i - 9] && gr@moveHistory_moveLocation[i - 4] == gr@moveHistory_moveLocation[i - 10] && gr@moveHistory_moveLocation[i - 5] == gr@moveHistory_moveLocation[i - 11]; } QQQQQ_36 #.............................................................................. text3 = <= 6 && loc == gr@moveHistory_koLocation[i - 3] && gr@moveHistory_moveLocation[i - 1] == gr@moveHistory_koLocation[i - 4] && gr@moveHistory_moveLocation[i - 2] == gr@moveHistory_koLocation[i - 5] && gr@moveHistory_moveLocation[i - 3] == gr@moveHistory_koLocation[i - 6]; } QQQQQ_37 #.............................................................................. return text1 if fetch_triple_ko == "none" return text2 if fetch_triple_ko == "williams" return text3 if fetch_triple_ko == "critter" return "ERROR abcd" end ############################################################################### def generate_set_ko_loc #.............................................................................. text1 = < WHITE) return BAD_COLOR; // when using unsigned, the compiler produces a warning for 0 if(location < 1) return BAD_LOCATION; if(location >= g@PHYSICAL_BOARD_SIZE) return BAD_LOCATION; if(gr@locations_color[location] != EMPTY) return NOT_EMPTY; // check stacks if(g@i1_undo_log_overflow(v@)) return STACK_OVERFLOW; if(g@i2_undo_log_overflow(v@)) return STACK_OVERFLOW; if(g@i4_undo_log_overflow(v@)) return STACK_OVERFLOW; if(gr@moveHistory_nextMoveNumber >= g@MOVE_HISTORY_COUNT) return TOO_MANY_MOVES; return SUCCESS; } QQQQQ_44 #.............................................................................. text2 = < 0); g@I2_UNDOABLE_ASSIGN(gr@chains_n_stones[chain], 0); // TODO: rethink all versions of this. g@liberties_capture(v@chain); g@adjacencies_capture(v@chain); } static inline void g@chain_merge(p@const CHAIN chain_a, const CHAIN chain_b) { CHAIN bigger_chain, smaller_chain; if(gr@chains_n_stones[chain_a] >= gr@chains_n_stones[chain_b]) (bigger_chain = chain_a, smaller_chain = chain_b); else (bigger_chain = chain_b, smaller_chain = chain_a); g@adjacencies_merge(v@bigger_chain, smaller_chain); g@liberties_merge(v@bigger_chain, smaller_chain); g@chains_redirect(v@bigger_chain, smaller_chain); // merge the stone lists BASIC temp_bigger = gr@locations_next_stone[bigger_chain]; BASIC temp_smaller = gr@locations_next_stone[smaller_chain]; g@I2_UNDOABLE_ASSIGN(gr@locations_next_stone[bigger_chain], temp_smaller); g@I2_UNDOABLE_ASSIGN(gr@locations_next_stone[smaller_chain], temp_bigger); g@I2_UNDOABLE_ADD_TO(gr@chains_n_stones[bigger_chain], gr@chains_n_stones[smaller_chain]); g@I2_UNDOABLE_ASSIGN(gr@chains_n_stones[smaller_chain], 1); } static inline void g@board_suicide_move(p@const COLOR move_color, const LOCATION move_loc) { // this stone becomes a prisoner g@I2_UNDOABLE_ADD_TO(gr@players_n_prisoners_of_color[move_color], 1); LOCATION neighbor_loc, *state; g@FOR_ALL_NEIGHBORS(neighbor_loc, move_loc, state) { if(gr@locations_color[neighbor_loc] == move_color) { CHAIN neighbor_chain = g@redirect_find(v@neighbor_loc); COUNT iStones = gr@chains_n_stones[neighbor_chain]; g@I2_UNDOABLE_SUBTRACT_FROM(gr@players_n_stones_of_color[move_color], iStones); g@I2_UNDOABLE_ADD_TO(gr@players_n_prisoners_of_color[move_color], iStones); g@chain_capture(v@neighbor_chain, move_color); } } g@set_ko_location(v@g@INVALID_LOCATION); } QQQQQ_49 return text end ############################################################################### # TODO: rethink title def generate_external_functions #.............................................................................. text = <count = gr@chains_n_stones[chain]; CHAIN ptr = chain; for(COUNT i = gr@chains_n_stones[chain]; i > 0; i--) { result->locations[i] = ptr; ptr = gr@locations_next_stone[ptr]; } } #else void g@get_stones(p@const LOCATION loc, LOCATION* result) { const CHAIN chain = g@redirect_find(v@loc); BASIC ptr = chain; for(COUNT i = gr@chains_n_stones[chain]; i > 0; i--) { *(result++) = ptr; ptr = gr@locations_next_stone[ptr]; } } #endif BASIC g@get_liberty_count(p@const LOCATION loc) { const CHAIN chain = g@redirect_find(v@loc); return g@liberties_count(v@chain); } #if 0 void g@get_liberties(p@LOCATION loc, struct g@result* result) { const CHAIN chain = g@redirect_find(v@loc); result->count = gr@n_liberties[chain]; BASIC ptr = liberties_next[chain + g@LIBERTY_HEADER_OFFSET]; for(COUNT i = gr@n_liberties[chain]; i > 0; i--) { result->locations[i] = ptr >> 2; ptr = gr@liberties_next[ptr]; } } #else void g@get_liberties(p@const LOCATION loc, LOCATION* result) { CHAIN chain = g@redirect_find(v@loc); g@liberties_fetch(v@chain, result); } #endif COUNT g@get_adjacency_count(p@const LOCATION loc) { CHAIN chain = g@redirect_find(v@loc); return g@adjacencies_count(v@chain); // return gr@chains_n_adjacencies[chain]; } #if 0 void g@get_adjacencies(p@LOCATION loc, struct g@result* result) { CHAIN chain = g@redirect_find(v@loc); result->count = gr@chains_n_adjacencies[chain]; BASIC* chain_next_base = g@adjacencies_next[chain]; BASIC ptr = g@chain_next_base[g@ADJACENT_HEADER_OFFSET]; for(COUNT i = gr@chains_n_adjacencies[chain]; i > 0; i--) { result->locations[i] = ptr; ptr = g@chain_next_base[ptr]; } } #else void g@get_adjacencies(p@const LOCATION loc, LOCATION* result) { CHAIN chain = g@redirect_find(v@loc); g@adjacencies_fetch(v@chain, result); /* BASIC* chain_next_base = g@adjacencies_next[chain]; BASIC ptr = chain_next_base[g@ADJACENT_HEADER_OFFSET]; for(COUNT i = gr@chains_n_adjacencies[chain]; i > 0; i--) { *(result++) = ptr; ptr = chain_next_base[ptr]; } */ } #endif COUNT g@get_total_stone_count(p@const COLOR color) { return gr@players_n_stones_of_color[color]; } COUNT g@get_prisoner_count(p@const COLOR color) { return gr@players_n_prisoners_of_color[color]; } #{comment_seperator("Ladder")} void g@print_board(p@char *note) { char tmp[1000]; g@board_to_string(v@tmp); printf("ladder %s\\n %s\\n", note, tmp); fflush(stdout); } bool g@can_capture_in_ladder(p@const LOCATION loc) { const COUNT n_liberties = g@get_liberty_count(v@loc); if(n_liberties > 2) return false; if(n_liberties < 2) return true; LOCATION liberties[2]; g@get_liberties(v@loc, liberties); for(COUNT i = 0; i < 2; i++) { const int result = g@play(v@OPPONENT(gr@locations_color[loc]), liberties[i]); if(result != SUCCESS) continue; const bool bCanCapture = !g@can_escape_from_ladder(v@loc); g@undo(v@); // g@print_board(v@bCanCapture ? "can capture" : "cannot capture"); if(bCanCapture) return true; } return false; } bool g@can_escape_from_ladder(p@const LOCATION loc) { // check if already free const COUNT n_liberties = g@get_liberty_count(v@loc); if(n_liberties > 1) return true; if(n_liberties < 1) return false; LOCATION liberties[1]; g@get_liberties(v@loc, liberties); // escape by extending for(COUNT i = 0; i < 1; i++) { const int result = g@play(v@gr@locations_color[loc], liberties[i]); if(result != SUCCESS) continue; const bool bCanEscape = !g@can_capture_in_ladder(v@loc); g@undo(v@); // g@print_board(v@bCanEscape ? "can escape" : "cannot escape"); if(bCanEscape) return true; } // escape by capturing a surrounding chain const COUNT n_adjacencies = g@get_adjacency_count(v@loc); CHAIN* chains = alloca(sizeof (LOCATION) * n_adjacencies); g@get_adjacencies(v@loc, chains); for(COUNT i = 0; i < n_adjacencies; i++) { const bool atari = g@liberties_atari(v@chains[i]); if(!atari) continue; LOCATION liberties2[1]; g@get_liberties(v@chains[i], liberties2); const int result = g@play(v@gr@locations_color[loc], liberties2[0]); if(result != SUCCESS) continue; const bool bCanEscape = !g@can_capture_in_ladder(v@loc); g@undo(v@); if(bCanEscape) return true; } return false; } void g@board_to_string(p@char buffer[]) { for(int i = 0; i < #{logical_board_width ** 2 + 2 * logical_board_width}; i++) { buffer[i] = '\\0'; } int i = 0; for(int y = g@LOGICAL_BOARD_WIDTH - 1; y >= 0; y--) { for(int x = 0; x < g@LOGICAL_BOARD_WIDTH; x++) { LOCATION loc = g@location_computeZ(x, y); switch(g@get_state(v@loc)) { case EMPTY: buffer[i++] = (g@IS_HOSHI(loc) ? '+' : '.'); break; case BLACK: buffer[i++] = '#'; break; case WHITE: buffer[i++] = 'O'; break; case BORDER: buffer[i++] = '$'; break; default: buffer[i++] = '?'; break; } } buffer[i++] = '\\n'; } } static void g@get_check_liberties(p@CHAIN c, struct location_set* res) { res->count = 0; LOCATION loc, *state; g@FOR_ALL_BOARD_LOCATIONS(loc, state) { if(gr@locations_color[loc] != EMPTY) continue; LOCATION n, *state2; g@FOR_ALL_NEIGHBORS(n, loc, state2) { if(gr@locations_color[n] == EMPTY) continue; if(gr@locations_color[n] == BORDER) continue; CHAIN c2 = g@redirect_find_2(v@n); if(c == c2) { res->locs[res->count++] = loc; break; } } } } static bool g@verify_all_libs(p@) { LOCATION loc, *state; g@FOR_ALL_BOARD_LOCATIONS(loc, state) { switch(gr@locations_color[loc]) { case BLACK: case WHITE: { CHAIN c = g@redirect_find_2(v@loc); struct location_set res; g@get_check_liberties(v@c, &res); if(!g@liberties_verify(v@c, &res)) return false; } default: break; } } return true; } bool g@check_board(p@) { if(!g@verify_all_libs(v@)) return false; LOCATION loc, *state; g@FOR_ALL_BOARD_LOCATIONS(loc, state) { switch(gr@locations_color[loc]) { case EMPTY: case BORDER: { CHAIN c = g@redirect_find_2(v@loc); if(c != loc) { printf("border, empty: chain %d != loc %d\\n", c, loc); return false; } if(false && gr@chains_n_stones[c] != 0) { printf("border, empty: size == %d\\n", gr@chains_n_stones[c]); return false; } break; } case BLACK: case WHITE: { // verify that current loc is in the current chain CHAIN c = g@redirect_find_2(v@loc); // ASSERT_TRUE(size[c] >= 1); bool found = false; LOCATION ptr = gr@locations_next_stone[c]; for(int i = gr@chains_n_stones[c]; i > 0; i--) { if(ptr == loc) found = true; ptr = gr@locations_next_stone[ptr]; } if(!found) { printf("black, white: loc %d not in chain\\n"); return false; } // verify that all neighbors are in the current chain LOCATION n, *state; g@FOR_ALL_NEIGHBORS(n, c, state) { if(gr@locations_color[n] == gr@locations_color[c]) { CHAIN cn = g@redirect_find_2(v@n); CHAIN cc = g@redirect_find_2(v@c); if(cn != cc) { printf("locs %d and %d in separate chains\\n", n, c); return false; } } } break; } default: { printf("bad color %d at loc %d\\n", gr@locations_color[loc], loc); return false; } } } return true; } QQQQQ_54 return text end ############################################################################### def generate_checkpoint_functions text = < err end end ############################################################################### def test_number_of_moves return (logical_board_size * 9) / 10 end ############################################################################### $ptest_c_calls = "" def generate_ptest_c_header ptest_c_text = < #include #include "board.h" static int return_code = 0; #define ASSERT_TRUE(a) do { if(!(a)) { printf("%s %d: %s or %d\\n", __FILE__, __LINE__, #a, (int)a); return_code = 1; /* return; */ } } while(0) #define ASSERT_FALSE(a) do { if((a)) { printf("%s %d: %s or %d\\n", __FILE__, __LINE__, #a, (int)a); return_code = 1; /* return; */ } } while(0) #define ASSERT_EQ(a, b) do { if((a) != (b)) { printf("%s %d: %s or %d != %s or %d\\n", __FILE__, __LINE__, #a, (int)a, #b, (int)(b)); return_code = 1; /* return; */ } } while(0) #define ASSERT_NE(a, b) do { if((a) == (b)) { printf("%s %d: %s or %d == %s or %d\\n", __FILE__, __LINE__, #a, (int)a, #b, (int)(b)); return_code = 1; /* return; */ } } while(0) void shuffle(COUNT length, LOCATION locs[]) { for(int last = length - 1; last > 0; last--) { BASIC rnd = rand_get_range(last + 1); BASIC temp = locs[rnd]; locs[rnd] = locs[last]; locs[last] = temp; } } QQQQQ_55 begin $ptest_c_file.puts replace(ptest_c_text) rescue => err end end def generate_ptest_c ptest_c_text = < err end $ptest_c_calls += "\t#{gv("driver")}();\n" end def generate_ptest_c_footer ptest_c_text = < err end end ############################################################################### $ftest_c_calls = "" $ftest_prefixes = [] $ftest_params = [] $ftest_vars = [] $ftest_params_only = [] $ftest_vars_only = [] def generate_ftest_c_header ftest_c_text = < #include #include "board.h" #define ASSERT_TRUE(a) do { if(!(a)) { printf("%s %d: %s or %d\\n", __FILE__, __LINE__, #a, (int)a); return_code = 1; /* return; */ } } while(0) #define ASSERT_FALSE(a) do { if((a)) { printf("%s %d: %s or %d\\n", __FILE__, __LINE__, #a, (int)a); return_code = 1; /* return; */ } } while(0) #define ASSERT_EQ(a, b) do { if((a) != (b)) { printf("%s %d: %s or %d != %s or %d\\n", __FILE__, __LINE__, #a, (int)a, #b, (int)(b)); return_code = 1; /* return; */ } } while(0) #define ASSERT_NE(a, b) do { if((a) == (b)) { printf("%s %d: %s or %d == %s or %d\\n", __FILE__, __LINE__, #a, (int)a, #b, (int)(b)); return_code = 1; /* return; */ } } while(0) static int return_code = 0; static bool in_list(BASIC value, COUNT length, BASIC list[]) { for(int i = 0; i < length; i++) { if(value == list[i]) return true; } return false; } void shuffle(COUNT length, LOCATION locs[]) { for(int last = length - 1; last > 0; last--) { BASIC rnd = rand_get_range(last + 1); BASIC temp = locs[rnd]; locs[rnd] = locs[last]; locs[last] = temp; } } QQQQQ_58 begin $ftest_c_file.puts replace(ftest_c_text) rescue => err end end def generate_ftest_c ftest_c_text = < err end $ftest_c_calls += "\tg@driver();\n" $ftest_prefixes = $ftest_prefixes + [ fetch_prefix ] $ftest_params = $ftest_params + [ hidden_param ] $ftest_vars = $ftest_vars + [ hidden_var ] $ftest_params_only = $ftest_params_only + [ hidden_param_only ] $ftest_vars_only = $ftest_vars_only + [ hidden_var_only ] end def generate_ftest_c_footer ftest_c_text = < err end end ############################################################################### def check_empty(tokens) all_ok = true if tokens.length != 1 $stderr.puts "there must be exactly no arguments\\n" all_ok = false end return all_ok end def check_tokens(tokens, valid_tokens) all_ok = true found = false valid_tokens.each do |possible| if tokens[1] == possible found = true break end end if !found $stderr.puts "argument must be in set #{valid_tokens * ','}\n" all_ok = false end if tokens.length != 2 $stderr.puts "there must be exactly 1 argument\n" all_ok = false end return all_ok end def check_string(tokens) all_ok = true # if(line->tokens[1][0] != '\"' || line->tokens[1][strlen(line->tokens[1]) - 1] != '\"') { # $stderr.puts "argument must be a string\n" # all_ok = false # end if tokens.length != 2 $stderr.puts "there must be exactly 1 argument\n" all_ok = false end return all_ok end def check_arguments(tokens) all_ok = true case find_symbol(tokens[0]) when :RESET all_ok = check_empty tokens if all_ok reset_current_attr_set end when :GENERATE all_ok = check_empty tokens if all_ok generate_board_h generate_board_c generate_ptest_c generate_ftest_c $generate_number += 1 end when :PREFIX, :SUFFIX all_ok = check_string(tokens) if all_ok store_in_current_attr_set tokens end when :BOARD_SIZE valid_args = [ "5", "7", "9", "11", "13", "15", "17", "19" ] all_ok = check_tokens(tokens, valid_args) if all_ok store_in_current_attr_set tokens end when :KO_RULE valid_args = [ "simple_ko", "pos_super_ko", "sit_super_ko", "setable" ] all_ok = check_tokens(tokens, valid_args) if all_ok store_in_current_attr_set tokens end when :SUICIDE_RULE valid_args = [ "allowed", "disallowed", "setable" ] all_ok = check_tokens(tokens, valid_args) if all_ok store_in_current_attr_set tokens end when :MAX_MOVES valid_args = [ "400", "1000", "2000" ] # number of moves all_ok = check_int(tokens, valid_args) if all_ok store_in_current_attr_set tokens end when :HASH_WIDTH valid_args = [ "4", "8", "16" ] # number of bytes all_ok = check_int(tokens, valid_args) if all_ok store_in_current_attr_set tokens end when :TRACK_LIBERTIES valid_args = [ "arrays", "dense_links", "sparse_links", "boesch", "simple", "bitset" ] all_ok = check_tokens(tokens, valid_args) if all_ok store_in_current_attr_set tokens end when :LOCATION_TO_CHAIN valid_args = [ "strict", "union_find" ] all_ok = check_tokens(tokens, valid_args) if all_ok store_in_current_attr_set tokens end when :BORDER_TYPE valid_args = [ "overlap", "unique" ] all_ok = check_tokens(tokens, valid_args) if all_ok store_in_current_attr_set tokens end when :TRACK_ADJACENCIES valid_args = [ "arrays", "dense_links", "sparse_links", "search" ] all_ok = check_tokens(tokens, valid_args) if all_ok store_in_current_attr_set tokens end when :FOR_ALL_NEIGHBORS valid_args = [ "delta_checks", "deltas", "absolutes" ] all_ok = check_tokens(tokens, valid_args) if all_ok store_in_current_attr_set tokens end when :NORMAL_MOVE valid_args = [ "1", "2" ] all_ok = check_tokens(tokens, valid_args) if all_ok store_in_current_attr_set tokens end when :INVALID_CODE valid_args = [ "0", "-1" ] all_ok = check_tokens(tokens, valid_args) if all_ok store_in_current_attr_set tokens end when :SET_KO_LOC valid_args = [ "1", "2" ] all_ok = check_tokens(tokens, valid_args) if all_ok store_in_current_attr_set tokens end when :TRIPLE_KO valid_args = [ "none", "williams", "critter" ] all_ok = check_tokens(tokens, valid_args) if all_ok store_in_current_attr_set tokens end when :INTERFACE valid_args = [ "simple", "index", "pointer" ] all_ok = check_tokens(tokens, valid_args) if all_ok store_in_current_attr_set tokens end when :NUMBER_OF_GAMES valid_args = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16" ] all_ok = check_tokens(tokens, valid_args) if all_ok store_in_current_attr_set tokens end when :NUMBER_OF_BACKUPS valid_args = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32" ] all_ok = check_tokens(tokens, valid_args) if all_ok store_in_current_attr_set tokens end when :BORDER, :CHECK_INTERNALS, :DO_UNDO, :DO_GET_LIBERTIES, :DO_GET_ADJACENCIES, :DO_GET_ALL_CHAINS, :DO_CHECKPOINT, :DO_INSTRUMENTATION, :DO_TRACK_EMPTIES, :INLINE_CAPTURE_AND_MERGE, :UNROLL_IN_CAPTURE_AND_MERGE, :LAZY_CHAIN_INITIALIZATION, :PARALLEL_ARRAYS_FOR_RECORDS, :SPECIALIZE_ON_COLOR, :ALTER_BORDER_CHAINS, :UNROLL_IN_PLAY_AND_SUICIDE, :UNROLL_IN_LEGAL, :USE_LRO_STRUCTS, :USE_ZRO_STRUCTS, :USE_BOARD_STRUCTS, :UNSIGNED_SHORT valid_args = [ "true", "false" ] all_ok = check_tokens(tokens, valid_args) if all_ok store_in_current_attr_set tokens end else $stderr.puts "unknown parameter\n" all_ok = false end return all_ok end ############################################################################### def process_line(count, line) tokens = line.split if tokens.length == 0 return end if tokens[0][0..0] == '#' return end if !(is_present tokens[0]) $stderr.puts "process_line: token not present in " + (tokens * ",") elsif !(check_arguments tokens) $stderr.puts "process_line: bad arguments in " + (tokens * ",") else $stderr.puts "#{count}: found #{line}" end end def process_file(filename) begin counter = 1 config_file = File.open(filename) config_file.each do |line| process_line counter, line counter = counter + 1 end config_file.close rescue => err puts "Exception: #{err}" end end ############################################################################### $iCGBG_VERSION = "Version 0.1, Copyright 2008 the Critters" def print_usage() puts "cgbg usage:\n" puts "\tcgbg print usage\n" puts "\tcgbg -usage print usage\n" puts "\tcgbg generate files based on config\n" puts $iCGBG_VERSION + "\n" end if ARGV.length == 0 print_usage puts "ok\n" exit 0 end if ARGV.length == 1 && ARGV[0] == "-usage" print_usage puts "ok\n" exit 0 end if ARGV.length > 1 print_usage puts "err\n" exit 1 end begin $make_file = File.new("Makefile", "w") rescue => err $stderr.puts 'unable to open "Makefile"\n' exit 2 end begin $board_h_file = File.new("board.h", "w") rescue => err $stderr.puts 'unable to open "board.h"\n' exit 2 end begin $board_c_file = File.new("board.c", "w") rescue => err $stderr.puts 'unable to open "board.c"\n' exit 2 end begin $ptest_c_file = File.new("ptest.c", "w") rescue => err $stderr.puts 'unable to open "ptest.c"\n' exit 2 end begin $ftest_c_file = File.new("ftest.c", "w") rescue => err $stderr.puts 'unable to open "ftest.c"\n' exit 2 end generate_makefile generate_board_h_header generate_board_c_header generate_ftest_c_header generate_ptest_c_header process_file ARGV[0] generate_board_h_footer generate_ftest_c_footer generate_ptest_c_footer $make_file.close $board_h_file.close $board_c_file.close $ptest_c_file.close $ftest_c_file.close ###############################################################################