dlang
D言語Day 9

小物づくりからはじめるD言語入門

まえがき

新しい言語を学び始めたきっかけ、覚えてますか?
この記事では「小物(さいころ)を作って満足する」という視点から,D言語の紹介記事のようなサムシングをこしらえてみました。

下準備

Home D Programming language
https://dlang.org/
大体なんでもあります。公式の入門記事(日本語訳版あり)もあります。

編集の際は文字コードがUTF-8であることを確認してください。文字コードが違った場合の動作の保証は致しかねます。
改行コードは気にしなくても大丈夫だと思います。

実際にさいころを作る

さいころ?

さっそくサイコロを作ってみます。
まずは数字を std.stdio の write() などで出力してみます。

import std.stdio;

void main(){
    writeln(1);
    writeln(1);
    1.writeln();
}
$ rdmd dice.d
> 1
> 1
> 1

1面ピンじゃねぇか…!通るかっ…!こんなもん…!
一部に需要がありそうなサイコロですが、やっぱり変化が欲しいですね。

さいころのようなもの

一面ダイスのみではつまらないので六面ダイスも作りましょう。
std.random の uniform() で乱数(疑似)を生成しましょう。

import std.stdio
import std.random;

void main(){
    auto rnd = Random();
    uniform( 1, 6+1, rnd ).writeln();
}
$ rdmd dice.d
> 3
$ rdmd dice.d
> 3

こういうのでいいんだよ、こういうので…
…あれ、複数回実行しても結果が変わりませんでした。何か足りないのでしょうか?

よくあるさいころ

前回のコードでは シード値を与えていませんでした。
今回は 現在時刻をUnixTimeに直したものを シード値とするように変更してみます。
これで(ほぼ)毎回変わるサイコロになるはずです。

import std.stdio;
import std.random;
import std.datetime.systime;

void main(){
    auto rnd = Random(Clock.currTime().toUnixTime());
    // auto rnd = Random(unpredictableSeed()); // このコードもOK
    uniform( 1, 6+1, rnd ).writeln();
}

$ rdmd dice.d
> 5
$ rdmd dice.d
> 4
$ rdmd dice.d
> 2

よかった、これで解決ですね。

…これなら普通にさいころをふれば良いのでは?

無限の可能性を持つさいころ

ここからがプログラミングの本番です。
プログラムで標準入力から数字を受け取り、任意の面数であるサイコロにします。
(引数で受けとる方法もありますが、競技プログラミングでも活かせそうなこちらの手法を使用します)
(2018/12/15 @tm_tn さんより頂いた情報で、std.datetime.systime を使わないコードに書き直しました,thanks!)

import std.stdio;
import std.random;
import std.conv, std.string;

void main(){
    auto rnd = Random(unpredictableSeed());
    auto n = readln().chomp().to!size_t();
    uniform( 1, n+1, rnd ).writeln();
}
$ rdmd dice.d
> 10 (input)
> 6

これでコイントスも正二十面体ダイスも、一つのコードで完結します。素晴らしい!
一つ一つ真心を込めてさいころをふっているので、数字に温かみがあります。(ありません)

100万回ふれたさいころ

サイコロの個数分プログラムを動かすのは面倒に感じます。
せっかくなので、一度の入力でたくさんのサイコロを振れるようにします。

import std.stdio;
import std.random;
import std.conv, std.string;

void main(){
    auto rnd = Random(unpredictableSeed());
    auto list = readln().chomp().split("d");
    size_t sum;

    if ( list.length == 1 ){
        sum = uniform( 1, list[0].to!size_t()+1, rnd );
    } else if( list.length == 2 ) {

        foreach( i ; 0..list[0].to!size_t() ){
            sum += uniform( 1, list[1].to!size_t()+1, rnd );
        }
    }
    sum.writeln();
}
$ rdmd dice.d
> 1000000d64 (input)
> 32510601

ここまでくると「パワーワード」ならぬ「パワーナンバー」ですね。
工夫の余地はまだまだありますが、コードが複雑になってきたので ここでお開きにします。

最後に

小物づくりから一つの記事をこしらえてみました、皆様の暇つぶしになれば幸いです。