diff --git a/json_generator.py b/json_generator.py index 04f1fd3..1a5ce14 100644 --- a/json_generator.py +++ b/json_generator.py @@ -1,18 +1,15 @@ import json import random + import project_constants as const +# import tile class +import tile as tl -# auxiliary function that returns random attribute values based on their type -def _get_random_attribute_values(self, attr_type, grid_dimensions): - num_of_rows, num_of_columns = grid_dimensions - - if attr_type == int: - # temporary solution - return random.randint(num_of_rows + num_of_columns, (2 * num_of_rows + num_of_columns)) - - else: - return None +# import mine models +import mine_models.standard_mine as sm +import mine_models.time_mine as tm +import mine_models.chained_mine as cm class JsonGenerator: @@ -24,12 +21,9 @@ class JsonGenerator: self.agents_initial_position = agents_initial_position self.agents_initial_direction = agents_initial_direction - # getting position coordinates - starting_row, starting_column = agents_initial_position - # saving data to the grid dictionary self.grid["agents_initial_state"] = { - "position": str(starting_row) + ',' + str(starting_column), + "position": format_position_to_str(agents_initial_position), "direction": agents_initial_direction } @@ -39,19 +33,16 @@ class JsonGenerator: self.agents_initial_position = position self.agents_initial_direction = direction - # getting position coordinates - starting_row, starting_column = position - # setting new agent's initial state self.grid["agents_initial_state"] = { - "position": str(starting_row) + ',' + str(starting_column), + "position": format_position_to_str(position), "direction": direction } # overwrites grid field with a new grid with randomized colors and mines def generate_randomized_grid(self, dimensions, mine_appearance_chance=0.15, predecessor_chance_decrease=0.25): # clearing grid field - self.clear_tile_dictionary() + self.clear_grid() # getting grid dimensions num_of_rows, num_of_columns = dimensions @@ -60,6 +51,7 @@ class JsonGenerator: for i in range(num_of_rows): for j in range(num_of_columns): + # picking random values for tiles random_tile_color = random.choice(const.STRUCT_TILE_COLORS) @@ -86,7 +78,7 @@ class JsonGenerator: random_attribute_values = [] for attr_type in const.STRUCT_MINE_ATTRIBUTE_TYPES[random_mine_type]: - random_attribute_values.append(_get_random_attribute_values(self, attr_type, dimensions)) + random_attribute_values.append(_get_random_attribute_values(attr_type, dimensions)) # adding the mine self.set_a_mine((i, j), random_mine_type, random_attribute_values) @@ -94,15 +86,14 @@ class JsonGenerator: # if is ChainedMine create predecessors if random_mine_type == "chained": predecessor_appearance_chance = 1.0 - current_tile = str(i) + ',' + str(j) + current_tile = format_position_to_str((i, j)) # create chained predecessors while random.random() < predecessor_appearance_chance and len(tile_pool) > 0: predecessor_appearance_chance -= predecessor_chance_decrease predecessor_position = random.choice(tile_pool) - pre_row, pre_column = predecessor_position - predecessor = str(pre_row) + ',' + str(pre_column) + predecessor = format_position_to_str(predecessor_position) tile_pool.remove(predecessor_position) self.set_a_mine(predecessor_position, "chained", []) @@ -114,19 +105,14 @@ class JsonGenerator: # adds a new tile or edits an existing one in the grid field def add_tile(self, position, color): - # getting added/edited tile's index values - row, column = position - # creating new tile without a mine - self.grid[str(row) + ',' + str(column)] = { + self.grid[format_position_to_str(position)] = { "color": color, "mine": None } # adds a new tile with a mine or edits an existing one in the grid field def add_tile_with_a_mine(self, position, color, mine_type, attribute_values): - # getting added/edited tile's index values - row, column = position # setting mine data using attribute_values mine_values = const.STRUCT_MINE_ATTRIBUTES[mine_type] @@ -135,29 +121,23 @@ class JsonGenerator: mine_values[key] = attribute_values.pop(0) # creating a new tile - self.grid[str(row) + ',' + str(column)] = { + self.grid[format_position_to_str(position)] = { "color": color } # updating the tile with a mine field - self.grid[str(row) + ',' + str(column)]["mine"] = {} + self.grid[format_position_to_str(position)]["mine"] = {} for key in mine_values.keys(): - self.grid[str(row) + ',' + str(column)]["mine"][key] = mine_values[key] + self.grid[format_position_to_str()]["mine"][key] = mine_values[key] # deletes a mine with a given position from the grid field def delete_a_tile(self, position): - # getting tile's index values - row, column = position - # deleting a tile with given key - self.grid.pop(str(row) + ',' + str(column)) + self.grid.pop(format_position_to_str(position)) # adds a mine to a tile stored in the grid field def set_a_mine(self, position, mine_type, attribute_values): - # getting edited tile's index values - row, column = position - # setting mine data using attribute_values mine_values = const.STRUCT_MINE_ATTRIBUTES[mine_type] @@ -166,34 +146,36 @@ class JsonGenerator: mine_values[key] = attribute_values.pop(0) # adding a mine to the edited tile - self.grid[str(row) + ',' + str(column)]["mine"] = {} + self.grid[format_position_to_str(position)]["mine"] = {} for key in mine_values.keys(): - self.grid[str(row) + ',' + str(column)]["mine"][key] = mine_values[key] + self.grid[format_position_to_str(position)]["mine"][key] = mine_values[key] # deletes a mine from a tile stored in the grid field def delete_a_mine(self, position): - # getting edited tile's index values - row, column = position - # removing mine from the edited tile - self.grid[str(row) + ',' + str(column)]["mine"] = None + self.grid[format_position_to_str(position)]["mine"] = None + + # returns chosen tiles data + def get_tile(self, position): + return self.grid[format_position_to_str(position)] + + # returns chosen mines data + def get_mine(self, position): + return self.grid[format_position_to_str(position)]["mine"] # returns the grid field - def get_tile_dictionary(self): + def get_grid(self): return self.grid # clears the grid field - def clear_tile_dictionary(self): + def clear_grid(self): # clearing grid dict self.grid.clear() - # getting agent's starting position coordinates - starting_row, starting_column = self.agents_initial_position - # re-setting the agent's initial state self.grid["agents_initial_state"] = { - "position": str(starting_row) + ',' + str(starting_column), + "position": format_position_to_str(self.agents_initial_position), "direction": self.agents_initial_direction } @@ -226,3 +208,118 @@ class JsonGenerator: with open(file_path, "w") as output_file: # saving the newly created grid json.dump(new_grid, output_file, indent=2, sort_keys=True) + + +# STATIC "PUBLIC" FUNCTIONS + +# creates a Mine (Standard or Time or Chained) instance from mine dict data +# doesn't link chained mines, since it has no actual access to a grid +def create_a_mine(mine_dict, position): + # initializing a mine with no value + mine = None + + # if mine doesn't exist - returning None + if mine_dict is None: + return mine + + # formatting position to right format - in case it's not + position = format_position_to_tuple(position) + + # if mine's type is "standard" - creating standard mine + if mine_dict["mine_type"] == "standard": + mine = sm.StandardMine(position) + + # if mine's type is "time" - creating time mine + elif mine_dict["mine_type"] == "time": + timer_value = mine_dict["timer"] + mine = tm.TimeMine(position, timer_value) + + # if mine's type is "chained" - creating chained mine (no successors assigned yet) + elif mine_dict["mine_type"] == "chained": + mine = cm.ChainedMine(position) + + return mine + + +# creates a Tile instance with a mine (if a mine exists) from tile dict data +def create_a_tile(tile_dict, position): + # formatting position to right format - in case it's not + position = format_position_to_tuple(position) + + # getting tile's parameters + color = tile_dict["color"] + mine = create_a_mine(position, tile_dict["mine"]) + + # creating and returning a tile with the parameters set above + return tl.Tile(position, color, mine) + + +# returns a list of tuples containing chained mine's position and it's predecessors position +# data is in format [(chained_mine_position, its_predecessors_position), ...] +def get_chained_mine_and_its_predecessor_pairs(minefield_dictionary): + predecessors = list() + + # iterate for each key in the grid field + for key in minefield_dictionary.keys(): + # if a chained mine with predecessor exists - adding it's and it's predecessors positions as a tuple to a list + if key != "agents_initial_state" and minefield_dictionary[key]["mine"] is not None\ + and minefield_dictionary[key]["mine"]["mine_type"] == "chained"\ + and minefield_dictionary[key]["mine"]["predecessor"] is not None: + + # getting the chained mines and it's predecessors positions + this_mines_position = tuple(int(i) for i in key.split(',')) + its_predecessors_position = tuple(int(i) for i in minefield_dictionary[key]["mine"]["predecessor"].split(',')) + + # adding the positions to the list as a tuple + predecessors.append((this_mines_position, its_predecessors_position)) + + return predecessors + + +# changes position from str or tuple format to str format +def format_position_to_str(position): + # if mine's position is in "row,column" format - that means position parameter is already in good format + if isinstance(position, str): + pass + + # if mine's position is in (row:int, column:int) - creating string from tuple + elif isinstance(position, tuple) and list(map(type, position)) == [int, int]: + row, column = position + return str(row) + ',' + str(column) + + # if mine's position is not in any of 2 formats above - returning None - unsupported format + else: + return None + + return position + + +# changes position from str or tuple format to tuple format +def format_position_to_tuple(position): + # if mine's position is in "row,column" format - getting parameters from string + if isinstance(position, str): + position = tuple(int(i) for i in position.split(',')) + + # if mine's position is in (row:int, column:int) - that means position parameter is already in good format + elif isinstance(position, tuple) and list(map(type, position)) == [int, int]: + pass + + # if mine's position is not in any of 2 formats above - returning None - unsupported format + else: + return None + + return position + + +# AUXILIARY "PRIVATE" FUNCTIONS + +# auxiliary function that returns random attribute values based on their type +def _get_random_attribute_values(attr_type, grid_dimensions): + num_of_rows, num_of_columns = grid_dimensions + + if attr_type == int: + # temporary solution + return random.randint(num_of_rows + num_of_columns, (2 * num_of_rows + num_of_columns)) + + else: + return None