【YouTube動画公開】ローカルレイド配布の自動化紹介動画を公開しました

ますたーです。こんにちは。

 

早いもので5月も最終日となりました。

さて、今回はYouTubeに2本目の動画投稿を行ったのでその報告です。

動画の内容は、前回の記事(Arduino自動化18:ローカルレイド配布)で取り扱ったマックスレイドバトルのローカル配布についてです。ブログと動画、是非とも見比べながらお楽しみいただければ幸いです。

前回記事:【Arduino自動化18】ローカルレイド自動配布【デリバードレイドでマックスこうせき】

 

Arduino Leonardo自動化の導入・機材構成については導入記事を参考にしてください。

導入記事:【Arduino自動化01】Arduino開発環境の導入

※本ブログに初めてお越しの方は「本ブログについて」もぜひ、ご覧ください。

 

【投稿したYouTube動画はコチラ】

【Arduino自動化】レイドバトルをArduinoで自動ローカル配布(デリバードレイド周回) - YouTube

 

 

慣れない動画編集作業に苦戦しながらも、自動化のデモ作業など、色々と検討しながら丁寧に作ってみました。

日中は業務繁忙で平日は(土日も)ほとんど時間が取れませんが、まだまだ私自身の気概としては、本ブログも動画投稿も続けていきたいと思っていますので、引き続き応援のほどよろしくお願いいたします!

 

また、お陰様で、一昨日の2021/5/29に本ブログのページ総閲覧数(累計PV数)が、20,000PVを突破しました。2021/5/31(月)AM2:47現在で総PV数20,137、今月PV数は3,223になります。いつも訪問いただきありがとうございます。本日でブログ開設から175日。引き続きがんばります。

 

このブログや投稿した動画が、皆様のお役に立てば幸いです。

ではではc⌒っ.ω.)っ

 

前記事:【YouTube動画公開】YouTubeチャンネル設営&紹介動画を初投稿【ポケモン剣盾Arduino自動化】

導入記事:【Arduino自動化01】Arduino開発環境の導入

Arduino自動化記事一覧は こちら

 

 

【YouTube動画公開】YouTubeチャンネル設営&紹介動画を初投稿【ポケモン剣盾Arduino自動化】

ますたーです。こんにちは。

 

本日5/6にYouTubeチャンネルを作成しましたので、その報告記事となります。

記念すべき第1弾の投稿動画は、本ブログで取り扱っているArduino Leonardoを活用した自動化デモ紹介です。人生でYouTube初投稿です。是非とも御覧ください!

※本ブログに初めてお越しの方は「本ブログについて」もぜひ、ご覧ください。

 

【投稿したYouTube動画はコチラ】

www.youtube.com

【Arduino自動化】ポケモン剣盾の面倒な作業をマイコンで自動化しよう(紹介動画) - YouTube

 

動画中では、下記3記事の内容をデモとして紹介しております。

 

・A連打(無限穴掘り兄弟)

 【Arduino自動化01】Arduino開発環境の導入


ポケモンキャンプでカレー自動調理

 【Arduino自動化09】ポケモンキャンプでカレー自動調理【カレーのあかし】


・雪中渓谷のワットショップの目玉商品
 【Arduino自動化02】雪中渓谷のワットショップの目玉商品を全自動回収【カンムリ雪原】

 

この動画投稿を機に、より多くの人がArduinoでの自動化に魅力を 感じていただければ幸いです。

ではではc⌒っ.ω.)っ

 

【Arduino自動化18】ローカルレイド自動配布【デリバードレイドでマックスこうせき】

ますたーです。こんにちは。

前回の更新から1ヶ月が経ち、5月になりました。業務繁忙で、文字通り「忙殺」される毎日でした。

 

さて、今回は、前々回の記事(第17回)のコメント欄でリクエストをいただいた、「レイドを自動でローカル配布するプログラム」を紹介します。

Arduino自動化記事も今回で第18回。これからもよろしくお願いいたします。

 

なお、Arduino Leonardo自動化の導入・機材構成については導入記事を参考にしてください。

導入記事:【Arduino自動化01】Arduino開発環境の導入

※本ブログに初めてお越しの方は「本ブログについて」もぜひ、ご覧ください。

 

概要

ローカル通信(YY通信)でのレイドバトル配布を自動で繰り返し行います。待機時間の変更・バトル時のA連打時間も変更可能です。

f:id:tangential_star:20210503200445g:plain

レイド募集→みんなで挑戦→30秒待機→レイド開始→リセット…を自動で繰り返す
(上記画像は「レイド開始まで30秒」「開始後リセットまで9秒待機」で設定)

2021年9月20日追記:「ひとりで挑戦」に対応したプログラムを公開しました。合わせてご参考ください
【Arduino自動化19】ねがいのかたまりで自動レイドバトル周回【完全放置で「けいけんアメ」「ヨロイこうせき」】

2021年10月10日追記:Switch2台(レイド配布+レイド周回)に対応したプログラムも公開しました。
【Arduino自動化20】Switch2台で「完全」自動!レイドバトル自動周回【デリバード・色違いレイドなど】

続きを読む

【Arduino自動化05ex】乱数調整レイドでのArduino Leonardoの使い方

ますたーです。こんにちは。

3月は繁忙でなかなか更新ができませんでした。

 

さて、今回はArduino自動化記事05で紹介・実施した乱数調整色レイドの手順についての補足記事です。具体的には、Arduinoをどのタイミングで使うのか、に焦点を当てて執筆しました。一応、本記事だけでも読めるように書きますが、先に当該記事を一読しておくとスムーズです。

なお、Arduino Leonardoでの自動化環境の導入については、導入記事を参考にしてください。

※本ブログに初めてお越しの方は「本ブログについて」もぜひ、ご覧ください。

【!】本記事では乱数調整の内容を扱います。

 

概要

今回の記事では、レイド乱数調整の中で「Arduino Leonardoをどのタイミングで使うのか」を紹介します。 

詳細実際の作業手順は適宜 前回の記事(Arduno自動化05) で補ってください(途中途中にリンクも貼りますのでご安心ください)。

本記事のメインターゲットは「乱数調整は知っているけどArduinoを使うというのがいまいちピンとこない人」「前回記事を読んだけど、Arduinoコンパイル?抜き差し?をどのタイミングでやればいいのかわからない人」になります。

では目次です。補足記事なので、例のごとく分量多めです。順番に読んで頂くと抜け漏れが無いかと思いますが、各人、必要になる部分について、目次から飛んで読んでいただいても大丈夫です。

とりあえずお急ぎの方は【ここから本題】まで読み飛ばすと良いと思います。

 

自動化で準備するハードウェア5つ(おさらい)

まずは、使用機材についておさらいです。必要なものは以下の通りです。

ひとまず、これらが揃っていることを確認ください。

実際に筆者が使っている機材については「番外編03:機材紹介記事」をご参考ください)セットアップ手順は「Arduino自動化01:導入記事」で紹介しています)。

乱数調整の自動化に必要なものは、「Nintendo Switch」と「Arduino Leonardo」、これらをつなぐ「USBケーブル」と「ドック」、そして「PC」の5点です。

筆者が使っている機材のイメージ。要するに上記5つで準備完了だ。

 

乱数調整に使うツール

続いて、使うツールの話です。

具体的には、乱数調整は「初期シード特定」「目標消費作業」の2ステップありますが、インストールするアプリケーションがいくつかあります。特に初期シード特定作業は有名なツールが2つあります。ここでは補足記事として両方紹介します。

初期シード特定は「1-Star Seed Search」「SW Seed Calculator」どちらもOK

様々なブログ記事や動画などで紹介されている乱数調整(初期シードの特定)を行うツールとしては、さびたコイル氏による「1-Star Seed Search」と、ぼんじり氏による「SW Seed Calculator」の2つが特に有名だと思います。

どちらも、初期シードの推定ができるツールとして優れており、筆者は両方とも使っています。どちらのツールも大変素晴らしいと思います。

「SW Seed Calculator」は初期シード特定に特化

一応、前回の記事(Arduino自動化05)では、1-Star Seed Searchを使っていますが、これは乱数調整の記事を扱う上で、「初期シード特定」と「目的の消費数の特定」の作業が同じツールで完結するため、説明しやすかったことが理由です。

一方で、ぼんじり氏が提供する「SW Seed Calculator」は、その次のステップ(目的の消費数の特定作業)には別のツール(夜網氏が提供する「8densearch」など)を使う必要があるため、乱数調整の流れを理解していない人には少し説明がしにくいです。

ただし、「初期シード特定」に限定するなら「SW Seed Calculator」はすごく使いやすくしかも高速で、エラーも少ないため個人的には大変おすすめです。特に、6日目検索ができるため初期シード特定の精度も高く、セットアップの煩雑さや別ツール連携の手間をいとわないのであれば、ぜひとも使っていきたいと感じます。

本記事や様々な記事で「乱数調整の全体の流れ」がわかってから使うと驚くほど使いやすいと思いますし、もし、前回の記事(Arduino自動化05)で初期シード特定につまづいているなら、試してみても良いかもしれません。

f:id:tangential_star:20210314181645p:plain
f:id:tangential_star:20210314181653p:plain
「1-Star Seed Search」「SW Seed Calculator」はどちらも初期シード特定ができる。
大きな違いはポケモンを捕まえる回数だ

乱数調整に使うツールの組み合わせ

乱数調整は大きく「初期シード特定」「目的の消費数の特定」の2つに分かれます。前回の記事では紹介した「1-Star Seed Search」では、これら2つを1つのツールで完結できるので、初期導入としては比較的簡単です。

一応、下記の2パターンがおすすめです。お好きな方で実施ください。前回の記事(Arduino自動化05)では下記1を採用しています。

  1. さびたコイル氏の「1-Star Seed Search」のみ(流れを理解するまではおすすめ)
  2. ぼんじり氏の「SW Seed Calculator」+夜網氏の「8densearch(慣れたらおすすめ)
f:id:tangential_star:20210314203914p:plain
f:id:tangential_star:20210314203921p:plain
「1-Star Seed Search」では目標個体検索まで1つのツールで完結する。
「SW Seed Calculator」利用時などは「8denSerach」など別ツールで目標個体検索を行う

 

「1-StarSeedSearch」を使う場合は、前回の記事(Arduino自動化05) を参考にセットアップしてください。「SW Seed Calculator」を使う場合は、ぼんじり氏のWebサイトから「SW Seed Calculator」をダウンロードしてください。

原則として、これらは最新版が良いかと思いますが、お好みで決めてください。その後、そのページの手順(ダウンロードリンクの下の方に設定方法載っています)に沿ってセットアップしてください(リンク先に載っているので、本稿ではセットアップ方法は割愛します)。

この記事では補完記事としての側面から、初期シード特定にはSW Seed Calculatorを利用します

 

【ここから本題】乱数調整でArduino自動化できる2つの手順

ここからが本題です。

前回の記事でも紹介した通り、乱数調整の手順は大きく4つです。

この中でArduinoによる一部自動化ができるのは下記2と3、2つの手順です。

  1. 準備(目当ての巣穴を見つけてねがいのかたまり投げ入れる)
  2. 乱数調整(日付回してポケモン捕まえて初期シードを特定する作業
  3. 乱数消費(目標の日付に向かって何度も日付を変更する作業
  4. 捕獲(お気に入りのボールで捕まえる)

ここからはまず、この「初期シードを特定する作業」について 紹介をします。

 

1.準備(目当ての巣穴を決めて「ねがいのかたまり」を投げ入れる)

まずは、レイド乱数調整に挑戦する巣穴を決めましょう。

具体的には、ポケモン徹底攻略の「レイドバトルのポケモン一覧」などから、欲しいポケモンのいる巣穴を探します。もし、乱数調整ツールに前述の「SW Seed Calculator」をお使いの場合は、右上の「巣穴マップを開く」から巣穴を逆引きできますので、必要に応じてご活用ください。

f:id:tangential_star:20210320190437p:plain
f:id:tangential_star:20210320184124p:plain
巣穴の場所は「ポケモン徹底攻略(左)」や「SW Seed Calculator(右)」などで調べよう

余談ですが、DLC冠の雪原の巣穴で出てくるポケモン夢特性が固定されるので、それが気になる人はガラル本土で探しましょう。

さて、今回は、色違いが金色で美しい、チルタリスを狙って行きます。チルタリスは様々な巣穴で出現しますが、今回は「ボールレイクの湖畔 D」の巣穴を目指します。 

f:id:tangential_star:20210320212626g:plain

まずは、目標の巣穴に向かおう

巣穴について、狙うポケモンによっては(例えばキョダイマックス個体など)、いわゆる「レア柱」でないと出現しないことがあります。つまり、目標となる巣穴の場所はもちろん、「通常」「レア」のいずれの柱を建てる必要があるのかも確認しておきましょう(レアの柱とは、通常の赤色の光の柱ではなく、紫色のオーラが出ている太い光柱のことです)。

f:id:tangential_star:20210320211737g:plain
f:id:tangential_star:20210320211758g:plain
巣穴前でセーブしておき、「ねがいのかたまり」を投げ入れたらすぐにHomeボタン。
赤色がうっすらと見えていたら即リセットすることで、投げ直し(レア柱厳選)ができる

なお、自分で「ねがいのかたまり」を投げ入れて建てた柱でないと、乱数調整はできません。もし、すでに目標の巣穴に光の柱が建っていても、そのまま次のステップに進まず、日付変更やレイド挑戦などで予め消しておき、必ず自分で建てましょう。

無事に目標の巣穴に光の柱を建て終わったら、念の為、セーブしておいてください。


2.Arduinoにプログラム(3日後・4日目用)を書き込もう

さあ、ついに手順の中にArduinoが登場しました。なお、本記事は導入記事でセットアップが完了している想定で書いています。悪しからずご了承ください。

ここから、乱数調整が始まりますが、今からの手順は「初期シードの推定」作業になります。このステップでは、条件を満たすポケモンが現れるまでひたすら3日後(4日目)のポケモンを捕まえてはリセット、捕まえてはリセット、…と幾度となく繰り返し作業が発生します。ここを、Arduinoで自動化する準備となります。

まずは、PCで、Arduino IDEを開いてください。そこに、Arduino自動化05記事のソースコード1つ目をコピペして、検証&マイコンボードに書き込みを行ってください。

f:id:tangential_star:20210320222301p:plain
f:id:tangential_star:20210320220743p:plain
PCとArduinoをつないでおき、IDEソースコードをコピペしてボードに書き込もう

ちなみに、「新しい名前で保存する」ダイアログが出てきたら、半角英数字でファイル名をつけてください。日本語はNGです。

無事にArduinoにプログラムが書き込まれたら、ArduinoをPCから抜いてください。

 

3.最初の目標ポケモンを把握する

まずは乱数調整のファーストステップです。ツールを使って、初期シード特定に必要なポケモン(3日後=4日目に出会わなければならないポケモン)を調べます。

「SW Seed Calculator」をお使いの方も、「1-Star Seed Search」をお使いの方も手順は共通です。巣穴情報を入力しておけば、最初に出会わなければならないポケモンはプルダウンメニューの中に出てきます。

※以降、本記事では「SW Seed Calculator」で画面説明をします。

f:id:tangential_star:20210320230213p:plain
f:id:tangential_star:20210320230225p:plain
まずは3日後(4日目)に遭遇する必要のあるポケモンを把握しよう
なお、「SW Seed Calculator」「1-Star Seed Search」いずれもやることは同じだ

今回の例(ボールレイクの湖畔D・レア/バッジ=8個/ROM=ソード)だと、まずは「★3 アオガラス」「★3 ゴルバット」のいずれかを見つける必要があることがわかります。これをまずは把握しましょう。

 

4.ArduinoをSwitchに挿し込もう 

さて、ゲーム画面に戻ります。ゲーム画面では、巣穴に「ねがいのかたまり」を投げ入れたタイミングで終了していると思います(つまり、Aを押したらレイド募集画面に入れる状態)。この状態のまま、SwitchとArduinoを接続してください。充電しながら行う場合は、先にSwitchをドックに差し込んでから、ドックのUSBポートにArduinoを挿し込んでください。

正しく接続されると、勝手に「ゲーム終了→ゲーム起動→レイド調整~日付変更を3回繰り返す→日付を戻して挑戦画面で待機」という一連の流れが行われます。自動操作が止まるまで、放置しましょう(2分半くらい)。

※このプログラムは3日間日付を進めても月をまたがない想定で使っています。注意してください

f:id:tangential_star:20210320224404p:plain
f:id:tangential_star:20210320225156g:plain
ArduinoをSwitchに接続すると自動で操作される。他コントローラー接続は解除しておくこと

なお、SwitchとArduinoを接続する際には、Switchに接続されている有線・無線コントローラーすべて(本体から取り外した状態のJoy-conや、プロコントローラーなどを含みます)の接続を解除または切断した状態にしてください。

 

5.自動操作が止まったら、目標のポケモンを捕獲しよう

ゲーム画面の動きが止まったら、画面に映っているポケモンが目標のポケモンだったかどうかを確認します。具体的には、ステップ3で確認したポケモンであればOKです。

今回の例(ボールレイクの湖畔D・レア/バッジ=8個/ROM=ソード)だと、まずは「★3 アオガラス」「★3 ゴルバット」のいずれかを見つけなければなりませんから、例えば「★4 アオガラス」「★5 クロバット」などで画面が止まっている場合はNGとなります(★の数も要注意!)。

目標のポケモンではなかった場合は、目標のポケモンが出るまでArduinoをSwitchから一度抜き、挿し直しましょう。

目標のポケモンが出現していた場合には、そのポケモンを捕獲します。

f:id:tangential_star:20210320232957p:plain

目標のポケモンが出るまでひたすらArduinoを挿し直そう
f:id:tangential_star:20210320231942p:plain
f:id:tangential_star:20201123010702g:plain
画面が目標のポケモンではなかった場合、Arduinoを挿し直す
f:id:tangential_star:20210320231438p:plain
f:id:tangential_star:20210320235704g:plain
画面が目標のポケモン(★も要チェック!)だった場合、レイドに挑戦して捕獲する

 

6.捕まえたポケモンの能力をツールに入力

捕まえたポケモンの特性・性格・能力値(個体値)をツールに入力します。

個体値の計算には、原則としてLv100まで引き上げるだけの「けいけんアメ」や「ふしぎなアメ」、そして性格補正で個体値判別が出来なかった場合に備えての「まじめミント」またはドーピングアイテムがあると非常に便利です。 

f:id:tangential_star:20210321002240g:plain
f:id:tangential_star:20210321001907p:plain
捕まえたポケモンの能力値をツールに入力しよう。アメとまじめミントがあると便利だ

6-1.利用できない個体値の場合

能力値を入力後、1-Star Seed Searchでは「NG!」、SW Seed Calculatorの画面で「利用できない個体値です」 という言葉がでてきた場合、残念ながら手順をやり直す必要があります。単純にやり直すのではなく、1日日付をずらす必要があります。

f:id:tangential_star:20210321005840p:plain
f:id:tangential_star:20210321004552g:plain
個体値がNGだった場合、再起動して日付を手動で1日進めよう。セーブも忘れずに

 具体的な手順としては

  1. 一度、ゲームを終了する(再起動する)
  2. 巣穴レイドバトル「みんなで挑戦」を選択する
  3. Homeボタン→設定→日付を1日すすめる
  4. 巣穴からワットを回収する
  5. セーブする

になります。 セーブまで完了したらまた4~6の手順をやり直します。

6-2.利用できる個体値の場合

能力値を入力後、1-Star Seed Searchで「OK!  Next ->」、SW Seed Calculatorの画面で「利用可能な個体値です」 という言葉がでてきた場合は、おめでとうございます。第1関門突破です。セーブしてはいけません。注意しましょう。

f:id:tangential_star:20210321012622g:plain
f:id:tangential_star:20210321012647p:plain
「利用可能な個体値です」となれば次ステップに進める

利用可能な個体値だった場合、次の目標ポケモンの指示も合わせてツール上に出てくるので、そちらを確認してください。具体的には、3V, 4V, 5Vなど、次に捕まえるべきポケモンのV数の指定が出てくるので、その数字にあった巣穴のポケモンを捕まえます。

f:id:tangential_star:20210321014105p:plain

次の目標ポケモンの条件が表記されるので、プルダウンからポケモン名を確認しよう

なお、詳細な原理については割愛しますが、「SW Seed Calculator」を利用の場合、「4V -> 4連」のように、Vの数と連数が両方表示されることがあります。

この時、もし、複数のV数・連数のペアが表示されている場合は、可能な限り「連数」が多い方のV数ポケモンを捕まえてください。例えば「4V->6連 3V->5連」と表示された場合は、「4V」の方を選択してください。「4V/5V -> 4連」のように、連数が変わらない場合は、どちらでも大丈夫です。

次の目標となるポケモンを把握したら、セーブせずに次のステップに進んでください。

 

7.次の目標ポケモンを捕まえて個体値入力

「4日目(2体目)」のポケモンを捕まえる場合、基本的に4~6と同じ手順です。

要するに、「次のターゲットとなるポケモンが出るまでArduinoを挿し直す」だけでOKです。ターゲットとなるポケモンが出たら、レイドバトルをして捕獲してください。

f:id:tangential_star:20210321030638g:plain
f:id:tangential_star:20210321031025p:plain
基本的に前の手順と同一。指定のV数を持つポケモンを捕まえればOKだ。

これで、最初の日を起算日として、3日後のポケモン2匹の個体値がツールに入力された状態となっています。ここまでくれば次の作業も同じ流れ。この調子です。

なお、やはりレポートはしません。要注意です。

 

8.Arduinoのプログラム(4日後・5日目用)に書き換えよう

さて、ここでArduinoに話が戻ります。次のステップでは「5日目(4日後)」のポケモンを捕まえる必要がありますので、事前にArduinoのプログラムを書き換える必要があります。

具体的には、再びArduino IDEで先程のソースコードを開いて、TIME_WARP_DAYSの(3)を(4)に書き換えてArduinoに書き込めばOKです。

#define TIME_WARP_DAYS (4) // 何日すすめるか(=ここは基本的に「3」こ

この1箇所の書き換えが完了したら、PCとArduinoをつなぎ、左上の「検証」「マイコンボードに書き込み」作業を行ってください。

ちなみに、次に捕まえるポケモンについてはツールの指示通り、基本的には不問ですが、可能な限りVの少ないレイドのほうが望ましいです。特にVの少なさはそっくりそのまま計算速度・精度に比例しますので、もし、マシンスペックが低いPCを使っている場合などは特に気をつけましょう。

f:id:tangential_star:20210321094229p:plain
f:id:tangential_star:20210321022029p:plain
次は「4日後(5日目)」のポケモンを捕まえる必要があるのでプログラムを書き換える

 

9.次の目標ポケモンを捕まえて個体値入力

続いて、「5日目」のポケモンを捕まえる場合も、基本的に4~6と同じ手順です。ただし、ターゲットは不問となりますので、★の少ないレイドなどを厳選しましょう。要するに、「極力Vの少ないレイドが出るまでArduinoを挿し直す」だけでOKです。

f:id:tangential_star:20210321104404g:plain
f:id:tangential_star:20210321104129p:plain
同様の手順で4日後(5日目)のポケモンを捕まえて能力値を入力しよう

口酸っぱく言いますが、ポケモンを捕まえた後はくれぐれもセーブしないように注意してください。

 

10.Arduinoのプログラム(5日後・6日目用)に書き換えよう

ここまで読まれた方にはお分かりかと思いますが、次のステップでは「6日目(5日後)」のポケモンを捕まえる必要がありますので、再びArduinoのプログラムを書き換えます。TIME_WARP_DAYSを(5)に書き換えてArduinoに書き込めばOKです。

#define TIME_WARP_DAYS (5) // 何日すすめるか(=ここは基本的に「3」こ

 

 

11.最後の目標ポケモンを捕まえて個体値入力

「6日目」のポケモンを捕まえる手順も、基本的に4~6と同様です。★の少ないレイドが出るまでArduinoを抜き差しして、目当てのレイドだったら捕獲して個体値チェックです。

ここで妥協して星5レイドなどで済ませると、SEEDの誤検出のリスクも高くなるため、極力★3レイドなど、V数が少ないレイドを選ぶようにしましょう。ここまでくれば、「SW Seed Calculator」の4項目(ポケモン4匹分の個体値・性格ほか)が埋まっている状態となります。

なお、目安として、この時点でも右下の「誤Seed検出率」が「高」の場合は、素直に最初からやり直したほうが良いです(V数の少ないレイドが不十分だったり理由は色々ですが…)。

f:id:tangential_star:20210321110809g:plain
f:id:tangential_star:20210321114808p:plain
同様の手順で5日後(6日目)のポケモンの能力を入力。誤Seed検出率が「低」ならベストだ

ここでも、捕まえてからセーブしてはいけません。くれぐれも気をつけましょう。

 

12.Seed推定をしよう

ここまでお疲れ様でした。あとは「SW Seed Calculator」右下の「計算」ボタンを押すだけです。

高速なCPU・グラフィックボード(GPU)を備えているゲーミングパソコンなどであれば、「Seedを1個見つけたら終了」の条件下では1分ほどでSeed特定ができます。

再計算回数と目安となる推定計算時間はツール中に記載の通りですので、例えば、再計算5回・CPUのみでの計算をするとこれが4時間半程度かかることがわかります。とにかく、計算が終わるまでは気長に待ちましょう。

f:id:tangential_star:20210321111610g:plain

SW Seed Calculatorの画面。「計算」を押すと、個体値から巣穴初期Seedが推定される

※誤Seed検出率が高いと「Seedを1つ見つけたら計算終了」条件だと不適
※ゲーミングPC(RAM:64GB, CPU: core i9-10900X, GPU: RTX2080Ti)での等倍速録画

なお、誤Seed検出率によっては、左下の「Seedを1つ見つけたら計算終了」のチェックボックスを外しておくことが必要になります。ただし、計算時間が非常に増えるのでPCスペックと相談してください。

参考までに、筆者環境(かなりしっかりしたゲーミングPC)でチェックを入れて計算すると10秒で計算完了していましたが、チェックを外して「10回」再計算の上限設定だと7分20秒もかかりました。計算時間で見ると44倍です。

まともに考えて、GPUを積んでいないPCだと時間がかかりすぎてしょうがないので、「誤Seed検出率が低であること」を前提とした上で、再計算「0~2」とかが落とし所ではないかと思います。

さて、推定されたSeedが無事に算出できれば、初期シード推定は完了です。お疲れ様でした。なお、この推定シードが複数ある場合には、初期シードを絞り込む作業が必要です。本稿では割愛しますが、前回記事の手順2-2-1を参考にしてください。

本稿では、初期シードは0xCBC17754E4E6EA62と特定できたので、次項もその数字で紹介します。

 

13.目標消費数を特定する

初期シードが特定できたので続いて、色違いのポケモンが出る目標消費数を計算します。目標消費数の計算ツールとしては、夜鯛氏による「8denSearch」、さびたコイル氏による「1-Seed Star Search」が主要です。これらの間で機能的な差はありません。本稿では導入手順については割愛しますが、本当にお好きな方を使ってください。

初期シード特定に使ったツールがSW Seed Calculatorの場合は8denSearchを、1-Star Seed Searchを使っている場合はそのまま1-Star Seed Searchを使うことをとりあえずはおすすめします。

本稿では、初期シード特定にSW Seed Calculatorを使ったので8denSearchを利用します。とは言っても、1-Star Seed Searchでも同じことができるので、ご安心ください。

手順としては、目標消費数を特定するためのツールに、初期シード値、バージョン・巣穴情報ほか、必要事項を入力し、計算を押すだけです。画面は、下記画像を参考にしてください。

f:id:tangential_star:20210328001418p:plain
f:id:tangential_star:20210328001425p:plain
「1-Star Seed Search」も「8denSearch」も目標個体の検索ができる

目標の個体の左には、1日目(巣穴に投げ入れた日)から起算して、何日目に色違いが出現するかの消費数が記載されています。これが、十分に小さい数字であれば、その数字を手元に控えて次のステップに進みましょう。今回は、色違いの菱形・星型を特に気しないので、最も消費数が小さい「1108」を目指します。この数字は「1108日後」を表します。「1108日目」ではありません。次のステップで重要なので注意しましょう。

 

14.Arduinoのプログラムを書き込もう

次は高速消費のプログラムをArduinoに書き込みます。具体的には、前回記事のソースコード2からArduino IDEにコピペして書き込みます。

ただし、コピペして使うだけでなく、SHOHISUの数字を書き換える必要があります。先程ツールで確認した数字から-3の数字を入力してください。例えば、今回の例だと、1108なので、1105と入力します。ただし、-3だと、消費数と現在日付の関係でずれることがあるので、実際には-10程度で残りを手動でしたほうが良いと思います。

また、ソースコードの作りの甘さもあるので-10くらいでやるのが良い気もします。

このプログラムは31日まである月で使う前提なので、もしこれがクリアしていない場合は、予め2,4,6,9,11月「以外」に日付を変更しておいてください。

#define SHOHISU (1108-3) // ここを「目的消費数-3」にする。

なお、このSHOHISUの上限は「32767」となります。もし、32768以上の消費が必要な場合、2回に分けるなどの工夫が必要です。これはArduino本体の仕様です。

また、プログラムですが、私が横着して作ったプログラムだったので、消費数の内部計算が甘く、実際の消費予定数より少なく消費される仕様になっていたので、55行目を下記のように書き換えると、より消費数が正しく消費できると思います

maxlooptime =31* (SHOHISU/30) + SHOHISU%30;

本件は、私がExcelで計算して検証した数式なので、誤っている可能性もありますが、筆者は実機でこれでうまくいきました(検証回数:1回)。

これらを自己責任で書き換えていただき、ArduinoIDEでプログラムを書き込みましょう。

f:id:tangential_star:20210320222301p:plain
f:id:tangential_star:20210328004343p:plain
PCとArduinoをつないでおき、IDEにソースコードをコピペしてボードに書き込もう

 

15.ランクマバグ状態にして、Arduinoを挿し込む

さて、目当てのポケモンに向けて消費(日付を進める作業)に移る必要がありますが、まずは、一度巣穴の場所を離れて、ポケモンセンターに移動してください

その状態で、いわゆる「ランクマバグ状態」に移行してください。詳細な手順は、前の記事の手順3-1を参考にしてください。

ランクマバグ状態にしたら、Homeボタンから設定画面に入り、「日付と時刻」から日付の変更画面に入り、日付を更新せずに「OK」を押してください。

この状態でArduinoをSwitchに挿せば自動的に日付更新が始まっていきます。

f:id:tangential_star:20210320224404p:plain
f:id:tangential_star:20201123121934g:plain
事前に「OK」を押しておき、Arduinoを指すだけで日付更新(乱数消費)が始まる

 

16.巣穴に戻り、セーブして準備完了

自動作業が終わったら、前回記事の捕獲パートです。お疲れ様でした。ポケモンセンターから目的の巣穴の目の前まで戻り、セーブしましょう

f:id:tangential_star:20210328032359g:plain

乱数消費が終わったら巣穴まで戻り、セーブしよう

あとは、自身が目的の消費数-3の日付になっていることを確認し、「みんなで挑戦」から3回、日付を変更すればOKです。その際に、目的のポケモンが出たら挑戦してそのまま捕獲、違うポケモンだったらリセットして、目当てのポケモンのシルエットが出るまで3回日付を変更して挑戦を繰り返すだけです。

なお、このとき、目標のポケモンではなかった場合(色違いのはずなのに光らなかった場合)は、一度そのまま捕まえて、それがどの個体のポケモンなのか、該当する性格・個体値のポケモンが目標の個体の付近にいるかをツールで確認してください。

もし、目標のポケモンよりも手前(上側)のポケモンが出現している場合には、日付を回す回数をそのズレ分だけ実施すればOKです。なお、目標ポケモンよりも下側だったり、そもそも付近にそのポケモンが見当たらなかった場合は、手順1からやり直しとなります。前者の場合は消費が大きすぎる、後者の場合はそもそも初期シードの特定に失敗しています。めげずに確認してみましょう。

f:id:tangential_star:20210328031105p:plain
f:id:tangential_star:20210328031921g:plain
3回日付を回して、目当てのポケモンが出たら挑戦しよう

 

17.捕獲しておしまい!

目当てのポケモンに、任意のボールを投げて捕獲できれば完了です。お疲れ様でした。

f:id:tangential_star:20210328033259g:plain

色違いが捕まえられたら完了だ。お疲れ様でした

 

あとがき 

本稿では、前回記事では必要最小限に留めていた「Arduino Leonardoを乱数調整のどのタイミングで使うのか?どのタイミングでプログラムを書き込むのか?」に焦点を当てた補足記事を書きました。

基本的には最小限のプログラム書き換えで済むことや、Switchとの接続タイミングが何となくお分かりいただけたかと思います。

もし、前回の記事で「Arduinoと乱数調整が結びつかない!」となっていた人にとって、この記事が参考となれば幸いです。

 

ではではc⌒っ.ω.)っ 

 

前回記事(本補足記事の対象):

【Arduino自動化05】乱数調整レイドで色違いパッチルドン探し【冠の雪原】

次の記事:

【Arduino自動化18】ローカルレイド自動配布【デリバードレイドでマックスこうせき】

導入記事:

【Arduino自動化01】Arduino開発環境の導入

 

【Arduino自動化17】ふしぎなおくりもの受け取り【あいことば自動入力】

ますたーです。こんにちは。

今回の記事では「ふしぎなおくりもの」での『あいことば』(シリアルコード)による受け取りを自動化します。

 

Arduino自動化記事はこれで第17回。これからもよろしくお願いします。

 

なお、Arduino Leonardo自動化の導入・機材構成については導入記事を参考にしてください。

導入記事:【Arduino自動化01】Arduino開発環境の導入

※本ブログに初めてお越しの方は「本ブログについて」もぜひ、ご覧ください。

 

概要

「ふしぎなおくりもの」の「シリアルコードで受け取る」を自動で行います。

f:id:tangential_star:20210226230616g:plain
f:id:tangential_star:20210226225427p:plain
シリアルコード(あいことば)の入力から受け取りまでを全部自動で行ってくれる

f:id:tangential_star:20210226234312g:plain

幻のポケモンゲットチャレンジ」など、10個以上の『あいことば』もまとめて入力できる
(注)「幻のポケモンゲットチャレンジ」はすでに終了しています

 

では、もくじです。

今回も余談が多めなので、ソースコードだけ欲しい方は⇒読み飛ばす

 

2021年2月27日は「赤・緑」発売から25周年の「ポケモンデー」

いきなり余談をはさみますが、ポケモンの最初の作品「赤・緑」が発売されたのは、今からちょうど25年前の、1996年2月27日でした。つまり、本日2021年2月27日は「ポケモン赤・緑発売25周年」となります。おめでとうございます!!

実は、昨年2020年には、株式会社ポケモンにより、2月27日を「ポケモンデー」として、記念日として制定(日本記念日協会が認定)されています。つまりは、今年の2月27日は発売25周年「ポケモンデー」となるわけですね。

f:id:tangential_star:20210226232259j:plain
f:id:tangential_star:20210226232303j:plain
「Pokémon Day」のロゴとポケモン一般社団法人 日本記念日協会のHPより引用)

 

「うたうを覚えたピカチュウ」を受け取ろう

明日2021年2月28日(日)には、ポケモン25周年を記念したバーチャルコンサートが開催されます。これを記念して、2021年2月27日現在、ポケモン剣盾では、「うたう」を覚えた特別なピカチュウがプレゼントされています(期日:3月25日(木)23時59分まで)。

f:id:tangential_star:20210226233517j:plain
f:id:tangential_star:20210226233513j:plain
Post Malone氏によるポケモン25周年記念コンサートの開催案内と、配信されるピカチュウ
ポケモン公式サイトの記事(2021.2.19掲載)より画像引用)
f:id:tangential_star:20210227000103p:plain
f:id:tangential_star:20210227000107p:plain
「うたう」を覚えていて、夢特性ひらいしん」のピカチュウ

プレゼント方法は、剣盾「ふしぎなおくりもの」の「あいことば」を使った配信です。

ちなみに、今回のピカチュウを受け取るための「あいことば」は「P25MUS1C」です。まさに「ポケモン25周年コンサート」を表すあいことばですね。

 

準備(プログラムの使い方など)

ここからが本題です。

「あいことば」をプログラムに書き込もう

今回のArduino自動化では、「あいことば」の入力から受け取りまでを自動で行います。入力する『あいことば』を予め準備しておきましょう。

プログラム上では、serial_code[][32]に書き込みます。

具体的には、今回のあいことばが「P25MUS1C」なので、これを半角のダブルクオートで囲み、最後に半角のカンマをつけて記入してください(例⇒ "P25MUS1C", )。「"P25M US1C",」のように、区切りの半角スペースを挟んでもしっかり動きます。

char serial_code[][32] = {
   "P25MUS1C", // ポケモン25周年記念ピカチュウのコマンド
    "" // ←この行は残してください(ループの判定に使うため)
};

余談ですが、剣盾のキーボードでは「Z(ゼット)」「I(アイ)」「O(オー)」はそれぞれ数字の「2」「1」「0」と間違えやすいため使われません。

このプログラムでは上記表記ミスにも対応できるように作ったつもりです。例えば、誤って「P25 MUSIC」などと記入しても動くはずなので、各人が読みやすい方法で記入してください。

f:id:tangential_star:20210227011924g:plain

プログラムに書き込むことで、「P25MUS1C」の入力が自動で行える

ちなみに、キャンペーンによっては、1つのキャンペーン中に複数(10程度)の『あいことば』が発行される場合があります(例えば、いずれもすでに期間は終了していますが「幻のポケモンゲットチャレンジ」「サトピカゲットキャンペーン」など)。このプログラムでは複数の「あいことば」の入力にも対応可能ですので、『あいことば』を複数serial_code[][32]の中に記入することで全部続けて入力できます。

 

// 例:「サトピカゲットキャンペーン」の『あいことば』
char
serial_code[][32] = { "P1KACHUGET", "P1KAADVANCE", "V0LTTACKLEP1KA", "P1KABESTW1SH", "KAL0SP1KA", "ULTRAP1KA", "K1NP1KA1855", "1CH00SEY0U", "" // ←この行は残してください(ループの判定に使うため) };

1つのシリアルならいざ知らず、複数のシリアルコード(あいことば)を入力する場合には、特にサブロムを持っている人などは重宝すると思います。

YY通信でオンライン接続し、カーソルを「ふしぎなおくりもの」に合わせる

次に、ゲーム本編での準備ですが、まず、YY通信で「インターネットに接続」をしてください。フィールド画面でYボタン⇒+ボタンで接続できるはずです。そして、Xボタンでメニューを開いた時に「ふしぎなおくりもの」にカーソルが合うようにしたら、Bを押してフィールド画面にもどってください。以上、わずか2ステップで準備完了です。

あとは、フィールド画面でArduinoを挿すだけ。簡単ですね。

f:id:tangential_star:20210227011003p:plain
f:id:tangential_star:20210227011009p:plain
準備は「インターネット接続」「カーソルを『ふしぎなおくりもの』に合わせる」だけ

 

ソースコード

プログラムにはポケモン25周年コンサート記念の「うたうピカチュウ」のシリアルコード(P25MUS1C)が入力されています。必要に応じて書き換えて使用ください。

なお、予めインターネットに接続した状態で、メニュー開いた際に「ふしぎなおくりもの」にカーソルが合う状態で、Arduinoを挿すだけで動きます。

 

/* 
 *  自動でふしぎなおくりもののシリアルコードを入力して受け取ってくれるやつ。
 *  
 *  Xボタンでメニューを開いた時に「ふしぎなおくりもの」にカーソルが合うこと。
 *  YY通信がオンラインになっている状態(予めインターネット接続するため)でArduino差し込むだけ!
 *  (c) 2021 ますたーの忘備録
 *  https://tangential-star.hatenablog.jp/
*/

#include <SwitchControlLibrary.h>

#define HOLDTIME (95) // 1回のキー入力の長押し時間

// ★ここに受け取りたい文字列を入力(半角・ダブルクオートで囲み、最後は半角カンマ,で改行)
char serial_code[][32] = {
   "P25MUS1C", // ポケモン25周年記念ピカチュウのコマンド
    "" // ←この行は残してください(ループの判定に使うため)
};


void PushRL(int delay_time_ms);
int PushKey(char* keyname, int holdtime, int delaytime);
void NextDayInCheatMode(void);

void input_serial(char*);

void setup() {
  // コントローラーとして認識されるためにRLを7回ほどカチャカチャする
  for(int i=0;i<7;i++)PushRL(300);
  delay(1000);
}

void loop() {
  int i=0;
  PushKey("X", HOLDTIME, 500);  // メニューを開いて
  PushKey("A", HOLDTIME, 1500); // ふしぎなおくりものを選択
  PushKey("A", HOLDTIME, 500);  // ふしぎなおくりものを受け取る

  // シリアルコード列が終わるまで受け取り続ける
  for(i=0; strcmp(serial_code[i],"") != 0 ;i++){
    
    PushKey("down", HOLDTIME, 120);
    PushKey("down", HOLDTIME, 120);
    PushKey("A", HOLDTIME, 1100);  // 警告画面が出る
    PushKey("A", HOLDTIME, 1500);  // Aを押さないと進まない

    // キーボード起動
    input_serial(serial_code[i]);  // シリアルを入力

    PushKey("+", HOLDTIME, 7000);  // +で確定⇒ギフトを探しています…

    PushKey("A", HOLDTIME, 5000);  // Aで受け取り⇒本当は21秒待機

    // 失敗した場合のケア(もう一度入力しますか?)
    PushKey("Down", HOLDTIME, 16000);

    PushKey("A", HOLDTIME, 1000);    // ▼
    
  }

  PushKey("B", HOLDTIME, 500);  
  PushKey("B", HOLDTIME, 500);  
  PushKey("B", HOLDTIME, 500);  
  PushKey("B", HOLDTIME, 500);  
  PushKey("B", HOLDTIME, 500);  
  for(;;) delay(100); // プログラム終了

}

void PushRL(int delay_time_ms){
  SwitchControlLibrary().PressButtonR();
  SwitchControlLibrary().PressButtonL();
  delay(HOLDTIME);
  SwitchControlLibrary().ReleaseButtonR();
  SwitchControlLibrary().ReleaseButtonL();
  delay(delay_time_ms);
  return;
}
int PushKey(char* keyname, int holdtime, int delaytime){
  // ホームボタン・方向キーはRight, Left, Up, Down, Homeなど2文字以上で入力。
  // その他ボタン入力は1文字(A,B,X,Y,R,L,+,-)ZR・ZLにも対応
  // 同時押しは非対応
  
  if(strlen(keyname)==1){
    switch(keyname[0]){
      case 'A': case 'a': // A
        SwitchControlLibrary().PressButtonA(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonA(); delay(delaytime);
      break;
      case 'B': case 'b': // B
        SwitchControlLibrary().PressButtonB(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonB(); delay(delaytime);
      break;
      case 'X': case 'x': // X
        SwitchControlLibrary().PressButtonX(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonX(); delay(delaytime);
      break;
      case 'Y': case 'y': // Y
        SwitchControlLibrary().PressButtonY(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonY(); delay(delaytime);
      break;
      case 'L': case 'l': // L
        SwitchControlLibrary().PressButtonL(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonL(); delay(delaytime);
      break;
      case 'R': case 'r': // R
        SwitchControlLibrary().PressButtonR(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonR(); delay(delaytime);
      break;
      case 'H': case 'h': // Home
        SwitchControlLibrary().PressButtonHome(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonHome(); delay(delaytime);
      break;
      case '+': case 'p': case 'P': // Plus
        SwitchControlLibrary().PressButtonPlus(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonPlus(); delay(delaytime);
      break;
      case '-': case 'm': case 'M': // Minus
        SwitchControlLibrary().PressButtonMinus(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonMinus(); delay(delaytime);
      break;
      default:
      break;
    }
  }else if(strlen(keyname)>=2){
    switch(keyname[0]){
      case 'z': case 'Z': // ZR/ZL
        if(keyname[1]=='R'||keyname[1]=='r'){
          SwitchControlLibrary().PressButtonZR(); delay(holdtime);
          if(holdtime>0)SwitchControlLibrary().ReleaseButtonZR(); delay(delaytime);
        }
        if(keyname[1]=='L'||keyname[1]=='l'){
          SwitchControlLibrary().PressButtonZL(); delay(holdtime);
          if(holdtime>0)SwitchControlLibrary().ReleaseButtonZL(); delay(delaytime);
        }
      break;
      case 'r': case 'R': // right
        SwitchControlLibrary().MoveHat(2); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().MoveHat(8); delay(delaytime);
      break;
      case 'l': case 'L': // left
        SwitchControlLibrary().MoveHat(6); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().MoveHat(8); delay(delaytime);
      break;
      case 'u': case 'U': // up
        SwitchControlLibrary().MoveHat(0); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().MoveHat(8); delay(delaytime);
      break;
      case 'd': case 'D': // down
        SwitchControlLibrary().MoveHat(4); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().MoveHat(8); delay(delaytime);
      break;
      case 'H': case 'h': // Home
        SwitchControlLibrary().PressButtonHome(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonHome(); delay(delaytime);
      default:
      break;  
    }
  }else{
    return -1;
  }
  return strlen(keyname);
}
void NextDayInCheatMode(){
  // ★日付変更
  // Homeボタンを押して設定の画面へ移動
  PushKey("Home", HOLDTIME, 1000);

  // Home画面で「設定」を選ぶ
  PushKey("down", HOLDTIME, 105);
  PushKey("right", HOLDTIME, 105);
  PushKey("right", HOLDTIME, 105);
  PushKey("right", HOLDTIME, 105);
  PushKey("right", HOLDTIME, 105);
  PushKey("right", HOLDTIME, 105);
  PushKey("A", HOLDTIME, 1500);

  // 設定画面で「日付と時刻」を開く
  PushKey("down", 1500, 105); // 1.5秒「↓」長押し
  PushKey("right", HOLDTIME, 105); 

  for(int i=0; i<4; i++){
    PushKey("down", HOLDTIME, 55);
  }
  PushKey("A", HOLDTIME, 500);

  // 時間設定(現在の日付と時刻を選ぶ)
  PushKey("down", HOLDTIME, 105);
  PushKey("down", HOLDTIME, 105);
  PushKey("A", HOLDTIME, 500);

  // 時刻設定(日付の部分のみ回していく
  // 時間の変更
  PushKey("right", HOLDTIME, 105);
  PushKey("right", HOLDTIME, 105);
  PushKey("up",    HOLDTIME, 105);
  PushKey("A", HOLDTIME, 105);
  PushKey("A", HOLDTIME, 105);
  PushKey("A", HOLDTIME, 105);
  PushKey("A", HOLDTIME, 105);
  PushKey("Home", HOLDTIME, 2000);
  PushKey("A", HOLDTIME, 1000);
  return;
}

void input_serial(char *str){
  char keyboard[4][15]={
    "1234567890@",
    "QWERTYUIOP=",
    "ASDFGHJKL&;",
    "ZXCVBNM*#!?"
  };
  int cur_x=0, cur_y=0; // 現在カーソル位置
  int x,y; // 目標キーボード位置
  int i=0;
  char *p;

  // ★すべて大文字に変換
  toupper(str);

  // ★剣盾のキーボードはZ,I,Oは不使用(それぞれ2,1,0に置き換え)
  for(i=0; str[i]!='\0' ;i++ ){
    switch(str[i]){
      case 'Z':
        str[i]= '2';
        break;
      case 'I':
        str[i]= '1';
        break;
      case 'O':
        str[i]= '0';
        break;
      default:
        break;
    }
  } 

  // ★入力する文字列strを1文字ずつ処理
  for(i=0; str[i] != '\0' ; i++ ){

    // 空白文字は読み飛ばし(例:"P25M US1"みたいなやつ)
    if(str[i] == ' ' ) continue;

    // キーボードから該当文字を検索(x,yを決定)
    for(x=0; x < 4 ; x++){
       p = strchr(keyboard[x], str[i]);
       if( p == NULL){ continue;
       }else{
         for(y=0; keyboard[x][y] != *p ; y++);
         break;
       }
    }
    delay(100);
    // y(左右位置)
    if(cur_y != y){
      for( ; cur_y < y ; cur_y++) PushKey("Right", HOLDTIME, 150);
      for( ; cur_y > y ; cur_y--) PushKey("Left", HOLDTIME, 150);
    }
    // x(上下位置)
    if(cur_x != x){
      for( ; cur_x < x ; cur_x++) PushKey("DOWN", HOLDTIME, 150);
      for( ; cur_x > x ; cur_x--) PushKey("UP", HOLDTIME, 150);
    }
    // 入力
    PushKey("A", HOLDTIME, 150);
  }
  

  return;
}

f:id:tangential_star:20210227012752g:plain

動作確認(再掲)。自動でふしぎなおくりものを開き、受け取ってくれる


あとがき

今回は、ポケモン25周年ということで、記念して配布されている「うたうを覚えた特別なピカチュウ」をArduinoで受け取りました。

Arduino自動化の記事と言いつつ、まずはポケモンのファンとして、心の底から25周年をお祝いします

自身が初めて出会ったポケモン作品が「金・銀」で、そこから遡る形で「赤・緑」も遊び、今に至るまでにポケモン本編作品についてはほぼすべてを遊んできました。どの作品にも思い入れがありますが、これだけシリーズを通してのめり込めたゲームは「ポケモン」だけです。自分の人生はポケモンとともにあった、と言っても過言で無い気もします。

そして、その遊び方も、「図鑑集め」「コンテスト制覇」「リボン集め」「育成・対戦」「ポケモンとの触れ合い」「色違い厳選」など、ずっと飽きることなく、たくさん広がりました。そして、ポケモン剣盾では、新たな遊び方として「Arduino自動化」が加わったような形です。

私にとってポケモンは、かけがえの無いゲームで、遊びごたえもキャラクタ性も、シナリオも全部が全部、大好きなのです。この25周年という節目の日に、こうやってブログで気持ちをしたためることができるのも、本当に光栄ですし、これからのポケモンの作品も楽しみで仕方がありません。

そういう意味では、ちょうど今日未明に新作「ブリリアントダイヤモンド」「シャイニングパール」のティザームービーも公開されましたが、今から発売日(2021年冬)が待ち遠しくてしょうがないです。25年分のワクワク、しっかりと温めておきたいです。

なにはともあれ、改めてポケモン25周年、おめでとうございます。

 

さて、話がだいぶ逸れました。

皆様のポケモンライフが、あるいはArduino自動化ライフが、このブログにより一助となれば幸いです。ではではc⌒っ.ω.)っ

 

前記事:【Arduino自動化16】自動ミラクル交換(ID集めほか)

導入記事:【Arduino自動化01】Arduino開発環境の導入

 

【Arduino自動化16】自動ミラクル交換(ID集めほか)

ますたーです。こんにちは。

今回は、自動でボックスのポケモンをマジカル交換(旧:ミラクル交換)に出し続けます。

※本記事ではポケモンを「交換に出します」。利用に際してはくれぐれも自己責任でお願いします

 Arduino自動化記事はこれで第16回。これからもよろしくお願いします。

 

なお、Arduino Leonardo自動化の導入・機材構成については導入記事を参考にしてください。

導入記事:【Arduino自動化01】Arduino開発環境の導入

※本ブログに初めてお越しの方は「本ブログについて」もぜひ、ご覧ください。

 

概要

本記事では、YY通信のマジカル交換(旧:ミラクル交換)を自動で繰り返し行います。「孵化余り」の有効活用や、ロトミIDくじ用のID集めなどにお役立てください。

※2021年2月19日AM9時追記:本稿中の「ミラクル交換」はすべて「マジカル交換」の誤りです。過去作品に引っ張られました。以降、適宜読み替えてください

f:id:tangential_star:20210213121954g:plain
f:id:tangential_star:20210213121616p:plain
マジカル交換(ミラクル交換)を自動で行う。待機時間など含め1回あたり約2分20秒ほど

では、目次です。

ソースコードのみ欲しいという方はどうぞコチラから⇒読み飛ばす

 

ラクル交換でID集め(ロトミIDくじを効率的に)

ラクル交換の大きな特徴は、何よりも交換先が全国不特定多数のポケモントレーナーであることです。ポケモン剣盾での「おやID」は6桁なので、32ボックス960匹をランダムに交換し続けたとしても、これらの間で重複が起こる可能性はほぼ0です

※無作為の960匹について、これらでIDが重複する確率は単純計算で 1-(1-1/106)960=0.09595%

おやIDをたくさん集めることで、ロトミIDくじの当選確率もアップします。例えば、50種類のおやIDを入手しておくと「はずれ」が出る確率が1%を下回ったり、100種類のおやIDがあれば50%以上の確率で「ポイントアップ」が手に入るようになったりと、非常にお得です。【Arduino自動化14】ロトミIDくじ無限抽選では、このあたりの、IDの数と当選確率の話も纏めているので、合わせてご参考いただければと思います。

f:id:tangential_star:20210204135040g:plain
f:id:tangential_star:20210203180947p:plain
たくさんのIDがあれば、ロトミIDくじ当選確率もアップ!

要するに、ミラクル交換で他人産IDのポケモンを50匹程度を集めておけば、ロトミIDくじが、まさにソシャゲの「ログインボーナス」のようになるのでおすすめです。

ほとんど毎日「ポイントアップ」が貰えて、時々「ポイントマックス」が貰えるとなれば、毎日のポケモンのモチベーションが大きく上がりますよね。

 

他人の孵化余りも手に入る

ラクル交換のもう一つの魅力、それは、孵化余りを流すプレイヤーも多いということ。私も含め、孵化余りは積極的にGTSポケモンHOMEでの交換、ミラクル交換に出していますが、ID集めはもちろん、これは何よりも他人の孵化余りを手に入れられるから。

現在、環境で流行っているポケモンの孵化余りが手に入ったり、有用なタマゴわざを持ったポケモンうたかたのアリア持ちラプラス、じばく持ちゴンベなど)などが手に入りやすく、対戦ガチ勢にも嬉しい仕様ですね。

f:id:tangential_star:20210218224023p:plain
f:id:tangential_star:20210218224028p:plain
有用なタマゴわざを覚えていたり、希少価値の高いオシャボに入っていたりも多い

つまりは、個体値ポケモン夢特性ポケモンタマゴわざを持っているポケモンおしゃれボールに入ったポケモンなどを手に入れることもできます。特に海外産ポケモンも手に入りやすく、これらを活用するとタマゴ孵化による色違い厳選もはかどります

ちなみに、全自動タマゴ孵化については本ブログでも取り扱っています。合わせてご参考いただければ幸いです⇒【Arduino自動化12】全自動タマゴ受け取り&孵化

 

準備(プログラムの書き換え)

ラクル交換をたくさん行うにあたっては、大量のポケモン準備する必要があります。また、効率的に通信交換をするためにも、図鑑は完成させておくと良いでしょう。

さて、本稿で扱う自動化プログラムについても、必要に応じて4箇所書き換える必要があります。

通信交換するポケモンの数

1箇所目は、何匹のポケモンを交換に出すかです。MAX_TRADE_POKEMONにて指定してください。必ずしも30の倍数である必要はありませんが、左詰めにあずけておいてください。

#define MAX_TRADE_POKEMON (30*3-5)
// ★何匹通信交換するか?【重要】

ラクル交換の待ち時間

2箇所目は、ミラクル交換の待機時間です。具体的には、YY通信で「ミラクル交換」を選んでフィールドに戻ってから「交換完了!」の文字が出るまでの待機時間です。

概ね30秒あればマッチングすることが多いですが、時々マッチングに時間がかかり、50秒ほどかかることもあります。皆様の環境に合わせて数字を記入してください。

数字は、WAIT_TIME_FOR_MATCHINGに単位「秒」で記入してください。

#define WAIT_TIME_FOR_MATCHING (45) 
// ★通信交換を何秒待つか?(単位:秒)

なお、この時間指定が短すぎると、その次のループでうまく交換ができませんので注意しましょう。45秒で設定した筆者実証時には、85回の交換中3回、45秒以内での通信交換に失敗しています。もし、時間に余裕のある人は、60秒などの充分に大きな数字を設定しておくと良いかもしれません。

図鑑の状況と通信進化ポケモン

3箇所目・4箇所目は、ポケモン図鑑の完成状況(新たに登録される可能性があるかどうか)と、受け取ったポケモンが進化する可能性を考慮するかどうかです。これらは数字ではなく、trueまたはfalseを記入します。

ポケモン図鑑が完成している場合はPOKEDEX_COMPLETEDにtrueを指定してください。また、通信交換で進化するポケモンを無視する場合はIGNORE_EVOLVEをtrueにしてください。デフォルトでは、ポケモン図鑑は完成済(true)・通信進化ポケモンは無視しない(false)になっています。

 

#define POKEDEX_COMPLETED (true) 
// ★ポケモン図鑑は完成済か?【重要】

 

#define IGNORE_EVOLVE (false)
// ★通信進化ポケモンは来ない前提とするか?【重要】

 

ポケモン図鑑に登録されていないポケモンを交換で受け取った場合、その図鑑説明の画面が出てきます。こちらは、たかだか5秒程度のロスなので、図鑑完成していない人も、あまり気にならないかもしれません。

一方で、バケッチャパンプジンに進化)などの通信進化するポケモンを受け取った場合、そのポケモンの進化画面が発生してしまいます。この進化ポケモン、数は20数匹と多めで、意外と受け取る機会が多いです。

通信進化は長くて20秒は時間を取られるので、よほど受け取らない自信が無い限りは、IGNORE_EVOLVEをfalseにしておきましょう。

特に、稀有な機会ではありますが、メタルコート持ちストライクの場合、進化時に「バレットパンチ」を覚えようとするため、そういうところもケアする必要があります。

f:id:tangential_star:20210218233952g:plain

バケッチャなど、通信交換で進化するポケモンを受け取る機会は意外と多い。注意しよう

 

実際に自動化ミラクル交換を試してみた

早速、85匹のパッチルドンを用意して、ミラクル交換のArduino自動化を実装&試してみました。

 

f:id:tangential_star:20210218234741g:plain
f:id:tangential_star:20210218234922g:plain
85匹のパッチルドンでミラクル交換!所要時間3時間20分の大半は待ち時間だ

設定は1試行あたり45秒の待機時間ポケモン図鑑は完成済、進化ポケモンは無視しない想定で、かかった時間は約3時間20分でした。1回の交換にかかる時間を平均すると約2分20秒となります。

なお、特筆すべき点として、待機時間を45秒に設定で、85回の通信交換中、3回はこの時間内に通信交換が成立せず、それぞれの翌試行分の交換が失敗しています。ゆえに、通信交換に成功したのは82匹です(いずれの試行も、通信交換に失敗した次の試行でループが復帰していました)。一応、これを避けるためには、待機時間を冗長に設定する他はありません。体感としては、60秒ほどあれば通信交換がほぼ成立すると考えます。

ちなみに、82匹の交換が成立したわけですが、そのうち1回のみ、通信交換するポケモンバケッチャ)を受け取っています。約80回に1回(確率にすれば約1.25%)ですし、もし「全体的に時間効率を高めたい」という人は、IGNORE_EVOLVEを(true)にしても良いかもしれません。

f:id:tangential_star:20210218234725g:plain

ラクル交換後のボックス。オシャボ入が7匹、準伝説3匹など上々の結果

 

ソースコード

さて、実際に使ったソースコードです。

使い方は簡単。ボックスを左詰めにした後、ポケモン剣盾をインターネット接続し、Arduinoを挿し込むだけ。

ただし、前述の通り、4箇所は各人のステータスに応じて書き換えてください。

/* 
 *  マジカル交換自動化
 *  
 *  ボックスは交換を始める先頭&左詰めにしておくこと。
 *  野生ポケモンが近くに発生しない環境で使うこと!
 *  (重くならない、ワイルドエリア「外」+オブジェクトが少ない場所を推奨)⇒シュートシティのタワー前とか?
 *  あとはYY通信がオンラインになっている状態でArduino差し込むだけ!
 *  (c) 2021 ますたーの忘備録
 *  https://tangential-star.hatenablog.jp/
*/

#include <SwitchControlLibrary.h>

#define HOLDTIME (95) // 1回のキー入力の長押し時間


// 実測値メモ 45秒指定で、85匹交換=合計3時間14分45秒[1試行平均137秒]
// [うち、交換失敗3回・改造と思しき個体3匹]

#define MAX_TRADE_POKEMON (30*3-5)
// ★何匹通信交換するか?【重要】
// ボックスの中で交換するポケモンの数を入れましょう。
// ※無論、ボックスの中身は左詰めでお願いします。

#define WAIT_TIME_FOR_MATCHING (45) 
// ★通信交換を何秒待つか?(単位:秒)
// 実際の待ち時間が上記指定時間をを超えた場合など、短すぎるとずれる可能性あり。
// 2順目でズレを吸収し、3順目から正式に進行するはずだが、この事象が発生したタイミング
// 如何によってはボックスの遷移が正しく行われない可能性あり。
// ※時間に余裕がある場合は、確実に交換できるよう「充分に長い時間(75など)」にしておくと安心。
// 特に深夜帯25:30を回ると45では心許なくなる。

#define POKEDEX_COMPLETED (true) 
// ★ポケモン図鑑は完成済か?【重要】
// 完成済の人は「true」にしてください
// 新規ポケモン受取時に図鑑登録ダイアログ出現を考慮するかどうかです。
// ※未完成の挙動は筆者未検証です!(そのへんの動画見て時間合わせしてるので動かないかも)

#define IGNORE_EVOLVE (false)
// ★通信進化ポケモンは来ない前提とするか?【重要】
// 進化後のポケモン例:フーディン・カイリキー・ゲンガー・ヤドキング・ニョロトノ・ハガネール・ハッサム・
// キングドラ・ポリゴン2・ミロカロス・ポリゴンZ・ドサイドン・エレキブル・ブーバーン・ヨノワール・
// ギガイアス・ローブシン・フレフワン・ペロリーム・オーロット・パンプジン・シュバルゴ・アギルダー
// ※コイツら↑を受け取らない前提なら「true」にしてください(非推奨)
// ※参考までに、筆者は本デバッグ中にバケッチャを受け取りました(パンプジンに進化しました)。わずか33試行目でした。


void PushRL(int delay_time_ms);
int PushKey(char* keyname, int holdtime, int delaytime);
void NextDayInCheatMode(void);

void YYconnection_start(int which_pokemon);
void YYconnection_receive(void);

void setup() {
  // コントローラーとして認識されるためにRLを7回ほどカチャカチャする
  for(int i=0;i<7;i++)PushRL(300);
  delay(1000);
}


void loop() {
  int num_pokemon; // 規定回数入れ替えたら
  for(num_pokemon=1; num_pokemon <= MAX_TRADE_POKEMON ; num_pokemon++){
    YYconnection_start(num_pokemon);
    delay( (unsigned long int)WAIT_TIME_FOR_MATCHING*1000UL );
    YYconnection_receive();
  }
  for(;;) delay(100); // プログラム終了
}

void PushRL(int delay_time_ms){
  SwitchControlLibrary().PressButtonR();
  SwitchControlLibrary().PressButtonL();
  delay(HOLDTIME);
  SwitchControlLibrary().ReleaseButtonR();
  SwitchControlLibrary().ReleaseButtonL();
  delay(delay_time_ms);
  return;
}
int PushKey(char* keyname, int holdtime, int delaytime){
  // ホームボタン・方向キーはRight, Left, Up, Down, Homeなど2文字以上で入力。
  // その他ボタン入力は1文字(A,B,X,Y,R,L,+,-)ZR・ZLにも対応
  // 同時押しは非対応
  
  if(strlen(keyname)==1){
    switch(keyname[0]){
      case 'A': case 'a': // A
        SwitchControlLibrary().PressButtonA(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonA(); delay(delaytime);
      break;
      case 'B': case 'b': // B
        SwitchControlLibrary().PressButtonB(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonB(); delay(delaytime);
      break;
      case 'X': case 'x': // X
        SwitchControlLibrary().PressButtonX(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonX(); delay(delaytime);
      break;
      case 'Y': case 'y': // Y
        SwitchControlLibrary().PressButtonY(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonY(); delay(delaytime);
      break;
      case 'L': case 'l': // L
        SwitchControlLibrary().PressButtonL(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonL(); delay(delaytime);
      break;
      case 'R': case 'r': // R
        SwitchControlLibrary().PressButtonR(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonR(); delay(delaytime);
      break;
      case 'H': case 'h': // Home
        SwitchControlLibrary().PressButtonHome(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonHome(); delay(delaytime);
      break;
      case '+': case 'p': case 'P': // Plus
        SwitchControlLibrary().PressButtonPlus(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonPlus(); delay(delaytime);
      break;
      case '-': case 'm': case 'M': // Minus
        SwitchControlLibrary().PressButtonMinus(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonMinus(); delay(delaytime);
      break;
      default:
      break;
    }
  }else if(strlen(keyname)>=2){
    switch(keyname[0]){
      case 'z': case 'Z': // ZR/ZL
        if(keyname[1]=='R'||keyname[1]=='r'){
          SwitchControlLibrary().PressButtonZR(); delay(holdtime);
          if(holdtime>0)SwitchControlLibrary().ReleaseButtonZR(); delay(delaytime);
        }
        if(keyname[1]=='L'||keyname[1]=='l'){
          SwitchControlLibrary().PressButtonZL(); delay(holdtime);
          if(holdtime>0)SwitchControlLibrary().ReleaseButtonZL(); delay(delaytime);
        }
      break;
      case 'r': case 'R': // right
        SwitchControlLibrary().MoveHat(2); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().MoveHat(8); delay(delaytime);
      break;
      case 'l': case 'L': // left
        SwitchControlLibrary().MoveHat(6); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().MoveHat(8); delay(delaytime);
      break;
      case 'u': case 'U': // up
        SwitchControlLibrary().MoveHat(0); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().MoveHat(8); delay(delaytime);
      break;
      case 'd': case 'D': // down
        SwitchControlLibrary().MoveHat(4); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().MoveHat(8); delay(delaytime);
      break;
      case 'H': case 'h': // Home
        SwitchControlLibrary().PressButtonHome(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonHome(); delay(delaytime);
      default:
      break;  
    }
  }else{
    return -1;
  }
  return strlen(keyname);
}
void NextDayInCheatMode(){
  // ★日付変更
  // Homeボタンを押して設定の画面へ移動
  PushKey("Home", HOLDTIME, 1000);

  // Home画面で「設定」を選ぶ
  PushKey("down", HOLDTIME, 105);
  PushKey("right", HOLDTIME, 105);
  PushKey("right", HOLDTIME, 105);
  PushKey("right", HOLDTIME, 105);
  PushKey("right", HOLDTIME, 105);
  PushKey("right", HOLDTIME, 105);
  PushKey("A", HOLDTIME, 1500);

  // 設定画面で「日付と時刻」を開く
  PushKey("down", 1500, 105); // 1.5秒「↓」長押し
  PushKey("right", HOLDTIME, 105); 

  for(int i=0; i<4; i++){
    PushKey("down", HOLDTIME, 55);
  }
  PushKey("A", HOLDTIME, 500);

  // 時間設定(現在の日付と時刻を選ぶ)
  PushKey("down", HOLDTIME, 105);
  PushKey("down", HOLDTIME, 105);
  PushKey("A", HOLDTIME, 500);

  // 時刻設定(日付の部分のみ回していく
  // 時間の変更
  PushKey("right", HOLDTIME, 105);
  PushKey("right", HOLDTIME, 105);
  PushKey("up",    HOLDTIME, 105);
  PushKey("A", HOLDTIME, 105);
  PushKey("A", HOLDTIME, 105);
  PushKey("A", HOLDTIME, 105);
  PushKey("A", HOLDTIME, 105);
  PushKey("Home", HOLDTIME, 2000);
  PushKey("A", HOLDTIME, 1000);
  return;
}

void YYconnection_start(int which_pokemon){
  // (注)which_pokemonはボックスの何匹目を交換に出すか?
  // 1 <= which_pokemon <= 30 (0<29ではないので注意)

  static int shift_box = 0; // ボックスで「R(次のボックスに変える)」を押すタイミング見計らい
  
  PushKey("Y", HOLDTIME, 1300);
  PushKey("Down", HOLDTIME, 700);
  PushKey("A", HOLDTIME, 2700);

  int col=0, row=0;
  col = (which_pokemon -1) % 6; 
  row = ((which_pokemon -1)%30) / 6;

  // 31匹目以降は必要に応じてRキーで次のボックスを参照する
  if((which_pokemon -1) / 30 == 1+shift_box){
    PushKey("R", HOLDTIME, 1600);
    shift_box++;
  }

  for(int i = 0 ; i < col ; i++ ){
    PushKey("Right", HOLDTIME, 170);
  }
  for(int i = 0 ; i < row ; i++ ){
    PushKey("Down", HOLDTIME, 170);
  }
  PushKey("A", HOLDTIME, 700);  // ○○を どうしますか?
  PushKey("A", HOLDTIME, 6000); // ⇒えらぶ ~ レポートを書いて マジカル交換を 始めても よろしいですか?
  PushKey("A", HOLDTIME, 900);  // ⇒はじめる ~ 通信できる 人を 探します! ▼
  PushKey("B", HOLDTIME, 900);  // 通信する 項目を 選ぶと 探すのを キャンセルできます ▼
  PushKey("B", HOLDTIME, 3000); // レポートをかいています。
  
  return;  
}
void YYconnection_receive(void){
  delay(100);
  PushKey("Y", HOLDTIME, 1300);
  PushKey("B", HOLDTIME, 1000); // ループ破綻防止用(想定待ち時間を超えて受け取り損ねた場合のケア)
  PushKey("B", HOLDTIME, 1000); // 予備

  // 通信交換(27秒待つ)
  delay(27*1000UL);

  // 通信進化ポケモン受取時のループ破綻防止   
  if(!IGNORE_EVOLVE){
    delay(6*1000UL); // 暗転画面で6秒
    delay(7*1000UL); // 鳴き声含め5秒
    PushKey("A", HOLDTIME, 13000); // ……おや!? ○○の 様子が……! ▼ 
    PushKey("A", HOLDTIME, 3500);  // おめでとう! ○○は ○○に 進化した!▼

    // 進化時にわざを覚えるポケモン(ハッサム=バレットパンチなど)対応
    PushKey("B", HOLDTIME, 1100);    // ○○は 新しく ○○を 覚えたい…… ▼
    PushKey("Down", HOLDTIME, 1100); // ○○の かわりに 他の 技を 忘れさせますか?
    PushKey("A", HOLDTIME, 1400);    // ⇒忘れさせない
    PushKey("B", HOLDTIME, 3000);    // ○○は ○○を 覚えずに 終わった! ▼
    
    delay(4*1000UL); // 暗転終了後、明転して次画面に
  }
  PushKey("B", HOLDTIME, 300); // 予備
  PushKey("B", HOLDTIME, 300); // 予備
  PushKey("B", HOLDTIME, 300); // 予備
  delay(2*1000UL); // 予備
  if(POKEDEX_COMPLETED) return; // ポケモン図鑑完成済なら以降のダイアログ出現なし

  PushKey("B", HOLDTIME, 1000); // ○○の データが 新しく ポケモン図鑑に 登録されます!▼
  PushKey("B", HOLDTIME, 2000);
  if(!IGNORE_EVOLVE){ // 進化ポケモンも未登録の場合
    PushKey("B", HOLDTIME, 3000);
    PushKey("B", HOLDTIME, 1000); // ○○の データが 新しく ポケモン図鑑に 登録されます!▼
    PushKey("B", HOLDTIME, 2000);
  }
  PushKey("B", HOLDTIME, 300); // 予備

  return;
}

 

あとがき 

今回は16回目のArduino自動化記事として、ミラクル交換の自動化を紹介しました。

自分で実装してみて、思った以上にデバッグが大変だと思いました。長時間放置することが前提のプログラムゆえに、挙動を見守るのが大変で、コーディングをする時間よりも、本当に動くのか?を見守る時間のほうが10倍くらい長かった気がします。

私の本職は、プログラマでもデバッガーでもSEでも無いですが、本当にデバッグという作業は心がポキっと行くんだろうな、と漠然と感じました。

 

さて、話が逸れましたね。

今回のミラクル交換の実装により、今まで作ったプログラムが更に相互に利用しやすくなったな、と感じます。

具体的には、下記のようなサイクルでポケモンを遊び続けられるなぁと。

  1. 【Arduino自動化12】全自動タマゴ受け取り&孵化で色違い厳選など
  2. タマゴ孵化を経て、余ったポケモンたちを他人産ポケモンと交換(本稿)
  3. 集まったIDを使って【Arduino自動化14】ロトミIDくじ無限抽選
  4. 抽選後、不要なポケモン【Arduino自動化13】全自動ポケモン逃がしでリリース
  5. オシャボや海外産ポケモンを活用し、タマゴ孵化厳選へ(1に戻る)

ほかにも、育成用アイテムは例えば【Arduino自動化11】5番道路で全自動羽集めなどで端数の努力値振りも対応できますし、「とくせいパッチ」などは【Arduino自動化06】完全放置「マックスこうせき」集め【ダイマックスアドベンチャー】で手に入れられるんですよね。

そういう意味で、Arduinoの自動化は、ポケモンの遊び方を深めることも、作業の代替もできるんだな、と改めて感じました。

 

皆様においても、このブログの記事ほかがお役立ていただければ幸いです。

 

ではではc⌒っ.ω.)っ

 

前記事:【Arduino自動化15】ラテラルタウン掘り出し物自動購入

次記事:【Arduino自動化17】ふしぎなおくりもの受け取り【あいことば自動入力】

導入記事:【Arduino自動化01】Arduino開発環境の導入 

 

【Arduino自動化15】ラテラルタウン掘り出し物自動購入

ますたーです。こんにちは。

今回は、いわゆるランクマバグ状態で「掘り出し物」を買い続ける自動化記事です。

第15回目のArduino自動化記事。引き続きよろしくお願いします。

 

なお、Arduino Leonardo自動化の導入・機材構成については導入記事を参考にしてください。

導入記事:【Arduino自動化01】Arduino開発環境の導入

※本ブログに初めてお越しの方は「本ブログについて」もぜひ、ご覧ください。

 

概要

本記事では、ランクマバグ状態による自動「ほりだしもの」購入を実装します。
※便宜上「ランクマバグ」と表記しますが、当ブログではランクマッチを使用しません。通信切断・初手降参の推奨もしません。

 

NintendoSwitch Ver.11.0アップデート対応済です。
★2021/9/20追記:NintendoSwitch Ver.13.0アップデート対応済です。
★2022/10/23追記:NintendoSwitch Ver.15.0アップデート対応済です。

f:id:tangential_star:20210211120145g:plain
f:id:tangential_star:20210211120226p:plain
ほりだしもの市で自動購入。「ぼうごパット」はここでしか手に入らない超レアアイテム

 

では、目次です。

相変わらず余談多めですので、ソースコードだけ欲しいという方は⇒読み飛ばす

 

ほりだしもの市でしか手に入らない「ぼうごパット」

余談を挟む余地もなく、最初に結論から話します。なぜ掘り出し物市を自動化するのか、その理由は、ここでしか買えないアイテム「ぼうごパット」があるからです。

また、ここでの入手が現実的なアイテムも複数あるのも魅力ですね。

f:id:tangential_star:20210211125124p:plain
f:id:tangential_star:20210211125118p:plain
「ぼうごパット」の他、野生のワンリキーがたまに(5%)持っている「きあいのハチマキ」なども買える

ここからはすこしだけ、余談をはさみます。

「『ぼうごパット』についてはいい、他のアイテムは何が手に入るんだ」という方は⇒読み飛ばす

どうぐ「ぼうごパット」の希少性

ガラル地方では本編(DLC含まず)において入手が困難なアイテムがいくつかあります。その中の筆頭として挙がるのはおそらく、「かえんだま」と「どくどくだま」※1、「マスターボール※2」「各種ガンテツボール※3」などでしょうか。なぜかは言わずもがな、これらは原則として「運」でしか手に入らないからです。

※1「かえんだま」「どくどくだま」はDLC・配布を除くと、トーナメントでの勝利報酬でしか入手できません
※2「マスターボール」はシナリオ内で1個+IDくじの特等で入手できます
※3「各種ガンテツボール」はシナリオ内で各1個+トーナメントでの勝利報酬で入手できます

さて、前述の通り「ぼうごパット」は、ラテラルタウンの「ほりだしもの市」でしか入手できない貴重なアイテムです。

しかも、上記「かえんだま」「どくどくだま」「ガンテツボール」などとは違い、剣盾発売から1年以上経った2021年2月11日現在において1度たりとも配布されたりレイド報酬になったりしたことがない「正真正銘」ここでしか手に入らないアイテムです。また、DLCで拾えたり作れたりするようになった「かえんだま」等とも違い、DLCを含めても入手方法がここだけです。如何に「ぼうごパット」がレアかがお分かりいただけたかと思います。

f:id:tangential_star:20210211144958p:plain
f:id:tangential_star:20210211144818g:plain
鎧の孤島では、ウッウロボで「たいようのいし」4つを合成すると「かえんだま」になる

どうぐ「ぼうごパット」の効果

そんな幻の超激レアアイテム「ぼうごパット」は、多少ピンポイントながら効果も優秀。その驚きの効果は「直接攻撃に対して発動するわざ・とくせい・どうぐの効果を受けない」というもの。

メジャーどころでは「せいでんき」「ほうし」「さめはだ」「てつのトゲ」など、直接攻撃した際に発動する特性をほぼシャットアウトできます。また、追加効果が非常に厄介な守備技「ブロッキング(防御2段階ダウン)」「トーチカ(どく状態付与)」「ニードルガード(最大HPの1/8ダメージ)」などの追加効果を無効化できます。

さらに、どうぐゴツゴツメット」の効果も無効にできるので、例えばナットレイには2重の意味で強く出られますし、ゴツメサンダー@夢(せいでんき)にも強く出られるかもしれませんね。

f:id:tangential_star:20210211145003p:plain
f:id:tangential_star:20210211143034g:plain
わざ「ブロッキング」の厄介な防御2段階ダウン効果を「ぼうごパット」で無効化できる
f:id:tangential_star:20210211144850g:plain
f:id:tangential_star:20210211143000g:plain
「ぼうごパット」があれば、相手の特性「てつのトゲ」「さめはだ」などを無効化できる

ただ、ここまで持ち上げておいてなんですが、皆様もよくご存知の通り対戦ではほとんど使われません。つまりは読まれにくい、ということだと思うので誰か使ってみてください。

 

ほりだしもの市で入手できる道具

さて、大きく話が逸れたので、一旦ラテラルタウンの話題に戻します。

ほりだしもの市では、1日に1回、露天商のお兄さんから3,000円でその日のほりだしものを購入することができます。また、前日に購入していなかった場合は、前日のほりだしものも5,000円で購入することができます。

目玉商品は前述の「ぼうごパット」ですが、有用なアイテムや他の入手方法が困難or現実的ではないアイテムも売られることがあるため、そちらも狙い目です。

いちおう、筆者的に狙い目のものには、黄色で網掛けしています。入手方法について特にコメントしていないものは、道中で拾えたり貰えたりするものです。

ラテラルタウンほりだしもの市で買えるもの一覧
店頭に並ぶ頻度 なまえ 用途 入手方法または筆者コメント
非常に多い われたポット ヤバチャ(がんさくフォルム)の進化用 実はガラル地方のどこにも落ちていない。DLC2弾「巨人の寝床」でドロップ報告あり。
多い するどいツメ 急所率が1段階上がる。夜にはニューラの進化にも 進化に使うが、ニューラは持っていない。ちなみにピントレンズと同じ効果。
多い プロテクター サイドンの通信進化用 第4世代では1個しか手に入らない貴重アイテムだったのに…
多い れいかいのぬの サマヨールの通信進化用 DPではギラティナ捕獲後、最奥の部屋にあるアイテムだった。でもギラティナは関係ない
ときどき せんせいのツメ 20%で先制攻撃できる ニューラが5%で持っている。ここで手に入れよう。
ときどき メタルコート はがねタイプのわざの威力が1.2倍に。イワーク等の通信進化にも。 穴掘り兄弟が掘り当ててくれるので結構余りがち。進化アイテムなのに効果がある。
まれ かけたポット ヤバチャ(しんさくフォルム)の進化用 ポケセンで売ると19,000円に化ける。まさに文字通りの掘り出し物。
まれ きあいのハチマキ ひんし相当の被ダメージ時、10%の確率でHP1で耐える ワンリキーが5%で持っている。ここで手に入れよう。
まれ きせきのタネ くさタイプのわざの威力が1.2倍になる 特にコメントが思いつかない。
まれ くろいヘドロ どくタイプは毎ターン1/16回復。それ以外は1/8ダメージ ドヒドイデのイメージが強いが、野生で持っているのはグレッグル系列とダストダス
まれ しめつけバンド わざ「しめつける」の毎ターンダメージが1/8⇒1/6になる かつては幻の超激レアアイテムだったDLC第2段冠の雪原で開放。
まれ しんぴのしずく みずタイプのわざの威力が1.2倍になる 実はラプラスが100%持っている。2番道路でランダムに会えるぞ。
まれ どくバリ どくタイプのわざの威力が1.2倍になる ハリーセンロゼリア系列・スコルピ系列が5%で持っている。
まれ ねらいのまと 相性無効タイプの被ダメージが等倍で当たるようになる DLC第1段ウッウロボ以外では入手不可。こいつも幻の超激レアアイテムだった
まれ のろいのおふだ ゴーストタイプのわざの威力が1.2倍になる ヨマワル系列が5%で持っている。ここで手に入れよう。
まれ ぼうごパット 直接攻撃に対して発動するわざ・とくせい・どうぐの効果を受けない 幻の超激レアアイテム。文字通りここでしか手に入らない!ちなみに「パッド」ではない
まれ まがったスプーン エスパータイプのわざの威力が1.2倍になる ケーシィが5%で持っている。ここで手に入れよう。
まれ メトロノーム 同じわざを繰り返し使うと威力アップ(+20%ずつ/最大+100%) かつては幻の超激レアアイテムだったDLC第2段冠の雪原で開放。
まれ もくたん ほのおタイプのわざの威力が1.2倍になる 金銀では9,800円で買えた=売価4,900円だったが、今作では500円にしかならない。
まれ りゅうのキバ ドラゴンタイプのわざの威力が1.2倍になる DLC第1段ウッウロボ以外では入手不可。こいつも幻の超激レアアイテムだった
ごくまれ ぎんのこな むしタイプのわざの威力が1.2倍になる コメント特になし。4番道路で拾えるそうです。
ごくまれ するどいくちばし ひこうタイプのわざの威力が1.2倍になる コメント特になし。これも4番道路で拾えるそうです。
ごくまれ くろいメガネ あくタイプのわざの威力が1.2倍になる RSEでカナシダトンネルを抜けたところで拾ったときのイベントが思い出です。
ごくまれ くろおび かくとうタイプのわざの威力が1.2倍になる 金銀ではいかりのみずうみで水曜にミズオから貰えたが、いあいぎり必須なので不便。
ごくまれ じしゃく でんきタイプのわざの威力が1.2倍になる 金銀では日曜日のニチオから貰えた。個人的に初めて出会った曜日兄弟でした。
ごくまれ シルクのスカーフ ノーマルタイプのわざの威力が1.2倍になる RSEではマッスグマにもたせていました。まさか今作であくタイプになるとは…
ごくまれ せいれいプレート フェアリータイプのわざの威力が1.2倍になる 唯一残ったプレート。アルセウスはノーマルかフェアリーの二者択一を迫られることに。
ごくまれ とけないこおり こおりタイプのわざの威力が1.2倍になる バイバニラが50%の確率で持っている。バニプッチは5%だ。

※注:上記の「幻の超激レアアイテム」とは、このラテラルタウンでしか入手できないことを指します 

 

プログラムの使い方(ランクマバグの入り方)

前述の項目などを通して、ラテラルタウンの「ほりだしもの市」が如何に重要かがわかったと思います。特に、DLCを買っていない人には唯一の入手経路となるアイテムが5つもあるわけですから、無視するわけにもいきませんね。

さて、おまたせしました。肝心のプログラムの使い方です。

本稿でも、前回の【Arduino自動化14】ロトミIDくじ無限抽選と同じく、いわゆるランクマバグ状態でプログラムを動かします。やり方については、何も難しいことはなく、ランクマッチで1戦するだけなのですが、ランクマッチ以外の方法だと下記もあります。画像は過去記事の使いまわしです。あしからず。

  1. YY通信で「通信対戦」を行う(ローカル通信)
  2. もう一台のSwitch・剣盾を使ってその通信対戦に応じる
  3. 戦闘が始まったらHomeボタン長押し→「機内モード」をONに変更する
  4. エラーが発生するのでそれを閉じて、「にげる」選択
  5. フィールド画面に戻ってくる(ランクマバグ状態に移行完了)
f:id:tangential_star:20201122213022g:plain
f:id:tangential_star:20201122213037g:plain
YY通信でローカル対戦を募る。バトルが始まったらHomeボタン長押しで機内モード
f:id:tangential_star:20201122213148g:plain
f:id:tangential_star:20201122213205g:plain
エラーが出たら「にげる」で対戦終了。この状態で時刻変更すると一瞬画面が暗転する

 

ソースコード

使い方は、ラテラルタウンの露天商のお兄さんの前で、ランクマバグ状態でArduinoを挿し込むだけの簡単仕様です。1試行あたり25秒(実測値)でした。1回で3,000円取られるので、ちゃんと金額は準備しておきましょう。

なお、新規アイテム(初めて入手したアイテム)があっても、そのままループは破綻しませんので、そのまま放置でOKのはずです。

NintendoSwitch Ver.11.0アップデート対応済です。

2021/9/20追記:NintendoSwitch Ver.13.0アップデート対応済(詳細はこちら
2022/10/23追記:NintendoSwitch Ver.15.0アップデート対応済
※Switch Liteをご利用の方は「#define SWITCH_VER (15)」を「#define SWITCH_VER (12)」に書き換えてご利用ください。ただし、未検証です。

/* ★NintendoSwitchのファームウェアVer13に対応版(2021/9/20)★
 * ★NintendoSwitchのファームウェアVer15に対応版(2022/10/23)★ 
 *  
 *  ラテラルタウン掘り出し物市 自動購入
 *  
 *  【ランクマバグ】状態で使うこと!
 *  掘り出し物市の前でArduino差し込むだけ!
 *  (c) 2021 ますたーの忘備録
 *  https://tangential-star.hatenablog.jp/
*/

#include <SwitchControlLibrary.h>

#define HOLDTIME (95) // 1回のキー入力の長押し時間

#define SWITCH_VER (15)
// 2021/9/20、SwitchのVer13アップデートに伴う追記
// Switchのバージョンを整数で入力(例:12.2.1⇒12, 13.0.0⇒13, 15.0.0→15)


void PushRL(int delay_time_ms);
int PushKey(char* keyname, int holdtime, int delaytime);
void NextDayInCheatMode(void);

void setup() {
  // コントローラーとして認識されるためにRLを7回ほどカチャカチャする
  for(int i=0;i<7;i++)PushRL(300);
  delay(1000);
}


void loop() {

  // ★日付を回すやつ
  NextDayInCheatMode();

  PushKey("A", HOLDTIME, 700);  // いらっしゃい… ほりだしもの みていくかい? 
  PushKey("A", HOLDTIME, 1500); // ⇒本日の ほりだし (※シークタイムあり)
  PushKey("A", HOLDTIME, 700);  // 本日の ほりだしものは ○○ だな…… ▼
  PushKey("A", HOLDTIME, 700);  // ○○円だが 買っていくかい? ⇒はい
  PushKey("B", HOLDTIME, 2100); // まいど どうも ▼ (※SEチャリーン音あり)
  PushKey("B", HOLDTIME, 3000); // ○○は ○○を 手に入れた! ▼
  PushKey("B", HOLDTIME, 700);  // ○○は ○○を ○○ポケットに しまった ▼
  PushKey("B", HOLDTIME, 700);  // ほかに 用は あるかい? ▼
  PushKey("B", HOLDTIME, 700);  // 気が 変わったら また 来な…… ▼
  PushKey("B", HOLDTIME, 700);  // 
  
  PushKey("B", HOLDTIME, 300); // 予備
  PushKey("B", HOLDTIME, 300);

  //// 以下、新規購入のダイアログ出現時に効率よく回せるようになるので、「きあいのハチマキ」「ぼうごパッド」など新規が多い人はつけよう
  // PushKey("B", HOLDTIME, 300);
  // PushKey("B", HOLDTIME, 300);
  // PushKey("B", HOLDTIME, 300);

}

void PushRL(int delay_time_ms){
  SwitchControlLibrary().PressButtonR();
  SwitchControlLibrary().PressButtonL();
  delay(HOLDTIME);
  SwitchControlLibrary().ReleaseButtonR();
  SwitchControlLibrary().ReleaseButtonL();
  delay(delay_time_ms);
  return;
}
int PushKey(char* keyname, int holdtime, int delaytime){
  // ホームボタン・方向キーはRight, Left, Up, Down, Homeなど2文字以上で入力。
  // その他ボタン入力は1文字(A,B,X,Y,R,L,+,-)ZR・ZLにも対応
  // 同時押しは非対応
  
  if(strlen(keyname)==1){
    switch(keyname[0]){
      case 'A': case 'a': // A
        SwitchControlLibrary().PressButtonA(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonA(); delay(delaytime);
      break;
      case 'B': case 'b': // B
        SwitchControlLibrary().PressButtonB(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonB(); delay(delaytime);
      break;
      case 'X': case 'x': // X
        SwitchControlLibrary().PressButtonX(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonX(); delay(delaytime);
      break;
      case 'Y': case 'y': // Y
        SwitchControlLibrary().PressButtonY(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonY(); delay(delaytime);
      break;
      case 'L': case 'l': // L
        SwitchControlLibrary().PressButtonL(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonL(); delay(delaytime);
      break;
      case 'R': case 'r': // R
        SwitchControlLibrary().PressButtonR(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonR(); delay(delaytime);
      break;
      case 'H': case 'h': // Home
        SwitchControlLibrary().PressButtonHome(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonHome(); delay(delaytime);
      break;
      case '+': case 'p': case 'P': // Plus
        SwitchControlLibrary().PressButtonPlus(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonPlus(); delay(delaytime);
      break;
      case '-': case 'm': case 'M': // Minus
        SwitchControlLibrary().PressButtonMinus(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonMinus(); delay(delaytime);
      break;
      default:
      break;
    }
  }else if(strlen(keyname)>=2){
    switch(keyname[0]){
      case 'z': case 'Z': // ZR/ZL
        if(keyname[1]=='R'||keyname[1]=='r'){
          SwitchControlLibrary().PressButtonZR(); delay(holdtime);
          if(holdtime>0)SwitchControlLibrary().ReleaseButtonZR(); delay(delaytime);
        }
        if(keyname[1]=='L'||keyname[1]=='l'){
          SwitchControlLibrary().PressButtonZL(); delay(holdtime);
          if(holdtime>0)SwitchControlLibrary().ReleaseButtonZL(); delay(delaytime);
        }
      break;
      case 'r': case 'R': // right
        SwitchControlLibrary().MoveHat(2); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().MoveHat(8); delay(delaytime);
      break;
      case 'l': case 'L': // left
        SwitchControlLibrary().MoveHat(6); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().MoveHat(8); delay(delaytime);
      break;
      case 'u': case 'U': // up
        SwitchControlLibrary().MoveHat(0); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().MoveHat(8); delay(delaytime);
      break;
      case 'd': case 'D': // down
        SwitchControlLibrary().MoveHat(4); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().MoveHat(8); delay(delaytime);
      break;
      case 'H': case 'h': // Home
        SwitchControlLibrary().PressButtonHome(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonHome(); delay(delaytime);
      default:
      break;  
    }
  }else{
    return -1;
  }
  return strlen(keyname);
}
void NextDayInCheatMode(){
  // ★日付変更
  // Homeボタンを押して設定の画面へ移動
  PushKey("Home", HOLDTIME, 1000);

  // Home画面で「設定」を選ぶ
  PushKey("down", HOLDTIME, 105);
  PushKey("right", HOLDTIME, 105);
  PushKey("right", HOLDTIME, 105);
  PushKey("right", HOLDTIME, 105);
  PushKey("right", HOLDTIME, 105);
  PushKey("right", HOLDTIME, 105);
  PushKey("A", HOLDTIME, 1500);

  // 設定画面で「日付と時刻」を開く
  PushKey("down", 1500, 105); // 1.5秒「↓」長押し
  PushKey("right", HOLDTIME, 105); 

#if (SWITCH_VER >= 15)
  // Switchのver15アプデでBluetoothオーディオの設定が変わった?ので、微修正。
  // ※本体のバッテリー残量(%)にずれるようになったので。
  PushKey("down", 750, 55);
#elif (SWITCH_VER >= 13)
  // Switchのアプデで「ドックの更新」項目が追加されたので
  // 日付変更をする場合には「↓」キー長押しが必要に。
  PushKey("down", 780, 55); 
#else
  // ver12まで(13アプデ前)は、1ページに収まるのでそのままでOK
  for(int i=0; i<4; i++){
    PushKey("down", HOLDTIME, 55);
  }
#endif


  
  PushKey("A", HOLDTIME, 500);

  // 時間設定(現在の日付と時刻を選ぶ)
  PushKey("down", HOLDTIME, 105);
  PushKey("down", HOLDTIME, 105);
  PushKey("A", HOLDTIME, 500);

  // 時刻設定(日付の部分のみ回していく
  // 時間の変更
  PushKey("right", HOLDTIME, 105);
  PushKey("right", HOLDTIME, 105);
  PushKey("up",    HOLDTIME, 105);
  PushKey("A", HOLDTIME, 105);
  PushKey("A", HOLDTIME, 105);
  PushKey("A", HOLDTIME, 105);
  PushKey("A", HOLDTIME, 105);
  PushKey("Home", HOLDTIME, 2000);
  PushKey("A", HOLDTIME, 1000);
  return;
}

一応、ループが破綻せずに2周目でズレを吸収する様子を↓下記GIF画像にて。

f:id:tangential_star:20210211170119g:plain
f:id:tangential_star:20210211125124p:plain
新規アイテム入手時のダイアログで動作がズレても、次の試行で吸収する設計

 

あとがき

今回で、Arduino自動化記事も15本目となります。

皆様に支えられ、本ブログも開設から3ヶ月が経過し、月間PV数も平均で2,537PV/月にまで成長しました(2021/2/8 0:00計算)。引き続きよろしくお願いいたします。

 

さて、DLCも第2弾まで出ているのに「なんで今更ラテラルタウンの記事?」と思った方も、ここまで読んでいただいて、「ここでしか入手できないアイテムなんてあったのか!」と驚いた方も多いのでは無いでしょうか。また、「『ぼうごパット』というアイテムなんて存在すら知らなかった!」という方もいらっしゃると思います。

 

f:id:tangential_star:20210211174915p:plain

落書き:パッチルドン@ぼうごパット

上述しましたが、超激レアアイテムの「ぼうごパット」は、メタとしては強力な一方、汎用性には乏しくかなりピンポイントな運用になると思います。が、それ故にきっと意表を突けるアイテム枠として採用できるポテンシャルは充分にあると思います。

本ブログ記事が、皆様にとって「ぼうごパット」を今一度認識する機会となったり、Arduino自動化の一助となったりすれば幸いです。

 

ではではc⌒っ.ω.)っ

 

前記事:【Arduino自動化14】ロトミIDくじ無限抽選

次の記事:【Arduino自動化16】自動ミラクル交換(ID集めほか)

導入記事:【Arduino自動化01】Arduino開発環境の導入 

 

【Arduino自動化14】ロトミIDくじ無限抽選

ますたーです。こんにちは。

今回は、いわゆるランクマバグ状態で「ロトミIDくじ」を引き続ける自動化記事です。

Arduino自動化記事もこれで第14回。これからもよろしくお願いします。

 

なお、Arduino Leonardo自動化の導入・機材構成については導入記事を参考にしてください。

導入記事:【Arduino自動化01】Arduino開発環境の導入

※本ブログに初めてお越しの方は「本ブログについて」もぜひ、ご覧ください。

 

概要

本記事では、ランクマバグ状態を利用した、ロトミIDくじ無限抽選を実装します。
※便宜上「ランクマバグ」と表記しますが、当ブログではランクマッチを使用しません。通信切断・初手降参の推奨もしません。

【!】ロトミIDくじは、その特性上、大量の「レポート」を伴います。必然的にmicroSDや本体メモリへの書き込みが増えますので、セーブデータ破損のリスクや動作不良のリスクなど、充分に危険性を理解した上でご参考ください。

 

NintendoSwitch Ver.11.0アップデート対応済です。
★2021/9/20追記:NintendoSwitch Ver.13.0アップデート対応済です。
★2022/10/23追記:NintendoSwitch Ver.15.0アップデート対応済です。

f:id:tangential_star:20210130135029g:plain
f:id:tangential_star:20210201212827p:plain
無限にIDくじを引き続けることができる。目指せ、特賞「マスターボール

では、目次です。確率計算とかもしました!(理系っぽい!)

ロトミIDくじの当選確率を知りたいという方はコチラ⇒読み飛ばす

ソースコードだけほしい方はコチラ⇒読み飛ばす

 

ポケモンセンターでロトミIDくじが引ける

まずは前提、というか余談です。

ポケモン剣盾では、ポケモンセンター各店舗のパソコンライクな機械「ロトミ」で1日1回「IDくじ」を引くことができます。

「IDくじ」をご存じない方にも説明をすると、手持ち・ボックスにいる全ポケモンの親IDと、ランダムで発生した5桁の乱数とを比較し、一致する桁数に応じて賞品が貰える、という毎作品お馴染みのおまけ要素です。

古くは第二世代(金銀)時代に始まり、ID完全一致の特等景品「マスターボール」は当時からの憧れの的でした(当時は、1日1回ではなく1週間に1回だったので引ける回数は大きく増えましたね)。完全に余談ですが、この「IDくじ」、何故か第五世代(BW)だけなかったんですよね。毎日のゲームモチベが減ったものです。

f:id:tangential_star:20210202103550g:plain
f:id:tangential_star:20210202085422p:plain
ポケモンRSEではミナモデパートでIDくじを引くことができた

前作までは、わざわざコガネシティ(ラジオとう)やミナモシティ(ミナモデパート)、コトブキシティ(テレビコトブキ)などの街に移動する、いわゆる「IDくじのための移動」が必要でした。

今作は、なんと、どこの街のポケモンセンターでもIDくじが引けますDLCでも、鎧の孤島なら拠点にロトミを連れてくることができるため、大変手軽にくじを回すことができるようになりました。また、今作のIDくじについても例外なく、特等(=ID下5桁一致)の賞品は「マスターボール」になります。

 

ロトミIDくじで特等「マスターボール」を狙う

ロトミIDくじは、ランダムに生成された5桁の数字を、手持ち・ボックスの全ポケモン(ポケジョブ除く)の親IDそれぞれの下5桁とを比較し、一致した桁数に応じて賞品がもらえます。

さて、肝心の特等「マスターボール」ですが、前述の通り親IDの下5桁が完全一致する必要があります。親IDが1つの場合(例えば一切他人と交換していない場合)の「マスターボール」当選確率を計算すると、「10の5乗分の1」になります。すなわち、わずか0.001%です

※一説によれば、今作は先頭5桁の一致も含むという噂?があるようです。それに則れば単純計算で当選確率は2倍になりますが、本ブログでは7回「特等」を当選していますが「上5桁一致」での当選はありませんでした。そのため、下5桁のみ当選する前提にて確率計算・表記しています

※ところが、後述の通り、実測値で計算した確率が「理論値の2倍」になります

f:id:tangential_star:20210203092440p:plain
f:id:tangential_star:20210203092444p:plain
f:id:tangential_star:20210203092449p:plain
「特等」当選時のメンバーの一例。いずれも下5ケタ一致だ(205575, 101082, 590328
f:id:tangential_star:20210203003331g:plain
f:id:tangential_star:20210203003339g:plain
f:id:tangential_star:20210203003348g:plain
筆者は7回「特等」を引いたが、いずれも「下5ケタ すべてが おんなじロ」と評される

 

ロトミIDくじの当選確率

上述の通り、「マスターボール」の当選確率はただでさえ低いですので、ミラクル交換やポケモンHOME(スマホ版)の交換機能などを活用し、できるだけ親IDを集めておくと良いでしょう。

ボックスいっぱいにすると30匹×32ボックス=960匹預けることができますので、これらのIDに一切の重複が無いと仮定すれば、マスターボールの当選確率が約1%まで跳ね上がります

一応、理論値としては、手持ち6匹+960匹すべて違うポケモンで0.9614%が上限です。

300匹で特等の確率は0.3%程度になるので、マスターボール狙いなら、少なくとも10ボックス程度は他人の親IDのポケモンで埋めておきたいです。どうしても難しい場合でも、ハズレの確率が1%を下回る50種類までは少なくとも集めておきたいです。

なお、IDの一致桁数に応じた賞品の当選確率は下記の通りです(筆者試算)。

 

所持ID数と各賞品の当選確率(小数点第3位を四捨五入)
ID数 【特等】5桁
マスターボール
【1等】4桁
ふしぎなあめ
【2等】3桁
ポイントマックス
【3等】2桁
ポイントアップ
【4等】1桁
モーモーミルク
はずれ
1 0.00% 0.01% 0.09% 0.90% 9.00% 90.00%
10 0.01% 0.08% 0.81% 7.75% 52.41% 38.94%
25 0.02% 0.20% 2.00% 18.00% 70.31% 9.46%
50 0.05% 0.40% 3.95% 31.96% 62.74% 0.90%
100 0.10% 0.80% 7.71% 50.90% 40.48% 0.01%
300 0.30% 2.36% 21.01% 69.69% 6.64% 0.00%
500 0.50% 3.90% 31.85% 62.66% 1.09% 0.00%
700 0.70% 5.41% 40.65% 53.07% 0.18% 0.00%
960 0.96% 7.32% 49.59% 42.11% 0.02% 0.00%
966 0.96% 7.37% 49.77% 41.89% 0.02% 0.00%

 

所持ID数と各賞品の当選確率のグラフ

狙う賞品によって最適なID数は違うが、はずれが出にくくなる50種は少なくとも欲しい

f:id:tangential_star:20210208165840p:plain

特等(マスターボール)・1等(ふしぎなあめ)は、ID数に応じて当たりやすくなる

言わずもがな、ポイントマックスはもちろんマスターボールやふしぎなあめの当選確率は、持っているID数が多ければ多いほど上がります。ユニークなのはポイントアップとモーモーミルクの当選確率で、途中で極大値を取ります。

具体的には、ポイントアップは283匹の時に69.764%、モーモーミルクは28匹の時に70.504%でそれぞれ極大値を取ります。現実的に960匹違うIDでボックスを埋めるのはツライと思いますので、このあたりを参考に、狙う道具を検討しつつ、事前に用意するポケモンの数を検討すべしですね。

 

マスターボール」の当選確率は2倍?

9時間46分放置でマスターボールを7個入手しました

筆者は過去作でGTS交換したものなども含めて12ボックス分(360匹)、ポケモンHOMEで連れてきて、自動化プログラムを使用しました。結果、プログラムを9時間46分稼働させ続け、推定試行回数888抽選で「マスターボール」7つを入手できました。

※プログラムソースコード後述します

f:id:tangential_star:20210204135040g:plain
f:id:tangential_star:20210130135029g:plain
他人産ポケモンで12ボックスを埋めて、いざ自動化!
f:id:tangential_star:20210204130023p:plain
f:id:tangential_star:20210204130028p:plain
9時間46分稼働させ、「マスターボール」7個を入手(左:実施前/右:実施後)

マスターボールの当選確率を計算(考察)

さて、確率計算です。完全に余談ですので、読み飛ばしOKです→読み飛ばす

888試行に対して7回の「特等」当選ですが、これは確率に表すと0.7883%になります。一方、12ボックス分(360匹)での、1試行あたりの入手確率は計算上、0.3593%になります。すなわち、実績値が理論値のおおよそ2倍になるという、かなり稀有な事象が起こっています。

もし、噂通り「上5桁も当選する仕様」なら理論値は上記2倍の0.7187%になるので理論値とかなり近しくなりますが、これはかなり不思議です。というのも、筆者が特等を引いた7回とも「下5桁」で当選しているからです

※7回続けて「下5桁」で当選するのは統計学的に有意水準1%で有意な偏り(符号検定よりp<0.01)と言えます。要するに偶然の範疇を超えています

なので、もしかしたら、ロトミは内部的に2回「下5桁完全一致」の抽選を行っているのかもしれませんし、上5桁で当選した時に、下5桁で言い直しているのかもしれません。

いずれにしても、実績値から考えるに当選確率は、単純な「下5桁完全一致」で計算した理論値の2倍と考えるのが妥当なので、ロトミIDくじの各賞品の当選確率は下表になるかもしれません。どちらを信じるかは読者の判断に委ねます。

 

所持ID数と各賞品の当選確率(特等の当選確率が2倍で仮定した時の試算)
ID数 【特等】5桁
マスターボール
【1等】4桁
ふしぎなあめ
【2等】3桁
ポイントマックス
【3等】2桁
ポイントアップ
【4等】1桁
モーモーミルク
はずれ
1 0.00% 0.01% 0.09% 0.90% 9.00% 90.00%
10 0.02% 0.06% 0.82% 7.75% 52.41% 38.94%
25 0.05% 0.15% 2.03% 18.00% 70.31% 9.46%
50 0.10% 0.30% 4.00% 31.96% 62.74% 0.90%
100 0.20% 0.60% 7.81% 50.90% 40.48% 0.01%
300 0.60% 1.77% 21.30% 69.69% 6.64% 0.00%
500 1.00% 2.93% 32.33% 62.66% 1.09% 0.00%
700 1.39% 4.06% 41.31% 53.07% 0.18% 0.00%
960 1.90% 5.49% 50.48% 42.11% 0.02% 0.00%
966 1.91% 5.52% 50.66% 41.89% 0.02% 0.00%

 

プログラムの使い方(ランクマバグの入り方)

おまたせしました。

肝心のプログラムの使い方ですが、ロトミの前でソースコードを書き込んだArduinoを挿し込むだけの簡単仕様です。ただし、いわゆる「ランクマバグ」状態で使う必要がありますので、ランクマッチで1戦してください。

なお、ランクマッチを使用しない方法での「ランクマバグ状態」移行は下記手順でできます。画像は過去記事の使いまわしです。あしからず。

  1. YY通信で「通信対戦」を行う(ローカル通信)
  2. もう一台のSwitch・剣盾を使ってその通信対戦に応じる
  3. 戦闘が始まったらHomeボタン長押し→「機内モード」をONに変更する
  4. エラーが発生するのでそれを閉じて、「にげる」選択
  5. フィールド画面に戻ってくる(ランクマバグ状態に移行完了)
f:id:tangential_star:20201122213022g:plain
f:id:tangential_star:20201122213037g:plain
YY通信でローカル対戦を募る。バトルが始まったらHomeボタン長押しで機内モード
f:id:tangential_star:20201122213148g:plain
f:id:tangential_star:20201122213205g:plain
エラーが出たら「にげる」で対戦終了。この状態で時刻変更すると一瞬画面が暗転する

 

ソースコード

今回も例のごとく、「ランクマバグ」状態で使います。使い方は、最寄りのポケモンセンターのロトミの前でArduinoを挿し込むだけの簡単仕様です。

30試行あたり19分47秒(実測値)だったので、ざっくり1時間放置で90回抽選できます。

NintendoSwitch Ver.11.0アップデート対応済です。

2021/9/20追記:NintendoSwitch Ver.13.0アップデート対応済(詳細はこちら
2022/10/23追記:NintendoSwitch Ver.15.0アップデート対応済
※Switch Liteをご利用の方は「#define SWITCH_VER (15)」を「#define SWITCH_VER (12)」に書き換えてご利用ください。ただし、未検証です。

※2023/5/31 微修正

/* ★NintendoSwitchのファームウェアVer13に対応版(2021/9/20)★
 * ★NintendoSwitchのファームウェアVer15に対応版(2022/10/23)★ 
 *  
 *  ロトミIDくじ自動抽選
 *  
 *  【ランクマバグ】状態で使うこと!
 *  ロトミの前でArduino差し込むだけ!
 *  (c) 2021 ますたーの忘備録
 *  https://tangential-star.hatenablog.jp/
*/

#include <SwitchControlLibrary.h>

#define HOLDTIME (95) // 1回のキー入力の長押し時間
#define INTERVAL (105)
#define SWITCH_VER (15)
// 2021/9/20、SwitchのVer13アップデートに伴う追記
// Switchのバージョンを整数で入力(例:12.2.1⇒12, 13.0.0⇒13, 15.0.0→15)


void PushRL(int delay_time_ms);
int PushKey(char* keyname, int holdtime, int delaytime);
void NextDayInCheatMode(void);

void setup() {
  // コントローラーとして認識されるためにRLを7回ほどカチャカチャする
  for(int i=0;i<7;i++)PushRL(300);
  delay(1000);
 
}


void loop() {

  // ★日付を回すやつ
  NextDayInCheatMode();

  PushKey("A", HOLDTIME, 700); // こんにちロ~! なにを しますロミ? ▼
  PushKey("A", HOLDTIME, 700); // 
  PushKey("down", HOLDTIME, 350); // IDくじ
  PushKey("A", HOLDTIME, 700); // ただいま IDくじセンターの 抽選コーナーに つないだロミ!▼
  PushKey("A", HOLDTIME, 700); // 引いた くじの ナンバーと ○○さんの ポケモンのIDが▼
  PushKey("A", HOLDTIME, 700); // みごと あってると ステキな 賞品を もらえちゃうんだロ!▼
  PushKey("A", HOLDTIME, 700); // 運試しに レポートを 書いて 引いてみるのは どうロミ?
  PushKey("A", HOLDTIME, 2000); // はい⇒レポートを書き込んでいます⇒しっかり書き残した▼
  PushKey("B", HOLDTIME, 800); // かしこまりロ~! 抽選 スタート ロミ!▼
  PushKey("B", HOLDTIME, 1200); // …… …… ……▼
  PushKey("B", HOLDTIME, 700); // ハイ! でたロミ! くじの ナンバーは *****!▼
  PushKey("B", HOLDTIME, 700); // ○○さんの ポケモンのIDと どれだけ あってるか▼
  PushKey("B", HOLDTIME, 700); // 調べて 見るロ!▼
  PushKey("B", HOLDTIME, 3000); // おめでロ~~~!!!!▼
  PushKey("B", HOLDTIME, 700); // ボックスに 預けている ○○ちゃんの IDが みごと▼
  PushKey("B", HOLDTIME, 700); // くじの ナンバーと ぴったしロミ!▼
  PushKey("B", HOLDTIME, 700); // ロミ! ○ケタが おんなじロ!▼
  PushKey("B", HOLDTIME, 700); // そんな スペシャルな 奇跡には 2等の 賞品▼
  PushKey("B", HOLDTIME, 700); // ポイントマックスを プレゼントだロ!!▼
  
  PushKey("B", HOLDTIME, 3000); // ○○は ポイントマックスを 手に入れた!▼
  PushKey("B", HOLDTIME, 700); // ○○は ポイントマックスを どうぐポケットに しまった▼
  PushKey("B", HOLDTIME, 900); // それじゃあ またの 挑戦を お待ちしてるロ~~!▼
  PushKey("B", HOLDTIME, 700); // ▼
  
  PushKey("B", HOLDTIME, 300); // 予備
  PushKey("B", HOLDTIME, 300);
  PushKey("B", HOLDTIME, 300);
  

}

void PushRL(int delay_time_ms){
  SwitchControlLibrary().PressButtonR();
  SwitchControlLibrary().PressButtonL();
  delay(HOLDTIME);
  SwitchControlLibrary().ReleaseButtonR();
  SwitchControlLibrary().ReleaseButtonL();
  delay(delay_time_ms);
  return;
}
int PushKey(char* keyname, int holdtime, int delaytime){
  // ホームボタン・方向キーはRight, Left, Up, Down, Homeなど2文字以上で入力。
  // その他ボタン入力は1文字(A,B,X,Y,R,L,+,-)ZR・ZLにも対応
  // 同時押しは非対応
  
  if(strlen(keyname)==1){
    switch(keyname[0]){
      case 'A': case 'a': // A
        SwitchControlLibrary().PressButtonA(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonA(); delay(delaytime);
      break;
      case 'B': case 'b': // B
        SwitchControlLibrary().PressButtonB(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonB(); delay(delaytime);
      break;
      case 'X': case 'x': // X
        SwitchControlLibrary().PressButtonX(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonX(); delay(delaytime);
      break;
      case 'Y': case 'y': // Y
        SwitchControlLibrary().PressButtonY(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonY(); delay(delaytime);
      break;
      case 'L': case 'l': // L
        SwitchControlLibrary().PressButtonL(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonL(); delay(delaytime);
      break;
      case 'R': case 'r': // R
        SwitchControlLibrary().PressButtonR(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonR(); delay(delaytime);
      break;
      case 'H': case 'h': // Home
        SwitchControlLibrary().PressButtonHome(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonHome(); delay(delaytime);
      break;
      case '+': case 'p': case 'P': // Plus
        SwitchControlLibrary().PressButtonPlus(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonPlus(); delay(delaytime);
      break;
      case '-': case 'm': case 'M': // Minus
        SwitchControlLibrary().PressButtonMinus(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonMinus(); delay(delaytime);
      break;
      default:
      break;
    }
  }else if(strlen(keyname)>=2){
    switch(keyname[0]){
      case 'z': case 'Z': // ZR/ZL
        if(keyname[1]=='R'||keyname[1]=='r'){
          SwitchControlLibrary().PressButtonZR(); delay(holdtime);
          if(holdtime>0)SwitchControlLibrary().ReleaseButtonZR(); delay(delaytime);
        }
        if(keyname[1]=='L'||keyname[1]=='l'){
          SwitchControlLibrary().PressButtonZL(); delay(holdtime);
          if(holdtime>0)SwitchControlLibrary().ReleaseButtonZL(); delay(delaytime);
        }
      break;
      case 'r': case 'R': // right
        SwitchControlLibrary().MoveHat(2); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().MoveHat(8); delay(delaytime);
      break;
      case 'l': case 'L': // left
        SwitchControlLibrary().MoveHat(6); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().MoveHat(8); delay(delaytime);
      break;
      case 'u': case 'U': // up
        SwitchControlLibrary().MoveHat(0); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().MoveHat(8); delay(delaytime);
      break;
      case 'd': case 'D': // down
        SwitchControlLibrary().MoveHat(4); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().MoveHat(8); delay(delaytime);
      break;
      case 'H': case 'h': // Home
        SwitchControlLibrary().PressButtonHome(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonHome(); delay(delaytime);
      default:
      break;  
    }
  }else{
    return -1;
  }
  return strlen(keyname);
}
void NextDayInCheatMode(){
  // ★日付変更
  // Homeボタンを押して設定の画面へ移動
  PushKey("Home", HOLDTIME, 1000);

  // Home画面で「設定」を選ぶ
  PushKey("down", HOLDTIME, 105);
  PushKey("right", HOLDTIME, 105);
  PushKey("right", HOLDTIME, 105);
  PushKey("right", HOLDTIME, 105);
  PushKey("right", HOLDTIME, 105);
  PushKey("right", HOLDTIME, 105);
  PushKey("A", HOLDTIME, 1500);

  // 設定画面で「日付と時刻」を開く
  PushKey("down", 1500, 105); // 1.5秒「↓」長押し
  PushKey("right", HOLDTIME, 105); 

#if (SWITCH_VER >= 15)
  // Switchのver15アプデでBluetoothオーディオの設定が変わった?ので、微修正。
  // ※本体のバッテリー残量(%)にずれるようになったので。
  PushKey("down", (int)750, (int)INTERVAL);
#elif (SWITCH_VER >= 13)
  // Switchのアプデで「ドックの更新」項目が追加されたので
  // 日付変更をする場合には「↓」キー長押しが必要に。
  PushKey("down", (int)780, (int)INTERVAL/2);
#else
  // ver12まで(13アプデ前)は、1ページに収まるのでそのままでOK
  for(int i=0; i<4; i++){
    PushKey("down", (int)HOLDTIME/2, (int)INTERVAL/2);
  }
#endif

  PushKey("A", HOLDTIME, 500);

  // 時間設定(現在の日付と時刻を選ぶ)
  PushKey("down", HOLDTIME, 105);
  PushKey("down", HOLDTIME, 105);
  PushKey("A", HOLDTIME, 500);

  // 時刻設定(日付の部分のみ回していく
  // 時間の変更
  PushKey("right", HOLDTIME, 105);
  PushKey("right", HOLDTIME, 105);
  PushKey("up",    HOLDTIME, 105);
  PushKey("A", HOLDTIME, 105);
  PushKey("A", HOLDTIME, 105);
  PushKey("A", HOLDTIME, 105);
  PushKey("A", HOLDTIME, 105);
  PushKey("Home", HOLDTIME, 2000);
  PushKey("A", HOLDTIME, 1000);
  return;
}

あとがき

今回は、「ロトミIDくじ」の自動化について紹介しました。

ロトミってRotom Information Serviceの意味だったんですね。この記事を書くまで知りませんでした。

 

さて、本稿でも結構考察しましたが、様々なWebサイトを調べてもマスターボールの当選について「5桁一致」とは書いてあるものの「下5桁」のみならず「上5桁」も含むのかが分からず、自分で検証してしまいました。

結論、ロトミは「下5桁」でしか当選を教えてくれないが、確率は単純計算時の2倍で設定されている、という仮説ができましたね。そういう意味では、ある意味「自動化記事」でありながら「疑問だし記事」にもなってしまいました(笑)。

誰か、数学に強い人か、ロトミに詳しいポケモン博士にぜひともコメントしていただきたいものです(もしかしたらそもそも私の試算が間違っている、なんて本末転倒かもしれませんし)。

 

話が逸れましたが、これで「マスターボール」の自動入手もできるようになりました。マスターボールは「孵化厳選」では絶対に引き継げない、とても希少なボールですし、ボールエフェクトもカッコイイんですよね。そういう意味でも、すごく需要があるボールなのに…。もう少し手軽に入手できれば良いのにな、と思います。そういった意味でも、需要のある自動化だったのではないでしょうか。

 

本ブログが皆様の自動化ライフをより豊かなものにできれば幸いです。

ではではc⌒っ.ω.)っ

 

前記事:【Arduino自動化13】全自動ポケモン逃がし

導入記事:【Arduino自動化01】Arduino開発環境の導入 

次の記事:【Arduino自動化15】ラテラルタウン掘り出し物自動購入

 

2021/2/19追記:IDを効率よく集められる「ミラクル交換」の自動化記事を執筆しました。

参考:【Arduino自動化16】自動ミラクル交換(ID集めほか)