SImpuleBlokER

Simple ImpulseC Blokus Engine by Ritsumeikan

Tomonori IZUMI
(Ritsumeikan University)
2013.04.09a

SImpuleBlokERとは

SImpuleBlokER (シンプルブロッカー)は、 ICFPT / RECONF研の Blokus コンテストのための対戦テスト用として、 また、ImpulseC を用いた Blokus Player 開発のためのサンプルとして 開発した Bolkus Player です。

ソースコードはハードウェアに合成可能な ImpulseC で記述しています。 FPGAボードに実装するには、 ImpulseC から生成したハードウェア記述に 対象FPGAとFPGAボードにあわせた UART通信モジュール、 トップ記述、ピンアサインなどを加えて合成・書込します。

別途、汎用のUART通信モジュールと TERASIC DE2-115用トップ記述、ピンアサイン等を提供しています。 DE2-115 向けにコンパイル済みの sof ファイルも提供しますので、 実機テスト用の対戦相手として使用するだけなら、 これをQuartus のプログラマでボードに書き込めばすぐに使用できます。

コンテスト用の Impulse CoDeveloper ライセンス TERASIC DE2-115 FPGAボード の貸し出しがあります。 詳しくはそれぞれのサイトをご覧ください。

SImpuleBlokERの構成

SImpuleBlokER には次のコード、ファイルを含みます。

対戦テストをするには

TERASIC社DE2-115用に合成済みのコンフィギュレーションデータを 提供しています。 QuartusII の Programmer を用いて Blokus.sof をボードに書き込んでください。 このPlayerのチームコードは'ZZ'となっています。

審判プログラムは ICFPT2013 Design Competition のウェブサイト (琉球大学長名先生提供)から入手して下さい。 簡便には、TeraTermなどの端末ソフトでも人間とプレイできます。 コマンド間のスペースや改行コードなどは無視します。

ボード上で使用可能なスイッチや表示は次の通りです。

KEY0リセットスイッチ
KEY3-0動作チェック用(押すとLEDGがカウンタ表示)
LEDG7UART RXD (受信)
LEDG6Input Stream eos
LEDG5Input Stream en
LEDG4Input Stream rdy
LEDG3UART TXD (送信)
LEDG2Output Stream eos
LEDG1Output Stream en
LEDG0Output Stream rdy
HEX7-6受信文字コード
HEX5-4送信文字コード
HEX3-0ImpulseC 記述ハードウェアからの出力(デバグ用)
LEDR17-0ImpulseC 記述ハードウェアからの出力(デバグ用)
SW17-0ImpulseC 記述ハードウェアへの入力(デバグ用)

合成するには

準備

まず、「ImpulseC用RS232Cハードウェアラッパーキット」で、全体の流れを確認してください。

次のファイルを、 ラッパーキットで作成した Impulse_project フォルダ内の ものと差し替えます。

また次のファイルを、 Quartus_project フォルダ内のものと差し替えます。

Impulse CoDeveloper シミュレーション

ソフトウェアシミュレーションの際に、Application Monitorを用いると便利です。 次のように設定します。

テストで用いる入力データは filter_in.dat というファイルに用意します。 この実装ではコマンド間のスペースや改行等は無視します。 テキストファイルですので、適当なエディタで作成・編集してください。
入力の例
0初期化コマンド
2a初手位置
457j084k6相手の第1手・第2手
351m4相手の第3手
324l7相手の第4手
:(以下同様)
30000相手のパス
9終了コマンド

ソフトウェアシミュレーションを実行すると、 端末画面と Application Monitor 画面が現れます。 Application Monitor の Producer, Consumer タブの下部画面で 入出力を確認できます。 Blokus タブの下部画面ではゲームの進行状況が確認できます。

Impulse CoDeveloper ハードウェア生成

ハードウェアを生成し、エクスポートします。

QuartusII 合成

Impulseのプロジェクトフォルダの export フォルダ以下を QuartusII のプロジェクトフォルダに上書きコピーします。 合成します。

Programmer 書込み

QuartusII Programmer を起動し、Blokus.sof をボードに書き込みます。

動作確認

TeraTermなどの端末ソフトを使って、動作を確認します。 ボードをリセット状態から、 テスト用入力(上述filter_in.datの内容)を TeraTermの画面にタイプして入力します。 入力に応じた応答(例:'0'に対して'1ZZ'など)が返ってくることを確認します。

改造するには

この設計はコンテストに興味を持っていただいた方が開発する際の サンプルとして提供しています。 対戦アルゴリズムを独自に開発するベースとして、 この設計の、 ホストとの通信やゲームの流れの制御部分、デバッグ用の部分などを 利用して頂いて構いません。(利用した場合は謝辞などに記載願います)

本設計の Blokus Player のコードは Blokus_hw.c に収められています。 主な変数、関数を次に挙げます。

対戦の流れの制御(Blokus())は、 コンテストの通信規約にのっとって送受信を行い、 相手の手を受信して盤面に置く、 自分の手を決定する関数を呼び出してその手を盤面に置き送信する、 などの処理を行います。 このBlokus()を(必要に応じて改造して)用いて、 DecideNextMove()を自身のアルゴリズムに置き換えることで、 対戦アルゴリズムに専念できます。 通信手順・方法の詳細は ICFPT2013 Design Competition の ウェブサイトをご参照ください。 なお、このコードでは1手目は固定的に定め、送信しています。

DE2-115の16進表示器、発光ダイオード、スライドスイッチを ImpulseC コーディングのデバグ等で使うために、 register型のインターフェースで接続しています。 Blokus()関数の中で co_register_read() するとその時点でのスライドスイッチの値を読み出すことができ、 また、co_register_write() するとその値を16進表示器や発光ダイオードに表示することができます。

本設計では、 次に置く駒と場所の決定(SIBR_DeceideNextMove())は、 「置ける駒・場所を見つけて、置く」だけの愚直なアルゴリズムです。 次の疑似コードのような単純な4重ループで決定しています。

foreach tile t
   if (not used)
     foreach position (x,y)
       foreach rotation r
         if acceptable
           put(x,y,t,r)

ハードウェア化コーディングのノウハウ〜楽な方法

ハードウェア化コードの制約

ハードウェア化するプロセスにおいては記述法に次のような制約があります。

簡便な関数の実装について

本来は、複雑な処理を設計し高性能化を目指すのであれば、 処理をプロセスとして分割することを検討すべきです。 しかし、簡便には、関数をそのまま展開することでハードウェア化できます。 それには co primitive あるいは co inline プラグマで指定します。 結果として呼び出し回数分が全てインスタンス化されるため、 場合によっては回路規模が膨大になってしまうことに注意が必要です。

入力は単純型か静的配列(int *x ではなく int x[ ])の引数で与え、 出力は単純型の戻り値で返すか、引数の静的配列に書き込みます。

/* 上記方針に沿った関数の実装例 */
void sort ( int n, char a[ ] ) {
#pragma co primitive
   int i, j ;
   char tmp ;
   for ( i = 0 ; i < n - 1 ; i ++ )
     for ( j = i + 1 ; j < n ; j ++ )
       if ( a [ i ] > a [ j ] ) {
         tmp = a [ i ] ;
         a [ i ] = a [ j ] ;
         a [ j ] = tmp ;
     }
}

void hw_process ( co_stream Ist , co_stream Ost ) {
   char a [ 256 ] ; /* 静的配列 */
   char b [ 1024 ] ; /* 静的配列 */
   int n , m ;

   /* データ列を a に、個数を n に読み込み */

   sort ( n , a ) ;
   sort ( m , b ) ;

   /* データ列を a から書き出し */

}

記述法に関するその他の tips

関連情報

ICFPT2013 (International Conference on Field Programmable Technology)
www.fpt2013.org
ICFPT2013 Design Competition
lut.eee.u-ryukyu.ac.jp/dc13
FPGA設計コンテスト
www.cs.tsukuba.ac.jp/~yoshiki/FPGA/Contest
コンテスト用 Impulse CoDeveloper ライセンス貸し出し
www.cs.tsukuba.ac.jp/~yoshiki/FPGA/Contest
コンテスト用 FPGA ボード貸し出し
www.cs.tsukuba.ac.jp/~yoshiki/FPGA/Contest
PC と FPGA ボードを RS-232C コネクタで接続
www.ritsumei.ac.jp/se/re/izumilab/lecture/13RS232