LoginSignup
20
8

More than 5 years have passed since last update.

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

Last updated at Posted at 2018-03-29

概要

「ポ」「プ」「テ」「ピピック」をランダムに出力して「ポプテピピック」が完成したら竹●房を破壊するJavaScript
をC# + WPF + Reactive Extensions で書いてみました。

C#でもすでに先達がおられる
https://qiita.com/ruhiel/items/c98451e4700344654f25

今回コンソールじゃなくてWPFにしたのはAAをきれいに表示するため。WinFormsでも同じようにできます。

コード

AAは改行が含まれていてい直接コードに書きづらいので、ResourceにTakeで登録しておきます。
NugetでReactive Extensions(System.Reactive)を導入します。

WindowのXamlではAAが正しく表示されるようTextboxのフォントを「MS PGothic」に設定しています。

MainWindow.xaml
<Window
    x:Class="PopTeamEpicWpf.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="「ポ」「プ」「テ」「ピピック」をランダムに出力して「ポプテピピック」が完成したら竹●房を破壊するC#"
    Width="900"
    Height="600">
    <ScrollViewer>
        <TextBox
            x:Name="textBox"
            FontFamily="MS PGothic"
            FontSize="16"
            IsReadOnly="True"
            TextWrapping="Wrap" />
    </ScrollViewer>
</Window>

コードビハインドでは主に以下の2つを行っています。

  • ランダムに「ポ」「プ」「テ」「ピピック」が流れてきて、「ポプテピピック」に一致したらCompleteするIObservableの生成
  • それを購読してOnNextではそのまま、CompleteではAAをTextboxへ出力

注意点は一致判定のためにBufferでまとめている部分で、あえてBufferの長さを余分にしていることです。
これは一致した時の最後のOnNext「ピピック」を流すためです。

MainWindow.xaml.cs
public partial class MainWindow : Window
{
    static string[] pops = new[] { "ポ", "プ", "テ", "ピピック" };

    public MainWindow()
    {
        InitializeComponent();

        CreateRandomPops()
            //Textboxにアクセスするので、UIスレッド上で購読
            .ObserveOn(this.Dispatcher)
            .Subscribe(
                //OnNextは流れてきた文字をそのままTextboxに書き足す
                x => this.textBox.Text += x,
                //CompleteしたらリソースからAAを取得してTextboxに書き足す
                () => textBox.Text += Properties.Resources.Take);
    }

    /// <summary>
    /// ランダムに「ポ」「プ」「テ」「ピピック」がOnNextに流れてきて、「ポプテピピック」に一致したらCompleteするIObservable
    /// </summary>
    private static IObservable<string> CreateRandomPops()
    {
        int maxCount = pops.Count();
        var random = new Random();
        IObservable<string> randomPop = Observable
            //10msecごとに
            .Interval(TimeSpan.FromMilliseconds(10))
            //ランダムに「ポ」「プ」「テ」「ピピック」のどれか
            .Select(_ => pops[random.Next(maxCount)]);
        //※テスト用 最初がいきなり「ポプテピピック」になる
        //.Select(i => pops[i % maxCount]);

        //バッファを空白で埋めておく (["","","","",""])
        return Observable.Repeat("", maxCount)
            .Concat(randomPop)
            //最後の「ピピック」をOnNextに流すために1つ余分にBufferをもつ
            .Buffer(maxCount + 1, 1)
            //Bufferの前が「ポプテピピック」に一致する状態(["ポ","プ","テ","ピピック",*])になるまで続行 
            .TakeWhile(x => !x.Take(maxCount).SequenceEqual(pops))
            //Bufferの最後をOnNextに流す  ([*,*,*,*,○] の ○)
            .Select(x => x.Last());
    }
}

実行結果例

スクリーンショット 2018-03-30 01.00.14.png

参考

Reactive Extensions再入門
https://qiita.com/amay077/items/85dfc4bd194f57c52c57#_reference-557477ce374f1a552c5c

環境

System.Reactive 3.1.1
VisualStudio2017
.NET Framework 4.7
C#7.1

20
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
8