Created
December 9, 2018 10:33
-
-
Save kotet/20f8231a3dfa328cb81ccf491f502ac7 to your computer and use it in GitHub Desktop.
シクシク素数列 Advent Calendar 2018
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/rdmd | |
// 自然数を返す無限レンジ。 | |
// map等の関数を使うためにはinputrangeである必要があり、 | |
// inputrangeの条件を満たすためには | |
// front,popFront,emptyという3つの関数を実装する必要がある | |
struct NaturalNumber | |
{ | |
long n = 1; | |
// 先頭の要素を返す | |
@property long front() | |
{ | |
return n; | |
} | |
// 先頭の要素を取り除く | |
void popFront() | |
{ | |
n++; | |
} | |
// 空であるか返す。無限レンジなので常にfalse | |
bool empty() | |
{ | |
return false; | |
} | |
} | |
bool isPrime(long n) | |
{ | |
// iには2からn-1までの整数が入る | |
foreach (i; 2 .. n) | |
{ | |
if (n % i == 0) | |
{ | |
return false; | |
} | |
} | |
return true; | |
} | |
bool is4949Prime(long n) | |
{ | |
long tmp = n; | |
do | |
{ | |
if (tmp % 10 == 4 || tmp % 10 == 9) | |
{ | |
return isPrime(n); | |
} | |
tmp /= 10; | |
} | |
while (0 < tmp); | |
return false; | |
} | |
void main() | |
{ | |
// 局所的 & 選択的インポート | |
import std.conv : to, text; | |
import std.array : join; | |
import std.range : take; | |
import std.stdio : readln, writeln; | |
import std.string : chomp; | |
import std.algorithm : filter, map; | |
long n = readln().chomp().to!long(); | |
assert(1 <= n); | |
// 下のコードは | |
// writeln(join(map!(text)(take(filter!(is4949Prime)(NaturalNumber();), n)), ',')); | |
// と等価。 | |
NaturalNumber() | |
.filter!is4949Prime | |
.take(n) | |
.map!text | |
.join(',') | |
.writeln(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/rdmd | |
// 自然数を返す無限レンジ。 | |
// map等の関数を使うためにはinputrangeである必要があり、inputrangeの条件を満たすためには | |
// front,popFront,emptyという3つの関数を実装する必要がある | |
struct NaturalNumber | |
{ | |
long n = 1; | |
// 先頭の要素を返す | |
@property long front() | |
{ | |
return n; | |
} | |
// 先頭の要素を取り除く | |
void popFront() | |
{ | |
n++; | |
} | |
// 空であるか返す。無限レンジなので常にfalse | |
bool empty() | |
{ | |
return false; | |
} | |
} | |
bool isPrime(long n) | |
{ | |
foreach (i; 2 .. n) | |
{ | |
if (n % i == 0) | |
{ | |
return false; | |
} | |
} | |
return true; | |
} | |
bool is4949Prime(long n) | |
{ | |
long tmp = n; | |
do | |
{ | |
if (tmp % 10 == 4 || tmp % 10 == 9) | |
{ | |
return isPrime(n); | |
} | |
tmp /= 10; | |
} | |
while (0 < tmp); | |
return false; | |
} | |
size_t[] createLookupTable(string str) | |
{ | |
size_t[] result; | |
foreach (i, c; str) | |
{ | |
if (c == ',') | |
{ | |
// ~は配列に対する追加演算子。 | |
// str[0..x]はstrの最初からx-1文字目までを表すので、 | |
// コンマのインデックスを使うとそのコンマの手前までが表示できる | |
result ~= i; | |
} | |
} | |
// コンマは 100 - 1 == 99 個あるので、 | |
// ここまででresultには N == 99 までの結果のインデックスが入っている。 | |
// N == 100 の時は文字列全体を表示する | |
result ~= str.length; | |
return result; | |
} | |
void main() | |
{ | |
import std.stdio : readln, writeln; | |
import std.string : chomp; | |
import std.conv : to, text; | |
import std.algorithm : filter, map; | |
import std.range : take, array; | |
import std.array : join; | |
long n = readln.chomp.to!long; | |
assert(1 <= n); | |
assert(n <= 100); | |
// enumはコンパイル時定数。数値リテラル100と同じような扱いを受ける | |
enum N = 100; | |
// この変数は値が実行ファイルに埋め込まれる。 | |
// したがってその値の計算はコンパイル時に行われる | |
static immutable string str = NaturalNumber() | |
.filter!is4949Prime | |
.take(N) | |
.map!text | |
.join(','); | |
static immutable size_t[] lookuptable = createLookupTable(str); | |
// コンパイル時のassert | |
static assert(lookuptable.length == N); | |
// 実行時には配列を見るだけ | |
writeln(str[0 .. lookuptable[n - 1]]); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment