的の得点の配置 その2

いくらやっても分からないので、延々と評価し続けるようにしました。

/**
 * ダーツの的の得点の配置を考える
 */
#include <cstdio>
#include <cstdlib>
#include <unistd.h>
#include <ctime>
#include <vector>
#include <algorithm>

using namespace std;

// 固定値
enum {
	NINZU = 50,
	KAISUU = 3
};

// 人型
struct MAN {
	int no;
	double ave;
};

// 得点
struct TOKUTEN {
	int point;   // 評価関数による得点
	int p[ 12 ]; // 的の得点の配列
};

// 取得得点の比較関数。降順
int myComp( const void* a, const void* b )
{
	return (((MAN*)a)->ave > ((MAN*)b)->ave) ? -1 : ((((MAN*)a)->ave < ((MAN*)b)->ave) ? 1 : 0);
}

// 得点配列比較のための関数オブジェクト
class tokutenComp
{
public:
	bool operator() ( const TOKUTEN& lhs, const TOKUTEN& rhs ) const
	{
		return (lhs.point < rhs.point);
	};
};

// 取得得点の評価関数
int myEval( const MAN* m )
{
	int point = 0;

	// ダブったら +1。小さい方が優秀かもしれない
	for( int i = 0; i < NINZU-1; ++i ) {
		if( m[ i ].ave == m[ i+1 ].ave ) ++point;
	}
	return point;
}


//////////////////////////////////// main
int main(void)
{
	int i, j, k; // カウンタ
	int pickup = 0; // 引いた点数
	TOKUTEN nowTk;    // 現在の対象得点配列
	TOKUTEN recordTk; // 最高ポイントをマークした得点配列
	MAN     m[ NINZU ]; // 人
	vector< TOKUTEN > tokutenArray;  // 20回試行したものを保存する

	// 初期値
	for( int i = 0; i<12; ++i ) nowTk.p[i] = 30;
	nowTk.point = 50;

	// 乱数発生器
	srand( (unsigned long)time(NULL) );

	while( 1 ) {
		tokutenArray.clear();

		printf( "proc   %2d [%2d] [%2d] [%2d] [%2d] [%2d]  [%2d] [%2d] [%2d] [%2d] [%2d]  [%2d] [%2d]?n",
					nowTk.point, 
					nowTk.p[ 0], nowTk.p[ 1], nowTk.p[ 2], nowTk.p[ 3], nowTk.p[ 4], nowTk.p[ 5],
					nowTk.p[ 6], nowTk.p[ 7], nowTk.p[ 8], nowTk.p[ 9], nowTk.p[10], nowTk.p[11] );

		// 20 回試行
		for( k = 0; k < 20; ++k ) {
			// ダーツ投げ部
			for( i = 0; i < NINZU; ++i ) { // 人数分繰り返し
				// 初期化をここで
				m[ i ].no = i;
				m[ i ].ave = 0.0;

				// ダーツを投げる
				for( j = 0; j < KAISUU; ++j ) {      // KAISUU 回投げます
					pickup = rand() % 12;            // 的に刺さった
					m[ i ].ave += nowTk.p[ pickup ]; // 点数加算
				}
			}

			// 集計
			for( i = 0; i < NINZU; ++i ) {
				m[ i ].ave /= static_cast<double>(KAISUU); // 平均
			}

			// ソート
			qsort( m, NINZU, sizeof( MAN ), &myComp );

			// 評価関数による評価
			nowTk.point = myEval( m );

			// 得点配列に入れる
			tokutenArray.push_back( nowTk );
		}

		// 試行が終わった
		// 得点配列を、ポイントの高い(= 得点の低い)順にソート
		sort( tokutenArray.begin(), tokutenArray.end(), tokutenComp() );

		// 現在の最低得点を下回ったか?
		if( tokutenArray[0].point < recordTk.point ) {
			recordTk = tokutenArray[0]; // 記録更新!!!

			TOKUTEN a = tokutenArray[0];
			printf( "HIT!   %2d [%2d] [%2d] [%2d] [%2d] [%2d]  [%2d] [%2d] [%2d] [%2d] [%2d]  [%2d] [%2d]?n",
					a.point, 
					a.p[ 0], a.p[ 1], a.p[ 2], a.p[ 3], a.p[ 4], a.p[ 5],
					a.p[ 6], a.p[ 7], a.p[ 8], a.p[ 9], a.p[10], a.p[11] );
		}

		nowTk = recordTk;
		printf( "result %2d [%2d] [%2d] [%2d] [%2d] [%2d]  [%2d] [%2d] [%2d] [%2d] [%2d]  [%2d] [%2d]?n",
					nowTk.point, 
					nowTk.p[ 0], nowTk.p[ 1], nowTk.p[ 2], nowTk.p[ 3], nowTk.p[ 4], nowTk.p[ 5],
					nowTk.p[ 6], nowTk.p[ 7], nowTk.p[ 8], nowTk.p[ 9], nowTk.p[10], nowTk.p[11] );

		// 適当に調整
		for( k = 0; k < 12; ++k ) {
			nowTk.p[ k ] = rand() % 30 + 1;
		}

		sleep( 1 ); // のんびりいきまっしょい
	}

	return 0;
}

とりあえず明日はずっと裏でぶん回しておこうと思います。
いつか最適解に近い値が得られるでしょう。こんぴーた万歳。