三流プログラマの戯言

プログラミング初心者が気になったことを書き綴るだけ。主にc#

brainfuck でオセロを書く(前編)

初めに

今回は Brainf*ck Advent Calendar 201910 日目の記事です。 adventar.org

前日の記事はこちら
明日の記事はこちら


目次


概要

今回、カレンダーが空いていたので適当な記事で埋めました。
本当は、最後まで書こうと思ったのですが、
記事が長くなりそうなのと、疲れてきたのと、時間がないのとで、今回は前編ということで、
初期セットアップと盤面の表示のコードだけ書いて逃げようと思います。

続きは明日かもしくはもっと先に公開する予定です。


メモリ配置

コードの説明に入る前に、どういうメモリの取り方をしているかを説明します。

盤面情報

盤面を管理するために 配列を用いて管理します。また、ランダムアクセスをすることを考慮しないといけません。
ランダムアクセスに関しては、以前記事を書きました。
今回は、アクセスの速さと一時メモリの確保も兼ねて、1 要素 3 セルで要素を確保しています。
今回は、盤面の状態として、黒を x 白を o 何も置かれてない状態を _ とすることにします。

また、出力のことや、境界値判定のことも考えて、メモリに以下のように配置することにします。

 * A B C D E F G H 
 1 _ _ _ _ _ _ _ _ 
 2 _ _ _ _ _ _ _ _ 
 3 _ _ _ _ _ _ _ _ 
 4 _ _ _ _ _ _ _ _ 
 5 _ _ _ _ _ _ _ _ 
 6 _ _ _ _ _ _ _ _ 
 7 _ _ _ _ _ _ _ _ 
 8 _ _ _ _ _ _ _ _ 
                 

2 次元として表現していますが、実際には、1 次元的に格納しています。
また、終端には改行文字も入れています。
また、文字としては書かれませんが、8 の行の次にスペースで構成されたメモリ配列が取られています。
また、配列の前後には、3 セルの空白が挿入されています。

入力情報および石情報

盤面の直後に入力情報と石情報が配置されています。
入力情報は入力直後に、盤面位置のインデックスに変換されます。
その続きに、ターンプレイヤーの石、非ターンプレイヤーの石と続きます。
先手手番か後手手番かの判断は、ターンプレイヤーの石と非ターンプレイヤーの石を入れ替える形で行っています。

固定文字列

入力情報と石情報のあとに、空白セルが 6 セルあり、 そのあとに、繰り返し登場する固定文字列がメモリに展開されています。
具体的には

  • It's _ turn.
  • Plese input place.
  • Can't put here.
    の三つです。

メモリ図

メモリの配置を簡単に示すと以下のようになっています。

_{...field...}_{index}{myStone}{enemyStone}__{texts}

field は盤面情報、
index は位置情報、
myStone は手番プレイヤーの石、
enemyStone は相手プレイヤーの石、
texts は固定文字列です。

texts 以外の情報は、 3 セルを 1 セットとして、データ格納に用いています。3 セルのうちの 2 セルは、配列のランダムアクセスや、計算時の一時メモリとして使われます。


初期セットアップ

フィールドの作成

コード

上記のメモリをコードに表現するのコードを以下に列挙します。

これで、盤面の周囲全てに何かしらの値が入っていることになり、境界値判定が容易になります。 (厳密には、境界値判定ではなく、ポインタの移動のしやすさです。)

_ のセット

(クリックで展開)

>>>++++++++[->>>++++++++++++>>>++++++<<< <<<]>>>- //ptr ==2 {0}{0}{95}{48}
// **** Make '_' pattern ***
[
  -
  >>> >>> >>> >>> >>> >>> >>> >>> >>>
  >>>+>>>+>>>+>>>+>>>+>>>+>>>+>>>+>>> >>>   //1
  >>>+>>>+>>>+>>>+>>>+>>>+>>>+>>>+>>> >>>   //2
  >>>+>>>+>>>+>>>+>>>+>>>+>>>+>>>+>>> >>>   //3
  >>>+>>>+>>>+>>>+>>>+>>>+>>>+>>>+>>> >>>   //4
  >>>+>>>+>>>+>>>+>>>+>>>+>>>+>>>+>>> >>>   //5
  >>>+>>>+>>>+>>>+>>>+>>>+>>>+>>>+>>> >>>   //6
  >>>+>>>+>>>+>>>+>>>+>>>+>>>+>>>+>>> >>>   //7
  >>>+>>>+>>>+>>>+>>>+>>>+>>>+>>>+>>> >>>   //8
  
  <<< <<<
  [[<<<]<<< <<< <<<]
  <<< <<< <<< <<< <<< <<<
]
// **** End of Make '_' pattern ***

1 ~ 9 のセット

(クリックで展開)

>>>
// **** Make '1'to'9' pattern ***
>>> >>> >>> >>> >>> >>> >>> >>>+//1
[>>>]>>>++//2
[>>>]>>>+++//3
[>>>]>>>++++//4
[>>>]>>>+++++//5zz
[>>>]>>>++++++//6
[>>>]>>>+++++++//7
[>>>]>>>++++++++//8
<<< <<<
[[<<<]<<<]
<<< <<< <<< <<< <<< <<<
[-
  >>> >>> >>> >>> >>> >>> >>> >>>
  [+[>>>]>>>]
  <<< <<<
  [[<<<]<<<]
  <<< <<< <<< <<< <<< <<<
]
// **** End of Make '1'to'9' pattern ***

A~H のセット

(クリックで展開)

<<< <<< <<<
// **** Make 'A'to'H' pattern***
>>>++++++++[-<<<++++++++>>>]
>>>+        //A
>>>++       //B
>>>+++      //C
>>>++++     //D
>>>+++++    //E
>>>++++++   //F
>>>+++++++  //G
>>>++++++++ //H
[<<<]<<<
[-
  >>> >>>[+>>>]
  <<<[<<<]<<<
]
// **** End of Make 'A'to'H' pattern***

* および \n のセット

(クリックで展開)

++++++++[->>>++++<<<]
// **** 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 ****

手番石変数の初期化

コード(クリックで展開)

// **** End of Set first stones ****
>>> //位置ポインタに移動
+               //ダミーの設置
>>>             //Move to TrunPlayerStone Pointer 
// **** Set StornColor to TrunStonePointer ****
[-]++++[->++++++<]>[-<+++++>]<  // Set 'x'
>>> 
[-]++++[->+++++<]>++[-<+++++>]<+ // Set 'o'
>>>
// **** End of Set first stones ****

位置ポインタはランダムアクセスの位置を示す index を入れるメモリです。
今後位置ポインタは常に値が入ってる前提となるので、一度ダミーとして 1 を入れています。

文字列の初期化

コード(クリックで展開)

// **** 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


盤面の表示

盤面のメモリを、表示し易いように調整しているので、盤面表示は特に難しくはないです。
しかし、そのままだと、縦長になるので、各文字の前にスペースを入れることで調整しています。
ついでに、テキストも出力しています。

コード(クリックで展開)

// *** 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 ***

この時の出力結果はこのようになります。

 * A B C D E F G H 
 1 _ _ _ _ _ _ _ _ 
 2 _ _ _ _ _ _ _ _ 
 3 _ _ _ _ _ _ _ _ 
 4 _ _ _ o x _ _ _ 
 5 _ _ _ x o _ _ _ 
 6 _ _ _ _ _ _ _ _ 
 7 _ _ _ _ _ _ _ _ 
 8 _ _ _ _ _ _ _ _ 
                   
It's 'x' turn.
Plese 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 ***
// *********************************************

あとがき

brainfuck でオセロを書く人なんて、自分以外にいるんですかね…

質問とかあれば、ここにコメントするか、Twitterでリプもらえれば反応すると思います。
今回の記事の内容じゃなくても全然大丈夫なので気軽に質問ください。
それでは良い、brainfuck ライフを。