2009年12月29日

コミケ77販売品のプレビュー版アップしました(生徒会の一存の一般向け本)

完成しました!
やっほい!

よろこびの叫びをあげる海月歩空です。こんばんは。

もう、今日からコミケですね。
わくわくしますね!

入稿した同人誌がある初めてのコミケ……なんて幸せなんでしょう!
いままで、ぎりぎりまで本を書いていて、ひ―ひ―いいながらコピー誌を作っていたあのころ。
ああ、なにもかも懐かしい……。

とまあ、そんな、個人的な感想は置いておいて。
31日の同人誌の見本版をこちらにアップしました!

なぜか、PDF形式で!

な、なぜって……?

い、いや、まぁ、あれです。

同人誌にするために、ストーリーエディタ(愛用のフリーソフト)から、
デザインのためにwordにして、
さらにそこで、いろいろできるPDFにして、
そのあと、印刷業者に送るためフォトショップで画像に変換する……
という、気の長い手順を経験したおかげで、PDF形式のファイルを作る方法を把握したためです。

超便利!

なので、同人誌のプレビュー版も、同じように作りました。
決して、ブログにそのまま書けばいいのに、とか、面倒くさかったんでしょう、とか、
思わないように!

……う、うん、ごめん。

それはともかく、プレビュー版はこちらです

内容に、興味わいた皆様方、立ち読みでもいいので、見に来てくださいね!

あ、そうそう、本の中身じゃなく、ちゃんとした情報も必要ですよね。
タイトル『生徒会の年末 碧陽学園生徒会議事録超外伝』です。
ページ数は、16ページ(中身は14ページで、原稿用紙で44枚ほど。短編1話分くらい)で、
価格は未定です(すみません!)
少部数(たしか30部)なので、あり得ませんが、もしも、もーしーも! 売り切れていたらごめんなさい。

ではでは、コミケに来る方はまた31日にお会いしましょう!
posted by 海月歩空 at 00:35| Comment(0) | TrackBack(0) | 日記

2009年12月06日

遅くなりましたがコミケ76ありがとう&77出ます!

超お久しぶりです! というかごめんなさい!

超放置してました……。

というわけでいまさらですが、ありがとうございました!

へんなものとか、いまさらポリフォニカとかでしたが、わざわざ来ていただいて感動しました!


それはさておき、こちらもいまさらですがコミケ77でますの報告です。
場所は、3日目の東1・F−33bです。
応募した時は、えっちぃのとコメディとの2つを出そうと思っていたのですが、現在はパロディでコメディだけになりそうです……。

毎回計画の半分以下という、ダメダメが発揮。
残念人生です。

新刊の本は、さっきも言った通りコメディで、今回はラジオ的に何かしながら流しみするには最高の作品(山場も何もないぐだぐだアニメ)である、生徒会の一存シリーズの小説版パロディ同人誌ということになります。

エロとかないです!

ぐだぐだのコメディがあります!

……何の自信があるのか……。

というわけで、次回更新でちょろっと中身をこんな感じという風に書かせていただきます。

お楽しみに!

……お楽しみできればいいなー。
posted by 海月歩空 at 22:44| Comment(0) | TrackBack(0) | 日記

2009年08月07日

現在進行形

かなり泣きそう!
お久しぶりです海月歩空です。

というわけで、コミケまで現在あと2週間どころかあと1週間を切った現在、皆様いかがお過ごしでしょうか。

まず始めにあやまっておきます! ごめんなさい!

今回の計画として上げていた三つの柱、ぜんぜん達成しなさそうです!
ううー、本気で申し訳ない気持ちで満杯です。
オフセットの一冊でも出しちゃおうと思っていたのに。
自分に残念だ!

というわけで、現在確定の予定を改めて。
1.「ポリフォニカのエロ本(コピー誌)」
   タイトル未定。
   ペルセルテメインで、フォロンとあわあわエッチです。
   まだ終わってないけれど!

2.「海月歩空in海月小屋HPオフライン(CDorFD)」
   タイトル”ほからいん(仮)”
   よろずコネタホームページとして、しふぉんの時にかいていた学園モノやら、ダイススクリプトやら。
   ダイススクリプトは現在の候補として、ホームページにアップしている「通常ダイス」と、「ダブルクロス」にくわえ、「ソードワールド」、「六門世界」、「六門世界2」、「スワップダイス(メガテン?)」、「逆スワップダイス(メガテン?)」など。
   学園モノは、放送部ラジオドラマ風文章「七夕−ひこぼし編」と、いつものお話「風邪ひき編」を追加して全部まとめ。
   やっぱりまだ終わってないけれど!

そして、魔法少女は出せません!
ホントに申し訳ないです……時間内のにくわえ、プレ版から遡る罠にやられました。

頑張ろう、めっちゃ頑張ろう……。

それでは続報をお待ちください!
posted by 海月歩空 at 01:00| Comment(0) | TrackBack(0) | 日記

2009年06月08日

コミケ76

自宅に帰ると、ポストに封筒。

封筒についている半透明の窓から、見えるのは配置場所の文字。

あわててあけると、サークルチケットやらなにやらが……。

……。

…………。

………………。

うひぃ、受かってしまったー!?(え、しまった?)

というわけで、海月小屋サークル参加第2回は、コミックマーケット76に決定しました。
いえーい!

い……いえーい……。

ど、どうしよう。

まだ手をつけてないものだらけですよ!

仕事がピンチで怠けていた(ちょっと矛盾)のツケが回ってきました!

頑張ろう、何とか頑張ろう!


さて、そんな自分を励ました海月歩空さんから、今回のコミケ76参加に関する予定を発表です。

1.ポリフォニカで何か書く予定(しふぉんリベンジ)
2.魔法少女の続きというかちゃんと本編書く予定(海月小屋リベンジ)
3.文章のサークルなのにフロッピーとかCDとかでここで公開しているダイススクリプトのいろいろ機能版配布予定(人生リベンジ)

予定だらけだ!?
そして、無駄にリベンジ!

ちなみに、3のダイススクリプトいろいろ機能版は、同人とかはまったく関係ないけれど個人的趣味です。
本のスケジュールが終わった後に、がりがりと説明書を作る予定です。
というか、基本はできているので(ブログ用に丁寧に書き直しているだけ)、これが一番楽。
これぞ趣味の世界。

さて、これらがどれくらいできあがるのか、神のみぞ知る!(あなたが頑張りなさい)

それでは、これからはちょくちょく手が止まったら報告しに来ます! ではでは!
(嬉しいような嬉しくないような)
posted by 海月歩空 at 18:44| Comment(0) | TrackBack(0) | 日記

2009年04月29日

久しぶりに文章

クトゥルフの元ネタはよんだことない海月歩空です。こんばんは。

しふぉんではよく文章を書いていた……というかあんなに元気にかけていたのは奇跡的、という感じなのですが、不意に面白いネタを見かけたので、私ぱろってみました。

――――――――――――――――――――――――

 私が空腹に耐えかね暗い森の中で倒れ込んでいると
中空から唐突に出現した深紅に染まる服を着た生命体。
 自分の顔をもぎ取るという生物として冒涜的な行為
を行いながら私を嘲り笑う。
「ぼくのかおをおたべ」
 私に差し出したのは彼……と呼んで良いのだろうか、
その身体の一部分。それを食べてしまえば、私は彼の
眷属として生きることとなってしまうだろう。
 なんてことだ。空腹の中で死んでしまうか、それを
受け入れるかしかないなんて。しかし、食べてはいけ
ない。食べては……。
「ぼくのかおをおたべ」
 迫り来るその生命体は顔の形を歪めることなく、更
に頭を毟り取る。深淵をのぞき込んでいるようなその
瞳をのぞき込んでいると空腹で死ぬ選択肢はあり得な
い思いにさせられてしまう……。ああ……。だめだ…
…。もう……たべ……。


                 かばおの日記


――――――――――――――――――――――――

というわけで、クトゥルフ風アンパンマンでした。

何となく嫌な感じが出たかな? とか思ったりします。
文章書くの楽しい!
posted by 海月歩空 at 00:32| Comment(0) | TrackBack(0) | 文章

2009年04月16日

多重人格分析

日記の書くネタがなくなったときは、占い系だよね! 海月歩空です。

テレビ見ていたら、面白い占いをやっていたので、やってみました!
多重人格分析
海月歩空さんが100人の村だったら的な、そんな感じの占いです。
つまりは、私の中にいる天使さんと悪魔くんが、
悪魔「あのお金、ねこばばしてもばれねえよ」
天使「いけません。同じリスクならもうちょっと高いものを狙うべきです」
というように言い合いを……あれ?
と、ともかく、そんな私の中にいる人たちを見てみました。

海月歩空さん。あなたの中の他人はこんな人達です。

海月歩空さんの事の中に居る55人はどいう訳かハードボイルド風味な人達です。
海月歩空さんの事の中に居る16人は今日こそアレを言わなければ!な人達です。
海月歩空さんの事の中に居る11人は善人ぶりは正直疲れね?と思う人達です。
海月歩空さんの事の中に居る7人は健康オタでもいいじゃんよと思う人達です。
海月歩空さんの事の中に居る6人は自分結構イケてる!と思いたい人達です。
海月歩空さんの事の中に居る3人はすぐ卑屈になって考えすぎる人達です。
海月歩空さんの事の中に居る1人はもっと社会に貢献したい人達です。
海月歩空さんの事の中に居る1人はもっと尽くたい気持ちで一杯な人達です。


海月歩空さんのいい人はマイノリティすぎます……。
私っぽくない大多数な人たちは、ハードボイルドなんで前に出てこないから、やっぱり私っぽくない感じ。
中盤グループが私が思う私かな! ちょっと、嫌だけどしょうがない!

そんな、究極の引き籠もりになるのが夢な海月歩空さんでした。

……うん、占い、なかなか楽しい!
posted by 海月歩空 at 01:59| Comment(0) | TrackBack(0) | 日記

2009年04月01日

スクリプトのこと・その3

肩こりがひどいので、アンメルツが手放せられない、海月歩空です。こんばんは。

いつもいっているところでevalはいやだなぁ、という話を読んで、前回は、eval以外の方法でやってみよう、ということを考えてみました。
しかし結果は、直接ファイルを読み込むのと同じ意味合いになってしまいましたね、ということでした。
つまりは、再評価をしている時点であんまり変わらない、という感じでしょうか。

で。
ここ最近見てみると、その記事のコメントで、プリプロセッサ談義が花を咲かせている模様なので、私はlimechat2&javascriptで作るならと考えてみました。
考えた結果、コメントにするには思ったより長くなったのと、最近ダイスのネタをまとめられない(次回は六門か何かにする予定)ので、せっかくだからと記事にさせてもらいました。
かってしてます、ごめんなさい!

さてさて、プリプロセッサはざっくり言えば、ファイルを読み込んだり文字列を置き換えたり、条件によってソースを消したり出したりして、プログラムコンパイル用にいろいろやってくれるようなものですね。
つまり、通常のファイルに、”ここにこんなソース書いて欲しいなー”と言う印を付けておいて、置き換えるようにしておけば、インクルード風味のものができるわけです。
たぶん実際にも、インクルードって言うものはそんなものだと思わなくもないです(あやふやな表現ですね)
というわけで、プリプロセッサ風味に、実行すると置き換えるjavascriptをつくるのでしたら、単純な方法としてrepleceを使う方法があります。
例として、”/*test test*/”というコメントをソースに置き換えてくれるスクリプトを作成しましょう。


base.txt(ソース読み込み用元ファイル)

/*test インクルードコメントtext関数取り込み test*/
try
{
log(test());
}
catch(e)
{
log("プリプロセッサ風味の実行失敗");
}


test.txt(ソース置き換え用元ファイル)

function test()
{
return("プリプロセッサ風味の実行成功!");
}


preprocessor.js
//ソース読み込み用元ファイル
var fileObj = openFile("base.txt");
var baseStr = fileObj.readAll();
fileObj.close();

//ソース置き換え用元ファイル
var fileObj2 = openFile("test.txt");
var testStr = fileObj2.readAll();
fileObj2.close();

//置き換え(肯定先読み置換) "/*test〜test*/"を置き換え。
var overStr = baseStr.replace(/\/\*test.*(?=test\*\/)test\*\//g, testStr);
//書き込み
fileObj = openFile("output.js", false);
fileObj.truncate();
fileObj.write(overStr);
fileObj.close();


これで、preprocessor.jsを実行すると、output.jsに以下の感じで出力されます。

output.js
function test()
{
return("プリプロセッサ風味の実行成功!");
}

try
{
log(test());
}
catch(e)
{
log("プリプロセッサ風味の実行失敗");
}


書き換える度に、コンパイル的なことをしないといけないので、インタプリタの強みが無くなってしまうのけれど、別方向からのインクルードというならこういう形でしょうね。
ちなみに、なぜ肯定先読みしているかといわれれば、ただの好みですが、なにが入る予定、というコメントをかけるのがいいのでこういう形にしました。
それと、なんでコメント? 実行失敗したら結局変わらないのに、とかは、気持ちの問題というか、エディタでコメントの文字色が変わるような設定にしているからというか、そんな感じです(アバウトすぎです)
置き換えだと、ソース以外に、定数も定数風味に文字列を書いておいて、置き換えで数字や文字列にすることで使用できますね。
以上、プレコンパイル的javascript作成方法のひとつでした。


さてちなみに。
わざわざインクルード風味で行わなくても、くっつければいいじゃない、linuxならcatで、という風に言いましたが、windowsなら、typeコマンドでできることをご報告しておきます。
コマンドプロンプトで、”type a.txt b.txt >c.js”というようにすれば、楽ちん。
コピペコマンド風味ですけれど、これもまたひとつの方法になりますね。
posted by 海月歩空 at 22:49| Comment(0) | TrackBack(0) | プログラム

2009年03月27日

スクリプトのこと・その2

スクリプトのことでちょこちょことお話モードの海月歩空です。こんばんは。

時々行くところで、私の記事が取り上げられています! わほー。
記事の内容は、evalを使用して、インクルードする方法に心理抵抗が大きいとのこと。
気持ちはわからなくもないです。自分でごりごり書いているんではなくて、人のものだったら一応確認せずにはいられないです。
個人的には、インタプリタといえばeval、言語操作といえば正規表現というくらい、大好きな物なのですが、実際に悪いことしようと思えば、いくらでもできるのもevalなんですよね。
ファイル名:test.js
var fileObj = openFile("test2.js");
var str = fileObj.readAll();
eval(str);
fileObj.close();

ファイル名:test2.js
log("海月歩空大好きー");

こうすると、スクリプトコンソールに、自画自賛コメントが出てきます。ちょっぴり幸せ。
次は、すごく単純に悪いことする方法の簡易版。実際にはまねしちゃダメだぞ!
ファイル名:test2.js
fileObj = new Object();
fileObj.close = function()
{
log("海月歩空なんて大嫌いー");
};

例えば、こうすると、fileObjを上書きして、クローズしようとする度に非難メッセージが出てくる&ファイルクローズができない、なんてことが起こります。
これは危険。超危険。

というわけで、そんなあなたにはnew Function。
ファンクションオブジェクトを生成することができるものです。
使い方はいたって簡単。
基本的には、文字列を渡して実行すると、ファンクションオブジェクトができます。
使用例は以下の通り。
ファイル名:test.js
var testFunc = new Function("log('海月歩空大好きー');");
testFunc();

ということは、ファイルを読み込んで、文字列を渡してあげれば、関数になりそうです。
ファイル名:test.js
var fileObj = openFile("test2.js");
var str = fileObj.readAll();
testFunc = new Function(str);
testFunc();
fileObj.close();

ファイル名:test2.js
log("海月歩空大好きー");

おお、なんて簡単!
evalにもまけないぜー!続きを読む
posted by 海月歩空 at 02:33| Comment(0) | TrackBack(0) | プログラム

2009年03月25日

LimeChat2のjavaScriptでダイス作成(7)

ダブルクロスとお寿司大好き、海月歩空です。こんばんは。

ダブルクロスは、無駄に許容量が広いところが大好きです。
最近のリプレイの果てしなさがすごい……。
というわけで、対抗して、”寿司王子”をダブルクロスキャラクターとして作成しました。

米寿・司、ハヌマーン/サラマンダーの格闘家で、自然流琉球空手の伝承者として設定。

経験表−生まれ・名家の生まれ:祖父はスシ王。父はスシ伯爵。スシの名家に生まれた彼は、人呼んでスシ王子。
経験表−幼少・死別:祖父と父を、巨大カジキマグロ"ヌシ"によって殺されてしまう。
覚醒表・犠牲:祖父と父を殺され、魚に睨まれたことから、その魚と戦うための力に目覚めた。
衝動表・破壊:魚と戦う力――それは、無差別に破壊してまわるだけの、暴走であった。
神秘・達人の指導:親を亡くした彼は、師匠である武留守リリーによって育てられた。
経験表−死別:師匠は遺言を残し、彼の前から消え去った。
「自然流空手の神髄は、スシにある。スシを握れ」

ロイス
武留守リリー タイタス:自然流琉球空手の師匠であり、彼の育ての親。
一柳サヨリ 慕情○/疎外感:子供の頃に離ればなれになった、実の母。
Dロイス・伝承者(白兵):自然流琉球空手の拳の握りは、スシの握り。
自然流をマスターするため、そして母に会うために、彼はスシの世界に戻ることとなった。

さすがダブルクロス。ルールに対して違和感のない設定です。
”電光石火稲妻握り返し”をコンボとして作ることができたりと、懐の深さにわくわく。

さてさて、ダブルクロスダイス、完成しましたね。
使い方とか説明していないので、誰か使うんだろうか、的な考えも沸くんですが、そんなこと自己満足の前では無視です!
実際は、チャットでセッションする人がお友達にいるので、その人にあげたり自分で使ったりしていますけど。
では、前回の要約から。

・eval関数あいらぶゆー。
ajaxの一翼を担う関数。例えばlimechat2なら、
メッセージの入力で関数呼び出しまでできます。

・ソースは小分けに見通しよく。
どこを直せばいいのか、
何となくわかるようにしておくとなおよし。

ざっくりですね!
evalはいとおしいので、みんなも使ってみてください。
正規表現とevalが大好きな海月歩空よりのお願い!

そんな、変なお願いはいいのよ!
前回適当に進めすぎた分のフォローをするそうじゃない!(そ、そうなんですか)
さっさと、始めなさいよ!

・ダイス作成(7) 機能拡張・その2−ダブルクロスダイス作成(2)(ぱらららーん)

あんまり勢いで書いていてもあれなので、今回は、海月歩空のスクリプトの書き方というか考え方を、前回までのネタを使いながらやっていきたいと思います。
ちなみに、私が短めな文章書くときも、方向は違いますが似たような方法で書きます。
つまり、私にとってスクリプトの書き方=文章の書き方、ということに。
とてもとてもベーシックな方法なので、たぶん、他の人もやっていると思います。

というわけで、海月歩空のスクリプト作成方法、紹介!

その1。入出力をイメージする。
ダイス作成(1)とダイス作成(2)にかぶりますが、はじめに考えることは、入出力を決めるところからですね。
こういうデータがあって、こういう結果が欲しい、という考え方です。
使う側にとって、処理なんてものは、信頼できる処理が入っていれば、後はお任せです。お任せ。
なので、実は入出力をどれだけうまく人の思考にあわせられるかが、使われるシステムになるかの重要ポイント……というわけでもないところがプログラムの悲しいところ。
今回で言うと、前回仕様で書いていた入力と出力の処理を行うにはどうしよう、というところをまずイメージします。
この時点では、イメージだけで、ダイス作成(2)みたいなものを作っておきます。
テストできるように、準備をするという感じですね。

その2。最低限の処理項目を考える。
最低限、必要な処理をリストアップします。
実は、これが超重要!
というか、ダイス作成(6)で書いた、機能の仕様(大まかに)の部分が必要な処理のリストアップがそれにあたります。
機能の仕様(大まかに)
1.ダイスの面数は10面ダイス固定。
2.ダイスの個数は入力式。
3.クリティカルは入力式。
4.技能値等の達成値ボーナスは入力式。
5.ダイスの個数分、一度にダイスを振る。
6.ダイスの振った結果、一番高いダイス目を成功度として扱う。
7.ダイスを振った結果クリティカル値以下のダイスがある限り
クリティカルした個数分振り足しをする(クリティカル処理)
8.クリティカル処理が行われたときの成功度計算方法は、
ダイス目に関係なくクリティカル=10として、振り足しを行う。
9.ダイスの個数は0個を下回ることがある。
下回ったときクリティカルは絶対せず、ダイスは1個となる。
10.1回目に全てのダイスが1を出したとき、ファンブルとなる。
11.制限として、無限ループに陥る可能性があるため
、無限ループ用の制御をする。

これです。
実際にどれが入力で必要か、どれが結果として必要かーみたいなのを考えるのも、ここですね。

その3。コメントをおいていく。
ここから、プログラムを書いていくという作業に入ります。
上から、必要な処理がリストアップができたので、それを流れになおします。
本当は、ここでなんとか図を書いてみたり、いろいろするのが普通なんでしょうが、一人で書く場合とかは楽するためにそんな感じです。
いわゆる下書き! 感覚で書きます。
ちょっと、本来のソースとコメントが違う部分もありますけれど、そこはわかりやすくしたためで、本当は単語でざらっと書いていることが多いです。
関数のひな形
//ダブルクロスダイスの関数。入出力は外に任す。引数はダイスの要素の文字列

//返却に必要な項目。
//ここで出力する予定はないので、objectで複数項目返す。
//必要そうな項目
//達成値
//成功度
//表示項目
function ()
{
//判定用の値取得。○x△+□で分割。
//○=ダイスの個数
//△=クリティカル値
//□=達成値ボーナス

//分割した物を計算

//達成値ボーナスはなくてもいいので、無いときの処理。

//ダイスの個数が0以下のとき、
//クリティカル値を11にして、ダイスの個数は1個にする。

//計算結果、無限ループや
//すごい大きな処理になりそうなら終了
//どうやってエラーを返す?
//マイナス達成値? 表示だけ返す?

//ダイスロール。10面ダイスと、ダイスの個数でロール
//ロール結果を表示項目に追加

//1回目に全てのダイスが1を出したとき、ファンブル
//ファンブルを返却

//達成値判定
//ダイスロールした結果一番高い数値を成功度に

//クリティカル値以上の値をカウント
//クリティカルがでていたら、
//成功度はダイスの数値ではなく10に。

//クリティカルしている限り以下を繰り返し

//ダイスロール。10面ダイスと、
//クリティカルをカウントした結果のダイスの個数でロール。
//ロール結果を表示項目に追加

//達成値判定
//ダイスロールした結果一番高い数値を成功度に加算

//クリティカル値以上の値をカウント
//クリティカルがでていたら、
//成功度はダイスの数値ではなく10に。

//以上を繰り返し

//達成値計算。成功度+ボーナス
}

大体コメントはこんな感じでざっくりと書きます。
クエッションなんかかいていたり、ソース上ではdo〜while文にして一回で書いている所を2回で書いていたりしますが、これは実際になにをどうしようと考えながら書いていたためです。
今回は、元々他のダイスでイメージができていたのでそんなに違いはないですが、実際に関係ないコメントやら、入れ替えたり処理が消えたりすることもままあります。
プログラムを書くとき、ソースを書いてからコメントを書く人がいますが、コメントを書いてからプログラムを穴埋めしていくのが簡単かつ間違えづらいのです。
繰り返しますが、コメントは下書き!

その4。プログラムを書く。
後は、書いてください。
重複したりしたら、省略できないか考えたりするのはここです。
エラーの返却方法が決まっていなかったですが(複数の関数を使って作る場合は、エラーと結果の返し方は決めておいた方が無難)、オブジェクトを返すしそれならエラーフラグの方が楽だからとフラグ式にしました。
受け側がどう処理するかも考えていくと、大体、プログラムの大筋は人によってそこまでずれないです。
小技やらテクニック、後は知識、書き方によって、細かい部分は変わってきますけど。

こんな感じで私はプログラムを書いています。
普通にプログラムを書くときは、入力、返却、コメント、この三つを決めておくと、あとで細かい修正をするとき他に影響が少なくなるので、皆様も試してみてくださいね!
posted by 海月歩空 at 03:38| Comment(0) | TrackBack(0) | プログラム

2009年03月23日

LimeChat2のjavaScriptでダイス作成(6)

アメリカンヒーローではバットマンが大好き、海月歩空です。こんばんは。

スパイダーマはもちろんいろんな意味で好きですが、原作の方はちょっと苦手。
なんていうか、アメリカンな人がミュータントをテーマにするとごちゃっとしますよね。
ミュータントタートルズも何となく複雑だったような思い出が。

それはともかく、前回は、ダイスの機能拡張として、四則演算やらなにやらを使えるようにできました!
これで、ダイスを使用するある程度の機能がそろったわけですね。
では、前回の要約から。

・無名関数はちょっとしたときに便利。
配列ソートの並び替えあたりが一番わかりやすい例。
・try-catch文はエラー対策に。
本当はそういう使い方あまりお勧めじゃないけれど、
キャッチからのリターンで普通に処理ができるようにも。

ざっくりですね!
javascriptを書く人なら覚えておいても損はない二つのものです。
無名関数なんかはもう流行と書いてながれと読むくらいベターな技ですよ!

そんなよくある説明はいいのよ!
今回は、なんかゲーム用のダイスを作るらしいじゃないの!(え、そうなんですか?)
さあ、そのゲーム用ダイスの説明を始めなさい!

・ダイス作成(6) 機能拡張・その2−ダブルクロスダイス作成(ぱらららーん)

実は、ここ最近、ちょこちょことおじゃましているブログがありまして、そちらでダブルクロスのダイスをつくっていらっしゃいまして。
せっかくちょっかい出しているのなら、ダブルクロスのダイスを、私ならこう作ってますよーとアピールしてみようと思ったわけです。
ブログを書き始めているのはあちらの方がむちゃくちゃ早いんですが。
後出しな私。(パクリ! パクリ!)
そ、そんな、い、一応、chocoaからライムチャット2に今もまだ移行中ですが、ここに書いているのは移行時点で作ったものをブログ用に丁寧に書き直したものなので、スクリプト的にはパクリではないと!
言いたいわけです!(きわどくあらがってます)

……発表が早い者勝ちなので、ぱくりと言われればその通り!(あ、認めました)

それはともかく、私もオンラインでダブルクロスをやる身としては、ダブルクロスのダイスも作ってみよう、となるわけです。
というわけで、”ダブルクロスダイスの機能追加”を要望です。

さてさて、ダブルクロスのダイスといえば、どういう機能が必要でしょうか。
ざっと上げていきましょう。
機能の仕様(大まかに)
1.ダイスの面数は10面ダイス固定。
2.ダイスの個数は入力式。
3.クリティカルは入力式。
4.技能値等の達成値ボーナスは入力式。
5.ダイスの個数分、一度にダイスを振る。
6.ダイスの振った結果、一番高いダイス目を成功度として扱う。
7.ダイスを振った結果クリティカル値以下のダイスがある限り
クリティカルした個数分振り足しをする(クリティカル処理)
8.クリティカル処理が行われたときの成功度計算方法は、
ダイス目に関係なくクリティカル=10として、振り足しを行う。
9.ダイスの個数は0個を下回ることがある。
下回ったときクリティカルは絶対せず、ダイスは1個となる。
10.1回目に全てのダイスが1を出したとき、ファンブルとなる。
11.制限として、無限ループに陥る可能性があるため、
無限ループ用の制御をする。


はい、こんな感じです。
本当は、もうちょっと丁寧に説明しろ、っていう感じなんでしょうが、めんどう……もとい、ルールブックを買ってください! という感じで(本気で投げっぱなしです)
というか、私はプログラムを作成するときは感覚派なので説明が苦手だと言うことがわかってきたかも(大問題です)

さてさてさて、それを入出力の形にすると以下のように。
機能の仕様
1.メッセージにデータ入力
・入力の形式は、○x△+□で、
○=【ダイスの個数(実数かかっこを含む四則演算の結果)】、
△=【クリティカル値(実数かかっこを含む四則演算の結果)】、
□=【達成値(実数かかっこを四則演算を含む)】とする。
□はなくてもよい。
例:1*3+2+5x(10-3)+5+1
2.出力形式は× : ○x△+□=■ 成功度:▲ 達成値:●で、
■=【ダイスを振った結果(振り足し処理ごとに分ける)】、
▲=【成功度】、●=【達成値】とする。
例:× : 10x10+4=[.3.1.7.6.5.5.7.10.6.10.][.6.9.] 成功度:19 達成値:23

そして、内部的な仕様は、大まかな部分から抽出してください(本気でおおざっぱすぎます)

ではでは、これからイメージを高めていきましょう。
このダイス、つまるところ、クリティカル処理とファンブル処理とをうまく行えればいいというわけですよね。
それと、無限にループする可能性があるので、それの制御をする必要があります。

ファイル名:dice.js
//文字列入力処理
function event::onChannelText(prefix, channel, text)
{
//textの中に○d△があるとき、ダイス要素部分を取り出す
if (text.match(/^([0-9+*/()-]*?[1-9]\d*d[1-9]\d*[0-9+*/()-]*?)([  ].*)?$/i))
{

//通常ダイス関数呼び出し
var dice = normalDice(RegExp.$1);

//文字列出力処理
send(channel, prefix.nick + " : " + dice.words
+ " = " + dice.disp + " = " + dice.sum);
}

//ダイス要素っぽいものがあれば取り出し
if (text.match(/^([0-9()x/+*-]+)([  ].*)?$/i))
{

//通常ダイス関数呼び出し
if (dice = doubleCrossDice(RegExp.$1))
{
if (dice.errFlg)
{
//メッセージ
send(channel, prefix.nick + " : " + dice.words + "= " + dice.disp.join(""));
}
else
{
if (dice.fumbleFlg)
{
//メッセージ
send(channel, prefix.nick + " : " + dice.words
+ "= " + dice.disp + "= FUMBLE!!");
}
else
{
//メッセージ
send(channel, prefix.nick + " : " + dice.words
+ "=" + dice.disp.join("") + " 成功度:"
+ dice.succVal + " 達成値:" + dice.achiVal);
}
}
}
}
}

/******************************************************
前回分中略
******************************************************/

//ダイス個数上限(ダブルクロスダイス関数制御用グローバル変数)
var defDXDiceMaxLim = 40;

//クリティカル値下限(ダブルクロスダイス関数制御用グローバル変数)
var defDXClitMinLim = 5;

/******************************************************
ダブルクロスダイス関数

基本説明
○x△の要素を含む文字列を受け取り、○x△+□の形を抽出。
○個分10面ダイスを振り、△以下の結果をカウント、
カウントした個数分10面ダイスをふり直す行為を繰り返す。
ふり直した回数×10と、最後に振った10面ダイスの最大値を
成功度。成功度に□を足した結果を計算したものを達成値。
ダイスの振っている経過をdispに配列。
始めに振ったダイスが全て1であったときはファンブルフラグはtrue。
ダイスの個数かクリティカル値が制限をこえていたときはerrFlgはtrue。
これらの要素を含むオブジェクトを返却する。

in
diceWords:ダイス要素を含む文字列

out
ダイス結果object
[
disp:ダイス結果配列(Array)
fumbleFlg:ファンブルフラグ
errFlg:上限/下限エラーフラグ
achiVal:達成値
succVal:成功度
]
*******************************************************/
function doubleCrossDice(diceWords)
{
try
{
//返却用ダイスobject
var dice = new Object();
//ファンブルフラグ
dice.fumbleFlg = true;
//達成値
dice.achiVal = 0;
//成功度
dice.succVal = 0;
//表示項目
dice.disp = new Array();
//上限・下限エラーフラグ
dice.errFlg = false;

//子文字化
dice.words = diceWords.replace(/x/ig, "x");

//判定用の値取得。○x△+□で分割。
if (dice.words.
match(/([0-9()+*/-]+\)?)x(\d+|\([^)]+?\)|\([^(]*?\([^)]*?\)[^)]*?\))(.*)/i))
{
//数値計算
var diceCount = Math.floor(parseFloat(eval(RegExp.$1)));
var diceCritical = Math.floor(parseFloat(eval(RegExp.$2)));
var diceBonus = Math.floor(parseFloat(eval(RegExp.$3)));

//達成値上昇無し
if (!diceBonus)
{
diceBonus = 0;
}

//ダイス個数がマイナス時の処理
if (diceCount < 1)
{
diceCritical = 11;
diceCount = 1;
}

//上限値チェック
if (diceCount > defDXDiceMaxLim
|| diceCritical < defDXClitMinLim)
{
//エラー
dice.errFlg = true;
//メッセージ
dice.disp.push("ダイス個数かクリティカル値が上限を超えています。");
dice.disp.push("個数=" + diceCount+ "・個数上限="
+ defDXDiceMaxLim + "/クリティカル値="
+ diceCritical + "・クリティカル下限=" + defDXClitMinLim);

//エラーで終了
return(dice);
}

//判定
do
{
var xVal = 0;
var critFlg = false;
//ダイスロール
var diceData = diceRoll(diceCount, 10);

//ファンブルチェック
if (dice.fumbleFlg && diceData.sum != diceCount)
{
dice.fumbleFlg = false;
}

//ダイスの個数をリセット
diceCount = 0;

//ダイスループ
for (var i = 0; i < diceData.array.length && !dice.FumbleFlg; i++)
{
//達成値判定
if (diceData.array[i] > xVal)
{
xVal = diceData.array[i];
}

//クリティカル判定
if (diceCritical <= diceData.array[i])
{
xVal = 10;
critFlg = true;
++diceCount;
}
}

dice.succVal += xVal;
dice.disp.push("[." + diceData.array.join(".") + ".]");
}
while(critFlg) //クリティカルしていたら繰り返し

//達成度計算
dice.achiVal = dice.succVal + diceBonus;
}
return(dice);
}
catch(e)
{
return(null);
}
}

ざっくりと、作りましたね。
正規表現、いつもはこだわるんですが、今回はあんまりこだわらずに作っています。
ひとつは計算できないときはエラーに飛ぶから、というtry文にお任せなのと、もう一つはXと数字とかっこ位しか入力されないだろうという前提があるからです。

今回の注目として、グローバル変数で制限用の値を指定しています。
通常、関数の中のものは関数の中で処理して、グローバルを汚さないようにしましょうというのが基本(javascriptは適当にvarを使わずに作った変数はグローバル変数となってしまうのでなおさら)。
なのですが、プログラム動かしている間は固定だけれど、変えたいときにどこを変えればいいかすぐわかるようにする場合なんかは、わざとグローバルで宣言することもあります。

もっと単純に、関数同士で呼び出されたことを記憶して切り替わるスイッチとして使うこともありますけれどね!

さてさて。
そういえば、グローバル変数を取り出すときには、こうした方がいいかも、とかいっていたときがありましたよね。
そう、「スクリプトのこと」の回です。
ファイルを読み込んで、evalで再評価することによって、共通で使う関数とか定数ファイルとかを別に書いておくことができます。
というわけでその機能を含めて改めて書き直しましょう。
前回の分も含めて、三つのソースと1つの定数ファイルに分けます。
ファイル名:diceRoll.js
/******************************************************
ダイス基本関数

基本説明
ダイス個数回分、ダイス面数で指定されたダイスを振り、
ダイスの振った結果をオブジェクトとして返却する。

in
diceNum:ダイス個数(正数)
diceFace:ダイス面数(正数)

out
ダイス結果object
[
array:ダイス結果配列(Array)
sum:ダイス結果合計値
]
*******************************************************/
function diceRoll(diceNum, diceFace)
{
//返却用ダイスobject
var dice = new Object();
//返却用ダイス結果合計値
dice.sum = 0;
//返却用ダイス結果配列
dice.array = new Array();

//0以下のときには0を返す。
if (diceNum <= 0 || diceFace <= 0)
{
dice.array.push(0);
return(dice);
}

//ダイス個数分、ダイス面数で指定されたダイスを振る。
for (var i = 0; i < diceNum; i++)
{
//ダイスを振った結果をダイス結果配列に。
dice.array.push(Math.floor(Math.random() * diceFace) + 1);

//ダイスを振った結果を合計値に足していく。
dice.sum += dice.array[i];
}

//結果返却
return(dice);
}

ファイル名:normalDice.js
//文字列入力処理
function event::onChannelText(prefix, channel, text)
{
//ダイス要素っぽいものがあれば取り出し
if (text.match(/^([0-9()d./+*-]+)([  ].*)?$/i))
{

//通常ダイス関数呼び出し
if (dice = normalDice(RegExp.$1))
{

//文字列出力処理
send(channel, prefix.nick + " : " + dice.words
+ " = " + dice.disp + " = " + dice.sum);
}
}
}
/******************************************************
↓初期読み込み処理↓
******************************************************/
//ダイス関数ファイル読み込み
var fileObj = openFile("diceRoll.js");
if (fileObj) {
try
{
var fileStr = fileObj.readAll();
fileObj.close();
eval(fileStr);
}
catch(e)
{
log("diceRoll.jsファイル読み込み失敗");
}
} else {
log("diceRoll.jsファイルオープン失敗");
}
/******************************************************
↑初期読み込み処理↑
******************************************************/

/******************************************************
通常ダイス関数

基本説明
ダイスの要素を含む文字列を受け取り、○d△の形を抽出。
ダイスを振り、結果をダイス要素に置き換えたものと、
結果を計算したものをオブジェクトとして返却する。
通常の数式を入れた場合も計算をする。
in
words:入力ワード(ダイス要素を含む文字列)

out
ダイス結果object
[
disp:ダイス表示用(ダイスを振った結果で置き換えた文字列)
sum:ダイス結果合計値(計算した結果の数値)
cal:計算式(ダイスを振った後の計算過程の計算式)
diceWords:渡された入力文字列
]
*******************************************************/
function normalDice(diceWords)
{
try
{
//返却オブジェクト
var dice = new Object();

//入力文字列保存
dice.words = diceWords.replace(/d/ig, "D");

//かっこ計算処理
while (diceWords.match(/(\([^d(]+?\))/i))
{
var sum = eval(RegExp.$1);

//かっこ計算後置き換え
diceWords = diceWords.replace(/(\([^d(]+?\))/i, sum);
}

//
dice.disp = diceWords;
dice.cal = diceWords;

var diceMatch =
new RegExp(/((0|[1-9]\d*)(\.[0-9]+)?)d((0|[1-9]\d*)(\.[0-9]+)?)/i);

//ダイスの要素を取り出し(小数点を含む場合の正規表現の関係で、
//括弧対応の取り出しは1番目と4番目)
while (dice.disp.match(diceMatch))
{
//ダイス個数
var diceNum = Math.floor(parseFloat(RegExp.$1));
//ダイス面数
var diceFace = Math.floor(parseFloat(RegExp.$4));

//ダイス結果格納
var diceData = diceRoll(diceNum, diceFace);

//表示置き換え(ループしないようにDをMに一時的に置き換え)
dice.disp = dice.disp.replace(diceMatch,
"(" + diceNum + "M" + diceFace + "=[."
+ diceData.array.join(".") + ".]=" + diceData.sum + ")");

//計算式置き換え
dice.cal = dice.cal.replace(diceMatch, diceData.sum);
}

//表示置き換え
dice.disp = dice.disp.replace(/M/ig, "D");

//計算結果入れ
dice.sum = eval(dice.cal);

//結果返却
return(dice);
}
catch(e)
{
return(null);
}
}

ファイル名:doubleCrossDice.js

//文字列入力処理
function event::onChannelText(prefix, channel, text)
{
//ダイス要素っぽいものがあれば取り出し
if (text.match(/^([0-9()x/+*-]+)([  ].*)?$/i))
{

//通常ダイス関数呼び出し
if (dice = doubleCrossDice(RegExp.$1))
{
if (dice.errFlg)
{
//メッセージ
send(channel, prefix.nick + " : " + dice.words + "= " + dice.disp.join(""));
}
else
{
if (dice.fumbleFlg)
{
//メッセージ
send(channel, prefix.nick + " : " + dice.words + "= " + dice.disp + "= FUMBLE!!");
}
else
{
//メッセージ
send(channel, prefix.nick + " : " + dice.words + "=" + dice.disp.join("")
+ " 成功度:" + dice.succVal + " 達成値:" + dice.achiVal);
}
}
}
}
}

/******************************************************
↓初期読み込み処理↓
******************************************************/
//ダイス関数ファイル読み込み
var fileObj = openFile("diceRoll.js");
if (fileObj) {
try
{
var fileStr = fileObj.readAll();
fileObj.close();
eval(fileStr);
}
catch(e)
{
log("diceRoll.jsファイル読み込み失敗");
}
} else {
log("diceRoll.jsファイルオープン失敗");
}

//初期設定ファイル読み込み
var fileObj = openFile("diceStatus.txt");
if (fileObj) {
try
{
var fileStr = fileObj.readAll();
fileObj.close();
eval(fileStr);
}
catch(e)
{
log("diceStatus.txtファイル読み込み失敗");
}
} else {
log("diceStatus.txtファイルオープン失敗");
}

//ダイス個数上限宣言されているか判定
if (typeof defDXDiceMaxLim == "undefined")
{
//ダイス個数上限(ダブルクロスダイス関数制御用グローバル変数)
var defDXDiceMaxLim = 40;
}

//クリティカル値下限宣言されているか判定
if (typeof defDXDiceMaxLim == "undefined")
{
//クリティカル値下限(ダブルクロスダイス関数制御用グローバル変数)
var defDXClitMinLim = 5;
}
/******************************************************
↑初期読み込み処理↑
******************************************************/

/******************************************************
ダブルクロスダイス関数

基本説明
○x△の要素を含む文字列を受け取り、○x△+□の形を抽出。
○個分10面ダイスを振り、△以下の結果をカウント、
カウントした個数分10面ダイスをふり直す行為を繰り返す。
ふり直した回数×10と、最後に振った10面ダイスの最大値を
成功度。成功度に□を足した結果を計算したものを達成値。
ダイスの振っている経過をdispに配列。
始めに振ったダイスが全て1であったときはファンブルフラグはtrue。
ダイスの個数かクリティカル値が制限をこえていたときはerrFlgはtrue。
これらの要素を含むオブジェクトを返却する。
エラー及びマッチしない場合は、falseを返却する。

in
diceWords:ダイス要素を含む文字列

out
ダイス結果object
[
disp:ダイス結果配列(Array)
fumbleFlg:ファンブルフラグ
errFlg:上限/下限エラーフラグ
achiVal:達成値
succVal:成功度
words:渡された入力文字列
]
*******************************************************/
function doubleCrossDice(diceWords)
{
try
{
//返却用ダイスobject
var dice = new Object();
//ファンブルフラグ
dice.fumbleFlg = true;
//達成値
dice.achiVal = 0;
//成功度
dice.succVal = 0;
//表示項目
dice.disp = new Array();
//上限・下限エラーフラグ
dice.errFlg = false;

//子文字化
dice.words = diceWords.replace(/x/ig, "x");

//判定用の値取得。○x△+□で分割。
if (dice.words.match(/([0-9()+*/-]+\)?)x(\d+|\([^)]+?\)|\([^(]*?\([^)]*?\)[^)]*?\))(.*)/i))
{
//数値計算
var diceCount = Math.floor(parseFloat(eval(RegExp.$1)));
var diceCritical = Math.floor(parseFloat(eval(RegExp.$2)));
var diceBonus = Math.floor(parseFloat(eval(RegExp.$3)));

//達成値上昇無し
if (!diceBonus)
{
diceBonus = 0;
}

//ダイス個数がマイナス時の処理
if (diceCount < 1)
{
diceCritical = 11;
diceCount = 1;
}

//上限値チェック
if (diceCount > defDXDiceMaxLim
|| diceCritical < defDXClitMinLim)
{
//エラー
dice.errFlg = true;
//メッセージ
dice.disp.push("ダイス個数かクリティカル値が上限を超えています。");
dice.disp.push("個数=" + diceCount+ "・個数上限=" + defDXDiceMaxLim + "/クリティカル値="
+ diceCritical + "・クリティカル下限=" + defDXClitMinLim);

//エラーで終了
return(dice);
}

//判定
do
{
var xVal = 0;
var critFlg = false;
//ダイスロール
var diceData = diceRoll(diceCount, 10);

//ファンブルチェック
if (dice.fumbleFlg && diceData.sum != diceCount)
{
dice.fumbleFlg = false;
}

//ダイスの個数をリセット
diceCount = 0;

//ダイスループ
for (var i = 0; i < diceData.array.length && !dice.FumbleFlg; i++)
{
//達成値判定
if (diceData.array[i] > xVal)
{
xVal = diceData.array[i];
}

//クリティカル判定
if (diceCritical <= diceData.array[i])
{
xVal = 10;
critFlg = true;
++diceCount;
}
}

dice.succVal += xVal;
dice.disp.push("[." + diceData.array.join(".") + ".]");
}
while(critFlg) //クリティカルしていたら繰り返し

//達成度計算
dice.achiVal = dice.succVal + diceBonus;
}
else
{
return(false);
}
return(dice);
}
catch(e)
{
return(false);
}
}

ファイル名:diceStatus.txt
//ダイス個数上限(ダブルクロスダイス制御用)
defDXDiceMaxLim = 40;
//クリティカル値下限(ダブルクロスダイス制御用)
defDXClitMinLim = 5;


ざっくりざっくり。こんな感じです。
というか長すぎ!

ファイルの場所は、normalDice.jsとdoubleCrossDice.jsはスクリプトフォルダ、diceStatus.txtとdiceRoll.jsはスクリプトフォルダ内のfilesとなります。
openFile関数の参照場所のデフォルトがそこなので、変に設定を増やさなくていいので、そんな感じ!

こういう風に小分けにしておくと、「スクリプトのこと」で言っていたように、見通しがよくなるのとか、修正しやすくなったりとか、オンオフが機能ごとにできるようになるとか、いろいろ利点があります。
後、こういう記事ネタにするときに、後々見やすくなるというか。
なので、分割作業をこれ以上長くなる前の今したわけですね。

というわけで、今回分のソースです。
複数個なので圧縮してプレゼント。
前回と同じように、自主責任において使用してください、フリーなソースです。
使用方法とか説明するのが面倒なので、そのあたり含めてフリー。
でもおしえてっていわれれば教えなくもないわよ!
そして、ちょっぴり著作をアピール。

追伸。ソースを表示するために改行を増やすのが面倒になってきたので、縮小しています。実際のソースは、ファイルか何かで見てください。ごめんなさい!
(本当は長さもルールで決めるべきですよ)

2010.2.28追記
一部バグがあったため(半角かっこのみ等で入力されると反応してしまう)
修正いたしました。
posted by 海月歩空 at 22:22| Comment(0) | TrackBack(0) | プログラム