昔作ったアプリgithubにあげた

昔作ったiPhoneアプリせっかくだから公開します。
AppStoreに載せようとしたんですがAppleからリジェクト食らって公開できずにいました。
このまま陽の目をみないのもあれなのでgithubでコード公開しました。

概要としては人とすれ違った時に写真を交換できるiPhoneアプリです。
「ちがぞう」という名前でリリースしようと思ってました。
すれ「ちが」った人と「がぞう」を交換できるアプリなので。
写真を交換するだけではなくお互いの画像を重ねあわせて表示することもできます。
地味に写真の保存・モノクロ・ネガ加工もできます。
文字で説明するのアレなのでスクショはります。



初期画面です。写真をカメラロールから選択するかその場で撮影し、そのままアプリをバックグラウンドに回してしまいます。


まわりにもうひとつ同じアプリがバックグラウンド状態にあると、このように検知します。



上の写真で「はい」を押すと写真を検知した同士で写真を交換します。同時に写真を合成します。



写真の合成のON/OFFは設定画面で切り替えることができます。

バイスの接続はBlueToothで行なっています。
BlueTooth接続、Objective-Cでのモノクロ・ネガ加工、マルチタスキングなどの参考になればと思います。

ちなみにリジェクトされた理由はもうぶっちゃけよく覚えてないのですが「BlueTooth接続するときはユーザーに確認をもらうようにしろ」という理由だったと思います。明らかにUIAlert使ってるんですけどね。なんでですかね。一回抗議したけど判定覆らずでした。

まぁ公開はできなかったですけど就活で奴に立ちましたね。はは。
これ作ったのが一年前かぁ。懐かしいです。もうそろそろ僕も社会人になってしまいますねー。
全部自分で作るしかなかったのでスクショの絵もネットで適当にとってきたやつです。万が一権利者のひといたら絵の公開はすぐにやめます。まぁ当時手伝ってくれる友達いないどころかiPhoneアプリの勉強して周りから馬鹿にされてましたから仕方ないですね。

githubのURLはこちら
https://github.com/gong023/public-product/tree/master/GattaiBlueTooth

とらちゃんbot改修

ぎーまる住人とらちゃんのTwitterbotのコードを改修した。
前のはこんな感じで
http://gong023.com/toraBot/index.php
新しくしたのはこんな感じ
http://gong023.com/torabot/www/?action_index=true

何を変えたかというと

  1. ethnaフレームワークで作り直しました
  2. access tokenの保存をmysqlで行うようにしました
  3. perlで動いていたスクリプトphpに書き直しました

見た目がしょぼくなったのはご愛嬌です。done is better than perfectと偉い人も言っています。
フレームワークethnaを使用しているのは普段からethnaつかっててなじんでるからですね。特に深い意図はありません。ethnaoauth認証したい人はコード参考になるかも。
スクリプトは以前@hnnhnがくれたperlスクリプトをほぼ丸パクリしてつかっていたのですが、僕perlはあまり使えないのでphpで書き直しました。

というわけでみんな新とらちゃんbot登録してね。
コードは僕のgithubで公開してるよ。
https://github.com/gong023/public-product/tree/master/torabot

練習

もんだい

こんな感じの出力をオブジェクト指向でいい感じに書いてみる

player1:オレは「せんし」。力だけが自慢だ(HP 183/MP 0)
player2:私は「そうりょ」。回復は任せて(HP 152/MP 100)
player3:僕は「ゆうしゃ」。バランス型です(HP 180/MP 50)
player4:オレは「せんし」。力だけが自慢だ(HP 218/MP 0)
player5:私は「そうりょ」。回復は任せて(HP 128/MP 123)
スライムの群れがあらわれた!
player2はスライムに15のダメージを与えた
//ここで任意のplayerをジョブチェンジ
player1:僕は「ゆうしゃ」。バランス型です(HP 160/MP 20)

==

コード

job.php
<?php
//factory method pattern
interface Job {
	public function getJobName();
	public function getSelfAppoint();
	public function getIntroduce();
	public function getAdditionalHp();
	public function getAdditionalMp();
}
class Soldier implements Job{
	var $job_name = 'せんし';
	var $self_appoint = 'オレ';
	var $introduce = '力だけが自慢だ';
	var $additional_hp = 83;
	var $additional_mp = 0;
	public function getJobName(){return $this->job_name;}
	public function getSelfAppoint(){return $this->self_appoint;}
	public function getIntroduce(){return $this->introduce;}
	public function getAdditionalHp(){return $this->additional_hp;}
	public function getAdditionalMp(){return $this->additional_mp;}
}
class Brave implements Job{
	var $job_name = 'ゆうしゃ';
	var $self_appoint = '';
	var $introduce = 'バランス型です';
	var $additional_hp = 60;
	var $additional_mp = 20;
	public function getJobName(){return $this->job_name;}
	public function getSelfAppoint(){return $this->self_appoint;}
	public function getIntroduce(){return $this->introduce;}
	public function getAdditionalHp(){return $this->additional_hp;}
	public function getAdditionalMp(){return $this->additional_mp;}
}
class Monk implements Job{
	var $job_name = 'そうりょ';
	var $self_appoint = '';
	var $introduce = '回復は任せて';
	var $additional_hp = 38;
	var $additional_mp = 80;
	public function getJobName(){return $this->job_name;}
	public function getSelfAppoint(){return $this->self_appoint;}
	public function getIntroduce(){return $this->introduce;}
	public function getAdditionalHp(){return $this->additional_hp;}
	public function getAdditionalMp(){return $this->additional_mp;}
}
class JobFactory {
	public function create ($job) {
		$reader = $this->createReader($job);
		return $reader;
	}
	public function createReader($job) {
		if ($job === 'soldier') {
			return new Soldier;
		} else if ($job === 'brave') {
			return new Brave;
		} else if ($job === 'monk') {
			return new Monk;
		} else {
			die ('JobFactory faild');
		}
	}
}
?>
player.php
<?php
//iterator pattern
interface MyIterator {
	public function hasNext();
	public function getPlayerAt();
}
class Players {
	private $players;
	private $last;
	public function __construct ($max) {
		$this->last = $max;
	}
	public function add (Player $player) {
		$this->players[] = $player;
	}
	public function getCurrent ($index) {
		return $this->players[$index];
	}
	public function getLength () {
		return $this->last;
	}
	public function getIterator() {
		return new PlayersIterator($this);
	}
}
class PlayersIterator implements MyIterator {
	private $players;
	private $index;
	public function __construct (Players $players) {
		$this->players = $players;
		$this->index = 0;
	}
	public function hasNext () {
		if ($this->index < $this->players->getLength()) {
			return true;
		} else {
			return false;
		}
	}
	public function getPlayerAt () {
		$player = $this->players->getCurrent($this->index);
		$this->index++;
		return $player;
	}
	public function getSinglePlayer ($at) {
		$player = $this->players->getCurrent($at);
		return $player;
	}
}
class Player {
	var $name;
	var $player_hp;
	var $player_mp;
	var $player_job;
	public function __construct ($name, $player_hp, $player_mp, $player_job) {
		$this->name = $name;
		$this->player_hp = $player_hp;
		$this->player_mp = $player_mp;
		$this->player_job = $player_job;
	}
	public function getName () {
		return $this->name;
	}
	public function getPlayerHp () {
		return $this->player_hp;
	}
	public function getPlayerMp () {
		return $this->player_mp;
	}
	public function getPlayerJob () {
		return $this->player_job;
	}
	public function setPlayerJob ($job) {
		$this->player_job = $job;
	}
}
?>
quest.php
<?php
require_once('job.php');
require_once('player.php');
?>
<?php
//singleton pattern
class Quest {
	private $players;
	private $factory;
	private $iterator;
	private static $instance;

	private function __construct () {
		$this->players = new Players(5);
		$this->players->add(new Player('player1', 100 ,0, 'soldier'));
		$this->players->add(new Player('player2', 114 ,20, 'monk'));
		$this->players->add(new Player('player3', 120 , 30, 'brave'));
		$this->players->add(new Player('player4', 135 ,0, 'soldier'));
		$this->players->add(new Player('player5', 90, 43, 'monk'));

		$this->iterator = $this->players->getIterator();
		$this->factory = new JobFactory();
	}
	public static function getQuest () {
		if (!isset(self::$instance)) {
			self::$instance =  new Quest();
		}
		return self::$instance;
	}
	public final function __clone () {
		throw new RuntimeException ('Clone is not allowed against'.get_class($this));
	}
	public function culculateStatus ($player_hp, $player_mp, $job_hp, $job_mp) {
		$status = array (
			'hp' => $player_hp + $job_hp,
			'mp' => $player_mp + $job_mp,
		);
		return $status;
	}
	public function jobChange ($at, $job) {
		$player = $this->iterator->getSinglePlayer($at);
		$player->setPlayerJob($job);
		$player = $this->iterator->getSinglePlayer($at);
		$changed_player = array();
		$changed_player['name'] = $player->getName();
		$changed_player['hp'] = $player->getPlayerHp();
		$changed_player['mp'] = $player->getPlayerMp();
		$changed_player['job'] = $player->getPlayerJob();
		return $changed_player;
	}
	public function runPlayer () {
		$player_param = array();
		$i = 0;
		while($this->iterator->hasNext()) {
			$player = $this->iterator->getPlayerAt();
			$player_param[$i]['name'] = $player->getName();
			$player_param[$i]['hp'] = $player->getPlayerHp();
			$player_param[$i]['mp'] = $player->getPlayerMp();
			$player_param[$i]['job'] = $player->getPlayerJob();
			$i++;
		}
		return $player_param;
	}
	public function runJob ($player_job) {
		$job_param = array();
		$job = $this->factory->create($player_job);
		$job_param['name'] = $job->getJobName();
		$job_param['self_appoint'] = $job->getSelfAppoint();
		$job_param['introduce'] = $job->getIntroduce();
		$job_param['hp'] = $job->getAdditionalHp();
		$job_param['mp'] = $job->getAdditionalMp();
		return $job_param;
	}
	public function tatakau () {
		$attack_player = $this->iterator->getSinglePlayer(1);
		return  $attack_player->getName().'はスライムに15のダメージを与えた'.PHP_EOL;
	}
}
?>
run.php
<?php
require_once('quest.php');
?>
<?php
$quest = Quest::getQuest();
$player = $quest->runPlayer();
foreach($player as $key => $play) {
	$job = $quest->runJob($play['job']);
	$status = $quest->culculateStatus($play['hp'], $play['mp'], $job['hp'], $job['mp']);
	echo $play['name'].':'.$job['self_appoint'].'は「'.$job['name'].'」。'.$job['introduce'].'(HP '.$status['hp'].'/MP '.$status['mp'].')'.PHP_EOL;
}

sleep(1);
echo 'スライムの群れがあらわれた!'.PHP_EOL;
echo $quest->tatakau();
sleep(1);

$changed_player = $quest->jobChange(0, 'brave');
$changed_job = $quest->runJob($changed_player['job']);
$status = $quest->culculateStatus($changed_player['hp'], $changed_player['mp'], $changed_job['hp'], $changed_job['mp']);
echo $changed_player['name'].':'.$changed_job['self_appoint'].'は「'.$changed_job['name'].'」。'.$changed_job['introduce'].'(HP '.$status['hp'].'/MP '.$status['mp'].')'.PHP_EOL;

/*
-----------output-----------
player1:オレは「せんし」。力だけが自慢だ(HP 183/MP 0)
player2:私は「そうりょ」。回復は任せて(HP 152/MP 100)
player3:僕は「ゆうしゃ」。バランス型です(HP 180/MP 50)
player4:オレは「せんし」。力だけが自慢だ(HP 218/MP 0)
player5:私は「そうりょ」。回復は任せて(HP 128/MP 123)
スライムの群れがあらわれた!
player2はスライムに15のダメージを与えた
player1:僕は「ゆうしゃ」。バランス型です(HP 160/MP 20)
?>

==

感想とか

オブジェクト指向というかデザインパターンの練習でした(factory method,iterator,singleton)。
1日つぶれたお。どこでどこまで書くかがとても難しい。jobはplayerの中に入れたかったな・・・。

さくらにcouchDBを入れた

レンタルサーバーのさくらにcouchDBを入れたのでメモ。

=環境=

centOS 5.7
couchDB 1.0.3

=はまった=

基本的に足りないものばっかりコンパイル一切とおらないです。
ほとんどこちらのサイトに書かれていることを順にやればよい感じです。

http://dev.worksap.co.jp/Members/end/2010/07/25

ただ一つこんなerlangインストール後のコンパイルでたこんなエラーでてはまりました

Are the Erlang headers installed? Use the `--with-erlang' option to specify the path to the Erlang include directory

erlangディレクトリを指定するオプションをつけるようにいわれました。
erlangのパスを調べて--with-erlangするも今度は入れたはずのjsがないと怒られます。
悩みましたが、こんなふうにオプション足せばいいみたいです。

./configure --enable-js-trunk --with-erlang=/usr/lib64/erlang/usr/include

あとmakeすればよし
ドキュメント指向のDBを手に入れました。なんとなく世間ではmongoDBの方が盛り上がってる気がしますが…
よーし遊ぼう。

vimで分割した画面を一気に拡大表示

vimをがしゃがしゃいじっていたらhelpに載っていない(たぶん)コマンドが使えた。ググっても出てこないし(たぶん)手持ちのvimテクニックバイブルにも載ってない(たぶん)のでもしかしたらあんまり知られていないのかもしれないと思ってメモ。vimでvsp/spとした時に表示する領域を一気に大きくする方法です。

vimの画面分割がうまくないよー

vimで:vsp/:spとした時に画面を縦横に分割できますよね。こんな風に。

これはまぁ基本中の基本みたいなもんなんで誰でも知っていると思うのですが、この状態でたくさん分割すると分割された画面の領域がどんどん狭くなってしまいます。一つ一つの画面領域を拡大するにはctrl+wと+とかを使えばいいのですが、これだと一行分ずつしか大きくならないのでちまちまとしか領域を広げられない。行数指定をしてガッ!と動かすこともできるけれど、何行指定すれば最大になるのかっていうのがわかりづらい上に入力に必要なコマンドも多くて使いづらい。何かいい方法はないかなーとずっと思ってたんですが、結局見つけられずに泣く泣くscreenをたくさん開いて対応するみたいなことしてたわけです。

ぼくたちには「ctrl+w + ctrl+-」があった

そんな感じでもんもんとしたvimライフをしばらく送っていたわけですが、ある日とんでもないコマンドを発見してしまった。
vimで画面分割して以下のコマンドを打ってみてください。

ctrl+w + ctrl+-
追記:2012/01/29
「ctrl+w + _ 」でもできるそうです。
id:thincaさんにご指摘頂きました。ありがとうございます!

すると・・・

なんと。一発でカーソルのあるウィンドウが最大表示されたじゃないですか!
実際これはすばらしい。なんでどこにも紹介されてないんだろう。
コードが長かろうと継承関係が複雑だろうと余裕で読めますね。
ちなみにこれ元に戻すには

ctrl+w + =

すればいいみたいです。
もう一つ補足すると、これ縦方向に最大化はできるみたいなのですが横方向に広げることはできないようです。まぁまた別のコマンドがあるのかもしれませんが。

追記:2012/01/29
横方向拡大は以下のコマンドでできるそうです。
> ctrl+w + |
>:help CTRL-W_bar
id:thincaさんにご指摘頂きました。ありがとうございます!

どうでもいいですけど僕のitermいつもはあんなにエグい色じゃないです

なに?eclipseemacs
知らん。

twitterのbotつくった

ツイッタァのボット作ったよ
ぎーまるのアイドルとらちゃんのbotです

http://gong023.com/toraBot/

「セッ」から「セェェッッッッッッッッック!!!!!( >д<),;」ぐらいの文字列がランダムでツイートされます。
「ェ」「ツ」「ク」「!」の文字数と顔文字の有無は人によって違うと思います。

日本語の環境設定やらライブラリのインストールなんかですごく手間取ってしまったなー。
おかげさまですごく大規模なwebサービスには携わらせてもらってるんですが、
きちんとしたオブジェクト指向で書かなくていいし変数名とかもいい加減でいいけど、
ライブラリとか環境とか一から知らなきゃいけないのは大変だなーと思いました。

ふんふんありがとう。

クリスマスに競技プログラミングといた/その1

メリークリスマス。クリスマスはギークハウス高円寺と水道橋でしろくまさんのustみながらコードを書いていましたごんげです。
時間が空いてしまいましたが久しぶりに競技プログラミングの問題解きました。
まぁ@mojaieさんがもうだいぶ先まで解いてくれてるから、彼のコードと見比べて見るのもいいですね。
それでは早速いきます。前回の続きでlevel0の5問目からです。
==

0005: GCD and LCM

問題

Write a program which computes the greatest common divisor (GCD) and the least common multiple (LCM) of given a and b (0 < a, b ≤ 2,000,000,000). You can supporse that LCM(a, b) ≤ 2,000,000,000.
GCD and LCM | Aizu Online Judge

回答
import java.util.*;

class GCD {
    public static void main (String args[]) {
        Scanner scn = new Scanner(System.in);
        int a = scn.nextInt();
        int b = scn.nextInt();
        int i = 0;
        ArrayList<Integer> gcd = new ArrayList<Integer>();
        while (i>=0) {
            if (i==0) {
                gcd.add(a % b); 
            } else if (i==1) {
                gcd.add(b % gcd.get(i-1));
            } else {
                gcd.add(gcd.get(i-2) % gcd.get(i-1));
            }   
            if (gcd.get(i)==0) {
                System.out.println("GCD=" + gcd.get(i-1));
                int lcm = a * b / gcd.get(i-1);
                System.out.println("LCM=" + lcm);
                break;
            }   
            i++;        
        }   
    }   
}
感想

最大公約数と最小公倍数を求める問題。アルゴリズムはユーグリッドの互除法です。これですね

ユーグリッドの互除法:ユークリッドの互除法 - Wikipedia

まぁこれ自体は複雑なアルゴリズムなわけではないのですが、なんでこの計算方法で最大公約数が出せるのか・・・誰か説明してくれ。ぶっちゃけよくわからんでした。数学って難しいな。

==

0006: Reverse Sequence

問題

Write a program which reverses a given string str.

回答
import java.io.*;
import java.util.*;

class ReverseSequence {
    public static void main (String args[]) throws java.io.IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        String input= in.readLine();
        ArrayList<Character> output = new ArrayList<Character>();
        for(int i=input.length()-1;i>=0;i--) {
            output.add(input.charAt(i));
        }   
        System.out.println(output);
    }   
}
感想

また配列を逆から回してる。なんかいいやり方ありそうな気がするけど。っていうか今思うとこれ出力おかしいよね・・・。


なんかもう少しあるのでわけて書きます
その2はこちら
http://d.hatena.ne.jp/gong023/20111225/1324825134