コンピュータ将棋①

自分で考えている基本的な考え方
 
①ソフトウェア作成の方法論として
 
 ソフトウェアを作るにあたって、将棋のルールや対局のことについてよく知っていることは大切なことですが、それだけでは不足です。勝つためのソフトウェアを作成するためには、作り手が、勝ち方を知っていないと勝てないと考えられなくはないでしょうか?いかに、ハードウェアが高速で、幾通りもの指し手を予測する性能があったとしても、勝てる手を指せなければ意味がありません。次手に、どのような評価値をつけるかは、自分の経験や判断で決めていかないといけないということです。
 一方で、プロの棋士が、将棋を指したスコアをまとめた電子アーカイブが存在します。手に入れるために、有償であるのか、無償であるのかは別として。洗練された棋譜の中から、概ねこの方法が良かろうということを学習して、評価値を決めることもできるのです。不可能ではありませんね。だとしたら、棋力の少ない一般人がプロ棋士に勝つためには、素人が企んだ戦略で勝負することよりも、科学の力を借りて他の棋士の戦歴を分析することに注力することのほうが、より力を発揮しそうであることは予想に難くありませんね。そういう意味では、データありきで勝負することも現実の手段としては有効ではないかと考えられます。
 
②将棋の発展に寄与するコンピュータ将棋の在り方
 
 シミュレーターとしてのコンピュータ将棋の在り方には、価値があると考えています。コンピュータの力を借りて、過去の経験値から、どのような時にどんな方法が妥当な指し手として、有効であるかを測る尺度(最善手)として選ばれるべきかを知ることは非常に意味があることだと思っています。そういう意味では、主に研究分野としての利用価値が高く、電王トーナメント終了の合図をもってその存在意義をなくすものではないと考えています。どういう戦法がトレンドなのか?などという話に至っては、コンピュータ将棋が業界をリードする役割を果たしていくのではないかと考えています。
 
③コンピュータ将棋を支える技術基盤
 
 ソフトウェア開発において、Windows 環境において C++ で開発することが花形であるように見受けられます。Linux で開発することも視野に入ってないわけではないのでしょうが、私が気づいていないプラットフォームに依存する操作の具合(簡便性、特殊なAPI)が存在することにより、Windows 上での開発が主流になっているように感じます。対局場と、思考エンジンとを結ぶソフトウェアの通信プロトコルについては、このように実装すればよろしいというような、解説を伴っての平易な案内がなく、新規参入組の高い壁となっているような気がします。コンピュータ将棋の今後の発展を期待するにあたって、より分かりやすい解説が、障壁なく手に入れることができるという要件が必要になってくると思われます。

大富豪

大富豪を作りたくて書き始まったプログラム。

プレイヤーの数を4人で想定してシャッフルしていますが、可変にすると難しいことになりそうです。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Card001
{
class Program
{
static List<Card> card = new List<Card>();

static void Main(string[] args)
{
InitCardType();

var x = GetUniqRandomNumbersEasy(0, 53, 53);

int[,] a = new int[2, 53];

int i = 0;
foreach(var s in x)
{
a[1, i] = s;

if(0 == (i % 4))
{
a[0, i] = 0;
}
if (1 == (i % 4))
{
a[0, i] = 1;
}
if (2 == (i % 4))
{
a[0, i] = 2;
}
if (3 == (i % 4))
{
a[0, i] = 3;
}

string str = string.Format("{0}-{1}", a[0, i], a[1, i]);
Console.WriteLine(str);
i++;
}

for(int j=0;j<53;j++)
{
if(a[0, j] == 0)
{
Console.WriteLine(card[a[1, j]].cardName);
}
}
}

static int GetCardNum(IEnumerable<int> x, int num)
{
int rtn = -1;

foreach (var s in x)
{
if (s == num)
return s;
}

return rtn;
}

static IEnumerable<int> GetUniqRandomNumbersEasy(int rangeBegin, int rangeEnd, int count)
{
// 指定された範囲の整数で埋めたリストを用意する
List<int> work
= Enumerable.Range(rangeBegin, rangeEnd - rangeBegin + 1).ToList();

// workからランダムに取り出して、順に返していく(count回繰り返す)
var rnd = new Random();
for (int i = 0; i < count; i++)
{
// workからランダムに1つ選んで値を取り出す
int pos = rnd.Next(0, work.Count);
int value = work[pos];
work.RemoveAt(pos); // 取り出した値はリストから取り去る

// 取り出した値を順に返す
yield return value;
}
}

static void InitCardType()
{
card.Add(new Card(0, "Jocker"));
card.Add(new Card(1, "クラブ-エース(1)"));
card.Add(new Card(2, "クラブ-デュース(2)"));
card.Add(new Card(3, "クラブ-トレイ(3)"));
card.Add(new Card(4, "クラブ-ケイト(4)"));
card.Add(new Card(5, "クラブ-シンク(5)"));
card.Add(new Card(6, "クラブ-サイス(6)"));
card.Add(new Card(7, "クラブ-セブン(7)"));
card.Add(new Card(8, "クラブ-エイト(8)"));
card.Add(new Card(9, "クラブ-ナイン(9)"));
card.Add(new Card(10, "クラブ-テン(10)"));
card.Add(new Card(11, "クラブ-ジャック(11)"));
card.Add(new Card(12, "クラブ-クイーン(12)"));
card.Add(new Card(13, "クラブ-キング(13)"));
card.Add(new Card(14, "ダイア-エース(1)"));
card.Add(new Card(15, "ダイア-デュース(2)"));
card.Add(new Card(16, "ダイア-トレイ(3)"));
card.Add(new Card(17, "ダイア-ケイト(4)"));
card.Add(new Card(18, "ダイア-シンク(5)"));
card.Add(new Card(19, "ダイア-サイス(6)"));
card.Add(new Card(20, "ダイア-セブン(7)"));
card.Add(new Card(21, "ダイア-エイト(8)"));
card.Add(new Card(22, "ダイア-ナイン(9)"));
card.Add(new Card(23, "ダイア-テン(10)"));
card.Add(new Card(24, "ダイア-ジャック(11)"));
card.Add(new Card(25, "ダイア-クイーン(12)"));
card.Add(new Card(26, "ダイア-キング(13)"));
card.Add(new Card(27, "ハート-エース(1)"));
card.Add(new Card(28, "ハート-デュース(2)"));
card.Add(new Card(29, "ハート-トレイ(3)"));
card.Add(new Card(30, "ハート-ケイト(4)"));
card.Add(new Card(31, "ハート-シンク(5)"));
card.Add(new Card(32, "ハート-サイス(6)"));
card.Add(new Card(33, "ハート-セブン(7)"));
card.Add(new Card(34, "ハート-エイト(8)"));
card.Add(new Card(35, "ハート-ナイン(9)"));
card.Add(new Card(36, "ハート-テン(10)"));
card.Add(new Card(37, "ハート-ジャック(11)"));
card.Add(new Card(38, "ハート-クイーン(12)"));
card.Add(new Card(39, "ハート-キング(13)"));
card.Add(new Card(40, "スペード-エース(1)"));
card.Add(new Card(41, "スペード-デュース(2)"));
card.Add(new Card(42, "スペード-トレイ(3)"));
card.Add(new Card(43, "スペード-ケイト(4)"));
card.Add(new Card(44, "スペード-シンク(5)"));
card.Add(new Card(45, "スペード-サイス(6)"));
card.Add(new Card(46, "スペード-セブン(7)"));
card.Add(new Card(47, "スペード-エイト(8)"));
card.Add(new Card(48, "スペード-ナイン(9)"));
card.Add(new Card(49, "スペード-テン(10)"));
card.Add(new Card(50, "スペード-ジャック(11)"));
card.Add(new Card(51, "スペード-クイーン(12)"));
card.Add(new Card(52, "スペード-キング(13)"));
}
}
}

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Card001
{
class Card
{
public int id;
public string cardName;

public Card(int id, string cardName)
{
this.id = id;
this.cardName = cardName;
}
}
}

コンピュータ将棋を実感してみる①

暑いですね。

久しぶりにバイクで外に出て、スポンジとシャンプーを買ってきたので、洗車しました。

マオマオ、ごめんな。汚れたままで…。

 

最近凝っている話題の中に、コンピュータ将棋があります。

電王戦で、実際にプロ棋士と対戦しているようなプログラムを作ることはとても大変なことですが、将棋のルール上指すことができる手を探し出すプログラムを書くことができたので、より深く、関係者の皆さんがどんなことを考えながらプログラムを組み立てているのかが気になって、いろいろ調べてみました。

 

将棋所というプログラムがあるようです。

これは、コンピュータ将棋の対局の場を提供するもので、自作の思考エンジン(将棋の戦略を考えるプログラム)を登録してあげると、プログラム対プログラムの対戦が実現できます。

 

将棋所の作者の方が作った、思考エンジンと対戦することができるので、動かし方を何回かに分けて解説していきたいと思います。

回転変換

win32アプリケーション。

回転変換を行うコードを書いてみた。

 

case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: HDC を使用する描画コードをここに追加してください...
int origin = 1000;

//背景色を設定する
SelectObject(hdc, GetStockObject(GRAY_BRUSH));
Rectangle(hdc, 0, 0, 1980, 1200);

//グリッドを引いて、見やすくする
for (int i = 0; i < origin; i++)
{
SetPixel(hdc, i, origin, 0xffff00);
SetPixel(hdc, origin, i, 0xffff00);
}

//変数の宣言
double a1, a2, b1, b2;
double degree = 60;
double rad = degree * PI / 180.0;
double x, y;

//初期値を、(600, 400)に設定
x = 600.0;
y = 400.0;

MoveToEx(hdc, x + origin, -y + origin, NULL);
LineTo(hdc, origin, origin);

//変換前の座標から、原点に向かって線を引く
//MoveToEx(hdc, x + 800, y + 800, NULL);
//LineTo(hdc, 800, 800);

//一次変換
a1 = cos(rad) * x;
a2 = sin(rad) * x;
b1 = -sin(rad) * y;
b2 = cos(rad) * y;

x = a1 + b1;
y = a2 + b2;

//変換後の座標から、原点に向かって線を引く
SetPixel(hdc, x+ origin, -y+ origin, 0xFF0000);

MoveToEx(hdc, x+ origin, -y+ origin, NULL);
LineTo(hdc, origin, origin);

EndPaint(hWnd, &ps);
}
break;