def main(): parser = argparse.ArgumentParser(description="LSTM CRF implementation") opt = parse_arguments(parser) conf = Config(opt) reader = Reader(conf.digit2zero) set_seed(opt, conf.seed) trains = reader.read_txt(conf.train_file, conf.train_num) devs = reader.read_txt(conf.dev_file, conf.dev_num) tests = reader.read_txt(conf.test_file, conf.test_num) if conf.context_emb != ContextEmb.none: print('Loading the ELMo vectors for all datasets.') conf.context_emb_size = load_elmo_vec(conf.train_file + "." + conf.context_emb.name + ".vec", trains) load_elmo_vec(conf.dev_file + "." + conf.context_emb.name + ".vec", devs) load_elmo_vec(conf.test_file + "." + conf.context_emb.name + ".vec", tests) conf.build_label_idx(trains) conf.build_word_idx(trains, devs, tests) conf.build_emb_table() conf.map_insts_ids(trains) conf.map_insts_ids(devs) conf.map_insts_ids(tests) print("num chars: " + str(conf.num_char)) # print(str(config.char2idx)) print("num words: " + str(len(conf.word2idx))) # print(config.word2idx) train_model(conf, conf.num_epochs, trains, devs, tests)
def main(): parser = argparse.ArgumentParser(description="LSTM CRF implementation") opt = parse_arguments(parser) conf = Config(opt) reader = Reader(conf.digit2zero) set_seed(opt, conf.seed) trains = reader.read_txt(conf.train_file, conf.train_num) devs = reader.read_txt(conf.dev_file, conf.dev_num) tests = reader.read_txt(conf.test_file, conf.test_num) if conf.context_emb != ContextEmb.none: logging.info('[Data Info] Loading the ELMo vectors for all datasets.') conf.context_emb_size = load_elmo_vec( conf.train_file + "." + conf.context_emb.name + ".vec", trains) load_elmo_vec(conf.dev_file + "." + conf.context_emb.name + ".vec", devs) load_elmo_vec(conf.test_file + "." + conf.context_emb.name + ".vec", tests) # conf.use_iobes(trains + devs + tests) conf.build_label_idx(trains + devs + tests) conf.build_word_idx(trains, devs, tests) conf.build_emb_table() conf.map_insts_ids(devs + tests) logging.info("[Data Info] num chars: " + str(conf.num_char)) logging.info("[Data Info] num words: " + str(len(conf.word2idx))) logging.info( f"[Data Info] Removing {conf.entity_keep_ratio*100}% of entities from the training set" ) logging.info("[Data Info] Removing the entities") ## it will return the set of removed entities (for debug purpose) _ = remove_entites(trains, conf) # logging.info(f"entities removed: {span_set}") conf.map_insts_ids(trains) random.shuffle(trains) for inst in trains: inst.is_prediction = [False] * len(inst.input) if conf.variant == "soft": inst.marginals = np.full((len(inst.input), conf.label_size), -1e10) for pos, label in enumerate(inst.output): if label == conf.O: inst.is_prediction[pos] = True if conf.variant == "soft": inst.marginals[pos, conf.label2idx[label]] = 0 num_insts_in_fold = math.ceil(len(trains) / conf.num_folds) trains = [ trains[i * num_insts_in_fold:(i + 1) * num_insts_in_fold] for i in range(conf.num_folds) ] train_model(config=conf, train_insts=trains, dev_insts=devs, test_insts=tests)
def main(): parser = argparse.ArgumentParser(description="LSTM CRF implementation") opt = parse_arguments(parser) conf = Config(opt) reader = Reader(conf.digit2zero) set_seed(opt, conf.seed) if "ontonotes" in conf.train_file: trains = reader.read_conll(conf.train_file, conf.train_num) devs = reader.read_conll(conf.dev_file, conf.dev_num) tests = reader.read_conll(conf.test_file, conf.test_num) else: trains = reader.read_txt(conf.train_file, conf.train_num) if conf.typing_model: devs = reader.read_txt_with_extraction(conf.dev_file, conf.dev_extraction, conf.dev_num) tests = reader.read_txt_with_extraction(conf.test_file, conf.test_extraction, conf.test_num) else: devs = reader.read_txt(conf.dev_file, conf.dev_num) tests = reader.read_txt(conf.test_file, conf.test_num) if conf.context_emb != ContextEmb.none: print('Loading the ELMo vectors for all datasets.') conf.context_emb_size = load_elmo_vec( conf.train_file + "." + conf.context_emb.name + ".vec", trains) load_elmo_vec(conf.dev_file + "." + conf.context_emb.name + ".vec", devs) load_elmo_vec(conf.test_file + "." + conf.context_emb.name + ".vec", tests) conf.use_iobes(trains + devs + tests) conf.build_label_idx(trains + devs + tests) conf.build_word_idx(trains, devs, tests) conf.build_emb_table() conf.map_insts_ids(trains + devs + tests) if conf.typing_model: """ Building mapping, for example: {B-per: [B-per, B-org, B-misc], O: O, I-org: [I-per, I-org]} Will be used when creating the mask """ conf.typing_map = build_type_id_mapping(conf) print("num chars: " + str(conf.num_char)) # print(str(config.char2idx)) print("num words: " + str(len(conf.word2idx))) # print(config.word2idx) train_model(conf, conf.num_epochs, trains, devs, tests)
def main(): parser = argparse.ArgumentParser() opt = parse_arguments(parser) conf = Config(opt) reader = Reader(conf.digit2zero) dataset, max_length, label_length = reader.read_trigger_txt( conf.trigger_file, -1) reader.merge_labels(dataset) trains = reader.read_txt(conf.train_all_file, conf.train_num) devs = reader.read_txt(conf.dev_file, conf.dev_num) tests = reader.read_txt(conf.test_file, conf.test_num) print(len(dataset)) if conf.context_emb == ContextEmb.bert: print('Loading the BERT vectors for all datasets.') conf.context_emb_size = load_bert_vec( conf.trigger_file + "." + conf.context_emb.name + ".vec", dataset) # setting for data conf.use_iobes(trains) conf.use_iobes(dataset) conf.use_iobes(devs) conf.use_iobes(tests) conf.optimizer = opt.trig_optimizer conf.build_label_idx(dataset) conf.build_word_idx(trains, devs, tests) conf.build_emb_table() conf.map_insts_ids(dataset) conf.map_insts_ids(trains) conf.map_insts_ids(devs) conf.map_insts_ids(tests) dataset = reader.trigger_percentage(dataset, conf.percentage) encoder = SoftMatcher(conf, label_length) trainer = SoftMatcherTrainer(encoder, conf, devs, tests) # matching module training random.shuffle(dataset) trainer.train_model(conf.num_epochs_soft, dataset) logits, predicted, triggers = trainer.get_triggervec(dataset) # all the trigger vectors, trigger type, string name of the trigger triggers_remove = remove_duplicates(logits, predicted, triggers, dataset) numbers = int(len(trains) * (1 - opt.unlabeled_percentage)) print("number of train instances : ", numbers) initial_trains = trains[:numbers] unlabeled_x = trains[numbers:] for data in unlabeled_x: data.output_ids = None # sequence labeling module self-training random.shuffle(dataset) inference = SoftSequence(conf, encoder) sequence_trainer = SoftSequenceTrainer(inference, conf, devs, tests, triggers_remove) sequence_trainer.self_training(conf.num_epochs, dataset, unlabeled_x)
def __init__(self, device: str, keyboard: Queue): """ device: 如果是 USB 连接,则为 adb devices 的返回结果;如果是模拟器,则为模拟器的控制 URL 。 """ self.d = u2.connect(device) self.config = Reader() self.upgrade_iter_round = 0 self.keyboard = keyboard self.command_mode = False # 检查 uiautomator if not self.d.uiautomator.running(): self.d.reset_uiautomator()
def __init__(self, device: str, keyboard: Queue): """ device: 如果是 USB 连接,则为 adb devices 的返回结果;如果是模拟器,则为模拟器的控制 URL 。 """ self.d = u2.connect(device) self.config = Reader() self.upgrade_iter_round = 0 self.keyboard = keyboard self.command_mode = False self._check_uiautomator() self.time_start_working = time.time() self.refresh_times = 0 self.delivered_times = 0
def main(): parser = argparse.ArgumentParser(description="LSTM CRF implementation") opt = parse_arguments(parser) conf = Config(opt) reader = Reader(conf.digit2zero) set_seed(opt, conf.seed) trains = reader.read_txt(conf.train_file, conf.train_num) devs = reader.read_txt(conf.dev_file, conf.dev_num) tests = reader.read_txt(conf.test_file, conf.test_num) if conf.static_context_emb != ContextEmb.none: print('Loading the static ELMo vectors for all datasets.') conf.context_emb_size = load_elmo_vec( conf.train_file + "." + conf.static_context_emb.name + ".vec", trains) load_elmo_vec( conf.dev_file + "." + conf.static_context_emb.name + ".vec", devs) load_elmo_vec( conf.test_file + "." + conf.static_context_emb.name + ".vec", tests) conf.use_iobes(trains + devs + tests) conf.build_label_idx(trains + devs + tests) if conf.embedder_type == "normal": conf.build_word_idx(trains, devs, tests) conf.build_emb_table() conf.map_insts_ids(trains) conf.map_insts_ids(devs) conf.map_insts_ids(tests) print("[Data Info] num chars: " + str(conf.num_char)) # print(str(conf.char2idx)) print("[Data Info] num words: " + str(len(conf.word2idx))) # print(config.word2idx) else: """ If we use the pretrained model from transformers we need to use the pretrained tokenizer """ print( colored( f"[Data Info] Tokenizing the instances using '{conf.embedder_type}' tokenizer", "red")) tokenize_instance( context_models[conf.embedder_type]["tokenizer"].from_pretrained( conf.embedder_type), trains + devs + tests, conf.label2idx) train_model(conf, conf.num_epochs, trains, devs, tests)
def main(): parser = argparse.ArgumentParser(description="LSTM CRF implementation") opt = parse_arguments(parser) conf = Config(opt) reader = Reader(conf.digit2zero) #set_seed(opt, conf.seed) trains = reader.read_txt(conf.train_file, conf.train_num) devs = reader.read_txt(conf.dev_file, conf.dev_num) tests = reader.read_txt(conf.test_file, conf.test_num) if conf.context_emb != ContextEmb.none: print('[Data Info] Loading the ELMo vectors for all datasets.') conf.context_emb_size = load_elmo_vec( conf.train_file + "." + conf.context_emb.name + ".vec", trains) load_elmo_vec(conf.dev_file + "." + conf.context_emb.name + ".vec", devs) load_elmo_vec(conf.test_file + "." + conf.context_emb.name + ".vec", tests) conf.use_iobes(trains + devs + tests) conf.use_iobes_gold(trains) conf.build_label_idx(trains + devs + tests) conf.build_word_idx(trains, devs, tests) conf.build_emb_table() conf.map_insts_ids(devs + tests) print("[Data Info] num chars: " + str(conf.num_char)) print("[Data Info] num words: " + str(len(conf.word2idx))) conf.map_insts_ids(trains) conf.get_gold_label_ids(trains) random.shuffle(trains) for inst in trains: inst.is_prediction = [False] * len(inst.input) for pos, label in enumerate(inst.output): if label == conf.O: inst.is_prediction[pos] = True num_insts_in_fold = math.ceil(len(trains) / conf.num_folds) trains = [ trains[i * num_insts_in_fold:(i + 1) * num_insts_in_fold] for i in range(conf.num_folds) ] train_model(config=conf, train_insts=trains, dev_insts=devs, test_insts=tests)
def main(): parser = argparse.ArgumentParser(description="LSTM CRF implementation") opt = parse_arguments(parser) conf = Config(opt) reader = Reader(conf.digit2zero) set_seed(opt, conf.seed) trains = reader.read_txt(conf.train_file, conf.train_num, conf.category) devs = reader.read_txt(conf.dev_file, conf.dev_num, conf.category) tests = reader.read_txt(conf.test_file, conf.test_num, conf.category) if conf.context_emb not in [ContextEmb.none, ContextEmb.mbert]: print('Loading the ELMo vectors for all datasets.') conf.context_emb_size = load_elmo_vec( conf.train_file + "." + conf.context_emb.name + ".vec", trains) load_elmo_vec(conf.dev_file + "." + conf.context_emb.name + ".vec", devs) load_elmo_vec(conf.test_file + "." + conf.context_emb.name + ".vec", tests) conf.use_iobes(trains) conf.use_iobes(devs) conf.use_iobes(tests) conf.build_label_idx(trains + devs + tests) if conf.context_emb == ContextEmb.mbert: from tokenizers import BertWordPieceTokenizer conf.bert_path = f'data/{conf.dataset}/distilbert-base-uncased' tokenizer = BertWordPieceTokenizer(f'{conf.bert_path}/vocab.txt', lowercase=True) conf.map_tokens_ids(trains, tokenizer) conf.map_tokens_ids(devs, tokenizer) conf.map_tokens_ids(tests, tokenizer) else: conf.build_word_idx(trains, devs, tests) conf.build_emb_table() conf.map_insts_ids(trains) conf.map_insts_ids(devs) conf.map_insts_ids(tests) print("num chars: " + str(conf.num_char)) # print(str(config.char2idx)) print("num words: " + str(len(conf.word2idx))) # print(config.word2idx) train_model(conf, conf.num_epochs, trains, devs, tests)
def start(self): """ 启动脚本,请确保已进入游戏页面。 """ while True: # 检查是否有键盘事件 if not self._need_continue(): self.schedule_keyboard.put('') self.p.join() break msg = self.pipe.get() if isinstance(msg, bytes) or msg.startswith(CONFIG_PREFIX): msg = msg[len(CONFIG_PREFIX):] if not isinstance( msg, bytes) else msg self.config = Reader.from_string(msg) elif msg.startswith(METHOD_PREFIX): msg = msg[len(METHOD_PREFIX):] method_list = msg.split(METHOD_SEP) method_list = sorted( method_list, key=lambda item: METHOD_ORDER.get(item, float('inf'))) # 简单粗暴的方式,处理 “XX之光” 的荣誉显示。 # 当然,也可以使用图像探测的模式。 self.d.click(550, 1650) logger.info(f'Scheduled method: [{", ".join(method_list)}]') for method_name in method_list: methodcaller(method_name)(self) logger.info('Sub process end')
def main(): parser = argparse.ArgumentParser(description="LSTM CRF implementation") opt = parse_arguments(parser) conf = Config(opt) reader = Reader(conf.digit2zero) setSeed(opt, conf.seed) trains = reader.read_txt(conf.train_file, conf.train_num, True) devs = reader.read_txt(conf.dev_file, conf.dev_num, False) tests = reader.read_txt(conf.test_file, conf.test_num, False) if conf.context_emb != ContextEmb.none: print('Loading the elmo vectors for all datasets.') conf.context_emb_size = reader.load_elmo_vec( conf.train_file + "." + conf.context_emb.name + ".vec", trains) reader.load_elmo_vec( conf.dev_file + "." + conf.context_emb.name + ".vec", devs) reader.load_elmo_vec( conf.test_file + "." + conf.context_emb.name + ".vec", tests) conf.use_iobes(trains) conf.use_iobes(devs) conf.use_iobes(tests) conf.build_label_idx(trains) conf.build_word_idx(trains, devs, tests) conf.build_emb_table() ids_train = conf.map_insts_ids(trains) ids_dev = conf.map_insts_ids(devs) ids_test = conf.map_insts_ids(tests) print("num chars: " + str(conf.num_char)) # print(str(config.char2idx)) print("num words: " + str(len(conf.word2idx))) # print(config.word2idx) if opt.mode == "train": learn_from_insts(conf, conf.num_epochs, trains, devs, tests) else: ## Load the trained model. test_model(conf, tests) # pass print(opt.mode)
def main(): logging.info("Transformer implementation") parser = argparse.ArgumentParser( description="Transformer CRF implementation") opt = parse_arguments_t(parser) conf = Config(opt) conf.train_file = conf.dataset + "/train.txt" conf.dev_file = conf.dataset + "/valid.txt" os.environ['CUDA_VISIBLE_DEVICES'] = opt.device_num # data reader reader = Reader(conf.digit2zero) set_seed(opt, conf.seed) # set logger utils.set_logger(os.path.join(conf.model_folder, 'train.log')) # params for k in opt.__dict__: logging.info(k + ": " + str(opt.__dict__[k])) # read trains/devs logging.info("\n") logging.info("Loading the datasets...") trains = reader.read_txt(conf.train_file, conf.train_num) devs = reader.read_txt(conf.dev_file, conf.dev_num) logging.info("Building label idx ...") # build label2idx and idx2label conf.build_label_idx(trains + devs) random.shuffle(trains) # set the prediction flag, if is_prediction is False, we will not update this label. for inst in trains: inst.is_prediction = [False] * len(inst.input) for pos, label in enumerate(inst.output): if label == conf.O: inst.is_prediction[pos] = True # dividing the data into 2 parts(num_folds default to 2) num_insts_in_fold = math.ceil(len(trains) / conf.num_folds) trains = [ trains[i * num_insts_in_fold:(i + 1) * num_insts_in_fold] for i in range(conf.num_folds) ] train_model(config=conf, train_insts=trains, dev_insts=devs)
def __init__(self, device: str, keyboard: Queue): """ device: 如果是 USB 连接,则为 adb devices 的返回结果;如果是模拟器,则为模拟器的控制 URL 。 """ self.d = u2.connect(device) self.config = Reader() self.upgrade_iter_round = 0 self.keyboard = keyboard self.schedule_keyboard = Queue() self.pipe = Queue() self.p = Process(target=make_scheduler, args=(self.schedule_keyboard, self.pipe)) self.p.start()
class Automator: def __init__(self, device: str, keyboard: Queue): """ device: 如果是 USB 连接,则为 adb devices 的返回结果;如果是模拟器,则为模拟器的控制 URL 。 """ self.d = u2.connect(device) self.config = Reader() self.upgrade_iter_round = 0 self.keyboard = keyboard self.command_mode = False self._check_uiautomator() self.time_start_working = time.time() self.refresh_times = 0 self.delivered_times = 0 def _need_continue(self): if not self.keyboard.empty(): # 不在命令模式下时才接受回车暂停 if not self.command_mode: txt = self.keyboard.get() if txt == prop.END: logger.info('End') return False logger.info('Pause') txt = self.keyboard.get() if txt == prop.END: logger.info('End') return False # 判断是否输入命令 elif txt.split(' ')[0] == prop.RUN: # 若输入了命令则进行解析 self._interpreter(txt.split(' ')[1:]) return True else: logger.info('Restart') return True else: return True def _interpreter(self, cmd): """ cmd: 用户输入的命令 """ # logger.info(txt.split(' ')[1:]) op = cmd[0] # 命令 - 升至 x 级 if op == prop.UPGRADE_TO: try: target_level = int(cmd[1]) except Exception: logger.warn("Invalid number. Ignored.") else: self._upgrade_to(target_level) # 命令 - 升级 x 次 elif op == prop.UPGRADE_TIMES: try: input_num = int(cmd[1]) except Exception: logger.warn("Invalid number. Ignored.") else: self._upgrade_times(input_num) # 命令 - 命令模式 elif op == prop.COMMAND_MODE: if len(cmd) == 2 and cmd[1] == 'on': self.command_mode = True logger.info('Enter command mode.') elif len(cmd) == 2 and cmd[1] == 'off': self.command_mode = False logger.info('Exit command mode.') self._return_main_area() else: logger.warn("Unknown parameter. Ignored.") # 命令 - 拆红包 elif op == prop.UNPACK: if len(cmd) == 3 and cmd[1] in ['s', 'm', 'l']: try: input_num = int(cmd[2]) except Exception: logger.warn("Invalid number. Ignored.") else: self._unpack_times(cmd[1], input_num) logger.info('Unpack complete.') else: logger.warn("Unknown parameter. Ignored.") elif op == prop.OPEN_ALBUM: try: input_num = int(cmd[1]) except Exception: logger.warn("Invalid number. Ignored.") else: self._open_albums(input_num) logger.info('Open complete.') elif op == prop.SUMMARY: self._print_summary() # 无法识别命令 else: logger.warn("Unknown command. Ignored.") if not self.command_mode: logger.info('Restart') def start(self): """ 启动脚本,请确保已进入游戏页面。 """ tmp_upgrade_last_time = time.time() logger.info("Start Working") while True: # 检查是否有键盘事件 if not self._need_continue(): break # 进入命令模式后不继续执行常规操作 if self.command_mode: continue # 更新配置文件 self.config.refresh() if self.config.debug_mode: logger.info("Debug mode") # 重启游戏法 # self._refresh_train_by_restart() # 重连 wifi 法 # self._refresh_train_by_reconnect() # 是否检测货物 if self.config.detect_goods: logger.info('-' * 30) logger.info("Start matching goods") # 获取当前屏幕快照 screen = self._safe_screenshot() # 判断是否出现货物。 has_goods = False refresh_flag = False for target in self.config.goods_2_building_seq.keys(): has_goods |= self._match_target(screen, target) # 如果需要刷新火车并且已送过目标货物 if has_goods and self.config.refresh_train: refresh_flag = True logger.info("All target goods delivered.") # 如果需要刷新火车并且未送过目标货物 elif self.config.refresh_train: for target in self.config.goods_2_building_seq_excpet_target.keys( ): if UIMatcher.match(screen, target) is not None: has_goods = True break if has_goods: refresh_flag = True logger.info("Train detected with no target goods.") else: logger.info("Train not detected.") if refresh_flag: # 刷新火车 logger.info("Refresh train.") logger.info("-" * 30) self.refresh_times += 1 if not self._refresh_train_by_restart(): # 重启不成功(超时)时中止脚本 logger.warn("Timed out waiting for restart!") break else: logger.info("End matching") # 简单粗暴的方式,处理 “XX之光” 的荣誉显示。 # 当然,也可以使用图像探测的模式。 self.d.click(550, 1650) # 滑动屏幕,收割金币。 logger.info("Collect coins") self._swipe() # 自动升级建筑 tmp_upgrade_interval = time.time() - tmp_upgrade_last_time if tmp_upgrade_interval >= self.config.upgrade_interval_sec: if self.config.upgrade_building is True: self._auto_upgrade_building() tmp_upgrade_last_time = time.time() else: logger.info( f"Left {round(self.config.upgrade_interval_sec - tmp_upgrade_interval, 2)}s to upgrade" ) time.sleep(self.config.swipe_interval_sec) self._print_summary() logger.info('Sub process end') def _swipe(self): """ 滑动屏幕,收割金币。 """ for i in range(3): # 横向滑动,共 3 次。 sx, sy = self._get_position(i * 3 + 1) ex, ey = self._get_position(i * 3 + 3) self.d.swipe(sx, sy, ex, ey) @staticmethod def _get_position(key): """ 获取指定建筑的屏幕位置。 ###7#8#9# ##4#5#6## #1#2#3### """ return prop.BUILDING_POS.get(key) def _get_target_position(self, target: TargetType): """ 获取货物要移动到的屏幕位置。 """ return self._get_position(self.config.goods_2_building_seq.get(target)) def _match_target(self, screen, target: TargetType): """ 探测货物,并搬运货物。 """ # 由于 OpenCV 的模板匹配有时会智障,故我们探测次数实现冗余。 counter = 6 logged = False while counter != 0: counter = counter - 1 # 使用 OpenCV 探测货物。 result = UIMatcher.match(screen, target) # 若无探测到,终止对该货物的探测。 # 实现冗余的原因:返回的货物屏幕位置与实际位置存在偏差,导致移动失效 if result is None: break rank = result[-1] result = result[:2] sx, sy = result # 获取货物目的地的屏幕位置。 ex, ey = self._get_target_position(target) if not logged: self.delivered_times += 1 logger.info(f"Detect {target} at ({sx},{sy}), rank: {rank}") logged = True # 搬运货物。 self.d.swipe(sx, sy, ex, ey) # 侧面反映检测出货物 return logged def _auto_upgrade_building(self): """ 按顺序升级建筑 """ logger.info("Start upgrade buildings") self.d.click(*prop.BUILDING_DETAIL_BTN) time.sleep(0.5) for pos in self.config.upgrade_building_list: self.d.click(*self._get_position(pos)) time.sleep(0.5) self.d.click(*prop.BUILDING_UPGRADE_BTN) time.sleep(0.5) self.d.click(*prop.BUILDING_DETAIL_BTN) logger.info("Upgrade complete") def _upgrade_to(self, target_level): """ target_level: 目标等级 升至 target_level 级 利用 Tesseract 识别当前等级后点击升级按钮 target_level - 当前等级次 """ screen = self._safe_screenshot() screen = UIMatcher.pre_building_panel(screen) tmp = UIMatcher.cut(screen, prop.BUILDING_INFO_PANEL_LEVEL_POS, (120, 50)) # import cv2 # cv2.imwrite("./tmp/screen.jpg", screen) tmp = UIMatcher.plain(tmp) tmp = UIMatcher.fill_color(tmp) tmp = UIMatcher.plain(tmp) txt = UIMatcher.image_to_txt(tmp, plus='-l chi_sim --psm 7') txt = UIMatcher.normalize_txt(txt) try: cur_level = int(txt) logger.info(f'Current level -> {cur_level}') except Exception: logger.warning(f'Current level -> {txt}') return click_times = target_level - cur_level self._upgrade_times(click_times) def _upgrade_times(self, click_times: int): """ click_times: 点击/升级次数 执行点击升级按钮的操作 click_times 次 """ # assert(times >= 0) while click_times > 0: click_times -= 1 bx, by = prop.BUILDING_INFO_PANEL_UPGRADE_BTN self.d.click(bx, by) time.sleep(0.015) logger.info("Upgrade complete") # 非命令模式下完成操作后返回主界面以继续常规流程 if not self.command_mode: self._return_main_area() def _return_main_area(self): """ 通过点击两次导航栏内建设按钮来回到主界面 """ time.sleep(0.5) tx, ty = prop.CONSTRUCT_BTN self.d.click(tx, ty) time.sleep(0.1) self.d.click(tx, ty) time.sleep(0.5) def _unpack_times(self, pack_type, num: int): """ 开红包 num 个 """ # 红包标题栏坐标 开红包后点这里直到开完这个红包 tx, ty = prop.REDPACKET_TITLE_POS if pack_type == 'm': bx, by = prop.REDPACKET_BTN_M t = 12 elif pack_type == 'l': bx, by = prop.REDPACKET_BTN_L t = 24 else: bx, by = prop.REDPACKET_BTN_S t = 6 self.d.click(bx, by) time.sleep(1) while num > 1: num -= 1 self.d.press("enter") time.sleep(0.08) time.sleep(1) # 防止意外多点几下 例如升星或开出史诗 for _ in range(t): self.d.click(tx, ty) time.sleep(0.25) if not self.command_mode: self._return_main_area() def _open_albums(self, num: int): """ 开相册 num 个 """ self.d.click(*prop.ALBUM_BTN) time.sleep(1) while num > 1: num -= 1 self.d.press("enter") time.sleep(0.08) time.sleep(1) for _ in range(4): self.d.click(*prop.REDPACKET_TITLE_POS) time.sleep(0.5) if not self.command_mode: self._return_main_area() def _is_good_to_go(self): """ 检测是否有排行图标来判断是否进入了游戏界面 """ screen = self._safe_screenshot() return UIMatcher.match(screen, TargetType.Rank_btn) is not None def _refresh_train_by_restart(self): """ 通过重启游戏的方法来刷新火车 全程用时大约在 20s 左右 qq 账号测试不用授权 20s 左右 """ time_before_restart = time.time() self.d.app_stop("com.tencent.jgm") self.d.app_start("com.tencent.jgm", activity=".MainActivity") time.sleep(5) good_to_go = False try_times = 0 while not good_to_go: try_times += 1 if self._is_good_to_go(): good_to_go = True logger.info( f"Refresh train costs {round(time.time() - time_before_restart, 2)}s." ) elif try_times >= 60: return False else: time.sleep(1) return True def _refresh_train_by_reconnect(self): """ 通过关闭开启 wifi 的方法刷新火车 要重新登陆+授权 暂时弃用 """ self.d.press("home") time.sleep(0.5) logger.info("Wifi disable.") logger.info(self.d.adb_shell("svc wifi disable")) time.sleep(0.5) logger.info("Wifi enable.") logger.info(self.d.adb_shell("svc wifi enable")) time.sleep(5) self.d.app_start("com.tencent.jgm", activity=".MainActivity") def _check_uiautomator(self): """ 检查 uiautomator 运行状态 """ if not self.d.uiautomator.running(): self.d.reset_uiautomator() def _safe_screenshot(self): """ 防止执行 screenshot 时报错终止 """ self._check_uiautomator() return self.d.screenshot(format="opencv") def _print_summary(self): logger.info('-' * 30) pass_time = time.time() - self.time_start_working logger.info( f"本次启动运行了 {int(pass_time // 3600)} 小时 {int(pass_time % 3600 // 60)} 分钟 {round(pass_time % 60, 2)} 秒" ) logger.info( f"重启了 {self.refresh_times} 次, 检测到 {self.delivered_times} 车厢目标货物(非总送货次数)" ) logger.info('-' * 30)
help="+ hard / soft matching") # soft, hard parser.add_argument('--percentage', type=int, default=100, help="how much percentage of training dataset to use") args = parser.parse_args() for k in args.__dict__: print(k + ": " + str(args.__dict__[k])) return args parser = argparse.ArgumentParser() opt = parse_arguments(parser) conf = Config(opt) reader = Reader(conf.digit2zero) dataset, max_length, label_length = reader.read_trigger_txt( conf.trigger_file, -1) reader.merge_labels(dataset) devs = reader.read_txt(conf.dev_file, conf.dev_num) tests = reader.read_txt(conf.test_file, conf.test_num) print(len(dataset)) if conf.context_emb == ContextEmb.bert: print('Loading the BERT vectors for all datasets.') conf.context_emb_size = load_bert_vec( conf.trigger_file + "." + conf.context_emb.name + ".vec", dataset) # setting for data conf.use_iobes(dataset) conf.use_iobes(devs)
class Scheduler: def __init__(self, keyboard: Queue, pipe: Queue): self.config = Reader() self.keyboard = keyboard self.pipe = pipe def _generate_do_2_time(self): res = {} for config_name in CONFIG_NAME_2_METHOD_NAME.keys(): res[config_name] = set() return res # 判断哪些任务需要重新放回调度队列,有可能出现关闭一个任务后重启,而此时这个任务将会饿死,因为没有trigger def _generate_restart_list(self, do_2_time: dict, interval_map: dict): res = [] for config_name in interval_map.keys(): if interval_map[config_name] > 0 and len( do_2_time[config_name]) == 0: res.append(config_name) return res def _add_time_2_do(self, time_2_do: dict, new_time: int, do: str): if new_time not in time_2_do: time_2_do[new_time] = {do} else: time_2_do[new_time].add(do) def run(self): default_loop_interval = 5 loop_time = 0 # 记录哪个时间干哪些事(实际上只是塞队列) time_2_do = {} # 记录哪些事在哪些时候干 do_2_time = self._generate_do_2_time() while self.keyboard.empty(): # 更新配置 self.config.refresh() # self.pipe.put(f'{CONFIG_PREFIX}{self.config.to_string()}') self.pipe.put(self.config.to_string()) interval_map = self.config.interval_map pipe_msg = [] for config_name, interval in interval_map.items(): if interval <= 0: interval_map.pop(config_name) # 如果一个任务被置于<=0的值代表不希望被执行,那么同时需要把它移出任务队列 for _time in do_2_time[config_name]: time_2_do.get(_time, set()).discard(config_name) do_2_time[config_name] = set() # print(interval_map) if len(interval_map) == 0: loop_interval = default_loop_interval else: loop_interval = list_gcd(interval_map.values()) to_do_set = time_2_do.get(loop_time, set()) | set( self._generate_restart_list(do_2_time, interval_map)) # print(to_do_set) for config_name in to_do_set: # 塞入调度队列 pipe_msg.append(CONFIG_NAME_2_METHOD_NAME[config_name]) # 计算这个任务下一次何时调度 next_time = interval_map[ config_name] / loop_interval + loop_time # 更新time_2_do self._add_time_2_do(time_2_do, next_time, config_name) # 更新do_2_time do_2_time[config_name].discard(loop_time) do_2_time[config_name].add(next_time) # 把当前时间的任务队列销掉,节省内存 time_2_do.pop(loop_time, '') # print(pipe_msg) if len(pipe_msg) != 0: pipe_msg = f"{METHOD_PREFIX}{METHOD_SEP.join(pipe_msg)}" self.pipe.put(pipe_msg) loop_time += 1 time.sleep(loop_interval)
class Automator: def __init__(self, device: str, keyboard: Queue): """ device: 如果是 USB 连接,则为 adb devices 的返回结果;如果是模拟器,则为模拟器的控制 URL 。 """ self.d = u2.connect(device) self.config = Reader() self.upgrade_iter_round = 0 self.keyboard = keyboard self.command_mode = False # 检查 uiautomator if not self.d.uiautomator.running(): self.d.reset_uiautomator() def _need_continue(self): if not self.keyboard.empty(): # 不在命令模式下时才接受回车暂停 if not self.command_mode: txt = self.keyboard.get() # logger.info('txt1:' + txt) if txt == prop.END: logger.info('End') return False logger.info('Pause') txt = self.keyboard.get() # logger.info('txt2:' + txt) if txt == prop.END: logger.info('End') return False # 判断是否输入命令 elif txt.split(' ')[0] == prop.RUN: # logger.info(txt.split(' ')[1:]) cmd = txt.split(' ')[1] # 命令 - 升至 x 级 if cmd == prop.UPGRADE_TO: try: target_level = int(txt.split(' ')[2]) except Exception: logger.warn("Invalid number. Ignored.") else: self._upgrade_to(target_level) # logger.info('target_level: ' + str(target_level)) # 命令 - 升级 x 次 elif cmd == prop.UPGRADE_TIMES: try: input_num = int(txt.split(' ')[2]) except Exception: logger.warn("Invalid number. Ignored.") else: self._upgrade_times(input_num) # 命令 - 命令模式 elif cmd == prop.COMMAND_MODE: if txt.split(' ')[2] == 'on': self.command_mode = True logger.info('Enter command mode.') elif txt.split(' ')[2] == 'off': self.command_mode = False logger.info('Exit command mode.') self._return_main_area() else: logger.warn("Unknown parameter. Ignored.") # 无法识别命令 else: logger.warn("Unknown command. Ignored.") if not self.command_mode: logger.info('Restart') return True else: logger.info('Restart') return True else: return True def start(self): """ 启动脚本,请确保已进入游戏页面。 """ tmp_upgrade_last_time = time.time() logger.info("Start Working") while True: # 检查是否有键盘事件 if not self._need_continue(): break # 进入命令模式后不继续执行常规操作 if self.command_mode: continue # 更新配置文件 self.config.refresh() # 在下午五点以后再开始拿火车,收益最大化 # if datetime.now().hour > 17: if True: logger.info("Start matching goods") # 获取当前屏幕快照 screen = self.d.screenshot(format="opencv") # 判断是否出现货物。 has_goods = False for target in self.config.goods_2_building_seq.keys(): has_goods |= self._match_target(screen, target) if has_goods: UIMatcher.write(screen) # pass logger.info("End matching") # 简单粗暴的方式,处理 “XX之光” 的荣誉显示。 # 当然,也可以使用图像探测的模式。 self.d.click(550, 1650) # 滑动屏幕,收割金币。 # logger.info("swipe") self._swipe() # 升级建筑 tmp_upgrade_interval = time.time() - tmp_upgrade_last_time if tmp_upgrade_interval >= self.config.upgrade_interval_sec: if self.config.upgrade_type_is_assign is True: self._assigned_uprade() else: self._upgrade() tmp_upgrade_last_time = time.time() else: logger.info( f"Left {round(self.config.upgrade_interval_sec - tmp_upgrade_interval, 2)}s to upgrade" ) time.sleep(self.config.swipe_interval_sec) logger.info('Sub process end') def _swipe(self): """ 滑动屏幕,收割金币。 """ for i in range(3): # 横向滑动,共 3 次。 sx, sy = self._get_position(i * 3 + 1) ex, ey = self._get_position(i * 3 + 3) self.d.swipe(sx, sy, ex, ey) @staticmethod def _get_position(key): """ 获取指定建筑的屏幕位置。 ###7#8#9# ##4#5#6## #1#2#3### """ return prop.BUILDING_POS.get(key) def _get_target_position(self, target: TargetType): """ 获取货物要移动到的屏幕位置。 """ return self._get_position(self.config.goods_2_building_seq.get(target)) def _match_target(self, screen, target: TargetType): """ 探测货物,并搬运货物。 """ # 由于 OpenCV 的模板匹配有时会智障,故我们探测次数实现冗余。 counter = 6 logged = False while counter != 0: counter = counter - 1 # 使用 OpenCV 探测货物。 result = UIMatcher.match(screen, target) # 若无探测到,终止对该货物的探测。 # 实现冗余的原因:返回的货物屏幕位置与实际位置存在偏差,导致移动失效 if result is None: break rank = result[-1] result = result[:2] sx, sy = result # 获取货物目的地的屏幕位置。 ex, ey = self._get_target_position(target) if not logged: logger.info(f"Detect {target} at ({sx},{sy}), rank: {rank}") logged = True # 搬运货物。 self.d.swipe(sx, sy, ex, ey) # 侧面反映检测出货物 return logged def __find_selected_building_seq(self): selected_seq_list = elect(len(self.config.upgrade_order), self.upgrade_iter_round) tmp_set = set() for order_seq in selected_seq_list: tmp_set |= self.config.upgrade_order[order_seq] res = [] for i, building in enumerate(self.config.building_pos): if building in tmp_set: res.append(i + 1) if len(res) == 0: return list(prop.BUILDING_POS.keys()) else: return res def _select_min_building(self): screen = self.d.screenshot(format="opencv") screen = UIMatcher.pre(screen) min_level = float('inf') min_building_seq = None for key in self.__find_selected_building_seq(): pos = prop.BUILDING_LEVEL_POS[key] tmp = UIMatcher.cut(screen, pos) tmp = UIMatcher.plain(tmp) tmp = UIMatcher.fill_color(tmp) tmp = UIMatcher.plain(tmp) txt = UIMatcher.image_to_txt(tmp, plus='-l chi_sim --psm 7') txt = UIMatcher.normalize_txt(txt) try: level = int(txt) logger.info( f'{self.config.building_pos[key - 1]} tesser -> {level}') except Exception: logger.warning( f'{self.config.building_pos[key - 1]} tesser -> {txt}') continue if level < min_level: min_level = level min_building_seq = key # 一个屋子的等级都没拿到 if min_building_seq is None: res = choice(list(prop.BUILDING_POS.keys())) logger.warning( f'No tesseract result, random to {self.config.building_pos[res - 1]}' ) return res else: logger.info( f'Minimum level is {min_level} from {self.config.building_pos[min_building_seq - 1]}' ) return min_building_seq def _upgrade(self): logger.info("Start upgrading") # 迭代次数加一 self.upgrade_iter_round += 1 self.d.click(*prop.BUILDING_DETAIL_BTN) time.sleep(1) need_upgrade_building_seq = self._select_min_building() self.d.click(*self._get_position(need_upgrade_building_seq)) time.sleep(1) self.d.long_click(prop.BUILDING_UPGRADE_BTN[0], prop.BUILDING_UPGRADE_BTN[1], self.config.upgrade_press_time_sec) time.sleep(0.5) self.d.click(*prop.BUILDING_DETAIL_BTN) logger.info("Upgrade complete") def _assigned_uprade(self): logger.info("Start assigned upgrading") self.d.click(*prop.BUILDING_DETAIL_BTN) time.sleep(0.5) self.d.click(*self._get_position(self.config.assigned_building_pos)) time.sleep(0.5) self.d.long_click(prop.BUILDING_UPGRADE_BTN[0], prop.BUILDING_UPGRADE_BTN[1], self.config.upgrade_press_time_sec) time.sleep(0.5) self.d.click(*prop.BUILDING_DETAIL_BTN) logger.info("Upgrade complete") def _upgrade_to(self, target_level): """ target_level: 目标等级 升至 target_level 级 利用 Tesseract 识别当前等级后点击升级按钮 target_level - 当前等级次 """ screen = self.d.screenshot(format="opencv") screen = UIMatcher.pre_building_panel(screen) tmp = UIMatcher.cut(screen, prop.BUILDING_INFO_PANEL_LEVEL_POS, (120, 50)) # import cv2 # cv2.imwrite("./tmp/screen.jpg", screen) tmp = UIMatcher.plain(tmp) tmp = UIMatcher.fill_color(tmp) tmp = UIMatcher.plain(tmp) txt = UIMatcher.image_to_txt(tmp, plus='-l chi_sim --psm 7') txt = UIMatcher.normalize_txt(txt) try: cur_level = int(txt) logger.info(f'Current level -> {cur_level}') except Exception: logger.warning(f'Current level -> {txt}') return click_times = target_level - cur_level self._upgrade_times(click_times) def _upgrade_times(self, click_times: int): """ click_times: 点击/升级次数 执行点击升级按钮的操作 click_times 次 """ # assert(times >= 0) while click_times > 0: click_times -= 1 bx, by = prop.BUILDING_INFO_PANEL_UPGRADE_BTN self.d.click(bx, by) time.sleep(0.015) logger.info("Upgrade complete") # 非命令模式下完成操作后返回主界面以继续常规流程 if not self.command_mode: self._return_main_area() def _return_main_area(self): """ 通过点击两次导航栏内建设按钮来回到主界面 """ time.sleep(0.5) tx, ty = prop.CONSTRUCT_BTN self.d.click(tx, ty) time.sleep(0.1) self.d.click(tx, ty) time.sleep(0.5)
help="+ hard / soft matching") # soft, hard parser.add_argument('--percentage', type=int, default=100, help="how much percentage of training dataset to use") args = parser.parse_args() for k in args.__dict__: print(k + ": " + str(args.__dict__[k])) return args parser = argparse.ArgumentParser() opt = parse_arguments(parser) conf = Config(opt) reader = Reader(conf.digit2zero) dataset = reader.read_txt(conf.train_file, conf.dev_num) devs = reader.read_txt(conf.dev_file, conf.dev_num) tests = reader.read_txt(conf.test_file, conf.test_num) print(len(dataset)) if conf.context_emb == ContextEmb.bert: print('Loading the BERT vectors for all datasets.') conf.context_emb_size = load_bert_vec( conf.trigger_file + "." + conf.context_emb.name + ".vec", dataset) # setting for data conf.use_iobes(dataset) conf.use_iobes(devs) conf.use_iobes(tests) conf.optimizer = opt.trig_optimizer
parser.add_argument('--bert_path', type=str, default="./BERTOverflow") # parser.add_argument('--bert_path', type=str, default="./bert-base-cased") parser.add_argument('--from_pretrain', type=bool, default=True) parser.add_argument('--bert_embedding_size', type=int, default=768) parser.add_argument('--rnn', type=str, default='lstm') args = parser.parse_args() for k in args.__dict__: print(k + ": " + str(args.__dict__[k])) return args parser = argparse.ArgumentParser() opt = parse_arguments(parser) conf = Config(opt) reader = Reader(conf.digit2zero) # train_file = 'data/annotated_ner_data/StackOverflow/train.txt' # dev_file = 'data/annotated_ner_data/StackOverflow/dev.txt' # test_file = 'data/annotated_ner_data/StackOverflow/test.txt' # dataset = reader.read_txt(train_file, -1) # devs = reader.read_txt(dev_file, -1) # tests = reader.read_txt(test_file, -1) dataset = reader.read_txt(conf.train_all_file, -1) # devs = reader.read_txt(conf.dev_file, -1) tests = reader.read_txt(conf.test_file, -1) print(len(dataset)) # setting for data conf.use_iobes(dataset)
class Automator: def __init__(self, device: str, keyboard: Queue): """ device: 如果是 USB 连接,则为 adb devices 的返回结果;如果是模拟器,则为模拟器的控制 URL 。 """ self.d = u2.connect(device) self.config = Reader() self.upgrade_iter_round = 0 self.keyboard = keyboard self.command_mode = False # 检查 uiautomator if not self.d.uiautomator.running(): self.d.reset_uiautomator() self.time_start_working = time.time() self.refresh_times = 0 self.delivered_times = 0 def _need_continue(self): if not self.keyboard.empty(): # 不在命令模式下时才接受回车暂停 if not self.command_mode: txt = self.keyboard.get() # logger.info('txt1:' + txt) if txt == prop.END: logger.info('End') return False logger.info('Pause') txt = self.keyboard.get() # logger.info('txt2:' + txt) if txt == prop.END: logger.info('End') return False # 判断是否输入命令 elif txt.split(' ')[0] == prop.RUN: # logger.info(txt.split(' ')[1:]) cmd = txt.split(' ')[1] # 命令 - 升至 x 级 if cmd == prop.UPGRADE_TO: try: target_level = int(txt.split(' ')[2]) except Exception: logger.warn("Invalid number. Ignored.") else: self._upgrade_to(target_level) # logger.info('target_level: ' + str(target_level)) # 命令 - 升级 x 次 elif cmd == prop.UPGRADE_TIMES: try: input_num = int(txt.split(' ')[2]) except Exception: logger.warn("Invalid number. Ignored.") else: self._upgrade_times(input_num) # 命令 - 命令模式 elif cmd == prop.COMMAND_MODE: if txt.split(' ')[2] == 'on': self.command_mode = True logger.info('Enter command mode.') elif txt.split(' ')[2] == 'off': self.command_mode = False logger.info('Exit command mode.') self._return_main_area() else: logger.warn("Unknown parameter. Ignored.") # 命令 - 拆红包 elif cmd == prop.UNPACK: pack_type = txt.split(' ')[2] if pack_type in ['s', 'm', 'l']: try: input_num = int(txt.split(' ')[3]) except Exception: logger.warn("Invalid number. Ignored.") else: self._unpack_times(pack_type, input_num) logger.info('Unpack complete.') else: logger.warn("Unknown parameter. Ignored.") elif cmd == prop.OPEN_ALBUM: try: input_num = int(txt.split(' ')[2]) except Exception: logger.warn("Invalid number. Ignored.") else: self._open_albums(input_num) logger.info('Open complete.') # 无法识别命令 else: logger.warn("Unknown command. Ignored.") if not self.command_mode: logger.info('Restart') return True else: logger.info('Restart') return True else: return True def start(self): """ 启动脚本,请确保已进入游戏页面。 """ tmp_upgrade_last_time = time.time() logger.info("Start Working") while True: # 检查是否有键盘事件 if not self._need_continue(): logger.info('-' * 30) pass_time = time.time() - self.time_start_working logger.info(f"本次启动运行了 {int(pass_time // 3600)} 小时 {int(pass_time % 3600 // 60)} 分钟 {round(pass_time % 60, 2)} 秒") logger.info(f"重启了 {self.refresh_times} 次, 检测到 {self.delivered_times} 次货物(非总送货次数)") break # 进入命令模式后不继续执行常规操作 if self.command_mode: continue # 更新配置文件 self.config.refresh() if self.config.debug_mode: None # 重启游戏法 # self._refresh_train_by_restart() # 重连 wifi 法 # self._refresh_train_by_reconnect() # 是否检测货物 if self.config.detect_goods: logger.info('-' * 30) logger.info("Start matching goods") # 获取当前屏幕快照 screen = self.d.screenshot(format="opencv") # 判断是否出现货物。 has_goods = False refresh_flag = False for target in self.config.goods_2_building_seq.keys(): has_goods |= self._match_target(screen, target) # 如果需要刷新火车并且已送过目标货物 if has_goods and self.config.refresh_train: refresh_flag = True logger.info("All target goods delivered.") # 如果需要刷新火车并且未送过目标货物 elif self.config.refresh_train: for target in self.config.goods_2_building_seq_excpet_target.keys(): if UIMatcher.match(screen, target) is not None: has_goods = True break if has_goods: refresh_flag = True logger.info("Train detected with no target goods.") else: logger.info("Train not detected.") if refresh_flag: # 刷新火车 logger.info("Refresh train.") logger.info("-" * 30) self.refresh_times += 1 self._refresh_train_by_restart() else: logger.info("End matching") # 简单粗暴的方式,处理 “XX之光” 的荣誉显示。 # 当然,也可以使用图像探测的模式。 self.d.click(550, 1650) # 滑动屏幕,收割金币。 # logger.info("swipe") self._swipe() # 升级建筑 tmp_upgrade_interval = time.time() - tmp_upgrade_last_time if tmp_upgrade_interval >= self.config.upgrade_interval_sec: if self.config.upgrade_type_is_assign is True: self._assigned_uprade() else: self._upgrade() tmp_upgrade_last_time = time.time() else: logger.info(f"Left {round(self.config.upgrade_interval_sec - tmp_upgrade_interval, 2)}s to upgrade") time.sleep(self.config.swipe_interval_sec) logger.info('Sub process end') def _swipe(self): """ 滑动屏幕,收割金币。 """ for i in range(3): # 横向滑动,共 3 次。 sx, sy = self._get_position(i * 3 + 1) ex, ey = self._get_position(i * 3 + 3) self.d.swipe(sx, sy, ex, ey) @staticmethod def _get_position(key): """ 获取指定建筑的屏幕位置。 ###7#8#9# ##4#5#6## #1#2#3### """ return prop.BUILDING_POS.get(key) def _get_target_position(self, target: TargetType): """ 获取货物要移动到的屏幕位置。 """ return self._get_position(self.config.goods_2_building_seq.get(target)) def _match_target(self, screen, target: TargetType): """ 探测货物,并搬运货物。 """ # 由于 OpenCV 的模板匹配有时会智障,故我们探测次数实现冗余。 counter = 6 logged = False while counter != 0: counter = counter - 1 # 使用 OpenCV 探测货物。 result = UIMatcher.match(screen, target) # 若无探测到,终止对该货物的探测。 # 实现冗余的原因:返回的货物屏幕位置与实际位置存在偏差,导致移动失效 if result is None: break rank = result[-1] result = result[:2] sx, sy = result # 获取货物目的地的屏幕位置。 ex, ey = self._get_target_position(target) if not logged: self.delivered_times += 1 logger.info(f"Detect {target} at ({sx},{sy}), rank: {rank}") logged = True # 搬运货物。 self.d.swipe(sx, sy, ex, ey) # 侧面反映检测出货物 return logged def __find_selected_building_seq(self): selected_seq_list = elect(len(self.config.upgrade_order), self.upgrade_iter_round) tmp_set = set() for order_seq in selected_seq_list: tmp_set |= self.config.upgrade_order[order_seq] res = [] for i, building in enumerate(self.config.building_pos): if building in tmp_set: res.append(i + 1) if len(res) == 0: return list(prop.BUILDING_POS.keys()) else: return res def _select_min_building(self): screen = self.d.screenshot(format="opencv") screen = UIMatcher.pre(screen) min_level = float('inf') min_building_seq = None for key in self.__find_selected_building_seq(): pos = prop.BUILDING_LEVEL_POS[key] tmp = UIMatcher.cut(screen, pos) tmp = UIMatcher.plain(tmp) tmp = UIMatcher.fill_color(tmp) tmp = UIMatcher.plain(tmp) txt = UIMatcher.image_to_txt(tmp, plus='-l chi_sim --psm 7') txt = UIMatcher.normalize_txt(txt) try: level = int(txt) logger.info(f'{self.config.building_pos[key - 1]} tesser -> {level}') except Exception: logger.warning(f'{self.config.building_pos[key - 1]} tesser -> {txt}') continue if level < min_level: min_level = level min_building_seq = key # 一个屋子的等级都没拿到 if min_building_seq is None: res = choice(list(prop.BUILDING_POS.keys())) logger.warning(f'No tesseract result, random to {self.config.building_pos[res - 1]}') return res else: logger.info(f'Minimum level is {min_level} from {self.config.building_pos[min_building_seq - 1]}') return min_building_seq def _upgrade(self): logger.info("Start upgrading") # 迭代次数加一 self.upgrade_iter_round += 1 self.d.click(*prop.BUILDING_DETAIL_BTN) time.sleep(1) need_upgrade_building_seq = self._select_min_building() self.d.click(*self._get_position(need_upgrade_building_seq)) time.sleep(1) self.d.long_click(prop.BUILDING_UPGRADE_BTN[0], prop.BUILDING_UPGRADE_BTN[1], self.config.upgrade_press_time_sec) time.sleep(0.5) self.d.click(*prop.BUILDING_DETAIL_BTN) logger.info("Upgrade complete") def _assigned_uprade(self): logger.info("Start assigned upgrading") self.d.click(*prop.BUILDING_DETAIL_BTN) time.sleep(0.5) self.d.click(*self._get_position(self.config.assigned_building_pos)) time.sleep(0.5) self.d.long_click(prop.BUILDING_UPGRADE_BTN[0], prop.BUILDING_UPGRADE_BTN[1], self.config.upgrade_press_time_sec) time.sleep(0.5) self.d.click(*prop.BUILDING_DETAIL_BTN) logger.info("Upgrade complete") def _upgrade_to(self, target_level): """ target_level: 目标等级 升至 target_level 级 利用 Tesseract 识别当前等级后点击升级按钮 target_level - 当前等级次 """ screen = self.d.screenshot(format="opencv") screen = UIMatcher.pre_building_panel(screen) tmp = UIMatcher.cut(screen, prop.BUILDING_INFO_PANEL_LEVEL_POS, (120, 50)) # import cv2 # cv2.imwrite("./tmp/screen.jpg", screen) tmp = UIMatcher.plain(tmp) tmp = UIMatcher.fill_color(tmp) tmp = UIMatcher.plain(tmp) txt = UIMatcher.image_to_txt(tmp, plus='-l chi_sim --psm 7') txt = UIMatcher.normalize_txt(txt) try: cur_level = int(txt) logger.info(f'Current level -> {cur_level}') except Exception: logger.warning(f'Current level -> {txt}') return click_times = target_level - cur_level self._upgrade_times(click_times) def _upgrade_times(self, click_times: int): """ click_times: 点击/升级次数 执行点击升级按钮的操作 click_times 次 """ # assert(times >= 0) while click_times > 0: click_times -= 1 bx, by = prop.BUILDING_INFO_PANEL_UPGRADE_BTN self.d.click(bx, by) time.sleep(0.015) logger.info("Upgrade complete") # 非命令模式下完成操作后返回主界面以继续常规流程 if not self.command_mode: self._return_main_area() def _return_main_area(self): """ 通过点击两次导航栏内建设按钮来回到主界面 """ time.sleep(0.5) tx, ty = prop.CONSTRUCT_BTN self.d.click(tx, ty) time.sleep(0.1) self.d.click(tx, ty) time.sleep(0.5) def _unpack_times(self, pack_type, sum: int): # 红包标题栏坐标 开红包后点这里直到开完这个红包 tx, ty = prop.REDPACKET_TITLE_POS if pack_type == 'm': bx, by = prop.REDPACKET_BTN_M t = 6 elif pack_type == 'l': bx, by = prop.REDPACKET_BTN_L t = 12 else: # logger.inf("暂不支持开小红包") bx, by = prop.REDPACKET_BTN_S t = 3 while sum > 0: sum -= 1 self.d.click(bx, by) time.sleep(0.5) self.d.click(tx, ty) time.sleep(0.5) # 防止意外多点几下 例如升星或开出史诗 for i in range(t): # logger.info(f"第{i}次点击") self.d.click(tx, ty) time.sleep(0.5) def _open_albums(self, sum: int): tx, ty = prop.ALBUM_BTN bx, by = prop.REDPACKET_TITLE_POS while sum > 0: sum -= 1 self.d.click(tx, ty) time.sleep(1) for i in range(5): logger.info(f"第{i}次点击") self.d.click(bx, by) time.sleep(0.5) def _is_good_to_go(self): screen = self.d.screenshot(format="opencv") return UIMatcher.match(screen, TargetType.Rank_btn) is not None def _refresh_train_by_restart(self): """ 通过重启游戏的方法来刷新火车 全程用时大约在 20s 左右 qq 账号测试不用授权 20s 左右 """ time_before_restart = time.time() self.d.app_stop("com.tencent.jgm") self.d.app_start("com.tencent.jgm", activity=".MainActivity") time.sleep(5) good_to_go = False while not good_to_go: if self._is_good_to_go(): good_to_go = True logger.info(f"Refresh train costs {round(time.time() - time_before_restart, 2)}s.") else: time.sleep(1) def _refresh_train_by_reconnect(self): """ 通过关闭开启 wifi 的方法刷新火车 要重新登陆+授权 暂时弃用 """ self.d.press("home") time.sleep(0.5) logger.info("Wifi disable.") logger.info(self.d.adb_shell("svc wifi disable")) time.sleep(0.5) logger.info("Wifi enable.") logger.info(self.d.adb_shell("svc wifi enable")) time.sleep(5) self.d.app_start("com.tencent.jgm", activity=".MainActivity")
def __init__(self, keyboard: Queue, pipe: Queue): self.config = Reader() self.keyboard = keyboard self.pipe = pipe