anythingを使ってflymakeのエラー行を表示する

探してみても見あたら無かったので慣れないelispで書いてみたでござるの巻

(eval-when-compile (require 'cl))
(require 'flymake)
(setq anything-c-source-flymake
  '((name . "Flymake")
    (init . (lambda ()
              (setq anything-flymake-err-list
                    (loop for err-info in flymake-err-info
                          for err = (nth 1 err-info)
                          append err))))
    (candidates
     . (lambda ()
         (mapcar
          (lambda (err)
            (let* ((text (flymake-ler-text err))
                   (line (flymake-ler-line err)))
              (cons (format "[%s] %s" line text) err)))
          anything-flymake-err-list)))
    (action
     . (("Goto line" . (lambda (candidate) (goto-line (flymake-ler-line candidate) anything-current-buffer)))))))

(defun anything-flymake ()
  (interactive)
  (something (list anything-c-source-flymake)))
M-x anything-flymake

でエラーの一覧を表示。
C-zでanythingのバッファを開いたままactionが実行出来るので、
一覧を表示させたままエラー行の表示できます。

ポーカーの勝敗判定

haskell入門中

■参考
http://www6.airnet.ne.jp/spade/poker/rule/yaku.html

import Data.List
import Data.Maybe
import Random

data Suit = Spade | Heart | Diamond | Club deriving (Eq, Enum, Show)
type Rank = Int
data Card = Card Rank Suit deriving Show
data Pair = Pair Rank Int deriving Show
data Role = HighCard
          | OnePair
          | TwoPair
          | ThreeOfAKind
          | Straight
          | Flush
          | FullHouse
          | FourOfAKind
          | StraightFlush
          | RoyalFlush  deriving (Eq, Ord, Show)
data Hand = Hand Role [Rank] deriving Show

run :: [Card] -> [Card] -> Ordering
run p1 p2 = deal (analysis p1) (analysis p2)

deal :: Hand -> Hand -> Ordering
deal (Hand h1 r1) (Hand h2 r2)
    | h1 /= h2  = h2 `compare` h1
    | otherwise = r2 `compare` r1

analysis :: [Card] -> Hand
analysis cs  = let rs = sortRank cs
                   s  = straight rs
                   f  = flash cs
                   ps = pair rs
                   hs = highcard rs
               in hand s f ps hs
    where
      sortRank :: [Card] -> [Rank]
      sortRank = sortRoyal . toRanks
          where
            toRanks = map $ \(Card r _) -> r
            sortRoyal rs | rs == [1, 2, 3, 4, 5] = rs
                         | otherwise             = sort $ map (\r -> if r == 1 then 14 else r) rs

      straight :: [Rank] -> Bool
      straight rs = all (== 1) $ zipWith (-) (tail rs) rs

      flash :: [Card] -> Bool
      flash = same . toSuits
          where
            toSuits = map $ \(Card _ s) -> s
            same (s:ss) = all (== s) ss

      pair :: [Rank] -> [Pair]
      pair = (map (\xs -> Pair (head xs) (length xs))) . (filter ((> 1) . length)) . group

      highcard :: [Rank] -> [Rank]
      highcard = concat . (filter ((== 1) . length)) . group

hand :: Bool -> Bool -> [Pair] -> [Rank] -> Hand
hand True  True  [                        ] rs | rs == [10, 11, 12, 13, 14] = Hand RoyalFlush []
                                               | otherwise                  = Hand StraightFlush [head rs]
hand False False [(Pair r  4)             ] rs = Hand FourOfAKind $ r:reverse rs
hand False False [(Pair r2 2), (Pair r3 3)] _  = Hand FullHouse [r3, r2]
hand False False [(Pair r3 3), (Pair r2 2)] _  = Hand FullHouse [r3, r2]
hand False True  [                        ] rs = Hand Flush [head rs]
hand True  False [                        ] rs = Hand Straight [head rs]
hand False False [(Pair r  3)             ] rs = Hand ThreeOfAKind $ r:reverse rs
hand False False [(Pair r1 2), (Pair r2 2)] rs = Hand TwoPair $ r2:r1:reverse rs
hand False False [(Pair r  2)             ] rs = Hand OnePair $ r:reverse rs
hand False False [                        ] rs = Hand HighCard $ reverse rs

ランダムに対戦させてみる。

cards = [(Card r s) | r <- [1 .. 13], s <- [Spade .. Club]]
main = do cards' <- getStdGen >>= (\g -> return $ shuffle g cards)
          mapM_ (\(p1, p2) -> poker p1 p2) $ oddEvenList $ splits 5 cards'
    where
      poker :: [Card] -> [Card] -> IO ()
      poker p1 p2 = do print $ "p1 = " ++ (show p1)
                       print $ "   = " ++ (show $ analysis p1)
                       print $ "p2 = " ++ (show p2)
                       print $ "   = " ++ (show $ analysis p2)
                       print $ msg $ run p1 p2
          where
            msg LT = "P1 Win!!"
            msg GT = "P1 Lose..."
            msg EQ = "even"

splits :: Int -> [a] -> [[a]]
splits n xs | length xs >= n = let (x, xs') = splitAt n xs
                               in x : splits n xs'
            | otherwise      = []

oddEvenList :: [a] -> [(a, a)]
oddEvenList xs = zip (oddList xs) (evenList xs)
    where
      filterList :: ([a] -> Bool) -> [a] -> [a]
      filterList p []                  = []
      filterList p (x:xs)  | p xs      = x : filterList p xs
                           | otherwise = filterList p xs

      oddList = filterList (odd . length)
      evenList = filterList (even . length)

shuffle g [] = []
shuffle g xs = x : shuffle g' rest
    where
      (n, g')   = randomR (0, length xs - 1) g
      (x, rest) = pick n xs

pick :: Int -> [a] -> (a, [a])
pick n xs = let (ys, p:zs) = splitAt n xs
            in (p, ys++zs)

xmlのfolding(折り畳み)をする

たまには更新しろよってことでemacs小ネタ。

一万行のxmlファイルの修正依頼に涙がぶち切れそうになったので
emacsの折り畳みについてさらっと調べてみたら、hs-minor-modeなるものが標準で入ってた。

ということでsgmlモードでxmlの折り畳みをする設定。
ついでに標準のキーバインド(C-c @ C-c とか)が使いづらいので、
sgml-modeで空いてそうなC-c系列に変更。

(add-hook 'sgml-mode-hook
          '(lambda()
             (hs-minor-mode 1)))
(add-to-list 'hs-special-modes-alist
             '(sgml-mode
               "<!--\\|<[^/>]>\\|<[^/][^>]*[^/]>"
               ""
               "<!--"
               sgml-skip-tag-forward
               nil))

;; key bind
(define-key sgml-mode-map (kbd "C-c C-o") 'hs-toggle-hiding)
(define-key sgml-mode-map (kbd "C-c C-l") 'hs-hide-level)
(define-key sgml-mode-map (kbd "C-c C-s") 'hs-show-all)

ここ最近インストールして便利だったソフト

Synergy
複数のパソコンでキーボードやマウスを共有するためのソフト。
Windows to Linuxだったり逆だったり。
クリップボードの共有もできて超便利。
入手先 : apt-get


xmonad
Haskellで書かれたタイル型のWindow Maneger。
キーボードでウィンドウのレイアウト切り替えたりランチャー起動したり。
キーボードマニア垂涎。
こいつのせいでGnome Doやら数多のソフトが御役御免になった。南無。
xmonad + emacs + vimperator + HHK Pro 無刻印
世界中の人間は皆敵みたいな環境ができた。
難点(利点?)は設定ファイルが.hs(Haskell)なとこ。
入手先 : apt-get


Dropbox
ローカルファイルと同じように使えるオンラインストレージサービス。
無料で使えるのは2Gまで。
指定のフォルダに変更が入ると勝手に同期とってくれる。
.zshrcやら.emacs.d/やらの設定ファイルをこいつに上げて、
homeフォルダからシンボルリンクを張れば複数パソコンの共有が完成。
ついでにシンボルリンク張る所と必要なパッケージ取得する所を、
shell化したら環境導入もめっちゃ楽になった。
入手先 : Dropbox - Simplify your life

どう書く?org#8053「島の数をカウントする」

お題

m×nの長方形のマス目のうちいくつかを黒く塗りつぶします。
このとき、白の島、黒の島がそれぞれいくつあるかをカウントしてください。

ただし、2つのマスは、同色マスの上下左右の移動で移れるとき、
同じ島にあると定義します。

例:
□■■□
□□■□
□■□□
□■■□
白の島は2つ
黒の島は2つ

例:
□□□□
■□■□
□■□□
□□□□
白の島は1つ
黒の島は3つ

回答

object Q8053 {
  object Tile extends Enumeration {
    val White, Black, Fill = Value
  }
  import Tile._
  
  def countIsland(str : String, target : Value) = {
    var data = parse(str)
    var result = 0
    for (y <- 0 to data.length - 1; x <- 0 to data(y).length - 1) {
      if (data(y)(x) == target) {
        fill(data, y, x, target)
        result += 1
      }
    }
    result
  }

  def parse(str : String) = {
    str.lines.toList.map(_.toList.map( x => if (x == '□') White else Black).toArray).toArray
  }

  def fill(data : Array[Array[Value]], y :Int, x :Int, target : Value):Unit = {
    if (y < 0 || y >= data.length || x < 0 || x >= data(y).length || data(y)(x) != target) {
      return
    }
    data(y)(x) = Fill
    fill(data, y-1, x, target)
    fill(data, y+1, x, target)
    fill(data, y, x-1, target)
    fill(data, y, x+1, target)
  }
}

object Main {
  val sample1 = """□■■□
                  |□□■□
                  |□■□□
                  |□■■□""".stripMargin

  val sample2 = """□□□□
                  |■□■□
                  |□■□□
                  |□□□□""".stripMargin

  def main(args : Array[String]) = {
    println(Q8053 countIsland(sample1, Q8053.Tile.White)) // 2
    println(Q8053 countIsland(sample1, Q8053.Tile.Black)) // 2
    println(Q8053 countIsland(sample2, Q8053.Tile.White)) // 1
    println(Q8053 countIsland(sample2, Q8053.Tile.Black)) // 3
  }
}

すごくjavaっぽいです…。

完全に副作用無しで書こうして挫折した。
こういうのを関数型言語っぽく書くにはどうしたらいいんだろう。

うはwww Scala で Grass を実装してみたwwwwwwww

Scalaの勉強がてら ちょっと草植えときますね型言語 Grass を実装してみましたwwwwwww
今更感が今更だけど大自然の意志には逆らえないwwwwwww

    _, ._
  ( ・ω・) んも〜
  ○={=}〇,
   |:::::::::\, ', ´
、、、、し 、、、(((.@)wvwwWWwvwwWwwvwwwwWWWwwWw


事前目標

  • Scalaに慣れる。
  • javaのGrass実装を写経するのではなく(俺なりに)関数型言語っぽく書く。
  • Grassの仕様を理解する。

コード

class Grass {
  class CED(c :List[Insn], e :List[Value], d :List[CE]) {
    val code = c
    val env = e
    val dump = d
  }

  class CE(c :List[Insn], e :List[Value]) {
    val code = c
    val env = e
  }

  val ENV = List[Value](In, CharFn('w'), Succ, Out)
  val DUMP : List[CE] = List(new CE(Nil, Nil), new CE(List(App(1, 1)), Nil))
 
  def run(str : String) : Unit = evalGrass(new CED(parse(str), ENV, DUMP))

  def evalGrass(ced :CED) : Unit = {
    def loop(ced :CED) : CED = ced.code match {
      case head::tail => loop(eval(head, new CED(tail, ced.env, ced.dump)))
      case Nil => 
        if (!ced.dump.isEmpty) {
          loop(new CED(ced.dump.last.code, ced.dump.last.env:::List(ced.env.last), ced.dump.slice(0, ced.dump.length-1))) 
        } else {
          null
        }
    }
    loop(ced)
  }
  
  val PATTERN_ABS = "^(w+)(.*)".r
  val PATTERN_APP = "^(W+)(w+)(.*)".r

  def parse(src : String) : List[Insn] = {
    normalize(src).split("v").toList.flatMap(_ match {
      case PATTERN_ABS(x, y) => List(Abs(x.length, parseBody(y)))
      case PATTERN_APP(m, n, body) => App(m.length, n.length)::parseBody(body)
      case _ => throw new Exception("parse error")
    })
  }

  def normalize(s : String) = {
    "[^wWv]".r.replaceAllIn(
      "\\A[^w]*".r.replaceFirstIn(
        s.replaceAll("w", "w").
          replaceAll("W", "W").
          replaceAll("v", "v"),
        ""),
      "")
  }
  
  def parseBody(src : String) : List[Insn] = {
    def _parseBody(src : String, code : List[Insn]) : List[Insn] = src match {
      case PATTERN_APP(m, n, body) => _parseBody(body, code:::List(App(m.length, n.length)))
      case _ => code
    }
    _parseBody(src, Nil)
  }
  
  abstract class Insn
  case class App(m :Int, n :Int) extends Insn
  case class Abs(n :Int, code :List[Insn]) extends Insn

  def eval(insn :Insn, ced :CED) : CED = insn match {
    case App(m, n) => app(ced.env(ced.env.length - m), ced.env(ced.env.length - n), ced)
    case Abs(1, c) => new CED(ced.code, ced.env:::List(Fn(c, ced.env)), ced.dump)
    case Abs(n, c) => new CED(ced.code, ced.env:::List(Fn(List(Abs(n - 1, c)), ced.env)), ced.dump)
  }
  
  abstract class Value
  case class Fn(code : List[Insn], env : List[Value]) extends Value { override def toString() :String = "Fn" }
  case class CharFn(char : Char) extends Value
  case object Succ extends Value
  case object Out extends Value
  case object In extends Value

  val ChurchTrue = Fn(List(Abs(1, List(App(3, 2)))), List(Fn(Nil, Nil)))
  val ChurchFalse = Fn(List(Abs(1, Nil)), Nil)

  def app(v :Value, arg :Value, ced :CED) : CED = v match {
    case Fn(c, e) => new CED(c, e:::List(arg), ced.dump:::List(new CE(ced.code, ced.env)))
    case CharFn(char) => new CED(ced.code, ced.env:::List(if (char == getChar(arg)) ChurchTrue else ChurchFalse), ced.dump)
    case Succ => new CED(ced.code, ced.env:::List(CharFn(((getChar(arg) + 1) % 256).asInstanceOf[Char])), ced.dump)
    case Out => 
      System.out.print(getChar(arg))
      System.out.flush()
      new CED(ced.code, ced.env:::List(arg), ced.dump)
    case In => new CED(ced.code, ced.env:::List(CharFn(System.in.read().asInstanceOf[Char])), ced.dump)
  }
  
  def getChar(v :Value) : Char = v match {
    case CharFn(char) => char
    case _ => throw new Exception("eval error at getChar")
  }
}

100行ぐらいに収まりました。

実行例

object Main {
  def main(args : Array[String]) = {
    var grass = new Grass()
    // w
    grass.run("wWWwwww")
    println()
    // x
    grass.run("wWWWwwwwWWWw")
    println()
    // ww
     grass.run("wwWWwvwwwwWWWwwWwwWWWWWWwwwwWwwvwWWwwwWwwwwWwwwwwwWwwwwwwwww")
    println()
    // Hello, world!
    grass.run("wvwWwwwwWwwwwwwWWWWWwWWWWWwwwwvwwwwWWWwwWwwWWWWWWwwwwWwwvwWW" + 
              "wWwwvwwWWwvwWWWwwWWWWWwwwWwwWWWWWWwWWWWWWWwWWWWwWWWWWwWWWWWW" + 
              "wWWWWWWWWWWWWWWwwwwwwwwWwWwWWWwwWWWWwwwwwwwWWWWWwwwwwwwWWWWW" +
              "WwwwwwwwWWWWWWWWWWWWWWWWWWWWWwwwwwwwwwwwwwwwwwwwwwWwwwwwwwww" + 
              "wwwwwwwwwwwWwwwwwwwwwwwwwWwwwwwwWWwwwwwwWWWwwwwwwWWWWWWwwwww" + 
              "wwwwwwwwwwwwwwwWwwwwwwwwwwWWwwwwWWWwwwwWWWWwWWWWWwwwwwwwwwww" + 
              "wwwwwwwWWWWWWWWWWWwWwwwWWwWWWwWWWWwWWWWWWWWWWWWWWWWWwwwwwwww" + 
              "wwwwwwwwwWwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwWwwwwwwwwwww" + 
              "WWwwwwwwwwwwwWWWwwwwwwwWWWWwWWWWWwwwwwwwwWWWWWWwwwwwwwwwwwww" + 
              "wwwwwwwwWWWWWWWwwwwwwwwwwwwwwwwwwwwwwwwwwwwWWWWWWWWWwwwwwwww" + 
              "WwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwWWwwwwwwwwwwwwwWWWwwwwwwwww" + 
              "wwwwWWWWwwwwwwwwWWWWWwwwwwwwwwwwwwwwwwwwwwwwwwwWWWWWWwwwwwww" + 
              "wwwwwwwwwwwwwwwwww")
  }
}

芝が広がりんぐwwwwwww

備忘録 screenの設定 (気分更新)

screenを導入したので設定等の晒し上げ

■.screenrc

defencoding UTF-8
escape ^z^z
defscrollback 1024
hardstatus alwayslastline
hardstatus string "%{.bW}%-w%{.rW}%n %t%{-}%+w %=%{..G} %H %{..Y} %m/%d %C%a "
shell /bin/zsh


markkeys h=^b:l=^f:$=^e:^d=^v


vbell off
startup_message off
autodetach on


bind -c REGION 2 split
bind -c REGION 1 only
bind -c REGION 0 remove
bind -c REGION o focus
bind x command -c REGION

  • エスケープキャラクタはC-z
  • shellはzshを仕様
  • コピーモードのキーバインドemacsに(C-f, C-b, C-e, C-v)
  • ウィンドウ関連のキーバインドemacs「風」に(C-z x 0, C-z x 1, C-z x 2, C-z x o)
  • startup messageをoff
  • etc

■.zshrcに追加

# screenでsshしたときに新しい仮想画面+画面名をログイン先のホスト名に
function ssh_screen(){
 eval server=\${$#}
 screen -t $server ssh "$@"
}
if [ x$TERM = xscreen ]; then
  alias ssh=ssh_screen
fi

# zsh起動時にscreenの自動起動
case "${TERM}" in
kterm*|xterm*)
  screen
esac

■基本操作(key-bind変更済)
ウィンドウ関連

  • C-z 1..9 n番目のウィンドウに切り替え
  • C-z c 新しいウィンドウを作成
  • C-z A ウィンドウの名前を変更
  • C-z n ウィンドウの切替(昇順)
  • C-z p ウィンドウの切替(降順)
  • C-z w ウィンドウ一覧の表示(常に表示させてるからイラネ)

画面分割関連

  • C-z x 2 画面を分割する(横)
  • C-z x 1 画面を一つにする
  • C-z x 0 画面を閉じる
  • C-z x o 画面を切りかえる

コピーモード関連

  • C-z [ コピーモードの開始
  • C-z ] コピーモードの終了、コピーモードで選択したバッファの貼り付け
  • C-f コピーモード中にカーソルを一つ進める
  • C-b コピーモード中にカーソルを一つ戻す
  • C-n コピーモード中にカーソルを一行下に
  • C-p コピーモード中にカーソルを一行上に
  • C-a コピーモード中にカーソルを行の先頭に
  • C-e コピーモード中にカーソルを行の最後に
  • SPC コピーモード中に領域の選択

■TODO

  • コピーしたバッファをクリップボードに入れる
  • 画面の縦分割 -> バッチ等を当てれば可能みたい

■参考URL
Let's use SCREEN!
http://www.dekaino.net/screen/
GNU screen いろいろまとめ。 - naoyaのはてなダイアリー
http://d.hatena.ne.jp/naoya/20051223/1135351050
つなが〜る - .screenrcを晒してみる
http://mobcov.nowa.jp/entry/d7673576c3