def post(self): user = users.get_current_user() if not user: self.redirect(users.create_login_url(self.request.uri)) conflict_id = self.request.get("conflict_id") try: conflict = Conflict.get_by_id(int(conflict_id)) except (db.BadKeyError, StandardError) as e: self.error(500) print >>sys.stderr, str(e) return char = Character.gql("WHERE user = :1 AND conflict = :2", user, conflict).get() if char is None: char = Character(user=user, conflict=conflict) if not char.finalized: char.name = self.request.get("char_name") char.intent = self.request.get("intent") char.finalized = True char.put() self.redirect('/conflict?conflict_id=%s' % conflict_id)
def post(self): user = users.get_current_user() if not user: self.redirect(users.create_login_url(self.request.uri)) conflict_id = self.request.get("conflict_id") try: conflict = Conflict.get_by_id(int(conflict_id)) except (db.BadKeyError, StandardError) as e: self.error(500) print >> sys.stderr, str(e) return char = Character.gql("WHERE user = :1 AND conflict = :2", user, conflict).get() if char is None: char = Character(user=user, conflict=conflict) if not char.finalized: char.name = self.request.get("char_name") char.intent = self.request.get("intent") char.finalized = True char.put() self.redirect('/conflict?conflict_id=%s' % conflict_id)
def get(self): conflict_id = self.request.get("conflict_id") if not conflict_id: # TODO: Add overview page print "lolfukt" return try: conflict = Conflict.get_by_id(int(conflict_id)) if conflict is None: raise RuntimeError("Can't find Conflict") except StandardError: self.error(404) return if all(char.finalized for char in conflict.characters): conflict.ready = True html_page = 'run_conflict.html' if conflict.ready else 'create_conflict.html' user = users.get_current_user() if user is None: user_char = None else: # May still be none if user is not in this conflict # TODO: Have conflict track their users so it can be validated user_char = Character.gql("WHERE user = :1 AND conflict = :2", user, conflict).get() html_path = os.path.join(os.path.dirname(__file__), html_page) template_values = {'conflict': conflict, 'user_char': user_char} self.response.out.write(template.render(html_path, template_values))
def next_conflicts(self): if self.aircraft1.itinerary is None or\ self.aircraft2.itinerary is None: return [] if self.aircraft1.itinerary.next_target is None or\ self.aircraft2.itinerary.next_target is None: return [] if self.aircraft1.itinerary.next_target == \ self.aircraft2.itinerary.next_target: return [Conflict(None, [self.aircraft1, self.aircraft2])] return []
def next_conflicts(self): loc1, loc2 = self.aircraft1.get_next_location(Aircraft.LOCATION_LEVEL_COARSE), \ self.aircraft2.get_next_location(Aircraft.LOCATION_LEVEL_COARSE) print("83", loc1, loc2) if not loc1 or not loc2 or not loc1.is_close_to(loc2): return [] if loc1 == self.aircraft1.itinerary.targets[-1].nodes[-1] \ and loc2 == self.aircraft2.itinerary.targets[-1].nodes[-1]: print("success") return [] return [Conflict((loc1, loc2), [self.aircraft1, self.aircraft2])]
def __get_conflicts(self, is_next=False): __conflicts = [] aircraft_pairs = list(itertools.combinations(self.aircrafts, 2)) for pair in aircraft_pairs: if is_next: loc1, loc2 = pair[0].next_location, pair[1].next_location else: loc1, loc2 = pair[0].location, pair[1].location if not loc1.is_close_to(loc2): continue __conflicts.append(Conflict((loc1, loc2), pair)) return __conflicts
def post(self): """ Create a new conflict """ user = users.get_current_user() if not user: self.redirect(users.create_login_url(self.request.uri)) conflict = Conflict.new() Character(user=user, conflict=conflict).put() html_path = os.path.join(os.path.dirname(__file__), 'create_conflict.html') template_values = {'conflict': conflict} self.response.out.write(template.render(html_path, template_values))
def __get_next_conflict(self): __conflicts = [] __conflicts_dist = [] aircraft_pairs = list(itertools.combinations(self.aircrafts, 2)) for pair in aircraft_pairs: if pair[0] == pair[1]: continue loc1, loc2 = pair[0].get_next_location(Aircraft.LOCATION_LEVEL_PRECISE), \ pair[1].get_next_location(Aircraft.LOCATION_LEVEL_PRECISE) if not loc1 or not loc2 or not loc1.is_close_to_plan(loc2): continue dist = loc1.get_distance_to(loc2) __conflicts.append(Conflict((loc1, loc2), pair)) __conflicts_dist.append(dist) return __conflicts
def __get_conflicts(self, is_next=False): # Remove departed aircraft or __conflicts = [] aircraft_pairs = list(itertools.combinations(self.aircrafts, 2)) for pair in aircraft_pairs: if pair[0] == pair[1]: continue if is_next: loc1, loc2 = pair[0].get_next_location(Aircraft.LOCATION_LEVEL_PRECISE), \ pair[1].get_next_location(Aircraft.LOCATION_LEVEL_PRECISE) else: loc1, loc2 = pair[0].precise_location, pair[1].precise_location if not loc1 or not loc2 or not loc1.is_close_to(loc2): continue __conflicts.append(Conflict((loc1, loc2), pair)) return __conflicts
def conflicts(self): if self.aircraft1.location == self.aircraft2.location: return [Conflict(None, [self.aircraft1, self.aircraft2])] return []
def merge_with(self, ours, theirs): our_added = ours.get_added_tracks_compared_to(self) their_added = theirs.get_added_tracks_compared_to(self) our_removed = ours.get_removed_tracks_compared_to(self) their_removed = theirs.get_removed_tracks_compared_to(self) # Any removed from both our_removed_ids = [t.track_id for t in our_removed] their_removed_ids = [t.track_id for t in their_removed] both_removed_ids = [ t for t in our_removed_ids if t in their_removed_ids ] # Remove the tracks from self both_removed = [ t for t in self.tracks if t.track_id in both_removed_ids ] self.tracks = [ t for t in self.tracks if t.track_id not in both_removed_ids ] for t in both_removed: # NOTE: This might not work if merging multiple times as the elements # will have changed after reconcilliation self.tree.find('LiveSet').find('Tracks').remove(t.elem) # Get all of the return value mappings for each track in each version # Added can be ignored because they won't have any conflicting sends (they are new) # As can removed # Only care about maintained? # We have track.return_map at this point for ours and theirs our_same = ours.get_intersection_tracks_compared_to(self) their_same = theirs.get_intersection_tracks_compared_to(self) def get_updated_tracks(branch, branch_same_tracks, base): base_tracks = base.tracks updated_tracks = [] for track in branch_same_tracks: original_track = [ t for t in base_tracks if t.track_id == track.track_id ][0] # Create mapping of returns # See note in equal.py for why this is necessary branch_return = branch.get_return_tracks() base_return = base.get_return_tracks() return_intersection_ids = [ t.track_id for t in branch_return if t.track_id in [b.track_id for b in base_return] ] # Get send ID mapping of these tracks to eachother # Their send id is based on their ordering # The key will be the base send ID # The value will be that send's ID in the branch track send_map = {} branch_r_ids = [t.track_id for t in branch_return] base_r_ids = [t.track_id for t in base_return] for i in return_intersection_ids: br_loc = branch_r_ids.index(i) ba_loc = base_r_ids.index(i) send_map[ba_loc] = br_loc if not tree_equal(track.elem, original_track.elem, send_map): updated_tracks.append(track) else: pass return updated_tracks # Can guarantee only one track in array updated_in_ours = get_updated_tracks(ours, our_same, self) updated_in_theirs = get_updated_tracks(theirs, their_same, self) # Intersection of both of these conflicting_track_ids = [ t.track_id for t in updated_in_ours if t.track_id in [h.track_id for h in updated_in_theirs] ] conflicts = [ Conflict(*map( lambda x: ET.tostring(x.get_track_with_id(id_).elem).decode(), [self, ours, theirs])) for id_ in conflicting_track_ids ] updates = [ t for t in updated_in_ours if t.track_id not in conflicting_track_ids ] updates += [ t for t in updated_in_theirs if t.track_id not in conflicting_track_ids ] for track in updates: self.replace_track(track) # Can safely add the tracks now for track in our_added: self.add_track(track) for track in their_added: self.add_track(track) ours.reconcile_send_values() theirs.reconcile_send_values() # Await conflicts here # need to make barebones files # notify macOS app using webbrowser # await file creation of some variety # if it's a normal track, get both versions leave returns? which returns? # if it's a return track, get a track as well that uses # it if len(conflicts) > 0: conflict_files = [] for i, conf in enumerate(conflicts): # Create a new project from blank.xml to hold the sample project for viewing the conflicts sample_root = ET.parse('.merge/blank.xml').getroot() # Remove any residual tracks from the blank file's tracks sample_tracks = sample_root.find('LiveSet').find('Tracks') for c in list(sample_tracks): sample_tracks.remove(c) # Add our branch to sample sample_ours = ET.fromstring(conf.ours) sample_ours.attrib['Id'] = "10" sample_ours.find('Name').find( 'UserName').attrib['Value'] = 'Ours' # Add their branch to sample sample_theirs = ET.fromstring(conf.theirs) sample_theirs.attrib['Id'] = "20" sample_theirs.find('Name').find( 'UserName').attrib['Value'] = 'Theirs' # Remove send values sample_ours_sends = sample_ours.find('DeviceChain').find( 'Mixer').find('Sends') sample_theirs_sends = sample_theirs.find('DeviceChain').find( 'Mixer').find('Sends') for c in list(sample_ours_sends): sample_ours_sends.remove(c) for c in list(sample_theirs_sends): sample_theirs_sends.remove(c) # Add our tracks to the sample sample_tracks.append(sample_ours) sample_tracks.append(sample_theirs) sample_tree = ET.ElementTree(sample_root) # Create a temporary folder to hold the samples temp_folder_name = '.conftemp' if not os.path.exists(temp_folder_name): os.makedirs(temp_folder_name) # Create the sample file path filename = 'conf_' + str(i) + '.xml' full_path = temp_folder_name + '/' + filename full_als_path = temp_folder_name + '/' + 'conf_' + str( i) + '.als' # Write the samples to the folder sample_tree.write(full_path, encoding='utf-8', xml_declaration=True) with open(full_path, 'rb') as f_in, gzip.open(full_als_path, 'wb') as f_out: f_out.writelines(f_in) # Add the file path to the list of sample file paths conflict_files.append(full_als_path) # Make a call to the url scheme for the jackdaw app # appending the paths of the sample files url_scheme = 'jackdaw://merge/' for cpath in conflict_files: url_scheme += cpath + '+' url_scheme = url_scheme[:-1] webbrowser.open(url_scheme) # Wait until the resolution file is present # created by the jackdaw app import time done_file = '.merge/done' while not os.path.exists(done_file): time.sleep(1) resolutions = [] # Eventually make this so that it reloads from # the actual als file so that user edits are saved # Open the resolution file with open(done_file) as json_data: # Load the contents of the file into json conf_branch_map = json.load(json_data) for conf, branch in conf_branch_map.items(): # For each path: true/false ours/theirs # Get the index of the resolution from the original list of files conf_i = conflict_files.index('.conftemp/' + conf) # Get the Conflict object for this version conflict = conflicts[conf_i] if branch: resolutions.append(ours) else: resolutions.append(theirs) for i, track_id in enumerate(conflicting_track_ids): # Get the chosen version chosen_branch = resolutions[i] # Get the track from the chosen branch with the selected ID to_replace_with = chosen_branch.get_track_with_id(track_id) # Replace the track with that ID self.replace_track(to_replace_with) os.remove('.merge/done') import shutil shutil.rmtree('.conftemp') self.move_return_tracks_to_end() self.reconcile_send_values() self.amend_track_collisions() self.generate_sends() self.amend_global_id_collisions() self.amend_sends_pre()
def main(args): level_data = None # Read server messages from stdin. msg_server_action("Starfish") level_data = sys.stdin # Create client using server messages starfish_client = Client(level_data) current_state = starfish_client.initial_state walls = starfish_client.walls # Solve and print # TODO: configuration when an agent is blocking all the others solution = starfish_client.solve_level() if isListEmpty(solution): coop = Cooperation(current_state, starfish_client.goal_state, starfish_client.walls) queries = coop.get_needed_coop() solution = starfish_client.queries_to_action(queries, current_state) nb_agents = len(solution) printer = ";".join(['{}'] * nb_agents) verified = False while (not isListEmpty(solution)) or (verified == False): missing_goals = get_missing_goals(current_state, starfish_client.goal_state) if len(missing_goals) == 0: verified = True for i, elt in enumerate(solution): if len(elt) == 0 and str(i) not in missing_goals: padding_state = current_state solution[i].append(padding_state) solution[i][-1].action = Action(ActionType.NoOp, None, None) elif len(elt) == 0 and str( i ) in missing_goals: # and not starfish_client.agents[i].has_goal(): starfish_client.agents[i].current_state = current_state starfish_client.agents[i].assign_goal( starfish_client.goal_state, (missing_goals[str(i)][0], 0)) new_path = starfish_client.agents[i].find_path_to_goal( starfish_client.walls) if new_path is not None and len(new_path) > 0: solution[i].extend(new_path) else: padding_state = current_state solution[i].append(padding_state) solution[i][-1].action = Action(ActionType.NoOp, None, None) # grabbing state for each agent state = [elt[0] for elt in solution] joint_action = [agent.action for agent in state] index_non_applicable, current_state, is_applicable = check_action( joint_action, current_state, walls) msg_server_comment( printer.format(*joint_action) + " - applicable: {}".format(is_applicable)) # if there is a conflict between agents if not is_applicable: conflict = Conflict(current_state, index_non_applicable, joint_action, solution, walls) agents, actions = conflict.handle_conflicts() joint_action = [Action(ActionType.NoOp, None, None)] * nb_agents for (agent, action) in zip(agents, actions): if action is not None: joint_action[int(agent)] = action # forgetting goal in order to help fix the conflict padding_state = current_state solution[int(agent)] = [padding_state] solution[int(agent)][-1].action = Action( ActionType.NoOp, None, None) solution[int(agent)].append(solution[int(agent)][-1]) starfish_client.agents[int(agent)].forget_goal() else: box_key = starfish_client.agents[int(agent)].box_key starfish_client.agents[int(agent)] = Agent( current_state, agent) starfish_client.agents[int(agent)].assign_goal( starfish_client.goal_state, box_key) new_path_to_goal = starfish_client.agents[int( agent)].find_path_to_goal(walls) solution[int(agent)] = new_path_to_goal # print(new_path_to_goal) # sys.exit() # updating state _, current_state, _ = check_action(joint_action, current_state, walls) msg_server_comment("New action: " + printer.format(*joint_action)) msg_server_action(printer.format(*joint_action)) if is_applicable: for i, elt in enumerate(solution): elt.pop(0) response = level_data.readline().rstrip() if 'false' in response: msg_server_err("Server answered with error to the action " + printer.format(*joint_action))