2020-06-15に更新

世界コンピューター将棋オンライン電竜戦の頂点を目指せだぜ☆(^~^)!

ひょぶっぷ☆(^~^) あらびょ☆(^~^) 電竜戦 公開下書き

2020-06-01(sun)

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 パーサーをもっと簡単に書けないかだぜ☆?」

KIFUWARABE_80x100x8_01_Futu.gif
「 使いやすいインターフェースが重要だぜ☆」

USIプロトコルとは

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 ↑ まず仕様書を眺めてみましょう!」

go btime 40000 wtime 50000 binc 10000 winc 10000

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 例えば フィッシャー・クロック・ルールのときは このように送られてくるぜ☆
上の例をパースすることを考えてみようぜ☆?」

go btime {} wtime {} binc {} winc {}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ スペースが複数個入ってきたら 考え方は破綻してしまうが、仮に 1つ としよう☆」

'go '

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ コマンドラインの先頭が go だったらトリガーだぜ☆」

'go btime ' | 9 characters.

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 先頭から9文字は問答無用で読み飛ばせだぜ☆」

  g   o       b   t   i   m   e
0   1   2   3   4   5   6   7  8  9

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ インデックスは Python でも使われている伝統で、両端と 文字間に 数が振ってあると思えだぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 で、次は 数かどうかを調べるより、 次に出てくる半角スペースがどこかを調べるんだぜ☆」

  g   o       b   t   i   m   e     4    0    0    0    0 
0   1   2   3   4   5   6   7  8  9   10   11   12   13   14   15

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 もし 40000 という数が途中にあれば、インデックスは 15 まで飛ばせだぜ☆
このとき、 913 の数を覚えておいて、あとで s[9:13] とすれば 文字列 40000 が取れるという仕組みだぜ☆」

regex

KIFUWARABE_80x100x8_01_Futu.gif
「 ↑ 正規表現を使えばいいのでは☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 プログラムを ごりごり 書くより、枠組みに はまった方がマシか……☆」

use regex::Regex;

pub struct Go {
    pub btime: u64,
    pub wtime: u64,
    pub binc: u64,
    pub winc: u64,
}
impl Go {
    /// Example
    /// -------
    /// go btime 40000 wtime 50000 binc 10000 winc 10000
    pub fn parse(line: &String) -> Go {
        let re = Regex::new(r"^go btime (\d+) wtime (\d+) binc (\d+) winc (\d+)$").unwrap();
        let cap = re.captures(line).unwrap();
        Go {
            btime: cap[1].parse().unwrap(),
            wtime: cap[2].parse().unwrap(),
            binc: cap[3].parse().unwrap(),
            winc: cap[4].parse().unwrap(),
        }
    }
}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 正規表現を使う事の 可読性の向上の方が メリットかな……☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 時間をかけて 完成しないプログラムに意味は無いのよ」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 これで 時間切れ が見えるようになったので、早指しさせることができるぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 次は 王手放置漏れ を解消しようぜ☆?」

  • 王手されていることの検知
  • 空き王手されてしまう合い駒をロック
  • 玉が、相手の利きへの飛び込んでしまう動きのロック

KIFUWARABE_80x100x8_01_Futu.gif
「 以上の3つに対応しろだぜ☆」

王手されていることの検知

20200430wcsc96.png

空き王手されてしまう合い駒をロック

20200531dr3.png

玉が、相手の利きへの飛び込んでしまう動きのロック

20200531dr4.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 王手されていることが分かっていても、どう逃げれば 王手を解除できるのか それも むずかしいぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 洗い出そうぜ☆?」

玉の8近傍で、相手の利きが利いていないところに逃げれる

20200531dr5.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 盤上に 相手の駒の利き というものを持ってないといけないよな☆」

王手している駒を取る

20200531dr6.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 空き王手されたり、玉が利きに飛び込んだりしないように しないといけないぜ☆」

合い駒する

20200531dr7.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 持ち駒を置けるなら、長い利きの途中に 駒を置いて 相手の利きを途切れさせることもできるぜ☆
もちろん 移動合い でもOK☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 利きボードを まず作ってみましょう!
利きの中に玉がいて、かつ、利きの外に逃げる手があれば、優先してそれを選ぶようにしましょう!」

KIFUWARABE_80x100x8_01_Futu.gif
「 今 わたしは、どんな盤してるんだぜ☆?」

20200531dr8.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ いろんな盤を試したが、現在も試行錯誤中で、これは わたしの計算力を活かせる わたしに扱いやすい形だぜ☆ 111マスある☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 じゃあ それで☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 これと同じサイズで、利きボードを作りましょう!」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 その前に、この盤も けっこう使いづらいんで、使いやすくしようぜ☆?」

  • SFEN をもとに置く
  • 移動先を指定して置く

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑  駒の置き方には2種類ある☆ これを1つに まとめたいと思うんだぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 違いは何なんだぜ☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 先手玉と、後手玉の位置を 調べるコードが入っているかどうかだぜ☆
あとは、駒に背番号を付けるコードが入ってるかどうかも違うな☆」

  • SFEN を読んだ時に背番号を付ける
  • 移動先を指定して駒を置く

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ なんとか機能を分けた☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 その他に、利きボード を設定するタイミングなんだが、
駒を置いたときか、それより前の 指し手生成 をしたときか☆?」

KIFUWARABE_80x100x8_01_Futu.gif
「 ひねくれなければ、駒を置いたときだぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 駒を持ち上げた時に、その駒の利きが盤上から消えて、長い利きがあれば それが伸びることがあるぜ☆
駒を置いた時に、その駒の利きが盤上に出てきて、長い利きがあれば それが切れることがあるぜ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 それでいけそうな気がするけどなあ」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 できれば 長い利きを止めている というフラグが欲しいぜ☆
キャッパーとか☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 キャプチャーと名前が似てて 紛らわしいぜ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 長い利きの駒は 飛飛角角香香香香 の8枚しかないのだから全検索したら?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 その8回を減らしたいぜ☆ 長い利きをリンクと考えれば、飛車なら4か所にリンクしている駒と考えることができるぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 今日はここまでだぜ☆」

2020-06-02(mon)

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 持ち駒を駒台に置く動きも ごちゃごちゃ してるから 書き直すぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 へーっ、つらっ☆」

20200601dr11a2.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 適当に番号振ったが、まあいいだろう☆」

20200601dr12.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 集合が変わるんだぜ☆ うーい☆」

20200601dr13.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ うーい☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 振っている数 を統一したら ……、集合の意味がなくなるかだぜ☆」

20200601dr14.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ うーーっいっ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 場合によって使い分けるのねぇ」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 駒の背番号を、うぃーっ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 お父んが読んだソースコードは 駒の背番号制ではなかったからな☆ 駒に背番号を付ける仕組みを改善しているのだろう☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 うぃーっ☆ 背番号のコードをすっきり うぃーっ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 そうか☆」

    /// 盤に駒を置く
    pub fn push_to_board(&mut self, addr: &AbsoluteAddress, piece: Option<Piece>) {
        if let Some(piece_val) = piece {
            // マスに駒を置きます。
            self.pieces[addr.serial_number() as usize] = piece;
            // 背番号に番地を紐づけます。
            self.address[piece_val.num as usize] = AddressOnPosition::Board(*addr);
        } else {
            // マスを空にします。
            self.pieces[addr.serial_number() as usize] = None;
        }
    }
    /// 台に駒を置く
    pub fn push_to_hand(&mut self, piece: &Piece) {
        let pp = piece.meaning.physical_piece();
        // 持ち駒を1つ増やします。
        self.hands[pp as usize].push(piece);
        // 背番号に番地を紐づけます。
        self.address[piece.num as usize] = AddressOnPosition::Hand(pp);
    }
    /// 盤から駒を取りのぞく
    pub fn pop_from_board(&mut self, adr: &AbsoluteAddress) -> Option<Piece> {
        // まず、駒があるか確認するぜ☆(^~^)
        let piece = self.pieces[adr.serial_number() as usize];
        if let Some(piece_val) = piece {
            // マスを空にします。
            self.pieces[adr.serial_number() as usize] = None;
            // 背番号の番地を消去します。
            self.address[piece_val.num as usize] = AddressOnPosition::Busy;
        }
        piece
    }
    /// 台から駒を取りのぞく
    pub fn pop_from_hand(&mut self, adr: PhysicalPiece) -> Piece {
        // 台から取りのぞきます。
        let piece = self.hands[adr as usize].pop();
        // 背番号の番地を消去します。
        self.address[piece.num as usize] = AddressOnPosition::Busy;
        piece
    }

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 盤と駒台の駒の移動は この4つの操作に絞り込んだぜ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 ここで 利きボード を編集したらいいのよ」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 その前に 香車にバグがあるみたいなんで そっちも直したいぜ☆」

20200601dr15a1.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑後手の香車が うしろを向いているんだぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 大問題だぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 なんでなんだろなあ☆」

20200601dr16a1.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ミスを見つけたぜ☆ 同じ名前の違う変数を指定していたんだぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 バグ取れた……☆」

2020-06-03(tue)

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 利きボードを もっと詳しく洗い出そうぜ☆?」

20200602dr17a1.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ こんな感じかだぜ☆?」

KIFUWARABE_80x100x8_01_Futu.gif
「 前後の対称性が無いのでは☆?」

20200602dr17a2.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ じゃあ こんな感じかだぜ☆?」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 短い利き はこれでいいんじゃない?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 次は アンドゥ の有名な方法も 確認しておこうぜ☆?」

20200602dr17a3.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 先後逆にして 指せばいいんだぜ☆ あっ、利きが ついてこねっ☆!」

KIFUWARABE_80x100x8_01_Futu.gif
「 180°回転するか、しないかを選べるように 折りこめだぜ☆」

20200602dr17a4.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ つまり こう☆?」

KIFUWARABE_80x100x8_01_Futu.gif
「 んー、いいんじゃないか☆?」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 駒を取る流れも 含めてみましょう!」

20200602dr19a5b2.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 11ステップだっけ……☆?」

KIFUWARABE_80x100x8_01_Futu.gif
「 利きを入れたシミュレーションは 今回が初めてだな☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 アンドゥ・ムーブ してみましょう!」

20200602dr19a5b3.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ イケてるぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 しかし わたしの do_move は イケてないが……☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 もっと 雑多な制御が入ってるからな☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 洗い出しましょう!」

20200602dr20.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 現在のきふわらべは こんな感じだぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 打だの、盤上だの 分けなければいけないのかだぜ☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 棋譜のつくり方、指し手のデータの持ち方から 見直せばいけるかもしれないな☆ 移動と指し手を分けてるのは 棋譜、指し手のデータ なんで☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 見直せだぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 すごい改造になるが、ストックフィッシュ系から離れる 面白い課題ではあるぜ☆」

/// 棋譜にも使うので、取った駒の情報を記憶しておくんだぜ☆(^~^)
/// 投了なら これを使わず、None にしろだぜ☆(^~^)
///
/// Copy: 配列の要素の初期化時に使う☆(^~^)
#[derive(Clone, Copy)]
pub struct Movement {
    // 移動元升。Dropのときは None だぜ☆(^~^)
    pub source: Option<AbsoluteAddress>,
    // 移動先升。
    pub destination: AbsoluteAddress,
    // 移動後に成るなら真
    pub promote: bool,
    // 打の場合、打った駒種類
    pub drop: Option<PhysicalPieceType>,
}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ ここの、 sourcedrop を区別せずに ひとつ にすればいいんだぜ☆
Bonanza や、大樹の枝 とは違う作りになるな☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 drop を PhysicalPieceType型ではなく、 PhysicalPiece型 にすればいけるわよ」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 慣性の法則に似てるよな☆ 先手か後手は、消すのではなく、残す☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 手番は 棋譜を見て 奇数か偶数かで 先後を見ているが、
指し手ひとつ ひとつに持たせた方がいいのか☆ 変な話しだぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 AbsoluteAddress と PhysicalPieceType を共有する新しい型を 作ってしまえだぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 AddressTypeOnPosition みたいな名前にすればいいか……☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 push_to_board で None も駒も設定していたが、 push_to_board と、 remove_from_board の2つに分けていいだろうか☆?」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 分岐を減らそうとしているのに、分けていいの?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 そうか……☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 将棋盤にセットするとき、Some(Piece) の形にしているから、Some は付けたままの方がいいか☆」

#[derive(Clone, Copy)]
pub enum AddressTypeOnPosition {
    // 盤上の移動なら、移動元升。
    Move(AbsoluteAddress),
    // 打の場合、打った駒種類
    Drop(PhysicalPieceType),
    // 未設定ならこれ。
    Busy,
}

/// 棋譜にも使うので、取った駒の情報を記憶しておくんだぜ☆(^~^)
/// 投了なら これを使わず、None にしろだぜ☆(^~^)
///
/// Copy: 配列の要素の初期化時に使う☆(^~^)
#[derive(Clone, Copy)]
pub struct Movement {
    pub source: AddressTypeOnPosition,
    // 移動先升。
    pub destination: AbsoluteAddress,
    // 移動後に成るなら真
    pub promote: bool,
}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ こんな風に改造☆ NPS 下がった気がするが、まだ このデータ構造を活かした実装にしてないしな☆」

2020-06-03(wed)

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 成るとか、打つとか言わず、機械的動作に落とし込んでくれだぜ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 成るのは 駒の表裏をひっくり返すのよ。
打つのは 駒台にある駒を 盤上に置くのよ」

20200603dr21.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 打を 含味すると こうだぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 成りも 包含してくれだぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 むぐぐ☆」

20200603dr21a2.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ ぐたっ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 アンドゥもできるか 試してみましょう!」

20200603dr21a3.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ へえっ☆!」

KIFUWARABE_80x100x8_01_Futu.gif
「 盤上か、駒台か 区別しない書き方にしてくれだぜ☆」

20200603dr21a4.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 取った駒は、駒台に行くことが確定だぜ☆!」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 指し手に書かれているところに戻ることが 確定 なら、
戻るように移動するためにやった180°回転は 要らないんじゃない?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 人間の棋譜の符号ではなく、コンピューター将棋の棋譜の符号だから そうなるが……☆
アンドゥのときは 移動先と 移動元を入れ替えて 移動する、ということをすれば 同じことだな☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 前後同型のアルゴリズムにこだわる必要はあるの?
プログラムに、逆順に実行するって 無いけど」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 関数を配列に入れれないか、あとで試そうぜ☆?」

20200603dr21a5.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 180°回転を 消した……☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 ドゥ ムーブも これでいけるか 試してみましょう!」

20200603dr21a6.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 大筋では do_move も undo_move も同型で、移動元と移動先だけが ひっくり返っていると
見れるんじゃないか☆?」

KIFUWARABE_80x100x8_01_Futu.gif
「 もっと 前後同型になるんじゃないかだぜ☆?」

20200603dr21a7.png

KIFUWARABE_80x100x8_01_Futu.gif
「 ↑ こう☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ふむむ……☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 さらに アンドゥもできるか 試してみましょう!」

20200603dr21a8.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ おや、どこかでミスったかだぜ☆? また明日 見直そうぜ☆」

2020-06-04(tue)

20200603dr21a7b1.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 塗り間違えていただけで、合ってるのでは☆?」

KIFUWARABE_80x100x8_01_Futu.gif
「 じゃあ コーディングの方を この図に合わそうぜ☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 まだ、手数を増やすとか、盛り込んでないからな☆」

20200604dr22.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 前後同型にならない部分ってあるだろ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 ならない部分を なるようにしようぜ☆?」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 棋譜の指し手を 投了に 始まり 投了 に終わるようにすれば
前後同型になるわよ」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 指すときは 指し手生成 なのに、戻すときは 指し手読取 なのは 違いを吸収できるものなのだろうか☆?」

KIFUWARABE_80x100x8_01_Futu.gif
「 じゃあ、 do_moveundo_move というより、 read_move と、 read_move_in_reverse なのかだぜ☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 そうだぜ☆ リネームしとくか……☆」

20200604dr22a1.png

KIFUWARABE_80x100x8_01_Futu.gif
「 ↑ 指し手を 棋譜に入れるとか、消さないとか ここに あるのは おかしいぜ☆ 消しておくぜ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 指し手は クローン しなくちゃいけないの?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 クローンしなくていいかどうか クローンを外して試してみるか……☆」

20200604dr22a2.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ クローンしなくてよかった……☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 取った駒を 棋譜に記録してるのは何でだぜ☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 棋譜には 取った駒が何かは書いてないんだぜ☆
動かしてみて 初めて 取った駒が分かるんだぜ☆ 駒を取ったら、棋譜に補足情報として記録するぜ☆
これは アンドゥ するために必要だぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 じゃあ read_move、 read_move_in_reverse は間違いだろ☆
do_movedo_move_in_reverse に変えろだぜ☆」

20200604dr22a3.png

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 do_move で 手番を読み取って 何してんの?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 駒を打つとき、どっちの駒台にある駒が減るかを判定するために使っているぜ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 USIの棋譜の符号には 駒を打つときの先後は 書いてないのねぇ」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 USIの思想と わたしたちの思想は 合ってないんじゃないの?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 それは そうなんだが……☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 わたしたちの思想に合った 棋譜オブジェクトを 作成しましょう」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 大改造になるな……☆」

20200604dr22a4.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 取られることになる駒は 先に棋譜に記録しておいたぜ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 持ち駒を打つのも 手番を確認せずに 打ちたいなあ!」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 大改造になるな……☆ コードを見直してみるかだぜ☆」

#[derive(Clone, Copy)]
pub enum AddressTypeOnPosition {
    // 盤上の移動なら、移動元升。
    Move(AbsoluteAddress),
    // 打の場合、打った駒種類
    Drop(PhysicalPieceType),
    // 未設定ならこれ。
    Busy,
}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ これが……☆」

#[derive(Clone, Copy)]
pub enum AddressTypeOnPosition {
    // 盤上の移動なら、移動元升。
    Move(AbsoluteAddress),
    // 打の場合、打った駒種類
    Drop(PhysicalPiece),
    // 未設定ならこれ。
    Busy,
}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ こうなればいいんだろ☆?」

(カタカタカタ)

20200604dr22a5.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 対応しておいたぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 do_move で局面ハッシュを更新していて、なんで undo_move で局面ハッシュを更新してないんだぜ☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 なんでなんだろな☆?」

KIFUWARABE_80x100x8_01_Futu.gif
「 直せ☆!」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 こりゃまた 大改造コースだぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ハッシュの差分更新は作ってなかったのか……☆ また明日だぜ☆」

2020-06-05(fri)

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 指し手の source には 駒台があるが、 destination は 駒台が無いからな☆
駒台に置くという操作がない☆
アシンメトリックだぜ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 前に リバーシブル指し手 を作ろうとしてたじゃない。あれをやればいいのよ」

KIFUWARABE_80x100x8_01_Futu.gif
「 駒台に指せるやつだろ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 リバーシブル指し手 への改造は進めているが、取った駒の扱いが よく見えないぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 というのも、『取った駒は歩』という記録の仕方をしてるだろ☆
これが『2四にある駒が、後手駒台の歩の位置へ』という記録の仕方をしてくれていたら
リバースさせやすいんだぜ☆
『後手駒台の歩が、2四へ』みたいな☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 取った駒が 盤の上を移動するケースがあるのか☆?
『2四にある駒が、8四へ』みたいな☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 それも自然だな☆ 投げ技みたいな……☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 バグの可能性が広がるのよ!」

#[derive(Clone, Copy)]
pub struct Movement {
    /// 移動元マス。
    pub source: AddressPos,
    /// 移動先マス。リバーシブルに作りたいので、駒台にも指せる。
    pub destination: AddressPos,
    /// 移動後に成るなら真
    pub promote: bool,
    /// 取ることになる駒
    pub captured: Option<Piece>,
}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ このキャプチャーを、ソースとデスティネーションにするかだな☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 玉を取ったかどうか 知りたいのよねぇ」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 指し手に 駒の種類を書かなければ、指し手から 将棋のルールを切り離せるが……☆
より 機械的動作 にできる……、やってみることは 方向性に沿ってるな……☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 プログラム中に pop と push の2ステップに分かれているのは 設計図と異なるな……☆
swap の1回で できないものかだぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 移動先で、駒があったときに コリジョンするぜ☆ 3点同時スワップでもあれば別だが……☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 考えてみるか……☆」

20200606dr24.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ まず 利きの操作を 出入り口周辺に集めてみるぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 あれっ☆? 3点同時スワップ では トグルにならね……☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 せめて 盤上に 空中マスA、B を用意して スワップ できない?
今 111マス あるんでしょ。 113マス にするのよ」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 スカイ・マスを作ってみたんだが むずかしい……、ローカル変数の方が コードが見やすいぜ☆」

20200606dr25.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 とりあえず 少しいじったぜ☆ 今日はここまでだぜ☆」

2020-06-06(sat)

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 取られた駒を 移動元、起動先にするか どうかだっけ……☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 盤上の移動は マスが分かればいいんだが、駒台の移動は その駒の種類が分からないといけないだろ☆
棋譜だけで できないんだよな☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 PieceMeaning の定義を変えたらどうだぜ☆?」

20200606dr26.png

KIFUWARABE_80x100x8_01_Futu.gif
「 ↑ 盤上か、駒台かも 包含したらどうだぜ☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 駒と 番地の区別は☆?」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 駒台の上に 番地は無いのよ」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 駒台の上の何を打ったのかを表すのは 駒の種類だろ☆
駒台の上において 駒の種類は 番地だぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 現に USI でも 金を打つときは G* だぜ☆ G* は番地なんだぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 盤の上のマスを1つ選べば、駒は1つに絞れるんだが、
持ち駒は 絞れないの、非対称だよな☆ どうするかな☆」

2020-06-07(sun)

20200607dr28.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ Piece は必ず、GameTable の中にあり、その外には出ないもととする☆
よくある言い方をすれば、 Piece をカプセル化するんだぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 指し手生成で Piece を使いたくならないか☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 駒の背番号を使えだぜ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 じゃあ 盤や 駒台の上にあるのも 駒の背番号 にすればいいんじゃない?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 むむむ、そうか……☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 根本的な大改造ばっかだが やるか……☆」

20200607dr31.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ いままで Piece は どこかにある、という構造だったが……☆」

20200607dr29.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 駒が40個ならんでいて、その駒は 場所の方を指差している、風に改造するんだぜ☆
ただ、これを そのまま改造するのはむずかしいので……☆」

20200607dr32.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 古い経路はバイパス(迂回路)として残しつつ、間に Num を置く、という手術を行うぜ☆
うまく 間に置けてから バイパスを取り除くぜ☆」

20200607dr34.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 今までは 番地 というリストに駒が紐づいていたが……☆」

20200607dr34.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ Num(駒の背番号)は、タグ(荷札)みたいなものとしよう☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 段階的改造ね」

KIFUWARABE_80x100x8_01_Futu.gif
「 住所録というのは、氏名に住所が紐づいているのではないか☆?
上の図では AddressList の住所と氏名が 逆だぜ☆」

20200607dr35.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 住所に 氏名が紐づいているから、 PostList か……☆?」

20200607dr36.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ そういう意味では 現状 AddressList なんだぜ☆」

20200607dr37.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ だから 今回は 無駄に PostList をまず作るんだぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 いや、現状が PostList なのでは☆? 将棋盤は PostList だぜ☆」

20200607dr38.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ じゃあ これが現状かだぜ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 そうよ!」

20200607dr39.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ PieceList 1つはさめば いいわけかだぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 Piece を色んなところに使ってるのか、更新が うまくいかないぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 Piece の使用箇所を洗い出そうぜ☆?」

  • 盤に乗っている
  • 駒台に乗っている

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 なんだ……☆ 盤とか 駒台とかに 今乗っているのは あとで捨てようと思ってるゴミかだぜ……☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 そのゴミは 捨ててはいけないわよ。まだ バイパスを通すのだから」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 どっかに置いとくか……☆ old_pieces みたいな変数とか☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 うーん、うまく いかんなあ……☆」

20200607dr41.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ こうしてみるか……☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 なんか 持ち駒ないのに 取ろうとしてしまうぜ☆?」

KIFUWARABE_80x100x8_01_Futu.gif
「 駒台の駒も、背番号を名指しして取る必要があるぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 なんでだぜ☆!」

KIFUWARABE_80x100x8_01_Futu.gif
「 将棋の盤上は マス で 1つの駒を選べるが、
駒台の駒は、駒番号でしか 1つの駒を選べないぜ☆」

20200607dr42.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ じゃあ 駒台の上は、玉2枚を除く38枚のための専用スペースを設けておくべきかだぜ☆?」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 歩を18枚 持っているとき、検索が遅くならない?」

20200607dr42a1.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 将棋の駒台専用の スタック を作るというのも手だぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 入り口は 固定位置だし、駒番号は……、駒を取り合ったら変わるのでは☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 出すのと入れるのとを きっちりやれば、取り出したい駒は 入り口にいるはずだぜ☆」

/// 駒台だぜ☆(^~^)これ1つで2人分あるんで☆(^~^)
#[derive(Clone)]
pub struct HandStack {
    king: Hand2Piece,
    gold: Hand4Piece,
    silver: Hand4Piece,
    knight: Hand4Piece,
    lance: Hand4Piece,
    rook: Hand2Piece,
    bishop: Hand2Piece,
    pawn: Hand18Piece,
}
impl Default for HandStack {
    // ゴミ値で埋めるぜ☆(^~^)
    fn default() -> Self {
        HandStack {
            king: Hand2Piece::default(),
            gold: Hand4Piece::default(),
            silver: Hand4Piece::default(),
            knight: Hand4Piece::default(),
            lance: Hand4Piece::default(),
            rook: Hand2Piece::default(),
            bishop: Hand2Piece::default(),
            pawn: Hand18Piece::default(),
        }
    }
}
impl HandStack {
    /// ひっくり返してから入れてください。
    fn push(&mut self, old_piece: &OldPiece) {
        match (*old_piece).old_meaning.physical_piece() {
            PhysicalPiece::King1 => {
                self.king.push_head(*old_piece);
            }
            PhysicalPiece::King2 => {
                self.king.push_tail(*old_piece);
            }
            PhysicalPiece::Gold1 => {
                self.gold.push_head(*old_piece);
            }
            PhysicalPiece::Gold2 => {
                self.gold.push_tail(*old_piece);
            }
            PhysicalPiece::Silver1 => {
                self.silver.push_head(*old_piece);
            }
            PhysicalPiece::Silver2 => {
                self.silver.push_tail(*old_piece);
            }
            PhysicalPiece::Knight1 => {
                self.knight.push_head(*old_piece);
            }
            PhysicalPiece::Knight2 => {
                self.knight.push_tail(*old_piece);
            }
            PhysicalPiece::Lance1 => {
                self.lance.push_head(*old_piece);
            }
            PhysicalPiece::Lance2 => {
                self.lance.push_tail(*old_piece);
            }
            PhysicalPiece::Rook1 => {
                self.rook.push_head(*old_piece);
            }
            PhysicalPiece::Rook2 => {
                self.rook.push_tail(*old_piece);
            }
            PhysicalPiece::Bishop1 => {
                self.bishop.push_head(*old_piece);
            }
            PhysicalPiece::Bishop2 => {
                self.bishop.push_tail(*old_piece);
            }
            PhysicalPiece::Pawn1 => {
                self.pawn.push_head(*old_piece);
            }
            PhysicalPiece::Pawn2 => {
                self.pawn.push_tail(*old_piece);
            }
        }
    }

    /// ゴミ値は消さないぜ☆(^~^)
    fn pop(&mut self, phy: PhysicalPiece) -> OldPiece {
        match phy {
            PhysicalPiece::King1 => self.king.pop_head(),
            PhysicalPiece::King2 => self.king.pop_tail(),
            PhysicalPiece::Gold1 => self.gold.pop_head(),
            PhysicalPiece::Gold2 => self.gold.pop_tail(),
            PhysicalPiece::Silver1 => self.silver.pop_head(),
            PhysicalPiece::Silver2 => self.silver.pop_tail(),
            PhysicalPiece::Knight1 => self.knight.pop_head(),
            PhysicalPiece::Knight2 => self.knight.pop_tail(),
            PhysicalPiece::Lance1 => self.lance.pop_head(),
            PhysicalPiece::Lance2 => self.lance.pop_tail(),
            PhysicalPiece::Rook1 => self.rook.pop_head(),
            PhysicalPiece::Rook2 => self.rook.pop_tail(),
            PhysicalPiece::Bishop1 => self.bishop.pop_head(),
            PhysicalPiece::Bishop2 => self.bishop.pop_tail(),
            PhysicalPiece::Pawn1 => self.pawn.pop_head(),
            PhysicalPiece::Pawn2 => self.pawn.pop_tail(),
        }
    }

    fn last(&self, phy: PhysicalPiece) -> Option<&OldPiece> {
        match phy {
            PhysicalPiece::King1 => self.king.last_head(),
            PhysicalPiece::King2 => self.king.last_tail(),
            PhysicalPiece::Gold1 => self.gold.last_head(),
            PhysicalPiece::Gold2 => self.gold.last_tail(),
            PhysicalPiece::Silver1 => self.silver.last_head(),
            PhysicalPiece::Silver2 => self.silver.last_tail(),
            PhysicalPiece::Knight1 => self.knight.last_head(),
            PhysicalPiece::Knight2 => self.knight.last_tail(),
            PhysicalPiece::Lance1 => self.lance.last_head(),
            PhysicalPiece::Lance2 => self.lance.last_tail(),
            PhysicalPiece::Rook1 => self.rook.last_head(),
            PhysicalPiece::Rook2 => self.rook.last_tail(),
            PhysicalPiece::Bishop1 => self.bishop.last_head(),
            PhysicalPiece::Bishop2 => self.bishop.last_tail(),
            PhysicalPiece::Pawn1 => self.pawn.last_head(),
            PhysicalPiece::Pawn2 => self.pawn.last_tail(),
        }
    }

    fn len(&self, phy: PhysicalPiece) -> usize {
        match phy {
            PhysicalPiece::King1 => self.king.len_head(),
            PhysicalPiece::King2 => self.king.len_tail(),
            PhysicalPiece::Gold1 => self.gold.len_head(),
            PhysicalPiece::Gold2 => self.gold.len_tail(),
            PhysicalPiece::Silver1 => self.silver.len_head(),
            PhysicalPiece::Silver2 => self.silver.len_tail(),
            PhysicalPiece::Knight1 => self.knight.len_head(),
            PhysicalPiece::Knight2 => self.knight.len_tail(),
            PhysicalPiece::Lance1 => self.lance.len_head(),
            PhysicalPiece::Lance2 => self.lance.len_tail(),
            PhysicalPiece::Rook1 => self.rook.len_head(),
            PhysicalPiece::Rook2 => self.rook.len_tail(),
            PhysicalPiece::Bishop1 => self.bishop.len_head(),
            PhysicalPiece::Bishop2 => self.bishop.len_tail(),
            PhysicalPiece::Pawn1 => self.pawn.len_head(),
            PhysicalPiece::Pawn2 => self.pawn.len_tail(),
        }
    }

    /*
    fn to_debug(&self, table: &GameTable) -> String {
        let mut buffer = String::new();
        for i in 0..=self.count {
            buffer.push_str(&format!(
                "({}, {:?}) ",
                self.items[i].meaning, self.items[i].num
            ));
        }
        buffer.trim_end().to_string()
    }
    */
}

#[derive(Clone)]
pub struct Hand2Piece {
    items: [OldPiece; 2],
    head: usize,
    tail: usize,
}
impl Default for Hand2Piece {
    /// ゴミ値だぜ☆(^~^)
    fn default() -> Self {
        Hand2Piece {
            items: [OldPiece::default(); 2],
            head: 0,
            tail: 1,
        }
    }
}
impl Hand2Piece {
    pub fn push_head(&mut self, num: OldPiece) {
        self.items[self.head] = num;
        self.head += 1;
    }
    pub fn push_tail(&mut self, num: OldPiece) {
        self.items[self.tail] = num;
        self.tail -= 1;
    }
    pub fn pop_head(&mut self) -> OldPiece {
        let num = self.items[self.head];
        self.head -= 1;
        num
    }
    pub fn pop_tail(&mut self) -> OldPiece {
        let num = self.items[self.tail];
        self.tail += 1;
        num
    }
    pub fn last_head(&self) -> Option<&OldPiece> {
        if 0 < self.head {
            Some(&self.items[self.head - 1])
        } else {
            None
        }
    }
    pub fn last_tail(&self) -> Option<&OldPiece> {
        if self.tail < 1 {
            Some(&self.items[self.tail + 1])
        } else {
            None
        }
    }
    pub fn len_head(&self) -> usize {
        self.head
    }
    pub fn len_tail(&self) -> usize {
        1 - self.tail
    }
}
#[derive(Clone)]
pub struct Hand4Piece {
    items: [OldPiece; 4],
    head: usize,
    tail: usize,
}
impl Default for Hand4Piece {
    /// ゴミ値だぜ☆(^~^)
    fn default() -> Self {
        Hand4Piece {
            items: [OldPiece::default(); 4],
            head: 0,
            tail: 3,
        }
    }
}
impl Hand4Piece {
    pub fn push_head(&mut self, num: OldPiece) {
        self.items[self.head] = num;
        self.head += 1;
    }
    pub fn push_tail(&mut self, num: OldPiece) {
        self.items[self.tail] = num;
        self.tail -= 1;
    }
    pub fn pop_head(&mut self) -> OldPiece {
        let num = self.items[self.head];
        self.head -= 1;
        num
    }
    pub fn pop_tail(&mut self) -> OldPiece {
        let num = self.items[self.tail];
        self.tail += 1;
        num
    }
    pub fn last_head(&self) -> Option<&OldPiece> {
        if 0 < self.head {
            Some(&self.items[self.head - 1])
        } else {
            None
        }
    }
    pub fn last_tail(&self) -> Option<&OldPiece> {
        if self.tail < 3 {
            Some(&self.items[self.tail + 1])
        } else {
            None
        }
    }
    pub fn len_head(&self) -> usize {
        self.head
    }
    pub fn len_tail(&self) -> usize {
        3 - self.tail
    }
}
#[derive(Clone)]
pub struct Hand18Piece {
    items: [OldPiece; 18],
    head: usize,
    tail: usize,
}
impl Default for Hand18Piece {
    /// ゴミ値だぜ☆(^~^)
    fn default() -> Self {
        Hand18Piece {
            items: [OldPiece::default(); 18],
            head: 0,
            tail: 17,
        }
    }
}
impl Hand18Piece {
    pub fn push_head(&mut self, num: OldPiece) {
        self.items[self.head] = num;
        self.head += 1;
    }
    pub fn push_tail(&mut self, num: OldPiece) {
        self.items[self.tail] = num;
        self.tail -= 1;
    }
    pub fn pop_head(&mut self) -> OldPiece {
        let num = self.items[self.head];
        self.head -= 1;
        num
    }
    pub fn pop_tail(&mut self) -> OldPiece {
        let num = self.items[self.tail];
        self.tail += 1;
        num
    }
    pub fn last_head(&self) -> Option<&OldPiece> {
        if 0 < self.head {
            Some(&self.items[self.head - 1])
        } else {
            None
        }
    }
    pub fn last_tail(&self) -> Option<&OldPiece> {
        if self.tail < 17 {
            Some(&self.items[self.tail + 1])
        } else {
            None
        }
    }
    pub fn len_head(&self) -> usize {
        self.head
    }
    pub fn len_tail(&self) -> usize {
        17 - self.tail
    }
}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 あれっ☆? この構造が1つあれば、2つ分の駒台も要らないぜ……☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 駒って、先後反転してから入れて、取り出すときは、どっちだぜ☆?
自分が指すときと、アンドゥするときがあるだろ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 ドゥの時は ひっくり返して入れて、ひっくり返さず取り出せだぜ☆
アンドゥのときは、ひっくり返さず入れて、ひっくり返して取り出せだぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 めんどくさ……☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 一元化されたデータを 先後反転 させているのではなく、
先後反転したインスタンスを作っては 変数に入れる、ということにしていて 状態の一貫性が欠けているぜ☆
直さないとな……☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 棋譜に記録してる取った駒、くるくる回ってんじゃないか☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 どうも どういじっても不具合が出るな……☆
push の回数より pop の回数の方が多いみたいなんだぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 なんでだぜ☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 成り駒かどうか、先後はどちらか、ぴったり合わせないといけないようだ……、持ち駒なのに……☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 知ってる☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 いくつか 整えたが まだ 動きがおかしい☆ 分からん……☆」

20200607dr42a2.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ もしかして 左右逆だった☆?」

    pub fn push_head(&mut self, num: OldPiece) {
        self.items[self.head] = num;
        self.head += 1;
    }
    pub fn pop_head(&mut self) -> OldPiece {
        self.head -= 1;
        let num = self.items[self.head];
        num
    }

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ さらに、プッシュでは 配列に要素を入れてからカーソルを進めるが、
ポップでは カーソルを戻してから 配列の要素を出すのだった☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 この2つを修正して なんか 動きはする……☆」

2020-06-08(mon)

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 持ち駒は、カウンティング・セマフォにした方がいいのでは……、という気もしてきているぜ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 順序が 保たれないじゃない」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ぬぐぐぐ……☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 昨日の実装は カウンティング・セマフォになってるんだぜ☆」

20200608dr43a1.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 インデックスをよく見て if文……、match文か、 を減らしてみるかだぜ……☆」

/// 駒台だぜ☆(^~^)これ1つで2人分あるんで☆(^~^)
#[derive(Clone)]
pub struct HandStack {
    items: [PieceNum; 40],
    starts: [isize; 16],
    currents: [isize; 16],
    steps: [isize; 16],
}
impl Default for HandStack {
    // ゴミ値で埋めるぜ☆(^~^)
    fn default() -> Self {
        HandStack {
            items: [PieceNum::King1; 40],
            starts: [
                0,  // King1
                20, // Rook1
                18, // Bishop1
                2,  // Gold1
                6,  // Silver1
                10, // Knight1
                14, // Lance1
                22, // Pawn1
                1,  // King2
                21, // Rook2
                19, // Bishop2
                5,  // Gold2
                9,  // Silver2
                13, // Knight2
                17, // Lance2
                39, // Pawn2
            ],
            currents: [
                0,  // King1
                20, // Rook1
                18, // Bishop1
                2,  // Gold1
                6,  // Silver1
                10, // Knight1
                14, // Lance1
                22, // Pawn1
                1,  // King2
                21, // Rook2
                19, // Bishop2
                5,  // Gold2
                9,  // Silver2
                13, // Knight2
                17, // Lance2
                39, // Pawn2
            ],
            steps: [
                1,  // King1
                1,  // Rook1
                1,  // Bishop1
                1,  // Gold1
                1,  // Silver1
                1,  // Knight1
                1,  // Lance1
                1,  // Pawn1
                -1, // King2
                -1, // Rook2
                -1, // Bishop2
                -1, // Gold2
                -1, // Silver2
                -1, // Knight2
                -1, // Lance2
                -1, // Pawn2
            ],
        }
    }
}
impl HandStack {
    /// 駒の先後を ひっくり返してから入れてください。
    pub fn push(&mut self, drop: DoubleFacedPiece, num: PieceNum) {
        // 駒台に駒を置くぜ☆(^~^)
        self.items[self.currents[drop as usize] as usize] = num;
        // 位置を増減するぜ☆(^~^)
        self.currents[drop as usize] += self.steps[drop as usize];
    }
    /// ゴミ値は消さないぜ☆(^~^)
    pub fn pop(&mut self, drop: DoubleFacedPiece) -> PieceNum {
        // 位置を増減するぜ☆(^~^)
        self.currents[drop as usize] -= self.steps[drop as usize];
        // 駒台の駒をはがすぜ☆(^~^)
        self.items[self.currents[drop as usize] as usize]
    }

    fn last(&self, drop: DoubleFacedPiece) -> Option<PieceNum> {
        let step = self.steps[drop as usize];
        if step == 1 {
            if self.starts[drop as usize] < self.currents[drop as usize] {
                Some(self.items[(self.currents[drop as usize] - 1) as usize])
            } else {
                None
            }
        } else {
            if self.currents[drop as usize] < self.starts[drop as usize] {
                Some(self.items[(self.currents[drop as usize] + 1) as usize])
            } else {
                None
            }
        }
    }

    fn len(&self, drop: DoubleFacedPiece) -> usize {
        let step = self.steps[drop as usize];
        if step == 1 {
            (self.currents[drop as usize] - self.starts[drop as usize]) as usize
        } else {
            (self.starts[drop as usize] - self.currents[drop as usize]) as usize
        }
    }

    /*
    fn to_debug(&self, table: &GameTable) -> String {
        let mut buffer = String::new();
        for i in 0..=self.count {
            buffer.push_str(&format!(
                "({}, {:?}) ",
                self.items[i].piece, self.items[i].num
            ));
        }
        buffer.trim_end().to_string()
    }
    */
}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ はい☆」

/// 駒台だぜ☆(^~^)これ1つで2人分あるんで☆(^~^)
#[derive(Clone)]
pub struct HandStack {
    items: [PieceNum; 40],
    areas: [HandStackArea; 16],
    currents: [isize; 16],
}
impl Default for HandStack {
    // ゴミ値で埋めるぜ☆(^~^)
    fn default() -> Self {
        HandStack {
            items: [PieceNum::King1; 40],
            areas: [
                HandStackArea::new(0, 1),   // King1
                HandStackArea::new(20, 1),  // Rook1
                HandStackArea::new(18, 1),  // Bishop1
                HandStackArea::new(2, 1),   // Gold1
                HandStackArea::new(6, 1),   // Silver1
                HandStackArea::new(10, 1),  // Knight1
                HandStackArea::new(14, 1),  // Lance1
                HandStackArea::new(22, 1),  // Pawn1
                HandStackArea::new(1, -1),  // King2
                HandStackArea::new(21, -1), // Rook2
                HandStackArea::new(19, -1), // Bishop2
                HandStackArea::new(5, -1),  // Gold2
                HandStackArea::new(9, -1),  // Silver2
                HandStackArea::new(13, -1), // Knight2
                HandStackArea::new(17, -1), // Lance2
                HandStackArea::new(39, -1), // Pawn2
            ],
            currents: [
                0,  // King1
                20, // Rook1
                18, // Bishop1
                2,  // Gold1
                6,  // Silver1
                10, // Knight1
                14, // Lance1
                22, // Pawn1
                1,  // King2
                21, // Rook2
                19, // Bishop2
                5,  // Gold2
                9,  // Silver2
                13, // Knight2
                17, // Lance2
                39, // Pawn2
            ],
        }
    }
}
impl HandStack {
    /// 駒の先後を ひっくり返してから入れてください。
    pub fn push(&mut self, drop: DoubleFacedPiece, num: PieceNum) {
        let area = &self.areas[drop as usize];
        // 駒台に駒を置くぜ☆(^~^)
        self.items[self.currents[drop as usize] as usize] = num;
        // 位置を増減するぜ☆(^~^)
        self.currents[drop as usize] += area.direction;
    }
    /// ゴミ値は消さないぜ☆(^~^)
    pub fn pop(&mut self, drop: DoubleFacedPiece) -> PieceNum {
        let area = &self.areas[drop as usize];
        // 位置を増減するぜ☆(^~^)
        self.currents[drop as usize] -= area.direction;
        // 駒台の駒をはがすぜ☆(^~^)
        self.items[self.currents[drop as usize] as usize]
    }

    fn last(&self, drop: DoubleFacedPiece) -> Option<PieceNum> {
        let area = &self.areas[drop as usize];
        if area.direction == 1 {
            if area.start < self.currents[drop as usize] {
                Some(self.items[(self.currents[drop as usize] - 1) as usize])
            } else {
                None
            }
        } else {
            if self.currents[drop as usize] < area.start {
                Some(self.items[(self.currents[drop as usize] + 1) as usize])
            } else {
                None
            }
        }
    }

    fn len(&self, drop: DoubleFacedPiece) -> usize {
        let area = &self.areas[drop as usize];
        if area.direction == 1 {
            (self.currents[drop as usize] - area.start) as usize
        } else {
            (area.start - self.currents[drop as usize]) as usize
        }
    }
}
#[derive(Clone)]
pub struct HandStackArea {
    // 開始地点。
    start: isize,
    // 向き。+1, -1。
    direction: isize,
}
impl HandStackArea {
    pub fn new(start: isize, direction: isize) -> Self {
        HandStackArea {
            start: start,
            direction: direction,
        }
    }
}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ こうした方がいいのか……☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 盤上の駒も 自駒スタック、相手駒スタックで 持ちたいぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 リンクリストは 読取が遅いぜ☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 いや、スワップを使うんだぜ☆ 絵で描くと……☆」

20200609dr44a3.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ これを使って、高速分類 ができると思うんだぜ☆」

20200609dr45.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 角を取ったら、そのスペースに 先頭の駒をスワップして……☆」

20200609dr45a1.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 駒を先後反転させて、境界線を1個ずらすだけだぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 駒の背番号が付いているから 位置は覚えておけばいいわけかだぜ☆」

2020-06-09(tue)

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 で、 できれば☆」

  • 盤上の先手の駒
  • 盤上の後手の駒
  • 駒台の先手の駒
  • 駒台の後手の駒

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ の4つに ミーシーに分類したいんだぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 駒を取ったときと、駒を取るのをアンドゥしたときしか 使わないだろう、こんな盤☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 途中局面から始まるときは 初期位置を入れ替えるのを忘れてはいけないぜ☆」

20200609dr46a2.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 背番号付きの駒は、上の80マスのうちの どこかに 重複も漏れもなく 1つだけあるはずだぜ☆」

  • Board
  • King
  • Gold
  • Silver
  • Knight
  • Lance
  • Bishop
  • Rook
  • Pawn

KIFUWARABE_80x100x8_01_Futu.gif
「 ↑ 列挙型どうすんだぜ☆?
この9種類、それぞれ先後があるから18種類だが、これは何なんだぜ☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 盤と 持ち駒を分けない 一貫した何かいいアイデアがあればいいんだけどな☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 番地という概念なら 先後は要らないし、
駒の種類という概念なら 盤は要らないじゃない」

20200609dr47.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 178要素の列挙型1つにすればいいのかだぜ☆?」

KIFUWARABE_80x100x8_01_Futu.gif
「 こんな match文 書きたくないぜ☆!」

2020-06-011(thu)

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 新しいデータ構造 UnifiedAddress と呼ぼうと思うんだが、それに差し替える前に、影響を受ける既存の構造を洗い出そうぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 まず 盤上の位置データ AbsoluteAddress
そして 持ち駒のデータ DoubleFacedPiece
これだけか……☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 UnifiedAddressfrom_absolute_address(), to_absolute_address(), from_double_faced_piece(), to_double_faced_piece() の4つのメソッドを作りましょう。
これで 置き換えが進むわよ」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 あと、テーブル・ジャンプを使って 盤上か、持ち駒かの2択を1ステップで算出できるようにしておきたいぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 じゃあ、しろだぜ☆」

impl UnifiedAddress {
    pub fn from_absolute_address(addr: &AbsoluteAddress2D) -> Self {
        let num = addr.serial_number();
        if 10 < num && num < 20 {
            if let Some(val) = UnifiedAddress::from_usize(num - 10) {
                val
            } else {
                panic!(Beam::trouble("(Err.124) 番地を変換できね☆(^~^)"))
            }
        } else if 20 < num && num < 30 {
            if let Some(val) = UnifiedAddress::from_usize(num - 20) {
                val
            } else {
                panic!(Beam::trouble("(Err.131) 番地を変換できね☆(^~^)"))
            }
        } else if 30 < num && num < 40 {
            if let Some(val) = UnifiedAddress::from_usize(num - 30) {
                val
            } else {
                panic!(Beam::trouble("(Err.137) 番地を変換できね☆(^~^)"))
            }
        } else if 40 < num && num < 50 {
            if let Some(val) = UnifiedAddress::from_usize(num - 40) {
                val
            } else {
                panic!(Beam::trouble("(Err.143) 番地を変換できね☆(^~^)"))
            }
        } else if 50 < num && num < 60 {
            if let Some(val) = UnifiedAddress::from_usize(num - 50) {
                val
            } else {
                panic!(Beam::trouble("(Err.149) 番地を変換できね☆(^~^)"))
            }
        } else if 60 < num && num < 70 {
            if let Some(val) = UnifiedAddress::from_usize(num - 60) {
                val
            } else {
                panic!(Beam::trouble("(Err.155) 番地を変換できね☆(^~^)"))
            }
        } else if 70 < num && num < 80 {
            if let Some(val) = UnifiedAddress::from_usize(num - 70) {
                val
            } else {
                panic!(Beam::trouble("(Err.161) 番地を変換できね☆(^~^)"))
            }
        } else if 80 < num && num < 90 {
            if let Some(val) = UnifiedAddress::from_usize(num - 80) {
                val
            } else {
                panic!(Beam::trouble("(Err.167) 番地を変換できね☆(^~^)"))
            }
        } else if 90 < num && num < 100 {
            if let Some(val) = UnifiedAddress::from_usize(num - 90) {
                val
            } else {
                panic!(Beam::trouble("(Err.173) 番地を変換できね☆(^~^)"))
            }
        } else {
            panic!(Beam::trouble("(Err.176) 番地を変換できね☆(^~^)"))
        }
    }

    pub fn to_absolute_address(self) -> AbsoluteAddress2D {
        if let Some(val) = AbsoluteAddress2D::from_absolute_address(self as usize) {
            val
        } else {
            panic!(Beam::trouble("(Err.135) 番地を変換できね☆(^~^)"))
        }
    }

    pub fn from_double_faced_piece(drop: DoubleFacedPiece) -> UnifiedAddress {
        const map: [UnifiedAddress; 16] = [
            UnifiedAddress::King1,
            UnifiedAddress::Rook1,
            UnifiedAddress::Bishop1,
            UnifiedAddress::Gold1,
            UnifiedAddress::Silver1,
            UnifiedAddress::Knight1,
            UnifiedAddress::Lance1,
            UnifiedAddress::Pawn1,
            UnifiedAddress::King2,
            UnifiedAddress::Rook2,
            UnifiedAddress::Bishop2,
            UnifiedAddress::Gold2,
            UnifiedAddress::Silver2,
            UnifiedAddress::Knight2,
            UnifiedAddress::Lance2,
            UnifiedAddress::Pawn2,
        ];
        map[drop as usize]
    }

    pub fn to_double_faced_piece(self) -> DoubleFacedPiece {
        const map: [DoubleFacedPiece; 16] = [
            DoubleFacedPiece::King1,
            DoubleFacedPiece::Rook1,
            DoubleFacedPiece::Bishop1,
            DoubleFacedPiece::Gold1,
            DoubleFacedPiece::Silver1,
            DoubleFacedPiece::Knight1,
            DoubleFacedPiece::Lance1,
            DoubleFacedPiece::Pawn1,
            DoubleFacedPiece::King2,
            DoubleFacedPiece::Rook2,
            DoubleFacedPiece::Bishop2,
            DoubleFacedPiece::Gold2,
            DoubleFacedPiece::Silver2,
            DoubleFacedPiece::Knight2,
            DoubleFacedPiece::Lance2,
            DoubleFacedPiece::Pawn2,
        ];
        map[self as usize]
    }

    pub fn from_address_pos(addr: &AddressPos) -> Self {
        match addr {
            AddressPos::Board(sq) => UnifiedAddress::from_absolute_address(sq),
            AddressPos::Hand(drop) => UnifiedAddress::from_double_faced_piece(*drop),
        }
    }

    pub fn to_address_pos(self) -> AddressPos {
        const map: [AddressPos; 178] = [
            AddressPos::Board(AbsoluteAddress2D { file: 1, rank: 1 }),
            AddressPos::Board(AbsoluteAddress2D { file: 1, rank: 2 }),
            AddressPos::Board(AbsoluteAddress2D { file: 1, rank: 3 }),
            AddressPos::Board(AbsoluteAddress2D { file: 1, rank: 4 }),
            AddressPos::Board(AbsoluteAddress2D { file: 1, rank: 5 }),
            AddressPos::Board(AbsoluteAddress2D { file: 1, rank: 6 }),
            AddressPos::Board(AbsoluteAddress2D { file: 1, rank: 7 }),
            AddressPos::Board(AbsoluteAddress2D { file: 1, rank: 8 }),
            AddressPos::Board(AbsoluteAddress2D { file: 1, rank: 9 }),
            AddressPos::Board(AbsoluteAddress2D { file: 2, rank: 1 }),
            AddressPos::Board(AbsoluteAddress2D { file: 2, rank: 2 }),
            AddressPos::Board(AbsoluteAddress2D { file: 2, rank: 3 }),
            AddressPos::Board(AbsoluteAddress2D { file: 2, rank: 4 }),
            AddressPos::Board(AbsoluteAddress2D { file: 2, rank: 5 }),
            AddressPos::Board(AbsoluteAddress2D { file: 2, rank: 6 }),
            AddressPos::Board(AbsoluteAddress2D { file: 2, rank: 7 }),
            AddressPos::Board(AbsoluteAddress2D { file: 2, rank: 8 }),
            AddressPos::Board(AbsoluteAddress2D { file: 2, rank: 9 }),
            AddressPos::Board(AbsoluteAddress2D { file: 3, rank: 1 }),
            AddressPos::Board(AbsoluteAddress2D { file: 3, rank: 2 }),
            AddressPos::Board(AbsoluteAddress2D { file: 3, rank: 3 }),
            AddressPos::Board(AbsoluteAddress2D { file: 3, rank: 4 }),
            AddressPos::Board(AbsoluteAddress2D { file: 3, rank: 5 }),
            AddressPos::Board(AbsoluteAddress2D { file: 3, rank: 6 }),
            AddressPos::Board(AbsoluteAddress2D { file: 3, rank: 7 }),
            AddressPos::Board(AbsoluteAddress2D { file: 3, rank: 8 }),
            AddressPos::Board(AbsoluteAddress2D { file: 3, rank: 9 }),
            AddressPos::Board(AbsoluteAddress2D { file: 4, rank: 1 }),
            AddressPos::Board(AbsoluteAddress2D { file: 4, rank: 2 }),
            AddressPos::Board(AbsoluteAddress2D { file: 4, rank: 3 }),
            AddressPos::Board(AbsoluteAddress2D { file: 4, rank: 4 }),
            AddressPos::Board(AbsoluteAddress2D { file: 4, rank: 5 }),
            AddressPos::Board(AbsoluteAddress2D { file: 4, rank: 6 }),
            AddressPos::Board(AbsoluteAddress2D { file: 4, rank: 7 }),
            AddressPos::Board(AbsoluteAddress2D { file: 4, rank: 8 }),
            AddressPos::Board(AbsoluteAddress2D { file: 4, rank: 9 }),
            AddressPos::Board(AbsoluteAddress2D { file: 5, rank: 1 }),
            AddressPos::Board(AbsoluteAddress2D { file: 5, rank: 2 }),
            AddressPos::Board(AbsoluteAddress2D { file: 5, rank: 3 }),
            AddressPos::Board(AbsoluteAddress2D { file: 5, rank: 4 }),
            AddressPos::Board(AbsoluteAddress2D { file: 5, rank: 5 }),
            AddressPos::Board(AbsoluteAddress2D { file: 5, rank: 6 }),
            AddressPos::Board(AbsoluteAddress2D { file: 5, rank: 7 }),
            AddressPos::Board(AbsoluteAddress2D { file: 5, rank: 8 }),
            AddressPos::Board(AbsoluteAddress2D { file: 5, rank: 9 }),
            AddressPos::Board(AbsoluteAddress2D { file: 6, rank: 1 }),
            AddressPos::Board(AbsoluteAddress2D { file: 6, rank: 2 }),
            AddressPos::Board(AbsoluteAddress2D { file: 6, rank: 3 }),
            AddressPos::Board(AbsoluteAddress2D { file: 6, rank: 4 }),
            AddressPos::Board(AbsoluteAddress2D { file: 6, rank: 5 }),
            AddressPos::Board(AbsoluteAddress2D { file: 6, rank: 6 }),
            AddressPos::Board(AbsoluteAddress2D { file: 6, rank: 7 }),
            AddressPos::Board(AbsoluteAddress2D { file: 6, rank: 8 }),
            AddressPos::Board(AbsoluteAddress2D { file: 6, rank: 9 }),
            AddressPos::Board(AbsoluteAddress2D { file: 7, rank: 1 }),
            AddressPos::Board(AbsoluteAddress2D { file: 7, rank: 2 }),
            AddressPos::Board(AbsoluteAddress2D { file: 7, rank: 3 }),
            AddressPos::Board(AbsoluteAddress2D { file: 7, rank: 4 }),
            AddressPos::Board(AbsoluteAddress2D { file: 7, rank: 5 }),
            AddressPos::Board(AbsoluteAddress2D { file: 7, rank: 6 }),
            AddressPos::Board(AbsoluteAddress2D { file: 7, rank: 7 }),
            AddressPos::Board(AbsoluteAddress2D { file: 7, rank: 8 }),
            AddressPos::Board(AbsoluteAddress2D { file: 7, rank: 9 }),
            AddressPos::Board(AbsoluteAddress2D { file: 8, rank: 1 }),
            AddressPos::Board(AbsoluteAddress2D { file: 8, rank: 2 }),
            AddressPos::Board(AbsoluteAddress2D { file: 8, rank: 3 }),
            AddressPos::Board(AbsoluteAddress2D { file: 8, rank: 4 }),
            AddressPos::Board(AbsoluteAddress2D { file: 8, rank: 5 }),
            AddressPos::Board(AbsoluteAddress2D { file: 8, rank: 6 }),
            AddressPos::Board(AbsoluteAddress2D { file: 8, rank: 7 }),
            AddressPos::Board(AbsoluteAddress2D { file: 8, rank: 8 }),
            AddressPos::Board(AbsoluteAddress2D { file: 8, rank: 9 }),
            AddressPos::Board(AbsoluteAddress2D { file: 9, rank: 1 }),
            AddressPos::Board(AbsoluteAddress2D { file: 9, rank: 2 }),
            AddressPos::Board(AbsoluteAddress2D { file: 9, rank: 3 }),
            AddressPos::Board(AbsoluteAddress2D { file: 9, rank: 4 }),
            AddressPos::Board(AbsoluteAddress2D { file: 9, rank: 5 }),
            AddressPos::Board(AbsoluteAddress2D { file: 9, rank: 6 }),
            AddressPos::Board(AbsoluteAddress2D { file: 9, rank: 7 }),
            AddressPos::Board(AbsoluteAddress2D { file: 9, rank: 8 }),
            AddressPos::Board(AbsoluteAddress2D { file: 9, rank: 9 }),
            AddressPos::Board(AbsoluteAddress2D { file: 1, rank: 1 }),
            AddressPos::Board(AbsoluteAddress2D { file: 1, rank: 2 }),
            AddressPos::Board(AbsoluteAddress2D { file: 1, rank: 3 }),
            AddressPos::Board(AbsoluteAddress2D { file: 1, rank: 4 }),
            AddressPos::Board(AbsoluteAddress2D { file: 1, rank: 5 }),
            AddressPos::Board(AbsoluteAddress2D { file: 1, rank: 6 }),
            AddressPos::Board(AbsoluteAddress2D { file: 1, rank: 7 }),
            AddressPos::Board(AbsoluteAddress2D { file: 1, rank: 8 }),
            AddressPos::Board(AbsoluteAddress2D { file: 1, rank: 9 }),
            AddressPos::Board(AbsoluteAddress2D { file: 2, rank: 1 }),
            AddressPos::Board(AbsoluteAddress2D { file: 2, rank: 2 }),
            AddressPos::Board(AbsoluteAddress2D { file: 2, rank: 3 }),
            AddressPos::Board(AbsoluteAddress2D { file: 2, rank: 4 }),
            AddressPos::Board(AbsoluteAddress2D { file: 2, rank: 5 }),
            AddressPos::Board(AbsoluteAddress2D { file: 2, rank: 6 }),
            AddressPos::Board(AbsoluteAddress2D { file: 2, rank: 7 }),
            AddressPos::Board(AbsoluteAddress2D { file: 2, rank: 8 }),
            AddressPos::Board(AbsoluteAddress2D { file: 2, rank: 9 }),
            AddressPos::Board(AbsoluteAddress2D { file: 3, rank: 1 }),
            AddressPos::Board(AbsoluteAddress2D { file: 3, rank: 2 }),
            AddressPos::Board(AbsoluteAddress2D { file: 3, rank: 3 }),
            AddressPos::Board(AbsoluteAddress2D { file: 3, rank: 4 }),
            AddressPos::Board(AbsoluteAddress2D { file: 3, rank: 5 }),
            AddressPos::Board(AbsoluteAddress2D { file: 3, rank: 6 }),
            AddressPos::Board(AbsoluteAddress2D { file: 3, rank: 7 }),
            AddressPos::Board(AbsoluteAddress2D { file: 3, rank: 8 }),
            AddressPos::Board(AbsoluteAddress2D { file: 3, rank: 9 }),
            AddressPos::Board(AbsoluteAddress2D { file: 4, rank: 1 }),
            AddressPos::Board(AbsoluteAddress2D { file: 4, rank: 2 }),
            AddressPos::Board(AbsoluteAddress2D { file: 4, rank: 3 }),
            AddressPos::Board(AbsoluteAddress2D { file: 4, rank: 4 }),
            AddressPos::Board(AbsoluteAddress2D { file: 4, rank: 5 }),
            AddressPos::Board(AbsoluteAddress2D { file: 4, rank: 6 }),
            AddressPos::Board(AbsoluteAddress2D { file: 4, rank: 7 }),
            AddressPos::Board(AbsoluteAddress2D { file: 4, rank: 8 }),
            AddressPos::Board(AbsoluteAddress2D { file: 4, rank: 9 }),
            AddressPos::Board(AbsoluteAddress2D { file: 5, rank: 1 }),
            AddressPos::Board(AbsoluteAddress2D { file: 5, rank: 2 }),
            AddressPos::Board(AbsoluteAddress2D { file: 5, rank: 3 }),
            AddressPos::Board(AbsoluteAddress2D { file: 5, rank: 4 }),
            AddressPos::Board(AbsoluteAddress2D { file: 5, rank: 5 }),
            AddressPos::Board(AbsoluteAddress2D { file: 5, rank: 6 }),
            AddressPos::Board(AbsoluteAddress2D { file: 5, rank: 7 }),
            AddressPos::Board(AbsoluteAddress2D { file: 5, rank: 8 }),
            AddressPos::Board(AbsoluteAddress2D { file: 5, rank: 9 }),
            AddressPos::Board(AbsoluteAddress2D { file: 6, rank: 1 }),
            AddressPos::Board(AbsoluteAddress2D { file: 6, rank: 2 }),
            AddressPos::Board(AbsoluteAddress2D { file: 6, rank: 3 }),
            AddressPos::Board(AbsoluteAddress2D { file: 6, rank: 4 }),
            AddressPos::Board(AbsoluteAddress2D { file: 6, rank: 5 }),
            AddressPos::Board(AbsoluteAddress2D { file: 6, rank: 6 }),
            AddressPos::Board(AbsoluteAddress2D { file: 6, rank: 7 }),
            AddressPos::Board(AbsoluteAddress2D { file: 6, rank: 8 }),
            AddressPos::Board(AbsoluteAddress2D { file: 6, rank: 9 }),
            AddressPos::Board(AbsoluteAddress2D { file: 7, rank: 1 }),
            AddressPos::Board(AbsoluteAddress2D { file: 7, rank: 2 }),
            AddressPos::Board(AbsoluteAddress2D { file: 7, rank: 3 }),
            AddressPos::Board(AbsoluteAddress2D { file: 7, rank: 4 }),
            AddressPos::Board(AbsoluteAddress2D { file: 7, rank: 5 }),
            AddressPos::Board(AbsoluteAddress2D { file: 7, rank: 6 }),
            AddressPos::Board(AbsoluteAddress2D { file: 7, rank: 7 }),
            AddressPos::Board(AbsoluteAddress2D { file: 7, rank: 8 }),
            AddressPos::Board(AbsoluteAddress2D { file: 7, rank: 9 }),
            AddressPos::Board(AbsoluteAddress2D { file: 8, rank: 1 }),
            AddressPos::Board(AbsoluteAddress2D { file: 8, rank: 2 }),
            AddressPos::Board(AbsoluteAddress2D { file: 8, rank: 3 }),
            AddressPos::Board(AbsoluteAddress2D { file: 8, rank: 4 }),
            AddressPos::Board(AbsoluteAddress2D { file: 8, rank: 5 }),
            AddressPos::Board(AbsoluteAddress2D { file: 8, rank: 6 }),
            AddressPos::Board(AbsoluteAddress2D { file: 8, rank: 7 }),
            AddressPos::Board(AbsoluteAddress2D { file: 8, rank: 8 }),
            AddressPos::Board(AbsoluteAddress2D { file: 8, rank: 9 }),
            AddressPos::Board(AbsoluteAddress2D { file: 9, rank: 1 }),
            AddressPos::Board(AbsoluteAddress2D { file: 9, rank: 2 }),
            AddressPos::Board(AbsoluteAddress2D { file: 9, rank: 3 }),
            AddressPos::Board(AbsoluteAddress2D { file: 9, rank: 4 }),
            AddressPos::Board(AbsoluteAddress2D { file: 9, rank: 5 }),
            AddressPos::Board(AbsoluteAddress2D { file: 9, rank: 6 }),
            AddressPos::Board(AbsoluteAddress2D { file: 9, rank: 7 }),
            AddressPos::Board(AbsoluteAddress2D { file: 9, rank: 8 }),
            AddressPos::Board(AbsoluteAddress2D { file: 9, rank: 9 }),
            AddressPos::Hand(DoubleFacedPiece::King1),
            AddressPos::Hand(DoubleFacedPiece::Rook1),
            AddressPos::Hand(DoubleFacedPiece::Bishop1),
            AddressPos::Hand(DoubleFacedPiece::Gold1),
            AddressPos::Hand(DoubleFacedPiece::Silver1),
            AddressPos::Hand(DoubleFacedPiece::Knight1),
            AddressPos::Hand(DoubleFacedPiece::Lance1),
            AddressPos::Hand(DoubleFacedPiece::Pawn1),
            AddressPos::Hand(DoubleFacedPiece::King2),
            AddressPos::Hand(DoubleFacedPiece::Rook2),
            AddressPos::Hand(DoubleFacedPiece::Bishop2),
            AddressPos::Hand(DoubleFacedPiece::Gold2),
            AddressPos::Hand(DoubleFacedPiece::Silver2),
            AddressPos::Hand(DoubleFacedPiece::Knight2),
            AddressPos::Hand(DoubleFacedPiece::Lance2),
            AddressPos::Hand(DoubleFacedPiece::Pawn2),
        ];
        map[self as usize]
    }
}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ とりあえず 雑に作って こんな感じで☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 盤上の升にも 先後 が付いてしまうんだが、要らん時どうしよ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 要らんとき というのはないのよ。必ず付けるのよ」

2020-06-014(sun)

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 2日ほど大改造した結果、NPS が下がったんで止めたぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 どんまい☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 理由としては Movement構造体の使用メモリが大きくなると メモリを使いきってしまうんだろう☆
Movement構造体の使用メモリを大きくしないことは 鉄則 だぜ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 さっき書いた記事 要らなかったんじゃない!」

    fn ff1(&self) -> bool {
        let fa = |x| 2 < x;
        let fb = |y| y > 2;
        self.ff2(3, fa) || self.ff2(3, fb)
    }
    fn ff2<F1>(&self, x: u8, fc: F1) -> bool
    where
        F1: Fn(u8) -> bool,
    {
        fc(x)
    }

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ ところで Rust で関数の引数にクロージャを渡す構文を メモ書きしておくぜ☆ あとで使う☆」

20200614dr52a2.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 将棋盤を150マスにする大改造を行うぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 わらう☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 Movement は座標を止め、 dx, dy にする☆
盤と駒台もシームレス☆
駒台は貧乏鉛筆スタック☆
何が起こるかは分からん☆
面白いからする☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 dy は -9 ~ 9、dx は -14 ~ 14 になるけど、何ビット?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 dy の要素数は 19、dx の要素数は 29 だから、 32 に収まる感じだな☆ 6bit が 2つで 12 bit だぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 じゃあ 16bit だろ☆ 移動元と移動先を持っていても 16 bit だろ☆ 変わらん☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 変わらんのか……☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 -138 ~ 138 だと 1byte に収まらないし……☆ あと 21 ほど縮まらないかだぜ☆?」

KIFUWARABE_80x100x8_01_Futu.gif
「 枠を使ったらダメなのかだぜ☆?」

20200614dr53a2.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 いけそう……☆ 平行移動だけなら signed byte でいけるのでは☆?」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 将棋所の符号は出せるの?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 棋譜とは別で☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 キャプチャーは 3bit だろ☆ 平行移動は 8bit だろ☆」

20200614dr54a5.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 この駒の背番号が ビットボードより有利かどうかが 分岐点だよな☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 動かす駒の背番号も情報として要るだろ☆ 7bit だぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ぬぎぎ……☆」

20200614dr55a2.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 とりあえず 少し進めて 今日は おわり☆」

2020-06-015(mon)

20200615dr56.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 駒の背番号だけだと、成りとか先後とか 見えないんだな☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 データベースに入っているはずだからな☆ データベース無いけど☆」

20200615dr56a1.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 データベースの中身が改造前だが、ここから改造だぜ、気が重いぜ……☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 持ち駒の B* とか P* を止めて、 10a12a にするのよね? 」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 いかにも……☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 持ち駒の位置は 駒の種類で持っているのに、どうやって マスの座標 に差し替えるんだぜ☆? またバイパスか☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 そうすると思う……☆」

/// 盤上と、駒台で 共通しないものを並列にします。
#[derive(Copy, Clone, Debug)]
pub enum FireAddress {
    Board(AbsoluteAddress2D),
    Hand(DoubleFacedPieceType),
}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 今、こうなっているが……☆」

/// 盤上と、駒台で 共通しないものを並列にします。
#[derive(Copy, Clone, Debug)]
pub enum FireAddress {
    Board(AbsoluteAddress2D),
    Hand(DoubleFacedPieceType, AbsoluteAddress2D),
}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 現行を維持しつつ、Boardと、Handの違いを埋めていく準備をしようぜ☆?」

KIFUWARABE_80x100x8_01_Futu.gif
「 盤上と 駒台を 同じアルゴリズムに融合することなんて できないと思うけどな☆」

        match self {
            FireAddress::Board(sq) => {
                ///
            }
            FireAddress::Hand(drop_type, _) => {
                ///
            }
        },

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 新しく追加した部分は _ (アンダースコア) で埋めておけば エラーにもならないしな☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 型だけで指定できればいいのに、マス座標を いちいち指定しなければいけないの?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 そうだぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 なんだかなあ……☆」

#[derive(Copy, Clone, Debug)]
pub struct HandAddress {
    pub old: DoubleFacedPieceType,
    pub new_: AbsoluteAddress2D,
}
impl HandAddress {
    pub fn new(old: DoubleFacedPieceType, new_: AbsoluteAddress2D) -> Self {
        HandAddress {
            old: old,
            new_: new_,
        }
    }
}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 タプルにするより 構造体にした方が応用が利いたかだぜ……☆」

<書きかけ>

何度でもクリック!→

むずでょ

光速のアカウント凍結されちゃったんで……。ゲームプログラムを独習中なんだぜ☆電王戦IIに出た棋士もコンピューターもみんな好きだぜ☆▲(パソコン将棋)WCSC29一次予選36位、SDT5予選42位▲(パソコン囲碁)AI竜星戦予選16位

Crieitは個人で開発中です。 興味がある方は是非記事の投稿をお願いします! どんな軽い内容でも嬉しいです。
なぜCrieitを作ろうと思ったか

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください!

ボードとは?

むずでょ の最近の記事