ラベル ネタ の投稿を表示しています。 すべての投稿を表示
ラベル ネタ の投稿を表示しています。 すべての投稿を表示

2012年12月5日水曜日

Sublime Text 2のステータスバー上で素数を数えるだけの画期的なプラグインを作りました。

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

http://www.flickr.com/photos/whitepebble/1381373166/

Sublime Text 2が面白いのでプラグインを作ろうと思い立ち、
API ReferenceとかHow to Create a Sublime Text 2 Pluginとかをチラ見しつつ作成しました。
凄いです。こんな画期的なプラグインが1日もかからず作れました。

プラグインの概要


タイトルにある通り、今回作成した「PrimeCounter」はステータスバーで素数を数えるだけです。
世界中で使われているSublime Text 2ですのでメッセージはもちろん英語。

"Let's calm down and count the prime..."
(素数を数えて落ち着こう・・・)

このメッセージの後に素数が表示されます!

このプラグインは以下の様な様々なシーンでご活用頂けます。
  • バグで手が止まった時に
  • 原稿が一文字も進まない時に
  • うっかり素数を忘れてしまった時に
  • 石を叩く音によるモールス信号で自分の正体がバレそうな時に
  • 簡単なSublime Text 2プラグインを勉強したい時に


  • 仕組み


    Sublimte Text 2ではプラグイン開発のベースとなるクラスとして
    EventListener
    ApplicationCommand
    WindowCommand
    TextCommand
    を提供しています。
    今回はWindowCommandを使いました。機能的には別にWindowCommandじゃなくても良かった気がします。

    ファイル構成はこうです


    これをSublimte Text 2のパッケージ置き場に適当にディレクトリ作って放り込めば動くんですから凄いですね。

    キーバインド


    素数のカウントを開始する為のキーバインドを定義しました。
    キーバインドは以下のファイルにjson形式で記述する事で実現出来ます。
    各プラットフォーム毎に分かれてます
    Default (Linux).sublime-keymap
    Default (OSX).sublime-keymap
    Default (Windows).sublime-keymap

    中身はこんな感じです
    [
     { "keys": ["ctrl+shift+p"], "command": "prime" }
    ]
    

    ctrl+shift+pで素数のカウントをスタート・ストップ出来ます。

    実装


    実装は以下の通り。素数計算は適当です。
    重要なのはrunメソッドとdescriptionメソッド。これはWindowCommandクラスのメソッドをオーバーライドしています。
    sublime.status_messageメソッドでステータスバーに文字列を表示させています。
    sublime.set_timeoutメソッドはjavascriptのsetTimeoutと同じで、指定した関数を指定ミリ秒後に実行します。lambda式で生成したメソッドでincrementメソッドを呼び出してます。これによって1秒毎に素数を数え上げていっています。
    今回は利用していないですがスレッドも使えるし、もちろん通信も出来るのでなんでもありですね。
    ファイルアクセス系は試してませんが、どこでもアクセス出来るとなるとセキュリティ怖いですね。
    そもそもEventListenerで色々取れるし、というか開いている文書の情報には全アクセス出来る気がするので色々お漏らし出来そうな悪寒はありますね。怖い怖い。

    # -*- coding: utf-8 -*-
    import sublime, sublime_plugin
    import thread
    
    #Prime Counter
    isStart=False
    class PrimeCommand(sublime_plugin.WindowCommand):
     prime = 1
     def run(self):
      global isStart
      if isStart:
       isStart = False;
       self.prime = 1
      else:
       isStart = True
       self.increment()
     def description(self, args):
      return "prime counter."
     def increment(self):
      if isStart == True:
       self.prime = self.next_prime(self.prime)
       sublime.status_message("Let's calm down and count the prime..."+str(self.prime))
       sublime.set_timeout(lambda:self.increment(), 1000)
     def next_prime(self, now):
      p = now
      while True:
       is_prime = True
       p = p+1
       div_max = p/2
       if div_max < 2:
        return p
       for i in range(2, div_max+1):
        if p%i == 0:
         is_prime = False
         break
       if is_prime==True:
        return p
    


    インストールの仕方


    PrimeCounterはgithubで公開しています。Sublime Text 2にインストールするにはまずリポジトリを追加します。(Sublime Package Controlがインストールされている事とします)

    command+shift+pでCommand Paletteを開き、"add repository"と入れると出てきます。


    画面下部にリポジトリ追加のエディットが出てくるので
    https://github.com/sys1yagi/PrimeCounter
    を入力してEnter


    その後またCommand Paletteを開き、次は"install"を入力


    インストールするプラグインを絞り込む為に"PrimeCounter"と入れると出てきます。


    Enterを押せばPrimeCounterがインストールされます。

    実行!


    ctrl+shift+pで実行!
    素数がカウントされていきます・・・!


    終わりに


    素数計算部分がしょぼいのでpull request待ってます。
    あとこれ並列計算に何か使えないかなーとか。おもた

    2011年12月30日金曜日

    Chain Of ResponsibilityパターンによるFizzBuzz実装

    このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
    出落ち感満載ですが、実装してみました。
    単純にGoFデザインパターンの一つであるChain Of Responsibilityパターンを使ってみたかっただけです。
    今まで実際に使った事が無かったので・・・。

    Chain Of Responsibilityパターンって?


    ggrks。
    Wikipedia:Chain of Responsibility パターン
    簡単に言うと責任の鎖。「ちょっと責任者に代わって。君じゃ埒があかん。」とこういう事ですね。


    実装


    ChainOfResponsibilityクラスのインナークラスとして全て書いています。
    Fizz, Buzz, FizzBuzz, Integersクラスは抽象クラスであるHandlerを継承しています。
    ChainOfResponsibility#fizzBuzz()の中でsetNextしてお互いを連結しています。

    Handler#fizzBuzz(int)で実行。inCharge(int)で自分がこの値を担当しているかどうかをbooleanで返します。担当であればpring(int)を実行して終了。担当じゃなかったら自分の次の人のHandler#fizzBuzz(int)を呼び出します。

    例えば65という値が入れられた場合はFizzBuzz->Fizz->Buzzまで行ってprintされます。

    なんとなくFizzBuzzクラスやIntegersクラスのinCharge(int)はFizzクラスとBuzzクラスを使って判定させてます。
    連結の仕方によって計算量が変わる気がしますがなんだか面倒なので考えるのをやめました。
    もっと短く出来ると思いますが面倒なので(ry

    public class ChainOfResponsibility {
        static public abstract class Handler{
            private Handler next = null;
           
            public Handler setNext(Handler next){
                this.next = next;
                return next;
            }
            public final void fizzBuzz(int value){
                if(inCharge(value)){
                    print(value);
                }else if(next != null){
                    next.fizzBuzz(value);
                }else{
                    throw new RuntimeException("Oops!");
                }
            }
            protected abstract boolean inCharge(int value);
            protected abstract void print(int value);
        }
        
        static class Integers extends Handler{
            Fizz fizz = new Fizz();
            Buzz buzz = new Buzz();
            @Override
            protected boolean inCharge(int value) {
                return !fizz.inCharge(value) && !buzz.inCharge(value);
            }
            @Override
            protected void print(int value) {
                System.out.println(value);
            }
        }
        static class Fizz extends Handler{
            @Override
            protected boolean inCharge(int value) {
                return value%3 == 0;
            }
            @Override
            protected void print(int value) {
                System.out.println("Fizz");
            }
        }
        static class Buzz extends Handler{
            @Override
            protected boolean inCharge(int value) {
                return value%5 == 0;
            }
            @Override
            protected void print(int value) {
                System.out.println("Buzz");
            }
        }
        
        static class FizzBuzz extends Handler{
            Fizz fizz = new Fizz();
            Buzz buzz = new Buzz();
            @Override
            protected boolean inCharge(int value) {
                return fizz.inCharge(value) && buzz.inCharge(value); 
            }
            @Override
            protected void print(int value) {
                System.out.println("FizzBuzz");
            }
        }
        
        public void fizzBuzz(){
            Handler integer = new Integers();
            Handler fizz = new Fizz();
            Handler buzz = new Buzz();
            Handler fizzBuzz = new FizzBuzz();
            
            fizzBuzz.setNext(fizz).setNext(buzz).setNext(integer);
            for(int i = 1; i <= 100; i++){
                fizzBuzz.fizzBuzz(i);
            }
        }
        
        public static void main(String[] args) {
            new ChainOfResponsibility().fizzBuzz();
        }
    }
    

    まとめ


    このパターンはいろいろ使えそうだなぁ。
    デザインパターンによるFizzBuzz実装をシリーズ化できるかなー。どうかな。

    2011年11月9日水曜日

    JavaによるErrorSortの実装

    このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
    また画期的なソートアルゴリズムが出ましたね。
    [Python]SleepSort、BogoSortに続く画期的なソートアルゴリズム、ErrorSortを考えた
    で、こういうネタソート、何か作れないかなーと思って考えていたら、「あっ、そうだ。エラーを使ってソートすればいいじゃないか」と思って実装してみた。

    面白いので早速Javaで実装してみました。


    ErrorSort


    ソートはintでやる事になるのでTをintに変換するインタフェースを設けました。
    try-cacthの部分で ToインタフェースのIntメソッドを呼び出してTのint表現をもらって配列を作り、
    インクリメントされていくindexで配列にアクセスしてIndexOutOfBoundsExceptionを起こさせています。

     public interface To<T> {
      public int Int(T t);
     }
     public static <T> List<T> errorSort(List<T> list, To<T> to){
      List<T> copy = new ArrayList<T>(list);
      List<T> result = new ArrayList<T>();
      int size = copy.size();
      int count = 0;
      int index = 0;
      WHILE:while(count < size){
       for(T t : copy){
        try{
         (new byte[to.Int(t)])[index] = 0;
         }catch(IndexOutOfBoundsException e){
         result.add(t);
         copy.remove(t);
         count++;
         continue WHILE;
        }
       }
       index++;
      }
      return result;
     }
    


    実行


    以下の様に使います。

     public static void main(String[] args){
      List<Integer> list = Arrays.asList(new Integer[]{2,4,60,3,23,44});
      list = errorSort(list, new To<Integer>(){
       @Override
       public int Int(Integer t) {
        return t;
       }
      });
     }
    

    結果
    2,3,4,23,44,60,


    結論


    まだまだいろんなソートアルゴリズムがありそうですね。