Esempio n. 1
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.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)
Esempio n. 2
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.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)
Esempio n. 3
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)

    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)
Esempio n. 4
0
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)
Esempio n. 5
0
 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()
Esempio n. 6
0
 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
Esempio n. 7
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)
Esempio n. 9
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, 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)
Esempio n. 10
0
    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')
Esempio n. 11
0
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)
Esempio n. 12
0
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)
Esempio n. 13
0
 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()
Esempio n. 14
0
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)
Esempio n. 15
0
                        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)
Esempio n. 16
0
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)
Esempio n. 17
0
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)
Esempio n. 18
0
                        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
Esempio n. 19
0
    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)
Esempio n. 20
0
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")
Esempio n. 21
0
 def __init__(self, keyboard: Queue, pipe: Queue):
     self.config = Reader()
     self.keyboard = keyboard
     self.pipe = pipe