def main(): print("sdsdsds") GLogger('file', 'graph_validator_logger.txt', 'ERROR') Window.size = (1920, 1090) Utils.read_game_config_file(MAIN_CONFIG_FILE_PATH) Utils.read_graph_config_file(GRAPH_CONFIG_FILE) Utils.image_folder = path.join("..", Utils.image_folder) max_turns = int(Utils.game_config_data['Default']['max_turns']) it = itertools.product('1234', repeat=max_turns) number_of_successful_runs = 0 # use line 30 to test all the graphs in SAVED_GRAPH_PATH; use line 31 to only test the graphs specified in 'graphs_names' # for current_graph in [item for item in listdir(SAVED_GRAPH_PATH) if item.endswith(".xml")]: for current_graph in graphs_names: curr_path = path.join(SAVED_GRAPH_PATH, current_graph) graph = load_graph_from_json(curr_path) with open("{}_saved_steps.txt".format(curr_path[:-5]), 'w') as f: num_of_graph_nodes = len(graph.node_list) f.write("The graph contains {} nodes\n".format( str(num_of_graph_nodes))) while True: try: buttons = it.next() except StopIteration: break answer, number_of_nodes_seen = run_buttons_on_graph( graph, buttons) number_of_successful_runs += answer f.write("steps: {}, seen nodes: {} \n".format( str(buttons), str(number_of_nodes_seen))) f.write("number of successful runs = {0}\n".format( number_of_successful_runs))
def run_q_player(self, graph_file_path, log_file_path): Utils.read_game_config_file(CONFIG_FILE_PATH) Utils.read_graph_config_file(GRAPH_CONFIG_PATH) Utils.image_folder = path.join("..", Utils.image_folder) log.setLevel(Utils.game_config_data['Default']['log_level']) session_length = 1000 graph = load_py_graph(graph_file_path) q_matrix = QMatrix(action_space=4, max_steps=int(Utils.game_config_data['Default']['max_turns']), nodes_in_graph=len(graph.node_list)) with open(log_file_path,'w') as f: f.write("episode, score\n") for i in range(session_length): dummy_screen = DummyScreen(graph) game = GraphTabletDisplay(dummy_screen) data_handler = GameDataHandler(GRAPH_CONFIG_PATH, graph.size) data_handler.add_view_to_db(game.get_info_from_screen()) rw = 0 game.press_button(self.auto_first_press + 1) data_handler.add_view_to_db(game.get_info_from_screen()) q_matrix.reinit(known_nodes=len(data_handler.get_real_nodes())) for j in range(1, int(Utils.game_config_data['Default']['max_turns'])): log.debug("doing a step {}/{}".format(j, Utils.game_config_data['Default']['max_turns'])) btn = q_matrix.choose_action_epsilon_greedy() game.press_button(btn + 1) data_handler.add_view_to_db(game.get_info_from_screen()) rw = q_matrix.update_matrix(num_nodes=len(data_handler.get_real_nodes()), current_step=btn) log.info("Q session {}:{} - reword:{}".format(i, session_length, rw)) f.write("{},{}\n".format(i + 1, rw))
def add_view_to_db(self, view): """ Go over the new view gotten from the game. For each new node add it to self.graph.node_list For each edge check both ends. if the node has real=False we know it's only a placeholder. Update the graph of BasicGamer :param view: A dictionary containing the data gotten from the screen :return: None """ # Innumerate over the nodes for node in view['nodes']: if self.graph.get_node_by_serial(node.serial_num) is None: self.graph.add_node(node.x, node.y, node_colour=node.colour, node_size=node.size, serial=node.serial_num) num = self.graph.get_node_by_serial(node.serial_num).dummy_num #self.log.info("Adding node: num="+ str(num)+ ", real=True", location="{}:{}".format(node.x, node.y),serial=node.serial_num) # Innumerate over the edges for edge in view['edges']: if self.graph.get_node_by_serial(edge[0].serial_num) is not None: node_0 = self.graph.get_node_by_serial(edge[0].serial_num) else: node_0 = self.graph.add_node(edge[0].x, edge[0].y, node_size=1, real=False, serial=edge[0].serial_num) num = self.graph.get_node_by_serial(node_0.serial_num).dummy_num GLogger.log(logging.DEBUG,Utils.format_log_msg("Adding node",num=num, real=False, location="{}:{}".format(node_0.x, node_0.y), serial=node_0.serial_num)) if self.graph.get_node_by_serial(edge[1].serial_num) is not None: node_1 = self.graph.get_node_by_serial(edge[1].serial_num) else: node_1 = self.graph.add_node(edge[1].x, edge[1].y, node_size=1, real=False, serial=edge[1].serial_num) num = self.graph.get_node_by_serial(node_1.serial_num).dummy_num GLogger.log(logging.DEBUG, Utils.format_log_msg("Adding node",num=num, real=False, location="{}:{}".format(node_1.x, node_1.y), serial=node_1.serial_num)) if node_1.serial_num not in node_0.possible_neighbors: node_0.possible_neighbors.add(node_1.serial_num) if node_0.serial_num not in node_1.possible_neighbors: node_1.possible_neighbors.add(node_0.serial_num) self.graph.connect_nodes(node_0, node_1, allow_overflow=True) if edge not in self.extra_edges: self.extra_edges.append(edge) self.edges_to_add = [] GLogger.log(logging.DEBUG, "Triming data from graph") self.trim_data() GLogger.log(logging.DEBUG, "Adding extra edges to edge list") for item in self.edges_to_add: self.extra_edges.append(item) self.clear_empty_nodes() GLogger.log(logging.DEBUG, Utils.format_log_msg("Finished triming data:", num_of_node=len(self.graph.node_list), num_real_node=(len([item for item in self.graph.node_list if item.is_real()])), num_of_edges=len(self.extra_edges))) GLogger.log(logging.DEBUG, Utils.format_log_msg("edge list:", edges=self.extra_edges))
def test_trim_data(self, mock_utils): mock_utils.graph_config_data = None mock_utils.game_config_data = {'Default': {'log_level': 'ERROR'}} Utils.read_game_config_file(path.join("..", CONFIG_FILE_PATH)) Utils.read_graph_config_file(path.join("..", GRAPH_CONFIG_PATH)) data_handler = GameDataHandler(path.join("../", "graph_config.txt"), None) data_handler.graph.add_node(self.node_1_real.x, self.node_1_real.y, serial=self.node_1_real.serial_num) data_handler.graph.add_node(self.node_2_unreal.x, self.node_2_unreal.y, serial=self.node_2_unreal.serial_num) data_handler.graph.add_node(self.node_2_unreal_moved.x, self.node_2_unreal_moved.y, serial=self.node_2_unreal_moved.serial_num) data_handler.graph.add_node(self.node_3_unreal.x, self.node_3_unreal.y, serial=self.node_3_unreal.serial_num) data_handler.graph.add_node(self.node_3_unreal_moved.x, self.node_3_unreal_moved.y, serial=self.node_3_unreal_moved.serial_num) data_handler.graph.add_node(self.node_4_real.x, self.node_4_real.y, serial=self.node_4_real.serial_num) edge_1 = (self.node_1_real, self.node_2_unreal_moved, 1, LineEquation(slope=1, const=0, edge1=self.node_1_real, edge2=self.node_2_unreal_moved)) edge_2 = (self.node_2_unreal, self.node_3_unreal_moved, 1, LineEquation(slope=1, const=0, edge1=self.node_2_unreal, edge2=self.node_3_unreal_moved)) edge_3 = (self.node_3_unreal, self.node_4_real, 1, LineEquation(slope=1, const=0, edge1=self.node_3_unreal, edge2=self.node_4_real)) edge_4 = (self.node_1_real, self.node_4_real, 1, LineEquation(slope=1, const=0, edge1=self.node_1_real, edge2=self.node_4_real)) data_handler.extra_edges = [edge_1, edge_2, edge_3] data_handler.trim_data() self.assertEquals(len(data_handler.edges_to_add), 1) self.assertEquals(data_handler.edges_to_add[0][0].serial_num, edge_4[0].serial_num) self.assertEquals(data_handler.edges_to_add[0][1].serial_num, edge_4[1].serial_num)
def create_rand_graph(config_file): """ :param config_file: :return: """ new_graph = GraphObject(config_file) config = Utils.read_game_config_file(config_file) for i in range(config.getint("GeneralParams", "NodeCount")): while True: xRandom = random.randint( config.getint("NodeData", "NodeSize"), config.getint("GeneralParams", "GraphSizeX") - config.getint("NodeData", "NodeSize")) yRandom = random.randint( config.getint("NodeData", "NodeSize"), config.getint("GeneralParams", "GraphSizeY") - config.getint("NodeData", "NodeSize")) if not check_collisions(xRandom, yRandom, new_graph, config.getint("NodeData", "NodeSize"), config.getint("NodeData", "ExtraDistance")): break randColor = random.choice(Colours.values()) new_graph.add_node(xRandom, yRandom, randColor, Shapes['circle'], config.getint("NodeData", "NodeSize")) connect_graph(new_graph, config.getint("NodeData", "MaxNeighbors"), config.getint("NodeData", "MinNeighbors")) return new_graph
def cleaned_graph(self): """ Called at the end of a run. Cleans the graph of none real connections This is really just a patch because we enter bad connections. We should probably fix the source of the issue :return: the cleaned graph """ self.graph.connections = [] for edge in self.extra_edges: if edge[0].is_real() and edge[1].is_real(): self.graph.connections.append((min(edge[0].serial_num, edge[1].serial_num), max(edge[0].serial_num, edge[1].serial_num))) else: self.clean_connection(edge[0], edge[1]) self.clean_connection(edge[1], edge[0]) self.extra_edges = [] real_nodes = [] for node in self.graph.node_list: if node.is_real(): nodes_to_remove = [] for neightbor in node.neighbors: if not self.graph.get_node_by_serial(neightbor).is_real(): nodes_to_remove.append(self.graph.get_node_by_serial(neightbor)) for item in nodes_to_remove: self.clean_connection(node, item) real_nodes.append(node) # Make sure we see only the same edge once self.graph.connections = list(set(self.graph.connections)) GLogger.log(logging.DEBUG, Utils.format_log_msg("Finished cleaning graph before continuing:", num_of_nodes=len(self.graph.node_list), num_real_nodes=(len([item for item in self.graph.node_list if item.is_real()])), num_of_connections=len(self.graph.connections))) self.graph.node_list = real_nodes return self.graph
def two_edges_are_one(self, edge_1, edge_2): """ Checks if the two edges are actually a single edge. :return: True if edges are 100% the same one """ eq1 = LineEquation(slope=edge_1[3].slope, const=edge_1[3].const, edge1=edge_1[0], edge2=edge_1[1]) eq2 = LineEquation(slope=edge_2[3].slope, const=edge_2[3].const, edge1=edge_2[0], edge2=edge_2[1]) # Check collision point collision_point = LineEquation.get_equation_collision_point(eq1, eq2) GLogger.log(logging.DEBUG, Utils.format_log_msg("Found collision point of both edges", point=collision_point, eq1=eq1, eq2=eq2)) if collision_point == LINES_ALWAYS_MEET: # Lines have the same slope + const. Big change they are the same one. if LineEquation.check_collision_point(eq1, eq2): GLogger.log(logging.DEBUG, "Lines meet and intersect with each other - They are the same line") return True else: GLogger.log(logging.DEBUG, "Lines have the same parameters but we are not sure if they meet") return False return False
def connect_nodes(self, node1, node2, allow_overflow=False): """ Connects both nodes, remove each from the list of possible neighbors of the other and adds to the list of neighbors. :param allow_overflow: If node can have more than max connections :return: True if nodes were connected, Raise exception if problem accrued """ GLogger.log( logging.DEBUG, Utils.format_log_msg("Creating edge", edge="{}:{} - {}:{}".format( node1.x, node1.y, node2.x, node2.y))) if (len(node1.neighbors) >= self.max_neighbors or len(node2.neighbors) >= self.max_neighbors) \ and not allow_overflow: raise Exception("One of the nodes has too many neighbors") if node1.serial_num in node2.possible_neighbors and node2.serial_num in node1.possible_neighbors: # Connect nodes node1.neighbors.add(node2.serial_num) node2.neighbors.add(node1.serial_num) # Removes from future possible connections node1.possible_neighbors.remove(node2.serial_num) node2.possible_neighbors.remove(node1.serial_num) self.connections.append((min(node1.serial_num, node2.serial_num), max(node1.serial_num, node2.serial_num))) return True else: raise Exception("Connection between the two nodes is not possible")
def clear_empty_nodes(self): """ Go over node list and see if two nodes are the same. :return: """ remove_list = [] GLogger.log(logging.DEBUG, "removing nodes with no neighbors") for node in self.graph.node_list: if len(node.neighbors) == 0: GLogger.log(logging.DEBUG, Utils.format_log_msg("Found node with no neighbors - deleting:", serial=node.serial_num, real=node.is_real())) remove_list.append(node.serial_num) for serial in remove_list: self.graph.node_list.remove(self.graph.get_node_by_serial(serial)) GLogger.log(logging.DEBUG, "removed {} nodes".format(len(remove_list)))
def clean_connection(self, main_node, node_to_remove): """ Removed all connection from main_node regarding node_to_remove :param node_to_remove: The node to remove - node object :param main_node: The node we want to remove data from - node object :return: """ GLogger.log(logging.DEBUG, Utils.format_log_msg("Cleaning connection to another node", main_node=main_node.dummy_num, node_to_remove=node_to_remove.dummy_num)) node = self.graph.get_node_by_serial(main_node.serial_num) if node is None: raise Exception("Node '{}' was not found in node list. Node list = {}" .format(main_node.dummy_num, [found_nodes.dummy_num for found_nodes in self.graph.node_list])) if node_to_remove.serial_num in node.neighbors: node.neighbors.remove(node_to_remove.serial_num) if node_to_remove.serial_num in node.possible_neighbors: node.possible_neighbors.remove(node_to_remove.serial_num)
def trim_data(self): """ Goes over all of the data that is saved and trims nodes and edges. Connects fake nodes to real ones if we found the actual node connects open edges together if possible """ slope_set = set() for edge in self.extra_edges: slope_set.add(edge[3].slope) sorted(slope_set) GLogger.log(logging.DEBUG,"Number of slops found = {}".format(len(slope_set))) for slope in list(slope_set): edges_to_check = [] for edge in self.extra_edges: if edge[3].slope == slope: edges_to_check.append(edge) GLogger.log(logging.DEBUG,Utils.format_log_msg("Number of edges in slope: ",slope="{} = {}".format(slope, len(edges_to_check)), edges=edges_to_check)) if len(edges_to_check) > 1: # we have two edges with the same slope! # Removing all edges from list. We add only the relevant ones later on for item in edges_to_check: self.extra_edges.remove(item) while True: first_edge = edges_to_check.pop() edge_reconstructed = False for second_edge in edges_to_check: if self.two_edges_are_one(first_edge, second_edge): GLogger.log(logging.DEBUG, "two edges are one") edge_reconstructed = True edges_to_check.remove(second_edge) edges_to_check.append(self.connect_edges(first_edge, second_edge)) break if not edge_reconstructed: # edge does not match any other on the list. We can leave it alone self.edges_to_add.append(first_edge) if len(edges_to_check) <= 1: self.edges_to_add.append(edges_to_check[0]) break
class GameType(Enum): VIEW_ONLY = 1 ALLOW_PLAY = 2 def main(game_type, graph_data): GLogger('file', 'graph_runner_logger.txt', 'ERROR') if game_type == GameType.VIEW_ONLY: game = DisplayApp(graph_data) elif game_type == GameType.ALLOW_PLAY: button_presses = [] # This needs to be more versatile test_screen = TestScreen(graph_data, button_presses, 0.2) test_screen.graph_config = "../GraphsData/graph_config.txt" game = GraphGameApp(test_screen) game.run() if __name__ == "__main__": Utils.read_game_config_file(CONFIG_FILE_PATH) Utils.read_graph_config_file(GRAPH_CONFIG_PATH) Utils.image_folder = path.join("..", Utils.image_folder) # ALLOW_PLAY, VIEW_ONLY game_type = GameType.ALLOW_PLAY graph = load_graph_from_json(graph_file_path) main(game_type, graph)
def build(self): self.init_communication() self.config = Utils.read_game_config_file(CONFIG_FILE_PATH) Utils.read_graph_config_file(GRAPH_CONFIG_PATH) self.logger = GLogger( self.config['Default']['logger_output_type'], self.config['Default']['logger_writing_location'], self.config['Default']['log_level'], self.user_data_dir) #self.init_communication(self.config['Cloud']['server_ip']) graph_config_path = self.config['Default']['graph_config_path'] self.sm = ScreenManager() screen = ZeroScreen() screen.start() screen.ids['subject_id'].bind( text=screen.ids['subject_id'].on_text_change) self.sm.add_widget(screen) screen = FinalScreen() self.sm.add_widget(screen) # # Setting up the login screen separately # login_screen = LoginScreen(name='LoginScreen') # login_screen.setup(main_app=self) # login_screen.add_widget(login_screen.display.layout) # self.sm.add_widget(login_screen) graph_list = self.load_graphs_from_folder() self.current_graph = None self.discovered_graph = None self.user_answers = [] self.question_list = [] self.button_presses = [] # Enumerate over all the graphs in the folder for i_net, graph_data in enumerate(graph_list): # Step 1 - Graph Game self.question_list = graph_data.question_object_list self.game_screen.append( GraphGameScreen(name='game_graph_' + str(i_net))) self.game_screen[-1].setup( number=i_net, main_app=self, max_turns=int(self.config['Default']['max_turns']), real_user=True, graph=graph_data, graph_config=graph_config_path, button_presses=self.button_presses) self.game_screen[-1].add_widget( self.game_screen[-1].graph_game.layout) # Step 2 - Questionnaire #Goren - run nine graphs with question and then one without if i_net < number_of_graphs: self.game_screen.append( QuestionnaireScreen(name='game_questionnaire_' + str(i_net))) self.game_screen[-1].setup(number=i_net, main_app=self, real_user=self.real_user) self.game_screen[-1].add_widget( self.game_screen[-1].questionnaire.the_widget) # Step 3 - Results self.game_screen.append( ResultScreen(name='game_results_' + str(i_net))) self.game_screen[-1].setup(number=i_net, main_app=self, real_user=True) self.game_screen[-1].add_widget( self.game_screen[-1].result_app.the_widget) for gs in self.game_screen: self.sm.add_widget(gs) self.sm.current = 'zero_screen' return self.sm