2021-03-12 20:48:16 +01:00
|
|
|
import json
|
|
|
|
import random
|
|
|
|
import project_constants as const
|
|
|
|
|
|
|
|
|
2021-04-03 23:00:46 +02:00
|
|
|
# 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:
|
2021-04-17 23:22:27 +02:00
|
|
|
return None
|
2021-04-03 23:00:46 +02:00
|
|
|
|
|
|
|
|
2021-03-12 20:48:16 +01:00
|
|
|
class JsonGenerator:
|
|
|
|
grid = dict()
|
|
|
|
|
2021-04-17 23:22:27 +02:00
|
|
|
# constructor that can be used to set agent's initial state
|
|
|
|
def __init__(self, agents_initial_position=(0, 0), agents_initial_direction=const.Direction.UP.value):
|
|
|
|
# saving agent's initial state (position & direction)
|
|
|
|
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),
|
|
|
|
"direction": agents_initial_direction
|
|
|
|
}
|
|
|
|
|
|
|
|
# sets agent's initial state
|
|
|
|
def set_agents_initial_state(self, position=(0, 0), direction=const.Direction.UP.value):
|
|
|
|
# setting fields in the instance
|
|
|
|
self.agents_initial_position = position
|
|
|
|
self.agents_initial_direction = direction
|
2021-03-12 20:48:16 +01:00
|
|
|
|
2021-03-31 21:56:53 +02:00
|
|
|
# getting position coordinates
|
|
|
|
starting_row, starting_column = position
|
|
|
|
|
2021-04-17 23:22:27 +02:00
|
|
|
# setting new agent's initial state
|
|
|
|
self.grid["agents_initial_state"] = {
|
|
|
|
"position": str(starting_row) + ',' + str(starting_column),
|
|
|
|
"direction": direction
|
|
|
|
}
|
2021-03-31 21:56:53 +02:00
|
|
|
|
2021-03-12 20:48:16 +01:00
|
|
|
# overwrites grid field with a new grid with randomized colors and mines
|
2021-04-17 23:22:27 +02:00
|
|
|
def generate_randomized_grid(self, dimensions, mine_appearance_chance=0.15, predecessor_chance_decrease=0.25):
|
2021-03-12 20:48:16 +01:00
|
|
|
# clearing grid field
|
|
|
|
self.clear_tile_dictionary()
|
|
|
|
|
|
|
|
# getting grid dimensions
|
2021-03-14 00:59:00 +01:00
|
|
|
num_of_rows, num_of_columns = dimensions
|
2021-03-12 20:48:16 +01:00
|
|
|
|
2021-04-03 23:00:46 +02:00
|
|
|
tile_pool = []
|
|
|
|
|
2021-03-14 00:59:00 +01:00
|
|
|
for i in range(num_of_rows):
|
|
|
|
for j in range(num_of_columns):
|
2021-03-12 20:48:16 +01:00
|
|
|
# picking random values for tiles
|
|
|
|
random_tile_color = random.choice(const.STRUCT_TILE_COLORS)
|
|
|
|
|
2021-04-17 23:22:27 +02:00
|
|
|
# adding added tile's indexes to a pool
|
2021-04-03 23:00:46 +02:00
|
|
|
tile_pool.append((i, j))
|
|
|
|
|
2021-04-17 23:22:27 +02:00
|
|
|
# creating random tile
|
2021-04-03 23:00:46 +02:00
|
|
|
self.add_tile((i, j), random_tile_color)
|
|
|
|
|
2021-04-17 23:22:27 +02:00
|
|
|
# deleting agent's starting tile from the pool
|
|
|
|
deleted_row, deleted_column = self.agents_initial_position
|
2021-04-03 23:00:46 +02:00
|
|
|
tile_pool.remove((int(deleted_row), int(deleted_column)))
|
|
|
|
|
|
|
|
for i in range(num_of_rows):
|
|
|
|
for j in range(num_of_columns):
|
|
|
|
|
|
|
|
# checking if a mine will appear
|
|
|
|
if random.random() < mine_appearance_chance and len(tile_pool) > 0 and tile_pool.__contains__((i, j)):
|
2021-04-17 23:22:27 +02:00
|
|
|
# removing current tile from the pool
|
2021-04-03 23:00:46 +02:00
|
|
|
tile_pool.remove((i, j))
|
2021-03-27 18:25:26 +01:00
|
|
|
|
2021-04-03 23:00:46 +02:00
|
|
|
# choosing random mine parameters
|
|
|
|
random_mine_type = random.choice(const.STRUCT_MINE_TYPES)
|
2021-03-27 18:25:26 +01:00
|
|
|
random_attribute_values = []
|
|
|
|
|
|
|
|
for attr_type in const.STRUCT_MINE_ATTRIBUTE_TYPES[random_mine_type]:
|
2021-04-03 23:00:46 +02:00
|
|
|
random_attribute_values.append(_get_random_attribute_values(self, attr_type, dimensions))
|
|
|
|
|
|
|
|
# adding the mine
|
|
|
|
self.set_a_mine((i, j), random_mine_type, random_attribute_values)
|
|
|
|
|
|
|
|
# if is ChainedMine create predecessors
|
|
|
|
if random_mine_type == "chained":
|
|
|
|
predecessor_appearance_chance = 1.0
|
|
|
|
current_tile = str(i) + ',' + str(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)
|
|
|
|
tile_pool.remove(predecessor_position)
|
|
|
|
|
|
|
|
self.set_a_mine(predecessor_position, "chained", [])
|
|
|
|
|
|
|
|
self.grid[current_tile]["mine"]["predecessor"] = predecessor
|
|
|
|
self.grid[predecessor]["mine"]["predecessor"] = None
|
2021-03-27 18:25:26 +01:00
|
|
|
|
2021-04-03 23:00:46 +02:00
|
|
|
current_tile = predecessor
|
2021-03-14 00:59:00 +01:00
|
|
|
|
|
|
|
# adds a new tile or edits an existing one in the grid field
|
2021-03-12 20:48:16 +01:00
|
|
|
def add_tile(self, position, color):
|
|
|
|
# getting added/edited tile's index values
|
|
|
|
row, column = position
|
2021-03-31 21:56:53 +02:00
|
|
|
|
2021-03-12 20:48:16 +01:00
|
|
|
# creating new tile without a mine
|
|
|
|
self.grid[str(row) + ',' + str(column)] = {
|
|
|
|
"color": color,
|
|
|
|
"mine": None
|
|
|
|
}
|
|
|
|
|
2021-03-14 00:59:00 +01:00
|
|
|
# adds a new tile with a mine or edits an existing one in the grid field
|
2021-03-27 18:25:26 +01:00
|
|
|
def add_tile_with_a_mine(self, position, color, mine_type, attribute_values):
|
2021-03-12 20:48:16 +01:00
|
|
|
# getting added/edited tile's index values
|
|
|
|
row, column = position
|
2021-03-27 18:25:26 +01:00
|
|
|
# setting mine data using attribute_values
|
|
|
|
mine_values = const.STRUCT_MINE_ATTRIBUTES[mine_type]
|
|
|
|
|
|
|
|
for key in mine_values.keys():
|
|
|
|
if key not in const.HARDCODED_VALUES and len(attribute_values) > 0:
|
|
|
|
mine_values[key] = attribute_values.pop(0)
|
|
|
|
|
|
|
|
# creating a new tile
|
2021-03-12 20:48:16 +01:00
|
|
|
self.grid[str(row) + ',' + str(column)] = {
|
2021-03-27 18:25:26 +01:00
|
|
|
"color": color
|
2021-03-12 20:48:16 +01:00
|
|
|
}
|
|
|
|
|
2021-03-27 18:25:26 +01:00
|
|
|
# updating the tile with a mine field
|
|
|
|
self.grid[str(row) + ',' + str(column)]["mine"] = {}
|
|
|
|
|
|
|
|
for key in mine_values.keys():
|
|
|
|
self.grid[str(row) + ',' + str(column)]["mine"][key] = mine_values[key]
|
|
|
|
|
2021-03-12 20:48:16 +01:00
|
|
|
# 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
|
2021-03-27 18:25:26 +01:00
|
|
|
|
2021-03-12 20:48:16 +01:00
|
|
|
# deleting a tile with given key
|
|
|
|
self.grid.pop(str(row) + ',' + str(column))
|
|
|
|
|
2021-03-14 00:59:00 +01:00
|
|
|
# adds a mine to a tile stored in the grid field
|
2021-03-27 18:25:26 +01:00
|
|
|
def set_a_mine(self, position, mine_type, attribute_values):
|
2021-03-12 20:48:16 +01:00
|
|
|
# getting edited tile's index values
|
|
|
|
row, column = position
|
2021-03-27 18:25:26 +01:00
|
|
|
|
|
|
|
# setting mine data using attribute_values
|
|
|
|
mine_values = const.STRUCT_MINE_ATTRIBUTES[mine_type]
|
|
|
|
|
|
|
|
for key in mine_values.keys():
|
|
|
|
if key not in const.HARDCODED_VALUES and len(attribute_values) > 0:
|
|
|
|
mine_values[key] = attribute_values.pop(0)
|
|
|
|
|
2021-03-12 20:48:16 +01:00
|
|
|
# adding a mine to the edited tile
|
2021-03-27 18:25:26 +01:00
|
|
|
self.grid[str(row) + ',' + str(column)]["mine"] = {}
|
|
|
|
|
|
|
|
for key in mine_values.keys():
|
|
|
|
self.grid[str(row) + ',' + str(column)]["mine"][key] = mine_values[key]
|
2021-03-12 20:48:16 +01:00
|
|
|
|
|
|
|
# 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
|
2021-03-31 21:56:53 +02:00
|
|
|
|
2021-03-12 20:48:16 +01:00
|
|
|
# removing mine from the edited tile
|
|
|
|
self.grid[str(row) + ',' + str(column)]["mine"] = None
|
|
|
|
|
|
|
|
# returns the grid field
|
|
|
|
def get_tile_dictionary(self):
|
|
|
|
return self.grid
|
|
|
|
|
|
|
|
# clears the grid field
|
|
|
|
def clear_tile_dictionary(self):
|
2021-03-31 21:56:53 +02:00
|
|
|
# clearing grid dict
|
2021-03-12 20:48:16 +01:00
|
|
|
self.grid.clear()
|
2021-03-31 21:56:53 +02:00
|
|
|
|
2021-04-17 23:22:27 +02:00
|
|
|
# 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),
|
|
|
|
"direction": self.agents_initial_direction
|
|
|
|
}
|
2021-03-12 20:48:16 +01:00
|
|
|
|
|
|
|
# loads a grid from a file and overwrites the grid field
|
|
|
|
def load_from_a_file(self, file_path):
|
2021-03-14 00:59:00 +01:00
|
|
|
# opening a file for reading
|
2021-03-12 20:48:16 +01:00
|
|
|
with open(file_path, 'r') as input_file:
|
2021-03-14 00:59:00 +01:00
|
|
|
# overwriting the grid field with the grid stored in a file
|
2021-03-12 20:48:16 +01:00
|
|
|
self.grid = json.load(input_file)
|
|
|
|
|
|
|
|
# saves the current grid field to a file
|
|
|
|
def save_to_a_file(self, file_path, access_mode):
|
2021-03-14 00:59:00 +01:00
|
|
|
# opening a file with a given access mode (w - write / a - append)
|
2021-03-12 20:48:16 +01:00
|
|
|
with open(file_path, access_mode) as output_file:
|
2021-03-14 00:59:00 +01:00
|
|
|
# saving the grid to the file
|
2021-03-12 20:48:16 +01:00
|
|
|
json.dump(self.grid, output_file, indent=2, sort_keys=True)
|
|
|
|
|
|
|
|
# edits a grid in a file. doesn't delete data, only overwrites and adds new entries
|
|
|
|
def edit_a_file(self, file_path):
|
2021-03-14 00:59:00 +01:00
|
|
|
# opening a file for reading
|
2021-03-12 20:48:16 +01:00
|
|
|
with open(file_path, "r") as input_file:
|
2021-03-14 00:59:00 +01:00
|
|
|
# loading data that was stored in the file previously
|
2021-03-12 20:48:16 +01:00
|
|
|
previous_data = json.load(input_file)
|
2021-03-31 21:56:53 +02:00
|
|
|
|
2021-03-14 00:59:00 +01:00
|
|
|
# creating and updating a new grid using it's own grid field
|
2021-03-12 20:48:16 +01:00
|
|
|
new_grid = previous_data
|
|
|
|
new_grid.update(self.grid)
|
2021-03-31 21:56:53 +02:00
|
|
|
|
2021-03-14 00:59:00 +01:00
|
|
|
# opening the file for writing
|
2021-03-12 20:48:16 +01:00
|
|
|
with open(file_path, "w") as output_file:
|
2021-03-14 00:59:00 +01:00
|
|
|
# saving the newly created grid
|
2021-03-12 20:48:16 +01:00
|
|
|
json.dump(new_grid, output_file, indent=2, sort_keys=True)
|