Journal InTime


2017-01-21 (Sat) [長年日記]

_ Textbringer 0.1.0

年末から作っていたテキストエディタをいったんリリースした。

こんな感じのスクリーンエディタである。

$ gem install textbringer

でインストールして、

$ tb

で起動する。

日本語テキストも扱える。

ISO-2022-JPも扱いたい場合は~/.textbringer.rbに以下のように書いておくとよい。

Buffer.detect_encoding_proc = Buffer::NKF_DETECT_ENCODING

マニュアルは何もないので、lib/textbringer/keymap.rbあたりを読んで使い方を想像してほしい。 まあだいたいEmacsと同じでredoがundoと別のコマンド(C-xC-/)になっているくらい。

Rubyモードも一応作ったけど、まだオートインデントとC-cC-cでのrake実行くらいしかできない。

名前の由来はマイクル・ムアコックのメルニボネの皇子とかに出て来る魔剣Stormbringerなんだけど、新訳が出たと思ったらもう紙は絶版になっているようでつらい。

何でテキストエディタを作っているかというと、会社の忘年会の時に中村君と話していて最近作りたいものないという話になって、昔テキストエディタを作りたいと思っていたことを思い出したから。 そのためにcursesの拡張ライブラリを作ったのだが、その時から20年くらい経ってしまった(しかも結局ncurseswというgemを使うことにしたので活かされてない)。

今のところEmacsに対するアドバンテージは括弧が少ないことくらいだが、地道に育てていきたい。

Tags: Ruby

2016-12-17 (Sat) [長年日記]

_ 松江Ruby会議08

今年も松江Ruby会議に参加してきた。

食後のコーヒーを飲んでいたらLTを聞き逃したが、その他のセッションはどれも楽しめた。松田さんの講演でdisられたけど。

吉岡さんに言われて参加したプログラミングコンテストでは一般部門1位でMisocaさん提供のAmazon Dash Button 1万円分(つまりボタン20個)をいただいた。

Amazon Dash Button

最終計測では2位のsimanさんと4msec差だったそうなので、測定誤差のような気がする。

同じようなプログラムをたくさん応募したのでどれが1位になったのかはっきりしないが、バイト数的にたぶん以下のプログラムだと思う。

m=$<.read;v=m.tr($/,?#).unpack"C*";g=/G/=~m;q=[s=/S/=~m];while(i=q.pop)!=g;v[i]=35;[1,-1,s,-s].each{|d|v[j=i+d]!=35&&q<<j&&$:[j]=i}end;m[i]=?:while(i=$:[i])!=s;$><<m

各変数は以下のような意味をもつ。

  • m -> map = マップ情報
  • v -> visited = 探索済みノード情報(兼壁情報)
  • s -> start = スタート位置
  • q -> queue = キュー(最終的にスタックになってしまった)
  • i -> 探索中ノードのインデックス
  • j -> 隣接ノードのインデックス
  • $: -> 経路情報(最終的にマップ上に:と出力)

一文字変数のわりにわかりやすい(自画自賛)。

その後さらに削って

q=[i=s=/S/=~m=$<.read];v=m.tr$/,?#;[1,-1,s,-s].each{|d|v[j=i+d]!=(v[i]=?#)&&q<<j&&$:[j]=i}while/G/!~v[i=q.pop];m[i]=?:while(i=$:[i])!=s;$><<m

こんなのや

m=$<.read;q=[i=s=/S/=~v=m.dup];[1,-1,s,-s].each{|d|v[i]=$/;/#|
/!~v[j=i+d]&&q<<j&&$:[j]=i}while/G/!~v[i=q.pop];m[i]=?:while(i=$:[i])!=s;$><<m

こんなのも応募(ブラウザからだと改行がCRLFになってしまうので、Net::HTTPで送信)したが、文字数節約のため探索済みノードのマーク(v[i]=?#)を無駄にeachの中に押しこんだり、vが配列ではなく文字列になったりしている分遅かったかもしれない。

最初はマップによっては速くなるかもしれないと思ってA*で書いていたが、

  • ヒューリスティック関数で常に0を返すようにしても本番のマップだとタイムが変わらないのでダイクストラに修正。
  • 隣接ノードへの移動コストはすべて1なので単純なBFSに(priority queueやsorted arrayがいらない)。
  • DFSに変更しても本番のマップ5つすべてクリアできることに気付きDFSに(shiftよりpopの方が短い)。

という感じ修正して、今回の条件だと単純な実装が一番速いという結果に。 たぶんマップが小さくて経路も少なく、A*が有利になるようなマップ(スタート・ゴールが偏っていて経路が直線的なのとか)もなかったのだろう。

工夫した点は

  • マップや探索済みノードの情報を二次元配列(というかjagged array)で持つとコストが大きいので、一次元配列を採用。 座標(x, y)をx + マップ幅 * yというインデックスに変換して扱うが、単純なBFS/DFSでは座標を意識する必要すらなかったので低コストにできた。
  • スタート・ゴール以外は壁で囲まれていることを利用して、インデックスが範囲外かどうかのチェックを省略。
  • ただし、スタートから左に移動すると壁がないため、改行($/)を壁(#)に置換。
  • 探索済みノードの情報を上記の壁情報と共通化。
  • すべてのマップでスタート位置が同じで二行目先頭だったため、マップ幅の計算をスタート位置で代用。

といったところ。

変数のスコープ的にwhile修飾子が使いにくいことを実感したので何か言語仕様の変更を提案しようかとも思ったが、ゴルフとかでしか使わなさそうだ(し自分はゴルファーじゃない)からやっぱりいいか。

Tags: Ruby

2016-11-18 (Fri) [長年日記]

_ リモコンキーの電池交換

電池交換

エクシーガ(CBA-YA5)のリモコンキー(非キーレスアクセス)の効きが悪くなったので交換した。

電池の型番はCR1620だった。

Tags:

2016-07-29 (Fri) [長年日記]

_ チェーン&スプロケ交換

チェーン&スプロケ

注文していたチェーンとスプロケが届いたので、交換してもらった

チェーンはDIDの428NZ。 スプロケはSUNSTARを勧められたが、15Tの設定がなかったらしく、フロントは結局キタコになった。

14T/47T→15T/47Tにして巡航が少し楽になった。

Tags: KLX125

2016-07-23 (Sat) [長年日記]

_ エキパイ交換

交換前

KLX125はあちこちすぐ錆びてくるのだが、エキパイとヒートガードがかなりひどいことになってきた。 いっそのこと、YZF-R25とかに買い換えたいが予算がない。

BEAMSのフロントパイプが安かったので交換してみた。

交換後

ステンレス製なのでもう錆は大丈夫なはず。

ヒートガードが小さいのでズボンが溶けたという話も見かけたが、乗るときに気を付ける方向で。

Tags: KLX125