概要
「ポ」「プ」「テ」「ピピック」をランダムに出力して「ポプテピピック」が完成したら竹●房を破壊する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」に設定しています。
<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「ピピック」を流すためです。
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());
}
}
実行結果例
参考
Reactive Extensions再入門
https://qiita.com/amay077/items/85dfc4bd194f57c52c57#_reference-557477ce374f1a552c5c
環境
System.Reactive 3.1.1
VisualStudio2017
.NET Framework 4.7
C#7.1