C#
ポプテピピック

「ポ」「プ」「テ」「ピピック」をランダムに出力して「ポプテピピック」が完成したら竹●房を破壊するC#をワンライナーにしたかった

元ネタ

「ポ」「プ」「テ」「ピピック」をランダムに出力して「ポプテピピック」が完成したら竹●房を破壊するJavaScript

先行研究(C#)

ランダム出力でポプテピピック
https://qiita.com/ruhiel/items/c98451e4700344654f25

「ポ」「プ」「テ」「ピピック」をランダムに出力して「ポプテピピック」が完成したら竹●房を破壊するC#
https://qiita.com/soi/items/05b1924f7c5d3edac716

本稿の趣旨

上記両記事が面白そうだったのでやってみた。
これらと同じではつまらないと思いワンライナーを目指したがすぐに挫折した。

コード

using System;
using System.Linq;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        var strings = args.Append(new[] { "ポ", "プ", "テ", "ピピック" }[new Random(args.GetHashCode() + new Random().Next()).Next(4)]);
        if (strings.Skip(strings.Count() - 4).SequenceEqual(new[] { "ポ", "プ", "テ", "ピピック" }) || Main(strings.ToArray()).IsCanceled)
            strings.Append("\r\n                         ------- 、 rへ------、 \r\n                   ___、+''\"~八 ~''< つ   \ \r\n _、+''\"~  ./ ,:    ^   丶     ヽく__ ∧ \r\n       , -r-     /       / / -、    '´ ̄!\‘, ‘:,  |    \/ \r\n     / .∧   \..゙|/_,,.。*'/ /|,/\__/^ヽ /,,_ `!   ', | \r\n    /   ∧    \ 〈〉. , .| y''\"ヽ______ 7´⌒ヽ _ | ト;′ \r\n 〈      ∧ (竹) .∨... || ,r ヽ 三三 /‘:, Y! .|,′ \r\n∨       ∧    ∨... |.| 八 °,!三三{. ° ノ 八/ ---、 \r\n. ∨       ∧    ∨....∨(.^    、_,、_, `   ,.ィ ^ !./_  ', \r\n     ∨   /三ミメ、  ∨ 冫≧=‐------‐ァ=≦/ .|/   }   ! \r\n.      ∨三三三三圦__.\\/ \|イ `''<:\/:::::/  |  (___) \r\n    〈〉   ノ ゞ三シ. \ \;   { /    `¨ヘ⌒こフ .∨ 〔、、、_) \r\n       )          \八  `^i、_ __    \\   .∨ `¨´ \r\n     <ヘ_/三\_/|\、.\ /::/  )     `'´ _ ,∨、 \r\n |\三三三三:/  |.\/^ ゞク≦---‐=≦::::::「:::::::::|::::/ \r\n /:::::::/:::::::/:::::::::;′:::::::::|::::::::::|:人\r\nhappy end!!").ToList().ForEach(p => Console.Write(p));
    }
}

解説

何とか実質3行までは来た。

static async Task Main(string[] args)

戻り値がTaskであることは後述。
緑の波線は愛嬌。1

var strings = args.Append(new[] { "ポ", "プ", "テ", "ピピック" }[new Random(args.GetHashCode() + new Random().Next()).Next(4)]);

「ポ」「プ」「テ」「ピピック」からランダムでひとつをコマンドライン引数に加えたものを取得する。
new Random().Next(4) だと、シードの更新(ミリ秒)よりループが早く乱数がばらけないため、StackOverflowExceptionが投げられる可能性が非常に高いが、 static Random Random = new Random(); なフィールドを持つと1行損してしまう。
毎回変わるのがargsくらいしかなかったので、argsのハッシュコードに乱数を加えたものをシードにしてみた。(適当)
それなりに乱数してると思う。

if (strings.Skip(strings.Count() - 4).SequenceEqual(new[] { "ポ", "プ", "テ", "ピピック" }) || Main(strings.ToArray()).IsCanceled)

これまでの結果の後ろ4要素が「ポ」「プ」「テ」「ピピック」の場合は分岐に入り、そうでなければ再帰する。
この条件式の中でMainを呼ぶためにその戻り値をTaskとした。
Task.IsCanceledプロパティについては後述。
戻り値intでもできるが最後にreturnが必要になってしまう。

strings.Append("\r\n・・・\r\nhappy end!!").ToList().ForEach(p => Console.Write(p));

これまでの結果の最後に"\r\n・・・\r\nhappy end!!"を加えてから全件出力する。
当然、"\r\n・・・\r\nhappy end!!"はAAである。
ここは最後の一回だけ通したいため、条件式の Main(strings.ToArray()).IsCanceled の部分は常にfalseが返らなければならない。
逆に言えば常にfalseを返してくれさえすればIsCanceledプロパティでなくても何でもいい。

なお、AAを省略せずに連発して、竹書房「AAが長すぎてこぶが引っ込んじゃった!」というネタはあまりの読みにくさに不採用となった。

結語

私のようなへっぽこにはこれが限界だった。
凄腕プログラマの完成版に期待したい。

ちなみにAAは盛大にズレている。


  1. VisualStudio 2017の場合