はじめに
同一局面検索をするにあたっては盤面を回転させた局面も一緒に検索できたら良いと思います。前回の記事のアップデートです。回転させた局面のSFENデータを取得できるようなPythonスクリプトを書きました。
SFENデータに関してはこちらを見てください。
本題
盤面を回転させる
回転前
ln5nl/6g1k/3ps2p1/2p1p1+Bgp/p2P1PP2/2r5P/P3PSKP1/LP4S2/1+r3G2L
回転後
l2g3+R1/2s4pl/1pksp3p/p5R2/2pp1p2P/PG+b1P1P2/1P2SP3/K1G6/LN5NL
ただ大文字と小文字をいれかえて逆から読んだだけのように見えますが実はそうではありません。
成り駒をあらわす「+」に注意が必要です。
そのために一つの関数を定義しました。
def make_list(str): skip = False result = [] for i in range(len(str)): if skip == True: skip = False continue if str[i] == '+': skip = True result.append(str[i:i+2]) else: result.append(str[i]) return result
これで「+」問題は解決します。
最終スクリプトがこのようになります。
def make_list(str): skip = False result = [] for i in range(len(str)): if skip == True: skip = False continue if str[i] == '+': skip = True result.append(str[i:i+2]) else: result.append(str[i]) return result banmen = 'ln5nl/6g1k/3ps2p1/2p1p1+Bgp/p2P1PP2/2r5P/P3PSKP1/LP4S2/1+r3G2L' banmen_row_list = [make_list(x) for x in banmen.swapcase().split('/')] r_banmen_row_list = [x[::-1] for x in banmen_row_list[::-1]] r_banmen = '/'.join([''.join(x) for x in r_banmen_row_list]) print(r_banmen)
持ち駒を書きかえる
回転前
GSNPbn3p
回転後
BN3Pgsnp
ただ大文字と小文字をいれかえただけのように見えますが実はそうではありません。
PCソフトに読み込ませるだけであればそれで良いのですが今回はテキスト検索を念頭にいれています。
先手→後手の順で記述する必要があります。
そのために二つの関数を定義しました。
import collections koma_kigo = ['r', 'b', 'g', 's', 'n', 'l', 'p'] koma_kigo2 = [x.swapcase() for x in koma_kigo] + koma_kigo def mochigoma_list_to_str(mochigoma_list): if len(mochigoma_list) == 0: return '-' else: mochigoma_dict = collections.Counter(mochigoma_list) mochigoma_str = '' for x in koma_kigo2: if mochigoma_dict[x] == 1: mochigoma_str += x elif mochigoma_dict[x] > 1: mochigoma_str += (str(mochigoma_dict[x]) + x) return mochigoma_str def mochigoma_str_to_list(mochigoma_str): if mochigoma_str == '-': return [] else: mochigoma_list = [] for i in range(len(mochigoma_str)): if mochigoma_str[i].isdigit(): for n in range(int(mochigoma_str[i])-1): mochigoma_list.append(mochigoma_str[i+1]) else: mochigoma_list.append(mochigoma_str[i]) return mochigoma_list
最終スクリプトがこのようになります。
import collections koma_kigo = ['r', 'b', 'g', 's', 'n', 'l', 'p'] koma_kigo2 = [x.swapcase() for x in koma_kigo] + koma_kigo def mochigoma_list_to_str(mochigoma_list): if len(mochigoma_list) == 0: return '-' else: mochigoma_dict = collections.Counter(mochigoma_list) mochigoma_str = '' for x in koma_kigo2: if mochigoma_dict[x] == 1: mochigoma_str += x elif mochigoma_dict[x] > 1: mochigoma_str += (str(mochigoma_dict[x]) + x) return mochigoma_str def mochigoma_str_to_list(mochigoma_str): if mochigoma_str == '-': return [] else: mochigoma_list = [] for i in range(len(mochigoma_str)): if mochigoma_str[i].isdigit(): for n in range(int(mochigoma_str[i])-1): mochigoma_list.append(mochigoma_str[i+1]) else: mochigoma_list.append(mochigoma_str[i]) return mochigoma_list mochigoma = 'GSNPbn3p' r_mochigoma = mochigoma_list_to_str(mochigoma_str_to_list(mochigoma.swapcase())) print(r_mochigoma)
指し手を書きかえる
回転前
52馬(34)
回転後
58馬(76)
こちらはPythonを使えば1行で書けます。
sashite = '52馬(34)' sashite = ''.join([str(10-int(x)) if x.isdigit() else x for x in sashite]) print(sashite)
最終的な同一局面検索のPythonスクリプト
import sys import re import glob import os import collections def make_list(str): skip = False result = [] for i in range(len(str)): if skip == True: skip = False continue if str[i] == '+': skip = True result.append(str[i:i+2]) else: result.append(str[i]) return result def mochigoma_list_to_str(mochigoma_list): if len(mochigoma_list) == 0: return '-' else: mochigoma_dict = collections.Counter(mochigoma_list) mochigoma_str = '' for x in koma_kigo2: if mochigoma_dict[x] == 1: mochigoma_str += x elif mochigoma_dict[x] > 1: mochigoma_str += (str(mochigoma_dict[x]) + x) return mochigoma_str def mochigoma_str_to_list(mochigoma_str): if mochigoma_str == '-': return [] else: mochigoma_list = [] for i in range(len(mochigoma_str)): if mochigoma_str[i].isdigit(): for n in range(int(mochigoma_str[i])-1): mochigoma_list.append(mochigoma_str[i+1]) else: mochigoma_list.append(mochigoma_str[i]) return mochigoma_list koma_kigo = ['r', 'b', 'g', 's', 'n', 'l', 'p'] koma_kigo2 = [x.swapcase() for x in koma_kigo] + koma_kigo sfen_files = glob.glob('sfen/*.sfen') while True: input_text = input('sfenを入力して下さい、終了時はq\n') if input_text == 'q': break else: input_text = input_text.replace('sfen ', '') print('\n') text_list = input_text.split(' ') if len(text_list) != 4: print('データが不適です') continue banmen, teban, mochigoma, tesu = text_list banmen_row_list = [make_list(x) for x in banmen.swapcase().split('/')] r_banmen_row_list = [x[::-1] for x in banmen_row_list[::-1]] r_banmen = '/'.join([''.join(x) for x in r_banmen_row_list]) r_mochigoma = mochigoma_list_to_str(mochigoma_str_to_list(mochigoma.swapcase())) normal_pattern = r'^' + re.escape(banmen) + r'\s([w|b])\s' + re.escape(mochigoma) + r'\s' + r'(\d+)$' rotate_pattern = r'^' + re.escape(r_banmen) + r'\s([w|b])\s' + re.escape(r_mochigoma) + r'\s' + r'(\d+)$' for each_file in sfen_files: with open(each_file, 'r') as f: my_data = f.read() normal_result = re.finditer(normal_pattern, my_data, flags = re.MULTILINE) rotate_result = re.finditer(rotate_pattern, my_data, flags = re.MULTILINE) normal_result_list = list(normal_result) rotate_result_list = list(rotate_result) if (len(normal_result_list) + len(rotate_result_list)) != 0: print(os.path.basename(each_file)) sente = re.search(r'^先手:.*$', my_data, flags = re.MULTILINE).group() gote = re.search(r'^後手:.*$', my_data, flags = re.MULTILINE).group() if len(normal_result_list) != 0: print('通常検索') for mm in normal_result_list: teban = mm.groups()[0] teban_text = sente if teban == 'b' else gote sashite_pattern = r'^' + re.escape(mm.groups()[1]) + r'\s(\S+)$' sashite_search = re.search(sashite_pattern, my_data, flags = re.MULTILINE) sashite = sashite_search.groups()[0] print('%s手目 %s が %s を指しました\n'%(mm.groups()[1], teban_text, sashite)) if len(rotate_result_list) != 0: print('反転検索') for mm in rotate_result_list: teban = mm.groups()[0] teban_text = sente if teban == 'b' else gote sashite_pattern = r'^' + re.escape(mm.groups()[1]) + r'\s(\S+)$' sashite_search = re.search(sashite_pattern, my_data, flags = re.MULTILINE) sashite = sashite_search.groups()[0] sashite = ''.join([str(10-int(x)) if x.isdigit() else x for x in sashite]) print('%s手目 %s が %s を指しました\n'%(mm.groups()[1], teban_text, sashite)) sys.exit()