paizaの恋愛SLGの水着とサンタ服がゲットできない……


先日、paizaからプログラミングで彼女を作るゲームが発表されました。
恋愛SLG: プログラミングで彼女をつくる|paizaオンラインハッカソン7
参考:プログラミングさえできれば誰でも彼女がつくれる恋愛シミュレーションゲーム「プログラミングで彼女をつくる」 – GIGAZINE

内容は出題されたプログラミングの問題を解くと、その問題にあわせて彼女用のパーツや衣装をゲットできるというもの。

とりあえずコツコツやって、全部ゲットできたらブログに「彼女ができました」というエントリーでも書こうかと思ったのですが、何度やっても「水着」と「サンタ服」をゲットできないでいます。どちらも、提出前動作確認では合格するのですが、テストケースで失敗します(サンタ服のほうなんて、テストケース3までは合格しますが、4で失敗します)。テストケースはデバッグできないのでほとほと困っています。

試したコードは下記です。

これを実際にブラウザ上で動作するようにしてみたのが下記のページ
paizaのサンタ服と水着ゲットチャレンジ

水着ゲットチャレンジで38を入力すると742912となりますし、サンタ服ゲットチャレンジで問題ページの入力例2を入力すると240になり、何が間違っているのか全く分からないでいます。環境がNode.jsとブラウザ(Chrome)で違うというのがあるのかもしれませんが、paiza.IOでもうまくいっているように見受けられるので、多分環境が原因ではないと思います。

誰か失敗する原因が分かる方はヒントを教えて下さい(失敗するテストケース等)。

amazonの「持っています」に登録するブックマークレット作った


どうもいまだに、『amazon 持っています』と検索すると、このブログの過去記事が上位に表示されるようです(amzon 持っています – Google 検索)。
過去記事:amazonの「持っています」にチェックを入れる3つの方法 | while(isプログラマ)

ただし、上記記事を書いた時と今では登録方法が異なっています。いや、異なっているというより正確には減っています。上記ページで3種類の登録方法を書きましたが、うち2種類が現在使えなくなっています。1ヶ月ぐらい前まではウィッシュリストに入れて削除すると持っていますのチェックがでるので、それにチェックを入れると登録することができたのですが、それも無くなりました(参考:アマゾンの「持っています」登録方法: アマゾンの「持っています」登録が変更された!)。これにより、おすすめ商品に表示されている商品しか「持っています」に登録できなくなってしまいました。

これは正直困ります。困ったすえ、試行錯誤して、「持っています」に登録するブックマークレットを作ってみました。
ブックマークレット:持っています登録

使い方は簡単。上記リンクをブックマークバーにドラッグ&ドロップするか右クリックしてブラウザのお気に入りに登録します。その後、持っていますに登録したいamazonの商品ページに移動して、このブックマークをクリックすると、「持っています」に登録します。成功すれば、『登録しました』というアラートが表示されます(といっても、ログインしてなくても『登録しました』と表示されるので、後で「持っています」にチェックを入れた商品のページで確認したほうがいいです)。なお、削除機能はありません。削除は「持っています」にチェックを入れた商品ページで行ってください。

具体的なコードは下記のとおりです。

見て分かるとおりjQuery依存となっています。もし、amazonがjQueryを利用しなくなったらこのブックマークレットは利用できなくなります。後、amazonの仕様が変更されたら利用できなくなる可能性は十分あります。

それにしても何で、おすすめ商品に表示されてる商品しか持っていますに登録できなくなったんだ……。まあ、おすすめ機能だけ利用されて、商品を買うのは別の場所というのはamazonに利益がありませんしね(自分のことです……)。そもそも、これまでの流れからして、『持っています』の機能が無くなるんじゃないかと思わなくもないです。

JavaScriptでlocationオブジェクトのようなオブジェクトを作成する関数を作ってみた


locationオブジェクトは現在表示しているページのURLの情報を含んだオブジェクトです(参考:window.location – Web API インターフェイス | MDN)。

ただ、リファラ(document.referrer)のように、自身のページ以外のURLもlocationオブジェクトのような情報を取得したいと思ったので、試しに作ってみました。正規表現使ったらもっと簡素にできるかもしれませんが、地道に検索して抜き出して……という感じで作っていきました。

引数にURLやパスを入れるとlocationオブジェクトのようなオブジェクトを返す関数です。ついでに、GETパラメータもオブジェクトとして取得するようにしています(参考:JavaScriptでGETパラメーターを取得する – Qiita)。

試しに、node.jsで”http://amyu.localhost:9000/hogehoge/index.html?a=a&b&c=c#zzz”というURLにアクセスできるようにし、locationオブジェクトと今回作った関数を比較してみました。開発者ツールのコンソールでcopyコマンドを利用し、それをペーストした結果です。

順番が異なっているのでわかりづらいですが、あってるようです。

ところで、今回この関数を作るにあたって、相対URLでも絶対URLに変換したうえで取得するようにしよう。そうすればaタグに記述している相対URLの情報も取得できるし。と思って調べたらaタグのhrefプロパティを取得すれば相対URLを入れていても絶対URLで取得できるということが分かりました(参考:JavaScript – 相対URLを絶対URL(URI)に変換する方法について – Qiita)。

なんだ、そんな簡単に相対URLを絶対URLに変換できるんだー! と驚きました。ただ、ここで試しておくべきだったんです……。a要素のプロパティに『hostname』や『pathname』があるのかどうかということを……。そうです。上記みたいな関数を作らなくても、a要素のプロパティにあるようなんです……。さっき知りました……。

参考:Location – Web API インターフェイス | MDN

まだまだJavaScriptは知らないことがあると実感しました。

JavaScriptで頭に!!をつけるとfalseになる値とNaNの挙動について


今年はやりたいことがあるので、少し更新頻度落とします(といっても、2週間以上も空けるつもりはなかった・・・)。

JavaScriptでは、頭に!をつけるとその値を否定したブーリアン値になります。例えば下記のような感じです。

そしてさらにその値に!を着けたら否定の否定なので、!をつけてtrueのものはfalse、falseになるものはtrueとなる。つまり、頭に!!をつけて得た値は、Booleanメソッドを使った場合と同じ結果になる。

で、本題ですが、JavaScriptで演算子を使わない値(プリミティブ値)で、頭に!!をつけてfalseになる値は、false,数値の0,空文字,null,undefined,NaNの6種類だけです。

これ以外の演算子を使わない値はすべてtrueになります。一見、falseになりそうな空オブジェクトや空配列、Infinityや文字列の”0″はtrueになります。

さて、ここで演算子を使わない値を限定しました。なぜなら、演算子を使うとキリがないからです。一応、例を少しあげると下記のような値(というより、演算子をつけてるので式といったほうがいいかもしれません)が頭に!!をつけるとfalseとなります。なお、今回はわざわざ頭に!!をつけていますが、比較演算子(>や<、二つ以上つづく=の演算子)を使った式の場合、!!を使わなくても結果はBoolean値になります。

さて、ここで「あれ?」となった人もいるかもしれません。自分も先日、「あれ? 何でだ?」と思って記述ミスがないか見なおしてみましたが、どこも間違ったところはありませんでした。どうやら、NaN同士を==や===で比較した場合、結果はfalseとなるようです。 参考:NaN – JavaScript | MDN

例えば下記のようなcheckNaNという関数を作った場合、引数にNaNをいれても”NaNじゃない”という結果になってしまいます。

NaNかどうか調べたいときは、isNaNメソッドを使ってNaNかどうかを調べるのがよさそうです。

ここで、trueやnullがNaNじゃないとなっているのは、true-0が1、null-0が0になるからです。今回はわざわざ値から0を引いて数値変換していますが、実はそんなことをしなくても同じ結果になります。

これじゃあ困るという場合は、同じ値を同値比較した場合にfalseになるのがNaNだけというのを利用して、下記のようにすると、引数がNaNの場合だけが”NaNです”となります。

非常にわかりづらいので、こういう手法を取るときはコメントを書いたほうがいいと思います。というより、できるだけ使わないようにするのがいいと思います。

ところで、NaNはなぜ同値比較するとfalseになるのか理由を考えると、例えば、『”aiueo”-0』と『”abcde”-0』の比較は等しくなってほしくないからじゃないかと思いました(実際のところどうしてか分かってません)。で、そこで、Infinity(無限大)はどうなんだと思いました。結論からいうと、Infinity同士の比較はtrueになります。なので下記の比較はすべてtrueとなります(Infinityになる値は右記を参考:【Javascript】0で割ると? at softelメモ)。

少し違和感があるかもしれませんが、こういうものだと思いましょう。

JavaScriptでのアニメーション処理に最適化したrequestAnimationFrameを使ってみた


ああけましておめでとうございます。年が明けて1週間以上経過しましたが、今年初のエントリーです。最近、ブログのネタが思い付かないし、書く気力も湧きません・・・。
ただ、今までは一週間に一度は書くということを目標につづけてきましたが(守れてない時も多いですが・・)、今年は書きたい時に書くという方針で行こうと思います。
そもそも、本で知った内容をブログにメモ代わりに書こうと思ったら、うまく再現できないということが多いんですよね・・・。「うまくいきませんでした」と書くのもなんなので、そういう時は試行錯誤したうえでブログに書いてません。

前置きはこのぐらいにして本題。

JavaScriptでアニメーションを行おうとした場合、ライブラリを使わないのであれば、setIntervalやsetTimeoutメソッドを使うことになると思いますが、最近のブラウザではrequestAnimationFrameという名前のとおりアニメーションに最適化した(といっても、アニメーション以外にも使えますが)メソッドがあると知って試しに使ってみました。

簡単に説明すると60fpsの間隔で引数のコールバック関数を実行するメソッドとなります。setTimeoutの第二引数を1000/60とした時とほぼ同じですが、requestAnimationFrameはアクティブでないタブやウィンドウでは処理しなかったり、描画処理の準備が整っている場合にだけ実行するなど、アニメーションに最適化した処理を行うことができるメソッドとなっているようです。なお、60fpsと書きましたが、実際にはコールバック関数内でrequestAnimationFrameを呼ばなければ次の処理は実行されません(つまり、動き的にはsetIntervalではなく、setTimeoutと同じ)。なので、正確には1/60秒後に引数のコールバック関数を実行するメソッドといったほうが正しいかもしれません。
参考:window.requestAnimationFrame – Web API インターフェイス | MDN

というわけで、実際に使ってみました。内容は、直径100pxの赤い丸が1辺の長さが500pxの四角いコンテナ内を右下左上の順番に5pxずつ動くようなアニメーションです。

HTML

CSS

JavaScript

実行結果:requestAnimationFrameのテスト

それなりにスムーズに赤丸が動いていると思います。
また、同じことを、setTimeoutに変更して試してみました。『requestAnimationFrame(animationLoop);』の箇所を『setTimeout(animationLoop, 1000/60);』に変えただけです。
実行結果:setTimeoutのテスト

違いはほとんどないと思います。試しに、タブを切り替えてから再度見てみると、requestAnimationFrameのほうはタブを切り替える前の位置から始まり(非表示の時は止まっている)、setTimeoutのほうは表示していない時は別の位置から始まる(非表示の時も動いている)という環境もあるかもしれません(自分の環境では、IE11では確かにそのような動きになったのですが、ChromeやFirefoxではどちらもタブ切り替え時の位置から始まりました)。

ただ、いろいろと問題もあるらしく、例えばsetIntervalとは併用して使えないという問題があるようです(参考:jQueryで破棄されたrequestAnimationFrameとJSでのアニメーション実装で注意すること)。なので、使いどころを考えて使ったほうがよさそうです。