Twitterで以下のツイートがバズっていました。
見た瞬間に思いついたC++のコードを書き殴ったので記録しておきます。【問題】配列{"ドド","スコ"}からランダムに要素を標準出力し続け、『その並びが「ドドスコスコスコ」を3回繰り返したもの』に一致したときに「ラブ注入♡」と標準出力して終了するプログラムを作成せよ(配点:5点)
— ((🐑++)) (@Sheeeeepla) August 1, 2022
コード
#include <iostream>
#include <random>
#include <string>
const std::string kmessage[] = {"ドド", "スコ"};
const std::string klove_message = "ラブ注入♡ ";
const int ktarget = 0b111011101110;
int main()
{
std::random_device seed_gen;
std::mt19937 engine(seed_gen());
int consume = ktarget;
while (consume) {
int rand = engine() % 2;
std::cout << kmessage[rand];
consume = (consume % 2 == rand) ? consume / 2 : ktarget / (!rand + 1);
}
std::cout << klove_message << '\n';
return 0;
}
解説
1.乱数生成器で0か1を生成
2.期待している数値であれば進める 期待した数値でなければリセット
3.klove_messageを出力して終了
乱数はメルセンヌツイスタを使用して生成します。詳しくはこちらをご覧ください。
"ドド"を0に、"スコ"を1に対応させると011101110111が期待する数列です。判定のためにこの数列から一桁ずつ取り出したいので順番を逆にした111011101110を変数tkargetに格納しています。consumeはktargetで初期化した値です。これにより、変数consumeを2で割ったあまりと、生成された乱数を比較すれば、生成された乱数が期待している値なのかを判定できます。期待している値であればconsumeを2で割り、右シフトします。期待している値でなければconsumeをktargetでリセットします。(追記)ここで"スコ"が期待されている時に"ドド"で間違えた場合、"ドドスコスコスコ〜"ではなく"スコスコス〜"を期待すれば良いことになります。そのため、"スコ"を期待している時に"ドド"で間違えた場合は、consumeを ktarget/2 つまり、111011101110ではなく11101110111で初期化します(@fujitanozomu さんにご指摘いただきました。ありがとうございました))
具体例
1.乱数生成により0が生成される
2."ドド"を出力
3.111011101110を2で割ったあまり、つまり111011101110の1の位と生成された乱数を比較
4.期待している値であるため111011101110を2で割り11101110111を得る
5.乱数生成により1が生成される
6."スコ"を出力
7.11101110111を2で割ったあまり、つまり11101110111の1の位と生成された乱数を比較
8.期待している値であるため11101110111を2で割り1110111011を得る
9.乱数生成により0が生成される
6."ドド"を出力
7.1110111011を2で割ったあまり、つまり1110111011の1の位と生成された乱数を比較
8.期待している値ではないため"ドド"の次の"スコ"からやり直し
これを乱数が011101110111の順で生成されるまで、つまり"ドドスコスコスコドドスコスコスコドドスコスコスコ"が出力されるまで繰り返し、最後に"ラブ注入♡"を出力する。
最後に
元ツイートを見るとめちゃくちゃ短いコードで実現されている方もいるみたいなので真似したいです。
もっといいアルゴリズムあるよ!という方はぜひコメントで教えてください。