2012年11月29日木曜日

Application - xyzzy

Wiki

なんかまともなエディタを使ってみたくなったので、とりあえず xyzzy というものにチャレンジしてみる。キーボードショートカットは基本的に emacs ライクらしい。

個人的な設定メモ、カンペを逐次更新予定

<環境設定>
環境変数に XYZZYHOME を追加。ここで指定したディレクトリに .xyzzy ファイルを作成する

現在の .xyzzy ファイルの中身。
参考 : http://chez-sugi.net/xyzzy/xyzzy001.html

----------------------------------------------------
(require "ni/setup")
;; 自動設定を利用する
(ni-autoload)

(require "xml/xml-mode")
(use-package 'xml)

(export 'ed::html+-mode "ed")
(autoload 'html+-mode "html+-mode" t)
(pushnew '("\\.s?html?$" . html+-mode) *auto-mode-alist* :test 'equal)

(set-buffer-fold-type-window)

(require "isearch")

(require "dabbrev")
(global-set-key #\M-/ 'dabbrev-expand)

(global-set-key '(#\C-c #\C-a) 'selection-whole-buffer)
(global-set-key '(#\C-c #\C-c) 'copy-selection-to-clipboard)
(global-set-key '(#\C-c #\C-v) 'paste-from-clipboard)

(global-set-key #\Home 'beginning-of-virtual-line)
(global-set-key #\End 'end-of-virtual-line)
(global-set-key #\S-Home 'selection-beginning-of-virtual-line)
(global-set-key #\S-End 'selection-end-of-virtual-line)

(setq *next-buffer-in-tab-order* t)
(global-set-key #\M-Right 'next-buffer)
(global-set-key #\M-Left 'previous-buffer)

(global-set-key #\M-Up 'move-previous-window)
(global-set-key #\M-Down 'other-window)
----------------------------------------------------

表示 → ツールバー → バッファ でタブを表示

NetInstaller の導入
xml-mode の導入
html-mode の導入

<注意>
xyzzy 内で C-k や C-w を使ってカットした内容はクリップボードにはコピーされない。xyzzy 内のみで使用可能

<思えておきたいショートカット>
  • C-Space : Mark Set
  • C-w : Mark Set した場所から現在地までを切り取り
  • C-k : 行末までを切り取り
  • C-y : バッファの貼り付け

2012年11月24日土曜日

Book - 『風が強く吹いている』 by 三浦しをん

風が強く吹いている

元エリートランナーが、天才ランナーと運動と縁が(ほとんど)なかった同じ寮に住む住人を巻き込み 1 年間で箱根駅伝を目指し、走る物語。

住人の成長率高過ぎるとか、周りの大学のレベルが低いとか、
そういう現実と比較するべきではない。

これはフィクション。フィクションとして割り切れば、十分に面白いし、
箱根駅伝の中で語られるそれぞれの『走る』という行為に対する思いにはリアリティがあると思う。

走ることが好きで、頑張って走って、頑張ったからこそ見えてしまった自分の限界に対する葛藤とか、ただ『努力が勝つ』みたいな終わりじゃなくって良かった。

あと、面白かったからこそ、もう少し練習期間中の思いにもページを割いて欲しかった。

Book - 『ゲームばっかりしてなさい』 by 浜村弘一

ゲームばっかりしてなさい。-12歳の息子を育ててくれたゲームたち-

Kindle で破格の 100 円以下だったので購入。
まぁ、そのぐらいの値段だったので損はなかったかな、という程度の読後感。

ゲーム雑誌編集者とその子供というちょっと状況が特殊過ぎて、あまり共感はできなかった。
結局は、ゲームは親の責任で遊ばせよう、という普遍的なメッセージで収まると思う。

Book - 『すべてが F になる』 by 森博嗣

すべてがFになる THE PERFECT INSIDER (講談社文庫)

ネタバレ若干有り

今読むとちょっと古い感じがするのは否めないと思う。
トリックの根幹は好きなんだけど、それを成立させるための条件を揃えるにはかなりの無理がある。
15年間も同じ OS を使うなんてありえないし、あんなトロイの木馬は誰か気付くでしょう…
何より決行の瞬間の行動が、周りの反応によっては簡単に潰されてしまう程脆い。

あと、動機はいまいち。というか理解できない。
作中でも『天才の考えとはそういうもの』という事になっている。

でも、最初に書いた通りトリックの根幹は好きだし、
文体も読みやすかったので
つまらなかった、という感じはなかった。

2012年11月23日金曜日

Android - リソース修飾子 w<N>dp, h<N>dp について

<N> に指定する値は、『アプリケーションが使用できる領域』
システムバーやナビゲーションバーが表示されている場合、その分を引いた値を指定しておく必要がある。

システムバーは 25dp, ナビゲーションバーは48dp なので、少し余裕を持って 80 dp くらい引いた値にしておく事と確実に適用される。

ただし、どうやらレイアウトのプレビューではシステムバーやナビゲーションバーの高さを無視しているようなので、実機で実行すると若干高さ方向が狭くなる。

システムバー + ナビゲーションバーを前提としたスキンを作成して、そちらで確認した方が良い。

作成方法
Android Virtual Device Manager の右側タブの Device Definitions で Nexus 7 を [Clone...]
高さ方向の解像度を 1180 くらいにする

2012年11月13日火曜日

Android - マルチタッチと ACTION_MOVE

久しぶりにマルチタッチイベントを処理していてはまったこと。

ev.getActionMasked() == ACTION_MOVE の場合は

pointerIndex = ev.getActionIndex()
pointerId = ev.getPointerId(activePointerIndex);

が 0 になる。

つまり、「どの指が動いたか」という事を識別できない。
移動量とかを使いたい場合、イベントが起こる毎に、ID と 座標を対応付けて保存する必要があるので結構面倒くさい。移動先の座標を使うだけなら、下のようにループで全部のタッチ情報を処理すれば、無駄はあるけどそこまで大変ではない。


case MotionEvent.ACTION_MOVE:
int count = ev.getPointerCount();
boolean alreadyMoved = false;
for (int c = 0; c < count; c++){
 int pointerId = ev.getPointerId(c);
 float x = ev.getX(c);
 float y = ev.getY(c);
 ...
}
break;

2012年11月4日日曜日

algorithm - ヒープソート

ワーストケースでも O (n log (n)) なパフォーマンスが出せる。
* ベストもアベレージも O (n log (n))
ただし、平均速度はクイックソートの方が上。

def comp(a, b):
    if a > b:
        return 1
    elif a < b:
        return -1
    else:
        return 0

# 親と子を比較し、子の方が大きければ交換
# 交換があれば更なる交換がないか再帰的に調べる
def heapify(arr, comp_func, idx, max_idx):
    left = 2 * idx + 1
    right = 2 * idx + 2
    largest = 0
    if left < max_idx and comp_func(arr[left], arr[idx]) > 0:
        largest = left
    else:
        largest = idx
    if right < max_idx and comp_func(arr[right], arr[largest]) > 0:
        largest = right
    if largest != idx:
        tmp = arr[idx]
        arr[idx] = arr[largest]
        arr[largest] = tmp
        heapify(arr, comp_func, largest, max_idx)

# 子は必ず親より小さい、という性質を持つ 2 分木を作成する
# 大きい数字が勝ち上がっていく、トーナメントのようなイメージ
def buildHeap(arr, comp_func, n):
    for i in range(n / 2 - 1, -1, -1):
        heapify(arr, comp_func, i, n)
        
def heapSort(arr, n, comp_func):
    # 初回のみ下から木を作る
    buildHeap(arr, comp_func, n)
    for i in range(n - 1, 0, -1):
        # 最大値が配列先頭にあるので、終端と交換
        tmp = arr[0]
        arr[0] = arr[i]
        arr[i] = tmp
        # 一度木が作成済みなので先頭から交換の有無を調べる
        # 上位に交換がなければ、下位に影響はない
        heapify (arr, comp_func, 0, i)
        
a = range(0, 500)
random.shuffle(a)
print a
heapSort(a, len(a), comp)
print a

python - range で逆順

参考 : range()で生成したリストの逆順を得る

range の第 3 引数が生成する配列の数値の間隔。
先頭と終端に注意。
# 0, 1, 2, 3, 4, 5, ..., 498, 499
range (0, 500)
# 499, 498, 497, ..., 3, 2, 1, 0
range (499, -1, -1)

2012年11月3日土曜日

algorithm - クイックソート

Median Sort と基本的な方法は同じ。
Median を選ばず適当な位置をピボットに配列を分割する。
ワーストケースパフォーマンスを避けるために単純なランダムでないバリエーションもある。
(Median-of-three 等)
配列が小さい時は挿入ソートの方が速くなるので、 サイズが一定以下になったら挿入ソートを使う。


def selectPivotIndex(left, right):
    return random.randint(left, right + 1)

# 配列を、pivotIndex の値で分割する。
# pivotIndex の値より小さい値は前、
# pivotIndex の値より大きい値は後ろに移動
def partition(arr, comp_func, left, right, pivotIndex):
    # pivot の値を最後尾に移動
    pivot = arr[pivotIndex]
    tmp = arr[right]
    arr[right] = pivot
    arr[pivotIndex] = tmp
    
    # pivot より小さい値を前に持っていく
    store = left
    for i in range(left, right):
        if comp_func(arr[i], pivot) < 0:
            tmp = arr[i]
            arr[i] = arr[store]
            arr[store] = tmp
            store += 1
    # pivot を配置
    tmp = arr[store]
    arr[store] = pivot
    arr[right] = tmp
    return store

# 挿入ソート
def insertion(arr, comp_func, left, right):
    for i in range(left, right + 1):
        tmp = arr[i]
        j = i - 1
        while j >= 0 and arr[j] >= tmp:
            arr[j + 1] = arr[j]
            j -= 1
        arr[j + 1] = tmp

# 最大深さを記録。特に意味は無い。
max_depth = 0
# 配列サイズがこれ以下なら挿入ソートを使う
MIN_SIZE = 4

def qsort(arr, comp_func, left, right, depth):
    if right <= left:
        return
    pivotIndex = selectPivotIndex(left, right)
    pivotIndex = partition(arr, comp_func, left, right, pivotIndex)
    # サイズが一定以下なら挿入ソート
    if pivotIndex <= MIN_SIZE:
        # グローバル変数にアクセスするには global 宣言が必要
        global max_depth
        max_depth = max(max_depth, depth)
        insertion(arr, comp_func, left, pivotIndex - 1)
    else:
        qsort(arr, comp, left, pivotIndex - 1, depth + 1)
    if right - pivotIndex - 1 <= MIN_SIZE:
        global max_depth
        max_depth = max(max_depth, depth)
        insertion(arr, comp_func, pivotIndex + 1, right)
    else:
        qsort(arr, comp, pivotIndex + 1, right, depth + 1)

a = range(1, 500)
random.shuffle(a)

print a

qsort(a, comp, 0, len(a) - 1, 0)

print max_depth
print a

2012年11月2日金曜日

algorithm - Median Sort

クイックソートの下準備的な知識になるらしい。

def comp(a, b):
    if a > b:
        return 1
    elif a < b:
        return -1
    else:
        return 0

# 配列を、pivotIndex の値で分割する。
# pivotIndex の値より小さい値は前、
# pivotIndex の値より大きい値は後ろに移動
def partition(arr, comp_func, left, right, pivotIndex):
    # pivot の値を最後尾に移動
    pivot = arr[pivotIndex]
    tmp = arr[right]
    arr[right] = pivot
    arr[pivotIndex] = tmp
    
    # pivot より小さい値を前に持っていく
    store = left
    for i in range(left, right):
        if comp_func(arr[i], pivot) <= 0:
            tmp = arr[i]
            arr[i] = arr[store]
            arr[store] = tmp
            store += 1
    # pivot を配置
    tmp = arr[store]
    arr[store] = pivot
    arr[right] = tmp
    return store

# 適当
def selectPivotIndex(left, right):
    return right

# K 番目の値を取得する。
# 返却値はインデックスだが arr が変化した後のインデックスなので
# 元の配列でどこにあったか、といったような情報ではない。
# あくまで値のみ。
# 結果として K 番目の値で配列が分割されている。
def selectKth(arr, comp_func, k, left, right):
    # 適当に pivot を選択
    pivotIndex = selectPivotIndex(left, right)
    # pivot で分割
    pivotIndex = partition(arr, comp_func, left, right, pivotIndex)
    # pivot が  K 番目だったら終了。
    if left + k == pivotIndex:
        return pivotIndex
    # pivot が K よりも大きければ、前方の配列から再度探す。
    elif left + k < pivotIndex:
        return selectKth(arr, comp_func, k, left, pivotIndex - 1)
    # pivot が K よりも小さければ、後方の配列から再度探す。
    else:
        return selectKth(arr, comp_func, (left + k) - pivotIndex - 1, pivotIndex + 1, right)

def medianSort(arr, comp_func, left, right):
    # 配列のサイズが 1 であれば終了
    if right <= left:
        return
    mid = (right - left) + 1 / 2
    # 配列を中央値で再帰的に分割
    selectKth(arr, comp_func, mid, left, right)
    medianSort(arr, comp_func, left, left + mid - 1)
    medianSort(arr, comp_func, left + mid + 1, right)

a = [1,5,2,7,9,32,6,87,9,21,6,43,556,14,69]

medianSort(a, comp, 0, len(a) - 1)

print a

2012年11月1日木曜日

algorithm - 挿入ソート

低速だけど安定で実装しやすい。ほとんど整列済みのデータに対しては高速。
さらに、ソート対象が連結リストであれば、挿入が高速にできるのでバブルソートよりも 大幅に速い。

データを1つずつ、手持ちのデータの中で正しい位置に挿入しながら、
段々とデータ数を増やしていくイメージ。


def insertion_sort(arr):
    n = len(arr)
    for i in range(1, n):
        tmp = arr[i]
        j = i - 1
        while j >= 0 and arr[j] > tmp:
            arr[j + 1] = arr[j]
            j -= 1
        arr[j + 1] = tmp