brainfuck でオセロを書く(後編)
初めに
今回は Brainf*ck Advent Calendar 2019
の 13
日目の記事です。
adventar.org
前日の記事はこちら
明日の記事はこちら
目次
概要
今回は、brainfuck
オセロ後編ということで、実際に盤面処理をするコードを紹介していきます。
前編がまだの方はこちらを見てください。
コードは長くなりがちなので、折りたたんでいます。
無限ループ
終了判定は行わず、無限ループで対応してます。
以下は、位置調整と無限ループの外枠のコードです。
(クリックで展開)
>>> //Move to PlacePointer [-]+ [//位置の入力により石を置く(メインループ) /* * メインループのコード */ [-]+//繰り返しフラグを立てる ]//End of 石を置くメインループ
次の項目から、メインループの中身について書いていきます。
入力の読み取り
概要
置きたい場所の位置の入力を受け取ります。
y
座標 x
座標 Enter(\n)
の 3
文字を受け取ります。
4c
の様に入力し、 それを配列にアクセスするための index
に変換します。
配列の本体は 8x8
ではなく、10x10
となっているため、 index
は y * 10 + x
で計算されます。
また、無効な入力に対するエラーチェックは行っていません。
コード
(クリックで展開)
[-]>[-]>[-]<< // メモリクリア ++++++[->++++++++<]> // 一つ目の入力のオフセットを設定 >, // 一つ目の入力を得る <[->-<]> // オフセットを引く <<++++[->++++<]>[-<++++++>]< // 二つ目の入力のオフセットを設定 >, // 一つ目の入力を得る <[->-<]> // オフセットを引く >[-<<++++++++++>>]<[-<+>]< // 番地を計算する(Add{ buf2*10_buf1 } ) >,[-]< // 改行コードを読み取る
_
かどうかの確認
概要
置く目標の場所が _
でなければ、コマは必然的に置けないので、その確認をしています。
コード
(クリックで展開)
// *****'_'かどうかの確認****** >[-]>[-]<<[->>+<<]>>[-<+<+>>]<< //位置メモリのbuf0をbuf1にコピー >[-< <<< <<< [<<<] >+< >>>[>>>]>>> > ]< //位置メモリのbuf1を始点メモリのbuf1に移動 <<< <<< [<<<] //始点メモリにポインタを移動 >[-<+>]< // buf0に値を移動 [ - > >>> [+>>>]+ [<<<]< ] > >>> [>>>]< //ターゲットの位置に移動 >++++++++[->++++++++++++<]>-<< // make '_' to buf2 (use buf1) [->+>-<<]>[-<+>]< // Cal buf2 minus val (use buf1) >[-]> [[-]+<]<[>]< // cast to Bool (1 or 0) >[-]>- [[+]+<]<[>]< // Get Not >>[-< <<< [<<<] >+ < >>> [>>>] < >>]<< //始点ポインタに結果の移動 > <<< [<<<]< //始点ポインタに移動 >> //置けるかどうかの判定結果が格納されているbuf2に移動 [ [-] /** 置ける時の処理 **/ ]
コマをひっくり返す
_
かどうかの確認しかしていませんが、以降は、実際にひっくり返してみて、ひっくり返せたコマが存在するかどうかで、実際にひっくり返せたかどうかを判断します。
サーチ方向の確保
概要
オセロはひっくり返せるかどうかの判断を 8
方向に行わないといけません。
ここで、方向を index
の変化量としてとらえると、
-11,-10,-9,-1,1,9,10,11
の 8
方向になります。
しかし、正負を同一のコードで行うのは大変なため、1,9,10,11
の 4
方向に対してそれぞれ正負で判定を行います。
以降は正方向のコードを例に説明していきます。
コード
(クリックで展開)
// *** 方向の値を代入 << //位置調整 >>> [>[[-]>>>]>>] >>> >>> >>> >>> //方向ポインタに移動 [-]+ > // 1をセット [-]+++++++++ > // 9をセット [-]++++++++++ > // 10をセット [-]+++++++++++> // 11をセット // ***方向の値の代入終了 < [ /*** 判定ループ ***/ ]
初めて相手の色が出なくなったマスに移動
概要
その方向のひっくり返す駒があるかどうかは、
相手の駒が出なくなるまで、移動を行い、
最終的なマスが、自分の色である必要があります。
加えて裁定でも一回は相手の色である必要があります。
以下のコードは、相手の駒が出なくなるまでの移動を行うコードです。
コードの説明は、めんどくさいので省略します。
コメント読んでください。
コード
(クリックで展開)
[<]<< <<< <<< //位置メモリに移動 >[-]>[-]<<[->>+<<]>>[-<+<+>>]<< //位置メモリのbuf0をbuf1にコピー >[-< <<< <<<[<<<]>+< >>>[>>>]>>> >]< //位置メモリのbuf1を始点メモリのbuf1に移動 <<< <<< [<<<] //始点メモリにポインタを移動 >[-<+>]< // buf0に値を移動 [ - > >>> [+>>>]+ [<<<]< ] //ターゲットの位置をセット (初期ポインタに移動) >>+ //初期ポインタのフラグ管理(buf2)に移動 [ //相手の色の石が出なくなるまで繰り返す [-] //フラグ値をゼロにする << >>> >>>[>>>] >>> >>> >>> >>>[>]< //方向ポインタの末尾に移動 [->+>+<<]>>[-<<+>>]>+ //対象の方向値をコピーする [<<-<[<]>[<<<]<<<[<<<] >+< >>>[>>>] >>> >>> >>> >>>[>]>] //対象の方向値を開始ポインタに移動 <<[<]>[<<<]<<<[<<<] //初期ポインタに移動 >[-<+>]< // buf0に値を移動 [ - > >>> [+>>>]+ [<<<]< ] > >>> [>>>]< //ターゲットの位置に移動 >[-]>[-]<<[->+>+<<]>[-<+>] //ターゲットの値をbuf2にコピー <<< [<<<]< //始点ポインタに移動 >>> [>>>] >>> >>> >>> //相手色ポインタに移動 >[-]>[-]<<[->>+<<]>>[-<+<+>>] //相手色の値をbuf1にコピー <[-<[<<<] <<< [<<<] >+< >>> [>>>] >>> >>> >>> >] //相手色の値を始点ポインタのbuf1に移動 <[<<<] <<< [<<<] //始点ポインタに移動 >[-<+>]< // buf0に値を移動 [-> >>> [>>>] > - < <<< [<<<] < ] //相手色とターゲットマスの色の差をターゲットポインタのbuf2に格納 > >>> [>>>] > //ターゲットポインタのbuf2に移動 [[-]<]<[>>]<[>>+<] //Notをとる(buf0がTrueでbuf1がfalseであることを利用)(buf1に移動する) >[ < <<< [<<<] >+< >>> [>>>] ]<[>] //演算結果を始点ポインタのbuf2にコピー(buf1に移動) <<< [<<<] //始点ポインタbuf1に移動 > //始点ポインタbuf2に移動 ]
ストップ位置が自分の色かの判定
概要
ストップ位置が自分の色かの判定を行います。
良く見るとわかるのですが、ここ以降は、ほぼコピペ見たいなコードが複数回出てきます。
コード
(クリックで展開)
// ***ストップ位置が自分の色かの判定*** << //始点ポインタbuf0に移動 > >>> [>>>]< //ターゲットの位置(buf0)に移動 >[-]>[-]<<[->+>+<<]>[-<+>] //ターゲットの値をbuf2にコピー(buf1に移動) <<< [<<<]< //始点ポインタに移動 >>> [>>>] >>> >>> //自分色ポインタに移動 >[-]>[-]<<[->>+<<]>>[-<+<+>>] //自分色の値をbuf1にコピー <[-<[<<<] <<< [<<<] >+< >>> [>>>] >>> >>> >] //相手色の値を始点ポインタのbuf1に移動 <[<<<] <<< [<<<] //始点ポインタに移動 >[-<+>]< // buf0に値を移動 [-> >>> [>>>] > - < <<< [<<<] < ] //相手色とターゲットマスの色の差をターゲットポインタのbuf2に格納 > >>> [>>>] > //ターゲットポインタのbuf2に移動 [[-]<]<[>>]<[>>+<] //Notをとる(buf0がTrueでbuf1がfalseであることを利用)(buf1に移動する) >[[-] < <<< [<<<] >+< >>> [>>>] ]<[>] //演算結果を始点ポインタのbuf2にコピー(buf1に移動) <<< [<<<] //始点ポインタbuf1に移動 // ***End of ストップ位置が自分の色かの判定***
実際にひっくりかえせる石のフラグを立てる
概要
実際にひっくりかすのは後でやるので、ここではひっくり返すフラグを立てておきます。
コード
(クリックで展開)
> //始点ポインタのbuf2に移動 [ //ひっくり返せるなら [-] //フラグ値をゼロにする >[>>[+>>>]>] <<< [<<<] >> //ひっくり返すフラグをインクリメント ] << >>> >>>[>>>] >>> >>> >>> >>>[>]< //方向ポインタの末尾に移動 [->+>+<<]>>[-<<+>>]>+ //対象の方向値をコピーする [<<-<[<]>[<<<]<<<[<<<] >+< >>>[>>>] >>> >>> >>> >>>[>]>] //対象の方向値を開始ポインタに移動 <<[<]>[<<<]<<<[<<<] //初期ポインタに移動 >[-<+>]< // buf0に値を移動 [ - > >>> [->>>] <<< <<< [<<<]< ] > >>> [>>>]< //ターゲットの位置に移動 > +[[-]<<<] //buf1のデータを初期化 >>[>>[->>>]>] <<< [<<<]> //ひっくり返すフラグをデクリメントし正規のひっくり返る位置のみフラグを立てる >>[>>[+>>>]>] //ひっくり返すフラグをインクリメントし、終点ポインタに移動 >>> >>> >>> >>> [>]< //方向ポインタの最終ポインタに移動
負方向の判定
概要
負方向も同様に判定します。
コード
(クリックで展開)
/************** * 負方向の判定 * **************/ [<]<< <<< <<< //位置メモリに移動 >[-]>[-]<<[->>+<<]>>[-<+<+>>]<< //位置メモリのbuf0をbuf1にコピー >[-< <<< <<< [<<<] >+< >>>[>>>]>>> > ]< //位置メモリのbuf1を始点メモリのbuf1に移動 <<< <<< [<<<] //始点メモリにポインタを移動 >[-<+>]< // buf0に値を移動 [ - > >>> [+>>>]+ [<<<]< ] //ターゲットの位置をセット (初期ポインタに移動) >>+ //初期ポインタのフラグ管理(buf2)に移動 [ //相手の色の石が出なくなるまで繰り返す [-] //フラグ値をゼロにする << >>> >>>[>>>] >>> >>> >>> >>>[>]< //方向ポインタの末尾に移動 [->+>+<<]>>[-<<+>>]>+ //対象の方向値をコピーする [<<-<[<]>[<<<]<<<[<<<] >+< >>>[>>>] >>> >>> >>> >>>[>]>] //対象の方向値を開始ポインタに移動 <<[<]>[<<<]<<<[<<<] //初期ポインタに移動 >[-<+>]< // buf0に値を移動 [ - > >>> [->>>]<<< <<< [<<<]< ] > >>> [>>>]< //ターゲットの位置に移動 >[-]>[-]<<[->+>+<<]>[-<+>] //ターゲットの値をbuf2にコピー <<< [<<<]< //始点ポインタに移動 >>> [>>>] >>> >>> >>> //相手色ポインタに移動 >[-]>[-]<<[->>+<<]>>[-<+<+>>] //相手色の値をbuf1にコピー <[-<[<<<] <<< [<<<] >+< >>> [>>>] >>> >>> >>> >] //相手色の値を始点ポインタのbuf1に移動 <[<<<] <<< [<<<] //始点ポインタに移動 >[-<+>]< // buf0に値を移動 [-> >>> [>>>] > - < <<< [<<<] < ] //相手色とターゲットマスの色の差をターゲットポインタのbuf2に格納 > >>> [>>>] > //ターゲットポインタのbuf2に移動 [[-]<]<[>>]<[>>+<] //Notをとる(buf0がTrueでbuf1がfalseであることを利用)(buf1に移動する) >[ < <<< [<<<] >+< >>> [>>>] ]<[>] //演算結果を始点ポインタのbuf2にコピー(buf1に移動) <<< [<<<] //始点ポインタbuf1に移動 > //始点ポインタbuf2に移動 ] // ***ストップ位置が自分の色かの判定*** << //始点ポインタbuf0に移動 > >>> [>>>]< //ターゲットの位置(buf0)に移動 >[-]>[-]<<[->+>+<<]>[-<+>] //ターゲットの値をbuf2にコピー(buf1に移動) <<< [<<<]< //始点ポインタに移動 >>> [>>>] >>> >>> //自分色ポインタに移動 >[-]>[-]<<[->>+<<]>>[-<+<+>>] //自分色の値をbuf1にコピー <[-<[<<<] <<< [<<<] >+< >>> [>>>] >>> >>> >] //相手色の値を始点ポインタのbuf1に移動 <[<<<] <<< [<<<] //始点ポインタに移動 >[-<+>]< // buf0に値を移動 [-> >>> [>>>] > - < <<< [<<<] < ] //相手色とターゲットマスの色の差をターゲットポインタのbuf2に格納 > >>> [>>>] > //ターゲットポインタのbuf2に移動 [[-]<]<[>>]<[>>+<] //Notをとる(buf0がTrueでbuf1がfalseであることを利用)(buf1に移動する) >[[-] < <<< [<<<] >+< >>> [>>>] ]<[>] //演算結果を始点ポインタのbuf2にコピー(buf1に移動) <<< [<<<] //始点ポインタbuf1に移動 // ***End of ストップ位置が自分の色かの判定*** > //始点ポインタのbuf2に移動 [ //ひっくり返せるなら [-] //フラグ値をゼロにする >[>>[+>>>]>] <<< [<<<] >> //ひっくり返すフラグをインクリメント ] << > >>> [>>>] //ターゲットの位置に移動 +[[-]<<<] //buf1のデータを初期化 >>[>>[->>>]>] <<< [<<<] > //ひっくり返すフラグをデクリメントし正規のひっくり返る位置のみフラグを立てる >>[>>[+>>>]>] //ひっくり返すフラグをインクリメントし、終点ポインタに移動 >>> >>> >>> >>> [>]< //方向ポインタの最終ポインタに移動 >>>[-]<<< //フラグに使ってたメモリをクリア [-]<
ひっくり返す駒が存在するかどうか
概要
ひっくり返す駒にフラグを立てているので、フラグが立っている駒があるかどうかを判断します。
コード
(クリックで展開)
> <<< [<<<] //終点ポインタに移動 <<< [< //ひっくり返すフラグが立っている場所を探す [ //フラグが立っていれば <<[<<<] //初期ポインタに移動 >+ //buf1に結果を格納 > //調整のためbuf2に移動 ] << ] //終点は初期ポインタ
駒をひっくり返す
概要
実際にひっくりかえせた場合は、ひっくり返します。
この時、ひっくり返せたかどうかは、後でも使用するので、もう一度再格納します。
コード
(クリックで展開)
> [ //ひっくり返せるとき(buf1) [-] < >>> [>>>] //終点ポインタに移動 >>> //配置位置ポインタに移動 >[-]>[-]<<[->>+<<]>>[-<+<+>>]<< //位置メモリのbuf0をbuf1にコピー >[-< <<< <<< [<<<] >+< >>>[>>>]>>> > ]< //位置メモリのbuf1を始点メモリのbuf1に移動 <<< <<< [<<<] //始点メモリにポインタを移動 >[-<+>]< // buf0に値を移動 [ - > >>> [+>>>]+ [<<<]< ] //ターゲットの位置をセット (初期ポインタに移動) > >>> [>>>] //ターゲット位置に移動 > [-]+ //ターゲット位置のひっくり返すフラグを立てる <+[[-]<<<] < //ターゲット位置情報をクリアしつつ初期位置に戻る >>> [>>[<<[-]+>]>[>]< ] //ひっくり返すフラグがある位置の色情報を1にする > //終点ポインタに移動 >>> >>> //自分の色ポインタに移動 [->>+<<] >> [-<+<+>>] //buf1にコピー <- // 値コピー用の数字を1引いておく(既に1は加算されているため) [- //自分の色をひっくり返る位置にコピー < <<< <<< <<< [<<<] //始点ポインタに移動 >>> [>>[<<+>]>[>]< ] //ひっくり返すフラグがある位置の色情報をインクリメント > //終点ポインタに移動 >>> >>> > //自分の色ポインタのbuf1に移動 ] < <<< <<< <<< [<<<] > //始点ポインタBuf1に移動 [-] >[-]+< //buf2にひっくり返せたことを格納する ] >[[-]<+>]< //buf2(ひっくり返したか)をbuf1に移動 >[-] //条件分岐を合わせるためにbuf2に移動後クリア
置けた場合の処理
概要
駒を置けた場合は、盤面の再描画を行い、手番をプレーヤの石の色を入れ替えます。
コード
(クリックで展開)
[-]+ //buf2にTrueを代入 < //buf1に移動 [ //ひっくり返えしたとき // ****手番プレーヤーを入れ替える < >>> [>>>] >>> >>> >>> //相手プレイヤーポインタに移動 [-<<+>>] //手番プレイヤーポインタのbuf1にデータを移動 <<< //手番プレイヤーポインタに移動 [->>>+<<<] //相手プレイヤーポインタにデータを移動 >[-<+>] //相手プレイヤーポインタのbuf1をbuf0に移動 < //相手プレイヤーポインタに移動 <<< <<< <<< <<< [<<<] //始点ポインタに移動 >>>[>[-]>[-]++++++++[-<++++>]<.[-]<.>>>]//Print Stage >>> [>>>] >>>>>>> //文字列メモリの先頭に移動 < //文字メモリの先頭のひとつ前に戻る < ] //End of 返えしたとき
置けなかった場合の処理
概要
駒を置けなかった場合は、エラーメッセージを出します。
コード
(クリックで展開)
> [ //ひっくり返せなかったとき << >>> [>>>] //終点ポインタに移動 >>> [>>>] >>>>>>> //文字列メモリの先頭に移動 [>]> [>]> [>]> //3(4)文目に移動 [.>] //print(can't put here) <[<] <[<] <[<] <[<] //文字メモリの先頭のひとつ前に戻る ]
共通メッセージの表示
概要
置けたか置けないかにかかわず、次の入力を促すメッセージを出力します。
コード
(クリックで展開)
// ****ポインタ=文字メモリの先頭のひとつ前 共通メッセージの描画 >[.>] //Print(It's ') <[<]<<<<<< <<< <<< . >>> >>> >>>>>>>[>]//Print(手番石) >[.>] //Print(' turn_) >[.>] //Print(Prease Input place_) <. //改行を出力 [<]<[<]<[<] <<< <<< <<< <<< <<< //位置ポインタに移動
全体のコード
オセロの全体のコードを載せておきます。実際に動かしたい場合はこのコードをコピペしてください。
(クリックで展開)
>>>++++++++[->>>++++++++++++>>>++++++<<< <<<]>>>- //ptr ==2 {0}{0}{95}{32} // **** Make '_' pattern *** [ - >>> >>> >>> >>> >>> >>> >>> >>> >>> >>>+>>>+>>>+>>>+>>>+>>>+>>>+>>>+>>> >>> //1 >>>+>>>+>>>+>>>+>>>+>>>+>>>+>>>+>>> >>> //2 >>>+>>>+>>>+>>>+>>>+>>>+>>>+>>>+>>> >>> //3 >>>+>>>+>>>+>>>+>>>+>>>+>>>+>>>+>>> >>> //4 >>>+>>>+>>>+>>>+>>>+>>>+>>>+>>>+>>> >>> //5 >>>+>>>+>>>+>>>+>>>+>>>+>>>+>>>+>>> >>> //6 >>>+>>>+>>>+>>>+>>>+>>>+>>>+>>>+>>> >>> //7 >>>+>>>+>>>+>>>+>>>+>>>+>>>+>>>+>>> >>> //8 <<< <<< [[<<<]<<< <<< <<<] <<< <<< <<< <<< <<< <<< ] // **** End of Make '_' pattern *** >>> // **** Make '1'to'9' pattern *** >>> >>> >>> >>> >>> >>> >>> >>>+//1 [>>>]>>>++//2 [>>>]>>>+++//3 [>>>]>>>++++//4 [>>>]>>>+++++//5zz [>>>]>>>++++++//6 [>>>]>>>+++++++//7 [>>>]>>>++++++++//8 <<< <<< [[<<<]<<<] <<< <<< <<< <<< <<< <<< [- >>> >>> >>> >>> >>> >>> >>> >>> [+[>>>]>>>] <<< <<< [[<<<]<<<] <<< <<< <<< <<< <<< <<< ] // **** End of Make '1'to'9' pattern *** <<< <<< <<< // **** Make 'A'to'H' pattern*** >>>++++++++[-<<<++++++++>>>] >>>+ //A >>>++ //B >>>+++ //C >>>++++ //D >>>+++++ //E >>>++++++ //F >>>+++++++ //G >>>++++++++ //H [<<<]<<< [- >>> >>>[+>>>] <<<[<<<]<<< ] // **** End of Make 'A'to'H' pattern*** // **** Make first ' ' *** ++++++++[->>>++++<<<] // **** End of Make first ' ' *** >>> // **** Make '\n' pattern (Ignore last2 line '\n'*** >>>[<<<++++++++++[>>>]>>>] // **** End of Make '\n' pattern *** // ****Make Last Line ' ' pattern*** ++++++++[-<<<++++>>>]<<< [ - >>>+>>>+>>>+>>>+>>>+>>>+>>>+>>>+>>>+ <<< <<< <<< <<< <<< <<< <<< <<< <<< ] ++++++++++ [>>>]++++++++++ // ****End of Make Last Line ' ' pattern*** // **** Set first stones **** [<<<] // Back to fiest Pointer // **set 'o' to 4D >++++++++++[-<++++>]<++++ //Set 4D [ - > >>> [+>>>]+ [<<<]< ] > >>> [>>>]< [-]//Zero Zet ++++[->+++++<]>++[-<+++++>]<+ // Set 'o' > <<< [[-]<<<]< //Reset // **set 'o' to 5E >++++++++++[-<+++++>]<+++++ //Set 5E [ - > >>> [+>>>]+ [<<<]< ] > >>> [>>>]< [-]//Zero Zet ++++[->+++++<]>++[-<+++++>]<+ // Set 'o' > <<< [[-]<<<]< //Reset // **set 'x' to 5D >++++++++++[-<+++++>]<++++ //Set 5D [ - > >>> [+>>>]+ [<<<]< ] > >>> [>>>]< [-]//Zero Zet ++++[->++++++<]>[-<+++++>]< // Set 'x' > <<< [[-]<<<]< //Reset // **set 'o' to 5E >++++++++++[-<++++>]<+++++ //Set 4E [ - > >>> [+>>>]+ [<<<]< ] > >>> [>>>]< [-]//Zero Zet ++++[->++++++<]>[-<+++++>]< // Set 'x' > <<< [[-]<<<]< //Reset >>> [ >>> ] // 末尾に移動 // **** End of Set first stones **** >>> //位置ポインタに移動 + //ダミーの設置 >>> //Move to TrunPlayerStone Pointer // **** Set StornColor to TrunStonePointer **** [-]++++[->++++++<]>[-<+++++>]< // Set 'x' >>> [-]++++[->+++++<]>++[-<+++++>]<+ // Set 'o' >>> // **** End of Set first stones **** // **** Set const chars **** >>>> >>> //方向メモリの確保 // ************Set sering "It's '_' turn_\n\0" (length:16) ※_の部分は0が代入されている >>>>>>>>>>>>>>>+++++++++++++++++++ [<<<<<<<<<<<<<<<+++>++++++>++>++++++>+>++>>++>+>++++++>++++++>++++++>+++++>++>>-] <++++++++++<++++++++<+++++++++++++++<<+++<++<+++++++++++++<+<<+<+++++++++++++<+<+<++<++++++++++++++++[>]>[>] > // **************Set sering "Plese input place_\n\0"(length:20) >>>>>>>>>>>>>>>>>>>++++++++++++++++ [<<<<<<<<<<<<<<<<<<<+++++>++++++>++++++>+++++++>++++++>++>++++++>++++++>+++++++>+++++++>+++++++>++>+++++++>++++++>++++++>++++++>++++++>++>>-] <++++++++++<++++++++++++++<+++++<+++<+<++++++++++++<<<++++<+++++<<++++++++++++++<+++++++++<<+++++<+++<+++++<++++++++++++<[>] > // *********************Set sering "Can't put here_\n\0" (length:17) >>>>>>>>>>>>>>>>++++++++++++++++ [<<<<<<<<<<<<<<<<++++>++++++>++++++>++>+++++++>++>+++++++>+++++++>+++++++>++>++++++>++++++>+++++++>++++++>++>>-] <++++++++++<++++++++++++++<+++++<++<+++++<++++++++<<++++<+++++<<<++++<+++++++<++++++++++++++<+<+++[>] <[<]<[<]<[<]<[<] << <<<<< << // **** End of Set const chars **** <<< <<< <<< <<< //Move to Last pointer of field // ************************End of setUp // *** Print stage and text *** [<<<] >>>[>[-]>[-]++++++++[-<++++>]<.[-]<.>>>]<<<//Print Stage >>> >>> >>> >>> >>> >>>>>>> [.>]//Print(It's ') <[<]<<<<<< <<< <<< . >>> >>> >>>>>>>[>]//Print(手番石) >[.>]//Print(' turn_) >[.>]//Print(Prease Input place_) <[<]<[<]<[<] <<<<<< <<< <<< <<< <<< //Move to Last pointer of field // *** End of Print stage and text *** // ********************************************* // ********************************************* >>> //Move to PlacePointer [-]+ [//位置の入力により石を置く(メインループ) [-]>[-]>[-]<< // メモリクリア ++++++[->++++++++<]> // 一つ目の入力のオフセットを設定 >, // 一つ目の入力を得る <[->-<]> // オフセットを引く <<++++[->++++<]>[-<++++++>]< // 二つ目の入力のオフセットを設定 >, // 一つ目の入力を得る <[->-<]> // オフセットを引く >[-<<++++++++++>>]<[-<+>]< // 番地を計算する(Add{ buf2*10_buf1 } ) >,[-]< // 改行コードを読み取る // ******************************************** // *****'_'かどうかの確認****** >[-]>[-]<<[->>+<<]>>[-<+<+>>]<< //位置メモリのbuf0をbuf1にコピー >[-< <<< <<< [<<<] >+< >>>[>>>]>>> > ]< //位置メモリのbuf1を始点メモリのbuf1に移動 <<< <<< [<<<] //始点メモリにポインタを移動 >[-<+>]< // buf0に値を移動 [ - > >>> [+>>>]+ [<<<]< ] > >>> [>>>]< //ターゲットの位置に移動 >++++++++[->++++++++++++<]>-<< // make '_' to buf2 (use buf1) [->+>-<<]>[-<+>]< // Cal buf2 minus val (use buf1) >[-]> [[-]+<]<[>]< // cast to Bool (1 or 0) >[-]>- [[+]+<]<[>]< // Get Not >>[-< <<< [<<<] >+ < >>> [>>>] < >>]<< //始点ポインタに結果の移動 > <<< [<<<]< //始点ポインタに移動 >> //置けるかどうかの判定結果が格納されているbuf2に移動 [ //もし置けるのであれば [-] // *** 方向の値を代入 << //位置調整 >>> [>[[-]>>>]>>] >>> >>> >>> >>> //方向ポインタに移動 [-]+ > // 1をセット [-]+++++++++ > // 9をセット [-]++++++++++ > // 10をセット [-]+++++++++++> // 11をセット // ***方向の値の代入終了 < [ //すべての方向に関してのサーチ /************** * 正方向の判定 * **************/ [<]<< <<< <<< //位置メモリに移動 >[-]>[-]<<[->>+<<]>>[-<+<+>>]<< //位置メモリのbuf0をbuf1にコピー >[-< <<< <<<[<<<]>+< >>>[>>>]>>> >]< //位置メモリのbuf1を始点メモリのbuf1に移動 <<< <<< [<<<] //始点メモリにポインタを移動 >[-<+>]< // buf0に値を移動 [ - > >>> [+>>>]+ [<<<]< ] //ターゲットの位置をセット (初期ポインタに移動) >>+ //初期ポインタのフラグ管理(buf2)に移動 [ //相手の色の石が出なくなるまで繰り返す [-] //フラグ値をゼロにする << >>> >>>[>>>] >>> >>> >>> >>>[>]< //方向ポインタの末尾に移動 [->+>+<<]>>[-<<+>>]>+ //対象の方向値をコピーする [<<-<[<]>[<<<]<<<[<<<] >+< >>>[>>>] >>> >>> >>> >>>[>]>] //対象の方向値を開始ポインタに移動 <<[<]>[<<<]<<<[<<<] //初期ポインタに移動 >[-<+>]< // buf0に値を移動 [ - > >>> [+>>>]+ [<<<]< ] > >>> [>>>]< //ターゲットの位置に移動 >[-]>[-]<<[->+>+<<]>[-<+>] //ターゲットの値をbuf2にコピー <<< [<<<]< //始点ポインタに移動 >>> [>>>] >>> >>> >>> //相手色ポインタに移動 >[-]>[-]<<[->>+<<]>>[-<+<+>>] //相手色の値をbuf1にコピー <[-<[<<<] <<< [<<<] >+< >>> [>>>] >>> >>> >>> >] //相手色の値を始点ポインタのbuf1に移動 <[<<<] <<< [<<<] //始点ポインタに移動 >[-<+>]< // buf0に値を移動 [-> >>> [>>>] > - < <<< [<<<] < ] //相手色とターゲットマスの色の差をターゲットポインタのbuf2に格納 > >>> [>>>] > //ターゲットポインタのbuf2に移動 [[-]<]<[>>]<[>>+<] //Notをとる(buf0がTrueでbuf1がfalseであることを利用)(buf1に移動する) >[ < <<< [<<<] >+< >>> [>>>] ]<[>] //演算結果を始点ポインタのbuf2にコピー(buf1に移動) <<< [<<<] //始点ポインタbuf1に移動 > //始点ポインタbuf2に移動 ] // ***ストップ位置が自分の色かの判定*** << //始点ポインタbuf0に移動 > >>> [>>>]< //ターゲットの位置(buf0)に移動 >[-]>[-]<<[->+>+<<]>[-<+>] //ターゲットの値をbuf2にコピー(buf1に移動) <<< [<<<]< //始点ポインタに移動 >>> [>>>] >>> >>> //自分色ポインタに移動 >[-]>[-]<<[->>+<<]>>[-<+<+>>] //自分色の値をbuf1にコピー <[-<[<<<] <<< [<<<] >+< >>> [>>>] >>> >>> >] //相手色の値を始点ポインタのbuf1に移動 <[<<<] <<< [<<<] //始点ポインタに移動 >[-<+>]< // buf0に値を移動 [-> >>> [>>>] > - < <<< [<<<] < ] //相手色とターゲットマスの色の差をターゲットポインタのbuf2に格納 > >>> [>>>] > //ターゲットポインタのbuf2に移動 [[-]<]<[>>]<[>>+<] //Notをとる(buf0がTrueでbuf1がfalseであることを利用)(buf1に移動する) >[[-] < <<< [<<<] >+< >>> [>>>] ]<[>] //演算結果を始点ポインタのbuf2にコピー(buf1に移動) <<< [<<<] //始点ポインタbuf1に移動 // ***End of ストップ位置が自分の色かの判定*** > //始点ポインタのbuf2に移動 [ //ひっくり返せるなら [-] //フラグ値をゼロにする >[>>[+>>>]>] <<< [<<<] >> //ひっくり返すフラグをインクリメント ] << >>> >>>[>>>] >>> >>> >>> >>>[>]< //方向ポインタの末尾に移動 [->+>+<<]>>[-<<+>>]>+ //対象の方向値をコピーする [<<-<[<]>[<<<]<<<[<<<] >+< >>>[>>>] >>> >>> >>> >>>[>]>] //対象の方向値を開始ポインタに移動 <<[<]>[<<<]<<<[<<<] //初期ポインタに移動 >[-<+>]< // buf0に値を移動 [ - > >>> [->>>] <<< <<< [<<<]< ] > >>> [>>>]< //ターゲットの位置に移動 > +[[-]<<<] //buf1のデータを初期化 >>[>>[->>>]>] <<< [<<<]> //ひっくり返すフラグをデクリメントし正規のひっくり返る位置のみフラグを立てる >>[>>[+>>>]>] //ひっくり返すフラグをインクリメントし、終点ポインタに移動 >>> >>> >>> >>> [>]< //方向ポインタの最終ポインタに移動 /************** * 負方向の判定 * **************/ [<]<< <<< <<< //位置メモリに移動 >[-]>[-]<<[->>+<<]>>[-<+<+>>]<< //位置メモリのbuf0をbuf1にコピー >[-< <<< <<< [<<<] >+< >>>[>>>]>>> > ]< //位置メモリのbuf1を始点メモリのbuf1に移動 <<< <<< [<<<] //始点メモリにポインタを移動 >[-<+>]< // buf0に値を移動 [ - > >>> [+>>>]+ [<<<]< ] //ターゲットの位置をセット (初期ポインタに移動) >>+ //初期ポインタのフラグ管理(buf2)に移動 [ //相手の色の石が出なくなるまで繰り返す [-] //フラグ値をゼロにする << >>> >>>[>>>] >>> >>> >>> >>>[>]< //方向ポインタの末尾に移動 [->+>+<<]>>[-<<+>>]>+ //対象の方向値をコピーする [<<-<[<]>[<<<]<<<[<<<] >+< >>>[>>>] >>> >>> >>> >>>[>]>] //対象の方向値を開始ポインタに移動 <<[<]>[<<<]<<<[<<<] //初期ポインタに移動 >[-<+>]< // buf0に値を移動 [ - > >>> [->>>]<<< <<< [<<<]< ] > >>> [>>>]< //ターゲットの位置に移動 >[-]>[-]<<[->+>+<<]>[-<+>] //ターゲットの値をbuf2にコピー <<< [<<<]< //始点ポインタに移動 >>> [>>>] >>> >>> >>> //相手色ポインタに移動 >[-]>[-]<<[->>+<<]>>[-<+<+>>] //相手色の値をbuf1にコピー <[-<[<<<] <<< [<<<] >+< >>> [>>>] >>> >>> >>> >] //相手色の値を始点ポインタのbuf1に移動 <[<<<] <<< [<<<] //始点ポインタに移動 >[-<+>]< // buf0に値を移動 [-> >>> [>>>] > - < <<< [<<<] < ] //相手色とターゲットマスの色の差をターゲットポインタのbuf2に格納 > >>> [>>>] > //ターゲットポインタのbuf2に移動 [[-]<]<[>>]<[>>+<] //Notをとる(buf0がTrueでbuf1がfalseであることを利用)(buf1に移動する) >[ < <<< [<<<] >+< >>> [>>>] ]<[>] //演算結果を始点ポインタのbuf2にコピー(buf1に移動) <<< [<<<] //始点ポインタbuf1に移動 > //始点ポインタbuf2に移動 ] // ***ストップ位置が自分の色かの判定*** << //始点ポインタbuf0に移動 > >>> [>>>]< //ターゲットの位置(buf0)に移動 >[-]>[-]<<[->+>+<<]>[-<+>] //ターゲットの値をbuf2にコピー(buf1に移動) <<< [<<<]< //始点ポインタに移動 >>> [>>>] >>> >>> //自分色ポインタに移動 >[-]>[-]<<[->>+<<]>>[-<+<+>>] //自分色の値をbuf1にコピー <[-<[<<<] <<< [<<<] >+< >>> [>>>] >>> >>> >] //相手色の値を始点ポインタのbuf1に移動 <[<<<] <<< [<<<] //始点ポインタに移動 >[-<+>]< // buf0に値を移動 [-> >>> [>>>] > - < <<< [<<<] < ] //相手色とターゲットマスの色の差をターゲットポインタのbuf2に格納 > >>> [>>>] > //ターゲットポインタのbuf2に移動 [[-]<]<[>>]<[>>+<] //Notをとる(buf0がTrueでbuf1がfalseであることを利用)(buf1に移動する) >[[-] < <<< [<<<] >+< >>> [>>>] ]<[>] //演算結果を始点ポインタのbuf2にコピー(buf1に移動) <<< [<<<] //始点ポインタbuf1に移動 // ***End of ストップ位置が自分の色かの判定*** > //始点ポインタのbuf2に移動 [ //ひっくり返せるなら [-] //フラグ値をゼロにする >[>>[+>>>]>] <<< [<<<] >> //ひっくり返すフラグをインクリメント ] << > >>> [>>>] //ターゲットの位置に移動 +[[-]<<<] //buf1のデータを初期化 >>[>>[->>>]>] <<< [<<<] > //ひっくり返すフラグをデクリメントし正規のひっくり返る位置のみフラグを立てる >>[>>[+>>>]>] //ひっくり返すフラグをインクリメントし、終点ポインタに移動 >>> >>> >>> >>> [>]< //方向ポインタの最終ポインタに移動 >>>[-]<<< //フラグに使ってたメモリをクリア [-]< ]//End of すべての方向へのサーチ > <<< [<<<] //終点ポインタに移動 <<< [< //ひっくり返すフラグが立っている場所を探す [ //フラグが立っていれば <<[<<<] //初期ポインタに移動 >+ //buf1に結果を格納 > //調整のためbuf2に移動 ] << ] //終点は初期ポインタ > [ //ひっくり返せるとき(buf1) [-] < >>> [>>>] //終点ポインタに移動 >>> //配置位置ポインタに移動 >[-]>[-]<<[->>+<<]>>[-<+<+>>]<< //位置メモリのbuf0をbuf1にコピー >[-< <<< <<< [<<<] >+< >>>[>>>]>>> > ]< //位置メモリのbuf1を始点メモリのbuf1に移動 <<< <<< [<<<] //始点メモリにポインタを移動 >[-<+>]< // buf0に値を移動 [ - > >>> [+>>>]+ [<<<]< ] //ターゲットの位置をセット (初期ポインタに移動) > >>> [>>>] //ターゲット位置に移動 > [-]+ //ターゲット位置のひっくり返すフラグを立てる <+[[-]<<<] < //ターゲット位置情報をクリアしつつ初期位置に戻る >>> [>>[<<[-]+>]>[>]< ] //ひっくり返すフラグがある位置の色情報を1にする > //終点ポインタに移動 >>> >>> //自分の色ポインタに移動 [->>+<<] >> [-<+<+>>] //buf1にコピー <- // 値コピー用の数字を1引いておく(既に1は加算されているため) [- //自分の色をひっくり返る位置にコピー < <<< <<< <<< [<<<] //始点ポインタに移動 >>> [>>[<<+>]>[>]< ] //ひっくり返すフラグがある位置の色情報をインクリメント > //終点ポインタに移動 >>> >>> > //自分の色ポインタのbuf1に移動 ] < <<< <<< <<< [<<<] > //始点ポインタBuf1に移動 [-] >[-]+<//buf2にひっくり返せたことを格納する ] >[[-]<+>]<//buf2(ひっくり返したか)をbuf1に移動 >[-]//条件分岐を合わせるためにbuf2に移動後クリア ]//End of [-]+//buf2にTrueを代入 <//buf1に移動 [//ひっくり返えしたとき // ****手番プレーヤーを入れ替える < >>> [>>>] >>> >>> >>> //相手プレイヤーポインタに移動 [-<<+>>]//手番プレイヤーポインタのbuf1にデータを移動 <<< //手番プレイヤーポインタに移動 [->>>+<<<] //相手プレイヤーポインタにデータを移動 >[-<+>] //相手プレイヤーポインタのbuf1をbuf0に移動 < //相手プレイヤーポインタに移動 <<< <<< <<< <<< [<<<] //始点ポインタに移動 //盤面の再描画 >>>[>[-]>[-]++++++++[-<++++>]<.[-]<.>>>]//Print Stage //終点ポインタに移動している >>> [>>>] >>>>>>> //文字列メモリの先頭に移動 <//文字メモリの先頭のひとつ前に戻る < ]//End of 返えしたとき > [//ひっくり返せなかったとき << >>> [>>>] //終点ポインタに移動 >>> [>>>] >>>>>>> //文字列メモリの先頭に移動 [>]> [>]> [>]> //3(4)文目に移動 [.>]//print(can't put here) <[<] <[<] <[<] <[<] //文字メモリの先頭のひとつ前に戻る ] // ****ポインタ=文字メモリの先頭のひとつ前 共通メッセージの描画 >[.>]//Print(It's ') <[<]<<<<<< <<< <<< . >>> >>> >>>>>>>[>]//Print(手番石) >[.>]//Print(' turn_) >[.>]//Print(Prease Input place_) <. //改行を出力 [<]<[<]<[<] <<< <<< <<< <<< <<< //位置ポインタに移動 [-]//位置ポインタの値を初期化 +//繰り返しフラグを立てる ]//End of 石を置くメインループ
あとがき
途中から説明を放棄していますが、どこまで詳しく説明すればいいのかわからないのと、実際に動かしたほうが理解が早いと思ってるので、省略しました。
実はこのコードは数年前に書いたコードなので、自分でもわからないというのも大きいです。
また、結構助長な部分と蚊もありますが、これだけの規模なので、実行速度よりも、可読性と取っています。
あと、純粋に、当時の自分があまり brainfuck
をきれいに書けなかったのもあると思います。
それでも、ここまでコメントを残していたのはいい点だとほめたいですね。
質問とかあれば、ここにコメントするか、Twitterでリプもらえれば反応すると思います。
今回の記事の内容じゃなくても全然大丈夫なので気軽に質問ください。
それでは良い、brainfuck
ライフを。