読み終わったのは大分前だけど、これも中古で買って面白かった作品。
アニメのように、第○話!ってタイトルが流れて区切られてます。
主人公がリストラサラリーマンとか、妙に生々しい。
フルボイスだから、オートで垂れ流しておくのにちょうどよかったですよ。
それほど長い話でもないし、各ルートも混ぜやすいというか、どのルートに進んでも一通り全員と話すので、そのままアニメ化できそう。
今も高値で中古が売られていたので、人気があるならアニメ化とかもあるんじゃないかなあとか。
中古で手に入れてチマチマやっていたんですが、1ルートに30時間くらいかかるうえに、一度始めると途中で止められない中毒性が危険すぎ。
正史ルート
謙信xウルザで攻撃を封じて、魔軍に対してはリズナ無双。
東側を無視して毛利側へ一気に攻めていったけど、それでも難易度高かったです。
平均兵数が600, 700 くらいだったかな?
蘭ルート
蘭と性眼と名取の全体攻撃無双。
今度は西側を無視。風林火山の条件を満たさずに武田を倒して真田透琳のみ仲間にしたけど、それでも強い強い。
最後に余裕を持って独眼流家を制圧したけど、これまた仲間にする条件を知らなかったので中途半端に。しょんぼりしながらクリアしちゃいました。
謙信ルート
お町無双。
帝レースをを終わらせて、今度こそ独眼流家を条件を満たして制圧。
五十六ルート
一番やる気がなかったわりに、エンディングは一番よかったですよ。
ボーナスでお町無双を最初から使ったのでひどい強さ。
風林火山を抑えるまでどこも制圧せずに力を溜めに溜めていたので、最後の兵数がすごいことに。
お金が余るので兵数3000とか。敵兵数が比例して9000とかなったけど;
毛利も条件を満たして制圧完了。ほぼ全国制覇してしまうほどの強さに。
猿殺しルート
武田と毛利がボーナスで使えるようになったので、あとは得点稼ぎのやり込みへ。
まだやってないけど、ここまでものすごく時間かかったし、wiki が充実するほどみんなやりこむ気持ちは分かりました。これ危険。

C++ で外部プロセスを呼び出そうとしたらすごく大変だったから、python の commands.getoutput(“ls -l”) みたいに一行で書けて標準出力が返ってくれば幸せになれるのに・・・!という経緯です。
CreateProcess
今回は WIndows 用に調べてたんで MSDN。
CreateProcess 関数
泣きたくなるような引数の数に加え、型が外国語すぎて読めません;
それでも一応頑張って読んでみると、STARTUPINFO ってのを外から与えると、構造体の中を破壊してきて標準出力とかがこの中に書き込まれるみたいですよ。
STARTUPINFO
このへんで投げ出したけど、真面目に実装するとけっこう長くなるかんじ。ハンドルって概念が分からないんですよ。なにそれ。
popen/pclose
まだこっちのが分かるよねってのが C 標準関数の popen/pclose。
Manage of POPEN
Windows でも _popen/_pclose で実装されてるみたいで、とりあえずこっちで書いてみることに。
python commands
目指すインターフェースは以下なかんじ。とりあえず getoutput だけ。
16.16 commands — コマンド実行ユーティリティ
commands.hpp
インターフェースをまねるとこんなかんじですよね。
インスタンス生成とかせずに、シンプルに関数呼び出しで扱える形に。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | /* * File: commands.hpp * Author: kei * * Created on 2009/08/18 */ #include <string> #ifndef _COMMANDS_HPP #define _COMMANDS_HPP namespace commands { const std::string getoutput(const std::string& command); } #endif /* _COMMANDS_HPP */ |
commands.cpp
実装。
C 言語特有のエラーコードを返す関数を、全部例外投げるようにラップしてみたけど、finally がないからクローズ処理がまとめられなかったり、throws がないから再 throw になっちゃったり。
あと Java の IOException みたいな例外定義がデフォルトでなくて、そもそも catch しなくてもコンパイル通るとか。
それぞれの例外クラスを定義して、catch で分けるのが正しいんですが、とりあえず std::runtime_error 投げたんで、よい子はマネしないでね。
popen がファイルディスクリプタを返してくるんですが、この子からファイルストリームを生成するうまい方法がなくて(昔のコンパイラはコンストラクタに喰わせて fstream 作れたみたいだけど)、素直に C 言語な実装に。
あと必ず pclose で閉じること!って書いてあったから、boost::shared_ptr なんか使って解放しちゃ危なそうってことで boost も出番なし。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | /* * File: commands.cpp * Author: kei * * Created on 2009/08/18 */ #include <cstdio> #include <sstream> #include <stdexcept> #include "commands.hpp" /** * 指定したコマンドのプロセスへのファイルディスクリプタを返します。 * 使用後は close_process(const FILE* process) でクローズしてください。 * プロセスのオープンに失敗した場合は例外を投げます。 * @param command * @return プロセスへのファイルディスクリプタ * @throw std::runtime_error */ FILE* open_process(const std::string& command) { FILE* process = popen(command.c_str(), "r"); if (process == NULL) { throw std::runtime_error("open " + command + " failed."); } return process; } /** * 実行プロセスの出力を返します。 * @param process * @return プロセス実行出力 */ const std::string read_process(FILE* process) { std::stringstream output; char buffer[128]; // allocate memory while (fgets(buffer, sizeof (buffer), process)) { output << buffer; } return output.str(); } /** * 指定したプロセスをクローズします。 * プロセスのクローズに失敗した場合は例外を投げます。 * @throw std::runtime_error */ void close_process(FILE* process) { const int result = pclose(process); if (result == -1) { throw std::runtime_error("close_process faild."); } } /** * 指定したコマンドをシェル経由で実行し、出力を返します。 * プロセスのオープン/実行/クローズのいずれかに失敗した場合は例外を投げます。 * @param command コマンド * @return コマンド出力 * @throw std::runtime_error */ const std::string commands::getoutput(const std::string& command) { FILE* process = NULL; std::string output; try { process = open_process(command); output = read_process(process); } catch (std::runtime_error error) { // finally 処理の代わりに、例外時にもクローズ処理を書いてあります。 // open/read の例外時のため、close の例外確認は行いません。 if (process != NULL) { close_process(process); } throw error; } // 正常時の close 処理です。例外確認も行います。 if (process != NULL) { try { close_process(process); } catch (std::runtime_error error) { throw error; } } return output; } |
main.cpp
date コマンドを打ってみた例。
まあこんなとこでしょ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | /* * File: main.cpp * Author: kei * * Created on 2009/08/18 */ #include <cstdlib> #include <iostream> #include <stdexcept> #include "commands.hpp" /** * メインエントリです。 * 以下は date コマンドを実行するサンプルです。 * @param argc * @param argv */ int main(int argc, char** argv) { try { std::cout << commands::getoutput("date") << std::endl; } catch(std::runtime_error error) { std::cerr << error.what() << std::endl; } return (EXIT_SUCCESS); } |
/usr/lib/python2.6/commands.py
python の実装を真面目に読んでみる。
os.popen() を使ってるみたい。
"""Execute shell commands via os.popen() and return status, output.確かに。
def getstatusoutput(cmd): """Return (status, output) of executing cmd in a shell.""" import os pipe = os.popen('{ ' + cmd + '; } 2>&1', 'r') text = pipe.read() sts = pipe.close()
/usr/lib/python2.6/os.py
subprocess の Popen からパイプを生成してるもよう。
import subprocess PIPE = subprocess.PIPE p = subprocess.Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE, stdout=PIPE, close_fds=True) return p.stdin, p.stdout
/usr/lib/python2.6/subprocess.py
あー、Windows 版はやっぱり CreateProcess を使って実装してるのね。
On UNIX, with shell=False (default): In this case, the Popen class
uses os.execvp() to execute the child program. args should normally
be a sequence. A string will be treated as a sequence with the string
as the only item (the program to execute).On UNIX, with shell=True: If args is a string, it specifies the
command string to execute through the shell. If args is a sequence,
the first item specifies the command string, and any additional items
will be treated as additional shell arguments.On Windows: the Popen class uses CreateProcess() to execute the child
program, which operates on strings. If args is a sequence, it will be
converted to a string using the list2cmdline method. Please note that
not all MS Windows applications interpret the command line the same
way: The list2cmdline is designed for applications using the same
rules as the MS C runtime.
startupinfo の文字が。やっぱり頑張らないとかー。
# Start the process try: hp, ht, pid, tid = CreateProcess(executable, args, # no special security None, None, int(not close_fds), creationflags, env, cwd, startupinfo)
最後に
boost::process みたいなのないですか。いやぐぐるとひっかかるんですけど、これ boost パッケージに含まれてます?
Pstreams ってのもあったけど使ってる人いるのかしら?
特になければ、今回作ったものをもう少しちゃんと実装して使い回していく方向かなあ。ぐぐっても出てこないあたり需要ないのか知らないけど、Windows で ssh ライブラリがないからこれで叩こうと思ったわけで。
PuTTY のソースも見たし、python paramiko も試したけど、大人の事情がもにょもにょだったので。
C++ 素人につきリファクタ職人の降臨が望まれます。
少し前に上野、浅草へ。
Apribase » 上野・浅草フォトアドベンチャー
つい最近は駒込をのぞいてきました。
Apribase » 山の手線沿線物件も意外といける
先週末は田端から日暮里へ歩いてみました。
リアルタイムに twitter に流してたから改めて書くのも微妙だし、写真ベースでうまいライフログのとりかた考えないとなー。
















