youtu.be
上記の動画で作成したソースコードです。正規表現を使います。
(この記事の後半に、処理速度を速くした版もあります)
main.py
import cshogi
import random
import re
def koma_count(board):
"""
局面の先手、後手の各駒の数を数えてdictで返す。(王を除く)
Args:
board (cshogi.Board): cshogiでの局面
Returns:
koma_cnt (dict): 各駒とその数
例:
{'先手の歩': 7, '先手の香': 2, '先手の桂': 1, '先手の銀': 3,
'先手の角': 0, '先手の飛': 1, '先手の金': 1, '先手のと': 1,
'先手の杏': 0, '先手の圭': 0, '先手の全': 0, '先手の馬': 0,
'先手の竜': 0, '先手持ち駒の歩': 0, '先手持ち駒の香': 0,
'先手持ち駒の桂': 0, '先手持ち駒の銀': 0, '先手持ち駒の角': 0,
'先手持ち駒の飛': 1, '先手持ち駒の金': 1, '後手の歩': 5,
'後手の香': 2, '後手の桂': 2, '後手の銀': 0, '後手の角': 2,
'後手の飛': 0, '後手の金': 1, '後手のと': 0, '後手の杏': 0,
'後手の圭': 0, '後手の全': 0, '後手の馬': 0, '後手の竜': 0,
'後手持ち駒の歩': 5, '後手持ち駒の香': 0, '後手持ち駒の桂': 1,
'後手持ち駒の銀': 1, '後手持ち駒の角': 0, '後手持ち駒の飛': 0,
'後手持ち駒の金': 1}
"""
board_str = str(board)
koma_cnt = {"先手の歩": 0}
koma_cnt["先手の歩"] = board_str.count("+FU")
koma_cnt["先手の香"] = board_str.count("+KY")
koma_cnt["先手の桂"] = board_str.count("+KE")
koma_cnt["先手の銀"] = board_str.count("+GI")
koma_cnt["先手の角"] = board_str.count("+KA")
koma_cnt["先手の飛"] = board_str.count("+HI")
koma_cnt["先手の金"] = board_str.count("+KI")
koma_cnt["先手のと"] = board_str.count("+TO")
koma_cnt["先手の杏"] = board_str.count("+NY")
koma_cnt["先手の圭"] = board_str.count("+NK")
koma_cnt["先手の全"] = board_str.count("+NG")
koma_cnt["先手の馬"] = board_str.count("+UM")
koma_cnt["先手の竜"] = board_str.count("+RY")
line_str = str(re.search(r"P\+00FU.*\n", board_str))
koma_cnt["先手持ち駒の歩"] = line_str.count("FU")
line_str = str(re.search(r"P\+00KY.*\n", board_str))
koma_cnt["先手持ち駒の香"] = line_str.count("KY")
line_str = str(re.search(r"P\+00KE.*\n", board_str))
koma_cnt["先手持ち駒の桂"] = line_str.count("KE")
line_str = str(re.search(r"P\+00GI.*\n", board_str))
koma_cnt["先手持ち駒の銀"] = line_str.count("GI")
line_str = str(re.search(r"P\+00KA.*\n", board_str))
koma_cnt["先手持ち駒の角"] = line_str.count("KA")
line_str = str(re.search(r"P\+00HI.*\n", board_str))
koma_cnt["先手持ち駒の飛"] = line_str.count("HI")
line_str = str(re.search(r"P\+00KI.*\n", board_str))
koma_cnt["先手持ち駒の金"] = line_str.count("KI")
koma_cnt["後手の歩"] = board_str.count("-FU")
koma_cnt["後手の香"] = board_str.count("-KY")
koma_cnt["後手の桂"] = board_str.count("-KE")
koma_cnt["後手の銀"] = board_str.count("-GI")
koma_cnt["後手の角"] = board_str.count("-KA")
koma_cnt["後手の飛"] = board_str.count("-HI")
koma_cnt["後手の金"] = board_str.count("-KI")
koma_cnt["後手のと"] = board_str.count("-TO")
koma_cnt["後手の杏"] = board_str.count("-NY")
koma_cnt["後手の圭"] = board_str.count("-NK")
koma_cnt["後手の全"] = board_str.count("-NG")
koma_cnt["後手の馬"] = board_str.count("-UM")
koma_cnt["後手の竜"] = board_str.count("-RY")
line_str = str(re.search(r"P-00FU.*\n", board_str))
koma_cnt["後手持ち駒の歩"] = line_str.count("FU")
line_str = str(re.search(r"P-00KY.*\n", board_str))
koma_cnt["後手持ち駒の香"] = line_str.count("KY")
line_str = str(re.search(r"P-00KE.*\n", board_str))
koma_cnt["後手持ち駒の桂"] = line_str.count("KE")
line_str = str(re.search(r"P-00GI.*\n", board_str))
koma_cnt["後手持ち駒の銀"] = line_str.count("GI")
line_str = str(re.search(r"P-00KA.*\n", board_str))
koma_cnt["後手持ち駒の角"] = line_str.count("KA")
line_str = str(re.search(r"P-00HI.*\n", board_str))
koma_cnt["後手持ち駒の飛"] = line_str.count("HI")
line_str = str(re.search(r"P-00KI.*\n", board_str))
koma_cnt["後手持ち駒の金"] = line_str.count("KI")
return koma_cnt
def komadoku_evaluate(koma_cnt):
"""
その局面の駒得による評価値を計算する。
Args:
koma_cnt(dict): 各駒とその数
Returns:
phase_value (int): その局面の駒得による評価値
"""
koma_value = {"先手の歩": 75,
"先手の香": 175,
"先手の桂": 275,
"先手の銀": 475,
"先手の角": 775,
"先手の飛": 875,
"先手の金": 575,
"先手のと": 575,
"先手の杏": 575,
"先手の圭": 575,
"先手の全": 575,
"先手の馬": 1175,
"先手の竜": 1275,
"先手持ち駒の歩": 125,
"先手持ち駒の香": 225,
"先手持ち駒の桂": 325,
"先手持ち駒の銀": 525,
"先手持ち駒の角": 825,
"先手持ち駒の飛": 925,
"先手持ち駒の金": 625,
"後手の歩": -75,
"後手の香": -175,
"後手の桂": -275,
"後手の銀": -475,
"後手の角": -775,
"後手の飛": -875,
"後手の金": -575,
"後手のと": -575,
"後手の杏": -575,
"後手の圭": -575,
"後手の全": -575,
"後手の馬": -1175,
"後手の竜": -1275,
"後手持ち駒の歩": -125,
"後手持ち駒の香": -225,
"後手持ち駒の桂": -325,
"後手持ち駒の銀": -525,
"後手持ち駒の角": -825,
"後手持ち駒の飛": -925,
"後手持ち駒の金": -625}
phase_value = 0
for key in koma_cnt.keys():
phase_value += koma_value[key] * koma_cnt[key]
return phase_value
def order_list(move_lst):
"""
cshogiから返ってきた合法手のリストをオーダリングする。
今のところ、とりあえずランダム。
これで、アルファベータカットしても
事前にシャッフルしているので、ランダムで指す。
Args:
move_lst(int list): 合法手のリスト
Returns:
int list: オーダリング(並べ替えた)した合法手のリスト
"""
random.shuffle(move_lst)
return move_lst
while True:
input_cmd = input()
if input_cmd == "usi":
print("id name 16-168ui", flush=True)
print("id author R.Sueyoshi", flush=True)
print("usiok", flush=True)
if input_cmd == "isready":
print("readyok", flush=True)
if input_cmd == "usinewgame":
pass
if input_cmd[0:8] == "position" or input_cmd[0:1] == "a" or input_cmd[0:1] == "w":
cmd_lst = list(input_cmd.split(" "))
if len(cmd_lst) == 2 or len(cmd_lst) % 2 == 1:
my_turn = "先手"
else:
my_turn = "後手"
if cmd_lst[0] == "a":
board = cshogi.Board()
elif cmd_lst[0] == "w":
b_phase = "l6nl/5+P1gk/2np1S3/p1p4Pp/3P2Sp1/1PPb2P1P/P5GS1/R8/LN4bKL w GR5pnsg 1"
b_cmd_lst = list(b_phase.split(" "))
board = cshogi.Board(b_phase)
if b_cmd_lst[1] == "b":
my_turn = "先手"
else:
my_turn = "後手"
elif cmd_lst[1] == "startpos":
board = cshogi.Board()
if len(cmd_lst) > 2:
for i in range(3, len(cmd_lst)):
board.push_usi(cmd_lst[i])
elif cmd_lst[1] == "sfen":
sfen_str = (cmd_lst[2] + " " + cmd_lst[3] +
" " + cmd_lst[4] + " " + cmd_lst[5])
if sfen_str[1] == "b":
my_turn = "先手"
else:
my_turn = "後手"
board = cshogi.Board(sfen_str)
if len(cmd_lst) > 6:
for i in range(7, len(cmd_lst)):
board.push_usi(cmd_lst[i])
else:
break
if input_cmd[0:2] == "go":
move_lst = list(board.legal_moves)
move_lst = order_list(move_lst)
if len(move_lst) == 0:
print("bestmove resign", flush=True)
else:
koma_cnt_dict = koma_count(board)
evaluation_value = komadoku_evaluate(koma_cnt_dict)
if my_turn == "後手":
evaluation_value = -evaluation_value
print(
f"info pv {cshogi.move_to_usi(move_lst[0])} score cp {evaluation_value}", flush=True)
print("bestmove", cshogi.move_to_usi(move_lst[0]), flush=True)
move = board.push(move_lst[0])
if input_cmd[:8] == "gameover":
break
if input_cmd == "quit":
break
quit()
cshogiにある駒の数を取り出す機能版
以下は、上記のソースコードに対して、48さんからの助言で
正規表現ではなくcshogiにある駒の数を取り出す機能を
使ったものに変えたものです。
★koma_count関数のところだけ変更しました。
たぶん、こっちの方が処理速度が速いと思うので
今後はこちらを使う予定です。
main.py
import cshogi
import random
def koma_count(board):
"""
局面の先手、後手の各駒の数を数えてdictで返す。(王を除く)
Args:
board (cshogi.Board): cshogiでの局面
Returns:
koma_cnt (dict): 各駒とその数
例:
{'先手の歩': 7, '先手の香': 2, '先手の桂': 1, '先手の銀': 3,
'先手の角': 0, '先手の飛': 1, '先手の金': 1, '先手のと': 1,
'先手の杏': 0, '先手の圭': 0, '先手の全': 0, '先手の馬': 0,
'先手の竜': 0, '先手持ち駒の歩': 0, '先手持ち駒の香': 0,
'先手持ち駒の桂': 0, '先手持ち駒の銀': 0, '先手持ち駒の角': 0,
'先手持ち駒の飛': 1, '先手持ち駒の金': 1, '後手の歩': 5,
'後手の香': 2, '後手の桂': 2, '後手の銀': 0, '後手の角': 2,
'後手の飛': 0, '後手の金': 1, '後手のと': 0, '後手の杏': 0,
'後手の圭': 0, '後手の全': 0, '後手の馬': 0, '後手の竜': 0,
'後手持ち駒の歩': 5, '後手持ち駒の香': 0, '後手持ち駒の桂': 1,
'後手持ち駒の銀': 1, '後手持ち駒の角': 0, '後手持ち駒の飛': 0,
'後手持ち駒の金': 1}
"""
koma_cnt = {"先手の歩": 0}
koma_cnt["先手の歩"] = board.pieces.count(1)
koma_cnt["先手の香"] = board.pieces.count(2)
koma_cnt["先手の桂"] = board.pieces.count(3)
koma_cnt["先手の銀"] = board.pieces.count(4)
koma_cnt["先手の角"] = board.pieces.count(5)
koma_cnt["先手の飛"] = board.pieces.count(6)
koma_cnt["先手の金"] = board.pieces.count(7)
koma_cnt["先手のと"] = board.pieces.count(9)
koma_cnt["先手の杏"] = board.pieces.count(10)
koma_cnt["先手の圭"] = board.pieces.count(11)
koma_cnt["先手の全"] = board.pieces.count(12)
koma_cnt["先手の馬"] = board.pieces.count(13)
koma_cnt["先手の竜"] = board.pieces.count(14)
koma_cnt["先手持ち駒の歩"] = board.pieces_in_hand[0][0]
koma_cnt["先手持ち駒の香"] = board.pieces_in_hand[0][1]
koma_cnt["先手持ち駒の桂"] = board.pieces_in_hand[0][2]
koma_cnt["先手持ち駒の銀"] = board.pieces_in_hand[0][3]
koma_cnt["先手持ち駒の角"] = board.pieces_in_hand[0][5]
koma_cnt["先手持ち駒の飛"] = board.pieces_in_hand[0][6]
koma_cnt["先手持ち駒の金"] = board.pieces_in_hand[0][4]
koma_cnt["後手の歩"] = board.pieces.count(17)
koma_cnt["後手の香"] = board.pieces.count(18)
koma_cnt["後手の桂"] = board.pieces.count(19)
koma_cnt["後手の銀"] = board.pieces.count(20)
koma_cnt["後手の角"] = board.pieces.count(21)
koma_cnt["後手の飛"] = board.pieces.count(22)
koma_cnt["後手の金"] = board.pieces.count(23)
koma_cnt["後手のと"] = board.pieces.count(25)
koma_cnt["後手の杏"] = board.pieces.count(26)
koma_cnt["後手の圭"] = board.pieces.count(27)
koma_cnt["後手の全"] = board.pieces.count(28)
koma_cnt["後手の馬"] = board.pieces.count(29)
koma_cnt["後手の竜"] = board.pieces.count(30)
koma_cnt["後手持ち駒の歩"] = board.pieces_in_hand[1][0]
koma_cnt["後手持ち駒の香"] = board.pieces_in_hand[1][1]
koma_cnt["後手持ち駒の桂"] = board.pieces_in_hand[1][2]
koma_cnt["後手持ち駒の銀"] = board.pieces_in_hand[1][3]
koma_cnt["後手持ち駒の角"] = board.pieces_in_hand[1][5]
koma_cnt["後手持ち駒の飛"] = board.pieces_in_hand[1][6]
koma_cnt["後手持ち駒の金"] = board.pieces_in_hand[1][4]
return koma_cnt
def komadoku_evaluate(koma_cnt):
"""
その局面の駒得による評価値を計算する。
Args:
koma_cnt(dict): 各駒とその数
Returns:
phase_value (int): その局面の駒得による評価値
"""
koma_value = {"先手の歩": 75,
"先手の香": 175,
"先手の桂": 275,
"先手の銀": 475,
"先手の角": 775,
"先手の飛": 875,
"先手の金": 575,
"先手のと": 575,
"先手の杏": 575,
"先手の圭": 575,
"先手の全": 575,
"先手の馬": 1175,
"先手の竜": 1275,
"先手持ち駒の歩": 125,
"先手持ち駒の香": 225,
"先手持ち駒の桂": 325,
"先手持ち駒の銀": 525,
"先手持ち駒の角": 825,
"先手持ち駒の飛": 925,
"先手持ち駒の金": 625,
"後手の歩": -75,
"後手の香": -175,
"後手の桂": -275,
"後手の銀": -475,
"後手の角": -775,
"後手の飛": -875,
"後手の金": -575,
"後手のと": -575,
"後手の杏": -575,
"後手の圭": -575,
"後手の全": -575,
"後手の馬": -1175,
"後手の竜": -1275,
"後手持ち駒の歩": -125,
"後手持ち駒の香": -225,
"後手持ち駒の桂": -325,
"後手持ち駒の銀": -525,
"後手持ち駒の角": -825,
"後手持ち駒の飛": -925,
"後手持ち駒の金": -625}
phase_value = 0
for key in koma_cnt.keys():
phase_value += koma_value[key] * koma_cnt[key]
return phase_value
def order_list(move_lst):
"""
cshogiから返ってきた合法手のリストをオーダリングする。
今のところ、とりあえずランダム。
これで、アルファベータカットしても
事前にシャッフルしているので、ランダムで指す。
Args:
move_lst(int list): 合法手のリスト
Returns:
int list: オーダリング(並べ替えた)した合法手のリスト
"""
random.shuffle(move_lst)
return move_lst
while True:
input_cmd = input()
if input_cmd == "usi":
print("id name 16-168ui", flush=True)
print("id author R.Sueyoshi", flush=True)
print("usiok", flush=True)
if input_cmd == "isready":
print("readyok", flush=True)
if input_cmd == "usinewgame":
pass
if input_cmd[0:8] == "position" or input_cmd[0:1] == "a" or input_cmd[0:1] == "w":
cmd_lst = list(input_cmd.split(" "))
if len(cmd_lst) == 2 or len(cmd_lst) % 2 == 1:
my_turn = "先手"
else:
my_turn = "後手"
if cmd_lst[0] == "a":
board = cshogi.Board()
elif cmd_lst[0] == "w":
b_phase = "l6nl/5+P1gk/2np1S3/p1p4Pp/3P2Sp1/1PPb2P1P/P5GS1/R8/LN4bKL w GR5pnsg 1"
b_cmd_lst = list(b_phase.split(" "))
board = cshogi.Board(b_phase)
if b_cmd_lst[1] == "b":
my_turn = "先手"
else:
my_turn = "後手"
elif cmd_lst[1] == "startpos":
board = cshogi.Board()
if len(cmd_lst) > 2:
for i in range(3, len(cmd_lst)):
board.push_usi(cmd_lst[i])
elif cmd_lst[1] == "sfen":
sfen_str = (cmd_lst[2] + " " + cmd_lst[3] +
" " + cmd_lst[4] + " " + cmd_lst[5])
if sfen_str[1] == "b":
my_turn = "先手"
else:
my_turn = "後手"
board = cshogi.Board(sfen_str)
if len(cmd_lst) > 6:
for i in range(7, len(cmd_lst)):
board.push_usi(cmd_lst[i])
else:
break
if input_cmd[0:2] == "go":
move_lst = list(board.legal_moves)
move_lst = order_list(move_lst)
if len(move_lst) == 0:
print("bestmove resign", flush=True)
else:
koma_cnt_dict = koma_count(board)
evaluation_value = komadoku_evaluate(koma_cnt_dict)
if my_turn == "後手":
evaluation_value = -evaluation_value
print(
f"info pv {cshogi.move_to_usi(move_lst[0])} score cp {evaluation_value}", flush=True)
print("bestmove", cshogi.move_to_usi(move_lst[0]), flush=True)
move = board.push(move_lst[0])
if input_cmd[:8] == "gameover":
break
if input_cmd == "quit":
break
quit()