iPhoneの加速度センサを利用する - CoreMotion
iPhoneには加速度センサが搭載されていますが、その加速度センサは重力加速も感知してくれます。(加速度センサというのそういうものですか?よく分かりません...
その重力加速度を利用してiPhoneの傾き具合を測定して、バランスゲームみたいなのを土台を作ってみましょう 。
iPhoneの加速度センサ
詳しくはiOSイベント処理ガイドの第4章を見てもらえば分かると思いますが
こんな感じでどの方向に力がかかっているかを指定した感覚で測定してくれます。
図の様に、地面に対して垂直だとx,zは0でyは-1.0になります。重力加速度の最大はおよそ1.0のようです。
時計回りに倒すとxが1.0、yは0.0になります。これを利用して画面上の物体を傾きで動かしてみましょう。
CoreMotionの利用
iPhoneの加速度センサを利用するには、「UIAccelerometer」もしくは「CoreMotion」を用います。但し、UIAccelerometerは今後廃止が検討されているそうなのでCoreMotionを利用しましょう。
まず、CoreMotionを利用する為に<CoreMotion/CoreMotion.h>をインポートする必要があります。
見ての通り、やってることは簡単です。マネージャーを作って、加速度を測定する間隔をsetAccelerometerUpdateInterval:で設定します。次にsetAccelerometerUpdatesToQueue: withHandler:でハンドラーを設定します。
ここで設定したハンドラはCMAccelerometerDataを受け取って、その中に加速度の情報が入ってるという訳です。
dispatch_syncを行なっているのは、どうやらメインスレッドでないと物体(UIView)の表示位置を変更できないようなので利用しているだけです。そのようなことを行わないでしたらdispatch_sync,asyncは必要ないと思います。
傾きで円を動かしてみる
円を描画するUIViewを作成し、傾けた方向に移動し端に当たると跳ね返るようにしてみましょう。
ここで注意しないと行けないのがy軸の加速度。下方向がマイナスなのでそのままiPhoneの座標系に当てはめると上下逆さまになってしまいます。
これ使って何か作ってみたいな...
剰余を使わないFizzBuzz
3の倍数の時に"Fizz"と言って、5の倍数の時に"Buzz"と言って、15の倍数の時に"Fizz Buzz"っていう例の奴です。
class FizzBuzz { static public void main(String[] args) { FizzBuzz obj = new FizzBuzz(); for (int i=1; i<=100; i++) { String ans = (obj.fizz(i,0) && obj.buzz(i,0)) ? "Fizz Buzz" : (obj.fizz(i,0)) ? "Fizz" : (obj.buzz(i,0)) ? "Buzz" : Integer.toString(i); System.out.println(ans); } } boolean fizz(int num, int i) { if (num < i) return false; if (num == i) return true; return fizz(num, i+3); } boolean buzz(int num, int i) { if (num < i) return false; if (num == i) return true; return buzz(num, i+5); } }
美しくないですね〜
ニコ生アラート(素) for Mac
Growlの通知テストが上手く行ったので、何か作って見ようかなということで、シンプルなニコ生アラートを制作しました。
ニコ生アラートは、公式でFlashベースのものがありますが
・公式放送の通知が煩わし
・ポップアップが時間の経過で消える
・スリープなどでネットワークが切断されると、再起動しないと通知してくれない (← これは私の勘違いかもしれませんが...
など、少し不満があるので勉強がてらシンプルなものを作ってみることにしました。
このサンプル画像では色々な放送を表示していますが、本来は参加コミュニティのみです。
参加していないコミュニティも追加出来るようにしようかと思ったりもしましたが、私にはその必要が無かったので参加コミュニティだけです。
見ての通りGrowlで通知を行なっており、1.3を対象にしていますので、Growl1.3とLionが必要です。
ダウンロードはこちらから
※本ソフトウェアの使用によって生じたすべての損害・障害について作者は責任を負いません。
Growl SDK 1.3.1 clickContext Error?
先日書いたGrowlへの通知で、clickContextにnil以外のオブジェクトを設定するとコールバックを受け取ることができるのですが、コールバックを受ける通知をするとその通知が表示されて数秒後に「Got disconnected: Error Domain=GCDAsyncSocketErrorDomain Code=4 "Read operation timed out"」というエラーログが吐き出されます。ログが出るだけなので、無視したらいいのかもしれませんがやはり気になります...
あと少し厄介なことに、エラーが出るまでに素早くクリックするとコールバック関数が2度呼び出されてしまいます。この時は、エラーログが出ません。
また、ここに書かれているようにコールバックを受ける通知とそうでない通知(clickCotext:nil)を順番に行うと順番が入れ替わることがあるみたいですね。
通知する時に他に何かやらなくてはいけないんですかね? さすがに仕様ってことはないでしょうし...
Growlに通知してみるテスト
Growlとは
「Growl」を画像検索すると、少しドキッとする写真が出てきたりしますが、GrowlというのはMac OSでアプリケーションのイベントをデスクトップ上に通知してくれるアプリケーションです。
このように画面の前面に表示されます。ツイッターやメールのクライアントに組み込まれていたりします。
GrowlはMac OS X 10.6までは無料だったんですが、10.7(Lion)からは有料($ 1.99)になってしまいました。(それでも便利なのでダウンロードする価値はあるかと思います。
ダウンロード
GrowlはMac OSのアプリケーションということで、APIがCocoa(Objective-C)向けに提供されています。
早速、公式サイトからSDK(1.3.1)をダウンロードしてみましょう。ダウンロードページの下の方にリンクがあります。
開発者向けドキュメントはこのリンク から見れます。
フレームワークの追加
次は、フレームワークの追加です。先程、ダウンロードしたSDKの中のFramework->Growl.frameworkをプロジェクト内のFrameworksフォルダ内に持ってきます。コピーするか?というところにはチェックを入れておきます。
次に、プロジェクトファイル→ターゲット→Build Phasesと選択し、追加したGrowl.frameworkをCopy Filesのところに追加します。Copy Filesが表示されてなければ、右下のAdd Build Phaseから追加できます。
アプリケーションの登録
通知するまえにアプリケーションをGrowlに登録する必要がります。登録は手動で行う必要はなく、決められたプロパティリストを用意しておくとアプリケーションが起動した時に登録されます。
まず、プロジェクトに「Growl Registration Ticket.growlRegDict」というプロパティリストを追加します。.plist形式、.growlRegDict形式どちらにするか聞かれますが一応.growlRegDict形式にしておきます。作成されると、Xcode上では編集できないので、適当なテキストエディタで開きます。
このように辞書のキーとなるのは、TicketViresion, AllNotifications, DefaultNotificationsの3つです。TicketVersionは辞書のフォーマットを表していて、デフォルトで1です。AllNotificationsとDefaultNotificationsは、アプリケーションから通知される時のキーとなるようなものです。通知するときには、ここで設定した値が必要です。
実際に通知してみる
まず、AppDelegate.hでGrowlをインポートします。また今回の場合は必ずしも必要ではありませんが、プロトコルにGrowlApplicationBridgeDelegateを設定しておきます。このデリゲートでは、通知をクリックしたときなどにコールバックを受けとれます。
次は通知するコードです。とりあえず通知することだけが目標なので、コードはアプリケーションが立ち上がった時に呼び出される - (void)applicationDidFinishLaunching:(NSNotification *)aNotification の中に全て書いてしまいます。
まず、デリゲートを設定します。コールバックを必要としない場合は設定する必要もありません。
通知は、[GrowlApplicationBridge notifyWithTitle: description notification: iconData: priority: isSticky: clickContext:]メソッドで行います。
サンプルを実際に動かすと
こんな感じになります。notifyWithTitleとdescriptionは見ての通りですね。notificationNameは、プロパティリストに書いたAllNotificationsで設定した値でなければなりません。iconDataははおそらく画像の表示です。priorityは-2~2の範囲で設定し、おそらく通知が多すぎて表示できない時の優先度だと思います。isStickyはYESにすると、クリックされるまで表示されつづけます。clickCotextはクリックされてコールバックするときに返される値です。
さて、通知も上手く行ったんでなんか作ってみるかな
SRM 535 Div2 500
SRM 535 Div2 500点の問題
内容は、最大公約数(G)と最小公倍数(L)が入力として与えられ、それを満たす2つの数字を足しあわせて最低となる値を返せ(なければ-1)というもの
簡単な例は、最大公約数が2で最小公倍数が20だとしたらそれを満たす組みは{2, 20}と{4,10}があって、4+10=14の方が小さいので答えは14となる
そして、無理やり書いたのがこのコード
public class FoxAndGCDLCM { public long get(long G, long L) { long a,b; a = G; b = L; long min = -1; while(a <= b) { if (L % a == 0) { b = (L / a) * G; if (gcd(a, b) == G) { if (min == -1 || min > a+b ) { min = a+b; } } } a += G; } return min; } long gcd(long low, long high){ if (low == 0) return high; return gcd(high%low, low); } }
正直、解き方が全く分からなかった...
数学の出来なさを改めて痛感
ちなみにこのコードはrun system testを通過できない
あまりにも大きい値はタイムアウトしてしまう
解き方が全くわからないなりに少しは考えてみた
例のG=2とL=20を満たす組みである{2,20},{4,10}について考えてみるとする
組みとして出てくる値は、最大公約数が2となるためには当然どちらも2の倍数の必要がある
次に、最小公倍数が20であるためにはどちらも20を超えてはいけない
単純に総当りで調べようとしたら、どちらの値も2→4→6→...→n×2とずらして各組み合わせのGとLが一致するか調べる方法がある
しかし、GとLの範囲が1~10^12となっていて大きい値だと2秒以内に結果を返すのは不可能である
結果的にタイムアウトしてしまってはいるが、少しでも処理をすくなくする為に、小さい値の方aを基準に1重のループで考えた
{4,10}と{10,4}は同じ扱いなのでaが大きい値bを超えたら繰り返しを終了とする
次に、aがLの約数になるときだけ可能性があるので検査する
ここでbの求め方が分からなかったのだが、{4,10}をじっくりみると20(L) / 4(a) = 5, 5 * 2(G) = 10(b)という関係が偶然にも見えてきた
ただの偶然なのか{2,20}でも試してみると成り立っている
後で知ったのだが、G * L = a * bという関係が成り立つそうだ
先ほどの式からb = L / a * Gでbを求めて、a+bが以前の値より小さければ最小値を更新するようにした
これで上手く行ったかのように思えたが、{a,b}の組みが何故かG,Lを満たしていいない時があるのだ
そこで最大公約数が正しいか判定するようにしている
これで、時間はかかるが一応正しい答えが得られるようにはなった
このコードは、Lが大きくGが小さい時にステップ数が増えて、更にLが割り切れやすい数だとbや最大公約数を求めるのにもの凄くの時間を必要とするのが分かる
しかし、解決策が思い当たらないので点数が高い人のコードを見て見ることに
import java.util.*; public class FoxAndGCDLCM { public long get(long G, long L) { int answ = 0; if (L % G != 0) { return -1; } long least = L / G; long minSum = Long.MAX_VALUE; long sqrt = (long)Math.pow(least, 0.5); for (int i = 1; i<=sqrt; i++) { if (least % i == 0) { long tmpSum = least / i + i; if (minSum > tmpSum && euclid(least/i, i) == 1) { minSum = tmpSum; } } } return minSum * G; } public static long euclid(long a, long b) { if (b == 0) { return a; } else { return euclid(b, a % b); } } }
まず、least = L / Gというのは何を表しているのだろうか?...
least / i + iという魔法のような式はなんなのだろうか?...
というか私の書いたコードはアルゴリズムというか、手順を書いただけのものですよね,,,
こういうのってアルゴリズムのパターンをひたすら覚えるのか、数学的知識を身につけるべきなのか...
何より地頭が悪すぎるorz
TopCoderに参加しよう(プラクティス編)
TopCoderというのはTopCoder社が開催してる競技プログラミングコンテストです
プログラミングコンテストと聞くと、難しそうなイメージがあるかと思います
私も、以前「CODE VS」というのにチャレンジしてみようと思いましたが、ちゃんとしたコードを実際に走らせるまでかなり苦労し、問題も今の実力では解くことが出来ませんでした
TopCoderは初心者でも出来る
TopCoderは問題、解答、提出が一体となったクライアント(Java Applet)で提供されているので簡単に解答、提出ができます
問題も、文字列の並び替えといった非常に簡単なレベルからあるので初心者でも解くことができます
競技では、制限時間以内に3つのレベルの問題を解いて、その速さを競うものなので1つずつの問題が関数を1つ作るというシンプルなものです
参加準備
まずは、TopCoderのトップページの右上にあるRegisterからアカウントを作成します
次に、TopCoderのコミュニティサイトの左側にあるカテゴリから「Competitions」→「Algorithm」→「Single Round Matches(SRM)」→「Launch Arena」の順に選択するとアプレットが立ち上がるらしい?です
私は、Macを使用しているのですが、どのブラウザでもうまく起動出来なかったので下記のサイトで直接アプレットを手に入れました
実際に問題を解いてみる
アプレットが立ち上がると、このような画面が出てくるので先ほど登録したユーザネームとパスワードを入力しGOをクリック (コネクションはDirectで問題ないと思います
ログインするとチャットルームに繋がります
ここで上のメニューバーにある「Practice Rooms」→「SRMs」→「適当な数字」 →「SRM ◯◯ DIV 2」を選択し、問題がある部屋に進みます
SRMというのは、先程説明した短い時間の間に問題を解くという競技のことで、そのあとの三桁の数字は第◯◯大会ということを表していて、その大会で出された問題を解くことが出来ます
そしてDIV 2というのは、ディビジョン2すなわち2部ということで、競技の結果で上位の人はDIV 1に配属されより難しい問題をとくという事になっているそうです
初心者含め大多数の人はDIV 2となるようなのでここではDIV 2を選択します
プラクティスルームに入ると、画面中央に「Select one」と書かれたプルダウンメニューがありますが、それをクリックすると3つの数字が表示されます
これは問題の点数を表しいて、高いほど難しい問題です
まず最初は一番点が低いものを選びましょう
問題を選ぶと、このような感じの新しいウィンドウが開きます
上側のテキストフィールドには問題の詳細が書かれていて、下側にコードを入力する形になっています
問題はもちろん英語なのですが、心配するほどのものではありません
「Probrem Statement」に問題の概要が書いてありますが、あまりしっかりと読む必要はありませんし、どうしても分からなければ翻訳サイトにぶち込めば雰囲気は理解できるでしょう
その下の「Definition」というのが重要で、ここで指定したクラス名やメソッド名、引数と返り値の型を守らなければいけません
次に、「Constraints」で引数の値の範囲などが書かれ
「Examples」では、入力に対してどのような与えを返せば正解なのかという例が書かれています
その為、最初の問題文が分からなくても、それほど難しい問題でなければ「Examples」を見ることで理解することが出来るはずです
コードの入力が完了したら、右下のコンパイルを押して、それが成功したらテストを行いましょう
右下のテストを押すと、ウィンドウが出てくるのでそこからExample ◯を選ぶと、先ほどの「Examples」に書かれていた例を実行することができます
全て成功したら、サブミットしましょう
サブミットを行うと点数が表示されます
暇つぶし程度に
今回の例は、あくまでも練習問題なのでコンテストとは言えませんが初心者でも簡単に問題にチャレンジできるのがいいと思います
もしこれで興味を持ったなら週一ぐらいで開催されている大会に参加してみて、自分のプログラミングスキルを測ってみてはどうでしょうか
私も、参加してどれぐらい出来るのか試してみるつもりです
スケジュール→TopCoder部