Language detail: xtal
Coverage: 17.14%
|
number of '+' ratings |
contribution for coverage |
Unsolved challenges
- π (Nested Flatten)
- タブ区切りデータの処理 (Nested Flatten)
- LL Golf Hole 9 - トラックバックを打つ (Nested Flatten)
- 2^i * 3^j * 5^k なる整数 (Nested Flatten)
- 起動オプションの解析 (Nested Flatten)
codes
自然数の分割
(Nested
Flatten)
fiber を使って書き換えてみる。
1 2 3 4 5 6 | (|n, m|{ c: callee; m--;
return fiber{
if(m < 1) yield [n];
else (n + 1).times{|x| c(x, m){ yield [n - x] ~ it; } }
}
})(5, 3).join("\n").p;
|
1 2 3 4 5 6 | (|n, m|{
if(m <= 1) return [[n]];
r: [];
(n + 1).times{|x| callee(x, m - 1){ r.push_back([n - x] ~ it); } }
return r;
})(5, 3){ it.p; }
|
2進数の記述
(Nested
Flatten)
0b か 0B で始めると2進整数リテラル。
1 2 3 4 5 | 0b1010.p;
// => 10
0B0110_1001.p;
// => 105 (アンダーバーは無視される)
|
九九の表示
(Nested
Flatten)
%f はフォーマット文字列を定義するリテラルです。 formatter は引数を3つ取る関数になります。 %(hogehoge)d とすることで名前付きにすることも できます。
1 2 3 4 5 6 7 8 9 10 11 12 | mul: fun(n, m) fiber {
n.times.map(|i| i+1).each{|i|
m.times.map(|j| j+1).each{|j|
yield i, j, i * j;
}
}
}
formatter: %f[%d * %d = %2d];
mul(9, 9) {|i,j,s|
formatter(i, j, s).p;
}
|
重複する要素を取り除く
(Nested
Flatten)
配列の要素を [その要素、*残りの要素] に map して 「残りの要素」に「その要素」が含まれていなければ yield します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | Iterator::skip: method(n) {
n.times { this { break; } }
}
Iterator::window: method(start, length) {
this.skip(start);
return this.take(length);
}
only_uniq: fun(arr) fiber {
len: arr.length;
iters: range(0, len).map(|i| arr.cycle.window(i, len).to_a);
iters {|it,rest|
if (rest.select(|e| e == it).to_a.empty) {
yield it;
}
}
}
only_uniq([3, 1, 4, 1, 5, 9, 2, 6, 5]).to_a.p;
|
仲間はずれの判定
(Nested
Flatten)
辞書などを使った回答はもうずいぶん出ているので違ったアプローチで書いたら、 ずいぶん長くなってしまいました。。 実装はひとつづつ要素を見ながら状態遷移していくものです。 each_classify で状態遷移を観察することができます。 無限列にも適用可能です。 もちろん本当に無限にある場合は「その他」以外では答えを出せないのですが、 無限列の最初の n 個の仲間はずれを判定できます。
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 73 74 75 76 77 78 79 80 81 82 83 | Classify: class {
- _iter;
- _state: "homo";
- _majority: null;
- _minority: null;
initialize: method(_iter) {}
+ classify: method(n: null) {
return each_classify(n).to_a.back;
}
+ each_classify: method(n: null) fiber {
iter: n ? _iter.take(n) : _iter;
iter.with_index {|i,it|
this.(_state)(i, it);
if (_state == "hetero") {
break;
}
}
}
- homo: method(i, it) {
if (_majority && _majority != it) {
_minority = it;
if (i < 2) {
_state = "quasi_homo0";
yield ["?", _majority, _minority];
} else {
_state = "quasi_homo";
yield ["quasi_homo", _majority, _minority];
}
} else {
_majority = it;
yield ["homo", it];
}
}
- quasi_homo0: method(i, it) {
if (it == _majority || it == _minority) {
if (it == _minority) {
_majority, _minority = _minority, _majority;
}
yield ["quasi_homo", _majority, _minority];
_state = "quasi_homo";
} else {
hetero(i, it);
}
}
- quasi_homo: method(i, it) {
if (it == _majority) {
yield ["quasi_homo", _majority, _minority];
} else {
hetero(i, it);
}
}
- hetero: method(i, it) {
_state = "hetero";
yield ["hetero", null];
}
}
Classify([1,1,1,1,1].each).classify.p; //=> [homo,1]
Classify([1,2,1,1,1].each).classify.p; //=> [quasi_homo,1,2]
Classify([2,1,1,1,1].each).classify.p; //=> [quasi_homo,1,2]
Classify([2,2,1,1,1].each).classify.p; //=> [hetero,null]
Classify([2,4,1,1,1].each).classify.p; //=> [hetero,null]
Classify([1,2,3,4,5].each).classify.p; //=> [hetero,null]
Classify([2,1,1,1,3].each).each_classify {
it.p;
}
//=> [homo,2]
//=> [?,2,1]
//=> [quasi_homo,1,2]
//=> [quasi_homo,1,2]
//=> [hetero,null]
Classify([1,1,3].cycle).classify(5).p; //=> [quasi_homo,1,3]
Classify([1,1,3].cycle).classify(6).p; //=> [hetero,null]
Classify([1,2,3].cycle).classify.p; //=> [hetero,null]
|
与えられた文字列でピラミッド
(Nested
Flatten)
末尾の空白の数がサンプル出力と違いますが、題意になかったのでスルーしました。 chainは引数のイテレータを順番に実行するイテレータを返す関数です。
1 2 3 4 5 6 7 8 9 10 11 12 | pyramid: fun(str) {
space: [" "].cycle;
arr: str.split("").to_a;
n: arr.length;
n.times.map(|i| i + 1){
chain(space.take(n - it ),
arr.slice(n - it, n).zip(space).map(|a,b| a~b)).join("").p;
}
}
pyramid("hoge");
pyramid("abracadabra");
|
隣り合う二項の差
(Nested
Flatten)
最初 diff は Array を引数に取り、その Array の Iterator と一個先に進めたIterator を zip して map していたんですが、無限列を diff したくなったので Array ではなく Iterator を引数に取るようにしました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | Iterator::each_pair: method fiber {
prev: null;
this { prev = it; break; }
this {
yield prev, it;
prev = it;
}
}
diff: fun(iter) {
return iter.each_pair.map(|a,b| b - a);
}
diff([3, 1, 4, 1, 5, 9, 2, 6, 5].each).to_a.p;
// 無限列のテスト
random_generator: fiber {
while (true) {
yield math::ceil(math::random_range(1, 10));
}
}
diff(random_generator).take(20).to_a.p;
|
アルファベットの繰り上がり
(Nested
Flatten)
前の桁で生成した値の頭にA..Zを付加するという戦略です。 無限桁に対応。A-Zの26進数以外もいけます。 ただ、メモリの消費量が激しいです。
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 | ExcelNumber: class {
+ _chars: "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ generate: method fiber {
before: [""];
while (true) {
before = generate_and_yield(before);
}
}
- generate_and_yield: method(before) {
r: [];
_chars.split("") {|c|
before {|b|
n: c ~ b;
r.push_back(n);
yield n;
}
}
return r;
}
}
excelnum: ExcelNumber();
excelnum.generate.take(100).to_a.p;
excelnum.chars = "abc";
excelnum.generate.take(100).to_a.p;
|
長方形の交差判定
(Nested
Flatten)
javascriptの投稿(http://ja.doukaku.org/comment/1146/)がすっきりしててかっこよかったのでそのままもらいました。 svn rev154 (0.9.7.1)です。
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 | Rectangle: class {
+ _top; + _right; + _bottom; + _left;
initialize: method(top: 0, right: 0, bottom: 0, left: 0) {
_top = top;
_right = right;
_bottom = bottom;
_left = left;
}
is_overlapped: method(other) {
return (math::min(_right, other.right) - math::max(_top, other.left) > 0 &&
math::min(_bottom, other.bottom) - math::max(_left, other.top) > 0);
}
to_s: method() {
return [_top, _right, _bottom, _left].to_s;
}
}
r1: Rectangle(top: 10, right: 20, bottom: 20, left: 10);
[ // overlapped
Rectangle(top: 10, right: 20, bottom: 20, left: 10), // 一致
Rectangle(top: 11, right: 19, bottom: 19, left: 11), // 内
Rectangle(top: 9, right: 21, bottom: 21, left: 9), // 外
Rectangle(top: 5, right: 15, bottom: 15, left: 5), // 左上
Rectangle(top: 5, right: 25, bottom: 15, left: 15), // 右上
Rectangle(top: 15, right: 25, bottom: 25, left: 15), // 右下
Rectangle(top: 15, right: 15, bottom: 25, left: 5), // 左下
// ! overlapped
Rectangle(top: 0, right: 10, bottom: 10, left: 0), // 左上
Rectangle(top: 0, right: 20, bottom: 10, left: 10), // 上
Rectangle(top: 0, right: 30, bottom: 10, left: 20), // 右上
Rectangle(top: 10, right: 30, bottom: 20, left: 20), // 右
Rectangle(top: 20, right: 30, bottom: 30, left: 20), // 右下
Rectangle(top: 20, right: 20, bottom: 30, left: 10), // 下
Rectangle(top: 20, right: 10, bottom: 30, left: 0), // 左下
Rectangle(top: 10, right: 10, bottom: 20, left: 0), // 左
].each {|r| r1.is_overlapped(r).p; }
|
実行時間の測定
(Nested
Flatten)
0.9.7 から追加された(と思われる) clock() 関数を使ってみました。 * profile 関数と func 関数が同じ引数を受け取れる。 * func 関数の戻り値を profile 関数の戻り値としている。 svn rev154 (0.9.7.1)です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | profile: fun(...) {
fmt: %f!profile: %d sec!;
start: clock();
result: func(...);
fmt(clock() - start).p;
return result;
}
func: fun(...) {
for (i: 0; i < 1000000; i++) {
// 重たい処理
}
}
profile("test");
|
メソッド名一覧の表示
(Nested
Flatten)
super クラスも検索するようにしてみました。 「bar: || "bar".p」というのは引数なしの lambda 関数を bar に束縛しているような感じです。
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 | String::start_with: method(sub) {
return this.split("").take(sub.length).to_a.join("") == sub;
}
TargetTest: class {
test_foo: || "test_foo".p;
test_bar: || "test_bar".p;
foo: || "foo".p;
bar: || "bar".p;
}
TargetTest2: class(TargetTest) {
test_foo: || "test_foo_sub".p;
test_baz: || "test_baz".p;
}
TestRunner: class {
suite: method(target, inherited_too: true) fiber {
klasses: [target];
if (inherited_too) {
klasses ~= target.each_ancestor.to_a;
}
override: Map();
klasses {|klass|
klass.each_member {|name, x, meth|
if (! override[name] && name.start_with("test_")) {
yield meth;
}
override[name] = true;
}
}
}
run: method(target) {
suite(target) {
it();
}
}
}
runner: TestRunner();
"---".p;
runner.run(TargetTest2);
"---".p;
runner.run(TargetTest);
|
Hello, world!その2
(Nested
Flatten)
xtal 0.9.7 から識別子に日本語が使えるようになったのでそれで。 なでしこのが参考になりました。
1 2 3 4 5 6 7 | へ: "He";
ろ: "l";
お: "o";
わ: "w";
る: "r";
ど: "d!";
(へ ~ ろ ~ ろ ~ お ~ ", " ~ わ ~ お ~ る ~ ろ ~ ど).p;
|
全ての組み合わせ
(Nested
Flatten)
fiber でジェネレータにしました。 「(...)」 というのは可変長引数をあらわすオブジェクトです。でも、コレ使うのなんかクラッシュする。。。 あと、配列の分配がきれいにかけないです。
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 | CrossProduct: class {
- _list: [];
initialize: method(...) {
(...).each_ordered_arg {
// ここのコメントを削除するとなぜかクラッシュする^^
if (it is String) {
_list.push_back(it.split("").to_a);
} else {
_list.push_back(it);
}
}
}
all: method fiber {
(fun (acc, rest) {
if (rest.empty()) {
yield acc;
} else {
x, xs: rest[0], rest.slice(1, rest.length);
x {
callee(acc ~ [it], xs);
}
}
})([], _list);
}
}
c: CrossProduct([0, 1], "ab", ["Foo", "Bar"]);
c.all {
it.p;
}
|
与えた条件を満たす候補
(Nested
Flatten)
not を何回も書けるようにしました。 and とか or みたいに1行メソッドがシンプルに書けるのがいいですね。 あと、xtal は callee があるので無名関数で再帰できるのもいいところ。
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 | // xtal 0.9.7.1 の inject はバグっているので自作。
Iterator::reduce: method(init, fn){
result: init;
this {
result = fn(result, it);
}
return result;
}
Solver: class {
- _expr;
initialize: method(_expr) {}
and: |a,b| a && b;
or: |a,b| a || b;
apply_not: method(values) {
r: values.clone();
i: 0;
_expr.each {
if (it == "not") {
r[i] = ! r[i];
} else {
i++;
}
}
return r[0], r.slice(1, r.length);
}
eval: method(values) {
first, rest: apply_not(values);
expr: _expr.select(|e| e != "not");
return expr.zip(rest.each).reduce(first, fun(r, pair) {
// this.("and") で and メソッドが取得できる
return this.(pair[0])(r, pair[1]);
});
}
}
prodloop: method(n) fiber {
(fun(n, xs) {
if (n == 0) {
yield xs;
} else {
[true, false] {
callee(n - 1, xs ~ [it]);
}
}
})(n, []);
}
solver: Solver(["and", "or", "not", "not", "not", "and"]);
prodloop(4).select(|v| solver.eval(v) ) {
it.p;
}
|
倍数になる13進数
(Nested
Flatten)
無駄に無限リストにしてみました。 遅くて3個目が見つからない。。。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | // xtal 0.9.7.1 の inject はバグっているので自作。
Iterator::reduce: method(init, fn){
result: init;
this {
result = fn(result, it);
}
return result;
}
Int::to_i13: method {
return this.to_s.split("").reduce(0, |r,e| r * 13 + e.to_i);
}
resolver: fiber {
for (i: 10; true; i++) {
if (i.to_i13 % i == 0) {
yield i;
}
}
}
resolver.take(1).to_a[0].p;
|
RFC 4180対応版 CSVレコードの分解
(Nested
Flatten)
汚いなぁ。。。 fiber 便利。
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 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | Iterator::with_peek: method fiber {
prev, curr: null, null;
noloop: true;
this {|next|
if (curr) {
yield prev, curr, next;
}
prev, curr = curr, next;
noloop = false;
}
if (!noloop) {
yield prev, curr, null;
}
}
CSVParser: class {
- _iter;
- _finish;
initialize: method(string) {
_iter = string.split("").each.with_peek;
_finish = false;
}
flush: method(field) {
r: field.join("");
field.clear();
return r;
}
line_parser: method fiber {
in_quote: false;
field: [];
_iter {|prev,it,next|
if (in_quote) {
if (it == "\"") {
if (prev == "\"") {
// ignore
} else if (next == "\"") {
field.push_back(it);
} else {
in_quote = false;
}
} else {
field.push_back(it);
}
} else {
if (field.empty() && it == "\"") {
in_quote = true;
} else if (it == "\n") {
yield flush(field);
break;
} else if (it == ",") {
yield flush(field);
} else {
field.push_back(it);
}
}
} nobreak {
_finish = true;
}
if (!field.empty()) {
yield flush(field);
}
}
parse: method fiber {
while (!_finish) {
yield line_parser();
}
}
}
parser: CSVParser(
[%!"aaa","b\nbb","ccc",zzz,"y""Y""y",xxx!,
%!a,b,c,d!,
%!a,b,c,!,
%!a!,
%!!,
].join("\n"));
format: %f[%(line)d:%(col)d: %(cell)s];
parser.parse.with_index {|lineno,line|
line.with_index {|colno,it|
format(line: lineno, col: colno, cell: it).p;
}
}
|
リストを逆順に表示
(Nested
Flatten)
1 2 3 4 5 6 7 8 9 | Iterator::reverse: method fiber {
arr: this.to_a;
while (!arr.empty()) {
yield arr[arr.size - 1];
arr.pop_back();
}
}
[1, 2, 3, 4, 5].each.reverse.to_a.p;
|
/*コメント*/を取り除く
(Nested
Flatten)
next >>
ひたすら一文字づつ見てパースしました。正規表現ほしぃ。。。
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 | Iterator::with_peek: method fiber {
prev, curr: null, null;
noloop: true;
this {|next|
if (curr) {
yield prev, curr, next;
}
prev, curr = curr, next;
noloop = false;
}
if (!noloop) {
yield prev, curr, null;
}
}
remover: fun(str) fiber {
in_comment: false;
str.split("").each.with_peek {|prev,it,next|
if (in_comment) {
if (prev == "*" && it == "/") {
in_comment = false;
}
} else {
if (it == "/" && next == "*") {
in_comment = true;
} else {
yield it;
}
}
}
}
remove_comment: fun(str) {
return remover(str).to_a.join("");
}
assert remove_comment("AAA") == "AAA";
assert remove_comment("AAA/*BBB*/") == "AAA";
assert remove_comment("AAA/*BBB") == "AAA";
assert remove_comment("AAA/*BBB*/CCC") == "AAACCC";
assert remove_comment("AAA/*BBB/*CCC*/DDD*/EEE") == "AAADDD*/EEE";
assert remove_comment("AAA/a//*BB*B**/CCC") == "AAA/a/CCC";
|






shimakuma
#4675()
[
xtal
]
Rating2/2=1.00
doukaku100: fun(n){ primes: fiber(){ yield 2; for(n: 3;; n += 2) for(d, m : 3, math::sqrt(n); d < m; d += 2) if(n % d == 0) break; nobreak yield n; } r: 1; n.to_s.split("").zip(primes){|d, p| r *= math::pow(p, d.to_i); } return r; }Rating2/2=1.00-0+
[ reply ]