感想一覧
▽感想を書く感想絞り込み
[一言]
もっと短くなった。
using System;
using System.Linq;
using System.Collections.Generic;
namespace ConsoleApp1
{
class Program
{
const int Skipped = -1;
static int CalcScore2(int[][] frames) =>
Enumerable.Range(0, frames.Length)
.Select(x => frames.Skip(x).SelectMany(x => x).Where(x => x != Skipped).Take(3).ToList())
.Sum(x => x switch
{
var y when y[0] == 10 || y[0] + y[1] == 10 => y.Sum(),
var y => y[0] + y[1]
});
static void Main(string[] args)
{
var scores = new int[][]
{
new int[] {10, Skipped },
new int[] {10 },
new int[] {10, Skipped },
new int[] {10 },
new int[] {10 },
new int[] {10 },
new int[] {10 },
new int[] {10 },
new int[] {10,Skipped },
new int[] {10, 10, 10 },
};
Console.WriteLine(CalcScore2(scores));
}
}
}
もっと短くなった。
using System;
using System.Linq;
using System.Collections.Generic;
namespace ConsoleApp1
{
class Program
{
const int Skipped = -1;
static int CalcScore2(int[][] frames) =>
Enumerable.Range(0, frames.Length)
.Select(x => frames.Skip(x).SelectMany(x => x).Where(x => x != Skipped).Take(3).ToList())
.Sum(x => x switch
{
var y when y[0] == 10 || y[0] + y[1] == 10 => y.Sum(),
var y => y[0] + y[1]
});
static void Main(string[] args)
{
var scores = new int[][]
{
new int[] {10, Skipped },
new int[] {10 },
new int[] {10, Skipped },
new int[] {10 },
new int[] {10 },
new int[] {10 },
new int[] {10 },
new int[] {10 },
new int[] {10,Skipped },
new int[] {10, 10, 10 },
};
Console.WriteLine(CalcScore2(scores));
}
}
}
エピソード1
[一言]
で。10フレの話を理解したうえで、効率無視して作成した、多少モダンぽい? c#コード。短さ優先。正しいかどうかは不明。
using System;
using System.Linq;
namespace ConsoleApp1
{
class Program
{
const int Skipped = -1;
static IQueryable<int> ToRaw(IQueryable<int[]> src, int skip) => src.SelectMany(x => x).Where(x => x != Skipped).Skip(skip);
static int CalcScore(IQueryable<int[]> frames) => frames.FirstOrDefault() switch {
null => 0,
var x when x[0] == 10 => 10 + ToRaw(frames, 1).Take(2).Sum() + CalcScore(frames.Skip(1)),
var x when x[0] + x[1] == 10 => 10 + ToRaw(frames, 2).First() + CalcScore(frames.Skip(1)),
var x => x[0] + x[1] + CalcScore(frames.Skip(1))
};
static void Main(string[] args)
{
var scores = new int[][]
{
new int[] {10, Skipped },
new int[] {10 },
new int[] {10, Skipped },
new int[] {10 },
new int[] {10 },
new int[] {10 },
new int[] {10 },
new int[] {10 },
new int[] {5,5 },
new int[] {10, 10, 10 },
};
Console.WriteLine(CalcScore(scores.AsQueryable()));
}
}
}
で。10フレの話を理解したうえで、効率無視して作成した、多少モダンぽい? c#コード。短さ優先。正しいかどうかは不明。
using System;
using System.Linq;
namespace ConsoleApp1
{
class Program
{
const int Skipped = -1;
static IQueryable<int> ToRaw(IQueryable<int[]> src, int skip) => src.SelectMany(x => x).Where(x => x != Skipped).Skip(skip);
static int CalcScore(IQueryable<int[]> frames) => frames.FirstOrDefault() switch {
null => 0,
var x when x[0] == 10 => 10 + ToRaw(frames, 1).Take(2).Sum() + CalcScore(frames.Skip(1)),
var x when x[0] + x[1] == 10 => 10 + ToRaw(frames, 2).First() + CalcScore(frames.Skip(1)),
var x => x[0] + x[1] + CalcScore(frames.Skip(1))
};
static void Main(string[] args)
{
var scores = new int[][]
{
new int[] {10, Skipped },
new int[] {10 },
new int[] {10, Skipped },
new int[] {10 },
new int[] {10 },
new int[] {10 },
new int[] {10 },
new int[] {10 },
new int[] {5,5 },
new int[] {10, 10, 10 },
};
Console.WriteLine(CalcScore(scores.AsQueryable()));
}
}
}
エピソード1
[一言]
おお。10フレのシステムというのは、ストライクやスペアの場合の先読みを、そのフレーム内で表記するため、と理解できるのか… もともとがそういう思想での構築だったのかもしれないけれど、一般には「10フレは特別、2投までに全部倒したら、もう一投おまけで投げられる。10フレはストライクやスペアの特殊処理をしないで、フレーム全体のピン数を加算する」と理解されていると思うし、自分もそうだったのでこのアルゴリズムが理解できていなかったのでした。
その意味での計算はあくまでフレーム単位で行う必要があるので、フレームとしてのデータ構造と無投を除いたシーケンスとしてのポイント構造を同時に扱う必要は出てくるのだな。たおしたピン数だけの一次元リストだと、末端の処理がやはりうまく行かないか。
10フレの秘密に気が付けたというのが大きな収穫でした/w
しかし、さすがにこれは、誰得話になっちゃうなあ…
おお。10フレのシステムというのは、ストライクやスペアの場合の先読みを、そのフレーム内で表記するため、と理解できるのか… もともとがそういう思想での構築だったのかもしれないけれど、一般には「10フレは特別、2投までに全部倒したら、もう一投おまけで投げられる。10フレはストライクやスペアの特殊処理をしないで、フレーム全体のピン数を加算する」と理解されていると思うし、自分もそうだったのでこのアルゴリズムが理解できていなかったのでした。
その意味での計算はあくまでフレーム単位で行う必要があるので、フレームとしてのデータ構造と無投を除いたシーケンスとしてのポイント構造を同時に扱う必要は出てくるのだな。たおしたピン数だけの一次元リストだと、末端の処理がやはりうまく行かないか。
10フレの秘密に気が付けたというのが大きな収穫でした/w
しかし、さすがにこれは、誰得話になっちゃうなあ…
エピソード3
[一言]
なるほど?
10フレの考え方というか、取り扱いが全く違うんだ。
ちょっと考えてみます。
なるほど?
10フレの考え方というか、取り扱いが全く違うんだ。
ちょっと考えてみます。
エピソード3
[一言]
あ、これ、インデント用の全角スペースをそのままWhite Spaceと解釈してコンパイルできるということ、です。
変数名のUnicode対応とかは、その流れ、ですね。MSのはそういった点しっかりしていると思う。
Scalaのプログラム、ideoneで実行してみようとしたけれど、あれはインタプリタでないからとりあえずダメだったみたいだけれど、まあともかくそのままコピペしたら全角スペースがエラーとなってしまったようです。
あ、これ、インデント用の全角スペースをそのままWhite Spaceと解釈してコンパイルできるということ、です。
変数名のUnicode対応とかは、その流れ、ですね。MSのはそういった点しっかりしていると思う。
Scalaのプログラム、ideoneで実行してみようとしたけれど、あれはインタプリタでないからとりあえずダメだったみたいだけれど、まあともかくそのままコピペしたら全角スペースがエラーとなってしまったようです。
エピソード1
[一言]
あとね。c#の凄いとこ。
このコード、そのままエラーなしでコンパイル・実行できるのだ。他の言語って、大抵だめだと思う。
勿論、漢字関数名・変数名・クラス名も何ら問題無し。
SQL Serverで(Oracleはうまくない)テーブル名・カラム名をみんな漢字にしてEntityFrameworkでマッピング作成すると、物理名の対応表なしできっちりプログラミングできる/w
あとね。c#の凄いとこ。
このコード、そのままエラーなしでコンパイル・実行できるのだ。他の言語って、大抵だめだと思う。
勿論、漢字関数名・変数名・クラス名も何ら問題無し。
SQL Serverで(Oracleはうまくない)テーブル名・カラム名をみんな漢字にしてEntityFrameworkでマッピング作成すると、物理名の対応表なしできっちりプログラミングできる/w
エピソード1
もともと、Linqは関数型プログラミング言語由来の機能ではあるので、Scala/Haskell/OCamlとかの関数型プログラミング言語方面だと割と似たようなコードがそのまま実行できる気がします。
ユニコード対応(つまり、漢字の識別子が使える)も最近の多くの言語では対応してたりしますね(JavaもScalaもKotlinも、.NET系のほかの言語でも、RubyもPythonも対応してるので、今はあんまり珍しくないです)
RDBMSでどのくらい漢字のテーブル名やカラム名が対応してるのかはわからないですが、MySQLとかは一応できるぽいですね(ただ、文字コード絡みで問題起こりやすいので、あんまり使われることはないですが)
ユニコード対応(つまり、漢字の識別子が使える)も最近の多くの言語では対応してたりしますね(JavaもScalaもKotlinも、.NET系のほかの言語でも、RubyもPythonも対応してるので、今はあんまり珍しくないです)
RDBMSでどのくらい漢字のテーブル名やカラム名が対応してるのかはわからないですが、MySQLとかは一応できるぽいですね(ただ、文字コード絡みで問題起こりやすいので、あんまり使われることはないですが)
- 久野真一
- 2021年 07月14日 17時01分
[一言]
あれ、9フレストライクで、10フレが3/5で3投目Skippedにすると、ストライクパターンにマッチしなくない?
あれ、9フレストライクで、10フレが3/5で3投目Skippedにすると、ストライクパターンにマッチしなくない?
エピソード3
最初のLazyList作るフェーズで、
10 : 3 : 5 : null
みたいな感じに前処理で変換されているので、10の次に3と5が来るとちゃんと3と5がストライクパターンとしてマッチして加算される(はず)です。
10 : 3 : 5 : null
みたいな感じに前処理で変換されているので、10の次に3と5が来るとちゃんと3と5がストライクパターンとしてマッチして加算される(はず)です。
- 久野真一
- 2021年 07月14日 16時50分
[一言]
うーん。やっぱり基本的に判りやすいか、というとどうなんだろう、と思っちゃう。
・LazyListであるか、というのは必ずしも本質ではないと思われ。デバッグの段階を考えると、加工済みリストを一度作った方がやりやすいと思う。
・LazyList化は明示的にしないといけないようだけれど、Linqなら暗黙のうちに遅延評価されるので、偉いのだ/w
・結局、10フレの特別扱いは必要。それが_によってなされている、ということはさすがにコメントなしですぐに理解するのは困難
・10フレの1/2投目が最終パターンにマッチするのは理解できるけれど、3投目がどのパターンにマッチするのかは、理解できない。10フレが5/5/5の場合にどうなるのだろう
入力データ形式が他と異なっているので、そのまま比較するのも適当ではないと思う。
きちんと作るなら、Frameクラスも作成して、Strike/Spareの判定もそのプロパティとしてカプセル化するとかしたい。
うーん。やっぱり基本的に判りやすいか、というとどうなんだろう、と思っちゃう。
・LazyListであるか、というのは必ずしも本質ではないと思われ。デバッグの段階を考えると、加工済みリストを一度作った方がやりやすいと思う。
・LazyList化は明示的にしないといけないようだけれど、Linqなら暗黙のうちに遅延評価されるので、偉いのだ/w
・結局、10フレの特別扱いは必要。それが_によってなされている、ということはさすがにコメントなしですぐに理解するのは困難
・10フレの1/2投目が最終パターンにマッチするのは理解できるけれど、3投目がどのパターンにマッチするのかは、理解できない。10フレが5/5/5の場合にどうなるのだろう
入力データ形式が他と異なっているので、そのまま比較するのも適当ではないと思う。
きちんと作るなら、Frameクラスも作成して、Strike/Spareの判定もそのプロパティとしてカプセル化するとかしたい。
エピソード3
さらに補足すると、パターンマッチのロジックでは、10フレーム目の「特別扱い」はしてないんですね。10フレームで終わったから、結果的に特別扱いしてるように見えるだけで。無限フレームボウリングをモデリングした結果として、10フレームで終わる通常のボウリングもその中で取り扱えるという感じです。
- 久野真一
- 2021年 07月14日 16時53分
一般的にわかりやすいかというと議論があると思います。Scala版(というか、遅延リスト使える言語ならどれでも簡単かと思いますが)の特徴は、ボウリングのルールを
・スペアは、「次の一投(あれば)」をボーナスとして加算する
・ストライクのは、「次の二投(あれば)」をボーナスとして加算する
・何フレーム投げるかは事前には決めないでいい
と抽象化して、「10フレームで打ち切った」のが通常のボウリングと考えればそのまま動くことですね。Skippedを入れたのは「投球してない」ということをデータで表現してあるのでした。
あんまり意味がないことですが、15投目までがあるボウリングも抽象化されている(ので、10フレームで打ち切ってもうまく動く)ので面白いところでしょうか。
LazyListが本質かどうかといわれると必ずしも本質でないのですが、LazyListであれば再帰をストップさせなくても、使う側でtake(10)すればいいというのがメリットですね(実用上はLazyListがそこまで使い物になるかは微妙ですが)。
10フレーム目の3投目(で5/5/5、つまりスペアということですよね)がどのパターンにマッチするかというと、2パターン目のスペアのパターンにマッチします。
・スペアは、「次の一投(あれば)」をボーナスとして加算する
・ストライクのは、「次の二投(あれば)」をボーナスとして加算する
・何フレーム投げるかは事前には決めないでいい
と抽象化して、「10フレームで打ち切った」のが通常のボウリングと考えればそのまま動くことですね。Skippedを入れたのは「投球してない」ということをデータで表現してあるのでした。
あんまり意味がないことですが、15投目までがあるボウリングも抽象化されている(ので、10フレームで打ち切ってもうまく動く)ので面白いところでしょうか。
LazyListが本質かどうかといわれると必ずしも本質でないのですが、LazyListであれば再帰をストップさせなくても、使う側でtake(10)すればいいというのがメリットですね(実用上はLazyListがそこまで使い物になるかは微妙ですが)。
10フレーム目の3投目(で5/5/5、つまりスペアということですよね)がどのパターンにマッチするかというと、2パターン目のスペアのパターンにマッチします。
- 久野真一
- 2021年 07月14日 16時49分
[一言]
c#のサンプル。ストライクの場合のリスト末尾省略可なパターン。
明確なフレーム数の規定がある(リストが不定長でない)し、フレーム番号に依存する特殊処理がある、ということからリストを加工するよりは普通にインデクサでアクセスするほうが筋な気がするので。
ちょっとなんだけれど、配列にFirst/Sum/Takeが使えるのがミソかな。StrikeでTake(2)を漏らすと、誤りになる。
using System;
using System.Linq;
namespace ConsoleApp1
{
class Program
{
static int CalcScore(int[][] scores)
{
var total = 0;
// 1..9 frames
for (var i = 0; i < 9; i++)
{
total += scores[i].Sum();
if (scores[i].First() == 10)
{
// strike
total += scores[i + 1].Take(2).Sum();
if (i < 8 && scores[i + 1].First() == 10)
{
// double or more
total += scores[i + 2].First();
}
}
else if (scores[i].Sum() == 10)
{
// spare
total += scores[i + 1].First();
}
}
// 10 frame
return total + scores[9].Sum();
}
static void Main(string[] args)
{
var scores = new int[][]
{
new int[] {10 },
new int[] {10 },
new int[] {10 },
new int[] {10 },
new int[] {10 },
new int[] {10 },
new int[] {10 },
new int[] {10 },
new int[] {10 },
new int[] {10, 10, 10 },
};
Console.WriteLine(CalcScore(scores));
}
}
}
c#のサンプル。ストライクの場合のリスト末尾省略可なパターン。
明確なフレーム数の規定がある(リストが不定長でない)し、フレーム番号に依存する特殊処理がある、ということからリストを加工するよりは普通にインデクサでアクセスするほうが筋な気がするので。
ちょっとなんだけれど、配列にFirst/Sum/Takeが使えるのがミソかな。StrikeでTake(2)を漏らすと、誤りになる。
using System;
using System.Linq;
namespace ConsoleApp1
{
class Program
{
static int CalcScore(int[][] scores)
{
var total = 0;
// 1..9 frames
for (var i = 0; i < 9; i++)
{
total += scores[i].Sum();
if (scores[i].First() == 10)
{
// strike
total += scores[i + 1].Take(2).Sum();
if (i < 8 && scores[i + 1].First() == 10)
{
// double or more
total += scores[i + 2].First();
}
}
else if (scores[i].Sum() == 10)
{
// spare
total += scores[i + 1].First();
}
}
// 10 frame
return total + scores[9].Sum();
}
static void Main(string[] args)
{
var scores = new int[][]
{
new int[] {10 },
new int[] {10 },
new int[] {10 },
new int[] {10 },
new int[] {10 },
new int[] {10 },
new int[] {10 },
new int[] {10 },
new int[] {10 },
new int[] {10, 10, 10 },
};
Console.WriteLine(CalcScore(scores));
}
}
}
エピソード1
おお。C#版。ありがとうございます。ちなみに、Scala版で9フレーム目と10フレーム目に特殊な処理がないのは、ボウリングでは、「第10フレームに特殊な処理がある」と考えなくても、単純にストライクは「(あれば)次の2投の点数を加算する」、スペアは「(あれば)次の1投の点数を加算する」と考えられるからですね。
それが遅延リストとパターンマッチで表現されている感じです。
それが遅延リストとパターンマッチで表現されている感じです。
- 久野真一
- 2021年 07月14日 11時36分
[一言]
ああ、流石にこれは理解の範囲外。
パターンマッチング使ってるのかな。
たしかc#にもパターンマッチ導入されたのだけれど、理解してない。
ああ、流石にこれは理解の範囲外。
パターンマッチング使ってるのかな。
たしかc#にもパターンマッチ導入されたのだけれど、理解してない。
エピソード3
おっしゃる通り、パターンマッチング使ってます。こうするとある種の処理が簡潔にかけるのがいいところでしょうか。
Rubyしかり、C#しかり、Java(予定)しかりとパターンマッチングはメインストリームの言語にドンドン入って来てますね。
Rubyしかり、C#しかり、Java(予定)しかりとパターンマッチングはメインストリームの言語にドンドン入って来てますね。
- 久野真一
- 2021年 07月14日 03時04分
感想を書く場合はログインしてください。