TOPへ


MJexeIO.DLL読込関数


MJexeIO.DLLマニュアル(ミラー)


MJexeIO.DLL を使って自分のAIがどの位強いか試したいが、そのためのプログラムを組むのが手間」
という人(全国で約3人)のために、MJexeIO.DLLから条件無しで読み取りでき、AI作りに関係ありそうな情報を
関数一つ呼ぶだけで取得できるプログラムを作りました。


MJexeIO.DLL読込関数ダウンロード
とりあえず公開版 Ver.0.01
細かな部分までデバッグしていません。バグが残っている可能性大。参考程度推奨。

内容
○ZIPファイル中身
・MJexeIO.DLL読込関数ヘッダ「GetDataMJEXEIO.h」
・MJexeIO.DLL読込関数本体「GetDataMJEXEIO.cpp」
・動作確認用サンプルコンソールアプリ&ソース
・MJexeIO.DLL本体(Ver.0.92)
VC++2008で作成しています。他コンパイラで不具合が出る場合は適時修正して下さい。

○機能
MJexeIO.DLLで用意されている関数を使い、画面から条件無しでわかるAI作成に必要そうな情報を読み込みます。
他、読みだしたデータを加工して以下の情報も取得します。
・シャンテン数
・場に見えている牌の数
・テンパイ、待ち
・フリテン

使い方
関数GetDataMJEXEIOを呼ぶと構造体MJexeDataにデータが入ります。読み込みたいソースファイルに
①"GetDataMJEXEIO.h"の宣言
②MJexeData構造体の定義
③GetDataMJEXEIOの呼出(MJexeData構造体のポインタ渡し)
④DLLの開放
を記述してください。同梱ファイルを含めてビルドしてください。
MJexeIO.DLLの機能上、東風荘の画面を最前面にしておかないと正しく動作しません。
単純に1から10まで読むだけだと非常に遅いので速くなるよう工夫してあります。
しかしそれでも遅く、情報量によりますが私の環境(Win7 64Bit,AthlonX2 2.80GHz,メモリ2G)
で0.5秒から2.5秒程かかってしまいます。もし案があればご教授願います。
改造自由ですので必要/不必要な部分を自由に追加/削除できます。
構造体は以下の様な構成になっています。
詳しい内容は本家をご参考ください。



見つけたDLLのバグ
・自分のターン以外でGetAvailableFunctionKeyのF5キーの値が0(F5鳴無(反転なし))になるはずが3になっている
・GetDorahaiはdora[0]にドラ表示牌の枚数が入るはずだが裏返しの牌(=41)もカウントしており常に5が入るようになっている

(ツモツモ君が牌サイズ小だとリーチ後ツモ切り動作しない。他は動く)

//データ格納用構造体
typedef struct{
	//汎用
	int size;//牌サイズ
	int tehai[51];	//手牌
	//GetAvailableFunctionKey用
	int AvailableFKey;//取得成功
	int AvailFKey_flags[20];//ボタンデータ
	int ExistFKey;//何かFキーが押せるか
	//GetDorahai用
	int RetGetDorahai;//返り値
	int dora[6];//ドラ表示牌
	int Jikaze;//自風
	int Bakaze;//場風
	//GetPlayInfo用
	int RetGetPlayInfo;//返り値
	int PlayInfo[10];//>GetPlayInfoの情報
	int MenzenKosuu;//GetTehaiで読み出せた牌の個数
	int RightestTehai;//最後にGetTehaiを呼び出した時の一番右の牌
	int WhereAmI;//今東風荘のどこにいるか
	char TonpuTitlebar[150];//東風荘ウインドウのタイトルバー文字列
	int WhereTonpuNum;//第○東風荘に接続しているか
	HWND hPlayRoom_p;//待合室ウインドウのハンドルを入れるHWNDへのポインタ
	HWND hMachiai_p;//卓ウインドウのハンドルを入れるHWNDへのポインタ
	int TurnPlayer;//現在ツモおよび打牌中の家
	//以下のものは2次元配列のN行目に情報が入っている
	//N → 1:自分 2:下家 3:対面 4:上家
	int fuurosuu[5],fuuro[5][51];//GetFurohai用
	int riichi[5];//GetReach用
	int RetGetPlayerInfo[5],tensuu[5],rate[5];//GetPlayerInfo用
	int SutehaiKosuu[5],sutehai[5][51],sutehaidata[5][51],tumokiridata[5][51],RedBorder[5][51];//GetSutehaiEx2用
	//GetNokorihai用
	//自分から見えている牌の個数が対応する牌番号に入る
	//参考:MJexeIO.DLL サンプル1
	int bahai[51];
	//シャンテン数
	int Nsyan;//通常
	int Tsyan;//チートイ
	int Ksyan;//国士
	//待ち
	//[0]に待ち牌の個数が入る
	//[1]以降に待ち牌の種類が昇順に並ぶ
	int Nmati[10];//通常
	int Tmati[3];//チートイ
	int Kmati[15];//国士
	bool is_furiten;//フリテンフラグ(TRUEでフリテン中)
	/**********************************************/
	//以下宣言のみで使用していないもの
	//GetExtendInformation用
	int ExtendMem[51];//拡張作業領域
	int RetExtendInfo;//返り値
	int ExtendInfoSize;//拡張作業領域のサイズ
	int HoldTime;//打牌するまでの制限時間
	int TonpuConnect;//東風への接続試行状態
	int DLLVer;//DLLのバージョン
	LPRECT lprect;//マウスカーソルの座標
	bool GetCursor;//マウスカーソルの座標取得成功
	//Check_tenpai用
	int agari[21];	//上がり牌
	int Ret_Check_tenpai;//Check_tenpaiの返り値
	//以下作業用
	bool once;
	int memturn;
}MJexeData;



○例えば

PushHaiに必要なhaipos(その牌が左から何番目の位置にあるか)を返す関数はこうなる

//@retern	左から何番目か
//@param1	知りたい牌番号
int get_haipos(int hai)
{
	int ret=0;

	if(hai==data.RightestTehai) return 14;

	data.tehai[data.RightestTehai]--;
	for(int i=1;i<=hai;i++){
		ret+=data.tehai[i];
	}
	data.tehai[data.RightestTehai]++;

	return ret;
}

麻雀得点計算C++ソース「MJScore.h」


●ダウンロード(ver1.072)

mjscore.h(ヘッダ)
mjscore.cpp(本体、使用するソースと共にビルド)
mjscore_sample.cpp(使用例)

右クリック→対象をファイルに保存から
開発ソフト:VisualC++2008 Express Editon


-------------------------------------------------------
おまけ Java版 MJScore.java v0.1
MJScore.hをそのまま移植したもの
簡単な動作確認しかしていないver0.1

cpp版のバグ修正を反映していないのでそのまま使用するのは非推奨(というか使い物にならない)
完全に参考程度でお願いします

MJScore.java(Source)
Test.java(Test)
JavaDoc(とりあえず)
-------------------------------------------------------

●履歴
v1.072 七対子、混老頭、混一が混合した場合に混一が判定されていなかったバグ修正

v1.071 あがり牌が赤だった場合の不具合修正

v1.07 役満関係修正


v1.061 KokusiSyanten()微修正

v1.06 アンカンで九蓮宝燈が成立してしまっていたバグ修正(v1.02エンバグ)


v1.05 タンヤオ判定のバグ修正


v1.04 ツモのみでドラがのらないバグ修正


v1.03 バグ修正、Get_ResultKiriwake、Set_Dorasuu追加


v1.02 下記修正
・暗槓で一盃口などが消え、食い下がりのある役の翻数が減るバグ修正
・Get_TokutenOyaTumo(), Get_TokutenKoTumo()メソッド追加
・裏ドラがGet_Fan()で得られる翻数に含まれないバグ修正
・5枚目の表ドラおよび裏ドラの入力に対応
・赤ドラを含むチーとポンを区別するように定数を追加(AKA_PON1,AKA_PON2,AKA_CHII)
・役名を東風荘のものと合わせる(まだ抜けがあるかも)

v1.01 バグ修正


●概要
一般的なルールでの麻雀得点計算C++クラス「MJScore」のソースファイルです。ライブラリの様に使用できます。無断使用、改造自由です。

●ルール
天鳳ルール(段位戦)
天鳳役一覧

天鳳段位戦のルールプラス、以下のルールが選択可能となっています

・赤有り(デフォルト:無し)
・クイタン(デフォルト:有り)
・満貫切り上げ(デフォルト:無し)
・場千五(1本場を1500点とする)(デフォルト:無し)
・国士13面待ちダブル役満(デフォルト:無し)
・九連宝燈9面待ちダブル役満(デフォルト:無し)
・大四喜ダブル役満(デフォルト:無し)
・四暗刻単騎ダブル役満(デフォルト:無し)

人和、大車輪等のローカル役には対応していません。


●定義

牌の表現方法等の定義は以下になります。定義に沿っていない場合、動作は保証されません。

牌の表現方法

牌番号 牌種
1・・・・・・ 1マン
2・・・・・・ 2マン

9・・・・・・ 9マン
10・・・・・・未定義
11・・・・・・1ピン
12・・・・・・2ピン

19・・・・・・9ピン
20・・・・・・未定義
21・・・・・・1ソウ
22・・・・・・2ソウ

29・・・・・・9ソウ
30・・・・・・未定義
31・・・・・・東
32・・・・・・南
33・・・・・・西
34・・・・・・北
35・・・・・・白
36・・・・・・発
37・・・・・・中
38・・・・・・赤5マン
39・・・・・・赤5ピン
40・・・・・・赤5ソウ

フーロ牌の表現方法

フーロ牌はint型の配列[20]に、n+1番目のフーロ牌について

となります。


ドラ牌の表現方法

ドラ牌はint型の配列[11]に

となります。使用してない場所(めくられていない場所+その裏)は0にしてください。

成立役の配列(結果用)

bool型の配列(サイズ[60])を用意してください。
列挙子で配列要素にアクセスし、trueなら成立しています。

例)yaku[MJScore::PINFU]など
MJScore::YAKU列挙子

役名の配列(結果用)

C++STLのstring型の配列(サイズ[20])を用意して下さい。
結果の書式は
「役名+半角スペース+翻数(半角数字)」
となります。


●使い方

1. まず使用するC++ファイルにMJScore.hをincludeします。

#include "mjscore.h"

2. MJScoreクラスのインスタンスを作成します

MJScore inst;

3. ルールを入力します(bool値)。未入力の場合はクイタン以外全てfalseとなります。

inst.Avail_Akahai(false);//赤牌有り(赤は各1枚ずつ)
inst.Avail_Kuitan(true);//クイタン有り
inst.Avail_ManganKiriage(false);//満貫切り上げ有り
inst.Avail_Ba1500(false);//場千五有り
inst.Avail_DoubleKokushi13(false);//国士13面待ちダブル役満有り
inst.Avail_DoubleTyuuren9(false);//九連宝燈9面待ちダブル役満有り
inst.Avail_DoubleDaisuusii(false);//大四喜ダブル役満有り
inst.Avail_DoubleSuttan(false);//四暗刻単騎ダブル役満有り

4. 以下の偶然役、状況役は個別の特殊な情報が必要ですので、成立した場合"成立フラグ(true)"を入力します(bool値)。未入力の場合は全てfalseとなります。

inst.Is_Riichi(false);//リーチ
inst.Is_Tenhou(false);//天和
inst.Is_Tiihou(false);//地和
inst.Is_DoubleRiichi(false);//ダブルリーチ
inst.Is_Ippatu(false);//一発
inst.Is_Tyankan(false);//チャンカン
inst.Is_Rinsyan(false);//リンシャン
inst.Is_NagashiMangan(false);//流し満貫
inst.Is_Haitei(false);//ハイテイ

5. 必須情報を入力します。未入力の場合ErrorCodeにエラーが返り、計算が中断されます。

//必須情報入力
inst.Set_Tehai(int[]);//手牌(int[41]の配列)
inst.Set_Agarihai(int);//あがり牌(牌番号)
inst.Set_Bakaze(int);//場風(31~34)
inst.Set_Jikaze(int);//自風(31~34)

6. 追加情報を入力します。未入力の場合は無し、又はfalseが選択されます。

//追加情報入力
inst.Set_Tumoagari(bool);//ツモあがりならTRUE
inst.Set_Honba(int);//N本場
inst.Set_KyoutakuRIichi(int);//供託リーチ本数
inst.Set_Fuuro(int[]);//フーロ牌入力(int[20]の配列)
inst.Set_Dora(int[]);//ドラ牌入力(int[11]の配列)
inst.Set_Dorasuu(inta);//ドラ数のみ単独入力したい場合

7. Run()メソッドを呼び計算を実行します。

inst.Run();//実行

8. Run()メソッドを呼んだ直後にエラーコードを確認します。0以外ならば正しく計算されていません。

inst.Get_ErrorCode();//エラーコード取得

//******返り値の意味******
//-1:未計算
//0:正常終了
//1:「非フーロ牌+フーロ数*3」が14枚でないor手牌に0未満か5以上のデータがある
//2:あがり牌情報がないor手牌にあがり牌がない
//3:あがっていない
//4:場風か自風情報がない
//5:鳴きリーチしている
//6:役がない

9.結果を確認します。以下のメソッドから必要な情報を取得します。

計算が正常終了した後に呼び出してください

//役名の配列取得
inst.Get_Yakuname(string result[]);//string型(サイズ20)のポインタ渡し

成立役の配列参照

//成立役のテーブル
inst.Get_Yakutable(bool Yakutable[]);//bool型のポインタ渡し

MJScore::YAKU(役名列挙子)参照

//結果取得
//点数には積棒が含まれます

inst.Get_OyaTumo();//親のツモ点 返り値=int
inst.Get_OyaRon();//親のロン点 返り値=int
inst.Get_KoTumoOya();//子のツモ点(対親) 返り値=int
inst.Get_KoTumoKo();//子のツモ点(対子) 返り値=int
inst.Get_KoRon();//子のロン点 返り値=int
inst.Get_Fu();//符 値が-1なら役満などの符が関係無い役 返り値=int
inst.Get_Fan();//役数 役満は40=役満、41=2倍役満……45=6倍役満まで 返り値=int
inst.Get_Dorasuu();//ドラ数(赤除く) 返り値=int
inst.Get_Uradorasuu();//裏ドラ数 返り値=int
inst.Get_Akadorasuu();//赤ドラ数 返り値=int

inst.Get_TokutenOya();//供託リーチなどを含めた、最終的に親が貰う点数(ロン) 返り値=int
inst.Get_TokutenKo();//供託リーチなどを含めた、最終的に子が貰う点数(ロン) 返り値=int

inst.Get_TokutenOyaTumo();//供託リーチなどを含めた、最終的に親が貰う点数(ツモ) 返り値=int
inst.Get_TokutenKoTumo();//供託リーチなどを含めた、最終的に子が貰う点数(ツモ) 返り値=int

inst.Get_ResultKiriwake(int *arg);////切り分け確定後のメンツ取得(配列int[10] MJScore::MENTU、ハイ番号の順に)


inst.Get_Ismangan();//満貫かどうか 返り値=bool
inst.Get_Ismangan();//満貫かどうか 返り値=bool


10.インスタンスを破棄せず続けて使用する場合、以下のどちらかのメソッドで中身をクリアしてから使用します。

inst.Clear();//中身を全てクリア
inst.Clear_WithoutRule();//ルール以外の中身をクリア




Q.速度は?
A.
平和のみ10000回→5.0秒
チンイツ多面張10000回→7.9秒
チートイのみ10000回→3.1秒
国士13面10000回→0.2秒
清老頭10000回→0.1秒
でした。


MJScore::MENTU(メンツ種類列挙子)



このプログラムを作る際、HP上の情報に結構な数の間違いがある事に気づき修正しました。すいません……


※応用

//ロン時の得点取得(int)
//0点なら出和了り不可なので出和了りチェックに使える
//
int getRonTokuten(
	int tehai[],	//手牌(あがり牌を含むあがり形)
	int fuuro[],	//フーロ牌
	int agarihai,	//あがり牌
	int bakaze,	//場風
	int jikaze,	//時風
	bool is_oya,	//親かどうか
	bool riichi 	//リーチかどうか
	)
{
	MJScore sc;
	sc.Set_Tehai(_tehai);
	sc.Set_Agarihai(agarihai);
	sc.Set_Fuuro(_fuuro);
	sc.Set_Bakaze(bakaze);
	sc.Set_Jikaze(jikaze);
	sc.Set_Tumoagari(false);
	sc.Is_Riichi(riichi);
	sc.Run();
	if(sc.Get_ErrorCode()){
		//役なしエラー等
		return 0;
	}
	if(is_oya) return sc.Get_OyaRon();
	return sc.Get_KoRon();
}




TOPへ 

inserted by FC2 system