2014年12月13日 (土)

第12回Phunコン JPCC その3

本日の成果は15rad/secでした。

Type-2:
偏心していないローターにThymeで生成した燃焼ガスをぶつけるもの

Type-3:
埋め込み力は埋め込み深度に比例するという認識の基、ローターとハウジングの隙間を小さくしたもの

Type-4a:
燃焼ガス発生位置を変えることでトルク増大を狙ったもの(失敗作)

Type-4b:
ローターをヒンジで接続することで、衝撃をいったんヒンジで受け止めるもの
回転時にヒンジが伸びっぱなしなのが気になる

Type-5a:
燃焼ガスを大型化することで、埋め込み力増大を狙ったもの
燃焼ガス生成と同時にキラーに触れて消えることが多く、排気をシミュレートしていない気がする

Type-5b:
燃焼ガスを4個生成するように変えたもの
今のところ最高速
やっぱり埋め込みは深度が大事か

昨日の記事で触れたDynamic Lensの関連シーンとして挙がっていたのがLens Cutter。点滅するレーザーを使用して凸レンズを切り出します。ここまでは私も構想していたのですが、このシーンは機械式で非球面レンズを作るのがすごい。シーン下部に完成品のレンズが置いてありますが、球面収差が見事に補正されています。

2014年12月12日 (金)

第12回Phunコン JPCC その2

第12回Phunコンへ挑戦中。本日の成果は6rad./sec。吸気と圧縮行程がないので、どう見てもガスタービンエンジンです。

Phun/Algodooで燃焼爆発をシミュレートしたい人は、OnCollide=(e)=>{ Scene.addCircle({pos := e.pos; radius := 半径;})}だけでも覚えると便利です。

さてAlgoboxを探検していて見つけたDynamic Lensのシーン。微小なレンズが回転することで焦点を結ぶ補償光学系です。OnLaserHitで衝突点の検出と、レーザーの回転両方をしているのが素晴らしい。私が作ったすばる望遠鏡オートフォーカスよりはるかにシンプルな実装になっています。

2014年12月 9日 (火)

第12回Phunコン JPCC

第12回Phunコン JPCC(Japan Phun Car Championship)が開催(12/15~22)されます。今回は独自エンジンを搭載した自動車による競走です。

作ってみた。今回はエンジン回転数も評価の対象になるので、高回転を狙ってシンプルな構造にしてみた。ヒンジを多用する変速機は、高回転時にヒンジずれが予測されるので撤去。おにぎりポリゴンは高回転に弱そうなので、ローターを四角に。ということで、こんな感じのインホイールモーター、ロータリーエンジンになった。

この車は走らない。容積変化を回転力に結びつけられないとダメだ。高回転って難しい。

2014年11月30日 (日)

続・C言語で要素を数える

昨日の続き。 中身が入っている配列の数をlast_indexに覚えさせる方式は分からないと言われたので、ID:zJNKuV6Eが書いたコードに近づけてみた。
// total.cpp : コンソール アプリケーションのエントリ ポイントを定義します。
//

#include "stdafx.h"


int _tmain(int argc, char* argv[])
{
	char code3[50][100];
	int data3[50];

	// 初期化
	for( int i=0; i<50; i++)
	{
		strcpy( code3[i], "\0");
		data3[i] = 0;
	}

	if (argc != 4)
	{
		fprintf( stderr, "Usage: %s inputfile1 inputfile2 outputfile\n", argv[0]);
		exit(-1);
	}
	
	// 入力ファイル読み込み
	for( int file_index=1; file_index<=2; file_index++)
	{
		FILE* fp_in = fopen( argv[file_index], "r");
		if( fp_in == NULL)
		{
			fprintf( stderr, "Cannot open input file %s\n", argv[file_index]);
			exit(-2);
		}

		char read_code[100];
		int read_data;
		while( fscanf( fp_in, "%s %d", read_code, &read_data) != EOF)
		{
			for( int i=0; i<50; i++)
			{
				if( strcmp( code3[i], read_code) == 0) // ヒット
				{
					data3[i] += read_data;
					break;
				}
				if( strcmp( code3[i], "\0") == 0) // code3配列の最後まで探してもread_codeは無かった
				{
					strcpy( code3[i], read_code);
					data3[i] = read_data;
					break;
				}
				// 結論が出ないので次のdata3[i]をチェック
			}
		}

		fclose( fp_in);
	}

	// ファイル出力
	FILE* fp_out = fopen(argv[3], "w");
	if (fp_out == NULL)
	{
		fprintf(stderr, "Cannot open file %s\n", argv[3]);
		exit(-3);
	}

	for (int i = 0; i < 50; i++)
	{
		if( strcmp( code3[i], "\0") == 0)
			break;
		fprintf(fp_out, "%s %d\n", code3[i], data3[i]);
	}

	fclose(fp_out);

	return 0;
}

2014年11月29日 (土)

C言語で要素を数える

プログラム技術板スレ立てるまでもない質問はここで 139匹目において、C言語で要素を数えたいという話題があった。

文字列を引数とするハッシュを使いたいので、はっきりいってC言語で実装したくない。でも頑張って書いてみた。

// total.cpp : コンソール アプリケーションのエントリ ポイントを定義します。
//
#include "stdafx.h"

int _tmain(int argc, char* argv[])
{
	char label[50][5];
	int count[50];
	int last_index = 0;

	if (argc != 4)
	{
		fprintf( stderr, "Usage: %s inputfile1 inputfile2 outputfile\n", argv[0]);
		exit(-1);
	}

	for (int file_index = 1; file_index <= 2; file_index++)
	{
		FILE* fp = fopen(argv[file_index], "r");
		if (fp == NULL)
		{
			fprintf( stderr, "Cannot open input file %s\n", argv[file_index]);
			exit(-2);
		}

		char read_label[5];
		int read_count;
		while (fscanf(fp, "%s %d", read_label, &read_count)!=EOF)
		{
			for (int i = 0; i < last_index; i++)
			{
				if (strcmp(read_label, label[i]) == 0)
				{
					count[i] += read_count;
					goto next_loop;
				}
			}
			strcpy(label[last_index], read_label);
			count[last_index] = read_count;
			last_index++;
		next_loop:
			;
		}
		fclose(fp);
	}

	FILE* fp = fopen(argv[3], "w");
	if (fp == NULL)
	{
		fprintf(stderr, "Cannot open file %s\n", argv[3]);
		exit(-3);
	}
	for (int i = 0; i < last_index; i++)
		fprintf(fp, "%s %d\n", label[i], count[i]);

	fclose(fp);

	return 0;
}
入力ファイル1
0001 3
0002 11
0003 6
入力ファイル2
0003 2
0004 8
出力ファイル
0001 3
0002 11
0003 8
0004 8

2014年11月12日 (水)

テキサスホールデムの役を判定する

プログラム技術板スレ立てるまでもない質問はここで 139匹目において、テキサスホールデムというゲームがあることを知った。

レス番483で提案されてるのは、7枚のカードのうち2枚を決定し成立する可能性のある役を絞り込むというものだ。しかし、このアルゴリズムだと最外周ループが42周するというのを、どうやっても削減できない。

しかし、7枚のカードでフラッシュが成立するかを調べるのは難しくない。複数のフラッシュが同時に成立する可能性がないから。スイートごとに枚数をカウントして5を超えたら打ち切ればよい。

ストレートが成立するかどうかを調べるのも難しくない。6枚以上連続する可能性があるので、ロイヤルストレートが成立するかを調べるためにデータ構造を工夫する必要があるだろう。

あとは、ペア、スリーカード、フォーカードの数を調べれば役を判定できるはずだ。ここでは集計を簡単にするために、スリーカードはtwo_or_moreとthree_or_moreの両方にカウントするものとする。同様に、フォーカードは、two_or_more, three_or_more, fourの全てでカウントする。そうするとフルハウスは、three_or_more>=1 && two_or_more>=2で判定できる。

この方針で作成したプログラムを以下に示す。1000万回のループを0.8秒で抜ける。(Core i5-2500K, Windows 7 64bit, VisualC++ 2013, Release構成)

// texasholdem1.cpp : コンソール アプリケーションのエントリ ポイントを定義します。
//

#include "stdafx.h"

const int LOOP = 10000000;
const char SUITE_CHAR[] = "SHDC";
char* RESULT;

typedef enum
{
	SUITE_NONE = -1,
	SUITE_SPADES = 0,
	SUITE_HEARTS = 1,
	SUITE_DIAMONDS = 2,
	SUITE_CLUBS = 3
} suite_t;

typedef struct
{
	int number;
	suite_t suite;
} card_t;

// ストレートを判定するため、数字が5枚以上連続するカードの開始点と終了点を記録する構造体
// 13-1境界を処理しやすくするために、1=14,2=15……とみなし、endは13を超えることがある
// ストレートが成立しないときは、begin, endともに0とする
typedef struct
{
	int begin;
	int end;
} straight_range_t;

typedef struct
{
	int two_or_more;
	int three_or_more;
	int four;
} pair_count_t;

void get_card(card_t cards[])
{
	bool exist[13 + 1][4];
	for (int i = 1; i <= 13; i++)
		for (int j = 0; j < 4; j++)
			exist[i][j] = false;

	srand((unsigned int)time(NULL));

	for (int i = 0; i < 7; i++)
	{
		while (true)
		{
			int number = rand() % 13 + 1;
			suite_t suite = (suite_t)(rand() % 4);
			if (!exist[number][suite])
			{
				cards[i].number = number;
				cards[i].suite = suite;
				exist[number][suite] = true;
				break;
			}
		}
	}
}

void print_card(card_t cards[])
{
	for (int i = 0; i < 7; i++)
		printf("%2d ", cards[i].number);
	printf("\n");

	for (int i = 0; i < 7; i++)
		printf(" %c ", SUITE_CHAR[cards[i].suite]);
	printf("\n");
}

suite_t check_flush(card_t cards[])
{
	int suite_count[4] = {};

	for (int i = 0; i < 7; i++)
		if (++suite_count[cards[i].suite] == 5)
			return cards[i].suite;

	return SUITE_NONE;
}

void count_number(card_t cards[], int number_count[])
{
	for (int i = 0; i < 7; i++)
	{
		number_count[cards[i].number]++;
		number_count[cards[i].number + 13]++;
	}
}

void check_number(card_t cards[], suite_t suite_flush, int number_exist[])
{
	for (int i = 0; i < 7; i++)
		if (cards[i].suite == suite_flush)
		{
			number_exist[cards[i].number]++;
			number_exist[cards[i].number + 13]++;
		}
}
void check_straight(int number_count[], straight_range_t &straight_range)
{
	for (int i = 1; i <= 13; i++)
	{
		if (number_count[i] != 0 &&
			number_count[i + 1] != 0 &&
			number_count[i + 2] != 0 &&
			number_count[i + 3] != 0 &&
			number_count[i + 4] != 0)
		{
			straight_range.begin = i;
			if (number_count[i + 5] != 0)
			{
				if (number_count[i + 6] != 0)
				{
					straight_range.end = i + 6;
					return;
				}
				straight_range.end = i + 5;
				return;
			}
			straight_range.end = i + 4;
			return;
		}
	}

	straight_range.begin = 0;
	straight_range.end = 0;
}

void count_pair(int number_count[], pair_count_t &pair_count)
{
	for (int i = 1; i <= 13; i++)
	{
		if (number_count[i] >= 2)
		{
			pair_count.two_or_more++;
			if (number_count[i] >= 3)
			{
				pair_count.three_or_more++;
				if (number_count[i] >= 4)
					pair_count.four++;
			}
		}
	}
}

int _tmain(int argc, _TCHAR* argv[])
{
	card_t cards[7];
	get_card(cards);
	print_card(cards);

	clock_t start = clock();
	for (int loop = 0; loop < LOOP; loop++)
	{
		// 情報収集 開始
		suite_t suite_flush = check_flush(cards);

		// 数字ごとの枚数を保持する変数
		// 13-1境界を処理しやすくするために、数字+13のカードでもあるとして、2カ所でカウントする
		// カードの数字は1から始まるため、配列サイズに+1する
		int number_count[13 + 13 + 1] = {};
		count_number(cards, number_count);

		straight_range_t straight_range;
		check_straight( number_count, straight_range);

		// フラッシュを構成する数字が存在するかを保持する変数
		int number_exist[13 + 13 + 1] = {};
		straight_range_t straight_flush_range;
		straight_flush_range.begin = straight_flush_range.end = 0;
		if (suite_flush != SUITE_NONE)
		{
			check_number(cards, suite_flush, number_exist);
			check_straight(number_exist, straight_flush_range);
		}

		pair_count_t pair_count;
		// 初期化
		pair_count.two_or_more = pair_count.three_or_more = pair_count.four = 0;
		count_pair(number_count, pair_count);
		// 情報収集 終了

		// 役の判定 開始
		if (straight_flush_range.begin != 0)
		{
			// ストレートフラッシュは確定
			if (straight_flush_range.begin <= 10 && straight_flush_range.end >= 14) // 14=A
				RESULT = "Royal Straight Flush";
			else
				RESULT = "Straight Flush";
		}
		else if (pair_count.four == 1)
			RESULT = "Four of a Kind";
		// three cardもtwo_or_moreに含まれるので、フルハウスならtwo_or_moreは2以上になるはず
		else if (pair_count.three_or_more >= 1 && pair_count.two_or_more >= 2)
			RESULT = "Full House";
		else if (suite_flush != SUITE_NONE)
			RESULT = "Flush";
		else if (straight_range.begin != 0)
			RESULT = "Straight";
		else if (pair_count.three_or_more >= 1)
			RESULT = "Three of a Kind";
		else if (pair_count.two_or_more >= 2)
			RESULT = "Two Pair";
		else if (pair_count.two_or_more == 1)
			RESULT = "One Pair";
		else
			RESULT = "No Pair";
		// 役の判定 終了
	}
	clock_t end = clock();
	printf("%lf sec\n", ((double)end - start) / CLOCKS_PER_SEC);

	printf("%s\n", RESULT);

	return 0;
}

2014年5月21日 (水)

2ちゃんねるブラウザ BonBon Ver. 0.1

datへのアクセス禁止らしいので記事削除(2015年2月16日)

その他のカテゴリー