Wordleの結果をLEDで表示しようとしたらめんどくさかった

Twitterでよく見かけるWordle、ニューヨークタイムズが買収したと報道されてましたね。

www.powerlanguage.co.uk

こんな感じのツイートを見かけるたびにGithubのコントリビューショングラフみたいだなぁと思ってたんですが、眺めてるうちに手元にあったseeedのマトリクスLEDに見えてきたので光らせたくなってきました。
何番煎じなのかわかんないですけど、やってみます。

www.seeedstudio.com

仕組み

Wordleをプレイ後、SHAREのボタンをクリックすると結果がクリップボードにコピーされます。
通常はTwtterにペーストしてツイートするんですが、代わりに ESP32に渡してLEDを光らせましょう。

ESP32に渡すのはWebServer経由がスマートな気がします。テキストをそのままPOSTで渡せばあとはパースするだけで簡単そうですね!(フラグ)

面倒だった

ESPAsyncWebServerを利用してPOSTされたデータを取得してパースする、ただそれだけ。

  server.on("/poi", HTTP_ANY, [](AsyncWebServerRequest *request) {
    if (request->hasArg("text")) {
      std::string str(request->arg("text").c_str());
      Serial.printf("%s\r\n", str);
      // この文字列をパースする!
    }
  }

いよいよ処理を書こうとしたら手が止まりました。

考えてみたら当たり前なんですが渡ってくる文字列はマルチバイトでした。
製品カテゴリによるとは思いますが、ドライバ寄りのファームウェアを開発しているとマルチバイトを扱うことが少ないので圧倒的に経験値が足りない!

どうしようかとしばらく考えましたが、string::compare()を範囲指定でちまちま比較することでなんとかしました。
もっとスマートな方法あるんですかね・・?

// indexの位置に該当の文字があるか判定する関数
int find(const std::string& str, int* index) {
  const std::string chip[] = { "⬜", "⬛", "🟨", "🟩" };
  const int code[] = { 0xff, 0xff, 0x25, 0x55 };  // MatrixLEDのカラーコード
  for (auto i = 0; i < 4; ++i) {
    if (str.compare(*index, chip[i].length(), chip[i]) == 0) {
      *index += chip[i].length();
      return code[i];
    }
  }
  return -1;  // 該当なし
}
// stringを末尾まで走査してMatrixLEDのデータに変換する
bool find(const std::string& str, int line) {
  if (str.empty()) {
    return false;
  }
  int x = 0;
  for (auto i = 0; i < str.length(); ++x) {
    auto n = find(str, &i);
    if (n < 0) {
      return false;
    }
    score[5 * line + x] = n;
  }
  return true;
}

妙にめんどくさくて手こずったけど、どうにかできました。
C/C++めんどくさいぜ(でも好き❤️)

余白を隠せばもっといい感じになるかな?

f:id:hollyhockberry:20220202175336j:plain

ソースコードはこちら↓

github.com