Language detail: D

Coverage: 64.29%
number of '+' ratings
contribution for coverage

Unsolved challenges

codes

Feed

Used modules

next >>

2^i * 3^j * 5^k なる整数 (Nested Flatten)

因数分解する方針で。

 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
import std.stdio;

struct HammingNumbers {
    static bool isHammingNumber(uint n) {
        static bool[uint] memo;
        
        if(n == 1) return true;
        if(auto p = n in memo) return *p;
        
        if(n % 2 == 0)
            return memo[n] = isHammingNumber(n / 2);
        if(n % 3 == 0)
            return memo[n] = isHammingNumber(n / 3);
        if(n % 5 == 0)
            return memo[n] = isHammingNumber(n / 5);
        return memo[n] = false;
    }
    
    static int opApply(int delegate(ref const(size_t), ref const(uint)) dg) {
        size_t i = 0;
        uint n = 1;
        while(true) {
            if(isHammingNumber(n)) {
                if(auto result = dg(i, n))
                    return result;
                i++;
            }
            n++;
        }
    }
}

void main(){
    foreach(i, n; HammingNumbers) {
        if(i == 100) break;
        writeln(i, ": ", n);
    }
}
不動点演算子 (Nested Flatten)

テンプレート引数の推論を使って型無しラムダっぽく。

 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
import std.stdio;

void main() {    
    auto Y = new class {
        auto opCall(_)(_ f) {
            return (new class {
                auto opCall(_)(_ g) {
                    return new class {
                        auto opCall(_)(_ x) {
                            return f(g(g))(x);
                        }
                    };
                }
            })(new class {
                auto opCall(_)(_ g) {
                    return new class {
                        auto opCall(_)(_ x) {
                            return f(g(g))(x);
                        }
                    };
                }
            });
        };
    };
    
    auto F = new class {
        auto opCall(_)(_ f) {
            return new class {
                auto opCall(_)(_ x) {
                    if (x == 0) {
                        return cast(_)1;
                    } else {
                        return x * f(x - 1);
                    }
                }
            };
        }
    };

    auto factorial = Y(F);
    writeln("fact(5) = ", factorial(10));
    writeln("fact(5) = ", factorial(20L));
}
LL Golf Hole 7 - バイト数を読みやすくする (Nested Flatten)

C++のを真似ようと思ったのですが、なんだか普通になってしまいました。 入力はリテラル、出力はコンパイラメッセージで。

出力:

123
234.5k
345.6M
456.7G
567.8T
d202.d(39): static assert  "done!"
 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
static import std.metastrings;

struct None { enum Symbol = "",  Base = 1;    }
struct Kilo { enum Symbol = "k", Base = 1e+3; }
struct Mega { enum Symbol = "M", Base = 1e+6; }
struct Giga { enum Symbol = "G", Base = 1e+9; }
struct Tera { enum Symbol = "T", Base = 1e12; }

template SIPrefix(long n) {
    static if(n < Kilo.Base)
        alias None SIPrefix;
    else static if(n < Mega.Base)
        alias Kilo SIPrefix;
    else static if(n < Giga.Base)
        alias Mega SIPrefix;
    else static if(n < Tera.Base)
        alias Giga SIPrefix;
    else
        alias Tera SIPrefix;
}

template SIFormat(long n) {
    enum SIFormat = ToString!(n / SIPrefix!(n).Base) ~ SIPrefix!(n).Symbol;
}

private template ToString(real x) {
    enum ToString = ToString!(cast(long)x) ~ "." ~ ToString!(cast(long)(x * 10))[$ - 1];
}
private template ToString(long x) {
    enum ToString = std.metastrings.ToString!(x);
}


pragma(msg, SIFormat!(123));
pragma(msg, SIFormat!(234567));
pragma(msg, SIFormat!(345678901));
pragma(msg, SIFormat!(456789012345));
pragma(msg, SIFormat!(567890123456789));

static assert(false, "done!"); // コンパイル終了
文字列型日時ののN秒後時間取得 (Nested Flatten)

使用例も書かないとダメですね。

 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
import std.conv;
import std.date;
import std.stdio;

string DateEx(string datetime, int tdelta_in_secs)
{
    d_time t = std.date.parse(datetime);
    d_time new_datetime = t + tdelta_in_secs * std.date.TicksPerSecond;
    return std.date.toString(new_datetime);
}
unittest {
    assert(DateEx("Mon Sep 01 13:00:00 GMT+0900 2008", -3600) ==
        "Mon Sep 01 12:00:00 GMT+0900 2008");
    assert(DateEx("Mon Sep 01 13:00:00 GMT+0900 2008", 3600) ==
        "Mon Sep 01 14:00:00 GMT+0900 2008");
}

void main(string[] args)
{
    string datetime;
    int tdelta_in_secs;
    if (args.length == 3) {
        datetime = args[1];
        tdelta_in_secs = toInt(args[2]);
    }
    else {
        d_time now = std.date.getUTCtime;
        datetime = std.date.toString(now);
        tdelta_in_secs = toInt(args[1]);
    }
    writefln("%s", DateEx(datetime, tdelta_in_secs));
}

// eof
D 2.0 + Phobos。
 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
import std.conv;
import std.date;
import std.stdio;

string DateEx(string datetime, int tdelta_in_secs)
{
    d_time t = std.date.parse(datetime);
    d_time new_datetime = t + tdelta_in_secs * std.date.TicksPerSecond;
    return std.date.toString(new_datetime);
}

void main(string[] args)
{
    string datetime;
    int tdelta_in_secs;
    if (args.length == 3) {
        datetime = args[1];
        tdelta_in_secs = toInt(args[2]);
    }
    else {
        d_time now = std.date.getUTCtime;
        datetime = std.date.toString(now);
        tdelta_in_secs = toInt(args[1]);
    }
    writefln("%s", DateEx(datetime, tdelta_in_secs));
}

// eof
LL Golf Hole 8 - 横向きのピラミッドを作る (Nested Flatten)

標準入力から。

1
2
3
4
5
6
7
import std.stdio, std.conv, std.string;

void main() {
    int n = to!(uint)(chomp(readln));
    foreach(i; 1..n*2)
        writeln("*".repeat(i<n?i:2*n-i));
}
LL Golf Hole 5 - 最上位の桁を数え上げる (Nested Flatten)

標準入力から。

この手の文字列操作はガーベジコレクタのおかげでたやすくできます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import std.stdio, std.string;

void main() {
    auto t = chomp(readln), s = "0".dup;
    while(s.length < t.length || s <= t) {
        writeln(s);
        
        if(s[0] < '9') {
            s[0]++;
        } else {
            s = "10" ~ s[1 .. $];
        }
    }
}
LL Golf Hole 6 - 10進数を2進数に基数変換する (Nested Flatten)

標準入力から一行読み込んで変換。

1
2
3
4
5
import std.stdio, std.conv, std.string;

void main() {
    writefln("%b",to!(int)(strip(readln)));
}
LL Golf Hole 4 - 文章から単語の索引を作る (Nested Flatten)

文章はコンパイル時に文字列リテラルとして取り込むので、dmdの-Jオプションでgpl.txtのあるディレクトリを指定してください。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
private import std.stdio, std.string, std.regexp;

auto text = import("gpl.txt");

void main() {
    int[][string] dict;
    auto re = RegExp(r"[\w-]+");
    foreach(i, line; text.splitlines()) {
        foreach(m; re.search(line)) {
            dict[m[0].tolower()] ~= i + 1;
        }
    }
    writeln(dict);
}
LL Golf Hole 3 - 13日の金曜日を数え上げる (Nested Flatten)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
private import std.stdio, std.date;

enum Friday = 5;

void main(){
    auto count = 0;
    foreach(day; Day(getUTCtime) .. MakeDay(2014, 1, 1)) {
        auto date = MakeDate(day, 0);
        if(WeekDay(date) == Friday && DateFromTime(date) == 13) {
            writefln("%04d-%02d-%02d", YearFromTime(date), MonthFromTime(date) + 1, DateFromTime(date));
            ++count;
        }
    }
    writeln(count);
}
LL Golf Hole 2 - 文字列に含まれる単語の最初の文字を大文字にする (Nested Flatten)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
private import std.string, std.regexp;

string totitle(in string str) {
    return str.sub(r"\b[a-z]", (RegExp m){return m[0].toupper();}, "g");
}

unittest {
    assert("LL future".totitle() == "LL Future");
    assert("LL day and night".totitle() == "LL Day And Night");
}
循環関数 (Nested Flatten)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
int modular(int n, int low, int high) {
    return low + (n + high - low + 1) % (high - low + 1);
}

unittest {
    assert(modular(0,100,200)   == 100);
    assert(modular(50,100,200)  == 150);
    assert(modular(100,100,200) == 200);
    assert(modular(101,100,200) == 100);
    assert(modular(-1,100,200)  == 200);
    assert(modular(1,-5,200)    ==  -4);
    assert(modular(-500,-5,-1)  ==  -5);
}
2次元ランダムウォーク (Nested Flatten)

出力はSVGにしてみました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private import std.stdio, std.math, std.random;

void main() {
    write(`<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="600" height="600">
<title>ランダムウォーク</title>
<g transform="translate(300,300)">
<circle style="fill:blue" cx="0" cy="0" r="5"/>
<path style="fill:none; stroke:black; stroke-width:1" d="M 0 0`);

    auto rgen = Random(unpredictableSeed);
    auto uniform = UniformDistribution!(real)(0, PI * 2);
    foreach(_; 0 .. 10000) {
        auto angle = uniform.next(rgen);
        auto move = expi(angle) * 10;
        writef(` l %.2f %.2f`, move.re, move.im);
    }

    write(`"/>
</g>
</svg>`);
}
LL Golf Hole 1 - tinyurl.comを使ってURLを短縮する (Nested Flatten)
1
2
3
4
5
6
7
8
9
private import std.stdio, std.string, std.socket, std.socketstream;

void main() {
    auto s = new SocketStream(new TcpSocket(new InternetAddress("tinyurl.com", 80)));
    scope(exit) s.close;
    
    s.writeString("GET /api-create.php?url=http://ll.jus.or.jp/2008/info/xgihyo HTTP/1.1\r\nHost: tinyurl.com\r\n\r\n");
    foreach(char[] line; s) if(line.startsWith("http://")) writeln(line);
}
環境変数の取得 (Nested Flatten)

変数名から値を得るだけなら、getenv 関数があります。

1
2
3
4
5
private import std.stdio, std.process;

void main() {
    writeln(getenv("PATH"));
}
D 2.0 + 標準ライブラリ (Phobos)、Linuxで動作確認。連想配列を作ってしまう方針で。
Phobosには環境変数APIが無いので、Cの environ(7) を直接呼び出します。
C文字列をDのstringに変換する処理が面倒ですね。もっとうまいやり方があるような気がする...
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import std.stdio;
import std.string;
import std.c.linux.linux: environ;
import std.c.string: strlen;

void main()
{
    char** p;
    string[string] envAA;
    for (p = environ; *p != null; p++) {
        char[] key_and_value = (*p)[0 .. strlen(*p)];    // "FOO=BAR"
        int iEqual = key_and_value.find('=');    // index to '='
        string key = cast(string)(key_and_value[0 .. iEqual]);
        string value = cast(string)(key_and_value[iEqual + 1 .. $]);
        envAA[key] = value;
    }
    envAA.rehash;

    foreach(key, value; envAA) {
        writefln("%s: %s", key, value);
    }
    writefln("PATH = %s", envAA["PATH"]);
}
クリップボードへの転送 (Nested Flatten)

生憎、今のところそのような便利ライブラリはなさそうなので生のWin32APIを使わざるを得ません。

 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
module win32.clipboard;
private import std.c.windows.windows;
private import std.contracts, std.conv;

export extern(Windows) {
    HGLOBAL GlobalAlloc(UINT uFlags, DWORD dwBytes);
    HGLOBAL GlobalFree(HGLOBAL hMem);
    LPVOID GlobalLock(HGLOBAL hMem);
    BOOL GlobalUnlock(HGLOBAL hMem);
    enum UINT GMEM_MOVEABLE = 2;
    
    BOOL CloseClipboard();
    BOOL EmptyClipboard();
    UINT EnumClipboardFormats(UINT format);
    HANDLE GetClipboardData(UINT uFormat);
    BOOL OpenClipboard(HWND hWndNewOwner);
    HANDLE SetClipboardData(UINT uFormat, HANDLE hMem);
    
    enum UINT CF_UNICODETEXT = 13;
}

public static class Clipboard {    
    static void setText(string text) {
        enforce(OpenClipboard(null));
        scope(exit) CloseClipboard();
        
        auto wtext = to!(wstring)(text);
        auto data = enforce(GlobalAlloc(GMEM_MOVEABLE, wchar.sizeof * (wtext.length + 1)));
        scope(failure) GlobalFree(data);
        
        {
            auto pdata = cast(wchar*)GlobalLock(data);
            scope(exit) GlobalUnlock(data);
            
            pdata[0..wtext.length] = wtext;
            pdata[wtext.length] = '\0';
        }
        
        enforce(EmptyClipboard());
        enforce(SetClipboardData(CF_UNICODETEXT, data));
    }
    
    static string getText() {
        enforce(OpenClipboard(null));
        scope(exit) CloseClipboard();
        
        auto data = GetClipboardData(CF_UNICODETEXT);
        if(!data) return null;
        
        auto pdata = cast(const(wchar)*)GlobalLock(data);
        auto wtext = pdata[0..strlen(pdata)];
        GlobalUnlock(data);
        
        return to!(string)(wtext);
    }
}

private uint strlen(const(wchar)* s) {
    uint len;
    while(*s++) len++;
    return len;
}

debug(Clipboard) {
import std.stdio;

void main() {
    Clipboard.setText("test テスト");
    writeln(Clipboard.getText);
}

}
変数の初期値 (Nested Flatten)

ああ、そうか

そもそもコンパイル系言語では変数が宣言されてないとコンパイル時エラーになるので「未定義の変数を操作」なんて状況自体が有り得ないわけですが、 必ず実行できるスクリプト系の言語では有り得るんですね。 それがどんな問題を引き起こすのかまでは分かりませんが、defined-or演算子が必要なのであろうことは分かります。 となるとD言語では「コンパイラが検出してくれるので必要ない」が正解かな。

ちなみにD言語では基本的に宣言した変数は全て初期化されますが、実行速度を重視する場合は初期化しないこともできます。 また、typedefで新しく型を定義するときにデフォルトの初期値を指定できます(変な言い方ですが)。 問題と似たようなケースで使えそうです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import std.stdio;

//デフォルトの初期値
typedef int myint = 100;

void main()
{
  int a;
  myint b;
  //未初期化の変数を宣言
  myint c = void;

  //"a=0 b=100 c=(不定)"
  writefln("a=%d b=%d c=%d",a,b,c);
}
比較しないソートの作成 (Nested Flatten)

Radix sort (内部アルゴリズムはBucket sort)

 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
private import std.stdio, std.stdint;

void main() {
    int64_t[] a = [int64_t.max, 0, -1, 3, 1 << 17, -1 << 30, int64_t.min];
    writeln(a); // [9223372036854775807 0 -1 3 131072 -1073741824 -9223372036854775808]
    a.radixSort();
    writeln(a); // [-9223372036854775808 -1073741824 -1 0 3 131072 9223372036854775807]
}

private import std.traits : unsigned;

void radixSort(T)(T[] array) if(is(unsigned!(T))) {
    alias unsigned!(T) U;

    auto uarray = new U[array.length];
    foreach(i, ref n; uarray) {
        n = array[i] - T.min;
    }
    
    foreach(i; 0 .. T.sizeof * 8 / 4) {
        auto buckets = new U[][1 << 4];

        foreach(n; uarray) {
            buckets[n >> i * 4 & 0b1111] ~= n;
        }

        auto p = uarray.ptr;
        foreach(bucket; buckets) {
            p[0 .. bucket.length] = bucket;
            p += bucket.length;
        }
    }

    foreach(i, ref n; array) {
        n = uarray[i] + T.min;
    }
}

Counting sort

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
private import std.stdio;

void main() {
    int[] a = [1, 9, 4, 8, 9, 6, 3, 9, 5, 2];
    a.countingSort(1, 10);
    writeln(a);
}

void countingSort(int[] array, int min, int max) {
    auto counts = new uint[max - min + 1];
    foreach(n; array) {
        counts[n - min]++;
    }
    auto p = array.ptr;
    foreach(i, c; counts) {
        p[0..c] = i + min;
        p += c;
    }
}
next >>

Index

Feed

Other

Link

Pathtraq

loading...