Пример #1
0
    def test_ayane5(self):
        print("test_ayane5 : ")

        server = ayane.AyaneruServer()
        for engine in server.engines:
            engine.set_engine_options({"Hash":"128","Threads":"1","NetworkDelay":"0","NetworkDelay2":"0","MaxMovesToDraw":"320" \
                , "MinimumThinkingTime":"0"})
            #engine.debug_print = True
            engine.connect("exe/YaneuraOu.exe")

        # 持ち時間設定。
        server.set_time_setting("byoyomi 100")  # 1手0.1秒
        # server.set_time_setting("time 1000 inc 2000")        # 1秒 + 1手2秒

        # これで対局が開始する
        server.game_start()

        # 対局が終了するのを待つ
        while not server.game_result.is_gameover():
            time.sleep(1)

        # 対局棋譜の出力
        print("game sfen = " + server.sfen)
        print("game_result = " + str(server.game_result))

        server.terminate()
Пример #2
0
    def test_ayane2(self):
        print("test_ayane2 : ")

        usi = ayane.UsiEngine()
        # usi.debug_print = True
        usi.set_engine_options({
            "Hash": "128",
            "Threads": "4",
            "NetworkDelay": "0",
            "NetworkDelay2": "0"
        })
        usi.connect("exe/YaneuraOu.exe")

        # usi.send_position("startpos moves 7g7f")
        # → 局面を指定しなければ初期局面のはず。
        # "isready"~"readyok"は完了してからしかusi_go()は実行されないのでここで待機などをする必要はない。

        # 時間を指定せずに思考させてみる。
        usi.usi_go("infinite")

        # 3秒待ってからstopコマンドを送信して、エンジンがbestmoveを返してくるまで待機する。
        time.sleep(3)
        usi.usi_stop()
        usi.wait_bestmove()

        # 思考内容を表示させてみる。
        print("=== UsiThinkResult ===\n" + usi.think_result.to_string())

        usi.disconnect()
        self.assertEqual(usi.engine_state, ayane.UsiEngineState.Disconnected)
Пример #3
0
    def test_ayane3(self):
        print("test_ayane3 : ")

        sfens = [
            "sfen 5R3/8k/9/9/7+b1/9/PP1+p5/LS7/KN7 b GSNrb3g2s2n3l15p",
            "sfen 5B1k1/9/9/5R3/9/9/1+P7/PP1+p5/K+P7 b Srb4g3s4n4l13p",
            "sfen 8k/6+Pg1/4+Bs2N/9/7+b1/9/PP1+p5/LS7/KN7 b GN2r2g2sn3l14p",
        ]

        usi = ayane.UsiEngine()
        # usi.debug_print = True
        usi.set_engine_options({
            "Hash": "128",
            "Threads": "4",
            "NetworkDelay": "0",
            "NetworkDelay2": "0"
        })
        usi.connect(self.__class__.engine_path)

        for sfen in sfens:
            usi.usi_position(sfen)

            # MultiPVで探索してMultiPVの2番目の指し手がMateスコアであるかで判定する。
            usi.send_command("multipv 2")
            # 5秒考えてみる
            usi.usi_go_and_wait_bestmove("btime 0 wtime 0 byoyomi 5000")

            if len(usi.think_result.pvs) < 2:
                print(f"sfen = {sfen} : only one move")
            else:
                print(f"sfen = {sfen} : 1つ目の指し手の評価値 {usi.think_result.pvs[0].eval.to_string()},"
                      f" 2つ目の指し手の評価値 {usi.think_result.pvs[1].eval.to_string()} ,"
                      f" 余詰めあり? {ayane.UsiEvalValue.is_mate_score(usi.think_result.pvs[1].eval)}")

        usi.disconnect()
Пример #4
0
    def test_ayane4(self):
        print("test_ayane4 : ")

        # エンジン二つ
        usis = []

        for _ in range(2):
            usi = ayane.UsiEngine()
        #    usi.debug_print = True
            usi.set_engine_options({
                "Hash": "128",
                "Threads": "1",
                "NetworkDelay": "0",
                "NetworkDelay2": "0",
                "MaxMovesToDraw": "256",
                "MinimumThinkingTime": "0"
            })
            usi.connect(self.__class__.engine_path)
            usis.append(usi)

        # 棋譜
        sfen = "startpos moves"
        # 手数
        game_ply = 1
        # 手番(先手=0 , 後手=1)
        turn = 0

        # 256手ルール
        while game_ply < 256:
            usi = usis[turn]

            # 局面を設定する
            usi.usi_position(sfen)

            # 0.1秒思考させる
            usi.usi_go_and_wait_bestmove("time 0 byoyomi 100")

            bestmove = usi.think_result.bestmove

            # 評価値を表示させてみる
            # print(usi.think_result.pvs[0].eval)
            # print(usi.think_result.pvs[0].eval.to_string())

            # 投了 or 宣言勝ち
            if bestmove == "resign" or bestmove == "win":
                break

            # 棋譜にこのbestmoveを連結
            sfen += " " + bestmove

            # 手番反転
            turn ^= 1
            game_ply += 1

        # 棋譜の出力
        print("game sfen = " + sfen)

        for usi in usis:
            usi.disconnect()
Пример #5
0
    def test_ayane6(self):
        print("test_ayane6 : ")

        server = ayane.MultiAyaneruServer()

        # 並列4対局

        # server.debug_print = True
        server.init_server(4)
        options = {
            "Hash": "128",
            "Threads": "1",
            "NetworkDelay": "0",
            "NetworkDelay2": "0",
            "MaxMovesToDraw": "320",
            "MinimumThinkingTime": "0"
        }

        # 1P,2P側のエンジンそれぞれを設定して初期化する。
        server.init_engine(0, "exe/YaneuraOu.exe", options)
        server.init_engine(1, "exe/YaneuraOu.exe", options)

        # 持ち時間設定。
        # server.set_time_setting("byoyomi 100")                 # 1手0.1秒
        server.set_time_setting(
            "byoyomi1p 100 byoyomi2p 200")  # 1P側、1手0.1秒 2P側1手0.2秒

        # これで対局が開始する
        server.game_start()

        # 10試合終了するのを待つ
        last_total_games = 0

        # ゲーム数が増えていたら、途中結果を出力する。
        def output_info():
            nonlocal last_total_games, server
            if last_total_games != server.total_games:
                last_total_games = server.total_games
                print(server.game_info())

        # 10局やってみる。
        while server.total_games < 10:
            output_info()
            time.sleep(1)
        output_info()

        server.game_stop()

        # 対局棋譜の出力
        # 例えば100局やるなら
        # "17 - 1 - 82(17.17% R-273.35[-348.9,-197.79]) winrate black , white = 48.48% , 51.52%"のように表示される。(はず)
        for kifu in server.game_kifus:
            print(
                f"game sfen = {kifu.sfen} , flip_turn = {kifu.flip_turn} , game_result = {str(kifu.game_result)}"
            )

        server.terminate()
Пример #6
0
    def test_ayane2(self):
        print("test_ayane2 : ")

        usi = ayane.UsiEngine()
        # usi.debug_print = True
        usi.set_engine_options({
            "Hash": "128",
            "Threads": "4",
            "NetworkDelay": "0",
            "NetworkDelay2": "0"
        })
        usi.connect(self.__class__.engine_path)
        self.do_test_ayane2(usi)
Пример #7
0
    def test_ayane1(self):
        print("test_ayane1 : ")

        # エンジンとやりとりするクラス
        usi = ayane.UsiEngine()

        # デバッグ用にエンジンとのやりとり内容を標準出力に出力する。
        # usi.debug_print = True

        # エンジンオプション自体は、基本的には"engine_options.txt"で設定する。(やねうら王のdocs/を読むべし)
        # 特定のエンジンオプションをさらに上書きで設定できる
        usi.set_engine_options({
            "Hash": "128",
            "Threads": "4",
            "NetworkDelay": "0",
            "NetworkDelay2": "0"
        })

        # エンジンに接続
        # 通常の思考エンジンであるものとする。
        usi.connect("exe/YaneuraOu.exe")

        # 開始局面から76歩の局面
        # ※ "position"コマンド、"go"コマンドなどについては、USIプロトコルの説明を参考にしてください。
        # cf.「USIプロトコルとは」: http://shogidokoro.starfree.jp/usi.html
        usi.usi_position("startpos moves 7g7f")

        # 現局面での指し手の集合を得る
        moves = usi.get_moves()
        self.assertEqual(
            moves,
            "1c1d 2c2d 3c3d 4c4d 5c5d 6c6d 7c7d 8c8d 9c9d 1a1b 9a9b 3a3b 3a4b 7a6b 7a7b 8b3b 8b4b 8b5b 8b6b 8b7b 8b9b 4a3b 4a4b 4a5b 5a4b 5a5b 5a6b 6a5b 6a6b 6a7b"
        )

        # 現在の局面の手番を得る
        turn = usi.get_side_to_move()
        self.assertEqual(turn, ayane.Turn.WHITE)

        # multipv 4で探索させてみる
        # 2秒思考して待機させる。
        usi.send_command("multipv 4")
        usi.usi_go_and_wait_bestmove("btime 0 wtime 0 byoyomi 2000")

        # 思考内容を表示させてみる。
        print("=== UsiThinkResult ===\n" + usi.think_result.to_string())

        # エンジンを切断
        usi.disconnect()
        self.assertEqual(usi.engine_state, ayane.UsiEngineState.Disconnected)
Пример #8
0
    def test_ayane1_ssh(self):
        print("test_ayane1_ssh : ")

        # エンジンとやりとりするクラス
        usi = ayane.SshUsiEngine()

        # デバッグ用にエンジンとのやりとり内容を標準出力に出力する。
        # usi.debug_print = True

        # エンジンオプション自体は、基本的には"engine_options.txt"で設定する。(やねうら王のdocs/を読むべし)
        # 特定のエンジンオプションをさらに上書きで設定できる
        usi.set_engine_options({
            "Hash": "128",
            "Threads": "4",
            "NetworkDelay": "0",
            "NetworkDelay2": "0"
        })

        # エンジンに接続
        # 通常の思考エンジンであるものとする。
        usi.connect('localhost', self.__class__.engine_path)

        self.do_test_ayane1(usi)
Пример #9
0
def AyaneruColosseum(arglist):
    # --- コマンドラインのparseここから ---

    parser = argparse.ArgumentParser("ayaneru-colosseum.py")

    # 持ち時間設定。デフォルト1秒
    parser.add_argument(
        "--time",
        type=str,
        default="byoyomi 100",
        help="持ち時間設定 AyaneruServer.set_time_setting()の引数と同じ。",
    )

    # home folder
    parser.add_argument("--home", type=str, default="", help="hole folder")

    # engine path
    parser.add_argument("--engine1",
                        type=str,
                        default="exe/YaneuraOu.exe",
                        help="engine1 path")
    parser.add_argument("--engine2",
                        type=str,
                        default="exe/YaneuraOu.exe",
                        help="engine2 path")

    # Hashサイズ。デフォルト64MB
    parser.add_argument("--hash1",
                        type=int,
                        default=128,
                        help="engine1 hashsize[MB]")
    parser.add_argument("--hash2",
                        type=int,
                        default=128,
                        help="engine2 hashsize[MB]")

    # 対局回数
    parser.add_argument("--loop",
                        type=int,
                        default=100,
                        help="number of games")

    # CPUコア数
    parser.add_argument("--cores",
                        type=int,
                        default=8,
                        help="cpu cores(number of logical thread)")

    # エンジンに割り当てるスレッド数
    parser.add_argument("--thread1",
                        type=int,
                        default=2,
                        help="number of engine1 thread")
    parser.add_argument("--thread2",
                        type=int,
                        default=2,
                        help="number of engine2 thread")

    # engine folder
    parser.add_argument("--eval1",
                        type=str,
                        default="eval",
                        help="engine1 eval")
    parser.add_argument("--eval2",
                        type=str,
                        default="eval",
                        help="engine2 eval2")

    # flip_turn
    parser.add_argument("--flip_turn",
                        type=bool,
                        default=True,
                        help="flip turn every game")

    # book_file
    parser.add_argument("--book_file",
                        type=str,
                        default=None,
                        help="book filepath")

    # start_gameply
    parser.add_argument("--start_gameply",
                        type=int,
                        default=24,
                        help="start game ply in the book")

    # BookDir
    parser.add_argument("--bookdir1",
                        type=str,
                        default="book",
                        help="book directory for engine1")
    parser.add_argument("--bookdir2",
                        type=str,
                        default="book",
                        help="book directory for engine2")

    # BookFile
    parser.add_argument("--bookfile1",
                        type=str,
                        default="no_book",
                        help="book file name for engine1")
    parser.add_argument("--bookfile2",
                        type=str,
                        default="no_book",
                        help="book file name for engine2")

    # Arbitrary options
    parser.add_argument(
        "--options",
        "-o",
        type=str,
        default=None,
        help="set arbitrary options as name:value for both engines")
    parser.add_argument(
        "--options1",
        "-o1",
        type=str,
        default=None,
        help="set arbitrary options as name:value for the 1st engine")
    parser.add_argument(
        "--options2",
        "-o2",
        type=str,
        default=None,
        help="set arbitrary options as name:value for the 2nd engine")

    # Early stopping
    parser.add_argument("--early_stopping", action="store_true")
    parser.add_argument(
        "--early_stopping_limit",
        type=int,
        default=0,
        help="stop when the lower limit get below the rating limit")

    args = parser.parse_args(arglist)

    # --- コマンドラインのparseここまで ---

    print("home           : {0}".format(args.home), flush=True)
    print("engine1        : {0}".format(args.engine1), flush=True)
    print("engine2        : {0}".format(args.engine2), flush=True)
    print("eval1          : {0}".format(args.eval1), flush=True)
    print("eval2          : {0}".format(args.eval2), flush=True)
    print("hash1          : {0}".format(args.hash1), flush=True)
    print("hash2          : {0}".format(args.hash2), flush=True)
    print("loop           : {0}".format(args.loop), flush=True)
    print("cores          : {0}".format(args.cores), flush=True)
    print("time           : {0}".format(args.time), flush=True)
    print("flip_turn      : {0}".format(args.flip_turn), flush=True)
    print("book file      : {0}".format(args.book_file), flush=True)
    print("start_gameply  : {0}".format(args.start_gameply), flush=True)
    print("bookdir1       : {0}".format(args.bookdir1), flush=True)
    print("bookdir2       : {0}".format(args.bookdir2), flush=True)
    print("bookfile1      : {0}".format(args.bookfile1), flush=True)
    print("bookfile2      : {0}".format(args.bookfile2), flush=True)
    print("options        : {0}".format(args.options), flush=True)
    print("options1       : {0}".format(args.options1), flush=True)
    print("options2       : {0}".format(args.options2), flush=True)
    print("early_stopping : {0}".format(args.early_stopping), flush=True)
    print("early_stopping_limit : {0}".format(args.early_stopping_limit),
          flush=True)

    # directory

    home = args.home
    engine1 = os.path.join(home, args.engine1)
    engine2 = os.path.join(home, args.engine2)
    eval1 = os.path.join(home, args.eval1)
    eval2 = os.path.join(home, args.eval2)
    bookdir1 = os.path.join(home, args.bookdir1)
    bookdir2 = os.path.join(home, args.bookdir2)

    # マルチあやねるサーバーをそのまま用いる
    server = ayane.MultiAyaneruServer()

    # 1対局に要するスレッド数
    # (先後、同時に思考しないので大きいほう)
    thread_total = max(args.thread1, args.thread2)
    # 何並列で対局するのか? 2スレほど余らせておかないとtimeupになるかもしれん。
    # メモリが足りるかは知らん。メモリ足りないとこれまたメモリスワップでtimeupになる。
    cores = max(args.cores - 2, 1)
    game_server_num = int(cores / thread_total)

    # エンジンとのやりとりを標準出力に出力する
    # server.debug_print = True

    # あやねるサーバーを起動
    server.init_server(game_server_num)

    # エンジンオプション
    options_common = {
        "NetworkDelay": "0",
        "NetworkDelay2": "0",
        "MaxMovesToDraw": "320",
        "MinimumThinkingTime": "0",
        # "BookFile": "no_book"
    }

    # command line options
    def split_opt(arg):
        argopt = {}
        if arg:
            for item in args.options.split(" "):
                name, value = item.split(":")
                argopt.update({name: value})
        return argopt

    #argopt = {}
    # if args.options:
    #    for item in args.options.split(" "):
    #        name, value = item.split(":")
    #        argopt.update({name: value})

    argopt = split_opt(args.options)
    argopt1 = split_opt(args.options1)
    argopt2 = split_opt(args.options2)
    print(f"argopt: {argopt}")
    print(f"argopt1: {argopt1}")
    print(f"argopt2: {argopt2}")

    options1p = {
        "USI_Hash": str(args.hash1),
        "Threads": str(args.thread1),
        "EvalDir": eval1,
        "BookDir": bookdir1,
        "BookFile": args.bookfile1
    }
    options2p = {
        "USI_Hash": str(args.hash2),
        "Threads": str(args.thread2),
        "EvalDir": eval2,
        "BookDir": bookdir2,
        "BookFile": args.bookfile2
    }

    # 1P,2P側のエンジンそれぞれを設定して初期化する。
    server.init_engine(0, engine1, {
        **options_common,
        **options1p,
        **argopt,
        **argopt1
    })
    server.init_engine(1, engine2, {
        **options_common,
        **options2p,
        **argopt,
        **argopt2
    })

    # 持ち時間設定。
    server.set_time_setting(args.time)

    # flip_turnを反映させる
    server.flip_turn_every_game = args.flip_turn

    # 定跡

    # テスト用の定跡ファイル
    # args.book_file = "book/records2016_10818.sfen"
    if args.book_file is None:
        start_sfens = ["startpos"]
    else:
        book_filepath = os.path.join(home, args.book_file)
        with open(book_filepath) as f:
            start_sfens = f.readlines()
    server.start_sfens = start_sfens
    server.start_gameply = args.start_gameply

    # 対局スレッド数、秒読み設定などを短縮文字列化する。
    if args.thread1 == args.thread2:
        game_setting_str = "t{0}".format(args.thread1)
    else:
        game_setting_str = "t{0},{1}".format(args.thread1, args.thread2)
    game_setting_str += (args.time.replace("byoyomi", "b").replace(
        "time", "t").replace("inc", "i").replace(" ", ""))

    # これで対局が開始する
    server.game_start()

    # loop回数試合終了するのを待つ
    last_total_games = 0
    loop = args.loop

    # ゲーム数が増えていたら、途中結果を出力する。
    def output_info():
        nonlocal last_total_games, server
        if last_total_games != server.total_games:
            last_total_games = server.total_games
            print(game_setting_str + "." + server.game_info(), flush=True)

    def early_stopping():
        nonlocal last_total_games, server, args, loop
        if args.early_stopping and (server.total_games > (loop / 10)) and (
                -server.game_rating().rating_lowerbound <
                args.early_stopping_limit):
            return True
        return False

    while server.total_games < loop and not early_stopping():
        output_info()
        time.sleep(1)
    output_info()

    server.game_stop()

    # 対局棋譜の出力
    # for kifu in server.game_kifus:
    #     print("game sfen = {0} , flip_turn = {1} , game_result = {2}".format(kifu.sfen , kifu.flip_turn , str(kifu.game_result)))

    server.terminate()

    return server.game_rating().win_rate
Пример #10
0
def AyaneruGate():

    # --- コマンドラインのparseここから ---

    parser = argparse.ArgumentParser("ayaneru-gate.py")

    # 持ち時間設定。デフォルト0.1秒。
    # エンジンのほうの設定でノード数を固定するとき秒数を固定するとか(MinimumThinkingTimeで)してエンジンを固定化するといいかも?
    parser.add_argument(
        "--time",
        type=str,
        default="byoyomi 100",
        help="持ち時間設定 AyaneruServer.set_time_setting()の引数と同じ。",
    )

    # home folder
    parser.add_argument("--home",
                        type=str,
                        default="AyaneruGate",
                        help="home folder")

    # イテレーション回数
    parser.add_argument("--iteration",
                        type=int,
                        default=10,
                        help="number of iterations")

    # 対局回数
    parser.add_argument("--loop", type=int, default=10, help="number of games")

    # CPUコア数
    parser.add_argument("--cores",
                        type=int,
                        default=8,
                        help="cpu cores(number of logical threads)")

    # flip_turn
    parser.add_argument("--flip_turn",
                        type=bool,
                        default=True,
                        help="flip turn every game")

    # book_file
    parser.add_argument(
        "--book_file",
        type=str,
        default="book/records2016_10818.sfen",
        help="book filepath",
    )

    # start_gameply
    parser.add_argument("--start_gameply",
                        type=int,
                        default=24,
                        help="start game ply in the book")

    args = parser.parse_args()

    # --- コマンドラインのparseここまで ---

    print("home           : {0}".format(args.home))
    print("iteration      : {0}".format(args.iteration))
    print("loop           : {0}".format(args.loop))
    print("cores          : {0}".format(args.cores))
    print("time           : {0}".format(args.time))
    print("flip_turn      : {0}".format(args.flip_turn))
    print("book file      : {0}".format(args.book_file))
    print("start_gameply  : {0}".format(args.start_gameply))

    # directory

    home = args.home
    log = ayane.Log(os.path.join(home, "log"))
    log.print("iteration start", output_datetime=True)

    # エンジンの列挙

    engines_folder = os.path.join(home, "engines")
    if not os.path.exists(engines_folder):
        print("Error : {0} folder is not exist.".format(engines_folder))
        return

    engine_infos = []  # List[EngineInfo]
    for engine_rel_path in os.listdir(engines_folder):
        info = EngineInfo()
        info.engine_folder = engine_rel_path
        info.read_engine_define(home)
        engine_infos.append(info)

    # 取得できたエンジンの一覧を表示
    if False:  # こんなん表示せんでええやろ。
        print("engines        :")
        for i, engine_info in enumerate(engine_infos):
            print("== Engine {0} ==".format(i))
            engine_info.print()

    # レーティングが変動するエンジンが少なくとも2つないと意味がない。
    non_fixed_rating_engines = 0
    for info in engine_infos:
        if not info.rating_fix:
            non_fixed_rating_engines += 1
    if non_fixed_rating_engines < 2:
        print("Error! : non fixed rating engine < 2")
        raise ValueError()

    # それぞれのエンジンのレーティングを表示する。
    def output_engine_rating():
        nonlocal log, engine_infos
        log.print("== engine rating list ==", also_print=True)
        for info in engine_infos:
            log.print(
                "engine : {0} , rating = {1} , rating_fix = {2} , threads = {3}"
                .format(
                    info.engine_display_name,
                    info.rating,
                    info.rating_fix,
                    info.engine_threads,
                ),
                also_print=True,
            )

    output_engine_rating()

    # サーバーを一つ起動して、任意の2エンジンで100対局ほど繰り返して、レーティングを変動させる。
    # あとは、それをloop回数だけ繰り返す。

    for it in range(args.iteration):
        log.print("iteration : {0}".format(it), output_datetime=True)

        # マルチあやねるサーバーの起動
        server = ayane.MultiAyaneruServer()

        # エンジンとのやりとりを標準出力に出力する
        # server.debug_print = True

        # 2つのエンジンを選択
        info1 = None
        info2 = None
        while True:
            num_of_engines = len(engine_infos)
            p1 = random.randint(0, num_of_engines - 1)
            p2 = random.randint(0, num_of_engines - 1)
            # 同じプレイヤー同士の対局には意味がない
            if p1 == p2:
                continue

            # engine番号が若い順になって欲しい。
            if p1 > p2:
                p1, p2 = p2, p1
                # pythonのswapテクニック

            info1 = engine_infos[p1]
            info2 = engine_infos[p2]
            # 両側がレーティング固定であっても意味がない。
            if info1.rating_fix and info2.rating_fix:
                continue

            # 条件を満たしたので抜ける
            break

        # 今回対局するエンジン名を出力

        log.print(
            "engine : {0} vs {1}".format(info1.engine_display_name,
                                         info2.engine_display_name),
            also_print=True,
        )

        # エンジンの設定

        engine1 = info1.engine_exe_fullpath(home)
        engine2 = info2.engine_exe_fullpath(home)

        thread1 = info1.engine_threads
        thread2 = info2.engine_threads

        # 1対局に要するスレッド数
        # (先後、同時に思考しないので大きいほう)
        thread_total = max(thread1, thread2)
        # 何並列で対局するのか? 2スレほど余らせておかないとtimeupになるかもしれん。
        # メモリが足りるかは知らん。メモリ足りないとこれまたメモリスワップでtimeupになる。
        cores = max(args.cores - 2, 1)
        game_server_num = int(cores / thread_total)

        # あやねるサーバーを起動
        server.init_server(game_server_num)

        # エンジンオプション
        options_common = {
            "NetworkDelay": "0",
            "NetworkDelay2": "0",
            "MaxMovesToDraw": "320",
            "MinimumThinkingTime": "0",
            "BookFile": "no_book",
        }
        # 1P,2P側のエンジンそれぞれを設定して初期化する。
        server.init_engine(0, engine1, options_common)
        server.init_engine(1, engine2, options_common)

        # 持ち時間設定。
        server.set_time_setting(args.time)

        # flip_turnを反映させる
        server.flip_turn_every_game = args.flip_turn

        # 定跡

        if args.book_file is None:
            start_sfens = ["startpos"]
        else:
            book_filepath = os.path.join(home, args.book_file)
            with open(book_filepath) as f:
                start_sfens = f.readlines()
        server.start_sfens = start_sfens
        server.start_gameply = args.start_gameply

        # 対局スレッド数、秒読み設定などを短縮文字列化する。
        if thread1 == thread2:
            game_setting_str = "t{0}".format(thread1)
        else:
            game_setting_str = "t{0},{1}".format(thread1, thread2)
        game_setting_str += (args.time.replace("byoyomi", "b").replace(
            "time", "t").replace("inc", "i").replace(" ", ""))

        # loop回数試合終了するのを待つ
        last_total_games = 0
        loop = args.loop

        # ゲーム数が増えていたら、途中結果を出力する。
        def output_info():
            nonlocal last_total_games, server, log
            if last_total_games != server.total_games:
                last_total_games = server.total_games
                log.print(game_setting_str + "." + server.game_info())

        # これで対局が開始する
        server.game_start()

        while server.total_games < loop:
            output_info()
            time.sleep(1)
        output_info()

        server.game_stop()

        # 対局棋譜の出力(ログとしてフォルダに書き出しておく)
        for kifu in server.game_kifus:
            log.print(
                "game sfen = {0} , flip_turn = {1} , game_result = {2}".format(
                    kifu.sfen, kifu.flip_turn, str(kifu.game_result)),
                also_print=False,
            )

        # 対局が終わったのでレーティングの移動を行う
        elo = server.game_rating()

        # 1P側は2P側よりどれだけ勝るか。
        # 完勝のときは+無限大扱いでいいと思う。(以下でclipするので)
        rating_diff = elo.rating

        # レーティングの移動量の絶対値の上限は、対局回数に比例させておく。
        # (少ない対局回数で思いっきり変動してしまうのを防ぐため)
        rating_diff = min(max(rating_diff, -loop), loop)

        player1_add = 0
        player2_add = 0
        if info1.rating_fix:
            player2_add = -rating_diff
        elif info2.rating_fix:
            player1_add = +rating_diff
        else:
            player1_add = +int(rating_diff / 2)
            player2_add = -int(rating_diff / 2)

        log.print(
            "Player1 : {0} , rating {1} -> {2}".format(
                info1.engine_display_name, info1.rating,
                info1.rating + player1_add),
            also_print=True,
        )
        log.print(
            "Player2 : {0} , rating {1} -> {2}".format(
                info2.engine_display_name, info2.rating,
                info2.rating + player2_add),
            also_print=True,
        )

        info1.rating += player1_add
        info2.rating += player2_add

        # レーティングが変動したのなら、エンジン設定ファイルに書き戻す
        if player1_add != 0:
            info1.write_engine_define(home)
        if player2_add != 0:
            info2.write_engine_define(home)

    # iteration回数だけ繰り返したので終了する。
    output_engine_rating()
    log.print("iteration end", also_print=True, output_datetime=True)
    server.terminate()
    log.close()
Пример #11
0
# 勝ち,負け,引き分けの結果を示す定数
WIN = 0
DRAW = 1
LOSE = 2

# Ayaneにおける結果をここでの結果に変換する辞書
result_converter = {
    ayane.GameResult.BLACK_WIN: WIN,
    ayane.GameResult.WHITE_WIN: LOSE,
    ayane.GameResult.DRAW: DRAW,
    ayane.GameResult.MAX_MOVES: DRAW
}

# インスタンス生成
server = ayane.AyaneruServer()

# サーバの設定
server.error_print = True
server.set_time_setting(f"byoyomi1p {args.time1} byoyomi2p {args.time2}")
server.moves_to_draw = 320

# YaneuraOuの設定
server.engines[1].set_engine_options({
    "USI_Ponder": "false",
    "NodesLimit": args.NodesLimit,
    "USI_Hash": hash_size,
    "BookMoves": 0,
    "NetworkDelay": 0,
    "NetworkDelay2": 0
})
Пример #12
0
def AyaneruColosseum():
    # --- コマンドラインのparseここから ---

    parser = argparse.ArgumentParser("ayaneru-colosseum.py")

    # 持ち時間設定。デフォルト1秒
    parser.add_argument("--time",type=str,default="byoyomi 100",help="持ち時間設定 AyaneruServer.set_time_setting()の引数と同じ。")

    # home folder
    parser.add_argument("--home",type=str,default="",help="hole folder")

    # engine path
    parser.add_argument("--engine1",type=str,default="exe/YaneuraOu.exe",help="engine1 path")
    parser.add_argument("--engine2",type=str,default="exe/YaneuraOu.exe",help="engine2 path")

    # Hashサイズ。デフォルト64MB
    parser.add_argument("--hash1",type=int,default=128,help="engine1 hashsize[MB]")
    parser.add_argument("--hash2",type=int,default=128,help="engine2 hashsize[MB]")

    # 対局回数
    parser.add_argument("--loop",type=int,default=100,help="number of games")

    # CPUコア数
    parser.add_argument("--cores",type=int,default=8,help="cpu cores(number of logical thread)")

    # エンジンに割り当てるスレッド数
    parser.add_argument("--thread1",type=int,default=2,help="number of engine1 thread")
    parser.add_argument("--thread2",type=int,default=2,help="number of engine2 thread")

    # engine folder
    parser.add_argument("--eval1",type=str,default="eval",help="engine1 eval")
    parser.add_argument("--eval2",type=str,default="eval",help="engine2 eval2")

    # flip_turn
    parser.add_argument("--flip_turn",type=bool,default=True,help="flip turn every game")

    # book_file
    parser.add_argument("--book_file",type=str,default=None,help="book filepath")

    # start_gameply
    parser.add_argument("--start_gameply",type=int,default=24,help="start game ply in the book")

    args = parser.parse_args()

    # --- コマンドラインのparseここまで ---

    print("home           : {0}".format(args.home))
    print("engine1        : {0}".format(args.engine1))
    print("engine2        : {0}".format(args.engine2))
    print("eval1          : {0}".format(args.eval1))
    print("eval2          : {0}".format(args.eval2))
    print("hash1          : {0}".format(args.hash1))
    print("hash2          : {0}".format(args.hash2))
    print("loop           : {0}".format(args.loop))
    print("cores          : {0}".format(args.cores))
    print("time           : {0}".format(args.time))
    print("flip_turn      : {0}".format(args.flip_turn))
    print("book file      : {0}".format(args.book_file))
    print("start_gameply  : {0}".format(args.start_gameply))

    # directory

    home = args.home
    engine1 = os.path.join(home,args.engine1)
    engine2 = os.path.join(home,args.engine2)
    eval1 = os.path.join(home,args.eval1)
    eval2 = os.path.join(home,args.eval2)

    # マルチあやねるサーバーをそのまま用いる
    server = ayane.MultiAyaneruServer()

    # 1対局に要するスレッド数
    # (先後、同時に思考しないので大きいほう)
    thread_total = max(args.thread1 , args.thread2)
    # 何並列で対局するのか? 2スレほど余らせておかないとtimeupになるかもしれん。
    # メモリが足りるかは知らん。メモリ足りないとこれまたメモリスワップでtimeupになる。
    cores = max(args.cores - 2 , 1)
    game_server_num = int(cores / thread_total)

    # エンジンとのやりとりを標準出力に出力する
    # server.debug_print = True

    # あやねるサーバーを起動
    server.init_server(game_server_num)

    # エンジンオプション
    options_common = {"NetworkDelay":"0","NetworkDelay2":"0","MaxMovesToDraw":"320","MinimumThinkingTime":"0","BookFile":"no_book"}
    options1p = {"Hash":str(args.hash1),"Threads":str(args.thread1),"EvalDir":eval1}
    options2p = {"Hash":str(args.hash2),"Threads":str(args.thread2),"EvalDir":eval2}

    # 1P,2P側のエンジンそれぞれを設定して初期化する。
    server.init_engine(0,engine1, {}.update(**options_common , **options1p))
    server.init_engine(1,engine2, {}.update(**options_common , **options2p))

    # 持ち時間設定。
    server.set_time_setting(args.time)

    # flip_turnを反映させる
    server.flip_turn_every_game = args.flip_turn

    # 定跡

    # テスト用の定跡ファイル
    # args.book_file = "book/records2016_10818.sfen"
    if args.book_file is None:
        start_sfens = ["startpos"]
    else:
        book_filepath = os.path.join(home,args.book_file)
        with open(book_filepath) as f:
            start_sfens = f.readlines()
    server.start_sfens = start_sfens
    server.start_gameply = args.start_gameply

    # 対局スレッド数、秒読み設定などを短縮文字列化する。
    if args.thread1 == args.thread2:
        game_setting_str = "t{0}".format(args.thread1)
    else:
        game_setting_str = "t{0},{1}".format(args.thread1,args.thread2)
    game_setting_str += args.time.replace("byoyomi","b").replace("time","t").replace("inc","i").replace(" ","")

    # これで対局が開始する
    server.game_start()

    # loop回数試合終了するのを待つ
    last_total_games = 0
    loop = args.loop

    # ゲーム数が増えていたら、途中結果を出力する。
    def output_info():
        nonlocal last_total_games , server
        if last_total_games != server.total_games:
            last_total_games = server.total_games
            print(game_setting_str + "." + server.game_info())

    while server.total_games < loop :
        output_info()
        time.sleep(1)
    output_info()

    server.game_stop()

    # 対局棋譜の出力
    # for kifu in server.game_kifus:
    #     print("game sfen = {0} , flip_turn = {1} , game_result = {2}".format(kifu.sfen , kifu.flip_turn , str(kifu.game_result)))

    server.terminate()