AndroidアプリHesoをリリースしました

「へそ」をたくさん出せるキモ面白いへそだしアプリ「Heso」をリリースしました。
https://market.android.com/details?id=com.github.hanachin.heso

ただのへそなのにいっぱい出るとなんだか不愉快。
タップするとへそが出るへそだしアプリです。

へそを出すのが恥ずかしいあなた、hesoを使っていっぱいへそを出してみませんか?

Twitterでの反応

ありがとうございます!

レビュー依頼中

applikoさんにレビュー依頼を投稿しました!
おすすめ!アンドロイドアプリ情報appliko(アプリコ)
レビューはいつでも待っているので是非よろしくお願いします。

2014: Surrounding Area

今日も簡単そうな問題から。
2014: Surrounding Area
以下クソース。
実装簡単だと思ってたら結構手こずった。コーディング力うんこ…。

#include <stdio.h>

#define MAX_WH 50
#define BLACK 1
#define WHITE 2

char map[MAX_WH][MAX_WH + 1];
char flag[MAX_WH][MAX_WH + 1];

int w, h;

void printFlag() {
  int i, j;
  for (i = 0; i < w; i++) {
    for (j = 0; j < h; j++) printf("%d", flag[j][i]);
    puts("");
  }
  puts("****************");
}

int count(int n) {
  int i, j, cnt = 0;
  for (i = 0; i < w; i++) {
    for (j = 0; j < h; j++) {
      if (flag[j][i] == n) cnt++;
    }
  }
  return cnt;
}

void reset_flag() {
  int i, j;
  for (i = 0; i < w; i++) {
    for (j = 0; j < h; j++) {
      flag[j][i] = 0;
    }
  }
}

int rinsetsu(int mask, int x, int y) {
  char c = mask == BLACK ? 'B' : 'W';
  if (0 <= x + 1 && x + 1 < w && map[y][x + 1] == c) return 1;
  if (0 <= x - 1 && x - 1 < w && map[y][x - 1] == c) return 1;
  if (0 <= y + 1 && y + 1 < h && map[y + 1][x] == c) return 1;
  if (0 <= y - 1 && y - 1 < h && map[y - 1][x] == c) return 1;
  return 0;
}

int kakudai_rinsetsu(int mask, int x, int y) {
  if (0 <= x + 1 && x + 1 < w && flag[y][x + 1] & mask) return 1;
  if (0 <= x - 1 && x - 1 < w && flag[y][x - 1] & mask) return 1;
  if (0 <= y + 1 && y + 1 < h && flag[y + 1][x] & mask) return 1;
  if (0 <= y - 1 && y - 1 < h && flag[y - 1][x] & mask) return 1;
  return 0;
}

void fill(int mask, int x, int y) {
  if (0 <= x && x < w && 0 <= y && y < h) {
    int c = map[y][x];
    if (c == 'B' || c == 'W') return;
    if (flag[y][x] & mask) return;
    
    if (rinsetsu(mask, x, y) || kakudai_rinsetsu(mask, x, y)) {
      flag[y][x] |= mask;
      fill(mask, x + 1, y);
      fill(mask, x, y + 1);
      fill(mask, x - 1, y);
      fill(mask, x, y - 1);
    }
  }
}

void solve() {
  int i, j;
  
  for (i = 0; i < w; i++) {
    for (j = 0; j < h; j++) {
      if (map[j][i] == 'B' || map[j][i] == 'W') {
        int mask = map[j][i] == 'B' ? BLACK : WHITE;
        fill(mask, i + 1, j);
        fill(mask, i, j + 1);
        fill(mask, i - 1, j);
        fill(mask, i, j - 1);
      }
    }
  }
  
  printf("%d %d\n", count(BLACK), count(WHITE));
}

int main() {
  int i;
  while (1) {
    scanf("%d %d\n", &w, &h);
    if (!(w | h)) break;
    
    for (i = 0; i < h; i++) {
      scanf("%s\n", map[i]);
    }
    reset_flag();
    
    solve();
  }
  return 0;
}

久々にAOJをやった。

今日やったことまとめ。
久々にAizu Online Judgeをやった。
Problem setのVolume 0で解いてないやつを。
最後にやったのは2011-05-01なので、おおよそ8ヶ月ぶり。
くソースアップしときます。

0068: Enclose Pins with a Rubber Band

解法分かんなくてググて出たページで凸包というのを初めて知るなど…。
その単語だけ見てアルゴリズム書いてるページへ。
点集合の凸包-数学アルゴリズム演習ノート-
deq notesさんのベクトルのページ等を見てなんとか解けた。
超時間かかった。

#include <cstdio>
#include <complex>

using namespace std;

#define MAX_N 100

typedef complex<double> P;
#define EPS (1e-10)
#define EQ(a,b) (abs((a) - (b)) < EPS)
#define EQV(a,b) (EQ((a).real(), (b).real()) && EQ((a).imag(), (b).imag()))

double cross(P a, P b) {
  return (a.real() * b.imag() - a.imag() * b.real());
}

int side(P start, P end, P point) {
  double arg = cross(end - start, point - start);
  if (arg > 0) return 1;  // left
  if (arg < 0) return -1; // right
  return 0; // center
}

int n;
P p[MAX_N];

int next_vertex(int start_index) {
  for (int i = 0; i < n; ++i) {
    if (start_index == i) continue;
    bool right = false;
    for (int j = 0; j < n; ++j) {
      if (i == j) continue;
      if (side(p[start_index], p[i], p[j]) == -1) right = true;
    }
    if (!right) return i;
  }
  return start_index;
}

int main() {
  while (1) {
    scanf("%d\n", &n);
    if (!n) break;
    
    for (int i = 0; i < n; ++i) {
      double x, y;
      scanf("%lf,%lf\n", &x, &y);
      p[i] = P(x, y);
    }
    
    int pm = 0;
    for (int i = 0; i < n; ++i) {
      if (p[pm].real() > p[i].real()) pm = i;
    }
    
    int start = pm;
    int current = next_vertex(start);
    int count = 1;
    
    while (start != current) {
      current = next_vertex(current);
      count++;
    }
    printf("%d\n", n - count);
  }
  return 0;
}

0069 Drawing Lots II

左右の横線の有無を確認するのを忘れてWAいっぱい出しちゃった。

#include <stdio.h>

int n, m, hit, d;
char dan[30][11];

int amida() {
  int i;
  int cur = m;
  for (i = 0; i < d; ++i) {
    // right
    if (cur < n && dan[i][cur - 1] == '1') {
      cur = cur + 1;
    }
    // left
    else if (cur > 1 && dan[i][cur - 2] == '1') {
      cur = cur - 1;
    }
  }
  return cur == hit;
}


void solve() {
  int i, j;
  if (amida()) {
    puts("0");
    return;
  }
  
  for (i = 0; i < d; i++) {
    for (j = 0; j < n - 1; j++) {
      if (dan[i][j] == '0') {
        if (j > 0 && dan[i][j-1] == '1') continue;
        if (j < n - 2 && dan[i][j+1] == '1') continue;
        dan[i][j] = '1';
        if (amida()) {
          printf("%d %d\n", i+1, j+1);
          return;
        }
        dan[i][j] = '0';
      }
    }
  }

  puts("1");
}

int main() {
  int i;
  while (1) {
    scanf("%d\n", &n);
    if (!n) break;

    scanf("%d\n%d\n%d\n", &m, &hit, &d);
    for (i = 0; i < d; i++) {
      scanf("%s\n", dan[i]);
    }
    solve();
  }
  return 0;
}

0078: Magic Square

方陣の問題。
return 0を忘れてRE

マス目に入る各数字は右詰4桁で出力してください。

を見落としPresentation errorでした。

#include <stdio.h>

#define MAX_N 15

int sq[MAX_N][MAX_N];
int n;

void reset() {
  int i, j;
  for (i = 0; i < n; i++) {
    for (j = 0; j < n; j++) {
      sq[i][j] = -1;
    }
  }
}

void fill(int count, int x, int y) {
  if (count > n * n) return;
  if (x < 0) x = n - 1;
  if (x >= n) x = 0;
  if (y >= n) y = 0;
  if (sq[x][y] != -1) {
    fill(count, x - 1, y + 1);
  } else {
    sq[x][y] = count;
    fill(count + 1, x + 1, y + 1);
  }
}

void printSq() {
  int i, j;
  for (i = 0; i < n; i++) {
    for (j = 0; j < n; j++) {
      printf(j ? "%4d" : "%4d", sq[j][i]);
    }
    puts("");
  }
}

void solve() {
  int center = n /  2;
  reset();
  sq[center][center + 1] = 1;
  fill(2, center + 1, center + 2);
  printSq();
}

int main() {
  while (1) {
    scanf("%d\n", &n);
    if (!n) break;
    
    solve();
  }
  return 0;
}

まとめ

やっぱり数学的な知識がないと辛いかも。
皆どうやって覚えてるんだろう。
あと解法分かんないときどしたらいい? 解法ググってでも解いたらいい?
僕頭固いからかなー。

とりえあずこんな感じで毎日解いていけるといいな。
次やるときは問題文をしっかり読んで重要なとこ見落とさないようにする。
目指せ一発Accept!

今年やりたいこと、やめたいこと

このリストの中の項目に優先度を付け、抽象的な項目を具体化し、目的をはっきりさせ、目標を立て実行していけば必ず実現出来るはずです。

やりたいことリスト

  • デート
    • 美味しい食事を食べさせたい
    • いい景色を見る
  • 旅行
    • こないだパスポート切れた。1回しか使わなかった。もったいない。
    • 円高のうちに海外行きたい。
  • 書き初め
    • 1月中にやりたい
  • 海で泳ぐ
    • 太ってたので裸になりたくなかったけど今なら多分大丈夫
  • カラオケ
    • 歌える曲が少ないので何か歌えるように頑張ろう
    • カラオケいくのをやめるという手もある(?
  • 料理する
    • 揚げ物作れるようになりたい
  • 洗濯をマスターする
  • 食べる
    • パプリカの牛すじカレーを食べる
    • LAMPのカレーかクスクス食べる
    • rukindのコーヒーを飲む、ワッフル食べる
    • 美ら豆コーヒー飲む
    • 海山味で刺身定食食べる
    • 東方美人飲む
    • 琉家のラーメン食べる
    • 阿里で鶏粥食べる
    • 勧められたお店に行く
    • 要するに食べ物屋巡る
  • ギークハウス住む
  • 家庭菜園
    • 野菜苦手なので食べるようにしたい
    • 多分何かを育てるのは小学校以来なので新しい経験が出来るはず
    • 野菜じゃなくてハーブとかでもいいかも
    • 成長記録撮りたい
  • 痩せる
    • 3ヶ月で15kg痩せてその後緩やかにリバウンドしている
    • 既にデブっぽい体型に戻っているのを戻す
    • とりあえず前に3ヶ月で15kg痩せたときのを参考にギークハウス住んでるうちに痩せる
    • 体重計(デジタル表示)買う
  • クレジットカード早く届いてください
    • 12月の頭あたりに申し込んだんだけど中々来ない。審査落ちてたらどうしよ。
    • 届いたらASAPAndroidマーケット登録する
  • 電子書籍版がある書籍は電子書籍版を買う
  • 日本語で書かれた電子書籍本を購入する
  • なるべく英語の電子書籍本を購入する
  • なんらかの英語検定的なものを受けるため勉強する
  • 自炊する
    • スペースとってしまうし読みたいとき読めない本は存在価値が低い(多分)
    • 裁断してスキャンしてOCRかけて検索可能なPDFにしたい
  • Androidマーケットにうんこでもいいのでアプリを投稿する
  • GitHubリポジトリを増やす
    • うんコードでもいいじゃない。人間だもの。
  • CoffeeScriptLispのようなものを書く
  • 勉強会で何か発表する
  • 本を読む
  • プログラミングコンテストに取り組む
  • Webサービスを公開する
  • 電子工作
    • せっかくArduino買ったのにいかせてない
  • もうちょっと人と関わる
    • ただしなるべくめんどくさくない感じで…
  • ブログを書く
    • もっと良質な記事を出す
  • 関数型言語
  • 女装

やめたいことリスト

  • ショートコーディング辞める
    • トップに勝てないから。
  • XSS探さない
    • 僕が探さなくても誰かが探す。
  • 飲み過ぎない
    • 昨年はケータイ紛失(みつかりました)、道ばたで寝る、後輩に絡むなど
  • 飲み物を自販機で買う
  • リンスをめんどくさがってやらない
  • 人に会わないとき髭剃らない、風呂はいらない
  • 暴飲暴食
  • 二度寝
  • 休日家に居る
    • これ気をつける。

まとめ

以上が2012年はじめに思いついたやりたいこと、やめたいことです。

最初に

このリストの中の項目に優先度を付け、抽象的な項目を具体化し、目的をはっきりさせ、目標を立て実行していけば必ず実現出来るはずです。

と書きました。
しかし、何かやろうとするとその過程で必ず何か失敗します。
例えば昨年は一昨年やらなかったことをやりました。
成功したことがいくつかあります。

  • 勉強会で発表
  • 9leapに応募して賞を頂く
  • GitHubにうんコードをいっぱいアップ

でも失敗したこともあります。

  • 頑張って作ったけど一度も自分以外の人に使われてないもの
  • 作ったbotがマイナーすぎてフォロワー30人にも満たない
  • 飲み過ぎ

他いろいろ。

成功したことの中にも「こうしておけばもっと良かったのでは?」という点がいくつもあります。
それを踏まえて、今年は昨年やらなかったことをどんどんやって、もっと「失敗」する一年にしたいです。
リストに挙げたやりたいこと・やめたいことを実践して、もう少し具体的な話を1つずつブログに書いていければいいなと思っています。
今年もよろしくお願いします。

node.js + socket.io + Arduinoでイイネ!

eXtreme Hagoで使われていた、リアルタイムに「いいね」と出すあのシステムをパクりました。
node.js + CoffeeScript + express + node-arduino + MongoDBで出来てます。

デモ動画

動機

ITfrogsとLexuesAcademyの懇親会でくまさんがいいねと同じの200分で作った!と言ってたので僕も作りたくなった。
これが[twitter:@higumachan725]さんがつくったやつ。
GitHub - higumachan/iine
本家のイイネに加え、グラフ機能つき。
開始時間と終了時間にぽちっとボタン押すとグラフが表示され、どこで盛り上がったか一目瞭然。

こんなすごいの「200分で作った」なんて言われたら僕も作りたくなっちゃうでしょ!!
僕が何か1つ機能を付け加えるなら何がいいか?
「そうだ、リアルにボタン押す機能でも作るか」
出来ました。

ソースコード

GitHub - hanachin/iine_duino
※何分で出来たかは秘密です

解説

僕はCoffeeScriptにハマっています。ちゃんと使ってみたい。
CoffeeScriptが書ければJavaScriptも書ける。
JavaScriptが書ければnode.jsが使える。
なので、CoffeeScript + node.jsで作成することに決めました。

ウェブサイトを表示する

ウェブ側はexpressを使って表示することにした。
理由:

  • 直接書くのは多分面倒
  • Sinatra-likeで学習コストが低そう
  • 持ってる本(パーフェクトJavaScript)に例がのってる

本のサンプルを動かしながら使い方を覚えさくっと開発環境を整える。

リアルタイムにイイネを出すために

Nodeが使えればsocket.ioが使える!!
ということでsocket.io使えば楽勝でした。
ただし実際にコード書くよりも使い方を調べる方が時間かかった。
socket.ioを使う理由:

  • リアルタイムに通信したいから
  • 自分でリアルタイムに通信出来るように一から書くより簡単、確実、便利、安心
  • 使ってみたかった
グラフを表示するために

くまさんはjqplotというライブラリを使っていたので僕もそれを使うことに。
グラフを表示するためには記録が必要、なのでMongoDBを使うことにしました。
理由:

  • RDBを設定するのが面倒だった
  • 既にmongooseというライブラリがある
  • 本に例が載ってる

イイネが押された時刻だけを記録するシンプルなデータベースです。
まず、開始時刻と終了時刻を含んだURLにアクセスすると、その間のイイネを集計してJSONで返すようなAPIを作った。
あとはグラフを表示する側からそれを叩いて、jqplotに渡すだけ。jqplot便利ですね。

リアルにボタンを押すために

ボタンをArduino経由でPCに接続しようと考えた。
押せればなんでもいいので100円ショップでプッシュライトボタンを買います。
Arduinoとnode.jsをつなぐにはnode-arduinoを使います。
普通にnpm install arduinoで入れると、digitalRead(入力)が使えなくてハマってました。
Forkされてるこちらのリポジトリを使いましょう。
GitHub - hapticdata/node-arduino: Control your Arduino with Node
後は、ボタンを分解してスイッチのところにつなぐだけ。簡単ですね。

Tips等
  • Guardを使うとCoffeeScriptを勝手にコンパイルしてくれる。coffee -wcでやるよりも便利。
  • node-devを使うとJavaScriptファイルが更新されると自動でサーバーを再起動してくれて楽。
  • プッシュライトはLEDが3つついてるんだけど、どうやって光らせるか誰か教えてください。(Arduinoじゃ電流足りないよね?)

反省点

3つあげると

  • コード書くのに時間をかけすぎた
  • ブログの解説がざっくりすぎる
  • ブログ書くのも旬なうちじゃないと書けない(なので早く製品を作ろう)

まとめ

  • CoffeeScriptでイイネシステムが書けた。
  • expressを使うと簡単にウェブアプリが書ける。
  • socket.io使えばリアルタイムに通信が出来る。
    • どうやって通信するか考えなくて済むのでリアルタイム性の高いものがすぐ作れる。
  • jqplotは見栄えのいいグラフをさっと作れる。
  • node-arduinoを使えばnode.jsとArduinoを連携出来る。
    • ソフトウェアだけでは出来ないことが出来るようになるかも。

オリジナル版と、くまさんの作った奴がなかったら作れなかった。ありがとうございます。
作ってる途中、失敗がいくつもあったけど最終的にボタン押して出来るようになると超楽しかった。
もっと電子工作、はんだづけやってみたい!
もっと聞きたい事、詳しく書いてほしい事があれば[twitter:@hanachin_]までお願いします。

SimpleTimeKeeperにURLでタイマーの時間を指定出来る機能を追加してpull requestおくったった

SimpleTimeKeeperという便利なタイマーがあります。
fluxflex.com
シンプルで見やすくてとってもべんり。プレゼンの時に重宝します。
その、SimpleTimeKeeperに、タイマーの時間をURLで設定出来る機能を付け加えてみた。
URLの末尾に#10:20や?10:30や#10-20や#10m20sとつけるだけで設定出来るよ!

実装

location.searchかlocation.hashを数字ごとに区切って、前から3つとってくる感じになってます。
最後にreverseしてるのは、10:20みたいに、hours, minutes, secondsを全部指定してないときに都合がいいからです。

time = (location.search || location.hash).split(/[^0-9]/).filter(function (x) { return x !== ""; }).slice(0, 3).map(function (x) { return parseInt(x, 10); }).reverse();
// Set Timer
$('#hours').val(time[2] || 0);
$('#minutes').val(time[1] || 0);
$('#seconds').val(time[0] || 10);

まとめ

  • SimpleTimeKeeperはシンプルだから機能を追加するのもらくちん。
  • もっと追加したい機能があるけど、追加するにしても、なるべくシンプルにいきたい。
  • 僕はforEachやfilterやmap等、enumerateするメソッドを続けて書く事が好きだということに気づきました。

こないだもこんなの書いてたし。

urls = tweets.select{|t|
  not t.attrs["entities"].empty?
}.select{|t|
  t.attrs["entities"]["urls"]
}.map{|t|
  t.attrs["entities"]["urls"].map{|u| u["expanded_url"]}
}.inject([]) {|result, urls|
  result + urls
}.select{|u|
  DB[:urls].where(:url => u).count.zero?
}.uniq

カップ麺用タイマーアプリ「QuickNoodleTimer」

作りました。
GitHub - hanachin/qnoodle: Timer for Noodles.

起動した瞬間から3分間カウントが始まります。
タイマーのスタートボタン押す必要なし。
Homeボタンを押して別のアプリを開いてても安心、3分たつとToastメッセージと(ちょっと小さい)音とバイブで知らせてくれます。

野良アプリですけど、インストールはこちらから
QNoodle.apk