def find_seen_but_unclick_elements(elements, scene_name): unclick_elements = [] for elem in elements: e = TouchElem(scene_name, elem[0]) if e not in clicked_elements: unclick_elements.append(elem) return unclick_elements
def find_unseen_elements(elements, scene_name): unseen_elements = [] for elem in elements: e = TouchElem(scene_name, elem[0]) if e not in seen_elements: unseen_elements.append(elem) return unseen_elements
def print_current_layer(): elements = engine.get_touchable_elements() scene_name = engine.get_scene() curr_layer = ViewLayer() for e, _ in elements: te = TouchElem(scene_name, e) curr_layer.add_element(te) curr_layer.sort_elems_by_name() print("current layer: %s" % curr_layer.fullstr())
def explore(statfilename="policy.log", forbid_names=None, mode=0, max_num=300, interval=3): # mode: 0 for new strategy, 1 for old one global seen_elements, clicked_elements, visited_layer, unclick_element_2_layers, layer_2_unclick_cnt policy_cnt = [0, 0, 0, 0] logger.info("Start Exploring") graph = Graph() init_game_activity() prev_layer = None prev_entry = None cnt = 0 error = 0 not_in_game = False while cnt < max_num: time.sleep(interval) count_stat(cnt, len(clicked_elements), len(seen_elements), len(visited_layer)) logger.info("loop cnt is %d", cnt) # not game package, sleep some time first to make it stable if not in_game_activity(): time.sleep(10) if not in_game_activity(): if qqwx.check_qq_wx_package(): # try to handle qq/wx package qqwx.handle_qq_wx_package() elif not_in_game: logger.info("not game package anymore, raise Exception") raise Exception, "not game package anymore" else: # exit this layer logger.info("not game package, back") device.back() prev_layer = None prev_entry = None cnt += 1 not_in_game = True continue not_in_game = False elements = [] try: elements = engine.get_touchable_elements() except: elements = None stack = traceback.format_exc() not_in_game = True logger.warn(stack) reporter.screenshot() # get elements timed out (0 fps) if elements is None: logger.info("get elements timed out, back") if qqwx.check_qq_wx_package(): # try to handle qq/wx package qqwx.handle_qq_wx_package() else: # exit this layer logger.info("not game package, back") device.back() prev_layer = None prev_entry = None cnt += 1 continue if forbid_names: elements = [ e for e in elements if e[0].object_name not in forbid_names ] elements = find_in_screen_elements(elements) scene_name = engine.get_scene() elements = get_desuffixed_elements(elements) # no touchable element if len(elements) == 0: # logger.info("no touchable element, click screen center") # click_screen_center() logger.info("no touchable element, click screen corner") click_screen_corner() prev_layer = None prev_entry = None cnt += 1 continue unseen_elements = find_unseen_elements(elements, scene_name) unclick_elements = find_seen_but_unclick_elements(elements, scene_name) # set current layer curr_layer = ViewLayer() for e, _ in elements: te = TouchElem(scene_name, e) curr_layer.add_element(te) curr_layer.sort_elems_by_name() # logger.info("current layer data:\n%s", curr_layer.fullstr()) logger.info("current layer: %s", curr_layer) # add vertex if not graph.check_vertex(curr_layer): graph.add_vertex(curr_layer) if curr_layer not in visited_layer: visited_layer.add(curr_layer) # set globals clear_view_layer_in_global(curr_layer) layer_2_unclick_cnt[curr_layer] = 0 for e, _ in elements: te = TouchElem(scene_name, e) # add TouchElement into seen_elements if te not in seen_elements: seen_elements.add(te) # if this is an unclick element if te not in clicked_elements: # if this unclick element was not recorded before if te not in unclick_element_2_layers or curr_layer not in unclick_element_2_layers[ te]: layer_2_unclick_cnt[curr_layer] += 1 # add into unclick_element_2_layers unclick_element_2_layers.setdefault(te, set()).add(curr_layer) # add edge if prev_layer and prev_entry: graph.add_edge(prev_layer, curr_layer, prev_entry) else: logger.info("prev layer and entry are None, ignore the edge") if mode == 1: # old strategy e, pos = tools.find_less_click_element(elements) else: # new strategy if unseen_elements: e, pos = unseen_elements[0] logger.info("choose an unseen element: %s", e.object_name) policy_cnt[0] += 1 elif unclick_elements: e, pos = unclick_elements[0] logger.info("choose an unclick element: %s", e.object_name) policy_cnt[1] += 1 else: # check if current layer has only 1 element and no edge out # NOTE!!! this policy is very *TRICKY* and should be fixed in SDK engine later outlayers = [ l.id for l in graph.get_vertex(curr_layer).get_connections() ] if len(elements) == 1 and (not outlayers or (len(outlayers) == 1 and outlayers[0] == curr_layer)): logger.info( "only 1 element and no edge to other layer, click screen corner" ) click_screen_corner() prev_layer = None prev_entry = None cnt += 1 continue logger.info("current layer contains no unclick element") max_unclick_layer, path = find_max_layer_unclick_reachable( graph, curr_layer) if max_unclick_layer and path: logger.info("choose a max unclick layer: %s", max_unclick_layer) prev_layer, prev_entry, num = go_through_graph_path( graph, path, forbid_names) cnt += num logger.info("cnt adds %d", num) policy_cnt[2] += 1 continue else: rand = random.randint(0, len(elements)) logger.info("choose an action by random: %d", rand) if rand == 0: # this policy could possibly combine with *no edge out* policy # say: delete *no edge out* policy, and only use this one logger.info("click screen corner") click_screen_corner() prev_layer = None prev_entry = None cnt += 1 continue else: e, pos = find_less_click_element_ex(elements) logger.info("choose a less click one: %s", e.object_name) policy_cnt[3] += 1 # actually click the element tools.screen_shot_click_pos(pos["x"], pos["y"]) # handle new click element te = TouchElem(scene_name, e) if te not in clicked_elements: logger.info("handle new click element: %s", te) # add into clicked_elements clicked_elements.add(te) # count down all related layers if te in unclick_element_2_layers: for layer in unclick_element_2_layers[te]: layer_2_unclick_cnt[layer] -= 1 # protect the code if layer_2_unclick_cnt[layer] < 0: logger.warn( "layer_2_unclick_cnt[layer] negative, must be wrong. %s", layer) layer_2_unclick_cnt[layer] = 0 # delete TouchElem from unclick_element_2_layers del unclick_element_2_layers[te] # set prev layer and entry prev_layer = curr_layer prev_entry = te # add loop count cnt += 1 count_stat(cnt, len(clicked_elements), len(seen_elements), len(visited_layer)) logger.info("Finish Exploring") output_stat(statfilename) logger.debug("%s", graph) log_desuffix() seen_sum = len(seen_elements) clicked_sum = len(clicked_elements) unclick_sum = 0 unclick_sum_zero = 0 for k in unclick_element_2_layers: if len(unclick_element_2_layers[k]) > 0: unclick_sum += 1 else: unclick_sum_zero += 1 logger.info( "sumcheck. seen sum: %d, clicked sum: %s, unclick sum: %s, unclick sum zero: %s", seen_sum, clicked_sum, unclick_sum, unclick_sum_zero) logger.info("visited layer cnt: %d", len(visited_layer)) logger.info("each policy cnt: %s", policy_cnt) sum1 = 0 for v in graph: sum1 += layer_2_unclick_cnt[v.get_id()] sum2 = 0 for elem in unclick_element_2_layers: sum2 += len(unclick_element_2_layers[elem]) logger.info( "sumcheck. layer sum unclick cnt is %d, unclick element sum layer is %d", sum1, sum2) for elem in unclick_element_2_layers: logger.debug("unclick element contained in following layers: %s", elem) for layer in unclick_element_2_layers[elem]: # logger.debug("%s", layer.fullstr()) logger.debug("%s", layer)
def go_through_graph_path(graph, path, forbid_names): ''' @return: (prev layer, prev entry, click number) ''' prev_layer = None prev_entry = None # go through the path num = 0 for i in range(0, len(path) - 1): time.sleep(3) from_vertex = graph.get_vertex(path[i]) to_vertex = graph.get_vertex(path[i + 1]) # get current real layer elements = engine.get_touchable_elements() if forbid_names: elements = [ e for e in elements if e[0].object_name not in forbid_names ] elements = find_in_screen_elements(elements) scene_name = engine.get_scene() elements = get_desuffixed_elements(elements) curr_layer = ViewLayer() for e, _ in elements: te = TouchElem(scene_name, e) curr_layer.add_element(te) curr_layer.sort_elems_by_name() # current layer diff from memory if curr_layer != path[i]: if i > 0: logger.info( "layer in real not equal to layer in memory, need to reset the edge" ) prev_layer = path[i - 1] prev_entry = graph.get_vertex(path[i - 1]).get_entry(from_vertex) graph.del_edge(path[i - 1], path[i]) else: logger.warn( "layer path[0] in real not equal to layer in memory, impossible?!" ) break else: logger.info("layer in real match memory, good") edge_element = from_vertex.get_entry(to_vertex) elem = engine.find_element(edge_element.element.object_name) if elem: tools.screen_shot_click(elem) num += 1 logger.info("go through path from %s to %s, edge is %s", path[i], path[i + 1], edge_element) else: logger.info("no entry %s in layer %s, clear the edge", edge_element, path[i]) graph.del_edge(path[i], path[i + 1]) break else: # last layer in path time.sleep(3) # get current real layer elements = engine.get_touchable_elements() if forbid_names: elements = [ e for e in elements if e[0].object_name not in forbid_names ] elements = find_in_screen_elements(elements) scene_name = engine.get_scene() elements = get_desuffixed_elements(elements) curr_layer = ViewLayer() for e, _ in elements: te = TouchElem(scene_name, e) curr_layer.add_element(te) curr_layer.sort_elems_by_name() if curr_layer != path[-1]: if len(path) > 1: logger.info( "layer in real not equal to layer in memory, need to reset the edge" ) prev_layer = path[-2] prev_entry = graph.get_vertex(path[-2]).get_entry( graph.get_vertex(path[-1])) graph.del_edge(path[-2], path[-1]) else: logger.warn( "layer path[0] in real not equal to layer in memory, impossible?!" ) else: logger.info("layer in real match memory, good") return (prev_layer, prev_entry, num)