C++用将棋ライブラリ
"OpenShogiLib"の紹介
H.Hiro (Sapporo.cpp)
http://hhiro.net/about/
Twitter: @h_hiro_
2013.7.13 CLR/H & Sapporo.cpp 勉強会
自己紹介
H.Hiro
• 大学院生
• 現在は就活と研究が
同時並行なので忙しめです
• こんなアイコン
使ってます→
H.Hiro
• Sapporo.cpp
• Ruby札幌
• 数学勉強会@札幌
:
いろいろやってます
部分文字列の取得を
効率よく!楽に!
~fundoshi.hppの紹介と
今後の予定~
Photo by KAIZUKA
Creative Commons BY-NC-SA 2.0
http://www.flickr.com/photos/kaizuka/386511394/
http://www.slideshare.net/maraigue/
20121117-clrhc-fundoshihpp
【前回の発表(2012.11.17)】
宣伝
http://www.ospn.jp/osc2013-do/
• 今年は9月なのでお間違いなく!
• 場所もコンベンションセンターなので
お間違いなく!
• ブース・セミナー申込締切は
7月22日(月)です
よろしく
お願いします
本題
C++用将棋ライブラリ
"OpenShogiLib"の紹介
H.Hiro (Sapporo.cpp)
http://hhiro.net/about/
Twitter: @h_hiro_
ということで
これから将棋の話を
するわけですが
第2回電王戦
(プロ棋士とコンピュータの五番勝負)
http://ex.nicovideo.jp/denousen2013/
コンピュータ側の第5局を
戦った「GPS将棋」
http://gps.tanaka.ecc.u-tokyo.ac.jp/gpsshogi/
このうち、汎用的な
部分を切り出したのが
OpenShogiLibです
さて
コンピュータに
将棋を扱わせるには
何が必要か
[質問]
将棋をよく/たまに
やるよ!という方
[質問]
将棋はあまり
しないけど
何となくどんな
ゲームかは分かる方
今日必要な前提知識(1/3)
将棋は、二人が順番に
駒を動かすゲームです
駒の動かし方
の表を別途
配布して
おります
今日必要な前提知識(1/3)
将棋は、二人が順番に
駒を動かすゲームです
取った駒は
盤上に打つ
ことができます
今日必要な前提知識(2/3)
駒にはそれぞれ動きが
決められています
今日必要な前提知識(3/3)
勝利条件は、相手の玉(王)
を取ることです
右図のように、実際に
玉を取らなくても、次に
取れることが確定すれば
勝ち(詰み)。
コンピュータ上で
将棋を扱うのに
必要そうなデータ構造
•将棋盤(81マス)
•将棋駒(40個)
•駒が動ける場所
•将棋盤(81マス)
→9×9の2次元配列?
•将棋駒(40個)
→40個の配列?
•駒が動ける場所
→8種をハードコーディング
→ルール上動けない場所
OpenShogiLibが
これらを全部
提供してくれます
導入方法
&
簡単な利用方法
導入方法
• # apt-get install libosl-dev
•ソースコードから導入の
場合、boostが必要
•Windowsでは試してません
もしかしたら面倒かも
// http://blog.livedoor.jp/maraigue/archives/1711816.html
// SimpleStateは盤面のみを保持するクラス
state::SimpleState sstate(osl::HIRATE);
// NumEffectStateは盤面+駒の動きを扱えるクラス
state::NumEffectState nstate(sstate);
Move move;
// 先手(BLACK)の(7,7)にあるPAWN(歩兵)を、
// (7,6)という何もないマス(PTYPE_EMPTY)に動かす
move = Move(Square(7,7), Square(7,6), PAWN,
PTYPE_EMPTY, false, BLACK);
if(nstate.isValidMove(move)){
nstate.makeMove(move);
}
// http://blog.livedoor.jp/maraigue/archives/1711816.html
// SimpleStateは盤面のみを保持するクラス
state::SimpleState sstate(osl::HIRATE);
// NumEffectStateは盤面+駒の動きを扱えるクラス
state::NumEffectState nstate(sstate);
Move move;
// 先手(BLACK)の(7,7)にあるPAWN(歩兵)を、
// (7,6)という何もないマス(PTYPE_EMPTY)に動かす
move = Move(Square(7,7), Square(7,6), PAWN,
PTYPE_EMPTY, false, BLACK);
if(nstate.isValidMove(move)){
nstate.makeMove(move);
}
// http://blog.livedoor.jp/maraigue/archives/1711816.html
// SimpleStateは盤面のみを保持するクラス
state::SimpleState sstate(osl::HIRATE);
// NumEffectStateは盤面+駒の動きを扱えるクラス
state::NumEffectState nstate(sstate);
Move move;
// 先手(BLACK)の(7,7)にあるPAWN(歩兵)を、
// (7,6)という何もないマス(PTYPE_EMPTY)に動かす
move = Move(Square(7,7), Square(7,6), PAWN,
PTYPE_EMPTY, false, BLACK);
if(nstate.isValidMove(move)){
nstate.makeMove(move);
}
これで、とりあえず
将棋が指せる
ことはわかった
では、もう少し
凝ったことを
してみよう
詰将棋
こんなのが詰将棋です
こんなのが詰将棋です
詰将棋の目的:
王手のみを続けて
相手の玉を詰める
まずは人手で解いてみる
人手だと
何となく
「この手が正解っぽい」
と分かるけど
コンピュータには
どう解かせる?
詰将棋の目的:
王手のみを続けて
相手の玉を詰める
コンピュータには
王手になる手を
総当りで指させる
コンピュータには
王手になる手を
総当りで指させる
(自分の立場)
コンピュータには
王手を回避する手を
総当りで指させる
(相手の立場)
• 詰みとなる条件
相手がどう指そうとも
自分の手によっては
王手を回避できなくなる
• 詰まない条件
自分がどう指そうとも
相手の手によっては
王手をかけられなくなる
ここから王手になる手は?
実は4通りある
先に進めると
手の数はすごいことになる
コンピュータに
全部試させればよい
// [駒を動かして王手]
ActionTryMove acm(mt_new, nstate, depth, max_depth);
for(int i = 0; i < osl::Piece::SIZE; ++i){
p = nstate.pieceOf(i);
if(p.isOnBoardByOwner(osl::BLACK)){
// 盤上にある先手の駒の場合
nstate.forEachEffectOfPiece<ActionTryMove>(p, acm)
}
}
valid_moves += acm.valid_moves();
コンピュータに
全部試させればよい
// [駒を動かして王手]
ActionTryMove acm(mt_new, nstate, depth, max_depth);
for(int i = 0; i < osl::Piece::SIZE; ++i){
p = nstate.pieceOf(i);
if(p.isOnBoardByOwner(osl::BLACK)){
// 盤上にある先手の駒の場合
nstate.forEachEffectOfPiece<ActionTryMove>(p, acm)
}
}
valid_moves += acm.valid_moves();
将棋で用いる全部の駒
(40個)についてループ
コンピュータに
全部試させればよい
// [駒を動かして王手]
ActionTryMove acm(mt_new, nstate, depth, max_depth);
for(int i = 0; i < osl::Piece::SIZE; ++i){
p = nstate.pieceOf(i);
if(p.isOnBoardByOwner(osl::BLACK)){
// 盤上にある先手の駒の場合
nstate.forEachEffectOfPiece<ActionTryMove>(p, acm)
}
}
valid_moves += acm.valid_moves();
動かしてみる
コンピュータに
全部試させればよい
// class ActionTryMove の中身
template<osl::Player pl> void doAction
(const osl::Piece & pc, const osl::Square & sq){
/*(中略)*/
if(osl::isPiece(pc.ptype()) && osl::canPromote(pc.ptype())){
// 成れる駒ならば、成ってみる
if(recursive_search(/*(中略)*/) != -2){ ++valid_moves_; }
}
// 成らない場合
if(recursive_search(/*(中略)*/) != -2){ ++valid_moves_; }
}
コンピュータに
全部試させればよい
// class ActionTryMove の中身
template<osl::Player pl> void doAction
(const osl::Piece & pc, const osl::Square & sq){
/*(中略)*/
if(osl::isPiece(pc.ptype()) && osl::canPromote(pc.ptype())){
// 成れる駒ならば、成ってみる
if(recursive_search(/*(中略)*/) != -2){ ++valid_moves_; }
}
// 成らない場合
if(recursive_search(/*(中略)*/) != -2){ ++valid_moves_; }
}
成れるかどうか判定し
成らないケースとともに試す
コンピュータに
全部試させればよい
if(nstate.isValidMove(*p_move)){ // 動かせるか確認
nstate.makeMove(*p_move); // 動かす
// (先手が指した結果の場合)後手玉が王手になっている
// (後手が指した結果の場合)後手玉が王手になっていない
if(logical_xor(depth % 2 == 1, nstate.inCheck(osl::WHITE))){
mt_new = MoveTree::createNewPtr(*p_move);
mt->children.push_back(mt_new);
}else{
return -2;
}
}else{
return -2; // 動かせない場合
}
コンピュータに
全部試させればよい
if(nstate.isValidMove(*p_move)){ // 動かせるか確認
nstate.makeMove(*p_move); // 動かす
// (先手が指した結果の場合)後手玉が王手になっている
// (後手が指した結果の場合)後手玉が王手になっていない
if(logical_xor(depth % 2 == 1, nstate.inCheck(osl::WHITE))){
mt_new = MoveTree::createNewPtr(*p_move);
mt->children.push_back(mt_new);
}else{
return -2;
}
}else{
return -2; // 動かせない場合
}
まず、将棋のルールとして
動けるかをチェック
コンピュータに
全部試させればよい
if(nstate.isValidMove(*p_move)){ // 動かせるか確認
nstate.makeMove(*p_move); // 動かす
// (先手が指した結果の場合)後手玉が王手になっている
// (後手が指した結果の場合)後手玉が王手になっていない
if(logical_xor(depth % 2 == 1, nstate.inCheck(osl::WHITE))){
mt_new = MoveTree::createNewPtr(*p_move);
mt->children.push_back(mt_new);
}else{
return -2;
}
}else{
return -2; // 動かせない場合
}
続いて、王手をかける/
回避するという条件をチェック
実際に
動かしてみる
https://github.com/maraigue/
clrhsapporocpp-20130713
補足
•詰将棋を解くだけなら
OpenShogiLibに最初から
コードがある
•でも、それ以上のことを
したかったので
自前で書いた
詰将棋制作支援の
プログラムが欲しかった
•回答が一意に定まる必要
•余計な駒を使わない
:
•そういう機能を持つ
ソフトもあるのだが
有料なうえに絶版
•なので自分で作りたかった
おわりに
将棋は
自身で遊ぶだけでなくて
コンピュータ的にも
奥が深いです
OpenShogiLibは
ドキュメントがあまり整備
されてないので
Tipsをブログとかに書くと
喜ばれるかも?
ありがとう
ございました

C++用将棋ライブラリ "OpenShogiLib"の紹介