go btime 40000 wtime 50000 binc 10000 winc 10000
「 ↑ 例えば フィッシャー・クロック・ルールのときは このように送られてくるぜ☆
上の例をパースすることを考えてみようぜ☆?」
go btime {} wtime {} binc {} winc {}
「 ↑ スペースが複数個入ってきたら 考え方は破綻してしまうが、仮に 1つ としよう☆」
'go '
「 ↑ コマンドラインの先頭が go
だったらトリガーだぜ☆」
'go btime ' | 9 characters.
g o b t i m e
0 1 2 3 4 5 6 7 8 9
「 ↑ インデックスは Python でも使われている伝統で、両端と 文字間に 数が振ってあると思えだぜ☆」
「 で、次は 数かどうかを調べるより、 次に出てくる半角スペースがどこかを調べるんだぜ☆」
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
「 もし 40000
という数が途中にあれば、インデックスは 15 まで飛ばせだぜ☆
このとき、 9
と 13
の数を覚えておいて、あとで s[9:13]
とすれば 文字列 40000
が取れるという仕組みだぜ☆」
「 プログラムを ごりごり 書くより、枠組みに はまった方がマシか……☆」
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(),
}
}
}
「 ↑ 正規表現を使う事の 可読性の向上の方が メリットかな……☆」
「 これで 時間切れ が見えるようになったので、早指しさせることができるぜ☆」
「 ↑ 王手されていることが分かっていても、どう逃げれば 王手を解除できるのか それも むずかしいぜ☆」
「 ↑ 盤上に 相手の駒の利き というものを持ってないといけないよな☆」
「 ↑ 空き王手されたり、玉が利きに飛び込んだりしないように しないといけないぜ☆」
「 ↑ 持ち駒を置けるなら、長い利きの途中に 駒を置いて 相手の利きを途切れさせることもできるぜ☆
もちろん 移動合い でもOK☆」
「 利きボードを まず作ってみましょう!
利きの中に玉がいて、かつ、利きの外に逃げる手があれば、優先してそれを選ぶようにしましょう!」
「 ↑ いろんな盤を試したが、現在も試行錯誤中で、これは わたしの計算力を活かせる わたしに扱いやすい形だぜ☆ 111マスある☆」
「 その前に、この盤も けっこう使いづらいんで、使いやすくしようぜ☆?」
「 ↑ 駒の置き方には2種類ある☆ これを1つに まとめたいと思うんだぜ☆」
「 先手玉と、後手玉の位置を 調べるコードが入っているかどうかだぜ☆
あとは、駒に背番号を付けるコードが入ってるかどうかも違うな☆」
「 その他に、利きボード を設定するタイミングなんだが、
駒を置いたときか、それより前の 指し手生成 をしたときか☆?」
「 駒を持ち上げた時に、その駒の利きが盤上から消えて、長い利きがあれば それが伸びることがあるぜ☆
駒を置いた時に、その駒の利きが盤上に出てきて、長い利きがあれば それが切れることがあるぜ☆」
「 できれば 長い利きを止めている というフラグが欲しいぜ☆
キャッパーとか☆」
「 長い利きの駒は 飛飛角角香香香香 の8枚しかないのだから全検索したら?」
「 その8回を減らしたいぜ☆ 長い利きをリンクと考えれば、飛車なら4か所にリンクしている駒と考えることができるぜ☆」
「 持ち駒を駒台に置く動きも ごちゃごちゃ してるから 書き直すぜ☆」
「 振っている数 を統一したら ……、集合の意味がなくなるかだぜ☆」
「 お父んが読んだソースコードは 駒の背番号制ではなかったからな☆ 駒に背番号を付ける仕組みを改善しているのだろう☆」
/// 盤に駒を置く
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
}
「 ↑ 盤と駒台の駒の移動は この4つの操作に絞り込んだぜ☆」
「 その前に 香車にバグがあるみたいなんで そっちも直したいぜ☆」
「 ミスを見つけたぜ☆ 同じ名前の違う変数を指定していたんだぜ☆」
「 ↑ 先後逆にして 指せばいいんだぜ☆ あっ、利きが ついてこねっ☆!」
「 180°回転するか、しないかを選べるように 折りこめだぜ☆」
「 しかし わたしの do_move
は イケてないが……☆」
「 棋譜のつくり方、指し手のデータの持ち方から 見直せばいけるかもしれないな☆ 移動と指し手を分けてるのは 棋譜、指し手のデータ なんで☆」
「 すごい改造になるが、ストックフィッシュ系から離れる 面白い課題ではあるぜ☆」
/// 棋譜にも使うので、取った駒の情報を記憶しておくんだぜ☆(^~^)
/// 投了なら これを使わず、None にしろだぜ☆(^~^)
///
/// Copy: 配列の要素の初期化時に使う☆(^~^)
#[derive(Clone, Copy)]
pub struct Movement {
// 移動元升。Dropのときは None だぜ☆(^~^)
pub source: Option<AbsoluteAddress>,
// 移動先升。
pub destination: AbsoluteAddress,
// 移動後に成るなら真
pub promote: bool,
// 打の場合、打った駒種類
pub drop: Option<PhysicalPieceType>,
}
「 ↑ ここの、 source
と drop
を区別せずに ひとつ にすればいいんだぜ☆
Bonanza や、大樹の枝 とは違う作りになるな☆」
「 drop を PhysicalPieceType型ではなく、 PhysicalPiece型 にすればいけるわよ」
「 慣性の法則に似てるよな☆ 先手か後手は、消すのではなく、残す☆」
「 手番は 棋譜を見て 奇数か偶数かで 先後を見ているが、
指し手ひとつ ひとつに持たせた方がいいのか☆ 変な話しだぜ☆」
「 AbsoluteAddress と PhysicalPieceType を共有する新しい型を 作ってしまえだぜ☆」
「 AddressTypeOnPosition みたいな名前にすればいいか……☆」
「 push_to_board
で None も駒も設定していたが、 push_to_board
と、 remove_from_board
の2つに分けていいだろうか☆?」
「 将棋盤にセットするとき、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,
}
「 ↑ こんな風に改造☆ NPS 下がった気がするが、まだ このデータ構造を活かした実装にしてないしな☆」
「 成るとか、打つとか言わず、機械的動作に落とし込んでくれだぜ☆」
「 成るのは 駒の表裏をひっくり返すのよ。
打つのは 駒台にある駒を 盤上に置くのよ」
「 指し手に書かれているところに戻ることが 確定 なら、
戻るように移動するためにやった180°回転は 要らないんじゃない?」
「 人間の棋譜の符号ではなく、コンピューター将棋の棋譜の符号だから そうなるが……☆
アンドゥのときは 移動先と 移動元を入れ替えて 移動する、ということをすれば 同じことだな☆」
「 前後同型のアルゴリズムにこだわる必要はあるの?
プログラムに、逆順に実行するって 無いけど」
「 大筋では do_move も undo_move も同型で、移動元と移動先だけが ひっくり返っていると
見れるんじゃないか☆?」
「 ↑ おや、どこかでミスったかだぜ☆? また明日 見直そうぜ☆」
「 棋譜の指し手を 投了に 始まり 投了 に終わるようにすれば
前後同型になるわよ」
「 指すときは 指し手生成 なのに、戻すときは 指し手読取 なのは 違いを吸収できるものなのだろうか☆?」
「 じゃあ、 do_move
と undo_move
というより、 read_move
と、 read_move_in_reverse
なのかだぜ☆?」
「 ↑ 指し手を 棋譜に入れるとか、消さないとか ここに あるのは おかしいぜ☆ 消しておくぜ☆」
「 クローンしなくていいかどうか クローンを外して試してみるか……☆」
「 棋譜には 取った駒が何かは書いてないんだぜ☆
動かしてみて 初めて 取った駒が分かるんだぜ☆ 駒を取ったら、棋譜に補足情報として記録するぜ☆
これは アンドゥ するために必要だぜ☆」
「 じゃあ read_move
、 read_move_in_reverse
は間違いだろ☆
do_move
、 do_move_in_reverse
に変えろだぜ☆」
「 駒を打つとき、どっちの駒台にある駒が減るかを判定するために使っているぜ☆」
「 USIの棋譜の符号には 駒を打つときの先後は 書いてないのねぇ」
「 USIの思想と わたしたちの思想は 合ってないんじゃないの?」
「 わたしたちの思想に合った 棋譜オブジェクトを 作成しましょう」
「 ↑ 取られることになる駒は 先に棋譜に記録しておいたぜ☆」
#[derive(Clone, Copy)]
pub enum AddressTypeOnPosition {
// 盤上の移動なら、移動元升。
Move(AbsoluteAddress),
// 打の場合、打った駒種類
Drop(PhysicalPieceType),
// 未設定ならこれ。
Busy,
}
#[derive(Clone, Copy)]
pub enum AddressTypeOnPosition {
// 盤上の移動なら、移動元升。
Move(AbsoluteAddress),
// 打の場合、打った駒種類
Drop(PhysicalPiece),
// 未設定ならこれ。
Busy,
}
(カタカタカタ)
「 do_move
で局面ハッシュを更新していて、なんで undo_move
で局面ハッシュを更新してないんだぜ☆?」
「 ハッシュの差分更新は作ってなかったのか……☆ また明日だぜ☆」
「 指し手の source には 駒台があるが、 destination は 駒台が無いからな☆
駒台に置くという操作がない☆
アシンメトリックだぜ☆」
「 前に リバーシブル指し手 を作ろうとしてたじゃない。あれをやればいいのよ」
「 リバーシブル指し手 への改造は進めているが、取った駒の扱いが よく見えないぜ☆」
「 というのも、『取った駒は歩』という記録の仕方をしてるだろ☆
これが『2四にある駒が、後手駒台の歩の位置へ』という記録の仕方をしてくれていたら
リバースさせやすいんだぜ☆
『後手駒台の歩が、2四へ』みたいな☆」
「 取った駒が 盤の上を移動するケースがあるのか☆?
『2四にある駒が、8四へ』みたいな☆」
#[derive(Clone, Copy)]
pub struct Movement {
/// 移動元マス。
pub source: AddressPos,
/// 移動先マス。リバーシブルに作りたいので、駒台にも指せる。
pub destination: AddressPos,
/// 移動後に成るなら真
pub promote: bool,
/// 取ることになる駒
pub captured: Option<Piece>,
}
「 ↑ このキャプチャーを、ソースとデスティネーションにするかだな☆」
「 指し手に 駒の種類を書かなければ、指し手から 将棋のルールを切り離せるが……☆
より 機械的動作 にできる……、やってみることは 方向性に沿ってるな……☆」
「 プログラム中に pop と push の2ステップに分かれているのは 設計図と異なるな……☆
swap の1回で できないものかだぜ☆」
「 移動先で、駒があったときに コリジョンするぜ☆ 3点同時スワップでもあれば別だが……☆」
「 あれっ☆? 3点同時スワップ では トグルにならね……☆」
「 せめて 盤上に 空中マスA、B を用意して スワップ できない?
今 111マス あるんでしょ。 113マス にするのよ」
「 スカイ・マスを作ってみたんだが むずかしい……、ローカル変数の方が コードが見やすいぜ☆」
「 取られた駒を 移動元、起動先にするか どうかだっけ……☆」
「 盤上の移動は マスが分かればいいんだが、駒台の移動は その駒の種類が分からないといけないだろ☆
棋譜だけで できないんだよな☆」
「 PieceMeaning の定義を変えたらどうだぜ☆?」
「 駒台の上の何を打ったのかを表すのは 駒の種類だろ☆
駒台の上において 駒の種類は 番地だぜ☆」
「 現に USI でも 金を打つときは G*
だぜ☆ G*
は番地なんだぜ☆」
「 盤の上のマスを1つ選べば、駒は1つに絞れるんだが、
持ち駒は 絞れないの、非対称だよな☆ どうするかな☆」
「 ↑ Piece は必ず、GameTable の中にあり、その外には出ないもととする☆
よくある言い方をすれば、 Piece をカプセル化するんだぜ☆」
「 じゃあ 盤や 駒台の上にあるのも 駒の背番号 にすればいいんじゃない?」
「 ↑ いままで Piece は どこかにある、という構造だったが……☆」
「 ↑ 駒が40個ならんでいて、その駒は 場所の方を指差している、風に改造するんだぜ☆
ただ、これを そのまま改造するのはむずかしいので……☆」
「 ↑ 古い経路はバイパス(迂回路)として残しつつ、間に Num を置く、という手術を行うぜ☆
うまく 間に置けてから バイパスを取り除くぜ☆」
「 ↑ 今までは 番地 というリストに駒が紐づいていたが……☆」
「 ↑ Num(駒の背番号)は、タグ(荷札)みたいなものとしよう☆」
「 住所録というのは、氏名に住所が紐づいているのではないか☆?
上の図では AddressList の住所と氏名が 逆だぜ☆」
「 ↑ 住所に 氏名が紐づいているから、 PostList か……☆?」
「 ↑ そういう意味では 現状 AddressList なんだぜ☆」
「 ↑ だから 今回は 無駄に PostList をまず作るんだぜ☆」
「 いや、現状が PostList なのでは☆? 将棋盤は PostList だぜ☆」
「 ↑ PieceList 1つはさめば いいわけかだぜ☆」
「 Piece を色んなところに使ってるのか、更新が うまくいかないぜ☆」
「 なんだ……☆ 盤とか 駒台とかに 今乗っているのは あとで捨てようと思ってるゴミかだぜ……☆」
「 そのゴミは 捨ててはいけないわよ。まだ バイパスを通すのだから」
「 どっかに置いとくか……☆ old_pieces みたいな変数とか☆」
「 将棋の盤上は マス で 1つの駒を選べるが、
駒台の駒は、駒番号でしか 1つの駒を選べないぜ☆」
「 ↑ じゃあ 駒台の上は、玉2枚を除く38枚のための専用スペースを設けておくべきかだぜ☆?」
「 ↑ 将棋の駒台専用の スタック を作るというのも手だぜ☆」
「 入り口は 固定位置だし、駒番号は……、駒を取り合ったら変わるのでは☆?」
「 出すのと入れるのとを きっちりやれば、取り出したい駒は 入り口にいるはずだぜ☆」
/// 駒台だぜ☆(^~^)これ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
}
}
「 あれっ☆? この構造が1つあれば、2つ分の駒台も要らないぜ……☆」
「 駒って、先後反転してから入れて、取り出すときは、どっちだぜ☆?
自分が指すときと、アンドゥするときがあるだろ☆」
「 ドゥの時は ひっくり返して入れて、ひっくり返さず取り出せだぜ☆
アンドゥのときは、ひっくり返さず入れて、ひっくり返して取り出せだぜ☆」
「 一元化されたデータを 先後反転 させているのではなく、
先後反転したインスタンスを作っては 変数に入れる、ということにしていて 状態の一貫性が欠けているぜ☆
直さないとな……☆」
「 棋譜に記録してる取った駒、くるくる回ってんじゃないか☆?」
「 どうも どういじっても不具合が出るな……☆
push の回数より pop の回数の方が多いみたいなんだぜ☆」
「 成り駒かどうか、先後はどちらか、ぴったり合わせないといけないようだ……、持ち駒なのに……☆」
「 いくつか 整えたが まだ 動きがおかしい☆ 分からん……☆」
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
}
「 ↑ さらに、プッシュでは 配列に要素を入れてからカーソルを進めるが、
ポップでは カーソルを戻してから 配列の要素を出すのだった☆」
「 持ち駒は、カウンティング・セマフォにした方がいいのでは……、という気もしてきているぜ☆」
「 昨日の実装は カウンティング・セマフォになってるんだぜ☆」
「 インデックスをよく見て 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()
}
*/
}
/// 駒台だぜ☆(^~^)これ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,
}
}
}
「 盤上の駒も 自駒スタック、相手駒スタックで 持ちたいぜ☆」
「 ↑ 角を取ったら、そのスペースに 先頭の駒をスワップして……☆」
「 駒の背番号が付いているから 位置は覚えておけばいいわけかだぜ☆」
「 駒を取ったときと、駒を取るのをアンドゥしたときしか 使わないだろう、こんな盤☆」
「 途中局面から始まるときは 初期位置を入れ替えるのを忘れてはいけないぜ☆」
「 ↑ 背番号付きの駒は、上の80マスのうちの どこかに 重複も漏れもなく 1つだけあるはずだぜ☆」
「 ↑ 列挙型どうすんだぜ☆?
この9種類、それぞれ先後があるから18種類だが、これは何なんだぜ☆?」
「 盤と 持ち駒を分けない 一貫した何かいいアイデアがあればいいんだけどな☆」
「 番地という概念なら 先後は要らないし、
駒の種類という概念なら 盤は要らないじゃない」
「 新しいデータ構造 UnifiedAddress
と呼ぼうと思うんだが、それに差し替える前に、影響を受ける既存の構造を洗い出そうぜ☆」
「 まず 盤上の位置データ AbsoluteAddress
☆
そして 持ち駒のデータ DoubleFacedPiece
☆
これだけか……☆」
「 UnifiedAddress
に from_absolute_address()
, to_absolute_address()
, from_double_faced_piece()
, to_double_faced_piece()
の4つのメソッドを作りましょう。
これで 置き換えが進むわよ」
「 あと、テーブル・ジャンプを使って 盤上か、持ち駒かの2択を1ステップで算出できるようにしておきたいぜ☆」
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]
}
}
「 盤上の升にも 先後 が付いてしまうんだが、要らん時どうしよ☆」
「 2日ほど大改造した結果、NPS が下がったんで止めたぜ☆」
「 理由としては Movement構造体の使用メモリが大きくなると メモリを使いきってしまうんだろう☆
Movement構造体の使用メモリを大きくしないことは 鉄則 だぜ☆」
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)
}
「 ↑ ところで Rust で関数の引数にクロージャを渡す構文を メモ書きしておくぜ☆ あとで使う☆」
「 Movement は座標を止め、 dx, dy にする☆
盤と駒台もシームレス☆
駒台は貧乏鉛筆スタック☆
何が起こるかは分からん☆
面白いからする☆」
「 dy は -9 ~ 9、dx は -14 ~ 14 になるけど、何ビット?」
「 dy の要素数は 19、dx の要素数は 29 だから、 32 に収まる感じだな☆ 6bit が 2つで 12 bit だぜ☆」
「 じゃあ 16bit だろ☆ 移動元と移動先を持っていても 16 bit だろ☆ 変わらん☆」
「 -138 ~ 138 だと 1byte に収まらないし……☆ あと 21 ほど縮まらないかだぜ☆?」
「 いけそう……☆ 平行移動だけなら signed byte でいけるのでは☆?」
「 キャプチャーは 3bit だろ☆ 平行移動は 8bit だろ☆」
「 この駒の背番号が ビットボードより有利かどうかが 分岐点だよな☆」
「 動かす駒の背番号も情報として要るだろ☆ 7bit だぜ☆」
「 駒の背番号だけだと、成りとか先後とか 見えないんだな☆」
「 データベースに入っているはずだからな☆ データベース無いけど☆」
「 データベースの中身が改造前だが、ここから改造だぜ、気が重いぜ……☆」
「 持ち駒の B*
とか P*
を止めて、 10a
と 12a
にするのよね? 」
「 持ち駒の位置は 駒の種類で持っているのに、どうやって マスの座標 に差し替えるんだぜ☆? またバイパスか☆?」
/// 盤上と、駒台で 共通しないものを並列にします。
#[derive(Copy, Clone, Debug)]
pub enum FireAddress {
Board(AbsoluteAddress2D),
Hand(DoubleFacedPieceType),
}
/// 盤上と、駒台で 共通しないものを並列にします。
#[derive(Copy, Clone, Debug)]
pub enum FireAddress {
Board(AbsoluteAddress2D),
Hand(DoubleFacedPieceType, AbsoluteAddress2D),
}
「 ↑ 現行を維持しつつ、Boardと、Handの違いを埋めていく準備をしようぜ☆?」
「 盤上と 駒台を 同じアルゴリズムに融合することなんて できないと思うけどな☆」
match self {
FireAddress::Board(sq) => {
///
}
FireAddress::Hand(drop_type, _) => {
///
}
},
「 ↑ 新しく追加した部分は _
(アンダースコア) で埋めておけば エラーにもならないしな☆」
「 型だけで指定できればいいのに、マス座標を いちいち指定しなければいけないの?」
#[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_,
}
}
}
「 タプルにするより 構造体にした方が応用が利いたかだぜ……☆」
<書きかけ>
Crieitは個人で開発中です。
興味がある方は是非記事の投稿をお願いします! どんな軽い内容でも嬉しいです。
なぜCrieitを作ろうと思ったか
また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!
こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください!