麻雀の対子が暗刻になるまでの平均順目

このQ&Aのポイント
  • 麻雀において、対子が暗刻になるまでの平均順目は13.492である。
  • C++のプログラムを使用して計算した結果、対子が暗刻になるまでの平均順目は13.492である。
  • 乱数の精度に関する意見を求めている。計算結果は予想よりも大きかった。
回答を見る
  • ベストアンサー

麻雀において、対子が暗刻になるまでの平均順目2

以前、数学カテゴリーでした質問(対子が暗刻になるまでの平均順目http://okwave.jp/qa/q9209998.html)をもとに、質問します。手計算に限界を感じたため、一念発起してC++の学習を始めて、プログラムを書いてみたのですがどうでしょうか?計算結果は13.492(順目)だったのですが、予想していた約8順に対して少し大きい値が得られてしまいました。 もっとこういう書き方をしたほうがいいよ、とか、立式が間違っているよ、とかなんでもいいので意見をいただけると嬉しいです。 あと、rand関数の精度?がいまいちだという話も聞いているので、もっといい乱数の発生させかたに関する意見も欲しいです。しかし、約5順のずれは乱数の問題だけではないような気がしますが・・ #include <iostream> #include <stdio.h> using namespace std; inline double chusen() { return rand() % 100 ;//0~100までの値を生成 } int main() { //牌姿は例えば、(1)(1)(9)(9)123456789のような形とする //ここに(1)(1)(9)(9)123456789+(1)or(9)のように、アンコができる場合を考える int nhai[18] = { 123, 119, 115, 111, 107, 103, 99, 95, 91, 87, 83, 79, 75, 71, 67, 63, 59, 55 };//各順目における残りの牌 double tumochusen[18];//各順目にツモってこれるかどうかを判定するために用いる。rand関数によって、ランダムな値を得る int SIMULATE = 10000;//シミュレーションの回数 int junme[10000];//アンコができた順目。終局までにできなければ18とする double sum=0;//順目の合計値 for (int j = 0; j < SIMULATE; j++) { junme[j] = 18; for (int i = 0; i <= 17; i++) { tumochusen[i] = chusen(); cout << "tumochusen[" << i << "]の値は" << tumochusen[i] << "です。\n"; if (tumochusen[i] < (400 / nhai[i])) { cout << i + 1 << "順目でアンコになりました。\n"; junme[j] = i + 1; goto end;//アンコができたら、その局は終了する } } end: cout << "シミュレーション" << j + 1 << "を終了します。\n"; } for (int k = 0; k < SIMULATE; k++) { cout<<"junme["<<k<<"]の値は"<<junme[k] << "です。\n"; } for (int l = 0; l < SIMULATE; l++) { sum += junme[l]; } cout << "よって、求める平均順目は" << sum / SIMULATE << "です。\n"; return 0; }

質問者が選んだベストアンサー

  • ベストアンサー
  • f272
  • ベストアンサー率46% (7995/17088)
回答No.1

if (tumochusen[i] < (400 / nhai[i])) { というように比較していますが,これって意図通りなのだろうか? まず400 / nhai[i]はint/intだから答えはintにしかならない。(切り捨てです。) tumochusen[i]は,rand() % 100を計算してdoubleにしていますが,実質的にはintです。 比較は,doubleとdoubleの比較にすべきなんじゃなかろうか? 他にはrand()を使うのならsrand()は使わないの?とか,そもそもrand()を使うべきなの?とかありますが,大勢には影響ありません。 もう一点だけ。 平均巡目はsum / SIMULATEでいいのだろうか?これについてはよくわからないので明確な言い方は避けますが,全員が無作為に打牌するわけではないという事実を完全に無視していますよね。それで求めた計算にどれほどの意味があるのだろうか? 少なくとも,自分からは見えていない牌の集合を考えて,そこから各プレイヤの手牌を推測した上で,ツモる牌の確率分布を考えるといったことまでしないと,計算がかなりずれそうです。実際にどういう計算をすればよいかは聞かないでください。私も答えは持っていません。 ちなみに,あなたが書いたプログラムでも18巡目にならないものだけを取り出して,その平均を取れば9巡目くらいにはすぐなりますよ。

snnnmdr
質問者

お礼

回答ありがとうございます。とても参考になりました。今後もよろしくお願いします。他の方からの意見も聞けるかもしれないので、回答はもうしばらくの間受け付けます 指摘1に関して:doubleとdoubleの比較に変更します。そのほうがいいと思います 指摘2に関して:srand()って、乱数列の並び?を初期化する関数でしたっけ?まだ、乱数の扱いが不慣れですので、どうしたらいいかよくわからなかったのですが、大きくは影響しないとのことなので、このままrand()を使います 指摘3に関して:平均順目はsum / SIMULATEでも、まあいいんじゃないかな、と思います。今回のシュミレーションでは他家は和了放棄のbotとして考えます。他家の手牌の推測等は今後の課題とします 指摘4に関して:暗刻ができる場合だけを取り出して、平均を取ろうとしたことがなかったので、意外でした。著者が言っている平均8順とは、これのことをいっているのかもしれませんね

関連するQ&A

  • 100x100行列の平均値を求めたい

    const int SIZE=100; for(int i=0; i< SIZE; i++){ for(int j=0; j< SIZE; j++){ fin >> array[i][j]; } } double sum=0.0; double ave=0.0; int J =3; for(int i=0; i< SIZE; i++){ sum += array[i][J]; } ave = sum / SIZE; cout << sum << endl; cout << ave << endl; 100x100行のファイルを読み込んで、すべての行の足し算および平均値を求めたいと思います。上のようある列(または行)を固定して求めることは出来るのですが、一度に0~99までの足し算および平均値を求めるやり方はどのようにしたらよろしいのでしょうか?たぶんfor文を使えば、できるのかなとは思うのですが、なかなか思うように行きません。 アドバイスよろしくお願いいたします。

  • C++で行列とベクトルの積を求める

    行列とベクトルの掛け算 y=Ax (A(3*3行列以上)とxを適当に初期化) を作成せよ これが分からないんですが誰か分かる人いませんか?下は行列の和と積をそれぞれ求めてるんですが、こんな感じになりそうなんですよね #include<iostream> using namespace std; int main() { double A[3][3]={{1,1,6},{5,3,2},{2,2,2}}; double B[3][3]={{4,1,3},{2,4,3},{5,9,2}}; double temp; int i,j,k; for(i=0;i<3;i++){ for(k=0;k<3;k++){ } } for(i=0;i<3;i++){ for(k=0;k<3;k++){ } } cout<<"和:A+B="<< '\n'; for(i=0;i<3;i++){ cout<<" { "; for(j=0;j<3;j++){ cout<< (A[i][j]+B[i][j]); if(j!=2) cout<<" , "; } cout<< " }" << '\n'; } cout<< '\n'; cout<<"積:A*B="<< '\n'; for(i=0;i<3;i++){ cout<<" { "; for(j=0;j<3;j++){ temp=0.0; for(k=0;k<3;k++) temp += A[i][k]*B[k][j]; cout<< temp; if(j!=2) cout<< " , "; } cout<< " }" << '\n'; } return 0; }

  • CPadでのアニメーションについて

    CPadでC言語を使ってアニメーションを作っているのですが、なにかいい例はないでしょうか。プログラムの形はこんなのです。↓ #include <glibw32.h> #include <windows.h> #include <stdlib.h> void main() { int i,j,k,l,m,n; ginit(512,512); GRAPH g; setcolor256(1,7); g.setlinestyle(0,3); for(l=0;l<50;l++) { j=(int)(double)rand()*500.0/RAND_MAX)+200; k=(int)(double)rand()*500.0/RAND_MAX)+200; for(n=0;n<100;n++) { g.cls(); fori=0;i<128;i++) { g.setcolor(i*2); g.setlinestyle(0.i/24); g.line(j-i-(n*2),k-i-(n*2),j-i-(n*2),k-i-(n*2)); } Sleep(10); } } delcolor256(); gend(); } 上記プログラムでは流れ星のようなものが現れます。C言語についてあまり知らないので何のプログラムを作っているのかわからない、何を聞きたいのかわからない、と思われるでしょうがそれを承知の上でお願いします。

  • 座標をランダムに表示させてx座標順にソートするプログラムを考えています

    座標をランダムに表示させてx座標順にソートするプログラムを考えています とりあえず、以下の様に決まった数の座標でソートすることはできたのですが、ランダムにするとなるとどうすればいいのかわかりません。 ------------------------------------------------- #include <stdio.h> int makepoints(int * pn, double * x, double * y){ double xp,yp; int k; int i,j; int n; n = 7; *pn = n; xp = 1; for(k=0;k<n;k++) { xp = xp/2; yp = xp*xp; x[k] = xp; y[k] = yp; } printf("初期座標列:\n"); for(k=0;k<n;k++) { printf("%f_%f\n",x[k],y[k]); } for(j=1;j<n;j++) { for(i=0;i<j;i++) { if(x[i]>x[j]){ xp=x[i];x[i]=x[j];x[j]=xp; yp=y[i];y[i]=y[j];y[j]=yp; } } } printf("整列後の座標列:\n"); for(k=0;k<n;k++) { printf("%d %f %f\n",k ,x[k],y[k]); } return 0; } ------------------------------------------------- なんとなくrand関数を使えばいいのかな、というのはわかるのですが、プログラミングに弱く困っています。 この後のプログラミング教えてくださる方いればよろしくお願いします。

  • 配列とポインタでの書き直しその2

    配列とポインタでの書き直し(c++)その1 のつづき cout << endl; cout << setw(5) << "Sum" << setw(12) << "Number" << setw(14) << "Probability" << setw(10) << "Error" << endl; cout << "-----------------------------------------" << endl << endl; cout << setiosflags(ios::fixed | ios::showpoint); for (int k = 0; k <= 10; k++) { probability = static_cast<double>(sum[k])/throws; cout << setw(4) << k+2 << setw(12) << sum[k] << setprecision(6) << setw(14) << probability << setprecision(2) << setw(11) << getError(probability, k, error) << endl; } return 0; } // Roll two dice. int rollDice() { int dice1, dice2; dice1 = rand()%6 +1; dice2 = rand()%6 +1; return (dice1 + dice2); } // Example: for error dice 12 // // prob = sum[10] / throws, // // // |prob - e[10]| // error = ----------------- x 100 // e[10] // double getError(double p, int i, double e[]) { return ((fabs(p - e[i])/e[i])*100); } 関連URL: http://www.okweb.ne.jp/kotaeru.php3?q=243537

  • 小さい順

    私はC言語初心者で、今本などをみながら独学で学んでいます。 配列の値を小さい順に並べたいのですがうまくいきません・・・プログラムは以下のようにしました。 #include <stdio.h> int main(void){ int ten[5] = {5,1,4,2,3}; int i,j,hako,a = 1,k = 1; for(i = 0;i <= 3;i++){ if(i == 2){ k++;} if(i == 3){ k = k + 1;} for(j = 4;j > a;j--){ if(ten[i] > ten[k]){ hako = ten[i]; ten[i] = ten[k]; ten[k] = hako;} k++;} a++; k = k - 3; } for(i = 0;i < 5;i++){ printf("%d\n",ten[i]);} return 0;} こうしたらよいなどヒントでもお願いしますm(__)m

  • 設定した値が意図せぬ値に

    POJ 3176の問題です。 http://poj.org/problem?id=3176 #include <iostream> #include <algorithm> #define MAX 100 using namespace std; int main() { int n; cin >> n; int line[n-1][MAX]; int num[n-1][MAX]; cin >> line[0][0]; if(n==0) { cout << 0 <<endl; return 0; } else if(n==1) { cout << line[0][0] << endl; return 0; } for (int i =1;i < n;i++) { for (int j=0;j < i+1;j++) { int x; cin >> x; line[i][j]= x; } } for (int k= 0 ; k<n;k++) { num[n-1][k]= line [n-1][k]; } for (int k= n-2; k > 0 ; k--) { for (int l=0 ; l<k+1; l++) { num[k][l] = max (num[k+1][l],num[k+1][l+1]) + line[k][l]; } } num[0][0] = max(num[1][0],num[1][1]) + line[0][0]; cout << line[0][0] <<" "<<num[0][0]<<endl; return 0; } 入力 4 3 1 3 1 2 3 1 3 4 5 出力 1 12 最後に出力でline[0][0]をするようにしているのはバグチェックのためです。 ここで僕がわからないのはどうしてline[0][0]が3で宣言し、ほかでいじっていないにも関わらず、最後に1になっているのかということです。 どなたかわかる方がいらっしゃったらよろしくお願いします。

  • 配列のエラーに関して

    java言語を用いて,Householder変換を用いた固有値の数値計算に挑戦してみました.しかし,次のようなエラーが発生し上手くいきません.どなたかこの問題を解決するためにお力をかしていただけないでしょうか. ----------エラー内容-------------------------------------------------------------------------------- Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0 at Out.Mhouse(House.java:90) at House.main(House.java:10) ---------------------------------------------------------------------------------------------------- //Householder変換 public class House{ public static void main(String[] args){ double[][] A = new double[3][3]; int n = A.length; Out out = new Out(); for(int i = 0;i < n;i++){ for(int j = 0;j < n;j++){ if(j < n-1){ System.out.print(out.Mhouse(A)[i][j] + " "); }else if (j == n-1) System.out.println(out.Mhouse(A)[i][j]); }; }; }; }; class Out{ double[][] outpro(double[] x){ int n; n = x.length; double[][] A = new double[n][n]; for(int i = 0;i < n;i++ ){ for(int j = 0;j < n;j++){ A[i][j] = x[i] * x[j]; } } return A; }; double[][] Msca(double a,double[][] A){ int n = A.length; for(int i = 0;i < n; i++){ for(int j = 0;j < n;j++){ A[i][j] = a * A[i][j]; } } return A; }; double selfpro(double[] x){ double a = 0; int n = x.length; for(int i = 0;i < n; i++){ a = a + x[i] * x[i]; }; return a; }; double[] minus(double[] x, double[] y){ int n = x.length; double[] z = new double[n]; for(int i = 0;i < n;i++){ z[i] = x[i] - y[i]; }; return z; }; double[][] house_1(double[] x){ int n = x.length; double[][] A = new double[n][n]; for(int i=0;i < n;i++){ for(int j = 0;j < n;j++){ if(i == j){ A[i][j] = 1 - Msca(2/selfpro(x),outpro(x))[i][j]; }else{ A[i][j] = - Msca(2/selfpro(x),outpro(x))[i][j]; }; }; }; return A; }; double[][] house_2(double[] x){ double[][] z = new double[1][1]; z[1][1] = 1 - 2; return z; }; double[][] Mhouse(double[][] A){ int n = A.length; double[][] H = new double[n][n]; for(int i = 0;i < n;i++){ double[] x = new double[n-i]; double[] y = new double[n-i]; double[][][] L = new double[i][n-i][n-i]; for(int j = 0;j < n-i;j++){ x[j] = A[i][i+j]; if(j == 0){ y[j] = 1; }else{ y[j] = 0; }; x[j] = y[j] - x[j]; }; if(i < n-1){ L[i] = house_1(x); for(int k = 0;k < n-i;k++){ for(int l = 0;l < n-i;l++){ H[i+k][i+l] = L[i][k][l]; }; }; }else if(i == n-1){ L[i] = house_2(x); for(int k = 0;k < n-i;k++){ for(int l = 0;l < n-i;l++){ H[i+k][i+l] = L[i][k][l]; }; }; }; }; double[][] B = new double[n][n]; for(int i = 0;i < n;i++){ for(int j = 0;j < n;j++){ for(int k = 0;k < n;k++){ B[i][j] = H[i][k] * A[k][j]; }; }; }; return A; }; };

    • ベストアンサー
    • Java
  • 配列 平均値と分散値

    #include <stdio.h> void mean_vari(int *s, int n, double *mean, double *variance); int main(void) { int i, n; int a[]={34, 54, 21, 80, 60, 90, 15, 24, 100}; double heikin, bunsan; mean_vari(&i,n,&heikin,&bunsan); printf("平均=%f 分散=%f\n",heikin,bunsan); return (0); } /* 合計を求める関数 */ void mean_vari(int *s, int n, double *mean, double *variance) { int i; int sum=0; /* 合計の初期化 */ double sum2=0; for (i = 0; i < n; i++) sum += s[i]; ????=sum/(double)????; for (i = 0; i < n; i++){ sum2 +=????; } ????=????; } 平均値と分散値を求めたいのですが、????の部分になりをいれていいかわかりません。 教えてください。

  • C++で縦の棒グラフ

    #include<iostream> #include<ctime> using namespace std; int main() { int a[7]; int k; int j; srand(time(NULL)); for(k = 0; k < 7; k++) a[k] = rand() % 10 + 1; for(k = 0; k < 7; k++){ cout << "a[" << k << "] = "; for(j = 0; j < a[k]; j++) cout << "*"; cout << "\n"; } cout << "-------------\n"; cout << "0 1 2 3 4 5 6\n"; return 0; } グラフを作ってみようと挑戦したんですけど 横の棒グラフは作ることはできたんですけど 縦の棒グラフを作ろうして、下の部分はできたんですけど その上に*をランダムの数だけ表示さす方法がわかりません。 どうしてらよいでしょうか?

専門家に質問してみよう