物理シミュレーター
概要
局面の情報をを表す構造体と,ショットの情報を与えると次の局面を生成するカーリングのシミュレーターです.
このシミュレーターは,ベストなコンディションでのリンクの情報を元に作成しており,物理エンジンとしてBox2D(公式サイト)を採用しています.
本システムでは,カーリングシミュレーターをDLLの形で提供しています。シミュレーターはこちらからダウンロードしてください。
座標系
このシミュレーターではカーリングのリンクの左上を基準 ( 0, 0 ) としており、横がX軸で縦がY軸になっています。
リンクやハウスのサイズは実際のカーリングのリンクと同じ大きさになっており、シミュレーターで扱う数字の単位はm(メートル)です。
主な座標は画像で表示したとおりで、4フット円(赤い円)の直径は1.22m、8フット円(白い円)の直径は2.44m、12フット円(青い円)の直径は3.66mとなっています。
ストーンの大きさについて
カーリングのストーンの大きさは、外周が91.44cm以下と決められています。これを直径に直すと29.12cmとなります。システムではストーンの直径を0.29(29cm)として扱っています。
ショットの強さについて
カーリングで使われるショットの強さを参考にして、本システムでは以下の図のようにショットの強さを定義しています。
ショットの強さは0〜16までの範囲で指定できます.図では強さ11までしか表記していませんが、11以降は10〜11の間隔幅と同じ間隔で16まで設定されています。また、ショットの強さはfloat型として数値を扱っているため小数によるシステムへの指定も可能です。
局面を表す構造体
局面を表す構造体として,GAMESTATEを以下の要素を持つデータとして定義しています。
struct GAMESTATE{ int ShotNum; // 現在のショット数 int CurEnd; // 現在のエンド数 int LastEnd; // 最終エンド数 int Score[10]; // 1~10エンドにおける得点 bool WhiteToMove; // 手番情報 float body[16][2]; // ストーン位置情報 };
ショットを表す構造体
ショットを表す構造体としてSHOTPOSとSHOTVECを,以下の要素を持つデータとして定義しています。
- ショット情報(座標)
struct SHOTPOS{ float x; // ストーン位置座標(横) float y; // ストーン位置座標(縦) bool angle; // ストーンの回転方向。0のとき右回転を表し、1のとき左回転を表す。 };
- ショット情報(ベクトル)
struct SHOTVEC{ float x; // ショットの初速度(横) float y; // ショットの初速度(縦) bool angle; // ストーンの回転方向。0のとき右回転を表し、1のとき左回転を表す。 };
シミュレータが提供している関数
- Simulation ‐ デジタルカーリングのシミュレートを行う関数
- int Simulation( GAMESTATE *pGameState, SHOTVEC Shot, float Rand = 0.30f, SHOTVEC *lpResShot = NULL, int LoopCount = -1 )
pGameState ‐ シミュレーションを行うゲーム局面の情報。GAMESTATEについてはCurlingSimulator.h を参照してください。
Shot ‐ ショットの強さベクトル。CreateShot関数またはCreateHitShot関数によって得られたSHOTVECの値を使用してください。
Rand ‐ シミュレートを行う際の乱数の大きさ。
lpResShot ‐ シミュレートを行う際に実際に計算で使用された値(乱数の加えられた値)が返ります。必要のない場合にはNULLを指定してください。
LoopCount ‐ LoopCountで指定したフレーム数までシミュレートを行います。LoopCountに-1を指定した場合には、ショット後すべてのストーンが静止するまでシミュレートを行います。
- CreateShot ‐ 座標からショットを生成する関数
- int CreateShot( SHOTPOS Shot, SHOTVEC *lpResShot )
Shot ‐ Shotで指定した座標に到達するショットを生成します。SHOTPOSについてはCurlingSimulator.hを参照してください。
lpResShot ‐ 生成したショットの強さベクトルが返ります。
- CreateHitShot ‐ 座標と強さからヒットショットを生成する関数
- int CreateHitShot( SHOTPOS Shot, float Power, SHOTVEC *lpResShot )
Shot ‐ Shotで指定した座標を通過するヒットショットを生成します。SHOTPOSについてはCurlingSimulator.hを参照してください。
Power ‐ Powerで指定した強さのヒットショットを生成します。ショットの強さについてはこちら?を参照してください。
lpResShot ‐ 生成したヒットショットの強さベクトルが返ります。
サーバー
ネットワーク上にカーリングの物理シミュレーションを行うサーバーを置き、いつでも対戦をできるようにします。このサーバーに接続することによりコンピュータ同士の対戦だけでなく、コンピュータと人間、人間同士のカーリングの試合もできる環境を整えます。
現在対戦用のネットワークサーバーは準備中です。
クライアント
クライアントはこちらで用意した通信プロトコルを利用することによって誰でも作成することができます。
また、このサイトでもクライアントを提供しています。そのクライアントを利用してもらうことで思考エンジンのみを作成すればサーバーと簡単に接続することができるようになっています。
クライアントプログラムはこちらでダウンロードできます。
クライアントの操作方法
サーバーからのメッセージ
赤枠で囲まれた位置にサーバーからのメッセージが表示されます(デバッグ用)。
コマンドの送信
コマンドを入力し送信ボタンを押すことでコマンドを送信することができます(デバッグ用)。
サーバーへの接続
ゲームタブをクリックし、接続ボタンを選択してください。接続ダイアログボックスが開きます。
ダイアログボックスに必要な情報を入力することでサーバーへ接続することができます。
※初めて利用されるIDは、その時ログインに使用されたパスワードと共にサーバーに登録されます。
思考エンジンの読み込み
ゲームタブをクリックし、エンジンの選択をクリックしてください。思考エンジンのプログラムはウインドウが表示されずに起動され、クライアントの名前が選択した思考エンジンの名前に変わります。
ログの書き出し
ローカル対戦およびネットワーク対戦を行うと自動でログが書き出される仕様になっています。ログファイルは、実行ファイルのディレクトリにLogフォルダが作成され、その中に作成されます。
通信プロトコル
- 新システムにおけるプロトコルはこちら(github)
- TCP/IP を用いてサーバーに接続することができます。
クライアントからサーバー
- LOGIN ‐ ログインコマンド
- LOGIN id pass name
id ‐ 半角英数字(4〜16字)
pass ‐ 半角英数字(4〜8字)
name ‐ 半角英数字(16字以内)
- LOGOUT ‐ ログアウトコマンド
- LOGOUT
- BESTSHOT ‐ ショットを送るコマンド
- BESTSHOT x y turn
x ‐ ショットの強さ(横方向)
y ‐ ショットの強さ(縦方向)
turn ‐ 回転方向(0:右回転、1:左回転)
サーバーからクライアント
- ISREADY - クライアントの準備を待つコマンド
- ISREADY※クライアントはこのコマンドを受信したらREADYOKコマンドを返してください
- NEWGAME - 試合開始を通知するコマンド
- NEWGAME first second
first - 先手プレイヤ(AI)の名前
second - 後手プレイヤ(AI)の名前
- POSITION ‐ ストーンの位置情報を通知するコマンド
- POSITION x1 y1 x2 y2 ・・・ x16 y16
xn ‐ n投目のストーンのx座標
yn ‐ n投目のストーンのy座標
- SETSTATE ‐ 局面の情報を通知するコマンド
- SETSTATE shot cend fend move
shot ‐ 現在のショット数
cend ‐ 現在のエンド数
fend ‐ 最終エンド
move ‐ 手番(0:第一エンドで先手だったチーム、1:第一エンドで後手だったチーム)
- GO ‐ 思考開始を合図するコマンド
- GO t1 t2
t1 ‐ 先手の残り持ち時間(ミリ秒)
t2 ‐ 後手の残り持ち時間(ミリ秒)
※クライアントはこのコマンドを受信したらBESTSHOTコマンドを返してください
- SCORE - 直前のエンドの得点を通知するコマンド
- SCORE score
score - 直前のエンドの得点(+ならば1エンド目で先手だったプレイヤの得点、-ならば後手の得点)
- GAMEOVER ‐ 試合の結果を送るコマンド
- GAMEOVER WIN/LOSE
思考エンジン
概要
思考エンジンは、ストーンの位置情報や現在の投数や得点から次にどこに投げるのかというショットの情報を返すものを作るだけで作成することができます。
ここで提供しているクライアントを用いる場合には、標準入出力を用いることによってサーバーとのメッセージが簡単にやり取りできるようになっています。
思考エンジンの実行方法については、こちらをご確認ください。
思考エンジンとクライアントでの通信
クライアントからのメッセージの受け取りは以下のようにReadFile関数を利用してください。
ReadFile( GetStdHandle( STD_INPUT_HANDLE ), Message, sizeof( Message ), &NumberOfBytesRead, NULL );
また、クライアントへのメッセージの書き込みは以下のようにWriteFile関数を利用してください。
WriteFile( GetStdHandle( STD_OUTPUT_HANDLE ), Message, strlen( Message ), &NumberOfBytesWritten, NULL );
上記したようにGetStdHandle関数で標準入出力のハンドルを取得し、そこへメッセージを書きこむことによってクライアントとのメッセージのやり取りを行うことができるようになります。
本来であれば、printfやscanfなどの関数でも入出力のやり取りを行えるようにしたかったのですが、現在は実装が行えていないため思考エンジンを作成する方はこの方法でのコーディングをよろしくお願い致します。思考エンジンは、ストーンの位置情報や現在の投数や得点から次にどこに投げるのかというショットの情報を返すものを作るだけで作成することができます。
ここで提供しているクライアントを用いる場合には、標準入出力を用いることによってサーバーとのメッセージが簡単にやり取りできるようになっています。 思考エンジンの実行方法については、こちらをご確認ください。
思考エンジンとクライアントでの通信
クライアントからのメッセージの受け取りは以下のようにReadFile関数を利用してください。
ReadFile( GetStdHandle( STD_INPUT_HANDLE ), Message, sizeof( Message ), &NumberOfBytesRead, NULL );
また、クライアントへのメッセージの書き込みは以下のようにWriteFile関数を利用してください。
WriteFile( GetStdHandle( STD_OUTPUT_HANDLE ), Message, strlen( Message ), &NumberOfBytesWritten, NULL );
上記したようにGetStdHandle関数で標準入出力のハンドルを取得し、そこへメッセージを書きこむことによってクライアントとのメッセージのやり取りを行うことができるようになります。
本来であれば、printfやscanfなどの関数でも入出力のやり取りを行えるようにしたかったのですが、現在は実装が行えていないため思考エンジンを作成する方はこの方法でのコーディングをよろしくお願い致します。
最終更新時間:2021年12月01日 15時47分48秒