迷走メモ
2009年5月中旬 | df-pn探索を神と崇める |
(同) | df-pn探索で詰みが証明された局面をパーセプトロンでなんとか学習して蓄積する方向でゴニョゴニョしる |
2009年5月末 | 詰みの成立条件にシームレスに繋がるような局面評価手段の完全版を発見した気がした |
(同) | れさぴょん改造着手 |
(同) | 駒の管理方法が合わないから放棄 |
2009年6-7月 | 駒移動の最小距離を全ての駒についてif-thenロジックに落とす…直後にこれは無駄であると気づく。変位で引くテーブルにすれば解決orz (うまく履歴管理して水平探索すれば81 node内外の探索でも済む。) |
2009年8月 | プログラムの新規作成開始 |
(同) | 完全にシームレスと思った局面評価手段の欠陥に気づく -- やっぱ学習で微調必要じゃん? |
2009年9月 | 強化学習教に改宗した。df-pn探索なんて飾りです |
2009年10月 | いろいろ実験 |
2009年11月 | いろいろ実験 |
2009年12月 | いろいろ実験 |
2009年12月末 | プログラムの新規作成を再開した(今頃 |
まあ手の生成と評価手段の組み込みは何とか完成した感じ。喜びのあまり一部を貼る(shogi.h)。
#pragma once /// 駒タイプ(駒の種類)を表します。成/不成と所有者は別途bitを用意して区別します。 enum TKomaType { EM = 0, FU = 1, KY, KE, GI, KI, KA, HI, OU, TKomaTypeEnd_ }; /// 駒タイプの最小値です。 const int KomaTypeMin = FU; /// 駒タイプ空間のサイズです。駒タイプは[0, SzKomaTypeSpc) の範囲内に収まります。 const int SzKomaTypeSpc = TKomaTypeEnd_; /// SzKomaTypeSpc以上かつ最小の2の累乗です。 const int Iv2SzKomaTypeSpc = 16; /// 駒コード空間のサイズです。駒コードは[0, SzKomaCodeSpc) の範囲内に収まります。 const int SzKomaCodeSpc = (SzKomaTypeSpc << 2); /*= 駒コードのパッキング形式: * typ(4), pr(1), ab(1) * ここで * typ : 移動する駒の種類 * pr : 成りフラグ (0: 生駒, 1: 成駒) * ab : 所有者 (1: A, 0: B) */ /// SzKomaCodeSpc以上かつ最小の2の累乗です。 const int Iv2SzKomaCodeSpc = 64; /// 駒の種類毎の個数(上限)です。 const int NumEachKomaTypes[SzKomaTypeSpc] = { // EM FU KY KE GI KI KA HI OU 1, 18, 4, 4, 4, 4, 2, 2, 2 }; /// KomaID空間のサイズです。 const int SzKomaIDSpc = 1 + 18 + 4 *4 + 3 * 2; /// 方位フラグです。利きの生成に使います。 enum TDirFlgs { JumpN = (1 << 0), JumpS = (1 << 1), JumpE = (1 << 2), JumpW = (1 << 3), JumpNE = (1 << 4), JumpSW = (1 << 5), JumpSE = (1 << 6), JumpNW = (1 << 7), WalkN = (1 << (8 + 0)), WalkS = (1 << (8 + 1)), WalkE = (1 << (8 + 2)), WalkW = (1 << (8 + 3)), WalkNE = (1 << (8 + 4)), WalkSW = (1 << (8 + 5)), WalkSE = (1 << (8 + 6)), WalkNW = (1 << (8 + 7)), KeiNE = (1 << (8 + 8)), KeiSW = (1 << (8 + 9)), KeiSE = (1 << (8 + 10)), KeiNW = (1 << (8 + 11)), }; /// BoardPosAdr上の移動オフセットです。 enum TDirOfs { DirN = -1, DirS = 1, DirE = -32, DirW = 32, DirNE = -33, DirSW = 33, DirSE = -31, DirNW = 31, DirKeiNE = -34, // (A桂馬飛び右) DirKeiSW = 34, // (B桂馬飛び右) DirKeiSE = -30, // (B桂馬飛び左) DirKeiNW = 30, // (A桂馬飛び左) }; /*= 座標と移動に関する定義: * <<座標系>> * プレイヤーA(本プログラム)から見た盤の手前側を南、奥側を北とみなし、 * sujiとdanを下記を満たすように割り振る。 * 北東隅の(suji, dan) = (1, 1) * 南東隅の(suji, dan) = (1, 9) * 北西隅の(suji, dan) = (9, 1) * 南西隅の(suji, dan) = (9, 9) * Aが先手のときは、sujiとdanをそのまま本将棋における筋と段に読み替えることができる。 * Aが後手のときは、180°回転する変換が必要である。 * * <<置駒位置のアドレッシング>> * 置駒位置(suji, dan)を表すアドレスBoardPosAdrを次式で定義する。 * BoardPosAdr := (suji << 5) + dan * * <<持駒のアドレッシング>> * 持駒にも次式によりアドレスHandAdrを定義する。 * Aの持駒xのHandAdr := ((BoardPosAdrの上限) + 1) + (2 * (xの駒タイプ) + 1) * Bの持駒yのHandAdr := ((BoardPosAdrの上限) + 1) + (2 * (yの駒タイプ) + 0) * * <<拡張BoardPosAdr>> * 着手生成過程で上記BoardPosAdrにTDirOfsの任意のものを * 1回だけ加算した値(これは盤外を指し得る)をも扱う。 * これは拡張BoardPosAdrまたはExBoardPosAdrと呼び、通常のBoardPosAdrとは区別する。 */ /// BoardPosAdrを生成します。 inline int GenBoardPosAdr(int suji, int dan) { return (suji << 5) + dan; } /// BoardPosAdrをデコードします。 inline void DecodeBoardPosAdr(int pos, int& suji, int& dan) { suji = (pos >> 5); dan = (pos & 0x1f); } /// BoardPosAdrから段を取得します。 inline int GetDan(int pos) { return (pos & 0x1f); } /// 敵陣内か否か反転します。 inline bool IsOppCamp(bool ownedByA, int pos) { return (ownedByA) ? (GetDan(pos) <= 3) : (GetDan(pos) >= 7); } /// BoardPoaAdr空間のサイズです。 /// BoardPosAdrは[0, SzBoardPosAdrSpc) の範囲内に収まります。 const int SzBoardPosAdrSpc = ((9 << 5) + 9) + 1; /// HandAdr空間の基準位置です。 const int HandAdrBase = SzBoardPosAdrSpc; /// BoardPosAdr空間とHandPosAdr空間を包含する空間のサイズです。 /// BoardPosAdr、HandPosAdrいずれも[0, SzTotalSpc) の範囲内に収まります。 const int SzTotalSpc = SzBoardPosAdrSpc + 2 * SzKomaTypeSpc; /// 拡張BoardPosAdrの下限です。 const int ExBoardPosAdrMin = -1; /*= ExBoardPosAdrの下限は、A桂馬が(1,1)から右へ桂馬飛びしたとき現れる: * ExBoardPosAdrMin = ((1 << 5) + 1) + DirKeiNE(=-34) = -1 */ /// 拡張BoardPoaAdrの上限です。 const int ExBoardPosAdrMax = 331; /*= ExBoardPosAdrの上限は、B桂馬が(9,9)から右へ桂馬飛びしたとき現れる: * ExBoardPosAdrMax = ((9 << 5) + 9) + DirKeiSW(=34) = 331 */ /// 駒コードを生成します。 inline int GenKomaCode(TKomaType typ, bool pr, bool ownedByA) { return (typ << 2) | ((int)pr << 1) | ((int)ownedByA); } /// 駒コードをデコードします。 inline void DecodeKomaCode(int code, TKomaType& typ, bool& pr, bool& ownedByA) { typ = (TKomaType)(code >> 2); pr = ((code & 0x2) != 0); ownedByA = ((code & 0x1) != 0); } /// 成りを解除します。 inline int GenUnpromoted(int code) { return code & ~(1 << 1); } /// 持駒にします。 inline int GenCaptured(int code, bool ownedByA) { return (code & ~0x3) | (int)ownedByA; } /// 駒コードから駒タイプを取得します。 inline TKomaType GetKomaTypeFromCode(int code) { return (TKomaType)(code >> 2); } /// /// (検閲削除) /// /// 手を表します。 typedef u32 TMove; /*= パッキング形式: * cap(4), typ(4), pr(1), ab(1), sta(9), dst(9) (計28 bit) * ここで * cap : 移動により取る駒(FU〜OU) * typ : 移動する駒の種類 * pr : 成りフラグ (0: 不成, 1: 成) * ab : 所有者 (1: A, 0: B) * sta : 移動元位置 (= (suji << 5) + dan) * dst : 移動先位置 (= (suji << 5) + dan) * 移動する駒が持駒のときは、staにはHandAdrBase + 駒タイプが入る。 */ /// MoveSeedを生成します。 inline TMove GenMoveSeed(TKomaType typ, bool pr, bool ownedByA, int sta) { return ((TMove)GenKomaCode(typ, pr, ownedByA) << 18) | ((TMove)sta << 9); } /// MoveSeedを生成します。 inline TMove GenMoveSeed(int code, int sta) { return ((TMove)code << 18) | ((TMove)sta << 9); } /*= TODO: MoveSeedを与えてstaのみ更新する方法との速度優劣調査。 */ /// Moveを生成します。 inline TMove GenMove(TMove mvs, int dst, TKomaType cap) { return ((TMove)((TMove)cap << 24)) | mvs | ((TMove)dst); } /// 成駒のMoveまたはMoveSeedを生成します。 inline TMove GenPromoted(TMove mvs) { return (mvs | ((TMove)1 << 19)); } /// MoveまたはMoveSeedからA駒か否か判定します。 inline bool IsOwnedByA(TMove mvs) { return ((mvs & ((TMove)1 << 18)) != 0); } /// MoveまたはMoveSeedから成駒か否か判定します。 inline bool IsPromoted(TMove mvs) { return ((mvs & ((TMove)1 << 19)) != 0); } /// MoveまたはMoveSeedから駒コードを取得します。 inline int GetKomaCode(TMove move) { return ((move >> 18) & (TMove)0x3f); } /// MoveまたはMoveSeedから駒タイプを取得します。 inline TKomaType GetKomaType(TMove move) { return (TKomaType)((move >> 20) & (TMove)0xf); } /// Moveからstaフィールドの値を取得します。 inline int GetSta(TMove move) { return ((move >> 9) & (TMove)0x1ff); } /// Moveからdstフィールドの値を取得します。 inline int GetDst(TMove move) { return ((move >> 0) & (TMove)0x1ff); } /// Moveからcapフィールドの値を取得します。 inline TKomaType GetCap(TMove move) { return (TKomaType)((move >> 24) & 0xf); } /// MoveSeedで空白か否かを判定します。 inline bool IsMvsEmpty(TMove mvs) { return (mvs == 0); } /// MoveSeedで壁か否かを判定します。 inline bool IsMvsWall(TMove mvs) { return ((s32)mvs < 0); } /// 局面のハッシュを表します。 typedef u64 THash; /// 盤のマス目を表します。 struct BoardCell { TMove MoveSeed; // 存在する駒の種類 u32 CtrlBy[2]; // [1]: A駒からの利き, [0]: B駒からの利き int KomaID; // 駒ID }; /// 駒情報を表します。 struct TKomaInf { TMove MoveSeed; // 駒が存在するBoardCellのMoveSeedと同じもの /// /// (検閲削除) /// }; /// 盤を表します。 template<class T> struct Board { T Padding[-ExBoardPosAdrMin]; T Buf[ExBoardPosAdrMax + 1]; /*= 拡張BoardPosAdrの値域に含まれる任意のposについて、 * Buf[pos]は本構造体内部のアクセスとなる。 */ }; /// 置換表要素を表します。 struct TSubstElem { THash Hash; // 局面のハッシュ int Alpha; // α値(または証明数(pn)) int Beta; // β値(または反証数(dn)) u32 Info; // 要素情報 /*= Infoのパッキング形式: * uuse(1), etyp(1), ab(1), rdepth(16) * ここで * uuse : 使用中か否か(1: 使用中, 0: 未使用) * etyp : エントリの種類(true: df-pn探索, false: αβ探索) * ab : 登録時の手番(1: A, 0: B) * rdepth : 登録時の相対探索深度 */ /// 置換表を参照します。 bool Consult(bool dfpn, bool turnOfA, THash hash, int rdepth, int& alpha, int& beta) { // 内容のシグネチャ生成 int sig = 0x4; if (dfpn) sig |= 0x2; if (turnOfA) sig |= 0x1; // ヒット可能性判定 bool canHit = ((Info >> 16) & 0x7) == sig // 使用中かつ探索タイプと手番が一致 && (Hash == hash); // かつハッシュ一致 // 置換可能性判定 if (canHit) { int regrdp = (Info & 0xffff); if (rdepth <= regrdp) { // (置換可能) alpha = Alpha; beta = Beta; return true; } } return false; } /// 置換表を更新します。 void Update(bool dfpn, bool turnOfA, THash hash, int rdepth, int alpha, int beta) { // 内容のシグネチャ生成 int sig = 0x4; if (dfpn) sig |= 0x2; if (turnOfA) sig |= 0x1; // 上書き Hash = hash; Info = (sig << 16) | (rdepth & 0xffff); Alpha = alpha; Beta = beta; } }; /// ゲームの状態を表します。 class GameState { private: // 局面を特定する情報 Board<BoardCell> board; // 盤 TKomaInf ktab[SzKomaIDSpc]; // 駒一覧 int numKomas; // 実際の駒数 int bgnKomaID[SzKomaTypeSpc + 1]; // 駒の種類毎の開始位置(要素数の+1は番兵用) int OUID[2]; // 玉の駒ID([1]: A玉, [0]: B玉) /*= 駒の移動はBoardPosAdrの定義式を直接使わずに、 * 次式のように定数offsetの加算で行う。 * pos' = pos + offset * ここでoffsetの値は、プレイヤーA(先手)から見て上を北として次の通り。 * 北(DirN) : -1 * 南(DirS) : 1 * 東(DirE) : -32 * 西(DirW) : 32 * 北東(DirNE) : -33 * 南西(DirSW) : 33 * 南東(DirSE) : -31 * 北西(DirNW) : 31 * 南南東(DirKeiSE) : -30 (B桂馬飛び左) * 北北西(DirKeiNW) : 30 (A桂馬飛び左) * 北北東(DirKeiNE) : -34 (A桂馬飛び右) * 南南西(DirKeiSW) : 34 (B桂馬飛び右) * * 駒の移動先が盤からはみ出るときのワーストケースは次の通り: * A桂馬が(1,1)から右へ桂馬飛び→((1 << 5) + 1) + (-34) = -1 * B桂馬が(9,9)から右へ桂馬飛び→((9 << 5) + 9) + ( 34) = 331 */ // 棋譜 int numMoves; // 手数 THash gameRecord[1024]; // 履歴(ハッシュ値) // 管理用 THash hash; // 最新局面ハッシュ値 /*= 局面ハッシュ生成方法: * 駒情報から乱数への写像 * r1:{駒の位置}×{駒コード}→{u64} * を用意しておき、下記値全てのXORをハッシュ値とする。 * ∀p∈{置} : r1(pの位置, pの駒コード) * ただし、pの位置は次式で与える。 * a. 置駒pについて: (suji << 5) + dan * (うち1≦suji≦9, 1≦dan≦9の範囲のみ使う) * b. 持駒pについて: (HandAdrBase + 2 * (pの駒タイプ) + ab */ // 定数 /** ハッシュ計算用 */ u64 randTab[SzTotalSpc][Iv2SzKomaCodeSpc]; // 乱数表[位置][駒コード] /// /// (検閲削除) /// /*= ハッシュ生成時は置駒も持駒も区別せずにrandTab[][]を引く。 * (そのためにSzTotalSpcを導入した。) */ /// 盤を初期化します。 void InitBoard(); /// ハッシュ用乱数テーブルを初期化します。 void InitHashSeed(); void InitHashSeed_Core(); /// ハッシュ用乱数テーブルを検証します。 bool ValidateHashSeed(); /// ハッシュを生成します。 void GenHash(THash& hash); /// 最小手数計算処理を初期化します。 void InitMinDist(); /// Aの生駒による利きをセットします。 void SetCtrlARaw(TKomaType typ, int pos); /// Aの生駒による利きをクリアします。 void ClrCtrlARaw(TKomaType typ, int pos); /// Aの成駒による利きをセットします。 void SetCtrlAPro(TKomaType typ, int pos); /// Aの成駒による利きをクリアします。 void ClrCtrlAPro(TKomaType typ, int pos); /// Bの生駒による利きをセットします。 void SetCtrlBRaw(TKomaType typ, int pos); /// Bの生駒による利きをクリアします。 void ClrCtrlBRaw(TKomaType typ, int pos); /// Bの成駒による利きをセットします。 void SetCtrlBPro(TKomaType typ, int pos); /// Bの成駒による利きをクリアします。 void ClrCtrlBPro(TKomaType typ, int pos); /// 飛び駒の利きをカットします。 void CutOffJumpCtrl(int pos); /// 飛び駒の利きを復元します。 void RestoreJumpCtrl(int pos); /// 駒を動かします(指し/打ち兼用)。 /// 上のMove()と同等ですが引の形式が違います。 /// (Move生成部作成前に駒移動テストするためのデバッグ用です。) void Move(int kid, bool pr, int dst); /// 駒を動かします(指し/打ち兼用)。 /// 低水準ルーチンのため、移動先dstは盤の中である必要があります。 /// また、将棋のルール上許されない指し方(打ち方)をチェックしません。 void Move(TMove move); /// Aの可能な手を列挙します。 /// A玉をB駒の利きに曝す関連と千日手関連以外の反則手は除外します。 /// 本当にAの手番かどうかは関知しません。 int EnumMovesA(TMove buf[], int n); /// Bの可能な手を列挙します。 /// B玉をB駒の利きに曝す関連と千日手関連以外の反則手は除外します。 /// 本当にBの手番かどうかは関知しません。 int EnumMovesB(TMove buf[], int n); /// 手を適用します。 bool ApplyMove(TMove move); /// 手を撤回します。 void UnrollMove(TMove move); /// 局面を評価します。 int Evaluate(); public: GameState(); void SetHirate(); };
実行結果:
<<駒移動テスト>> 9 8 7 6 5 4 3 2 1 ---------------------------+ KY KE GI KI OU KI GI KE KY |一 + HI + + + + + KA + |二 FU FU FU FU FU + FU FU FU |三 + + + + + + + + + |四 + + + + + FU + + + |五 + + + + + + + + + |六 歩 歩 歩 歩 歩 歩 歩 歩 歩 |七 + 角 + + + + + 飛 + |八 香 桂 銀 金 玉 金 銀 桂 香 |九 ---------------------------+ hash(act)=0x4ce3df627d3be5db OK hash(exp)=0x4ce3df627d3be5db 9 8 7 6 5 4 3 2 1 ---------------------------------------------------------------------------------------------------------------------+ (--) (--) (--) (--) (--) (--) (--) (--) (--) |一 (--) (--) (--) (--) (--) (--) (--) (--) (--) |二 (--) (--) (--) (--) (--) (--) (--) (--) (--) |三 (--) (--) (--) (--) (--) (--) (--) (--) (--) |四 (--) (--) (--) (--) (--) (--) (--) (--) (--) |五 (n_) (n_) (n_) (n_) (n_) (n_) (n_) (n_) (n_) |六 (N_NWKnw) (--) (NEKne) (--) (--) (--) (Knw) (N_) (N_Kne) |七 (N_) (W_nw) (W_n_nw) (W_n_nenw) (W_n_nenw) (W_n_nenw) (W_n_ne) (ne) (N_E_) |八 (SW) (--) (SEw_) (w_) (e_w_) (e_) (e_) (S_) (--) |九 ---------------------------------------------------------------------------------------------------------------------+ 9 8 7 6 5 4 3 2 1 ---------------------------------------------------------------------------------------------------------------------+ (--) (N_) (w_) (w_) (w_e_) (e_) (NWe_) (--) (NE) |一 (S_W_) (sw) (E_s_sw) (E_s_swse) (E_s_swse) (E_s_swse) (E_s_se) (E_se) (S_) |二 (S_Ksw) (S_) (Kse) (--) (--) (--) (SWKsw) (--) (S_SEKse) |三 (s_) (s_) (s_) (s_) (s_) (--) (s_) (s_) (s_) |四 (--) (--) (--) (--) (--) (--) (--) (--) (--) |五 (--) (--) (--) (--) (--) (s_) (--) (--) (--) |六 (--) (--) (--) (--) (--) (--) (--) (--) (--) |七 (--) (--) (--) (--) (--) (--) (--) (--) (--) |八 (--) (--) (--) (--) (--) (--) (--) (--) (--) |九 ---------------------------------------------------------------------------------------------------------------------+ 9 8 7 6 5 4 3 2 1 ---------------------------+ KY KE GI KI OU KI GI KE KY |一 + HI + + + + + KA + |二 FU FU FU FU FU FU FU FU FU |三 + + + + + + + + + |四 + + + + + + + + + |五 + + + + + + + + + |六 歩 歩 歩 歩 歩 歩 歩 歩 歩 |七 + 角 + + + + + 飛 + |八 香 桂 銀 金 玉 金 銀 桂 香 |九 ---------------------------+ hash(act)=0xd82e92d0b66d248f OK hash(exp)=0xd82e92d0b66d248f 9 8 7 6 5 4 3 2 1 ---------------------------------------------------------------------------------------------------------------------+ (--) (--) (--) (--) (--) (--) (--) (--) (--) |一 (--) (--) (--) (--) (--) (--) (--) (--) (--) |二 (--) (--) (--) (--) (--) (--) (--) (--) (--) |三 (--) (--) (--) (--) (--) (--) (--) (--) (--) |四 (--) (--) (--) (--) (--) (--) (--) (--) (--) |五 (n_) (n_) (n_) (n_) (n_) (n_) (n_) (n_) (n_) |六 (N_NWKnw) (--) (NEKne) (--) (--) (--) (Knw) (N_) (N_Kne) |七 (N_) (W_nw) (W_n_nw) (W_n_nenw) (W_n_nenw) (W_n_nenw) (W_n_ne) (ne) (N_E_) |八 (SW) (--) (SEw_) (w_) (e_w_) (e_) (e_) (S_) (--) |九 ---------------------------------------------------------------------------------------------------------------------+ 9 8 7 6 5 4 3 2 1 ---------------------------------------------------------------------------------------------------------------------+ (--) (N_) (w_) (w_) (w_e_) (e_) (NWe_) (--) (NE) |一 (S_W_) (sw) (E_s_sw) (E_s_swse) (E_s_swse) (E_s_swse) (E_s_se) (E_se) (S_) |二 (S_Ksw) (S_) (Kse) (--) (--) (--) (SWKsw) (--) (S_SEKse) |三 (s_) (s_) (s_) (s_) (s_) (s_) (s_) (s_) (s_) |四 (--) (--) (--) (--) (--) (--) (--) (--) (--) |五 (--) (--) (--) (--) (--) (--) (--) (--) (--) |六 (--) (--) (--) (--) (--) (--) (--) (--) (--) |七 (--) (--) (--) (--) (--) (--) (--) (--) (--) |八 (--) (--) (--) (--) (--) (--) (--) (--) (--) |九 ---------------------------------------------------------------------------------------------------------------------+ <<駒取りテスト>> 9 8 7 6 5 4 3 2 1 ---------------------------+ KY KE GI KI OU KI GI KE KY |一 + HI + + + + + KA + |二 FU FU FU FU FU + FU FU FU |三 + + + + + + + + と |四 + + + + + + + + + |五 + + + + + to + + + |六 歩 歩 歩 歩 歩 歩 歩 歩 + |七 + 角 + + + + + 飛 + |八 香 桂 銀 金 玉 金 銀 桂 香 |九 ---------------------------+ hash(act)=0x2531491652e2d0e1 OK hash(exp)=0x2531491652e2d0e1 9 8 7 6 5 4 3 2 1 ---------------------------------------------------------------------------------------------------------------------+ (--) (--) (--) (--) (--) (--) (--) (--) (--) |一 (--) (--) (--) (--) (--) (--) (--) (--) (--) |二 (--) (--) (--) (--) (--) (--) (--) (nw) (n_) |三 (--) (--) (--) (--) (--) (--) (--) (w_) (N_) |四 (--) (--) (--) (--) (--) (--) (--) (--) (N_s_) |五 (n_) (n_) (n_) (n_) (n_) (n_) (n_) (n_) (N_) |六 (N_NWKnw) (--) (NEKne) (--) (--) (--) (Knw) (N_) (N_Kne) |七 (N_) (W_nw) (W_n_nw) (W_n_nenw) (W_n_nenw) (W_n_nenw) (W_n_ne) (ne) (N_E_) |八 (SW) (--) (SEw_) (w_) (e_w_) (e_) (e_) (S_) (--) |九 ---------------------------------------------------------------------------------------------------------------------+ 9 8 7 6 5 4 3 2 1 ---------------------------------------------------------------------------------------------------------------------+ (--) (N_) (w_) (w_) (w_e_) (e_) (NWe_) (--) (NE) |一 (S_W_) (sw) (E_s_sw) (E_s_swse) (E_s_swse) (E_s_swse) (E_s_se) (E_se) (S_) |二 (S_Ksw) (S_) (Kse) (--) (--) (--) (SWKsw) (--) (S_SEKse) |三 (s_) (s_) (s_) (s_) (s_) (--) (s_) (s_) (s_) |四 (--) (--) (--) (--) (--) (n_) (--) (--) (--) |五 (--) (--) (--) (--) (w_) (--) (e_) (--) (--) |六 (--) (--) (--) (--) (sw) (s_) (se) (--) (--) |七 (--) (--) (--) (--) (--) (--) (--) (--) (--) |八 (--) (--) (--) (--) (--) (--) (--) (--) (--) |九 ---------------------------------------------------------------------------------------------------------------------+ 9 8 7 6 5 4 3 2 1 ---------------------------+ KY KE GI KI OU KI GI KE KY |一 + HI + + + + + KA + |二 FU FU FU FU FU + FU FU と |三 + + + + + + + + + |四 + + + + + + + + + |五 + + + + + + + + + |六 歩 歩 歩 歩 歩 to 歩 歩 + |七 + 角 + + + + + 飛 + |八 香 桂 銀 金 玉 金 銀 桂 香 |九 ---------------------------+ hash(act)=0x2d661f9914b3e548 OK hash(exp)=0x2d661f9914b3e548 9 8 7 6 5 4 3 2 1 ---------------------------------------------------------------------------------------------------------------------+ (--) (--) (--) (--) (--) (--) (--) (--) (--) |一 (--) (--) (--) (--) (--) (--) (--) (nw) (n_) |二 (--) (--) (--) (--) (--) (--) (--) (w_) (N_) |三 (--) (--) (--) (--) (--) (--) (--) (--) (N_s_) |四 (--) (--) (--) (--) (--) (--) (--) (--) (N_) |五 (n_) (n_) (n_) (n_) (n_) (--) (n_) (n_) (N_) |六 (N_NWKnw) (--) (NEKne) (--) (--) (--) (Knw) (N_) (N_Kne) |七 (N_) (W_nw) (W_n_nw) (W_n_nenw) (W_n_nenw) (W_n_nenw) (W_n_ne) (ne) (N_E_) |八 (SW) (--) (SEw_) (w_) (e_w_) (e_) (e_) (S_) (--) |九 ---------------------------------------------------------------------------------------------------------------------+ 9 8 7 6 5 4 3 2 1 ---------------------------------------------------------------------------------------------------------------------+ (--) (N_) (w_) (w_) (w_e_) (e_) (NWe_) (--) (NE) |一 (S_W_) (sw) (E_s_sw) (E_s_swse) (E_s_swse) (E_s_swse) (E_s_se) (E_se) (S_) |二 (S_Ksw) (S_) (Kse) (--) (--) (--) (SWKsw) (--) (S_SEKse) |三 (s_) (s_) (s_) (s_) (s_) (--) (s_) (s_) (--) |四 (--) (--) (--) (--) (--) (--) (--) (--) (--) |五 (--) (--) (--) (--) (--) (n_) (--) (--) (--) |六 (--) (--) (--) (--) (w_) (--) (e_) (--) (--) |七 (--) (--) (--) (--) (sw) (s_) (se) (--) (--) |八 (--) (--) (--) (--) (--) (--) (--) (--) (--) |九 ---------------------------------------------------------------------------------------------------------------------+ 9 8 7 6 5 4 3 2 1 ---------------------------+ KY KE GI KI OU KI GI KE KY |一 + HI + + + + + KA + |二 FU FU FU FU FU + FU FU + |三 + + + + + + + + と |四 + + + + + + + + + |五 + + + + + to + + + |六 歩 歩 歩 歩 歩 + 歩 歩 + |七 + 角 + + + + + 飛 + |八 香 桂 銀 金 玉 金 銀 桂 香 |九 ---------------------------+ hash(act)=0x3395abed868aac1f OK hash(exp)=0x3395abed868aac1f 9 8 7 6 5 4 3 2 1 ---------------------------------------------------------------------------------------------------------------------+ (--) (--) (--) (--) (--) (--) (--) (--) (--) |一 (--) (--) (--) (--) (--) (--) (--) (--) (--) |二 (--) (--) (--) (--) (--) (--) (--) (nw) (n_) |三 (--) (--) (--) (--) (--) (--) (--) (w_) (N_) |四 (--) (--) (--) (--) (--) (--) (--) (--) (N_s_) |五 (n_) (n_) (n_) (n_) (n_) (--) (n_) (n_) (N_) |六 (N_NWKnw) (--) (NEKne) (--) (--) (--) (Knw) (N_) (N_Kne) |七 (N_) (W_nw) (W_n_nw) (W_n_nenw) (W_n_nenw) (W_n_nenw) (W_n_ne) (ne) (N_E_) |八 (SW) (--) (SEw_) (w_) (e_w_) (e_) (e_) (S_) (--) |九 ---------------------------------------------------------------------------------------------------------------------+ 9 8 7 6 5 4 3 2 1 ---------------------------------------------------------------------------------------------------------------------+ (--) (N_) (w_) (w_) (w_e_) (e_) (NWe_) (--) (NE) |一 (S_W_) (sw) (E_s_sw) (E_s_swse) (E_s_swse) (E_s_swse) (E_s_se) (E_se) (S_) |二 (S_Ksw) (S_) (Kse) (--) (--) (--) (SWKsw) (--) (S_SEKse) |三 (s_) (s_) (s_) (s_) (s_) (--) (s_) (s_) (S_) |四 (--) (--) (--) (--) (--) (n_) (--) (--) (--) |五 (--) (--) (--) (--) (w_) (--) (e_) (--) (--) |六 (--) (--) (--) (--) (sw) (s_) (se) (--) (--) |七 (--) (--) (--) (--) (--) (--) (--) (--) (--) |八 (--) (--) (--) (--) (--) (--) (--) (--) (--) |九 ---------------------------------------------------------------------------------------------------------------------+ 9 8 7 6 5 4 3 2 1 ---------------------------+ KY KE GI KI OU KI GI KE KY |一 + HI + + + + + KA + |二 FU FU FU FU FU + FU FU FU |三 + + + + + + + + と |四 + + + + + + + + + |五 + + + + + to + + + |六 歩 歩 歩 歩 歩 歩 歩 歩 + |七 + 角 + + + + + 飛 + |八 香 桂 銀 金 玉 金 銀 桂 香 |九 ---------------------------+ hash(act)=0x2531491652e2d0e1 OK hash(exp)=0x2531491652e2d0e1 9 8 7 6 5 4 3 2 1 ---------------------------------------------------------------------------------------------------------------------+ (--) (--) (--) (--) (--) (--) (--) (--) (--) |一 (--) (--) (--) (--) (--) (--) (--) (--) (--) |二 (--) (--) (--) (--) (--) (--) (--) (nw) (n_) |三 (--) (--) (--) (--) (--) (--) (--) (w_) (N_) |四 (--) (--) (--) (--) (--) (--) (--) (--) (N_s_) |五 (n_) (n_) (n_) (n_) (n_) (n_) (n_) (n_) (N_) |六 (N_NWKnw) (--) (NEKne) (--) (--) (--) (Knw) (N_) (N_Kne) |七 (N_) (W_nw) (W_n_nw) (W_n_nenw) (W_n_nenw) (W_n_nenw) (W_n_ne) (ne) (N_E_) |八 (SW) (--) (SEw_) (w_) (e_w_) (e_) (e_) (S_) (--) |九 ---------------------------------------------------------------------------------------------------------------------+ 9 8 7 6 5 4 3 2 1 ---------------------------------------------------------------------------------------------------------------------+ (--) (N_) (w_) (w_) (w_e_) (e_) (NWe_) (--) (NE) |一 (S_W_) (sw) (E_s_sw) (E_s_swse) (E_s_swse) (E_s_swse) (E_s_se) (E_se) (S_) |二 (S_Ksw) (S_) (Kse) (--) (--) (--) (SWKsw) (--) (S_SEKse) |三 (s_) (s_) (s_) (s_) (s_) (--) (s_) (s_) (s_) |四 (--) (--) (--) (--) (--) (n_) (--) (--) (--) |五 (--) (--) (--) (--) (w_) (--) (e_) (--) (--) |六 (--) (--) (--) (--) (sw) (s_) (se) (--) (--) |七 (--) (--) (--) (--) (--) (--) (--) (--) (--) |八 (--) (--) (--) (--) (--) (--) (--) (--) (--) |九 ---------------------------------------------------------------------------------------------------------------------+ 9 8 7 6 5 4 3 2 1 ---------------------------+ KY KE GI KI OU KI GI KE KY |一 + HI + + + + + KA + |二 FU FU FU FU FU + FU FU FU |三 + + + + + + + 歩 + |四 // 注:この二歩はわざとやっている + + + + + + + + + |五 + + + + + to + + + |六 歩 歩 歩 歩 歩 歩 歩 歩 + |七 + 角 + + + + + 飛 + |八 香 桂 銀 金 玉 金 銀 桂 香 |九 ---------------------------+ hash(act)=0xafed46a6eff80ba9 OK hash(exp)=0xafed46a6eff80ba9 9 8 7 6 5 4 3 2 1 ---------------------------------------------------------------------------------------------------------------------+ (--) (--) (--) (--) (--) (--) (--) (--) (--) |一 (--) (--) (--) (--) (--) (--) (--) (--) (--) |二 (--) (--) (--) (--) (--) (--) (--) (n_) (N_) |三 (--) (--) (--) (--) (--) (--) (--) (--) (N_) |四 (--) (--) (--) (--) (--) (--) (--) (--) (N_) |五 (n_) (n_) (n_) (n_) (n_) (n_) (n_) (n_) (N_) |六 (N_NWKnw) (--) (NEKne) (--) (--) (--) (Knw) (N_) (N_Kne) |七 (N_) (W_nw) (W_n_nw) (W_n_nenw) (W_n_nenw) (W_n_nenw) (W_n_ne) (ne) (N_E_) |八 (SW) (--) (SEw_) (w_) (e_w_) (e_) (e_) (S_) (--) |九 ---------------------------------------------------------------------------------------------------------------------+ 9 8 7 6 5 4 3 2 1 ---------------------------------------------------------------------------------------------------------------------+ (--) (N_) (w_) (w_) (w_e_) (e_) (NWe_) (--) (NE) |一 (S_W_) (sw) (E_s_sw) (E_s_swse) (E_s_swse) (E_s_swse) (E_s_se) (E_se) (S_) |二 (S_Ksw) (S_) (Kse) (--) (--) (--) (SWKsw) (--) (S_SEKse) |三 (s_) (s_) (s_) (s_) (s_) (--) (s_) (s_) (s_) |四 (--) (--) (--) (--) (--) (n_) (--) (--) (--) |五 (--) (--) (--) (--) (w_) (--) (e_) (--) (--) |六 (--) (--) (--) (--) (sw) (s_) (se) (--) (--) |七 (--) (--) (--) (--) (--) (--) (--) (--) (--) |八 (--) (--) (--) (--) (--) (--) (--) (--) (--) |九 ---------------------------------------------------------------------------------------------------------------------+ [01] 歩, sta=(4, 7), dst=(4, 6); (captures FU) [02] と, sta=(2, 4), dst=(2, 3); (captures FU) [03] 歩, sta=(2, 7), dst=(2, 6); (No capture) [04] 歩, sta=(3, 7), dst=(3, 6); (No capture) [05] 歩, sta=(5, 7), dst=(5, 6); (No capture) [06] 歩, sta=(6, 7), dst=(6, 6); (No capture) [07] 歩, sta=(7, 7), dst=(7, 6); (No capture) [08] 歩, sta=(8, 7), dst=(8, 6); (No capture) [09] 歩, sta=(9, 7), dst=(9, 6); (No capture) [10] 香, sta=(1, 9), dst=(1, 8); (No capture) [11] 香, sta=(1, 9), dst=(1, 7); (No capture) [12] 香, sta=(1, 9), dst=(1, 6); (No capture) [13] 香, sta=(1, 9), dst=(1, 5); (No capture) [14] 香, sta=(1, 9), dst=(1, 4); (No capture) [15] 香, sta=(1, 9), dst=(1, 3); (captures FU) [16] 杏, sta=(1, 9), dst=(1, 3); (captures FU) [17] 香, sta=(9, 9), dst=(9, 8); (No capture) [18] 桂, sta=(2, 9), dst=(1, 7); (No capture) [19] 銀, sta=(3, 9), dst=(3, 8); (No capture) [20] 銀, sta=(3, 9), dst=(4, 8); (No capture) [21] 銀, sta=(7, 9), dst=(7, 8); (No capture) [22] 銀, sta=(7, 9), dst=(6, 8); (No capture) [23] 金, sta=(4, 9), dst=(4, 8); (No capture) [24] 金, sta=(4, 9), dst=(3, 8); (No capture) [25] 金, sta=(4, 9), dst=(5, 8); (No capture) [26] 金, sta=(6, 9), dst=(6, 8); (No capture) [27] 金, sta=(6, 9), dst=(5, 8); (No capture) [28] 金, sta=(6, 9), dst=(7, 8); (No capture) [29] 飛, sta=(2, 8), dst=(1, 8); (No capture) [30] 飛, sta=(2, 8), dst=(3, 8); (No capture) [31] 飛, sta=(2, 8), dst=(4, 8); (No capture) [32] 飛, sta=(2, 8), dst=(5, 8); (No capture) [33] 飛, sta=(2, 8), dst=(6, 8); (No capture) [34] 飛, sta=(2, 8), dst=(7, 8); (No capture) [35] 玉, sta=(5, 9), dst=(5, 8); (No capture) [36] 玉, sta=(5, 9), dst=(4, 8); (No capture) [37] 玉, sta=(5, 9), dst=(6, 8); (No capture) [01] FU, sta=(2, 3), dst=(2, 4); (captures 歩) [02] FU, sta=(3, 3), dst=(3, 4); (No capture) [03] to, sta=(4, 6), dst=(4, 7); (captures 歩) [04] to, sta=(4, 6), dst=(4, 5); (No capture) [05] to, sta=(4, 6), dst=(5, 6); (No capture) [06] to, sta=(4, 6), dst=(3, 6); (No capture) [07] to, sta=(4, 6), dst=(5, 7); (captures 歩) [08] to, sta=(4, 6), dst=(3, 7); (captures 歩) [09] FU, sta=(1, 3), dst=(1, 4); (No capture) [10] FU, sta=(5, 3), dst=(5, 4); (No capture) [11] FU, sta=(6, 3), dst=(6, 4); (No capture) [12] FU, sta=(7, 3), dst=(7, 4); (No capture) [13] FU, sta=(8, 3), dst=(8, 4); (No capture) [14] FU, sta=(9, 3), dst=(9, 4); (No capture) [15] KY, sta=(1, 1), dst=(1, 2); (No capture) [16] KY, sta=(9, 1), dst=(9, 2); (No capture) [17] GI, sta=(3, 1), dst=(3, 2); (No capture) [18] GI, sta=(3, 1), dst=(4, 2); (No capture) [19] GI, sta=(7, 1), dst=(7, 2); (No capture) [20] GI, sta=(7, 1), dst=(6, 2); (No capture) [21] KI, sta=(4, 1), dst=(4, 2); (No capture) [22] KI, sta=(4, 1), dst=(5, 2); (No capture) [23] KI, sta=(4, 1), dst=(3, 2); (No capture) [24] KI, sta=(6, 1), dst=(6, 2); (No capture) [25] KI, sta=(6, 1), dst=(7, 2); (No capture) [26] KI, sta=(6, 1), dst=(5, 2); (No capture) [27] HI, sta=(8, 2), dst=(9, 2); (No capture) [28] HI, sta=(8, 2), dst=(7, 2); (No capture) [29] HI, sta=(8, 2), dst=(6, 2); (No capture) [30] HI, sta=(8, 2), dst=(5, 2); (No capture) [31] HI, sta=(8, 2), dst=(4, 2); (No capture) [32] HI, sta=(8, 2), dst=(3, 2); (No capture) [33] OU, sta=(5, 1), dst=(5, 2); (No capture) [34] OU, sta=(5, 1), dst=(6, 2); (No capture) [35] OU, sta=(5, 1), dst=(4, 2); (No capture)
作成初期は、オブジェクト指向を覚えたての初心者のごとく盤クラスとか駒台クラスとかハッシュクラスとか置換表クラスとか細かく分けすぎて見通しが悪かくなりすぎたので、GameStateクラスに全部集約させた。こーいう類のプログラムはモノリシックに作るしかないと得心。
さらにすっきりさせるべく、表示はサブクラスにToString()メソッドを設け、表示する必要があるときダウンキャストする方式でロジックと分離した。
方位をプレイヤーAから見た東西南北で表しているが、これをテンプレートで変換することで、ロジックの記述はプレイヤーA/B共通で済ませている(上記コードには含まれていない)。
あとはこれに学習部を結合する。