def clear_prev_path_data(self): # these work like traditional arrays self.path.clear() self.pq_arr.clear() # added call number to each cell in the lookup table so that when contain key is called # it checks the call number of the cell, even if contains_key prop is true, if the call number # is not the same as the current call number it knows its from a different call. set sets # the call number. Because of this memset is not needed. self.g_arr.size = array_capacity(self.g_arr) self.came_from.size = array_capacity(self.came_from)
def check_lookup_table_size(self, game: Game): # check to see if the pathfinder capacity on the lookup tables is large # enough for the max map. path and pq_arr are not lookup tables, just regular arrays. map_row_ratio = game.max_map_size.x * game.move_grid_ratio map_col_ratio = game.max_map_size.y * game.move_grid_ratio map_max_capacity = map_row_ratio * map_col_ratio g_arr_capacity = array_capacity(self.g_arr) came_from_capacity = array_capacity(self.came_from) if g_arr_capacity < map_max_capacity or came_from_capacity < map_max_capacity: print( "PathFinder.check_lookup_table_size - path_finder g_arr capacity or came_from capacity is not large enough for the max size map.\nMax map size:", map_max_capacity, "\ng_arr capacity:", g_arr_capacity, "\ncame_from capacity:", came_from_capacity) exit(1)
def push_value(arr, value): capacity = array_capacity(arr) if arr.size > capacity - 1: print("push_value - array size is > than capacity - 1.", "size:", arr.size, "capacity:", capacity) exit(1) arr[arr.size] = value arr.size += 1
def push(arr, value_ptr): capacity = array_capacity(arr) if arr.size > capacity - 1: print("push - array size is > than capacity - 1.", "size:", arr.size, "capacity:", capacity) exit(1) arr[arr.size] = deref(value_ptr) arr.size += 1
def next_handle(arr): capacity = array_capacity(arr) if arr.size > capacity - 1: print("next_handle - array size is > than capacity - 1.", "size:", arr.size, "capacity:", capacity) exit(1) handle = arr.size arr.size += 1 return handle
def next(arr): capacity = array_capacity(arr) if arr.size > capacity - 1: print("next - array size is > than capacity - 1.", "size:", arr.size, "capacity:", capacity) exit(1) value = addr(arr[arr.size]) arr.size += 1 return value
def init(self, game: Game): self.units.size = array_capacity(self.units) last_enum_idx = last_enum_int(UnitName) if last_enum_idx > self.units.size - 1: print("UnitDB.init - UnitName's last enum idx is > units capacity.") exit(1) # skip NA by starting at 1 for i in range(1, last_enum_idx): unit_name = cast(i, "UnitName") game.temp_unit.init(game, 0) game.temp_unit.set_to(game, unit_name, Faction.Ally) self.units[i] = game.temp_unit
def init(self, game: Game): self.items.size = array_capacity(self.items) last_enum_idx = last_enum_int(ItemName) if last_enum_idx > self.items.size - 1: print( "ItemDB.init - ItemName's last enum idx is > items capacity.") exit(1) # skip NA by starting at 1 for i in range(1, last_enum_idx): item_name = cast(i, "ItemName") game.temp_item.set_to(game, item_name) self.items[i] = game.temp_item
def init(self, game: Game): self.abilities.size = array_capacity(self.abilities) last_enum_idx = last_enum_int(AbilityName) if last_enum_idx > self.abilities.size - 1: print( "AbilityDB.init - AbilityName's last enum idx is > abilities capacity." ) exit(1) # skip NA by starting at 1 for i in range(1, last_enum_idx): ability_name = cast(i, "AbilityName") game.temp_ability.set_to(game, ability_name) self.abilities[i] = game.temp_ability
def string_set(arr1, arr2): # arr1 and arr2 are both of type Array of char capacity = array_capacity(arr1) buffer1 = array_get_buffer(arr1) buffer2 = array_get_buffer(arr2) if arr2.size > capacity - 1: print("string_set - arr2.size > then the capacity of arr1", "\narr2.size:", arr2.size, "\narr1 capacity:", capacity, "\narr1 str:", buffer1, "\narr2 str:", buffer2) exit(1) strcpy(buffer1, buffer2) arr1.size = arr2.size
def string_set_literal(arr, string_literal): # arr is of type Array of char, string literal is of type char* capacity = array_capacity(arr) length = strlen(string_literal) buffer = array_get_buffer(arr) if length > capacity - 1: print( "string_set_literal - string literal length is > then the capacity of arr.", "\nstring literal length:", length, "\narr capacity:", capacity, "\narr str:", buffer, "\nstring_literal:", string_literal) exit(1) strcpy(buffer, string_literal) arr.size = length
def pool_get_handle(arr, last_in_use_handle_ptr: int, debug_pool_name_char_ptr) -> int: last_in_use_handle = deref(last_in_use_handle_ptr) for i, item in enumerate(arr): if not (item.in_use_in_pool): item.in_use_in_pool = True # update last_in_use_handle_ptr if the handle returned # is greater than the last_in_use_handle_ptr value if i > last_in_use_handle: set(deref(last_in_use_handle_ptr), i) return i capacity = array_capacity(arr) print("pool_get_handle - all elements are in use.") print("pool name:", debug_pool_name_char_ptr, "\npool size: ", arr.size, "\npool capacity:", capacity) exit(1)
def string_cat_literal(arr, string_literal): # arr is of type Array of char, string literal is of type char* capacity = array_capacity(arr) length = strlen(string_literal) buffer = array_get_buffer(arr) # nothing to cat if length == 0: return # if arr1 size is 0 make sure it has a null terminator by doing a strcpy of an empty string. # a size of 0 might mean its unitialized. if arr.size == 0: string_set_literal(arr, "") if arr.size + length > capacity - 1: print( "string_cat_literal - arr.size + string literal length is > then the capacity of arr.", "\narr size:", arr.size, "\nstring literal length:", length, "\narr capacity:", capacity, "\narr str:", buffer, "\nstring_literal:", string_literal) exit(1) strcat(buffer, string_literal) arr.size += length
def string_cat(arr1, arr2): # arr1 and arr2 are both of type Array of char capacity = array_capacity(arr1) buffer1 = array_get_buffer(arr1) buffer2 = array_get_buffer(arr2) # nothing to cat if arr2.size == 0: return # if arr1 size is 0 make sure it has a null terminator by doing a strcpy of an empty string. # a size of 0 might mean its unitialized. if arr1.size == 0: string_set_literal(arr1, "") if arr1.size + arr2.size > capacity - 1: print( "string_cat - arr1.size + arr2.size is > then the capacity of arr.", "\narr1 size:", arr1.size, "\narr2 size:", arr2.size, "\narr capacity:", capacity, "\narr1 str:", buffer1, "\narr2 str:", buffer2) exit(1) strcat(buffer1, buffer2) arr1.size += arr2.size
def set_path(self, game: Game, map: Map, acting_unit: Unit, p1: SDL_Point, p2: SDL_Point, check_unit_collissions: bool): # inc call number, doens't matter if it overflows just needs to be unique for each call self.call_number += 1 # if the call number if 0 it means it overflowed, clear the tables so that previous # call numbers won't be treated as valid. Imagine call number 5 is set in a cell from the # previous 0 - MAX_SIZE iteration, if the current call number is 5 it will treat it as valid, # even though it is from the previous 0 - MAX_SIZE iteration if self.call_number == 0: memset(addr(self.g_arr), 0, 1) memset(addr(self.came_from), 0, 1) # reset size as it was just zero'd out self.g_arr.size = array_capacity(self.g_arr) self.came_from.size = array_capacity(self.came_from) # finally inc call number to 1 so that 0 call number values from memset are not # treated as valid from this call number (that would mean every cell was valid) self.call_number = 1 # clear previous path data self.clear_prev_path_data() # make copies of p1 and p2 because there was a weird mutation bug start = deref(p1) target = deref(p2) # closest point to target - is only valid if find_closest_target param is true self.closest_point_to_target = start self.closest_dist_to_target = manhattan_distance(start, target) tile_point_hit_box_cpy = acting_unit.tile_point_hit_box if not(map.in_bounds_move_grid(target)): print("PathFinder.set path - target_point is not in bounds.") exit(1) if points_are_equal(start, target): print("Pathfinder.set_path - start and target points are equal.") return iters = 0 reconstruct_path_iters = 0 # max iters for now is the path capacity, though iters can be greater than # the number of tiles in the map if it gets stuck and needs go around obstacles. # a good starting point though, change later if people struggle to find paths. max_iters = array_capacity(self.path) # not sure if this is true but keeping it for now if max_iters > array_capacity(self.path): print("PathFinder.set_path max_iters must be <= path capacity") exit(1) neighbors = Array[SDL_Point](4) # set size directly because it will be manipulated with random access below neighbors.size = 4 path_node = PathNode() path_node.p = start path_node.g = 0 # self.g_arr.push(path_node) insert_point(self.g_arr, path_node.p, path_node, map.rows, self.call_number) pq_node = PQNode() pq_node.p = start pq_node.f = manhattan_distance(start, target) self.pq_arr.push(pq_node) came_from = CameFrom() # don't exit if iters fails, it just means a path couldn't be found. # it is not likely an error condition (althought it could be) while iters < max_iters and self.pq_arr.size > 0: iters += 1 # pop last idx from pq_arr. It is sorted so it is the # node with the min f value. pq_last_idx = self.pq_arr.size - 1 current = self.pq_arr[pq_last_idx] self.pq_arr.size -= 1 if points_are_equal(current.p, target): # print("Found target in", iters, "iters") self.path.push(target) while arr_contains_key(self.came_from, current.p, map.rows, self.call_number): reconstruct_path_iters += 1 if reconstruct_path_iters > max_iters: print( "PathFinder.set_path - reconstruct_path iters > max_iters.") exit(1) came_from_handle = get_1d_from_2d_idx(current.p, map.rows) came_from_ptr = self.came_from.at(came_from_handle) current.p = came_from_ptr.to_point if not(points_are_equal(current.p, start)): self.path.push(current.p) # reverse the array as it is currently backwards self.path.reverse() return n0 = neighbors.at(0) n1 = neighbors.at(1) n2 = neighbors.at(2) n3 = neighbors.at(3) n0.x = current.p.x + 1 n0.y = current.p.y n1.x = current.p.x - 1 n1.y = current.p.y n2.x = current.p.x n2.y = current.p.y + 1 n3.x = current.p.x n3.y = current.p.y - 1 for n in neighbors: if not(map.in_bounds_move_grid(n)): continue tile_point_hit_box_cpy.x = n.x tile_point_hit_box_cpy.y = n.y if check_unit_collissions and map.unit_occupies_tile_point_move_grid(game, tile_point_hit_box_cpy, acting_unit.handle): continue g_handle = get_1d_from_2d_idx(current.p, map.rows) g_node = self.g_arr.at(g_handle) new_g_cost = g_node.g + 1 neighbor_g_contains_handle = arr_contains_key( self.g_arr, n, map.rows, self.call_number) neighbor_g_handle = get_1d_from_2d_idx(n, map.rows) neighbor_g = -1 if neighbor_g_contains_handle: neighbor_g_node = self.g_arr.at(neighbor_g_handle) neighbor_g = neighbor_g_node.g if not(neighbor_g_contains_handle) or new_g_cost < neighbor_g: f = manhattan_distance(n, target) # update or push g_arr for the neighbor path_node.g = new_g_cost path_node.p = deref(n) insert_point(self.g_arr, path_node.p, path_node, map.rows, self.call_number) # push pq node and sort the pq pq_node.f = f pq_node.p = deref(n) self.pq_arr.push(pq_node) pq_insertion_sort(self.pq_arr) # update or push a new came from to came from arr came_from.from_point = deref(n) came_from.to_point = current.p insert_point(self.came_from, n, came_from, map.rows, self.call_number) # possibly update closest point to target dist = manhattan_distance(current.p, target) if dist > 0 and dist < self.closest_dist_to_target: self.closest_dist_to_target = dist self.closest_point_to_target = current.p
def init(self): self.slots.size = array_capacity(self.slots) # zero'd out memory will set slot is empty to false, it is initially true. for slot in self.slots: slot.slot_is_empty = True
def pool_init(game: Game, arr, last_in_use_handle_ptr: int): arr.size = array_capacity(arr) set(deref(last_in_use_handle_ptr), -1) for i, item in enumerate(arr): item.init(game, i)
def pool_of_text_init(game: Game, arr, last_in_use_handle_ptr: int): # text uses text_init because there are many texts for each string size. arr.size = array_capacity(arr) set(deref(last_in_use_handle_ptr), -1) for i, item in enumerate(arr): item.text_init(game, i)