gnubg python scripting: gnubg.findbestmove()

最善手を gnubg に計算させてみましょう！

これはとある日の赤坂例会のポジションです。赤の私が4-0/5pのクロフォードでした。青の54はどう動かしましょうか？
![IMG_20160717_131509.jpg](https://qiita-image-store.s3.amazonaws.com/0/42252/4e525a39-37b4-c6a0-4351-2b7ba78d8792.jpeg)

## board

まずはチェッカーの配置を tuple の list につめて指定します。
それぞれのポイントにあるチェッカーの数を順番に入れればよさそうです。25番目の項目は、オンザバーのチェッカー数らしいです。

```python
In [1]: board = ((0, 0, 0, 2, 2, 3, 2, 0, 0, 3, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0),
   ...:  (0, 0, 0, 0, 0, 5, 2, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 0))
```
## cubeinfo

マッチの長さやスコア、クロフォードか否かを指定します。`gammonprice`は分からないので、とりあえず 0 にしておきます。

```python
In [2]: cubeinfo = {'beavers': 0,
   ...:  'bgv': 0,
   ...:  'crawford': 1,
   ...:  'cube': 1,
   ...:  'cubeowner': -1,
   ...:  'gammonprice': ((0.0, 0.0), (0.0, 0.0)),
   ...:  'jacoby': 0,
   ...:  'matchto': 5,
   ...:  'move': 0,
   ...:  'score': (0, 4)}
```
`calcgammonprice` というメソッドがあるので、ギャモンプライスを計算できます。

```python
In [3]: cubeinfo = gnubg.calcgammonprice(cubeinfo)

In [4]: cubeinfo
Out[4]: 
{'beavers': 0,
 'bgv': 0,
 'crawford': 1,
 'cube': 1,
 'cubeowner': -1,
 'gammonprice': ((0.06355762481689453, 1.1390838623046875), (0.0, 0.0)),
 'jacoby': 0,
 'matchto': 5,
 'move': 0,
 'score': (0, 4)}
```
## posinfo

出目と、どっちのターンかを指定します。

```python
In [5]: posinfo = {'dice': (5, 4), 'doubled': 0, 'gamestate': 1, 'resigned': 0, 'turn': 0}
```
## gnubgid

このあと使うので、`gnubgid`なるものを作っておきます。

```python
In [6]: gnubgid = gnubg.gnubgid(board, cubeinfo, posinfo)

In [7]: gnubgid
Out[7]: u'2G4cAwTg2wkAKw:sIGyAAAAIAAE'
```

`set gnubgid` コマンドで、`gnubgid` を指定すると、これまで設定してきた局面になります。

```python
In [8]: gnubg.command('set gnubgid 2G4cAwTg2wkAKw:sIGyAAAAIAAE')
The dice have been set to 5 and 4.
 GNU Backgammon  Position ID: 4HPwATDgc/ABMA
                 Match ID   : sIGyAAAAIAAE
 +12-11-10--9--8--7-------6--5--4--3--2--1-+     O: gnubg
 | X           O    |   | O              X |     0 ポイント
 | X           O    |   | O              X |     ダイスを振る 54
 | X           O    |   | O                |     
 | X                |   | O                |     
 | X                |   | O                |    
^|                  |BAR|                  |     5 ポイントマッチ (キューブ: 1)
 | O                |   | X                |    
 | O                |   | X                |     
 | O           X    |   | X                |     
 | O           X    |   | X              O |     
 | O           X    |   | X              O |     4 ポイント
 +13-14-15-16-17-18------19-20-21-22-23-24-+     X: mkisono

 GNU Backgammon  Position ID: 2G4cAwTg2wkAKw
                 Match ID   : sIGyAAAAIAAE
 +12-11-10--9--8--7-------6--5--4--3--2--1-+     O: gnubg
 | X     O     O  O |   | O     X          |     0 ポイント
 | X           O  O |   | O                |     ダイスを振る 54
 |             O    |   | O                |     
 |                  |   | O                |     
 |                  |   | O                |    
^|                  |BAR|                  |     5 ポイントマッチ (キューブ: 1)
 |                  |   |                  |    
 |                  |   |                  |     
 |       X          |   | X                |     
 |       X        X |   | X  X  X  O       |     
 |       X        X |   | X  X  X  O  O  O |     4 ポイント
 +13-14-15-16-17-18------19-20-21-22-23-24-+     X: mkisono

Setting GNUbg ID 2G4cAwTg2wkAKw:sIGyAAAAIAAE
```

## findbestmove

ではいよいよ、最善手を調べましょう！

```python
In [9]: gnubg.findbestmove()
Out[9]: (10, 5, 8, 4)
```

10/5, 8/4* ですね。
他にこれといったいい手が見当たりません。インナーにブロットばら撒きますが、ここは赤にヒットしてもらい、２箇所目のアンカー取れればバックゲームの体裁にはなりそうです。

`hint` コマンドを使えば、もっと詳しい情報がずらずら出てきます。

```python
In [10]: gnubg.hint()
Out[10]: 
{'gnubgid': u'2G4cAwTg2wkAKw:sIGyAAAAIAAE',
 'hint': [{'context': {'cubeful': 1,
    'deterministic': 1,
    'noise': 0.0,
    'plies': 2,
    'prune': 1},
   'details': {'probs': (0.28211891651153564,
     0.03484905883669853,
     0.001164137851446867,
     0.38557541370391846,
     0.0413915291428566),
    'score': -0.4322209358215332},
   'eqdiff': 0.0,
   'equity': -0.4322209358215332,
   'move': '10/5 8/4*',
   'movenum': 1,
   'type': 'eval'},
  {'context': {'cubeful': 1,
    'deterministic': 1,
    'noise': 0.0,
    'plies': 2,
    'prune': 1},
   'details': {'probs': (0.2639846205711365,
     0.03448880836367607,
     0.0010329540818929672,
     0.41944432258605957,
     0.05380573496222496),
    'score': -0.46866169571876526},
   'eqdiff': -0.036440759897232056,
   'equity': -0.46866169571876526,
   'move': '8/4* 8/3',
   'movenum': 2,
   'type': 'eval'},
```

これまでの記事

- http://qiita.com/mkisono/items/bef45089dab399fac433
- http://qiita.com/mkisono/items/073d33dc99b23093cad5
- http://qiita.com/mkisono/items/53e5053b1bae3abfbf14