すごいH本のチェスの演習問題書いた

「すごいHaskellたのしく学ぼう!」の308ページの、3手で到達できるときその途中経路を出力する演習問題を書いてみた

import Control.Monad

type Route = [(Int, Int)]

routeStart :: (Int, Int) -> Route
routeStart x = [x]

inBoard :: Route -> Bool 
inBoard (x:xs) = x `elem` [(a,b) | a <- [1..8], b <- [1..8]]

possibleRoute :: Route -> [Route]
possibleRoute all@((x,y):xs) = do
  (dx,dy) <- [(2,1), (-2,1), (2,-1), (-2,-1), (1,2), (1,-2), (-1,2), (-1,-2)]
  let p = (x+dx, y+dy)
      r = p:all
  guard $ inBoard r
  return r

canReachIn3 :: (Int, Int) -> (Int, Int) -> [Route]
canReachIn3 s g = filter (\x -> head x == g)
                  (return (routeStart s) >>= possibleRoute >>= possibleRoute
                  >>= possibleRoute)

数学は若いころしか出来ない系語録(適当に更新)

いろいろためていってSAN値を下げていこう。随時募集中。

「若いころしか出来ないから急いだほうがいい、例外はあるけど」

うろおぼえ。「怠け数学者の記 (岩波現代文庫)」だったと思う。あと、小平邦彦が言ったわけではなくて、小平さんがプリンストンにいたときに一級の数学者の誰かに言われた言葉だったと思う。

「若くて一番頭のいい時期に数学をやり、少し悪くなったところで哲学をやり、それも出来なくなって歴史をやった。」

ラッセルらしい。

Amazon,ある数学者の生涯と弁明


ここのレビューから。

「かつてはあったがもう二度と帰って来ない創造的能に対する熱烈な嘆き」

Wikipedia,ある数学者の生涯と弁明

カナダ式キーボードでバックスラッシュを打つ

フランス語でTeXやろうとしたらバックスラッシュをどう打つかわからなかったのでメモ。

アクサンの入力

カナダキーボードでは本来はAltGr(AltCar)キーとナンバーキー(?、#キー。)を打てばよいのだが、日本語キーボードではそれぞれ右Altと半角全角キーに対応しているので、右Altを押しながら半角全角を押せばよい。が、うちには右AltがなかったのでKeySwapを使ってひらがなキーを右Altにした。

ギュメ(引用符)の入力

スクリーンキーボードには出ているが対応するキーがよくわからなかったのでEmacs上で何とかしようと思います。キーボードマクロでなんとかしましたが、できあがったものはとにかくこれです。

.emacsのなかに

(load-file "~/french.macs")

homeのfrench.macsに

;; -*-coding:iso-8859-1-*-

(fset 'insert-guillemet
[?« ?» ?\C-b])

としました。ファイル分割しないと文字コードが面倒なのです…


Emacs上でのエンコーディング

%% -*-mode: yatex; coding:iso-8859-1-*-

をつけて保存しました。

TeXでLatin-1を使う

とりあえずこのへん(http://www.tuteurs.ens.fr/logiciels/latex/manuel.html)を参考にいろいろくっつけて、

\usepackage[latin1]{inputenc}
\usepackage[francais]{babel}
\usepackage[cyr]{aeguill}
\usepackage[T1]{fontenc}

とした。何が何かは後で調べよう。

TeXにかます

pLaTeXがsjisにしか対応しないらしくあれなのでLaTeXにやったらうまくいった。

画面遷移構造雑考(一応完結)

Bonjour!前回の更新からもう200日近くたっているようです。あれまあ。最近はC#+XNAでいそいそゲーム開発駆け出しをしていて、今はライブラリ整備をしているのですが、遷移構造のところで霧中になってしまったので、書いて整理をしたいと思います。

定義

「画面遷移」という言葉は割りとポピュラーなようですが一応自分の確認のためにも定義を確認してみます。ゲームにおいては、大きく画面の見た目と機能が変わることがあります。たとえば、タイトル画面で"Press Any Key"と出ているときに何らかのキーを押せばたぶんメインメニュー画面に飛ぶでしょう。タイトル画面においては画面上で何か動かす処理やら、キーに反応してメインメニュー画面に飛ぶ処理やらが要求されますし、メインメニュー画面においては矢印キーで項目を選択したり、項目を表示する機能が要求されるでしょう。このように、タイトル画面の処理とメインメニュー画面の機能には明らかに関連が薄いので、これらの処理を一箇所にまとめて書くのはコードの可読性からして問題だと思われます。そこで、画面の状態で明らかに違うように分けたとき、それらの画面を互いに(何らかの規則にしたがって)移り変わる構造のことをこの記事の中では「画面遷移」と呼ぶことにします。

なぜこれのことで悩む必要があるのか。いい加減に作ればいいのではないか。

確かにいい加減に作って問題が出てから直せばいい、悩んだって徒に時間を消費するだけだというのはそんな気もするし、今のモットーとして「できるだけ小柄に」を採用しているのではっきり言って真理なのですが、ここであえてじっくり悩んだほうが良いと考える理由は次のとおりです。

画面遷移構造はどんなゲームにも出てくる

ミニゲームにしてもタイトル画面、ゲーム画面、リザルト画面の3つは出てきますし、何を作るにしても画面遷移から目を背けている間ずっと苦しむことになります。

可読性にたぶん効いてくる

「困難は分割せよ」は理系の基本ですが、画面遷移を上手に作れば画面ごとに分けてプログラムを書くことをプログラマに推奨することが出来る、というわけで眠いときにプログラムを書いてもそこそこ可読性の高いものを書くことが出来る、はず。

pygame時代の反省

pygame時代に安直に組んだら(あれはあれでそこそこ使えたのですが)もっと複雑なものを作ろうとすると面倒なことになるということが当時わかったのですがその問題点については後述。

考えてみる

ざっくり考えてみる

まず前提として、ゲームは主に描画をつかさどるDrawメソッドとロジックをつかさどるUpdateメソッドとから成っています。というわけで、SceneクラスにDrawメソッドとUpdateメソッドを持たせて、メインのところにSceneの変数CurrentSceneを持たせ、そのSceneを次々取り替えていき、メインのDrawとUpdateからCurrentSceneのDrawとUpdateを呼び出せば作れそうです。

どう実現するか

いきなり閑話休題なのですが、これをXNAでどう実現するかが不安なので少し考えてみます。いまいちXNAのフィロソフィー*1がよくわからないのですが、基本的にゲームで扱うもの全般はGameComponentというものらしく、それをGame.Components(ComponentsはGameComponentのCollection)にAddすると有効になるみたいな雰囲気みたいです。DrawableGameComponentというGameComponentを継承したクラスはUpdateとDrawを持っていて、Addしておくと自動的に呼んでくれます。というわけで登場人物的なものはGameComponentを主軸に書いていくことを考えています。もっといい方法(というかXNA開発者の意図した方法)を知っている人がいたら教えて下しあ><。問題はGame.Componentsがデフォルトでは1個しかなく、これに階層構造を持たせる方法も見たらないので、これをどう扱っていくかというところになりそうです。(そしてこの基本方針が一番怪しい。

そういうわけで、各SceneにIsDeadみたいなメソッドを持たせて、メインのUpdateからそのIsDeadを呼び出し、そのSceneがすでに終了したことがわかったらそのSceneに所属するGameComponentをSceneから取得してそれらをGame.Componentsから削除し、またそのSceneから次のSceneを受け取ってそれをメインのCurrentSceneに代入して作ればよさげです。*2

遷移エフェクトについて考えてみる

ところでこのまま実装するとたぶん画面が一瞬で切り替わってしまいますが、普通画面が切り替わるときは画面がゆっくり暗転するなりの画面の移り変わりのエフェクトがかかるものです。パワーポイントをご存知の方は「ワイプアウト」などを想像していただければそれです。というわけでそれを組み込むことを考えてみます。画面遷移時に遷移前のSceneと遷移後のSceneの両方にアクセスすることが考えられるので、先ほどあったCurrentSceneのほかにPreviousSceneも必要になりそうです。またSceneは、今自分が遷移中でCurrentSceneであるのか遷移が終わってCurrentSceneであるのかPreviousSceneであるのかを区別する方法が必要になります。うち、PreviousSceneであるかどうかは、そのSceneを終わらせるかの裁量はそのSceneにあるわけで、それを示すのがIsDeadでしたから明らかですが、遷移中でCurrentSceneであるのか遷移が終わってCurrentSceneであるのかの情報は遷移をつかさどるものに裁量があるはずです。というわけで、いったんこの「遷移をつかさどるもの」をどのように作るべきかを考えるのがよさそうです。

と、一瞬思ったのですが

CurrentSceneだけでなんとかなる気がしてきました。つまり、Scene甲がその役目を終えたときに、そのScene甲を次のScene乙に渡してしまい、CurrentSceneをScene乙にして、遷移エフェクトはScene乙に担わせればそれでいいような気がしてきました。そして、Scene乙は遷移が終了したときにScene甲を破棄します。このほうがすっきりしていますし、「ざっくり考えてみる」で考えたところからたいした変更なしに実現できそうです。一応、Scene甲はScene乙を生み出して参照せずにメインに渡しますし、Scene乙はScene甲を参照するだけなので、相互参照にはなっていないはずですが、破棄タイミングは不安です。そういうわけで、SceneがPreviousSceneを持つことになりそうです。

どう実現するか

二つの画面を扱うということは、それぞれのSceneについて、その画面を直接にスクリーンにアウトプットするわけには行きません。具体的に考えればすぐにわかる話で、たとえば簡単そうなワイプアウト、つまりScene甲の画面が徐々に左に押し出されていき、Scene乙の画面が右からScene甲を押し出すように入ってくるような遷移エフェクトを考えれば、直接にScene甲やScene乙の画面がスクリーンに直接アウトプットされると、そのアウトプット位置が制御できないためにワイプアウトは実現できなくなってしまうことがわかると思います。というわけで、少なくとも画面遷移中はScene甲や乙の画面は画像としてアウトプットされ、その画像を配置するという風にしないと実現しえません。画像の出力先を2DテクスチャであるTexture2Dにするためには、
http://stackoverflow.com/questions/8425922/draw-a-string-to-texture-in-xna
この辺のことを使えばいいと思うのですが、この辺で煮詰まったのでまた後で。

一度Componentsについて考えてみる(そして昨日煮詰まった原因)

なんかComponentsのなれない仕様に惑わされている気がするので、一度Componentsについてまとめなおしてみます。Game.ComponentsはGameComponentCollectionであって、MSDNhttp://msdn.microsoft.com/ja-jp/library/microsoft.xna.framework.game.components%28v=xnagamestudio.40%29.aspxによれば、

ゲームに対してゲーム コンポーネントを登録するには、対象のコンポーネントを Game.Components.Add に渡します。登録されたコンポーネントは、Game.Initialize、Game.Update、および Game.Draw メソッドから呼び出される描画、更新、および初期化メソッドを持ちます。

とのことなので、描画、更新のするされないはComponentsに含まれているいないで決まるわけです。(本当はGameComponentのVisibleをfalseにしてしまうととまるのですが、使わないものがコレクションに居座っているのも気持ちが悪いので、これに関しては心の片隅に止めつつなかったものとして考えて見ます。)このことを意識しておくと、(抽象的な言葉遣いになってしまうのですが)Sceneは基本的にはGameComponentを包むものであって、SceneがComponentsへSceneの保有するGameComponentを出し入れするという使い方が基本になりそうです。

おそらく(自分のことなんですけどね)昨日煮詰まった原因はここにあります。CurrentSceneがPreviousSceneSceneを保有する形にしてしまうと、CurrentSceneがアクティブなわけですからCurrentSceneのGameComponentはComponentsに登録されているわけですが、その内部でPreviousSceneを生かしておくからにはCurrentScene.PreviousSceneのGameComponentもComponentsに登録されてしまっていて、2画面を描き分けることが出来なくなってしまいます。つまり、機能考えた「と、一瞬思ったのですが」の「どう実現するか」は結構気持ち悪いということがわかりました。

で、どうするか

Game.Componentsの仕組みから言って、どう考えても1フレームには1Sceneにつき1回しかDrawやUpdateしか呼べないことになりますから、割と振り出しに戻った観はありますがComponentsをSceneにも持たせるということになりそうです。なんかすごい回り道でしたが(ここまでで約4500文字)、まあこれしかないという証明が出来てよかった…

とりあえず遷移なしのSceneの再構成

SceneはGameComponentを継承したクラスで、Scene.Componentsを持つ。Scene.DrawではScene.Componentsのすべてに対してDrawが呼ばれ、Scene.UpdateではScene.Componentsのすべてに対してUpdateが呼ばれ、Scene.InitializeではScene.Componentsのすべてに対してInitializeがよばれる。Sceneがアクティブなとき、そのSceneはメインの(つまりGameの)CurrentSceneに入っていて、またGame.Componentsにも入っている。基本的にGame.Componentsの中は1つのSceneだけが入っていることになる。デバッグ用とかで2つ以上にはなるかも

画面遷移ありのSceneの構成

やっぱり遷移のコードとSceneのコードは切り分けておいたほうが良い気がするのでそういう方針で作る。遷移もある意味Scene的な要素を持っているので、むしろ遷移もSceneの一種として捉えたほうがいいような気がしてきた。つまり、Sceneはゲーム中の画面を担うGameSceneクラスと遷移を担うTransSceneクラスに派生し(インターフェースでもいい、というかSceneはインターフェースのほうがいいような気が…)、TransSceneクラスは2つのGameSceneである、遷移前のGameScene甲と遷移後のGameScene乙をとる。遷移中はメインのCurrentSceneはTransSceneになる。TransScene.DrawメソッドでGameScene甲や乙のDrawを呼び出してその画面をTextureに振り向け、適当に処理して描画するということになる。遷移が終わったらTransSceneにもIsDeadがあって、GameScene同様Scene切り替えの手続きでメインのCurrentSceneをScene乙に切り替える。

各GameSceneはやはり遷移中でアクティブであるのか遷移が終わってアクティブであるのかすでに役目を終えたのかの3状態を持つことになる。遷移中かどうかはメインから(あるいはTransSceneから)与えら得る情報なので、その窓口としてStartMainPhaseみたいな遷移が終わったときに呼ばれるvoidのメソッドが必要になる。

SceneはIsDeadとGetNextSceneを持つことになる。メインはUpdateでCurrentScene.IsDeadを呼んで、trueならGetNextSceneで次のSceneを取得しCurrentSceneとする。

だんだん文章がひどいことに…

Sceneは階層構造を持つかもしれない

いままでは2状態の遷移だけを考え、遷移したら遷移した前のことはさっぱり忘れてしまっていたのですが、それだけではすまないかもしれません。たとえば、シューティングゲームでのポーズ画面は一種の状態かもしれません。(最初の定義の「明らかに違う状態」かどうかは怪しいですが。)そのとき、ポーズ中のSceneはゲーム画面にオーバーラップして表示されることになるでしょう。つまり、ゲームのSceneにアクセスできないと困るわけです。

どう実現するか

すると、SceneがSceneを持つことになるかもしれませんが、これを実現するためにいままでの構造を変更する必要はなさそうです。
f:id:sle:20120919234005p:plain
たとえば上のような状態を考えてみたいと思います。TitleからGameってなんやねんという気がするのですが、間にMenuを挟んでもあまり本質的ではないので省きました。鍵は右二つのMainMenuとSystemMenuで、想定としてはゲーム中にEscか何かを押すとSystemMenuに入ってゲームの中断(Titleへ戻る)ができ、さらに左右キーでItemMenuとSystemMenuを行き来できるというところです。二つのMenuはGame画面にオーバーラップして描かれるわけですからGameへのアクセス権が必要です。

今までと主に違うのはGameからSystemMenuへの遷移ですが、これは遷移時にSystemMenuがGameを要求するようにしておけばいいのではないでしょうか。そして、CurrentSceneはSystemMenuのSceneになります。また、ItemMenuに移るときもやはりGameが要求され、これはSystemMenuから渡されます。


なんか満足したのでこの辺で。そのうち推敲するかも。

*1:不安になってぐぐってみたのですが、"Philosophy of Programming Languages"という用法があったので良かった。「その言語はどう使われることを意図しているか」ぐらいの意味のつもりです。

*2:相互参照でどうこうする方法もあるとは思うのですが、一応避けられる場面なら避けておこうかなーと。

「Star Guard」やってみた

「250 Indie Games You Must Play」に載っていたインディーズゲーム「Star Guard」をやってみた。スクショとればよかったんだけど忘れてた。今度からつける。ご意見歓迎。

どのぐらいやったの?

ノーマルモードクリア。ミスあり。

入手法

「250 Indie Games You Must Play」に載っている入手先は404。新しいのはhttp://vacuumflowers.com/star_guard/index.html。WindowsとMacに対応。しかし、Flashゲームなんだから工夫すればLinux系でもいけるのではないか。

ゲーム概要

アクションシューティングゲーム。主人公の緑の人を操作して、ステージ(重力あり)を駆け巡り、モンスターを倒したりやりすごしたりしつつ、悪い魔法使いの撃破を目指す。

システム

全9面の面クリア型。セーブ不可。主人公は、ジャンプ(zキー)とレーザーガン(xキー)で戦う。緑色の味方もいて一緒に戦ってくれるがあまり頼りにはならない。敵はレーザーガンで何度か撃つと倒せる。踏んでも倒せない。一部の敵は倒れた後死体のようになるのだが、しばらくすると復活して白い敵になる。それで倒すと完全に撃破となるが、白い敵は倒しても点が入らないので、できるならさっさと逃げるが吉。最初から倒れたようになっているが、ある地点まで到達すると突然動き出したりする敵がいるのに少し理不尽さを感じた。しかし、割とこまめにステージ中チェックポイントが設置されており、死んでもさくさくやり直すことが出来るので、そのあたりで理不尽さを中和しているように感じる。また、死んでも一度倒した敵が復活したりはしないので、死ねば死ぬほど楽になるということになる。ノーミスクリアは至難かと。死んだ復活直後は無敵状態で、しかもその間に敵に触れると倒せるのでそれで多少楽できる。ステージ中にはダイヤモンドみたいなアイテムが設置されており、取るとボーナス点になる。ギミックとしては、崩れる床やら固定砲台やら、定番どころは押さえているが、組み合わせ方使い方がうまく感心した。ラスボスは3形態ぐらいあって、結構歯ごたえがあった。第1形態はパターンを見抜けばなんとかなる。第2形態もやることはすぐに気づくはず。第3形態はそろそろ疲れてきていて、しかも先述のセーブポイントがあったので、ショット連打で終わらせてしまった。ストーリーは背景として、文字情報で与えられるのはゲームの邪魔をせず好感が持てたのだが、当然英語だし妙に難しいし、ゆっくり読んでいるとやられてしまうので全然読めなかった。ネイティブなら余裕だと思う。

グラフィック

非常にシンプル。黒い背景で、主人公は緑、敵および触れると死ぬものは赤、破壊できないものは白い囲いと、うまくシステム的な情報をグラフィックに自然に乗せられている。このため、説明書がなくてもすぐに細かいルールが飲み込めるようになっている。敵にショットがヒットしたときに破片みたいなものが出るあたり細かい。敵の外形とその動きがよくマッチしていて、個性がよくついていると思う。

ただ、主人公の移動速度や、死んだときのセーブポイントまでの視点移動が速いせいか、2Dゲームにもかかわらず画面酔いしてしまった。画面サイズを縮められるので、それで多少は改善されたが、それと先に進めないストレスが重なってしまってクリア時にはぐったりだった。単にアクションゲームをプレイするのが久々だったからかもしれない。だとしたら作者に申し訳ないことをした。

サウンド

BGMはなし。これでほとんど同じ見た目の9面の間行くのは精神的に疲れた。音楽によって面の特徴づけをすることの重要性を再認識。

技術

Flash Playerが同梱されていて、それでプレイするのでFlashゲームと思われる。破片が飛び散るなどは細かいなあと思ったが、Flashならそういう挙動は得意分野だろうし実はたいしたことはないのかもしれない。ジャンプは長押しすると高く飛べる方式。敵の制御は丁寧なつくりなのではないか(あまり比較対象を知らない)。

こまごまと

どうもSF小説に影響を受けて作ったゲームらしい。そういう作り方もあるのね。

総括

とにかく酔った。それのせいでいろいろものがゆがんで見えてしまっている気もする。本の売り文句が"Presents 250 influential and fun indie video games"となっていたし、Independent Games Festival 2010でデザイン賞を受賞しているしで、かなり期待して望んだのだが、ちょっと過度の期待をしすぎたかなあと。製作面で学ぶことは結構あったように思える。

Vim User Manual読む usr_04

自分なりにまとめとかが入ったり。

usr_04

wind up

In fact, the "d" command may be followed by any motion command, and it deletes from the current location to the place where the cursor winds up.

"wind up"を「到達する」ぐらいにとらないと意味が分からない。"wind up"に「最後に~になる」というのがあり、

You may wind up losing your house.
家を失う羽目になるかもしれない。

というのがあるので、"the cursor winds up at the place"をwhereやらなんやらで書いた感じなのかもしれない。

inclusiveとexclusive

"w"では、カーソルは次の単語の先頭まで移動するが、"dw"とするとカーソルの移動先の一文字前までしか消えない。一方、"e"では、カーソルは次の単語の末尾まで移動するが、"de"とするとカーソルの移動先まで消える。このように、カーソルの移動先まで操作の影響が及ぶかどうかに関する移動コマンドの性質をexclusiveやinclusiveと呼ぶ。カーソルの移動先まで操作の影響が及ぶとき、その移動コマンドはinclusiveであるといい、カーソルの移動先までは操作の影響が及ばないとき、その移動コマンドはexclusiveであるという。"w"コマンドはexclusiveで、"e"コマンドはinclusive。"$"コマンドはinclusiveである。

操作コマンド(operator command)

テキストに対して、削除や変更などの操作を行うコマンド。"d"とか。

移動コマンド(motion command)

テキスト上でカーソルを移動するコマンド。上述のとおり、inclusiveとexclusiveとがある。"w"とか"e"とか"$"とか。

"操作コマンド-移動コマンド"のパターン

まず最初に操作コマンドを入力し、次に移動コマンドを入力する。このようにして、カーソルが動いたテキスト全体に対して操作が出来る。例えば、操作コマンドとして"d"、移動コマンドとして"4w"を選んで、"d4w"と入力すれば、4単語削除となる。

c

変更コマンド。対象を削除した後、インサートモードに入る。

ただ、"cw"の挙動にだけはVi由来の例外がある。

To err is human

で、"e"にカーソルを合わせた状態で"c2w"を実行すると、"To"の後と"human"の前の2箇所に空白が残る。一方、"2dw"を実行すると、"To"と"human"の間に1つだけ空白が残る。結局、"cw"は"ce"として振舞うことになる。

ことわざ

There is a saying that for every problem there is an answer that is simple, clear, and wrong."

Henry Louis Manckenという批評家の言葉らしい。どちらが先かは知らないが、調べたらこういうのもあった。(http://www2.wbs.ne.jp/~hhayashi/page338.html)

For every problem, there exists a simple and elegant solution which is absolutely wrong. - J. Wagoner, U.C.B. Mathematics

こちらの方が若干分かりやすい気がする。

cc

一行変更。インデントは残される。

ショートカット

x

"dl"と同じ。"l"はexclusive。

X

カーソルの左の文字を削除。"dh"と同じ。"h"はexclusive。カーソルの走る範囲は2文字だが、exclusiveの仕様として、移動方向にかかわらず走った範囲の右側(後方)が操作コマンドの対象から外れるらしい。(実験による。)

D

"d$"と同じ

C

"c$"と同じ

s

一文字変更。"cl"と同じ。(Substitute)

S

一行変更。"cc"と同じ。

difference without a distinction

The commands "3dw" and "d3w" delete three words. If you want to get really picky about things, the first command, "3dw", deletes one word three times; the command "d3w" deletes three words once. This is a difference without a distinction.

"distinction"は本質的な違いを表して、"difference"は表面上の違いを表すのか。

r

1文字変更のコマンド。(Replace)"r"を押した後1文字入力すると、カーソル下の文字が置き換わる。カウンタをつけるとその文字がカウンタの個数分現れる。改行コードで置き換えることも可能。このときカウンタを使うと、カウンタ分文字を消去して、1つの改行ができる。

.

最後の変更を繰り返す。アンドゥ、リドゥ、:コマンドは繰り返せない。

ビジュアルモード

vコマンドで、今のカーソル位置をスタート地点としてビジュアルモードに入る。その状態でカーソルを動かすと範囲がハイライトされる。そこで、操作コマンドを叩くとハイライトされた範囲に操作がなされる。ビジュアルモードに入ったけど特にすることがなかった場合はEscでノーマルモードに帰れる。

行ビジュアルモード

Vコマンドで行全体を選択するビジュアルモードに入れる。上下でたくさんの行を選択できる。

矩形ビジュアルモード

CTRL-Vで矩形ビジュアルモードに入れる。矩形に選択できる。表相手とか便利。

ビジュアルモードの反対側

ビジュアルモードに入ったはいいが、よく考えたらスタート地点が間違っていたというときに、"o"コマンドで、ビジュアルモードのスタート地点をカーソルで動かせるようになり、今カーソルのあるところが新たにスタート地点になる。

p

貼り付け。(Put)"d"や"x"で削除したテキストは保存されており、"p"で貼り付けることが出来る。貼り付け位置は、削除したのが行全体であればそのカーソルの下の行。そうでなければカーソルの直後。カウントがつく。

P

貼り付け。貼り付け位置は、削除したのが行全体であればそのカーソルの上の行。そうでなければカーソルの直前。カウントがつく。

xp

切り取って貼り付けの組み合わせ。つまり、2文字の入れ替え。

y

削除した後アンドゥするのと同じ。つまり、コピー。(Yank:ぐいっと引く)対象のテキストをレジスタにコピーする。あとは"p"で貼り付けられる。

yy

1行全体をヤンク。

Y

"yy"と同じ。"D"が"d$"と同じであることを考えると一貫性がない。

"*y

クリップボードにコピー。"y"の前に""*"(ダブルクオートスター)をつければいい。

"*p

クリップボードからペースト。"p"の前に""*"をつければいい。

テキストオブジェクト

操作コマンドの後につけて使える、対象を指定するコマンド。

aw

単語をあらわすテキストオブジェクト。(A Word)"daw"で、カーソルがその単語中の何処にあろうがその単語を削除できる。

is

文全体をあらわすテキストオブジェクト。(Inner Sentence)文の後の空白を含まない。** as
文全体をあらわすテキストオブジェクト。(A Sentence)文の後の空白を含む。

text-objects

helpの"text-objects"にテキストオブジェクトのリストがあるらしい。

リプレースモード

Rでリプレースモードに入れる。Escで脱出。入力すると、文章を上書きしていく。行の長さが足りなければ自動的に延長される。Insertキーでインサートモードと切り替えられる。Backspaceで訂正しようとすると、もとの文章が復元される。

~

大文字小文字を入れ替える。操作コマンドではないので、一括して実行したければビジュアルモードからやる必要がある。

I

カーソルのある行の最初の非空白文字までカーソルを移動してインサートモードに入る。

A

カーソルのある行の末尾までカーソルを移動してインサートモードに入る。

Vim User Manual読む usr_01-03

いままでも何度か挑戦してきたけど、読む先から忘れていって悲しいので記録をとりながら読む。分からなかった英文、英単語もついでに書いていく。登場したコマンドはすべて書いていく。覚え方みたいなものがあればそれも書く。

usr_01.txt

CTRL-]

ヘルプ中で、カーソル下の項目にジャンプ。

CTRL-O

ジャンプした後に、元の場所に戻る。help読んでてどういうわけか訳の分からないところにジャンプしたときに便利。(Older cursor position)

Vim Installed

香り屋さん版なので読み飛ばす

This material may be distributed only subject to the terms and conditions set forth in the Open Publication License.

set forth:説明する

usr_02.txt

In either case,

"cases"とかにならないのね。eitherは不定冠詞相当語なるものらしく、この場合冠詞をつける必要はないらしい。

Either book will do. (どちらの本でもよい)

In other words, when Vim runs out of file to display.

"runs out of..."と読んで、「ファイルを使い果たす。はて。」などと思ったので。ファイルを読んでいって一番下まで来るさまが"run out of..."らしい。「[品物を]切らす、ネタ切れになる」や「[容器に入っている水が]流れ出る」あたりが近いか

i

ノーマルモードからインサートモードへ。(Insert)

programmer's limeric

A very intelligent turtle
Found programming UNIX a hurdle

ぐぐると、http://www.indigo.org/humor/unixhumor.htmlに、

A very intelligent turtle
Found programming UNIX a hurdle
The system, you see,
Ran as slow as did he,
And that's not saying much for the turtle.

とある。なんか創世記っぽいが、元ネタ不明。turtleが何の洒落なのかよく分からないし日本語訳も見当たらない。「UNIX ジョーク 亀」あたりで調べてると「亀レス」という言葉が目に入り、動作がとろいと言いたいのかとようやっと気づく。であれば、

とても賢い亀が
UNIXはハードルであると気づいた。
システム、見てのとおり、
彼が走るように遅い。
そして、そんなことはその亀にとって当たり前であった。

か?なんか面白くない。何か分かっていないのだろう。
That's not saying much.:「そんなことは当然だろう」

Q_in

ヘルプのQ_inにテキスト変更のコマンドのリストがあるらしい。(Quickreference INsert)

:set showmode

現在のモードを見えるようにする。

Esc

インサートモードからノーマルモードへ。ノーマルモードにいるときにEscを押すとビープがなるらしい。困ったときはビープがなるまでEsc連打し、ノーマルモードへ戻る。

For Japanese users, Hiroshi Iwatani suggested using this:

hjklの覚え方。

For Japanese users, Hiroshi Iwatani suggested using this:

			Komsomolsk
			    ^
			    |
	   Huan Ho	<--- --->  Los Angeles
	(Yellow river)	    |
			    v
			  Java (the island, not the programming language)

Komsomolsk:コムソモーリスク
つづりの雰囲気で北の方だと分かるといえば分かるけど。"Huan Ho"はお手上げです><

x

カーソル上の文字を削除。(タイプライター時代に訂正箇所をxで上書きしていたらしい)

dd

一行削除。(Delete)

J

行の連結。(Join)

n行目で実行するとその行の改行記号を削除し、n行目の最後に(n+1)行目が連結される。

u

アンドゥ。(Undo)

CTRL-R

リドゥ。(Redo)

U

一行の変更全体に対してアンドゥ。これそのものが変更扱いなので、Uしたあとにuすると、Uする前の状態に戻り、さらにCTRL-RするとUした後の状態に戻る。a bit confusing.

a

カーソルの右側でインサートモードに入る。(Append)

o

カーソルのある行の下に空の行を作る。(Opening up a new line)

O

カーソルのある行の上に空の行を作る。

カウント

多くのコマンドは頭に数字をつけることで繰り返せる。"a!!!"が"3a!"でいいのはなんか不思議。

ZZ

保存して終了。

:q!

変更を破棄して終了。(Quit-and-throw-things-away)

:e!

変更を破棄して読み見直し。!はoverride command modifierと言うらしい。

:help

ヘルプ。F1でもいいらしい。ZZで脱出。このときVimは終了しない。

:help

一般ヘルプ。後ろにいろいろつけることができる。

:help {コマンド}

そのコマンドについてのヘルプ

:help {したいこと}

:help deleting

:help index

コマンドの完全な目録

:help {キー}

そのキーのコマンドについて。特殊キーについてはのようにする。

:help CTRL-A

どのモードでの挙動かを明示したいときには、モードの接頭辞をつける。接頭辞のリストは"help-context"でhelp。

:help i_CTRL-H

:help {コマンドライン引数}

:help -t

:help '{オプション}'

オプションについて調べたいときはシングルクォーテーションで囲む。

:help E{エラー番号}

E37: No write since last change (use ! to override) ~

のように出たとき、エラー番号のエラーについて調べる。

CTRL-T

タグ(バーで囲まれたやつ)をさかのぼって戻る。CTRL-]の逆。CTRL-Oは「元の場所に戻る」らしい。

ヘルプのまとめ

Summaryがついてたorz

usr_03.txt

Q_lr

helpのQ_lrにカーソル移動のコマンドのリストがあるらしい。(Quickreference Left-Right motions)

w

1単語後方の語頭に移動。(Word)

b

1単語前方の語頭に移動。(Backward)

e

1単語後方の語尾に移動。(End of word)

ge

1単語前方の語尾に移動。(gは何?)

'iskeyword'

'iskeyword'オプションで、単語の定義を変えられる。

WORDs

空白で区切られたひとまとまりのことをWORDと呼ぶらしい。

W

1WORD後方の先頭に移動。

B

1WORD前方の先頭に移動。

E

1WORD後方の末尾に移動。

gE

1WORD前方の末尾に移動。

$

行末に移動。Endキーと等価。"$"をたくさん繰り返しても意味はないが、"2$"にすると、一度行末に行った後、次の行末に行く。つまり、"n$"で、(n-1)行下の行末に移動する。

^

行の空白でない文字の中で先頭のものに移動。カウントをつけても意味はない。

0

行頭に移動。Homeキーと等価。0そのものが数なのでカウントがつかない。

f{1文字}

後方のその文字に移動。(Find)

F{1文字}

前方のその文字に移動。

t{1文字}

後方のその文字の1文字手前に移動。(To)

T{1文字}

前方のその文字の1文字後に移動。何に使うんだろう…

;

先に行われたf,F,t,Tを繰り返す。

,

先に行われたf,F,t,Tを逆方向に繰り返す。

only to

そんなのあったなぁ。

Sometimes you will start a search, only to realize that you have typed the wrong command.

Esc

f,F,t,Tまで押しちゃって、中止したいときに押せば何も起こらない。

%

対応する括弧に移動。()、[]、{}に対応。もし、カーソルが括弧の上にないなら、後方の括弧を検索しそこに移動する。括弧は、'matchpairs'オプションで設定できる。

G

カウントをつけると、そのカウントの値の行に移動。例えば、33Gで33行目に移動。カウントをつけないと、ファイルの終わりに移動。(Goto)

:make

コンパイラのエラーに対応してファイルを編集するためには":make"を使えばいいらしく、usr_30.txtを見ればいいらしい。

gg

ファイルのはじめに移動。"1G"と等価。

{カウント}%

ファイルの{カウント}%の点に移動。

H

画面内の最初の行の先頭に移動。(Home)

M

画面内の真ん中の行の先頭に移動。(Middle)

L

画面内の最後の行の先頭に移動。(Last)

CTRL-G

'ruler'オプションがオフなら、現在位置を表示。

'number'

オンなら、行番号を表示。

:set number
:set nonumber

ブールオプションは、noを名前につけるとオフに出来る。

'ruler'

カーソルの位置を右下に表示。

CTRL-U

スクリーンの半分だけ前方にスクロール。(Upwards 巻物を枠越しに見て、巻物を上に持ち上げるのではなく、枠を上に持ち上げる感じか)

CTRL-D

スクリーンの半分だけ後方にスクロール。(Downwards)

scroll down

The CTRL-U command scrolls down half a screen of text.

普通に、「ファイルの先へ進むこと」ブラウザで言うならスクロールバーを下方にやることなのかと思ったのだが、どう考えてもCTRL-Uで実行されるのはファイルの先頭方向に進むこと、スクロールバーを上方にやることなので、大変不思議に思った。

CTRL-E

一行後方にスクロール。(Extra line)

CTRL-Y

一行前方にスクロール。(由来不明。yから始まる単語で最初に思いついたのが"yield"なのだが、"I can't yield an inch."「もう一歩も後に引けない。」というのがあるらしいのでそう思っておくことにする。)

CTRL-F

2行残して後方に一画面スクロール。(多分Forward)気になって調べてみたら、EmacsのCTRL-Fはカーソルを右に移動でforwardらしい。

CTRL-B

2行残して前方に一画面スクロール。(多分Backward)

zz

現在カーソルのある行が画面の中心になるようにスクロール。

zt

現在カーソルのある行が画面の一番上になるようにスクロール。(Top)

zb

現在カーソルのある行が画面の一番下になるようにスクロール。(Bottom)

Q_sc

helpのQ_scにスクロールのコマンドの一覧があるらしい。(Quickreference SCroll)

'scrolloff'

カーソル上下の数行が常に画面に残るように出来る。

/

前方に検索。/を押した後検索文字列を入れてEnter。検索文字列の修正は左右キーとBackspaceで。(一貫性ないなー。)「.*[]^%/\?~$」は特殊な意味があるので、「\」でエスケープする必要がある。カウントはつかない。

n

最後に行った検索をもう一度行う。(多分Next)カウントが使える。

?

後方に検索。/の後方版。?の後にnを使うとどんどん前方に遡っていく。

N

最後に行った検索を逆方向に行う。/の後にNを使うとどんどん前方に遡っていき、nを使うとどんどん後方に進んでいく。

'ignorecase'

検索時に大文字小文字を無視する。

検索履歴

/を入力した時点で、上下キーを押すと検索履歴をたどって、以前にやった検索ワードを出してくれる。途中までワードを入力して上下キーを押すと、そこから始まる検索ワードを出してくれる。:コマンドでも同様。/と:の履歴は独立している。

*

カーソル下の単語を後方に検索。カウントがつく。

#

カーソル下の単語を前方に検索。カウントがつく。

検索単語の区切り指定

"\>"は単語の終わりにマッチ。"\<"は単語の始まりにマッチ。

/\<the\>

は"the"のみにマッチし、"there"や"soothe"にはマッチしない。*や#による検索では自動で単語の始めや終わりにこだわって検索してくれる。もし、そこにこだわらないで検索させたければ("the"にカーソルを合わせて"there"や"soothe"にマッチさせたければ)、"g*"や"g#"を用いる。

whole, partial

"whole"「全体の」、"partial"「部分的な」ぐらいの認識でいたのだけれど、

Notice that the "*" and "#" commands use these start-of-word and end-of-word markers to only find whole words (you can use "g*" and "g#" to match partial words).

をこの訳で逐語訳すると

"*"コマンドと"#"コマンドは、全体の単語だけを検索するために、語頭マーカーと語尾マーカーを自動的に使用します。(部分的な単語にマッチさせるには"g*"コマンドや"g#"コマンドを使用しましょう。)

なんか意味が分からない。多分、"there"や"soothe"の中に生じた"the"に注目することが普段ないから変な感じがするのだと思う。"partial word"でぐぐってみたらちょうどそんな感じの用法が出てきたので、"partial word"は「部分的に生じた」ぐらいがいいのかなとか。"whole word"は明らかにその反対だから、「単語そのもの」ぐらいにするといいのかなー。

"*"コマンドと"#"コマンドは、単語そのものだけを検索するために、語頭マーカーと語尾マーカーを自動的に付加します。(部分的に生じた単語にマッチさせるには"g*"コマンドや"g#"コマンドを使用しましょう。)

こんな感じ?

'hlsearch',":nohlsearch"

'hlsearch'オプションをオンにすると、検索語がハイライトされる。ハイライトを消そうと思って"set nohlsearch"とすると、以降検索してもハイライトされなくなってしまう。今の検索後のハイライトを消したいが、今後検索するときはまたハイライトしてほしいときは":nohlsearch"という:コマンドを実行する。

'incsearch'

検索語を入力している間に、その入力中の語と一致する箇所を表示する。そして、Enterキーを押すと、表示されている箇所にジャンプする。

'wrapscan'

デフォルトでオン。検索をファイルの終わりや始まりで終了せず、ループさせる。カーソル位置からファイル末尾までというだけでなく、ファイル全体を包むように対象にすることになるあたりが"wrap"?

intermezzo

intermezzo:間奏曲

":scriptnames"

起動時に読み込まれるVimスタートアップファイルの場所を表示する。そこにVimコマンドを書いておくと起動時に実行してくれる。

:set hlsearch<Esc>

とあるので、行頭に:は書くのか。(書かないのをよく見る気がするので、どちらでもいいのかも。)

specify

(正規表現は強力だ云々)
Unfortunately, this power comes at a price, because regular expressions are a bit tricky to specify.

specify:明確に述べる

正規表現

正規表現の完全な説明はhelpの"pattern"に書いてある。

^は行頭にマッチする

"^include"は行頭の"include"のみにマッチする。

$は行末にマッチする

"was$"は"was"が行末にあるときのみマッチする。"/^the$"と検索すると一行に"the"しか書いてないときにマッチする。空白が入っているとマッチしなくなることに注意。

.はどんな文字にもマッチする

We use a computer that became the cummin winter.

で、"c.m"は、"computer"の"com"、"became"の"cam"、"cummin"の"cum"にマッチする。

もしも、.そのものをマッチさせたいときはバックスラッシュでエスケープする。"ter\."で検索すると、"winter."の"ter."にのみマッチする。

マーク

ジャンプする前の位置のことらしい。

``

ジャンプする前の位置に戻る。たくさんやると二点間を往復することになる。@キーのところにある"`"のことは「バックチック」とか「オープンシングルクオート」と呼ぶらしい。へー。

ジャンプ

Generally, every time you do a command that can move the cursor further than within the same line, this is called a jump. This includes the search commands "/" and "n" (it doesn't matter how far away the match is). But not the character searches with "fx" and "tx" or the word movements "w" and "e".

Also, "j" and "k" are not considered to be a jump. Even when you use a
count to make them move the cursor quite a long way away.

どういうことなの…

CTRL-I, Tab

CTRL-Oの逆。Tabでも同じ。(IはOの隣)

":jumps"

ジャンプする場所のリストを表示する。最後に使ったエントリの位置(?)は">"で表示される。

ジャンプまとめ
	     |	example text   ^	     |
	33G  |	example text   |  CTRL-O     | CTRL-I
	     |	example text   |	     |
	     V	line 33 text   ^	     V
	     |	example text   |	     |
       /^The |	example text   |  CTRL-O     | CTRL-I
	     V	There you are  |	     V
		example text

分かりやすい

m{マーク名}

名前つきマーク(ブックマーク)をカーソル下に作る。(Markか)マーク名はa-zの26文字から選べる。

`{マーク名}

そのマーク名のマークにジャンプする。

'{マーク名}

そのマーク名のマークの行頭にジャンプする。

''

元いた場所へジャンプ。多分行頭。

":marks"

マークのリストを表示。

特殊なマーク

'

ジャンプをする前のカーソル位置

"

編集した最後の位置

[

最後の編集の始まり

]

最後の編集の終わり