furutatsuのメモ帳

ぼくがソフトウェアを設定したことや組んだプログラムを見返すためのブログです。

herokuに公開鍵を登録するぜ

herokuにデプロイしようとしたら、以下のエラーが出力された。

$ git push heroku production:master
Permission denied (publickey).
fatal: The remote end hung up unexpectedly

これはherokuに公開鍵を登録していないからだ。
(公開鍵の作り方はまたいつか)

登録するには以下のコマンドを実行すればいい。

$ heroku keys:add ~/.ssh/id_rsa.pub

参考:herokuに公開鍵を登録する方法 - 森薫の日記

Androidアプリの画面遷移

リストをクリックして画面変えたら面白いなと思って作ってみた。

こんなアプリ

リスト項目クリック→いろんな色の画面が表示する
f:id:nyannyanboo:20120716210954p:plain

ソースコード

MainActivity.java

package net.frtts.listviewsample;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;

public class MainActivity extends Activity
                            implements OnItemClickListener {

    ArrayAdapter<String> adapter;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        adapter = new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_1);

        // add some items
        adapter.add("red");
        adapter.add("green");
        adapter.add("blue");
        adapter.add("gray");
        adapter.add("hoge");
        ListView listView =
            (ListView) findViewById(R.id.listView1);

        // ListView set ArrayAdapter
        listView.setAdapter(adapter);
        listView.setOnItemClickListener(this);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }

    // リスト項目をクリック(タッチ)した時に実行するメソッド
    public void onItemClick(AdapterView<?> parent,
                            View view, int pos, long id) {
        Intent intent = new Intent(this, BackColorActivity.class);
        if (intent != null) {
            intent.putExtra("color", adapter.getItem(pos));
            startActivity(intent); // 画面遷移する
        }
    }

}

BackColorActivity.java

package net.frtts.listviewsample;

import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.widget.RelativeLayout;

public class BackColorActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_back_color);
        
        Bundle extras = getIntent().getExtras();
        String colorString;
        if (extras != null) {
            colorString = extras.getString("color");
        } else {
            colorString = "black";
        }
        RelativeLayout rl =
            (RelativeLayout)findViewById(R.id.RelativeLayout0);
        try {
            rl.setBackgroundColor(Color.parseColor(colorString));
        } catch (IllegalArgumentException e) {
            // 該当する色がない場合
            Log.e("EXCEPTION", e.toString());
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(
            R.menu.activity_back_color, menu);
        return true;
    }
}

activity_main.xml

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <ListView
        android:id="@+id/listView1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        tools:listitem="@android:layout/simple_list_item_1" >
    </ListView>

</LinearLayout>

activity_back_color.xml

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/RelativeLayout0"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".BackColorActivity" >

    <TextView
        android:id="@+id/TextView0"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:padding="@dimen/padding_medium"
        android:text="@string/hello_world"
        tools:context=".BackColorActivity" />

</RelativeLayout>

AndroidManifest.xml

<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="net.frtts.listviewsample"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="15" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/title_activity_main" >
            <intent-filter>
                <action
                  android:name="android.intent.action.MAIN" />
                <category
                  android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".BackColorActivity"
            android:label="@string/title_activity_back_color" >
        </activity>
    </application>

</manifest>

strings.xml

<resources>
    <string name="app_name">ListViewSample</string>
    <string name="hello_world">Hello world!</string>
    <string name="menu_settings">Settings</string>
    <string name="title_activity_main">ListView</string>
    <string name="title_activity_back_color">BackColorActivity</string>
    <string name="title_activity_edit_add">MainActivity</string>
</resources>

簡単にポイント

Intentで画面を遷移する。
Bundleで遷移元のデータを取る。

ProcessingでLangtonのループを作ってみた

追加

ルールの引用元を記載した。(2012年4月18日)

目的

Processingというグラフィックに特化したプログラム言語で、Langtonのループを動かしてみた。

Langtonのループって

Christopher Langtonが考案したセルオートマトンによる自己複製のモデルである。
一つのセルに0-7の状態があり、この(中央にある)セルの状態とこの上下左右のセルの状態からルールを適用することによってこの中央のセルの値が変わる。
これを繰り返すことでループを増殖していく。

仕様

  • 任意のキーでポーズ
  • ルールが適用できなかったら初期状態にして動かす
  • 状態の色
    • 0: ■
    • 1: □
    • 2:
    • 3:
    • 4:
    • 5:
    • 6:
    • 7:
  • ルールはruletablerepositoryLangtons-Loops.tableを使いました。

コードの構成

  • void initCellSpace(): セルを初期化する。
  • boolean nextState(): 次のセルを更新する。ここでルールの適用を行う。ルールが適用できたらtrue、そうでなければ(ルールを全部探索したら)falseを返す。

ソースコード

int rectSize = 5;
int[][] space;
int[][] nextSpace;
ArrayList rules;
boolean running = true;
int count = 0;

// Init state
int[][] langLoop = {
  {0,2,2,2,2,2,2,2,2,0,0,0,0,0,0},
  {2,1,7,0,1,4,0,1,4,2,0,0,0,0,0},
  {2,0,2,2,2,2,2,2,0,2,0,0,0,0,0},
  {2,7,2,0,0,0,0,2,1,2,0,0,0,0,0},
  {2,1,2,0,0,0,0,2,1,2,0,0,0,0,0},
  {2,0,2,0,0,0,0,2,1,2,0,0,0,0,0},
  {2,7,2,0,0,0,0,2,1,2,0,0,0,0,0},
  {2,1,2,2,2,2,2,2,1,2,2,2,2,2,0},
  {2,0,7,1,0,7,1,0,7,1,1,1,1,1,2},
  {0,2,2,2,2,2,2,2,2,2,2,2,2,2,0}
};

void setup() {
  size(800, 800);
  colorMode(RGB, 100);
  int sizeX = width/rectSize;  // Number of rect for x and y axis
  int sizeY = height/rectSize;
  println("X = " + sizeX);
  println("Y = " + sizeY);
  space = new int[sizeY][sizeX];
  nextSpace = new int[sizeY][sizeX];
  rules = new ArrayList();
  
  // init space
  initCellSpace();
  
  // load rules from a file "Langtons-Loops.table"
  // and add loaded rule to list
  BufferedReader br = createReader("Langtons-Loops.table");
  String l;
  try {
    while((l = br.readLine()) != null) {
      // like 00000, load numeric format
      if(Character.isDigit(l.charAt(0))) rules.add(l);
    }
  } catch (IOException e) {
    e.printStackTrace();
  }
  println("Loaded " + rules.size() + " rules.");
  frameRate(120);
}

void draw() {
  if(running) {
    if(nextState()) {
      //println(count);    
      for(int i=0; i<space.length; i++) {
        for(int j=0; j<space[i].length; j++) {
          fill(stateToColor(space[i][j]));
          rect(j*rectSize, i*rectSize, rectSize, rectSize);
        }
      }  
      count++;
    } else {
      initCellSpace();
      count = 0;
    }
  }
}

// stop or run
void keyPressed() {
  if (running) {
    println("Stop!");
  } else {
    println("Play!");
  }
  running = !running;
}

void initCellSpace() {
  for(int i=0; i<space.length; i++) {
    for(int j=0; j<space[i].length; j++) {
      space[i][j] = 0;
    }
  }
  
  // put init state on 'space' at center
  int offsetX = space.length/2;
  int offsetY = space[0].length/2;
  for(int i=0; i<langLoop.length; i++) {
    for(int j=0; j<langLoop[i].length; j++) {
      space[offsetY-langLoop.length/2+i][offsetX-langLoop.length/2+j] = langLoop[i][j];
    }
  }
}

color stateToColor(int state) {
  color cl = 0;
  switch(state) {
    case  0: cl = color(0,0,0); break;
    case  1: cl = color(100,100,100); break;
    case  2: cl = color(50,50,50); break;
    case  3: cl = color(0,100,0); break;
    case  4: cl = color(0,50,50); break;
    case  5: cl = color(0,0,100); break;
    case  6: cl = color(50,0,50); break;
    case  7: cl = color(100,100,100); break;
  }
  return cl;
}

// n_states:8(0-7)
// neighborhood:vonNeumann (Center, North, East, South, West) 
// symmetries:rotate4
boolean nextState() {
  for(int i=0; i<space.length; i++) {
    for(int j=0; j<space[i].length; j++) {
      // 読み込み
      int vN[] = new int[5];
      int next = space[i][j];
      
      vN[0] = space[i][j];   // Center
      vN[1] = (i == 0)                 ? space[space.length-1][j] : space[i-1][j]; // North 1 -> 2 -> 3 -> 4
      vN[2] = (j == space[i].length-1) ? space[i][0]              : space[i][j+1]; // East  2 -> 3 -> 4 -> 1
      vN[3] = (i == space.length-1)    ? space[0][j]              : space[i+1][j]; // South 3 -> 4 -> 1 -> 2
      vN[4] = (j == 0)                 ? space[i][space.length-1] : space[i][j-1]; // Weat  4 -> 1 -> 2 -> 3
      
      // 比較・回転
      String rule;
      int k;
      for(k=0; k<rules.size(); k++) {
        rule = (String)rules.get(k);
        
        // XXX: 片っ端から比較または回転する
        if (vN[0] == rule.charAt(0)-'0' && vN[1] == rule.charAt(1)-'0' &&
            vN[2] == rule.charAt(2)-'0' && vN[3] == rule.charAt(3)-'0' && vN[4] == rule.charAt(4)-'0') {
          next = rule.charAt(5)-'0';
          break;
        } else if (vN[0] == rule.charAt(0)-'0' && vN[1] == rule.charAt(2)-'0' &&
            vN[2] == rule.charAt(3)-'0' && vN[3] == rule.charAt(4)-'0' && vN[4] == rule.charAt(1)-'0') {
          next = rule.charAt(5)-'0';
          break;
        } else if (vN[0] == rule.charAt(0)-'0' && vN[1] == rule.charAt(3)-'0' &&
            vN[2] == rule.charAt(4)-'0' && vN[3] == rule.charAt(1)-'0' && vN[4] == rule.charAt(2)-'0') {
          next = rule.charAt(5)-'0';
          break;
        } else if (vN[0] == rule.charAt(0)-'0' && vN[1] == rule.charAt(4)-'0' &&
            vN[2] == rule.charAt(1)-'0' && vN[3] == rule.charAt(2)-'0' && vN[4] == rule.charAt(3)-'0') {
          next = rule.charAt(5)-'0';
          break;
        }
      }
      if(k == rules.size()) {
        return false;
      } else {
        nextSpace[i][j] = next;
      }
    }
  }
  
  // 全更新
  for(int i=0; i<space.length; i++) {
    for(int j=0; j<space[i].length; j++) {
      space[i][j] = nextSpace[i][j];
    }
  }
  return true;
}

実行結果

f:id:nyannyanboo:20120417230241p:plain

pikサブコマンド一覧

> pik help commands

  add             Adds another ruby location to pik.
  benchmark|bench Runs bencmarks with all versions that pik is aware of.
  config          Adds/modifies configuration options.
  default         Switches back to the default settings.
  devkit          Configures devkit settings
  gem             Runs the gem command with all versions that pik is aware of.
  gemsync         Synchronizes gems from the version specified to the current version.
  help            Displays help information.
  implode         Removes your pik configuration.
  info|checkup|cu Displays information about the current ruby version.
  install|in      Downloads and installs different ruby versions.
  list|ls         Lists ruby versions that pik is aware of.
  rake            Runs the rake command with all versions that pik is aware of.
  remove|rm       Removes a ruby location from pik.
  ruby|rb         Runs ruby with all versions that pik is aware of.
  run             Runs command with all versions of ruby that pik is aware of.
  tag             Adds the given tag to the current version.
  tags            Runs the pik command against the given tags.
  uninstall|unin  Deletes a ruby version from the filesystem and removes it from Pik.
  update|up       updates pik.
  use|switch|sw   Switches ruby versions based on patterns.

Win版RVM:pik

WindowsでRVMを使おうとしたらpikというRVMみたいに使える版管理システムがあったので使ってみた。

pikについて:vertiginous/pik

pik入れようぜ

pikはRuby Gemsとインストーラでインストールできるが、僕はRuby Gemsで入れた。

> gem install pik

pikの実行ファイルを入れようぜ

pik_installコマンドを使ってpikの実行ファイル(確かpik.exe)などを入れよう。
このコマンドの後にファルダを指定しよう。例えばC:\toolsに入れるには以下のコマンドを実行しよう。

> pik_install C:\tools

ここで、pikと打ってバッチファイルとして認識されていませんと云われないように環境変数を設定しよう。上のコマンドの場合は環境変数(PATH)にC:\toolsを追加した。

pikでRubyを入れようぜ

pikを使ってRubyをインストールするには、以下のように入力して実行する。
この場合はRubyの最新版(2012年4月4日現在:1.9.3-p125)がインストールされる。

> pik install ruby

インストール中、以下のようなことを聞かれたが、ぼくはyesと打った。

You need the 7zip utility to extract this file.
Would you like me to download it? (yes/no) 

また、バージョンを指定してインストールするには以下のように実行すればいい。

> pik install ruby -v 1.9.2-p290

切り替えようぜ

今どのRuby(あるいはどのバージョン)を使っているかを確かめてみよう。
以下のように、listというサブコマンドで実行するとインストールされているRubyとそのバージョンを示す。アスタリスクは現在使っているRubyとそのバージョンを表している。

> pik list
  187: ruby 1.8.7 (2010-12-23 patchlevel 330) [i386-mswin32]
  192: ruby 1.9.2p290 (2011-07-09) [i386-mingw32]
  193: ruby 1.9.3p125 (2012-02-16) [i386-mingw32]

んで、ruby 1.9.2に切り替えるに以下のコマンドを実行するとよい。

> pik use 192

すると、1.9.2の前にアスタリスクがつくようになる。

> pik list
  187: ruby 1.8.7 (2010-12-23 patchlevel 330) [i386-mswin32]
  192: ruby 1.9.2p290 (2011-07-09) [i386-mingw32]
  193: ruby 1.9.3p125 (2012-02-16) [i386-mingw32]

念のためバージョンを表示してみたら、うまく切り替えた。

> ruby -v
ruby 1.9.2p290 (2011-07-09) [i386-mingw32]