MikuMikuWatch製作記

この記事は「coins Advent Calendar 2014」の14日目の記事です。

AdventCalendarから来られた方のために簡単に自己紹介します。
ねぎです。3編生です。概念としての初音ミクが好きです。

What is "MikuMikuWatch" ?

MikuMikuWatchとは、開発中のAndroid Wear向けアプリケーションです。
腕時計型の端末の画面上に、時計と一緒に初音ミクを映します
→ 日常生活の中でふと時計を見ると、初音ミクが生活している様子が伺えます
→ 幸せになります
→ やったぜ。

製作記

  • 10月初頭、ひらめいた



  • ゴリゴリ実装する


(ドット絵なのは自分がドット絵じゃないとまともに描けないからです)
時間帯によって絵が変わります

  • 権利的にはクリプトンファミリーいけるんだよな…


製作で困ったポイント




初音ミクというのは外見と声以外の公式設定がほぼ存在せず、1人1人が考える初音ミクというのには差異があります。
そのため、このアプリで初音ミクの1日を描くというときに、「これは自分が考える初音ミクであって、真の初音ミクではないのではないか…?」という疑念と葛藤に襲われました。
(考えている本人は大真面目です)
最終的に、このアプリに登場する初音ミクは自分が考える初音ミクであると割り切りました。

  • 圧倒的絵心不足
    • 320x320というキャンパスに対して32x32のドット絵を貼り付けていくスタイル
    • 描いていくうちに絵柄が変わってきて昔のを描き直したりしてるとつらいことになった

現状

  • プログラムはほぼ完成しました
  • 絵を描く時間とスピードが足りないッ…!
  • ということで製作停滞中。描ききったらGoogle Playに出したいです
  • (2015/7/25追記) Google Playで公開しました

https://play.google.com/store/apps/details?id=negi.magnet.mmw


おわりに

  • 初音ミク最高
  • この記事を書くにあたって精神的な協力をして頂いた以下の楽曲に感謝します

ハル研プロコン2014参加記

ハル研究所プログラミングコンテスト2014に参加してました
400万点の壁を超えられなかった(かなしい)

工夫点

Uターンするような蓮の配置のとき

  • 定期的に加速していると蓮を通りすぎてしまうことがあり、大きなロスになる(先輩忍者がよく通り過ぎてる)
  • 蓮を踏んだ瞬間に次の蓮の方向へ加速することで、Uターン時のロスを最小限に
  • Uターンしない時も踏んだ瞬間に加速していると勿体無いことがあるので、角度によって加速するか場合分けした
  • かなり効果があった

なるべく内側を掠めるように蓮を踏む

  • 去年もやったなーとか思いつつ。それなりに効果があった

先輩忍者との衝突回避

  • 邪魔なんだよ先輩!
  • 数ターン後の位置まで推定して、このままの速度で進むと衝突しそうなら角度を最小限だけ変えて回避するように実装した
  • わりと実装がんばったけど使わないほうがスコアが良かったので使わなかった(つらい)

最初にスタートダッシュ

  • 最初は先輩が全力疾走するので、1つ目の蓮のあたりで先輩同士が衝突し合って非常にごたごたする
  • ゆっくり行ってごたごたに巻き込まれるより、サッと踏んでサッと次に向かった方がいいのでは? ということで実装
  • ただし加速回数を大きく消耗するので、初期配置的に2つ目の蓮にサッと向かえなさそうなら止めたり、1つ目までの距離が長いときは止めるようにしてある
  • 若干の効果があった

余裕があったら加速

  • ゴール時に加速度が残っているのは勿体無い。MOTTAINAI
  • 残りの蓮の数を計算し、加速回数に余裕がありそうなら加速頻度を高めた
  • 主に小規模なコースで効果を発揮

場の流れの考慮

  • 単純に目標地点から引いてみたらいい感じに動いたのでそうしておいた

javascriptとSPARQLでオープンデータをいじくる

オープンデータ・アプリコンテストが気になったので、とりあえずjavascriptからSPARQLを使ってオープンデータで遊んでみました

SPARQLってなんぞや

SPARQLはクエリ言語で、データベースを扱うためのSQLと似たようなものです。
SQLがデータベースを操作するなら、SPARQLはオープンデータを操作します。(SPARQLは検索だけですが)

文法とかについては割愛しますが、なんとなく雰囲気を掴むならCodeIQの問題が分かりやすかったです。
がっつり学ぶなら公式ドキュメントの和訳サイトでしょうか。
あと、SPARQLで遊びたいだけならDBpediaとかがあります。

javascriptからSPARQLを使うには

SPARQLは、エンドポイントと呼ばれるURIにGETリクエストでクエリを送りつけると、クエリに応じたjsonとかxmlとか(指定可能)が返ってきます。
あとはjavascriptの方でjson(またはxml)を解析することでオープンデータとキャッキャウフフできます。

最小限のサンプルコード

javascriptでSPARQLのクエリを鯖江市のエンドポイントに送り、返ってきたjsonをそのまま文字列として表示します。
鯖江市が提供しているオープンデータについては、こことかここを参考にしています。
(※GRAPHについてはいまいち分かってないです)

<!DOCTYPE html>
<html lang="ja">
<head>
	<meta charset="UTF-8">
	<title>sparql</title>
	<script type="text/javascript" src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
	<script type="text/javascript">

	// GETリクエストを送信
	$.get(
		"http://sparql.sabae.jrrk.org/data/sparql",	// エンドポイント
		{query:"\
			PREFIX schema: <http://schema.org/> \
			SELECT ?desc ?img \
			WHERE { \
			GRAPH ?g { \
				?id schema:description ?desc. \
				?id schema:image ?img. \
			} \
			} limit 20 \
		"},	// クエリ(説明文と画像を最大20件まで要求)
		success,	// 返ってきたデータを処理する関数
		"json"	// 返ってきてほしいデータの形式
	);

	// getリクエストで得たdataを処理する
	function success(data) {
		// 文字列に変換
		var html = JSON.stringify(data);
		// そのまま表示
		$("#disp").html(html);
	}

	</script>
	</head>

	<body>
		<div id="disp"></div>
		<p>このアプリケーションは、以下の著作物を改変して利用しています。<br>
鯖江市、さばかん、クリエイティブ・コモンズ・ライセンス 表示 2.1 日本(http://creativecommons.org/licenses/by/2.1/jp/)、オープンデータ・アプリコンテスト利用規約(http://www.opendata.gr.jp/2013contest/terms/index.html#rules)</p>

	</body>
</html>

「{"head":{"vars":["desc","img"]},"results":{"bindings":[{"desc":{"type":"literal","value":"店主が毎朝市場へ…」みたいな文字が出たらうまくいってます。きっと

jsonを解析して体裁を整えたバージョン

success関数の中身を書き換えます。
tableを使って体裁を整えるのと、取得した画像パスから画像を表示します。

function success(data) {
	var head = data.head.vars;
	var results = data.results.bindings;
	var html = "<table>";

	for(var i=0; i<results.length; i++) {
		html += "<tr><td>";
		html += results[i].desc.value;
		html += "</td><td>";
		html += "<img src=\""+results[i].img.value+"\"></img>";
		html += "</td></tr>";
	}
	html += "</table>";
	$("#disp").html(html);
}

上記コードによって出来たのがこちら
(追記:上記リンクのプロトコルhttpsにしていたため表示できないバグがありましたが修正しました)

ハル研究所プログラミングコンテスト2013参戦記

ここ1ヶ月ぐらい「ハル研究所プログラミングコンテスト2013」に参加してました
締切時のスコアは410万点ほどで、27位ぐらいでした(うろ覚え)

<基本方針>

貪欲法です。以下の動作をInit関数内で済ませます
1.まだ選んでないゴミの中で、現在地から最も少ないターン数で到達できるゴミを選ぶ
2.選んだゴミを記録し、現在地をさっき選んだゴミの位置に更新する
3.まだゴミがあるなら1に戻って繰り返す

<穴の対処方法>

現在地と目標のゴミの位置を結ぶ線分の式を作り、全ての穴に対して交差判定を行います
交差していた場合、下図のように中継点を作り、迂回します
また、現在地と中継点を結ぶ線分、中継点と目的のゴミの位置を結ぶ線分に対しても同じ処理を行います
これにより、複数の穴があっても華麗に避けてくれます(たぶん)
詳しくは下の資料で


<ちょっとした工夫>

ゴミとルンバ自機には半径があり、少しでも触れていれば拾ったことになります
そのため、下図のように動き、ちょっとだけショートカットを図っています

f:id:negi_magnet:20140108221401p:plain

<試したけど使わなかったアルゴリズム>

ユークリッドTSPの近似解法
 回転にターンが必要なければユークリッドTSPの近似解法を適用できると思い、とりあえず作ってみました
 380万点ぐらい止まりだったのでボツ
 やはり回転をいかに抑えられるかが勝負所…?

・n個のゴミを最小ターンで取れるようにゴミを選ぶ
 貪欲法よりはマシかなーと思ってたらnを増やすほどスコアが減りました


こんな感じでした。楽しかった(小並感)
上位陣のアルゴリズムが知りたい…

DXライブラリで多角形を描く (with C++サンプル)

DXライブラリで2Dゲーム作ってるときに、多角形を描く必要が出てきました
しかし、DXライブラリには三角形を描画する関数ならありますが多角形を描画する関数はありません
ということで、多角形を三角形に分割して描くことにしました

どうやって多角形を三角形にするのか?という理論については、こちらのサイトが分かりやすかったです。無断リンクお許しください
Javaゲーム制作記 任意多角形の三角形分割

以下、C++のサンプルコードです
タイトルからDXライブラリって描いてましたが、描画部分を変えれば他のライブラリでも使えます(多分)
なお、このコードは辺と辺が交差していない多角形でのみ使用できます。注意

// ベクトル構造体
struct t_vector{
	double sx, sy;
	double vx, vy;
};

// p1からp2へ伸びるベクトルを生成
t_vector makeVector( pair<double,double> p1, pair<double,double> p2 ){
	t_vector v;
	v.sx = p1.first;
	v.sy = p1.second;
	v.vx = p2.first - p1.first;
	v.vy = p2.second - p1.second;
	return v;
}

// v1とv2の外積を計算
double cross( t_vector v1, t_vector v2 ){
	return v1.vx*v2.vy - v1.vy*v2.vx;
}

//----------------------------------------------------------
/// @brief	点の集合vの中で、v1,v2で構成される三角形内部に点があるか確認する
/// @param	v1,v2 : 三角形を構成するベクトル。始点が同じである必要あり
///		v : 点の集合
/// @return	1つでも含まれている→true, ない→false
//----------------------------------------------------------
bool IsExistPointInTriangle(t_vector v1, t_vector v2, vector< pair<double,double> > &v){
	// v2の向き反転
	v2.sx += v2.vx;
	v2.sy += v2.vy;
	v2.vx *= -1;
	v2.vy *= -1;
	// v1の先端からv2の後端に伸びるベクトルv3生成
	t_vector v3;
	v3.sx = v1.sx + v1.vx;
	v3.sy = v1.sy + v1.vy;
	v3.vx = v2.sx - v3.sx;
	v3.vy = v2.sy - v3.sy;
	// 全ての点について、ベクトルv1~v3の左右どちらにあるか判定していく
	t_vector *vn[3] = {&v1, &v2, &v3};
	for(int i=0; i<v.size(); i++){
		t_vector vp;
		bool outside = false;
		for(int j=0; j<3; j++){
			vp.sx = vn[j]->sx;
			vp.sy = vn[j]->sy;
			vp.vx = v[i].first - vp.sx;
			vp.vy = v[i].second - vp.sy;
			if( cross( *vn[j], vp ) >= 0 ){
				outside = true;
				break;
			}
		}
		if( !outside )
			return true;
	}
	return false;
}

// 三角形構造体
struct t_triangle{
	double x[3], y[3];
};

//----------------------------------------------------------
/// @brief	点の集合vで表される多角形を三角形分割し、trisに格納する
/// @param	v : 多角形を作る点の集合vector。辺が繋がっている順番である必要あり
///		tris : 生成した三角形を格納するvector
///		v,trisとも、pairのfirstがx座標を、secondがy座標を表す
//----------------------------------------------------------
void SplitTriangles(vector< pair<double,double> > v, vector<t_triangle> &tris){
	// 三角形が作れなくなるまで繰り返す
	while( v.size() >= 3 ){
		// 原点から最も遠い点を探す
		int mfar = 0;
		for(int i=1; i<v.size(); i++){
			if( v[mfar].first*v[mfar].first+v[mfar].second*v[mfar].second < v[i].first*v[i].first+v[i].second*v[i].second )
				mfar = i;
		}
		// 最も遠い点から伸びる2つのベクトルを生成
		t_vector v1, v2;
		v1 = makeVector( v[mfar], v[(mfar+1)%v.size()] );
		v2 = makeVector( v[mfar], v[(mfar+v.size()-1)%v.size()] );
		// 参考元ではここで180度判定をしていたが、特に必要ない気がするので、はしょる
		// 三角形内部に点があるとき
		if( IsExistPointInTriangle(v1, v2, v) ){
			// 外積の記録
			double cr = cross( v1, v2 );
			// 見つかるまでループ
			while(1){
				// 1つ横の点を選ぶ
				mfar = (mfar+1)%v.size();
				// ベクトル生成
				v1 = makeVector( v[mfar], v[(mfar+1)%v.size()] );
				v2 = makeVector( v[mfar], v[(mfar+v.size()-1)%v.size()] );
				// 外積の符号が異なる→ループ最初に戻る
				if( cr*cross(v1,v2) < 0.0 )	continue;
				// 内部に点があるか確認
				// 点がある→ループ最初に戻る
				if( IsExistPointInTriangle(v1, v2, v) )	continue;
				// 点がない→脱ループ
				break;
			}
		}
		// 三角形の3点を_trisに記録
		t_triangle t;
		t.x[0] = v1.sx;		t.y[0] = v1.sy;
		t.x[1] = v1.sx+v1.vx;	t.y[1] = v1.sy+v1.vy;
		t.x[2] = v2.sx+v2.vx;	t.y[2] = v2.sy+v2.vy;
		_tris.push_back(t);
		// 選ばれた点をvから除外
		v.erase( remove( v.begin(), v.end(), v[mfar] ) );
	}
}

// 描画はこんな感じで
void Draw(){
	for(int i=0; i<tris.size(); i++){
		DrawTriangle(
			tris[i].x[0], tris[i].y[0],
			tris[i].x[1], tris[i].y[1],
			tris[i].x[2], tris[i].y[2],
			GetColor( 255, 255, 255 ),
			TRUE
		);
	}
}

IWIP2013参加記

8/28~29に長野で開催された「革新的プロジェクトに関する国際会議(IWIP2013)」に参加してきました

IWIP2013とは

  • 全国の高専生と東南アジアの学生が集まってプレゼンしたりレゴ作ったりする集まり
    • プレゼン…発表10分+質問5分、全部英語、テーマはわりと何でもあり(?)
    • レゴ(ワークショップ)…各国ごちゃまぜのチームでレゴブロック組み立ててトーナメント

参加記

日付 出来事
5/17 研究室のボスからIWIPの開催を知らされる
行くべきという直感に従って参加希望する
5/30 希望者が定員ジャストで参加が決定する
参加表明に後悔を感じ始める
6月中 概要締切と編入試験と中間テストで瀕死
本格的に参加を後悔する
7/28 学校紹介ポスターの作成依頼が来る
(^q^).o(めんどくせぇ…)
8/20 IWIPに向けた合宿開始
学校22時縛り&寝床が野球部と同じ(うるさい)でストレスがマッハ
8/27 長野に出発、参加登録
明日学校紹介プレゼンしてねと唐突に言われて内心ブチギレ
8/28 IWIP1日目、プレゼンとか
8/29 IWIP2日目、突然の寺参りイベント
8/30 帰宅

…まあ、色々ありましたが、結果的には参加して良かったと思います
高専高専生と話せてよかったです
英語にも若干慣れた気がします
他にも色々あるって多分

発表内容

卒業研究でやってることについて発表しました
空の画像から数分後の日射量を予測するという研究です
諸事情によりスライドはアップロードしてません

編入キメた

現在高専5年生なんですが、大学に編入することにしました
その編入生活が一段落ついたのでまとめます

結果から言うと、筑波大学 情報学群 情報科学類に編入できることになりました

受験校

第一志望 筑波大学 情報学群 情報科学

結果:合格
試験内容とか、勉強内容についてはこちらに→ http://kosen.herokuapp.com/stories/71

第二志望 電気通信大学 情報理工学部 情報・通信工学科

結果:合格
試験内容とか、勉強内容についてはこちらに→ http://kosen.herokuapp.com/stories/65

第三志望 豊橋技術科学大学 情報知能工学課程

結果:合格
ぶっちゃけると滑り止めです

編入勉強生活

勉強期間は6ヶ月ぐらい
勉強し始めたのは4年の12月、冬休みに入ったぐらいからです
この頃には筑波と電通大に決めてたので、数学を中心に、物理、英語(TOEIC)を勉強していました

勉強量については普通より少ないような気がするので、参考にしない方がいいです
試験1ヶ月前ぐらいまで普通にtwitterしてたからな