FXRubyでどうぶつ将棋をつくろう

# はじめに
[「wxPythonでオセロをつくろう」](http://qiita.com/kanlkan/items/5e6f2e63de406f46b3b1)の姉妹編です。
Rubyの勉強がしたい、そうだ、どうぶつ将棋をつくろう。
Rubyで簡単にマルチプラットフォームで動作するGUIアプリを作成できるFXRubyを使用して、どうぶつ将棋をつくってみます。
この記事に触発されてポーカーやバックギャモンなど作っていただければ嬉しいです。
どうぶつ将棋とは？という方は[Wikipedia](https://ja.wikipedia.org/wiki/%E3%81%A9%E3%81%86%E3%81%B6%E3%81%A4%E3%81%97%E3%82%87%E3%81%86%E3%81%8E)をご覧ください。
ソースは[GitHub](https://github.com/kanlkan/animal-chess)に上げてありますので、そちらから取得してください。

# FXRubyのインストール
 
 + LinuxMint(Ubuntu, Debian)
 
```
$ sudo apt-get install ruby-full
$ sudo apt-get install libfox-1.6-dev
$ sudo apt-get install libxrandr-dev
$ sudo gem install fxruby
```
他のディストリビューションでもruby gemがインストールできれば、あとは同様だと思います。

 + Windows
   + [こちら](http://rubyinstaller.org/downloads/)から、以下をダウンロードしてインストールします。32bit/64bitはご自身の環境に合わせてください。
     + rubyinstaller-x.x.x.exe
　 
   + コマンドプロンプトで以下を実行します。
   
```
gem install fxruby
```


# FXRuby Tips
今回、FXRubyを使用していてハマったところを紹介します。参考になればと思います。
 
 + FXTextのテキストクリア方法
   + FXText.clearTextとかあるだろう、と思ってましたが、無い...　indexを指定してテキストを消すremoveTextしかありません。そのためテキストのクリアは以下のようにやりました。

```rb
...
@log_text = FXText.new(sub_frame_mid, :opts => LAYOUT_FIX_WIDTH| \
                           LAYOUT_FIX_HEIGHT, :width => 300, :height => 200)
...
@log_text.removeText(0, @log_text.length)
```
 + FXTableのIconセット時に"illegal icon specified"のエラーが出る場合の対処
   +  詳しくは[こちら](http://www.fox-toolkit.org/faq.html#ILLEGALICON)を参照ください。強引ですが手っ取り早く解決するには、最初に作成したアイコンすべてを、一旦フォーム上に表示させておく、という方法があります。具体的には以下のようにします。

```rb
  def initialize(app)
    ...  

    # out_table is needed for showing all icon to use.
    # refer to "http://fox-toolkit.org/faq.html#ILLEGALICON"
    #
    # out_tableの:width=>5がミソです。幅を狭くしてGUI上に見えないようにしています。
    # こうして一度GUIに表示してしまえば、どのiconでもillegalにならずに使えます。
    out_frame = FXHorizontalFrame.new(base_frame, :opts => LAYOUT_FIX_WIDTH| \
                                      LAYOUT_FIX_HEIGHT, :x => 870, :width=>5,\
                                      :height => 480)
    @out_table = FXTable.new(out_frame, :opts => LAYOUT_FILL|TABLE_READONLY)
    @out_table.defColumnWidth = 90
    @out_table.defRowHeight = 120
    @out_table.setTableSize(4,3)
    @out_table.rowHeaderMode = LAYOUT_FIX_WIDTH
    @out_table.rowHeaderWidth = 0
    @out_table.columnHeaderMode = LAYOUT_FIX_HEIGHT
    @out_table.columnHeaderHeight = 0
    # show all icon to use
    @out_table.setItemIcon(0, 0, @piece_lion)
    @out_table.setItemIcon(0, 1, @piece_lion_inv)
    @out_table.setItemIcon(0, 2, @piece_giraffe)
    @out_table.setItemIcon(1, 0, @piece_giraffe_inv)
    @out_table.setItemIcon(1, 1, @piece_elephant)
    @out_table.setItemIcon(1, 2, @piece_elephant_inv)
    @out_table.setItemIcon(2, 0, @piece_cock)
    @out_table.setItemIcon(2, 1, @piece_cock_inv)
    @out_table.setItemIcon(2, 2, @piece_chick)
    @out_table.setItemIcon(3, 0, @piece_chick_inv)

    ...
```

 + FXTableのHeader行(列)を無くす
   + FXTableを普通に使うと、以下のグレーの部分のようにHeader行(列)ができてしまいます。

![fix_cell.png](https://qiita-image-store.s3.amazonaws.com/0/127380/9f79d2a0-0a41-b9bb-42ea-ab761498dee0.png)


   + 今回のようにテーブル全部にアイコンを並べたい場合にはHeader行(列)は邪魔です。消すには単にHeader行(列)の幅(高さ)を"0"にします。

```rb
    @main_table = FXTable.new(main_frame, :opts => LAYOUT_FILL|TABLE_READONLY)
    @main_table.defColumnWidth = 90
    @main_table.defRowHeight = 120
    @main_table.setTableSize(4,3)
    ## hide table header row and col
    @main_table.rowHeaderMode = LAYOUT_FIX_WIDTH
    @main_table.rowHeaderWidth = 0
    @main_table.columnHeaderMode = LAYOUT_FIX_HEIGHT
    @main_table.columnHeaderHeight = 0
```

# 動作確認環境
 + LinuxMint 17.3 (ruby 1.9.3p484 + fxruby 1.6.34)
 + Windows10 (ruby 2.2.4p230 + fxruby 1.6.34)

# 遊び方
![animal_chess.png](https://qiita-image-store.s3.amazonaws.com/0/127380/57665bd4-bf6f-ed64-78c8-2cd8c5da3e50.png)

Game Modeを選んでGame Startを押してプレイします。下側が先攻の陣地です。

+ Game Mode
 + Man vs Comp : 人が先攻、コンピュータが後攻
 + Comp vs Man : コンピュータが先攻、人が後攻

+ 駒
  + L : Lion (ライオン)
  + E : Elephant (ゾウ)
  + G : Giraffe (キリン)
  + c(小文字) : chick (ひよこ)
  + C(大文字) : cock (にわとり)

駒の動かせる位置は駒の赤丸で示しています。
ウィンドウの右側の上下のTableは相手から取った持ち駒が表示されます。
あとは駒を交互に動かします。コンピュータは自動で動かします。
相手のライオンを取る(catch)、または相手の陣地の奥一段に自分のライオンを動かす(try)すれば勝利です。

+ 制限事項
  + 千日手の実装はしていません。
  + ライオンは相手の次手で取られる位置にも動かせます。
  + 一度つかんだ駒は戻せません。ただ、どこにも動かせない駒をつかんだ場合は元に戻せます。


# コンピュータのAIの実装
以下の場所にインプリできます。

```rb
  def decide_next_move(move_pieces, pos_list, got_pieces)
    from = []
    to = []
    
    #### insert computer AI here. ####
    
    ...
    
    ##################################

    p "from = " + from.to_s
    p "to = " + to.to_s
    return from, to
  end
```
現状、インプリに使用できる情報として、「動かせる駒のリスト」(move_pieces)、「動かせる駒が移動できる場所のリスト、のリスト」(pos_list)、「移動した結果取れる駒のリスト、のリスト」(got_pieces) が用意してあります。
現在インプリされているAIは非常に拙いもので、「相手のライオンが取れる状態の場合はライオンを取る」、「その他の場合は打てる手をランダムで打つ」というものになっています。

ぜひ自分で強いAIを作成して、友人と戦ってみてください。
 一人が Man vs Computer, もう一人が Computer vs Manを使用すれば、それぞれのコンピュータAI同士で勝負できます。
 (相手の手をManの手としてそれぞれ入力していく)

2種類のAIを実装してComputer vs Computerで戦わせるのもおススメです。
(AIの切り替え機構は入れていないので、別途インプリが必要です。)

# 参考
[http://www.fxruby.org/doc/book.html](http://www.fxruby.org/doc/book.html)
[http://fxruby.org/doc/api/](http://fxruby.org/doc/api/)
[http://fox-toolkit.org/](http://fox-toolkit.org/)
[http://www.rubydoc.info/gems/fxruby](http://www.rubydoc.info/gems/fxruby)