ProjectEuler.vim : VimからProjectEuler

ProjectEulerとは?

ProjectEulerとは、プログラムで解く数学の問題集です。
公式サイト:About - Project Euler
つまり、数学的知識が必要で、かつプログラムを組まないととてもじゃないけど解けない問題が多数公開されています(2009-2-24時点で279問あります)。ユーザー登録することで問題に解答できるようになります。問題の日本語訳は以下のサイトにあります。
日本語訳:Project Euler - PukiWiki

ProjectEuler.vimって何?

このProjectEulerの問題をVimから閲覧・取得・解答できるようにすのがこのProjectEurler.vimです。なんとなく作ってみました。

インストール方法

ソースは GitHub - mmisono/ProjectEuler.vim: vim plugin for Project Euler (http://projecteuler.net) にあります(gitとかはじめて使った)。

  • plugin/projecteuler.vim
  • syntax/projecteuler.vim
  • syntax/projecteulerP.vim
  • doc/projecteuler.txt
  • projecteuler (空ディレクトリ)

以上のファイル/ディレクトリを適当な場所に置いて、パスを通して下さい。
helptag path-to/doc/ でヘルプが追加されます。

コマンド一覧

:ProjectEuler [id]
Problem の解答をProjectEulerに投稿します。
idが指定されなかった場合はファイル名から推測、それでも分らなかった場合尋ねます。


:ProjectEuler -l [pagenr]
問題のリストの1ページ目を表示します。
pagenrを指定すればそのページのリストを表示します。


:ProjectEuler -p [id]
Probrem の問題を表示します。
idが指定されなかった場合はファイル名から推測、
それでも分らなかった場合尋ねます。


:ProjectEuler -s
自分のプロファイルを表示します。
問題の箇所でを押せばその問題を表示します。


:ProjectEuler -c
現在開いている問題の言語を入れ替えます。


:ProjectEuler -o [id]
Probrem の問題のページをブラウザで開きます。
idが指定されなかった場合はファイル名から推測、
それでも分らなかった場合尋ねます。


:ProjectEuler -u [username]
にユーザーを切り替えます。
が指定されなければ現在のユーザー名を表示します。


:ProjectEuler -r
現在のユーザーで強制的にログイン処理を行います。
Vimを使用中にCookieの有効期限が切れてしまった時に行って下さい。

変数一覧

g:projecteuler_user
ProjectEulerにログインするデフォルトのユーザー名


g:projecteuler_base_dir
ProjectEulerの問題およびCookieを保存するためのディレクト
let g:projectuler_base_dir = "path-to/projecteuler/"
みたいに設定して下さい。最後の/を忘れると正しく動作しません。
デフォルトではプラグインのおかれたディレクトリから../projecteuler/となります。
このディレクトリはあらかじめ作成する必要があります


g:projecteuler_browser_command
ProjectEulerの問題等を閲覧するブラウザ
let g:projecteuler_browser_command = "コマンド名 %URL% &"
みたいに設定して下さい
%URL%をを抜かすと正しく動作しません
デフォルトでは多分デフォルトのブラウザが起動します(ややこしい…)


g:projecteuler_audio_play_command
CAPTCHAの音声を再生するためのコマンド
let g:projecteuler_audio_play_command = "コマンド名 %AUDIO% &"
みたいに設定して下さい
%AUDIO%をを抜かすと正しく動作しません
デフォルトでは、WindowsがMediaPlayer,MaciTunes,その他ではpaplayがあればpaplayです。


g:projecteuler_hold_cookie
ProjectEulerのCookieを保存するかどうか。
0:保存しない(Vim終了時に破棄) 1:保存する
デフォルトでは保存します


g:projecteuler_see_next
問題を正解したあと次の問題を表示するかどうか。
0:表示しない 1:表示する
デフォルトでは尋ねます


g:projecteuler_open_forum
問題を正解したあとフォーラムをブラウザで開くかどうか。
0:開かない 1:開く
デフォルトでは開きません


g:projecteuler_problem_lang
問題を取得・閲覧する際の言語を設定します。
let g:projecteuler_problem_lang = "ja"
とすれば日本語の問題文を取得・閲覧します
(日本語の問題は最初に紹介した日本語訳のページから取得しています)
デフォルトでは英語です

その他の機能

・問題のリスト表示時に、問題の説明箇所でを押せばその問題を表示します。もし一番下のページ番号でを押せばそのページ番号に移動します。
・プロファイル表示時に、問題の箇所でを押せばその問題を表示します。
・問題表示時に、Problem 67のようにテキストがダウンロードできる場所ではその場所でを押せばテキストがg:projecteuler_dirにダウンロードされます。

動作の仕組みなど

音声の再生方法

ProjectEulerでは、解答の投稿にはCAPTCHA認証が必要です。ProjectEuler.vimではこれを、CAPTCHAの音声ファイルを取得して再生するという強引なやりかたで切り抜けます(あーでもこれ読むかぎりなんかいけそう)。デフォルトでは、WindowsではWindows MediaPlayer , MacではiTunesが起動しますが、これでは全然うれしくありません。Macでは、

#import <AppKit/AppKit.h>

int main(int argc, char *argv[])
{
	if (argc < 2) return 0;
	NSAutoreleasePool *pool = [ [NSAutoreleasePool alloc] init];
	NSSound *sound =  [ [ [NSSound alloc] initWithContentsOfFile:[NSString stringWithCString: argv[1] encoding:NSUTF8StringEncoding] byReference:YES] autorelease];
	if (sound)
	{
		[sound play];
		while([sound isPlaying]){}
	}
	[pool release];
	return 0;
}

というプログラムを作って、これを

$ gcc -Wall play.m -framework AppKit -o play

みたいにコンパイルして、.vimrcに

let g:projecteuler_audio_play_command = '~/play %AUDIO% &'

とするといいと思います(参考:コマンドラインで WAV/AIFF を再生 - 空想犬猫記)。
Windowsならば、ここからplay.exeをダウンロードして、_vimrcに

let g:projecteuler_audio_play_command = 'C:\play.exe %AUDIO%'

みたいにするといいと思います。linuxなんかではpaplayがいいでしょう。こうすれば他のアプリケーションを立ち上げずにすみます。

IDの特定方法

:ProjectEuler などのコマンドでID(問題番号)を省略した場合には、現在のファイル名から推測を行います。実際には現在のファイル名から数字だけ抜き出します。つまり、Problem1.plというファイル名ならばIDは1になりますが、Problem1(2).plみたいなファイル名だとIDは12になります。予期しないIDになってしまったら素直にIDを指定してやりなおしてください。

問題の取得について

問題文はわざわざ何度も取得しても意味がないので、g:projecteuler_dirに保存します。まれに問題文が変わることがあるみたいですが、そうした場合は一度問題を消してから再び取得して下さい。

ログイン処理について

ログインはCookieで管理します。一度ログインしたユーザーは記憶されていて、それ以降Cookieの有効期限を確認せずに通信します。そのため、Vimを起動中にCookieの有効期限が切れてしまうと解答などができなくなってしまいます。もしそうなってしまったら:ProjectEuler -r で強制的にログイン処理をおこなって下さい。ちなみにprojecteuler.netのCookieの有効期限はだいたい1ヶ月です。

Cookieの削除

Cookieの削除についての設定はスクリプト読み込み時に:autocommandで設定しているのでCookieを保存したくない場合はあらかじめvimrcに

let g:projecteuler_hold_cookie = 0

としてください。

解答について

ProjectEulerでは一度問題を間違えて解答すると30秒しなければ次に解答できません。

スクリプト文字コード

スクリプトUTF-8で書かれています。iconvがないとWindowsでは文字化けして使いものにならなくなっちゃうとおもいます。
(2010-2-25 追記):scriptencodingというコマンドを使えば大丈夫ということなのでそれに変更しました。

問題点

・すでに解答してある問題にも解答できます。そのまま成否が判定されます(まぁでもこれはこれでいいかな)。
Windowsではパスにスペースがあると上手く動作しないかもしれません。
・ログイン処理で「ログインに成功しました」となるのにプロファイルなどがうまく取得できなかったり問題に投稿できなかったりしたらg:projecteuler_dirが存在しないからだと思います。g:projecteuler_dirを作成してみて下さい。

vimrc

私の.vimrcは次のように設定しています。

let g:projecteuler_user = "mfumi"
let g:projecteuler_audio_play_command = g:projecteuler_dir . "play %AUDIO% &"
let g:projecteuler_problem_lang = "ja"
nnoremap	 <Space>p		<NOP>
nnoremap <Space>pp	:<C-u>ProjectEuler<CR>
nnoremap <Space>pl		:<C-u>projecteuler -l<CR>
nnoremap <Space>ps		:<C-u>ProjectEuler -s<CR>
nnoremap <Space>pc		:<C-u>ProjectEuler -c<CR>
nnoremap <Space>po	:<C-u>ProjectEuler -o<CR>
nnoremap <Space>pr		:<C-u>ProjectEuler -r<CR>
nnoremap <Space>pu	:<C-u>ProjectEuler -u<CR>

その他(感想など)

quickrun.vimと組合せれば完全にVimで完結してProjectEulerができると思います。
はじめは問題の取得しか考えていなくて、その後どんどん思いつきで機能を足していったのでコードがごちゃごちゃになってしまいました(言い訳)。特に問題文の整形処理などはいろいろと試行錯誤しながらやったのでひどいかもしれません。まぁでも自分の予想以上のものができたと思います。プラグインを作ったのは初めてだったので、いろいろなプラグインを参考にさせて頂きました。特にログイン処理はhatena.vimを、ブラウザの起動などはGist.vimを参考にしています。%とか&とかがpatternで展開されるのに気づかなかったり、'と"はいつでも同じだろうと思ったり、Windowsのパスの区切り「\」の扱いなど、結構はまりました。基本的にMacOSX SnowLeopard & MacVim-kaoriyaでしか動作確認していないのでおかしいところがまだまだあると思います。もし何かあれば、メールもしくはここにコメント頂けたら嬉しいです。

スクリーンショット




ただでさえ試験でやってなかったのに最近はこれ作ってたから全然進んでない…