読者です 読者をやめる 読者になる 読者になる

D言語2.0で憂鬱な勇者

http://d.hatena.ne.jp/hrkt0115311/20080527/1211891558

うちのクソゲーに名前が似ていたので、D言語2.0の勉強がてらに作ってみました。やたらてこずってしまいましたが、公開してみます。

D言語2.0(dmd v2.014)でやってみました。

  • 経験値管理にクロージャを使ってみる
  • Range(1..30)っぽいforeachを使ってみる
  • std.bigint

困りポイント1:多倍長整数が標準で扱えない

経験値がレベルの階乗なので、ulongとかだとあっという間にあふれます。

D言語多倍長整数を扱うっぽいライブラリstd.bigintは、まだ準備中のようです。
http://www.kmonos.net/alang/d/2.0/phobos/std_bigint.html

準備中のソースらしきものはこの辺で拾えるので、とりあえずこれをお借りする。
http://www.dsource.org/projects/phobos/browser/trunk/phobos/std/bigint.d?rev=700

  • ソース中の「module std.bigint;」はコメントアウトする
  • mybigint.dとかいう名前で保存
  • 自分のソースからはprivate importで使う
    • public importとすると、予約?されてるstd.bigintと競合するのかなんかわからんけどエラーになる

bigintのソースコメントにもありますが、BigIntはこういうことができるようです。

BigInt a = "9588669891916142";
BigInt b = "7452469135154800";
auto c = a * b;
assert(c == "71459266416693160362545788781600");

困りポイント2:文字化けする

憂鬱な勇者特有の問題では全然ないんですけど、標準出力がUTF-8でぶちまけられるのでWindows上でそのまま動かすと思いっきり文字化けします。

この現象はずいぶん前から知っていたのですが、まだすっきりとした解決はないっぽいのですね。。。

アプリ側で対応するのが面倒な場合は、

yu | iconv -f utf-8 -t shift-jis

みたいにiconv*1通すか、リダイレクトしていったんファイルに落とすか、となりますね。

しかいサクッ使い捨てツール作って配布したい場合、こういうこまごまとした制限はうっとおしいなあ。


そーす

import std.stdio;
import std.random;
private import mybigint;

string[] m_monster = ["焼きたてパン","強いシャチホコ","もんじゃ焼き一年生","怪人ホタテ男","ニセ勇者","逃げ足の早いアレ","睡魔","煩悩","愛らしい子犬の中の人","恋するスズメバチ","勇敢なクマンバチ","信じられない物","勇者の師匠","浮遊する鎧","怪盗ドボン","闇の招き猫","誘惑のカスタードクリーム","しょっぱすぎる籠手","カレー味の兜","光沢だけは一流の盾","若葉マークのモンスター","新緑の季節","梅雨時の車両のニオイ","暑すぎる夏","新宿らしき何か","やたら発達したドーナツ","育ちすぎたクマー","なごやかな雰囲気","凍り付いた気配","忍び寄る恐怖",];
string[] m_skill   = ["お豆腐の買い方","鉛筆の買い方","消しゴムの使い方","メモの取り方","攻撃に使えないこともない呪文","裏町の歩き方","森林浴","珈琲の味","しじみのみそ汁の作り方","回覧板の回し方","郵便物の投函方法","立ち話のコツ","猫の呼び方","犬の呼び方","カラスの呼び方","鳩専用豆鉄砲","秘密の趣味","速く走るコツ","剣の使い方","斧の使い方","まきわりで、まっきわりわり","聖なる祈り","孤独","涼しく過ごすコツ","お洒落のコツ","卵をふわっと焼く方法","ごはんの研ぎ方","油汚れの対応方法","大人の振るまい","Suicaの使い方",];


const int MAX_LEVEL = 30;

// 経験値を管理する無名関数を作ってreturnする
mybigint.BigInt delegate() exp_dlg(int l, int e)
{
  int level = l;
  mybigint.BigInt bi = e;

  // クロージャ!
  return {
    bi = bi * level;
    level++;
    return bi;
  };
}

// 0 - (n-1) の乱数を作る
uint get_rand(uint n)
{
  return rand() % n;
}


int main()
{
  auto my_exp = exp_dlg(1, 1);
  
  foreach (i; 1..MAX_LEVEL+1)
  {
     auto m_id = get_rand(m_monster.length);
     auto s_id = get_rand(m_skill.length);

     writefln("*-----");
     writefln("%sを倒した!", m_monster[m_id]);
     writefln("%sの経験値を得た。", my_exp());
     if (i < MAX_LEVEL)
     {
       writefln("勇者は%dにレベルが上がった!勇者は、%sを覚えた。", i, m_skill[s_id]);
       writefln("");
       writefln("");
       writefln("そして、");
       writefln("かくかくしかじかで、山あり谷ありの冒険が続いたが割愛。");
     }
     else
     {
       writefln("勇者は、また、レベルが上がった!");
       writefln("勇者は、ふと空しさを覚えた。");       
     }
     writefln("");

  }

  return 0;
}

追記

http://d.hatena.ne.jp/hrkt0115311/20080609/ThankYou

ありがとうございます。
いやその、わたしド素人で勉強中なもので、こんなに好意的なコメントを頂くのは恐縮です。
とりあえずD2.xの新機能をためしに使ってみたよというレベルです。

*1:cygwin導入前提