【速報】NintendoSwitchバージョン11.0公開に伴うプログラムの変更について【重要】

ますたーです。本記事は速報として掲載しています。

2020年12月1日に公開されたNintendoSwitchVer11.0のアップデートを受けて、今まで公開してきたプログラムの一部が正常に動作しなくなりました。本ブログで取り扱っているプログラムについては、Nintendo Switch Ver. 11.0アップデートに対応完了しました(2020/12/5追記)

具体的には、Home画面を開いて「設定」に入るまでのキー入力数が変わるため、この部分を書き換えればうまく動くのですが、取り急ぎ、本内容を告知しました。

他サイトで掲載のプログラムはもちろん、すでにコンパイル済のプログラムや書き込み済のマイコンも正常に動作しなくなりますので、ご注意をお願いします。

f:id:tangential_star:20201201230643p:plain

NintendoSwitchVer11.0公開に伴うプログラムの変更ポイント

2020/12/5追記:本ブログのプログラムのアプデ対応状況は下記の通りです。 

2020/12/5現在 本ブログで紹介・掲載したプログラムのアップデート対応状況

プログラムを紹介した記事 ソースコード 対応状況

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

A連打のみ アプデ影響なし
(更新不要) 

【Arduino自動化02】
目玉商品を全自動回収

目玉商品の自動回収 2020/12/5
アプデ対応済

【Arduino自動化03】
ワット稼ぎ・自動回収

無限ワット回収バグ

2020/12/5 
アプデ対応済

【Arduino自動化04】
パッチルドン受け取り

パッチルドン自動受取 アプデ影響なし
(更新不要)

【Arduino自動化05】
乱数調整レイド

3日後の巣穴厳選

2020/12/5 
アプデ対応済
 高速乱数消費  アプデ影響なし
(更新不要)

  

以上、よろしくお願いいたします。

 

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

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

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

今回の記事は、Arduino乱数調整の一部手順と高速消費を自動化する方法についてです。乱数調整の流れにそって説明します。今回の目標は、色違いのパッチルドン(乱数レイド産)を捕まえることです。

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

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

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

 

概要

本記事では、レイド乱数調整で必要な2つの作業をArduinoで自動化します。
・1つ目:「初期シード」を推定するための2Vポケモン探し(3日進める作業)
・2つ目:「ランクマバグ」状態での乱数消費(日付を進める作業)
※便宜上「ランクマバグ」と表記しますが、当ブログではランクマッチを使用しません。通信切断・初手降参の推奨もしません。

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

 

2021/3/28追記:補足記事を執筆しました。Arduinoを使う具体的なタイミングについてもう少し詳しく知りたい、という方向けの記事です。合わせてご参考ください。

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

f:id:tangential_star:20201122220708g:plain
f:id:tangential_star:20201122220734g:plain
「シード特定用の3日後レイド厳選」と「高速乱数消費」をArduinoで自動化
(左:リセットして3日日付を進める 右:ランクマバグ状態で日付変更)

 

なお、本記事では乱数調整ツールは、さびたコイル氏の「1-StarSeedSearch」を使います。記事のメインは、Arduino Leonardoによる一部手順の自動化になりますが、乱数調整の忘備録も兼ねた構成で書きますので、Arduinoを持っていない人も乱数を始めたばかりorこれから始めるよっていう人にも読めるよう書いているつもりです。
(丸2日間かけてできるだけ丁寧に書きました。是非とも参考にしてください)

「いや、ソースコードと使い方だけ寄越せ」って方はどうぞ→ソースコードと使い方

 

目次です(もりだくさん!)。

 

作ったきっかけ

前回の記事では、色違いパッチルドンを、自動カセキ受け取りで厳選する方法 について紹介しました。今回は、どうしても色パッチルドンの「ボール厳選」がしたくて、DLCでレイドバトルが解禁されたパッチルドンの色乱数に挑戦しました。結論、紆余曲折ありましたが成功しました。

f:id:tangential_star:20201123113607g:plain
f:id:tangential_star:20201123113647g:plain
待ちに待った色パッチルドンのお出まし!かわいいいいい!!!

剣盾レイドの乱数調整では、手動だとめちゃくちゃ大変な部分が2つあります。中でもArduinoの価値が活きたのは、「何百日~何千日も日付を進める手順(乱数消費)」だと思います。こちらは流石に手作業では骨が折れる…というか、ミスの温床なのでArduinoで自動化しようというわけです。また、最初の厳選作業(3日日付を進めてツール指定の★3レイドが出るまでひたすらやり直す作業)も地味に大変で、運が悪いと何度も挑戦することになります。ゆえに、こちらも自動化しました。

 

大前提

本記事では「乱数調整」の手順に沿った構成で書き下します。乱数調整の紹介をメインとする記事ではありませんので原理やツールの使い方、導入手順などの紹介は最小限に留めます。ソースコードと使い方だけ必要な方は適宜読み飛ばしてください。

 ⇒ 「ソースコードと使い方」まで読み飛ばす

ただし、Arduinoの自動化は、あくまでも乱数調整の手順を簡略化するだけですので、全く予備知識がない状態で自動化を試みるのはリスクがあります。一度でも良いので、手動で乱数調整を試みてから、Arduinoプログラムを使って自動化してみることを筆者としてはおすすめいたします。

なお、乱数調整は改造・セーブデータの改竄とは違い、正規仕様の範囲内で出現するポケモンの性別や個体値、色違いの別を操作するものです。本稿で乱数調整の是非は問いませんが、本件ご理解の上、閲覧・活用くださいませ。

 

色パッチルドン探しの手順

パッチルドンの色違いを捕まえるまでは大きく4ステップあります。かなり長丁場ですが、オシャボ入り色違いパッチルドンのために頑張りましょう!

  1. 準備
    (パッチルドンが出る巣穴にねがいのかたまりを投げ入れる)
  2. 乱数調整
    (乱数ツールで、色違いが出るまでの日数を計算)
  3. 乱数消費
    (計算日数-3日だけ日にちをひたすら進める)
  4. 捕獲
    (手動で3日進めてパッチルドンを捕まえる)

なお、手順上に「@自動化可能」と書いているものは、Arduino Leonardoでの自動化プログラムを提供しています。適宜ご活用ください。ソースコード後述します

1.準備パート

【色パッチルドン探しの手順】
1.準備
(イマココ) → 2.乱数調整 → 3.乱数消費 → 4.捕獲
(1-1. 乱数調整ツールを準備 1-2.目的の巣穴で柱を建てる)
1-1.乱数調整ツール(PC)を準備

まずは、乱数調整ツールをPCにダウンロードします。本稿では、さびたコイル氏がGPL3.0ライセンスで提供する「1-StarSeedSearch」を使います。自身のPC環境に合ったものをダウンロード・解凍してください。筆者はWindows10(64bit)です。

起動したら、自身のバージョン・目的の巣穴に合わせて選択します。目的の巣穴の情報は、yakkun氏が運営するポケモン攻略サイトポケモン徹底攻略」で検索して拾ってください。パッチルドンの場合は「雪中渓谷 G」「レア」でOKです。

f:id:tangential_star:20201122010711p:plain
f:id:tangential_star:20201122010727p:plain
1-StarSeedSearchをダウンロード&ZIP解凍し、OneStar.exeを起動
f:id:tangential_star:20201122010741p:plain
f:id:tangential_star:20201122010903p:plain
起動したら、パッチルドンの巣穴の場所(雪中渓谷G・レア)をプルダウン入力
1-2.目的の巣穴で柱を建てる

ツールへの入力を済ませたら、該当の巣穴に「ねがいのかたまり」を投げ入れて光の柱を立てます。パッチルドンの巣穴の場合は、入り口から登っていくよりも、カンムリ神殿から道なりに下ったほうがスムーズに到着できます。

「ねがいのかたまり」を投げ入れたら、念の為セーブをしておきます

なお、パッチルドンは紫の柱からしか出現しませんので、注意しましょう。

f:id:tangential_star:20201122014031p:plain
f:id:tangential_star:20201122014103p:plain
パッチルドンは雪中渓谷にいる。お気に入りのボールを準備しておこう。
f:id:tangential_star:20201122013234g:plain
f:id:tangential_star:20201122010634p:plain
パッチルドンの巣穴へはカンムリ神殿から下っていくとスムーズに着く

2.乱数調整パート

【色パッチルドン探しの手順】
1.準備 → 2.乱数調整(イマココ) → 3.乱数消費 → 4.捕獲
(2-1. 現在シードの特定 2-2.消費数の特定)
2-1.現在シードの特定

ここからは乱数調整の要となる、「初期シード値」の推定を行います。推定と言っても我々ではなくツールが計算してくれますのでご安心を。ただし、かなり運の要素が絡むため、この部分だけで下手すると1日が終わります。

2-1-1.3日後のオムスター探し @自動化可能

まずは、3回日付を進めた上で、自然発生Vを除いて2Vのポケモン(難しければ3Vのポケモン)を捕まえます。具体的なターゲットはツールに表示されます。

パッチルドンの巣穴では、3回日付を進めて「★3 オムスター」のレイドが出るまで粘ります。出なかったらセーブせずにリセットしてもう一度繰り返しこの手順を行ってください。自動化プログラム(ソースコードは後述)は、このリセットを含めて対応しています。

※妥協する場合は3V個体が出るレイド「★3 パッチルドン」「★3 プテラ」でも可能です。ただし、ここで妥協すると、今後の作業でかなりのマシンスペックが必要となるのでPCスペックに余裕が無い場合はお控えください。また、成功率が下がるという報告もあります(筆者は未検証)。

f:id:tangential_star:20201122021129p:plain
f:id:tangential_star:20201122021040g:plain
「みんなで挑戦!」から日付変更を3度繰り返し、★3オムスターが出ればOK
2-1-2.オムスター捕獲と個体値チェック

おそらくここが一番の鬼門(究極の運ゲ)。沼にハマると時にはまともに色違い厳選したほうが楽なのでは?と思うほどの苦行です(決して乱数は「楽」ではない)

手順2-1-1で見つけたオムスターを捕まえます。その性格・個性・個体値(わからなければLv100にしたステータスから計算)をツール入力、「個体値チェック」ボタンを押してください。あまり出ませんが「OK」が出たら、セーブせずにリセットして手順2-1-3 に進んでください。第1関門にして最大の鬼門をクリアです(ちなみに2Vレイドで「OK」が出る確率は1/3です。運が良ければすぐにクリアできます)。

「NG」が出てもセーブせずにリセットし、その後、改めて「みんなで挑戦」で日付を1日進めてからセーブします。そして、手順2-1-1に戻ってください

f:id:tangential_star:20201122030252g:plain
f:id:tangential_star:20201122031447p:plain
オムスターを捕まえて性格や能力値をチェック。Lv100にするとわかりやすい
f:id:tangential_star:20201122145808p:plain
f:id:tangential_star:20201122145819p:plain
能力を入れて「個体値チェック」。OKが出る確率は3割程度なので根気強くやろう
2-1-3.指示に従い、3日後の個体を探す @自動化可能

第1関門突破、おめでとうございます。喜び勇んでセーブしないよう、くれぐれも注意してくださいね(リセットして同じ柱から続きをやります)。

続いて、同じく3日後の個体を探します。ツールの「OK! Next ->」の後に「3V」「4V」「3V or 4V」など、次のターゲットの指示が記載されているので、それに従います。自動化プログラム(ソースコードは後述)をそのまま使えます。

例えば、今回の巣穴であればターゲットはそれぞれ

  • 「Next -> 3V」なら、★3 パッチルドン、★3 プテラ
  • 「Next -> 4V」なら、★3 パッチラゴン、★3 パッチルドン、★4 パッチラゴン
  • 「Next -> 3V or 4V」なら、上記いずれも可能(3Vの方をおすすめ)

…となります。手順2-1-1と同様に、ターゲットを見つけて捕まえます。捕まえたら、個体値をツールに入力して、セーブせずにリセットして次へ進んでください。

なお、Vの数が指定と異なる場合、計算ミスでなければ初期シード推定が不可能になる場合があります。セーブせずにリセットし、その後、改めて「みんなで挑戦」で日付を1日進めてからセーブしてから手順2-1-1に戻るか、続けるか選んでください。

f:id:tangential_star:20201122152955p:plain

指示に従って次のターゲットを決める。複数選べる場合はVが少ないほうがおすすめ
f:id:tangential_star:20201122160131g:plain
f:id:tangential_star:20201122161045p:plain
ターゲットを捕まえて個体値を確認。Lv100にするとわかりやすい

f:id:tangential_star:20201122161205p:plain

個体値を入力したら次へ。この時点でVの数が指定通りかを確認しておく
2-1-4.極力Vの少ない4日後の個体を探す @自動化可能

今までの手順と同様に、今度は「4日後」ポケモンを捕まえます。指定は特に無いので、好きなポケモンを選んでください。なお、Vの数が少ないほうがマシンスペックを食わずに済むので、もし心許ないPCを利用している方は極力Vが少ないものを選びましょう。また、精度の問題から、複数の初期シード候補が見つかることを防ぐためにも、Vの数は少ないほうがおすすめです。

※Vの数は、自然発生「ではない」Vの数です。ゆえに、2Vのポケモンを捕まえて3V以上でないことを確認するのが最も確実ですが、ミスを防ぐためにあえて5Vのポケモンを選び、6Vじゃ無いことを確認するのも有効です

捕まえたら手順2-1-3同様、個体値をツールに入力してください。そして、入力が終わったら、セーブせずにリセットしてください。自動化プログラム(ソースコードは後述)は、対応箇所を「3」から「4」に書き換えることで利用できます。

f:id:tangential_star:20201122162203p:plain

最後のステップでは「4日後」のポケモンを捕まえる。肝心なので間違えないように注意!

2-2.消費数の特定

ここまでお疲れさまでした。これで、3つの項目すべてが埋まったことだと思います。あとは、意気揚々と「検索開始」を押すだけです。計算時間がかなりかかります。マシンスペックにもよりますが、 「1つ見つけたら終了」にチェックを入れた状態なら、NVIDIAGPUグラボを積んだPCであれば10秒もかからずに検索可能です。普通に計算すると10分くらいかかるそうです。

なお、ここもマシンスペックとの相談ですが、運に自信がない人は右下の「1つ見つけたら終了」のチェックボックスは外しておいてください。推定された初期シードが複数候補が見つかっていた場合に、それに気づけず、その後の作業がすべて無駄になってしまう恐れがあるからです。

f:id:tangential_star:20201122175957p:plain

「検索開始」を押す前に確認しておく。グラボ設定は該当者のみでOK
2-2-1.推定初期シードの検証(シード特定作業を兼ねる)

「計算開始」を押してからしばらくすると、推定リスト(推定された初期Seedに基づいた消費数と個体値・色違いの有無)がテキストファイルで出てきます。この際、複数の初期シード(ツール上ではDen Seed)が候補になった場合、その旨を表すダイアログも出てきますので、見逃さないように注意しましょう。

このseeds.txtの行をまるまるコピーし、「1-StarSeedSearch」の「リスト出力」タブのDen Seedに入れてリスト出力すると、レイドの内容と推定されたSeed条件で、それぞれ出てくる能力の羅列が出てきます。なお、複数候補がでてきた場合、これらはツールに渡した情報(3日後・4日後のポケモン個体値や性格など)はすべて共通して満たしています。

ゆえに、複数の初期シード候補が出てきた場合は、6日目(5日後)以降でVの数が少ないレイドで比較検証することで、正しい初期シードを絞り込むことができます

f:id:tangential_star:20201122180338p:plain
f:id:tangential_star:20201122180347p:plain
推定された初期シードが複数見つかった場合、「seeds.txt」ができているので確認

f:id:tangential_star:20201122182950p:plain

候補ごとの結果と実際の結果で比較すれば正しいシードが特定できる
f:id:tangential_star:20201122190453g:plain
f:id:tangential_star:20201122190602p:plain
日付を(5回以上)回してオムスターが出ればラッキー。捕まえてリストと比較しよう
2-2-2.色違いが何日先に出現するかを調べる

次に、「色違いのみ」にチェックを入れて、「リスト出力」を押してください。もし、結果が何も出てこなければ適宜「最大消費数」を増やして出力してください。消費数とは、要するに次の手順で進める必要のある日数のことです。

なお、手順2-2-1で必ず「初期シードが正しいこと」を確認した上で以降の手順を進めてください。この特定が曖昧のままだと、これからの作業はすべて水の泡になります。 

f:id:tangential_star:20201122192117p:plain
f:id:tangential_star:20201122192425p:plain
「色違いのみ」にチェックを入れると、何日後に色違いレイドが出現するかが分かる

一応、今回の私の例で言うと、Seed=0x 3DC5C8246ECEC24C で、19046日後に星エフェクトの色違いレイドになることがわかります。

 

3.乱数消費パート

【色パッチルドン探しの手順】
1.準備 → 2.乱数調整 → 3.乱数消費(イマココ) → 4.捕獲
(3-1. ランクマバグ状態に移行 3-2. 乱数消費する)
3-1.ランクマバグ状態に移行

ここからは手順2-2-2で確認した「目標個体までの日数」を目指して、日付をひたすらすすめていきます。なお、目標までの消費数(日付を回す回数)が100日程度であれば、手動で変更することをおすすめします。

まず、効率よく日付を進めるために、ランクマッチやYY通信のカジュアルバトルで機内モードに変更した際に日付変更ペナルティが解除されるバグ(通称:ランクマバグ)を活用します。まずは、巣穴の前からポケモンセンターに移動してください。 

そして、ランクマバグ状態に下記手順で移行します。なお、この方法が使えない人は、素直にランクマッチで1戦してください(Nintendo Onlineへの加入が必要です)。

  1. ポケモンセンターの中に入る
  2. YY通信で「通信対戦」を行う(ローカル通信)
  3. もう一台のSwitch・剣盾を使ってその通信対戦に応じる
  4. 戦闘が始まったらHomeボタン長押し→「機内モード」をONに変更する
  5. エラーが発生するのでそれを閉じて、「にげる」選択
  6. ポケモンセンターに戻ってくる(移行完了)

この状態で、一度Home画面に戻り、日付を1日進めて、ゲーム画面に戻ってください。一瞬だけ画面全体がチラッと暗転していれば、正常にランクマバグ状態に移行できています。

f:id:tangential_star:20201122212921p:plain
f:id:tangential_star:20201122212902p:plain
ランクマバグ状態に入る前に、まずはブラッシータウンのポケセンに入ろう
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
エラーが出たら「にげる」で対戦終了。この状態で時刻変更すると一瞬画面が暗転する
3-2.乱数消費する @自動化可能

手順3-1でランクマバグ状態になると、日付変更のペナルティが発生しなくなります。さらに「設定で日付を変更してゲーム画面に戻った瞬間」ではなく「日付を変更した瞬間」にゲーム中でも日付変更が反映されるようになります。つまり、設定画面の中で日付を変更し、「OK」を押すたびにゲーム中の日付も同じ回数だけ進んでいることになります。したがって、Home画面などを介する必要がなくなるため、日付変更が1日あたり約2秒という驚きの速さで実現可能になります(ソースコードは後述)。

この状態で、手順2-2-2で確認した「目標個体までの日数」までひたすら進めていくのですが、実際に進めるのは「目標の日数-3日間」となることに注意してください。原理は割愛しますが、例えば目標の日数が「19046日後」なら、この手順で消費するのは19046-3=「19043日」となります。

f:id:tangential_star:20201123121934g:plain

ゲーム画面に戻る必要はない。ひたすら日付を進めていこう

目安までに、自動化プログラム(ソースコードは後述)で日付を1ヶ月進めるのに実測値で42秒かかりました。ざっくりアバウトで5000日分を2時間くらいで消費できます。もしかしたら、消費上限数はこの値を参考に決めても良いかもしれません。

 

消費する日数と、実際にかかる時間(Arduino Leonardo用プログラム利用時)

消費する日数 自動化プログラムで
かかる時間(推定)
備考
1日 約1.4秒  
30日 42秒(実測値) ※31日分日付変更
100日 約140秒(2分20秒)  
200日 約280秒(4分40秒) この辺から手動だとツライ
300日 約420秒(7分)  
365日 約511秒(8分31秒)  
720日 約1022秒(約17分) 経験上、手動の限界
1000日 約1400秒(23分20秒)  
2000日 約2800秒(46分40秒)  
2500日 約3500秒(58分20秒) 約1時間
5000日 約7000秒(116分40秒) 約2時間
10000日 約14000秒(3時間54分) 約4時間
15000日 約21000秒(350分) 約6時間
20000日 約28000秒(700分) 約8時間

 

4.捕獲パート

【色パッチルドン探しの手順】
1.準備 → 2.乱数調整 → 3.乱数消費 → 4.捕獲(イマココ)
(4-1. 残りの消費数確認 4-2. 3日後のパッチルドン探し 4-3. 捕獲!)
4-1.残りの消費数を確かめる

目的消費数の概ね10日くらい前まで消費が終わったら、まずは巣穴の前に戻り、セーブします(無論、最初から自信があれば目的消費数の3日前でも問題ありません)。

そして、巣穴に出ているポケモンを捕まえます。捕まえたら、個体値を計算してください。レイドの情報をもとに乱数調整ツールでリストを出力し、その個体値と性格の組み合わせがどこにいるかを確認してください。これが、「目的の消費数-3」に重なれば準備完了です。なお、現在位置を調べるためにポケモンを捕まえたら、必ずセーブせずにリセットしてください

現在位置が、「目的消費数-3」に届いていない場合は、巣穴の「みんなで挑戦」から日付を1日ずつ進めてください。ちょうど「目的消費数-3」の位置にいる場合はセーブして次の手順に進んでください。

f:id:tangential_star:20201123145601p:plain
f:id:tangential_star:20201123145639p:plain
巣穴に戻って出ているポケモンを捕まえる。レイド★の数確認も忘れずに
f:id:tangential_star:20201123145747g:plain
f:id:tangential_star:20201123145742p:plain
捕まえたら個体値チェックだ。性格・能力値・特性・性別なども忘れずチェック

f:id:tangential_star:20201123151702p:plain

リスト出力し、現在の個体がどのくらい離れているかを確認しよう

f:id:tangential_star:20201123153210p:plain

現在位置が「目的の消費数-3」になるまでズレを計算して進めていこう
4-2.3日後のパッチルドンを探そう!

ここまで長らくお疲れさまでした。あとは、パッチルドンを探すだけです。

感の良い方・ここまで読んでくれた方はお気づきかと思いますが、巣穴のレイドバトルは2日後まで出現するポケモンが決定しており、3日後以降はランダムになっています。ゆえに、現在位置が「目的消費数-3」のタイミングでセーブしたわけです。

では、3回日付を進めて「★3 パッチルドン」「★4 パッチルドン」「★5 パッチルドン」のレイドが出るまで粘りましょう。出なかったらセーブせずにリセットしてもう一度この手順を行ってください。出たら、セーブして次の手順に進みます。

この流れは、手順2-1-1と完全に同様ですね。一応、2-1-1で使った自動化プログラム(ソースコードは後述)でも同じことができるのですが、最後くらいは自力でやったほうが、喜びがひとしおだと思います。

f:id:tangential_star:20201123155836g:plain
f:id:tangential_star:20201125115703p:plain
3日進めてパッチルドンが来たら終了だ。忘れずにセーブしておこう

ちなみに、パッチルドンが出たらセーブするのが本来の流れなのですが、代わりに「キャンプ」を開くのも有効です。万が一、日付を多く進めてしまった場合の保険になります(キャンプであればセーブしないためリセットでやり直しができます)。ここでは詳細は割愛しますが、興味のある方は「キャンプバックアップ」で調べてみてください。Switchと剣盾を2組持っている場合には、ひたすらサブロム側で色違い手に入れ続けることもできます。

 

4-3.パッチルドンの捕獲

本当にここまでお疲れさまでした。あとは、お好きなボールを使ってパッチルドンを捕まえるだけです。

パッチルドンはキョダイマックス個体が無いので、「一人で挑戦」の場合にはどのボールを投げても捕獲率は100%になるはずですが、本当に捕まるか心配な人や「みんなで挑戦」で色違いレイドを配布する場合には、挑戦前に必ずセーブをしておきましょう。

f:id:tangential_star:20201123113607g:plain
f:id:tangential_star:20201123161659g:plain
待ちに待った色パッチルドン。好きなボールを投げよう!

f:id:tangential_star:20201123134007p:plain

色パッチルドンは全体的にグレーの色合い。レイドで大きくなってもかわいい

 

ソースコードと使い方

読み飛ばしてここまで来た方に向けて一応説明をしておくと、今回は2つのソースコードを作成しています。それぞれ使い方も合わせて載せますのでご参考ください。

1つ目→「3日後の巣穴厳選」 2つ目→「高速乱数消費

ソースコード1:「3日後の巣穴厳選」

このプログラムは、「リセット」⇒「ゲーム起動」⇒「巣穴から『みんなで挑戦』を押して日付進める」をTIME_WARP_DAYS回繰り返す ⇒「TIME_WARP_DAYS日分日付を戻す」という一連の流れを自動化してくれます。基本的に厳選1回目・2回目は「3」、3回目は「4」になるかと思います。適宜数字を調整して活用ください。

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

なお、現在の日時から起算してTIME_WARP_DAYS日進めて月をまたぐ場合には日付がズレてしまいます(例えば、2月27日や12月30日などから3日進めたら月をまたぐためNG)。現在の日時を調整するか、この値を+1するなどで対応してください。

使い方のイメージとしては、

  1. プログラムをArduinoに書き込む
  2. 「ねがいのかたまり」を入れて柱を建てる
  3. セーブする
  4. Arduinoを差し込む
  5. 動作が止まるまで放置
  6. 目的のレイドか確認。違った場合はArduinoを挿し直す(4に戻る)

となります。挿し直すだけで、リセット含めて3日後のレイドの内容確認まで放置ができるので、繰り返しの際には重宝します。

f:id:tangential_star:20201123132507g:plain
f:id:tangential_star:20201123010702g:plain
自動で日付が進み、募集画面で待機してくれる。目的のレイドでなかったら挿し直そう

もし、このリセットが冗長だと感じる場合には、PROTO_AUTO_GAME_QUITをfalseにしてください。その場合は「みんなで挑戦」の手前でArduinoを挿してください。

ではプログラムのソースコードです。

2020/12/5追記: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のファームウェアVer11に対応版(2020/12/1)★
 * ★NintendoSwitchのファームウェアVer13に対応版(2021/9/20)★
 * ★NintendoSwitchのファームウェアVer15に対応版(2022/10/23)★
 * 
 * 日付はTIME_WARP_DAYS日進めても、月がまたがないようにしておくこと。
 * あとは自動で日付巻き戻しもしてくれるので繰り返し利用もできます。
*/

#include <SwitchControlLibrary.h>

#define HOLDTIME (95)
#define INTERVAL (105)
#define TIME_WARP_DAYS (3) // 何日すすめるか(=ここは基本的に「3」。最後のステップで使うなら「4」)
#define FIRST_DAY_WATT_EARNING (false) // 1日手動で進めた場合など、Watt回収をしていない場合は「true」にしてください。
#define PROTO_AUTO_GAME_QUIT (true) // trueなら挿し直すだけで再起動も行ってくれるようになる

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

int current_days;

void PushHome(int delay_time_ms);
void PushA(int delay_time_ms);
void PushB(int delay_time_ms);
void PushX(int delay_time_ms);
void PushR(int delay_time_ms);
void PushL(int delay_time_ms);
void PushRL(int delay_time_ms);
void move_for(char* Direction); // ex: "right" "left" "up" "down"
void move_for(char* Direction, int delay_time_ms);
void move_for(char* Direction, int hold_time_ms, int delay_time_ms);

void setup() {
  PushRL(300);
  PushRL(300);
  PushRL(300);
  PushRL(300);
  PushRL(300);


  delay(1000);
  
  if(PROTO_AUTO_GAME_QUIT){
    PushHome(1000); // ゲーム終了のためにホームを押し。
    PushX(500); // 終了Xを押す→終了しますか?画面
    PushA(3000); // はい→終了しています・・・
    PushA(1000); // ゲームタイトルクリック→ユーザを選んでください画面(複数ユーザいる場合)
    PushA(18500); // A押してから起動までおおよそ16秒(最短目安。環境に合わせて設定すること)
    PushA(10000); // タイトル画面からフィールド遷移までおおよそ10秒(環境に合わせて設定すること)
    // if(!FIRST_DAY_WATT_EARNING)PushA(1500); // 募集画面に明示的に入る <- chinese対応
  }
  current_days = 0;

  if(FIRST_DAY_WATT_EARNING){
    // ★フィールド画面に戻ってくる(watt回収)
    // There's energy pouring out from the den! [Enter]
    PushA(500);  // 1回目は「A」
    // You gained 2,000W! [Quit]
    PushB(500);  // 2回目は「B」
  }
}

void loop() {

  // [Enter]
  PushA(1500);  // 3回目は「A」(募集画面に入る)

  if(current_days >= TIME_WARP_DAYS ){
    // TIME_WARP_DAYS日進めたあとの処理として、日付を戻す。
    PushA(4000); // 通信待機中・・・
    PushHome(1000);
    // Home画面で「設定」を選ぶ
    move_for("down");move_for("right");move_for("right");move_for("right");move_for("right");move_for("right");
    PushA(1500);
 
    // 設定画面で「日付と時刻」を開く
    move_for("down", 1500, (int)INTERVAL/4);move_for("right");

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

    PushA(500);
  
    // 時間設定(現在の日付と時刻を選ぶ)
    move_for("down");
    move_for("down");
    PushA(500);
  
    // 時刻設定(日付の部分のみ回していく
    // 時間の変更
    move_for("right");
    move_for("right");
    for(int i=0;i<TIME_WARP_DAYS;i++) move_for("down"); // 日付巻き戻し
    PushA(INTERVAL);
    PushA(INTERVAL);
    PushA(INTERVAL);
    PushA(INTERVAL);
    PushHome(2000);
    PushA(1000);
    // ↑ここまでで設定画面おわり。
  
    // 募集終了処理
    PushB(500);  // 「募集終了」を選択
    PushA(1000); // 「はい」
    PushA(4500); // 「はい」

    // フィールドに戻ったら募集待機画面状態で待機
    PushA(4000); // 通信待機中・・・
    for(;;)delay(1000);  
  }


  // 開始 みんなで挑戦の直前から(1日目もWatt回収がある前提)。
  PushA(4000); // 通信待機中・・・
  
  // Homeボタンを押して設定の画面へ移動
  PushHome(1000);

  // Home画面で「設定」を選ぶ
  move_for("down");
  move_for("right");
  move_for("right");
  move_for("right");
  move_for("right");
  move_for("right");
  PushA(1500);

  // 設定画面で「日付と時刻」を開く

  move_for("down", 1500, (int)INTERVAL/4); // 「↓」長押し
  move_for("right");

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

  // 時間設定(現在の日付と時刻を選ぶ)
  move_for("down");
  move_for("down");
  PushA(500);

  // 時刻設定(日付の部分のみ回していく
  // 時間の変更
  move_for("right");
  move_for("right");
  move_for("up");
  PushA(INTERVAL);
  PushA(INTERVAL);
  PushA(INTERVAL);
  PushA(INTERVAL);
  PushHome(2000);
  PushA(1000);
  // ↑ここまでで設定画面おわり。

  // 募集終了処理
  PushB(750);  // 「募集終了」を選択 // 500->750 chinese対応
  PushA(1000); // 「はい」
  PushA(4500); // 「はい」

  // ★フィールド画面に戻ってくる(watt回収)
  // There's energy pouring out from the den! [Enter]
  PushA(500);  // 1回目は「A」
  // You gained 2,000W! [Quit]
  PushB(1500);  // 2回目は「B」

  current_days++;

}

void PushHome(int delay_time_ms){
  SwitchControlLibrary().PressButtonHome();
  delay(210);
  SwitchControlLibrary().ReleaseButtonHome();
  delay(delay_time_ms);
  return;
}

void PushA(int delay_time_ms){
  SwitchControlLibrary().PressButtonA();
  delay(HOLDTIME);
  SwitchControlLibrary().ReleaseButtonA();
  delay(delay_time_ms);
  return;
}
void PushB(int delay_time_ms){
  SwitchControlLibrary().PressButtonB();
  delay(HOLDTIME);
  SwitchControlLibrary().ReleaseButtonB();
  delay(delay_time_ms);
  return;
}
void PushX(int delay_time_ms){
  SwitchControlLibrary().PressButtonX();
  delay(HOLDTIME);
  SwitchControlLibrary().ReleaseButtonX();
  delay(delay_time_ms);
  return;
}
void PushR(int delay_time_ms){
  SwitchControlLibrary().PressButtonR();
  delay(HOLDTIME);
  SwitchControlLibrary().ReleaseButtonR();
  delay(delay_time_ms);
  return;
}
void PushL(int delay_time_ms){
  SwitchControlLibrary().PressButtonL();
  delay(HOLDTIME);
  SwitchControlLibrary().ReleaseButtonL();
  delay(delay_time_ms);
  return;
}
void PushRL(int delay_time_ms){
  SwitchControlLibrary().PressButtonR();
  SwitchControlLibrary().PressButtonL();
  delay(HOLDTIME);
  SwitchControlLibrary().ReleaseButtonR();
  SwitchControlLibrary().ReleaseButtonL();
  delay(delay_time_ms);
  return;
}

void move_for(char* Direction){
  // ex: "right" "left" "up" "down"
  
  switch(Direction[0]){
    case 'r':
    case 'R':
    SwitchControlLibrary().MoveHat(2); // right
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(INTERVAL);
    break;

    case 'l':
    case 'L':
    SwitchControlLibrary().MoveHat(6); // left
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(INTERVAL);
    break;

    case 'u':
    case 'U':
    SwitchControlLibrary().MoveHat(0); // up
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(INTERVAL);
    break;

    case 'd':  
    case 'D':
    SwitchControlLibrary().MoveHat(4); // down
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(INTERVAL);
    break;

    default:
    break;  
  }
  
}

void move_for(char* Direction, int delay_time){
  // ex: "right" "left" "up" "down"
  
  switch(Direction[0]){
    case 'r':
    case 'R':
    SwitchControlLibrary().MoveHat(2); // right
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time);
    break;

    case 'l':
    case 'L':
    SwitchControlLibrary().MoveHat(6); // left
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time);
    break;

    case 'u':
    case 'U':
    SwitchControlLibrary().MoveHat(0); // up
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time);
    break;

    case 'd':  
    case 'D':
    SwitchControlLibrary().MoveHat(4); // down
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time);
    break;

    default:
    break;  
  }
  
}

void move_for(char* Direction, int hold_time_ms, int delay_time_ms){
  // ex: "right" "left" "up" "down"
  
  switch(Direction[0]){
    case 'r':
    case 'R':
    SwitchControlLibrary().MoveHat(2); // right
    delay(hold_time_ms);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time_ms);
    break;

    case 'l':
    case 'L':
    SwitchControlLibrary().MoveHat(6); // left
    delay(hold_time_ms);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time_ms);
    break;

    case 'u':
    case 'U':
    SwitchControlLibrary().MoveHat(0); // up
    delay(hold_time_ms);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time_ms);
    break;

    case 'd':  
    case 'D':
    SwitchControlLibrary().MoveHat(4); // down
    delay(hold_time_ms);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time_ms);
    break;

    default:
    break;  
  }

}

 

ソースコード2:「高速乱数消費」

このプログラムは、ランクマバグ状態で日付を自動で進めるプログラムです。あらかじめSHOHISUを「(目的消費数-3)」に書き換えてから使ってください。

プログラムを横着したので、31日まである月(1月・3月・5月・7月・8月・10月・12月)で使ってください。また、消費数を31で割って月繰り上がり(31日→1日)のズレ吸収を行っている単純なプログラムなので、もしかしたら消費数がズレているかもしれません。なので、実際は、「目的消費数-10」くらいで設定しておき、あとは手動で検証しながら進めることをおすすめします。

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

2021/1/26追記:
このSHOHISUの上限は「32767」となります。もし、32768以上の乱数消費が必要な場合、2回に分けて自動化をするなどで工夫してください。

 

使い方としては、

  1. プログラムを書き換え、Arduinoに書き込んでおく
  2. ポケモンセンターに入る
  3. ランクマバグ状態にする
  4. Homeボタンを押し、設定→本体→日付と時刻→現在の日付と時刻から、何も変更せずに「OK」を押しておく【重要】
  5. Arduinoを差し込んで放置

になります。注意としては、上記4にも書いている通り、一度日付変更画面に入り、OKを押しておいてください(カーソルの位置が変わるからです)。もし、この4の手順すら面倒だと感じる方はFIRST_TIMEを(true)にしてください。

f:id:tangential_star:20201123142146p:plain
f:id:tangential_star:20201123121934g:plain
時刻設定で「OK」を押しておくと、カーソルが「OK」から始まるので高速に消費ができる

特に難しいところも無いと思います。

プログラムのソースコードです。

2020/12/5追記:こちらはNintendoSwitch Ver.11.0アップデートの影響はありません
2021/9/20追記:こちらはNintendoSwitch Ver.13.0アップデートの影響はありません

/* 消費日数の計算はかなり甘めに作っているので、注意してください。
●ランクマバグ後につかうこと。
●31日ある月にしておくこと。
^^^^^^^^^^^^^^^^^^^^^^^
*/

#include <SwitchControlLibrary.h>

#define HOLDTIME (40)
#define INTERVAL (105)
#define FIRST_TIME (false)

#define SHOHISU (19046-3) // ここを「目的消費数-3」にする。
// ※実際には-10くらいにして、残りを手動でやったほうが良いかもです。

int maxlooptime;
int currentlooptime;

void PushHome(int delay_time_ms);
void PushA(int delay_time_ms);
void PushB(int delay_time_ms);
void PushR(int delay_time_ms);
void PushL(int delay_time_ms);
void move_for(char* Direction); // ex: "right" "left" "up" "down"
void move_for(char* Direction, int delay_time_ms);
void move_for(char* Direction, int hold_time_ms, int delay_time_ms);
void Debug(void);

void setup() {
  if(FIRST_TIME){
    PushR(100);
    PushL(100);
    PushR(100);
    PushL(100);
    PushR(100);
    PushL(100);
    delay(10000);
  }else{
    PushR(100);
    PushL(100);
    PushR(100);
    PushL(100);
    PushR(100);
    PushL(100);
    PushR(100);
    PushL(100);
    delay(3000);
  }

  
  // 現在のループ回数を数える変数
  currentlooptime = 0;

  // 31日ごとに消費できる数は30なので31試行ごとに1試行分のモレが発生。それを計算。
  maxlooptime = (int)( (double)SHOHISU + (double)SHOHISU/31.0 ); 


  // first time
  if(FIRST_TIME){
    PushA(3000);
    
    PushA(250);
    PushA(250);
    move_for("up");
    PushA(250);
    PushA(250);
    PushA(250);
    PushA(250);
    currentlooptime++;
  }
  delay(1000);

}

void loop() {

  if(currentlooptime >= maxlooptime ){
    PushHome(1000);
    for(;;)delay(1000);  
  }

  PushA(INTERVAL);
  delay(20);
  move_for("left");
  move_for("left");
  move_for("left");
  move_for("up");
  PushA(INTERVAL);
  PushA(INTERVAL);
  PushA(INTERVAL);
  PushA(INTERVAL);
  currentlooptime++;
  delay(20);
}

void PushHome(int delay_time_ms){
  SwitchControlLibrary().PressButtonHome();
  delay(210);
  SwitchControlLibrary().ReleaseButtonHome();
  delay(delay_time_ms);
  return;
}

void PushA(int delay_time_ms){
  SwitchControlLibrary().PressButtonA();
  delay(HOLDTIME);
  SwitchControlLibrary().ReleaseButtonA();
  delay(delay_time_ms);
  return;
}
void PushB(int delay_time_ms){
  SwitchControlLibrary().PressButtonB();
  delay(HOLDTIME);
  SwitchControlLibrary().ReleaseButtonB();
  delay(delay_time_ms);
  return;
}
void PushR(int delay_time_ms){
  SwitchControlLibrary().PressButtonR();
  delay(HOLDTIME);
  SwitchControlLibrary().ReleaseButtonR();
  delay(delay_time_ms);
  return;
}
void PushL(int delay_time_ms){
  SwitchControlLibrary().PressButtonL();
  delay(HOLDTIME);
  SwitchControlLibrary().ReleaseButtonL();
  delay(delay_time_ms);
  return;
}void move_for(char* Direction){
  // ex: "right" "left" "up" "down"
  
  switch(Direction[0]){
    case 'r':
    case 'R':
    SwitchControlLibrary().MoveHat(2); // right
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(INTERVAL);
    break;

    case 'l':
    case 'L':
    SwitchControlLibrary().MoveHat(6); // left
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(INTERVAL);
    break;

    case 'u':
    case 'U':
    SwitchControlLibrary().MoveHat(0); // up
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(INTERVAL);
    break;

    case 'd':  
    case 'D':
    SwitchControlLibrary().MoveHat(4); // down
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(INTERVAL);
    break;

    default:
    break;  
  }
  
}

void move_for(char* Direction, int delay_time){
  // ex: "right" "left" "up" "down"
  
  switch(Direction[0]){
    case 'r':
    case 'R':
    SwitchControlLibrary().MoveHat(2); // right
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time);
    break;

    case 'l':
    case 'L':
    SwitchControlLibrary().MoveHat(6); // left
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time);
    break;

    case 'u':
    case 'U':
    SwitchControlLibrary().MoveHat(0); // up
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time);
    break;

    case 'd':  
    case 'D':
    SwitchControlLibrary().MoveHat(4); // down
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time);
    break;

    default:
    break;  
  }
  
}

void move_for(char* Direction, int hold_time_ms, int delay_time_ms){
  // ex: "right" "left" "up" "down"
  
  switch(Direction[0]){
    case 'r':
    case 'R':
    SwitchControlLibrary().MoveHat(2); // right
    delay(hold_time_ms);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time_ms);
    break;

    case 'l':
    case 'L':
    SwitchControlLibrary().MoveHat(6); // left
    delay(hold_time_ms);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time_ms);
    break;

    case 'u':
    case 'U':
    SwitchControlLibrary().MoveHat(0); // up
    delay(hold_time_ms);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time_ms);
    break;

    case 'd':  
    case 'D':
    SwitchControlLibrary().MoveHat(4); // down
    delay(hold_time_ms);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time_ms);
    break;

    default:
    break;  
  }

}

void Debug(){
  // Homeボタンを2回押すだけの関数
  PushHome(1000);
  PushHome(1000);
  return;  
  
}

 

あとがき

今回は、乱数調整をベースにArduinoを活用して、色パッチルドンを見つける記事を書きました。前回の記事では、パッチルドンをウカッツから自動で受け取って色違いを厳選する方法を紹介しましたが、やっぱりレイド産はボール厳選ができることが何よりも強みですね。

ただし、モンスターボール以外で捕まえると自ずとレイド産とバレてしまうという点は注意が必要です。レイド産のパッチルドンは必ず夢特性になるので「ゆきかき」で意表を突くことが難しくなり、「ちくでん」ではないことを自ら告白することになります。

とはいえ、タマゴ未発見のオシャボ入りというだけでその価値は天井知らずですから、そんなのは些細な問題に過ぎないかもしれませんね。私も今回、サファリボールで捕まえましたし。

 

ところで、乱数を今まで知らなかった人にとっては、かなり「大変」だと思ったのではないでしょうか。また、乱数を知っている人も、文章にするとかなり長くなると感じたのではないでしょうか。どちらが楽かという議論ではなく、乱数調整は厳選と同じく手間暇がかかる作業です。その点、Arduinoであれば、乱数・厳選を問わず簡略化や効率化ができるという点あるいは可能性にも気づいていただけたのではないかと思います。

これを読んでArduinoのユーザーが増えたり、コミュニティが活性になったりを期待しています。また、プログラミングや組み込み系への興味、はたまたゲームへの興味などが増えるとより嬉しいですね。

 

パッチルドンかわいい(余談)

さて。突然ですが、こちらを御覧ください。

f:id:tangential_star:20201123163741g:plain
f:id:tangential_star:20201123163828p:plain
パッチルドンは歩くのが苦手なのだ
f:id:tangential_star:20201123164331g:plain
f:id:tangential_star:20201123165307g:plain
キャンプではよちよち歩いてくる。戦闘では可憐に登場するぞ

執筆中ずっと思ってたんですけど、パッチルドンって本当にかわいらしいですよね。 

いや、コイツめちゃくちゃかわいくないですか?? 

何がって、たぶんチャームポイントは鼻水だと思うんですよ。上のgif画像でも分かると思いますが、念の為0.5倍速と0.16倍速を準備しましたので、下記にて御覧ください(あと、捕まえたボール「サファリボール」のエフェクトもご確認ください)。

f:id:tangential_star:20201123171250g:plain
f:id:tangential_star:20201123171313g:plain
はなみずに着目!かわいいぞ!!(左:0.5倍速/右:0.16倍速)

 いやぁ。良いんじゃないでしょうか…。

 

てなわけで今回はこのへんで。

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

 

 

補足記事(Arduinoの使い方・使うタイミングについての詳しい解説はこちら):

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

  

前記事:

【Arduino自動化04】パッチルドン自動受け取り(中国語・英語対応)

次記事:

【Arduino自動化06】完全放置「マックスこうせき」集め【ダイマックスアドベンチャー】

導入記事:

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

 

【Arduino自動化04】パッチルドン自動受け取り(中国語・英語対応)

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

ポケモン自動化4つ目の記事です。今回は、Arduino Leonardoで剣盾の化石ポケモン「パッチルドン」の受け取りを自動化します。これで色厳選・性格厳選・最遅厳選などができます。今回は、日本語のほかに、英語版・中国語版で動作確認しています。

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

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

 

概要

本記事では、「パッチルドン」の受け取りを自動化します。

f:id:tangential_star:20201114151526g:plain

カーソル移動があり連射コントローラーでは対応しにくい化石の受け取りも対応

 

では、もくじです。

 

作ったきっかけ

ポケモンの国際孵化のためにポケモン剣盾を英語版で遊んでいたのですが、Arduinoプログラムそのままだと動作がずれてうまく動きません。そこで、どうせなら外国語表記にも対応させよう!と思ったので作りました(だって外国語ってかっこいいじゃん…)

f:id:tangential_star:20201114170502g:plain

文字送り速度を調整して英語版でも正しく動くように!

ちなみに、パッチルドンに限らず化石ポケモンDLC冠の雪原でレイドで野生が解禁されました。こちらはレイドと違い、ボール厳選ができない反面、「完全放置」で「色厳選」ができます


使い方

諸々準備した後、ウカッツの前でArduinoを挿すだけです。

ちなみに、化石厳選を手動でやったことがある人なら知っているかもしれませんが、剣盾側で「設定」をいじる必要があります。注意しましょう。

デフォルトでは、日本語版の環境においてキリの良い100分(試行回数330回=11ボックス分)で止まるようなプログラムになっています。化石の所持数やボックスの空き状況などの必要に応じて、プログラムを書き換えてください。

準備はいいから早くソースコード寄越せって方は、どうぞ→ 読み飛ばす

f:id:tangential_star:20201114190354p:plain
f:id:tangential_star:20201114190401p:plain
左右の靴の色が違うミステリアスウーマン・ウカッツ氏は6番道路にいる
f:id:tangential_star:20201114191009p:plain
f:id:tangential_star:20201114191015p:plain
ボックスはしっかり空けておこう。連番で空けておくと後で確認が楽だ。

 

事前準備

準備としては、カセキ集め、ポケモン剣盾の設定とプログラムの書き換えの2つが必要です。それぞれの詳細は下記に載せますが、忘れがちな手順として、SEを消すなどがあるので注意しましょう。

化石を準備(カセキ集め)

パッチルドンの復元には、「カセキのトリ」「カセキのクビナガ」の2種類が必要です。充分な量を用意しましょう。カセキ集めは、ハシノマはらっぱの「穴掘り兄弟」の左側の兄貴(スキルのある方)にしてもらいましょう。ついでに「ねがいのかたまり」「ぎんのおうかん」などレアアイテムも掘りだせるのでコスパが良いです。

もし充分にカセキが無い人は、 自動ワット稼ぎ でワットをカンストしてから A連打で無限穴掘り をすると効率的です。

f:id:tangential_star:20201114211539p:plain

化石は余裕を持って準備しておく。パッチルドンは「トリ」「クビナガ」が必要だ。

ポケモン剣盾「設定」

設定画面を開き、下記の通り設定してください。「『SE』なんて項目が無いよ」って人は、エンジンシティで「すごいみみせん」をもらってください。

  • 話の速さ・・・「速い」
  • 手持ち/ボックス・・・「自動で送る」
  • ニックネーム登録・・・「しない」
  • SE・・・「0」

ちなみに、手動で化石厳選したことある人には分かると思いますが、SEを0にしないと、暗転した画面で「シュルルルルシュピッ!ピンポーン!」という音が2-3秒くらい入ります。1試行あたりの時間効率を上げるためにもSEは「0」推奨です。無論、今回のプログラムもそれに倣います。

f:id:tangential_star:20201114190048p:plain
f:id:tangential_star:20201114190054p:plain
「話の速さ」は「速い」、「手持ち/ボックス」は「自動で送る」に設定
f:id:tangential_star:20201114190132p:plain
f:id:tangential_star:20201114190127p:plain
さらに「ニックネーム登録」は「しない」、「SE」は「0」に設定

プログラムの書き換え(受け取る数)

前述の通り、このプログラムはパッチルドンを330匹(=11ボックス分)受け取ったら止まるようなプログラムになっています。化石の所持数やボックスの空き状況などの必要に応じて、プログラムを書き換えてください。

具体的には、「MAX_LIMIT_RECEIVE_POKEMON」の数字を必要に応じて「(330)」から書き換えます。日本語なら、1匹の受け取りにかかる時間は約18秒です。目安として、1ボックスで約9分、11ボックスで約100分です。

ちなみに、この1行をまるまる消すと、無限ループする(上限なく繰り返し続ける)プログラムになります。よくわからない人は素直に数字を入れてください。

// ↓受け取り上限数(空きボックス・所持化石の数で)を決めること
#define MAX_LIMIT_RECEIVE_POKEMON (330)

 

さらに、英語で遊んでいる人はその下にある「INTARVAL」の数字を「650」から「1300」に書き換える必要があります。中国語の人は「650」のままでOKです。

// ↓対応ロムの言語でINTARVAL(コマンド入力の間隔)を決めること 
#define INTERVAL (650)
// ←日本語・中国語ROM
//#define INTERVAL (1300) // ←英語版ROM

 

書いたプログラム

ウカッツに話しかけた時のセリフをひたすらAで進めていき、カセキの選択肢だけカーソル移動してAを押すだけのプログラム。

「そーれ がっちゃんこ! よし! よし! よしっ!」「パッチルドンを もらった!」 「パッチルドンを ボックスに転送しました!」など、待ち時間を調整しています。 

必要に応じて MAX_LIMIT_RECEIVE_POKEMON, INTERVALを書き換えてください。

/* ★自動カセキメラ受け取り【パッチルドン】★
【重要】設定 → SEを0、ニックネームはつけない、ボックスに自動で送る
上記設定で、ウカッツの前でセーブしてからArduinoを挿す。
*/ #include <SwitchControlLibrary.h> // ↓受け取り上限数(空きボックス・所持化石の数で)を決めること #define MAX_LIMIT_RECEIVE_POKEMON (330) // ↓対応ロムの言語でINTARVAL(コマンド入力の間隔)を決めること(どちらか) #define INTERVAL (650) // ←日本語・中国語ROM //#define INTERVAL (1300) // ←英語版ROM #define HOLDTIME (95) void PushHome(int delay_time_ms); void PushA(int delay_time_ms); void PushB(int delay_time_ms); void move_for(char* Direction); // ex: "right" "left" "up" "down" void move_for(char* Direction, int delay_time_ms); void move_for(char* Direction, int hold_time_ms, int delay_time_ms); void Debug(void); void setup() { PushHome(1000); PushHome(1000); PushHome(1000); PushHome(1000); PushHome(1000); PushHome(5000); // 5秒待つ PushHome(1000); delay(250); } void loop() { #ifdef MAX_LIMIT_RECEIVE_POKEMON int current_loop=0; for( current_loop=0; current_loop<MAX_LIMIT_RECEIVE_POKEMON; current_loop++ ){ #endif PushA(INTERVAL); // ん? カセキ そろってんね この ウカッツに みせてみ? PushA(INTERVAL); // はい //move_for("down"); // ウカッツの 眼鏡に かなう カセキは どれかね? delay(100); PushA(INTERVAL); // → カセキのトリを選択 delay(100); move_for("down"); // ウカッツの 興味を そそる カセキは どれかね? PushA(INTERVAL); // → カセキのクビナガ PushA(INTERVAL); // カセキのトリと カセキのクビナガで 復元? → それで よければ PushB(2200); // おけー! 復元しちゃって カセキの ナゾに せまるゾ!【暗転】 PushB(INTERVAL); // そーれガッチャンコ【明転】 delay(100); PushB(INTERVAL); // 目標 達成! みごとな 復元 カモ delay(100); PushB(INTERVAL); // 太古の ガラルで 暮らしていた 様子が 目に 浮かぶ ようだネ! PushB(4900); // かわいがって くれたまえよ PushB(2400);// パッチルドンを もらった! PushB(1200); // パッチルドンを 手持ちに 加えました! //Debug(); #ifdef MAX_LIMIT_RECEIVE_POKEMON } for(;;); // ここで処理終了(動作停止) #endif } void PushHome(int delay_time_ms){ SwitchControlLibrary().PressButtonHome(); delay(210); SwitchControlLibrary().ReleaseButtonHome(); delay(delay_time_ms); return; } void PushA(int delay_time_ms){ SwitchControlLibrary().PressButtonA(); delay(HOLDTIME); SwitchControlLibrary().ReleaseButtonA(); delay(delay_time_ms); return; } void PushB(int delay_time_ms){ SwitchControlLibrary().PressButtonB(); delay(HOLDTIME); SwitchControlLibrary().ReleaseButtonB(); delay(delay_time_ms); return; } void move_for(char* Direction){ // ex: "right" "left" "up" "down" switch(Direction[0]){ case 'r': case 'R': SwitchControlLibrary().MoveHat(2); // right delay(HOLDTIME); SwitchControlLibrary().MoveHat(8); // center delay(INTERVAL); break; case 'l': case 'L': SwitchControlLibrary().MoveHat(6); // left delay(HOLDTIME); SwitchControlLibrary().MoveHat(8); // center delay(INTERVAL); break; case 'u': case 'U': SwitchControlLibrary().MoveHat(0); // up delay(HOLDTIME); SwitchControlLibrary().MoveHat(8); // center delay(INTERVAL); break; case 'd': case 'D': SwitchControlLibrary().MoveHat(4); // down delay(HOLDTIME); SwitchControlLibrary().MoveHat(8); // center delay(INTERVAL); break; default: break; } } void move_for(char* Direction, int delay_time){ // ex: "right" "left" "up" "down" switch(Direction[0]){ case 'r': case 'R': SwitchControlLibrary().MoveHat(2); // right delay(HOLDTIME); SwitchControlLibrary().MoveHat(8); // center delay(delay_time); break; case 'l': case 'L': SwitchControlLibrary().MoveHat(6); // left delay(HOLDTIME); SwitchControlLibrary().MoveHat(8); // center delay(delay_time); break; case 'u': case 'U': SwitchControlLibrary().MoveHat(0); // up delay(HOLDTIME); SwitchControlLibrary().MoveHat(8); // center delay(delay_time); break; case 'd': case 'D': SwitchControlLibrary().MoveHat(4); // down delay(HOLDTIME); SwitchControlLibrary().MoveHat(8); // center delay(delay_time); break; default: break; } } void move_for(char* Direction, int hold_time_ms, int delay_time_ms){ // ex: "right" "left" "up" "down" switch(Direction[0]){ case 'r': case 'R': SwitchControlLibrary().MoveHat(2); // right delay(hold_time_ms); SwitchControlLibrary().MoveHat(8); // center delay(delay_time_ms); break; case 'l': case 'L': SwitchControlLibrary().MoveHat(6); // left delay(hold_time_ms); SwitchControlLibrary().MoveHat(8); // center delay(delay_time_ms); break; case 'u': case 'U': SwitchControlLibrary().MoveHat(0); // up delay(hold_time_ms); SwitchControlLibrary().MoveHat(8); // center delay(delay_time_ms); break; case 'd': case 'D': SwitchControlLibrary().MoveHat(4); // down delay(hold_time_ms); SwitchControlLibrary().MoveHat(8); // center delay(delay_time_ms); break; default: break; } } void Debug(){ // Homeボタンを2回押すだけの関数 PushHome(1000); PushHome(1000); return; }

 

動作確認

日本語版・英語版共にしっかりと動くはずです。
また、他の言語でやる場合も、上記プログラム書き換えの数字を調整すればうまくいくと思います(おそらく英語版と同じで動くのでは?)。

f:id:tangential_star:20201114151526g:plain
f:id:tangential_star:20201114170502g:plain
動作例(再掲)
※英語版では文字送り速度(プログラム上でINTERVAL)を650→1300に書き換え

 

あとがき

DLC「冠の雪原」が導入されて、パッチルドンを始めとする剣盾カセキポケモン4匹(通称カセキメラ)もレイドバトルで出現するようになりました。これが意味することは、彼らのボール厳選ができるようになってしまった、ということです(ショック)。

とはいえ、良くも悪くも今作のカセキポケモン4匹は「タマゴ未発見」グループのため、孵化厳選ができません。もとよりシンクロで性格固定もできないわけですし、レイドと今回の比較で見るならば、「色厳選」の観点で完全放置でできるこちらに軍配が上がりますよね。

同DLCで夢特性「ゆきかき」も解禁されたわけですし、色違いの「ゆきかきパッチルドン」の「でんげきくちばし」なんでのも面白いかと思います。

妄想が膨らみますね(この記事を書いている間にもずっとプログラム動かしていますが未だに色違いは見ていません。はやく会えるといいなぁ…)。→翌日に会えました

f:id:tangential_star:20201114224834p:plain
f:id:tangential_star:20201114224427p:plain
昼も夜も休むことなくウカッツはカセキを復元し続ける…

ニックネームをつけよう【余談】

完全に余談ですが、どうして今回は英語版や中国語版に対応させようと躍起になったかと言うと、ニックネームに英語7文字以上や漢字の入力がしてみたくなったからです。特に中国語(漢字)を使ったニックネームはマイブームでして、人気アニメのキャラクター名や必殺技名、地名や会社名など、色々と表記できるなぁと感心しています。

ちなみに、中国語で使われる漢字には「簡体字」と「繁体字」の2種類がありますが、後者は台湾や香港で使われている漢字で、日本語のそれと字体が近いものが多いんですね。Switchでは入力にコツがいりますが、漢字は日本人にとっても読みやすいものですし、いろいろなニックネーム付けや「おや」の名前が面白くできるので、個人的におすすめです。

f:id:tangential_star:20201114153541j:plain

中国語(繁体字)でのニックネーム例。
日本語では表せない厨二病くさいネームもお手の物だ。

実は、繁体字には、日本にない自体の漢字だったり、対応する漢字がそもそも無かったりなど、ちょっとだけ工夫が必要なので注意しましょう。

私としてはネタで、例えば

  • エンテイに「唯一神(エンテイ)」(第4世代以前のネタ
  • ブースターに「唯一王(ブースター)」(第5世代以前のネタ
  • しんそくマッスグマ(オリジナル)に「(マッスグマ)」(第7世代以前のネタ
  • 自信過剰ヘラクロス♂に「刺穿死棘槍(ゲイ・ボルク)」とつけてメガホーン@ハチマキ

あたりは面白いんじゃないかなーとか思っています。

 

あ、完全に話がそれちゃいましたね。

 

以上、今回のあとがきでした。

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

 

前記事:

【Arduino自動化03】ワット稼ぎ・自動回収

 


11月15日22時半追記:無事にパッチルドンの色違いに出会えました。

試行回数は9,592匹でした。かかった時間は丸1日。

でも昨日作って今日出てきたので効率としては悪く無い…よね…?(苦行でした)

f:id:tangential_star:20201115230253g:plain

色違いのパッチルドンに会えた瞬間。受け取った直後に色違いかどうかが確認できる。

f:id:tangential_star:20201115224704g:plain

震える色違いパッチルドンかわいいいい!!

ちなみに、これまた余談ですが、彼ら剣盾のカセキポケモンたちは「ひかるおまもり」の効果を受けないため、一律1/4,096の確率で色違いが出現します。n回目に色違いと出会える確率pは、p=1-(4095/4096)^nで計算できます。

私と同様に9,592回厳選すれば、上記pは90.3%となりますので、10人に9人は色違いに会える計算となりますね。

 

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

 

前記事:

【Arduino自動化03】ワット稼ぎ・自動回収

後記事:

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

導入記事:

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

【Arduino自動化 番外編2】NintendoSwitchControllライブラリの導入と、自動化できる作業の一覧【ポケモン剣盾自動化】

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

本記事では、前回の記事で紹介したArduino Leonardo用のSwitch操作用ライブラリ「NintendoSwitchControll」のインストール手順を説明します。つまり、導入記事でインストールする「SwitchControlLibrary」と合わせて2種類のライブラリを扱えるようになることをゴールとします。

何が嬉しいかと言うと「Arduino Leonardoでポケモン剣盾を自動化するけど、ソースコードを触る気はサラサラ無いよ。コピペしかしないよ」って方には朗報で、どちらのライブラリで書かれたソースコードも使えるようになります。要するに、単純計算でコピペでつかえるプログラムの種類が2倍になります。

 

では、もくじです。

経緯は長いので「大前提」まで読み飛ばし可。

結論(自動化できる作業の一覧)だけ読みたい人は「2つのライブラリを導入してできるポケモン剣盾マクロ」までジャンプしてください。

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

 

経緯

前回の記事では「番外編」と称して、ポケモン剣盾自動化をするためにはArduino UNOまたはArduino Leonardoのいずれかを購入すれば良いことを紹介しました。そして、その中で、Arduino Leonardoには「SwitchControlLibrary」「NintendoSwitchControll」の2つのライブラリがあることを取り上げました。

繰り返しになりますが、当ブログでは導入記事でも紹介している通り「Arduino Leonardo」+「SwitchControlLibrary」の組み合わせをおすすめしています。これは、当ブログのソースコードを読んだり、自らソースコードをバリバリ書いていく人が、導入時あるいは開発時に混乱しないためのある種の指針です。

これらのライブラリは両方とも目的が同じなので、名前が似ているというだけでなく、中身の定数宣言や基本的なclassの作り方・メソッド構成もそっくりです。ゆえに、両方を導入すると、開発者はソースコードをコピペしたり参照したりする際に、どちらのライブラリを使っているのかを意識せねばなりません。

 

NintendoSwitchControllとSwitchControlLibraryの冒頭比較

NintendoSwitchControllとSwitchControlLibraryのライブラリの一部を抜粋。
説明のため恣意的な比較になるが、ほぼすべてが一致していることが分かる。

一方で、ソースコードをメンテナンスする予定がなかったり、サンプルや世の中に公開されているソースを「そのまま使う」だけという場合には、事情が変わります。この場合、「プログラミング知識」「ライブラリの知識」を一切使わないので、目的が「コンパイルがきちんとできること」に挿げ替えられます。要するに、どちらのライブラリでも構わないから、きちんと動いてくれさえすればOKという発想になります。

だいぶ前置きが長くなりましたが、本記事では、導入記事でインストールする「SwitchControlLibrary」に続いて、「NintendoSwitchControll」も導入する手順を紹介します。

コードを読んで開発や改良をする場合
コピペしかしない前提の場合

Arduino Leonardoを使って剣盾を自動化する場合の考え方の比較。
(左:コードを読んで開発や改良をする場合/右:コピペしかしない前提の場合)

 

大前提

本記事は、本ブログの導入記事に則って、ArduinoIDEのインストールならびに、その他諸々の設定(AVRの導入、board.txtの書き換えSTL・SwitchControlLibraryの導入など)が完了している前提で書いています。

もし、まだこれらを導入されていない方は先にそちらを進めてください。SwitchControlLibraryの導入以外、すべて共通の導入手順ですし、手間もそう変わらないのでついでにSwitchControlLibraryもインストールしておくと良いかと思います。

 

「NintendoSwitchControll」のインストール

本記事で紹介する「NintendoSwitchControll」は、前回同様、Githubhttps://github.com/interimadd/NintendoSwitchControll)からダウンロードできます。

NintendoSwitchControllのダウンロード手順

NintendoSwitchControllのダウンロード手順

ZIPをダウンロードしたら解凍し、Arduinoのライブラリフォルダにフォルダごと入れてください。もちろん、本作業はArduino IDEが終了している状態で行うことを推奨します。場所は、下記好きな方で大丈夫です。

  • ユーザドキュメント直下のArduinoフォルダ【おすすめ】
    (例 C:\Users\<ユーザ名>\Documents\Arduino\libraries )
  • 本体インストールフォルダ(Program files(x86))のArduinoフォルダ
    (例 C:\Program Files (x86)\Arduino\libraries )

 

Windowsインストーラー版の場合、ドキュメントフォルダ直下にArduinoフォルダがある。Arduino→librariesにフォルダごとドラッグ&ドロップでライブラリの追加が完了する。

 

なんと、ライブラリの追加はこれで完了です。お疲れさまでした。

これで分かると思いますが、Arduino IDEにおいて、ライブラリの導入自体はハードルが決して高くありません。

 

サンプルスケッチのコンパイル

「NintendoSwitchControll」ライブラリを使ったサンプルファイルは、実はライブラリの中に同梱されています(お得ですね)。

具体的には、ライブラリをインストールしたファイル(例  C:\Users\<ユーザ名>\Documents\Arduino\libraries\NintendoSwitchControll-master\examples\pokemon )の中に格納されています。ここから、実行したいプログラムの入ったフォルダを、まるごとArduinoのフォルダにコピペまたは移動すれば準備完了です。

後は、Arduino LeonardoをPCに差し込み、その中のフォルダにある.inoをダブルクリックで開き、前回と同様、左上の「マイコンボードに書き込む」ボタンを押せばOKです。

なお、本ライブラリのサンプルの動作については、Githubを確認してください。

GitHub - NintendoSwitchControll: サンプルスケッチの説明

f:id:tangential_star:20201109235422p:plain

サンプルプログラムの導入方法。examples→pokemonフォルダの中から、
使いたいプログラムをフォルダごとArduinoフォルダにコピペする。

 

2つのライブラリを導入してできるポケモン剣盾マクロ

ここまでお疲れさまでした。そして、おめでとうございます。

これで、今、あなたのPCにはArduinoIDEと、Switchを制御する主要なライブラリ「SwitchControlLibrary」と「NintendoSwitchControll」の2つが無事に導入されました。

これによって様々なことがコピペで完結できるようになります。具体例を下記にリンクと共に一例を載せます。

なお、使い方は必ずリンク先で確認の上、自己責任で利用してください。また、動作をすべて確認したわけではありませんのであしからず。

 

2021/2/5追記;本記事を執筆していた頃と違い、私のブログ内容もだいぶ充実してきました。もし、当ブログの自動化記事のみをご覧になりたい方がいらっしゃれば下記からカテゴリ別にアクセスできます。

ポケモン剣盾Arduino自動化 カテゴリーの記事一覧 - ますたーの忘備録

 

SwitchControlLibraryを利用したプログラム

NintendoSwitchControllを利用したプログラム

※先頭3つはライブラリのサンプルで同梱されているもの

 

結論

本記事では、本ブログでおすすめしている「SwitchControlLibrary」の導入と合わせて「NintendoSwitchControll」の導入手順を紹介しました。

そして、これら2つのライブラリに対応することで、前項でリンク先を載せている通り、下記さまざまなことがコピペだけでできるようになります

  • きのみを揺らし続ける
  • 穴掘り兄弟に穴を掘らせ続ける
  • 自動でワットを回収する
  • ワットショップの目玉商品を買い続ける
  • 化石を自動で復元させる
  • 羽を集め続ける
  • 自動でマジカル交換を行い続ける
  • 自動で孵化させる
  • 自動でボックスのポケモンを逃がす
  • 自動でレイドバトルに参加し捕獲する
  • 色違い用の孵化厳選をする
  • 自動でカレーを作り続ける
  • 自動で掘り出し物を買い続ける
  • 自動でIDくじを引き続ける
  • 自動で乱数調整の高速消費をする
  • 自動でレイドバトルをソロ周回する
  • 自動でレイドバトルをローカル配布する

なんて魅力的なのでしょう(一部手前味噌ですが)。

このように、ライブラリの垣根を超えてスケッチの導入ができるのは、Arduino IDEの良いところだと思います。

 

あとがき

今回は、導入記事Arduino Leonardoをおすすめした理由がなんとなく理解できたのではないかと思います。また、やってみると意外と簡単なのだと思ったのではないでしょうか。

上記リンクの種類でもわかりますが、今は全国にいる有志の方々がソースコードを紹介しています。おかげで、コピペはもちろん実は開発も捗るんですよね。

本記事や、これらの関連記事などを読んで、少しでも興味を持った方がいらっしゃれば、是非ともまずは開発や改善にチャレンジしてみてください。

ポケモン剣盾に限らず、Switchの自動化には可能性があると私は思いますし、これがきっかけになって将来有望なプログラマハッカーが現れればなお素敵なことだと思います。

 

 

ちなみに、上記以外のソースコードも、Webを探せば出てくるかもしれません。そういうものはたいてい、「Arduino Leonardo やりたいこと」で検索すると出てきます。

そして、出てきたソースコードの先頭行を確認して

  • 「#include <auto_command_util.h>」とあれば「NintendoSwitchControll」が必要
  • 「#include <SwitchControlLibrary.h>」とあれば「SwitchControlLibrary」が必要
  • どちらも入っていなければ、おそらくそのソースコードは使えないもの

と簡易に判断することもできます。

もし、「他にも調べたいな!」となったら上記手順は一度お試しあれ。

 

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

 

前記事:

【Arduino自動化 番外編】マイコン導入にあたって気をつけるべきと思ったこと【ポケモン自動化 方法調査】

導入記事:

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

【Arduino自動化 番外編】マイコン導入にあたって気をつけるべきと思ったこと【ポケモン自動化 方法調査】

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

今回は、ポケモン剣盾の自動化をするにあたってArduinoマイコンの比較と、参考Webサイトについてまとめます。
付け焼き刃な知識ですが、皆様の最初のマイコン選びの一助になると思い、素人なりに一生懸命調べたので、忘備録がてら記します(間違ってたらごめんなさい)。

長いので、忙しい人は「Arduino UNO・Leonardoそれぞれの剣盾自動化」以降を読むと、先駆者のブログ記事にリンク貼っていますので参考になると思います。

 

目次は下記の通りです。

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

 

経緯(初心者が陥るマイコン選びの罠)

本当は4本目のポケモン剣盾自動化の記事…にしようかと思ったのですが、初心に立ち返ると、マイコンの購入がすごくハードルが高かったことを思い出しました。

(そりゃ、うまく行かないかもしれないものに3~4000円もかけてボード(互換機なら安いですが)を買うわけですから、うまく行かなかったらやるせない気持ちになるし、もったいない気持ちになりますよね)

 …で、Arduinoでのポケモン自動化を始めようと思った初心者の方々(私も含めて)は、まず、マイコンポケモン剣盾を自動化している、様々な紹介動画や導入記事を見て回ると思います。

そして、「どれも難しそう…」「結局どのマイコン買えばいいの…」「人によって持ってる機械(マイコン)が違う…」など、複雑な印象を受けたはずです。

また、少しプログラムやPC系を噛じった人なら「人によって呼び出している関数が違う…」「人によってArduino UNOがいいとか悪いとか言ってる…」というまばらな印象を持ったはずです。余計に混乱したかもしれません。

 それもそのはず。「マイコンポケモン剣盾を自動化する」という言葉がすごく曖昧なのです。テクニカルな話をしてもしょうがないので、ここではマイコンの種類やArduinoの種類については全く語りませんが、その種類はArduinoだけでも20種類を有に超えます

中には互換機と言って、オリジナルと同等の機能を備えた廉価版のボードもあります。互換機自体は素晴らしいものなのですが、最初のマイコン選びの観点からすると、目的が、ボード(Arduino)を選ぶことから、金額を抑えることに途中ですり替わってしまい何を買えばよいのかわからなくなってしまいます。また、互換機の中には、ボード上の印刷がない場合や、特殊な互換チップが搭載されている場合、ピンが少ない場合など、様々な差異もあるため、比較的上級者向けの商品といえます。

 

なぜArduino UNOかArduino Leonardoなのか

さて、結論を急ぎ、語弊を恐れずに言えば、ポケモン剣盾の自動化という目的に沿った最初のマイコン選び」なら、選択肢はたったの2つです

理由は明白で、日本においてSwitchの自動化についてまとめたブログ記事、日本において配布されているSwitchコントロール用のライブラリ・資料の多くは、ArduinoUNO・Leonardoのいずれかを利用しているからです(互換機を含む)。

ただし、これはあくまでもハードウェアの話です。その実装方法(プログラムの部分)は、これらの間で大きく異なりますし、さらに人によってまばらです。

 

Arduino UNOが持たないHID機能をLeonardoは持つ

ここで一つ余談をはさみます。Arduino UNOとLeonardoの機能的な違いです。
直接は関係ないので、読み飛ばしてもOKです→読み飛ばす

Arduino UNOかArduino Leonardoを使えばポケモン剣盾の自動化ができることは前述の通りですが、その実装方法は大きく異なります。

  • Arduino UNO:最もベーシックなArduino。Joy Conとして認識させる機能(HID機能)が標準で備わっていないためファームウェアも書き換えてJoy Conに擬態させる方法
  • Arduino Leonardo:UNOと違い、HID機能を持つため、ArduinoIDEを使って普通にプログラミング・書き込みを行う方法。ボード情報だけ書き換えることでSwitchの系列コントローラーに擬態させる方法

小難しく書きましたが、要するに、UNOとLeonardoではJoy Conになれるかどうかがそもそも違うのです(UNOはもともとなれない)。LeonardoはUSBのHID(ヒューマン・インターフェース・デバイス)クラスを予め持つため、有線コントローラとして認識する素地があるわけですね。

なので、素人の私からすれば、素直にArduino Leonardo使ったほうが確実なのでは?と思うわけですが、世の中は広いわけで、無いなら「ファームウェアを書き換えればいいじゃない!」となるわけです。マイコンを初めて購入する人には不思議な気がするかもしれませんが、やはり利用者の絶対数が多いArduino UNOならではの発想だと思います。

 

Arduino UNO・Leonardoそれぞれの剣盾自動化

まず、本ブログの導入記事でも扱っている通り、筆者としてはArduino Leonardo」+「SwitchControlLibrary」の組み合わせをおすすめしています。

ただし、先駆者のWebサイトは、駆け出しの当ブログと違い、内容も濃く、しっかりと記載されているため、これらを読んでから納得して選ぶのが妥当かと思います。

便宜上、Arduino UNO・Arduino Leonardoで大きく2つに分けて下記に記載します。
それぞれ、偉大な先駆者様のWebサイトへのリンクを載せますので、是非とも参考にしてください。

◆方法1:Arduino UNOを使う場合

Arduino UNOでは、原則としてWindowsPowershellや、Macのターミナルを使ってファームウェアを書き換えてJoy Conとして認識させます。

Arduinoの回路をショートさせたり、ターミナル(ハッカーとかがよくコマンドをカタカタ入れているアレ)を使う必要があるため、特にCUI初心者にはややハードルが高いのでは?と思います。逆に、少しでもターミナルを触れる人なら簡単に感じられると思います。また、海外を含め、プログラムの投稿数も多いらしいです。また、もとよりArduinoを触ったことがある方はArduinoといえばUNOという人も少なくなく、利用人口が多いというのも特徴です。

 

Arduino UNOの参考Webサイト】

sinonis826.hatenablog.com
blogenist.jp

 

rhapsx.blog.fc2.com

 

◆方法2:Arduino Leonardoを使う場合

前述の通り、Arduino LeonardoはHIDの機能を持っています。これがArduino Leonardoを使う最大の理由と言っても過言じゃないです。要するに、Arduino UNOと比較すると、プログラミングやマイコンに対する知識は少なくて済みます。
ただし、ライブラリが複数有志によって提供されており、これが初心者を混乱させる原因の一つでもあります。

1.ライブラリ「SwitchControlLibrary」を使った方法【本ブログおすすめ】

本ブログで紹介しているライブラリを使った方法です。私が個人的にArduinoの自動化を始めた今年の2月時点で勢いがあると思ったのでこれを採用しました。

ライセンスもMITライセンスとして提供されており、使える関数もそれほど難しく無いので、C言語が分かる人なら無理なくプログラミング・開発も始められます。

(ライブラリ:https://github.com/celclow/SwitchControlLibrary

【参考Webサイト】

qiita.com

 

sinonis826.hatenablog.com

 

2.ライブラリ「NintendoSwitchControll」を使った方法

もう一つ、Switchをコントロールできるライブラリの紹介です。

こちらは、interimadd氏、takeutchi氏、kurimoun氏の3名が合同で提供しているライブラリです。サンプルのソースや配布サイトも充実しており、こちらもおすすめです。

(ライブラリ:https://github.com/interimadd/NintendoSwitchControll

 

【参考Webサイト】

pokemonit.com

 

まとめ

むりやりですが、上述の内容をまとめたのが下図になります。

Arduino UNO・Leonardoで比較すると一長一短の関係になることがわかります。

f:id:tangential_star:20201108205357p:plain

Arduinoポケモン剣盾を自動化」の選択肢。

筆者としては、Arduino UNOには手続きが煩雑になる部分があるため、ポケモン剣盾の自動化だけを目的にするのであればArduino Leonardoを使うのが妥当だと考えます。

ただし、Arduinoを使ったプログラミングを楽しみたい、組み込み系の醍醐味を味わいたい、という方や、今までのバックボーンによっては、やはりコミュニティが活性になるArduino UNOを使うのも選択肢になるのかな、といったところでした。

 

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

 

(宣伝)Arduino Leonardo+SwitchControlLibraryの導入記事:

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

 


【2020/11/11追記】続きを書きました。
Arduino Leonardoで使える自動化ソースコードのリンク集としても使えます。

【Arduino自動化 番外編2】NintendoSwitchControllライブラリの導入と、自動化できる作業の一覧【ポケモン剣盾自動化】

【2021/2/6追記】本ブログでおすすめしているArduino Leonardoとその他機器類について纏めました。筆者が使っている周辺機器の購入リンクも載せています。

【Arduino自動化 番外編3】筆者の使用機材一覧【紹介記事】

 

【Arduino自動化03】ワット稼ぎ・自動回収

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

3つ目の記事では、n番煎じ感は否めませんが、日付バグによるワット自動回収Arduino Leonardoで自動化していきます。DLC含め大量のワットを消費する機会が増えたので、重宝すると思います。

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

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

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

 

概要

本記事では、日付バグの併用による巣穴の2,000Wの無限回収を実装します。
2020/12/5追記:NintendoSwitch Ver.11.0アップデート対応済です。
2021/9/20追記:NintendoSwitch Ver.13.0アップデート対応済です。
2022/10/23追記:NintendoSwitch Ver.15.0アップデート対応済です。

f:id:tangential_star:20201108131008g:plain

Arduino Leonardoを挿すだけで無限にワット回収ができる。

 

今回の目次です。かなりシンプルです。

 

作ったきっかけ

DLC第1弾「鎧の孤島」でのミツバへのワット貢ぎイベントや、前の記事でも取り上げた、DLC第2弾「冠の雪原」のワットショップの高額目玉商品など、シナリオに直結しない部分で使うワット数が増えたため、気軽に使えるワット回収スクリプトが欲しいと思ったので作りました。

また、先駆者の作成ソースコードは、プログラミング負荷軽減のため、仕様が制限されていて「1月1日に日付変更してから使うこと」「31日ある月で使うこと」「年を更新するタイプ」など、私の「気軽に使いたい」ニーズに応えるものではなかったので作りました。

 ※気軽に使いたい=巣穴に「ねがいのかたまり」入れてArduino挿すだけ!

 

使い方

至ってシンプルで、巣穴に「ねがいのかたまり」を投げ入れ、柱を立てたらそのままAを押して「みんなで挑戦」を押す手前の状態でArduino LeonardoをSwitchに挿すだけで使えます。

なお、挿して3~5秒ほど、何度かHomeボタンが押されるような挙動は仕様です。

挿してから数秒後、5秒ほどなんの操作もしていない時間がありますが、このタイミングでHome画面(Switchでゲームを選ぶ画面)になっていればOKです。もし、なっていなければ手動で1度Homeボタンを押しておいてください。

事前準備

正しく動作するための条件は下記の通りです。

  •  ポケモン剣盾側の設定
    • 巣穴に手動で柱を立てておく(近くに草むらなどが無い場所が良い)
  • NintendoSwitch側の設定
    • Switch設定「時刻と時刻」の「インターネットで時間をあわせる」をOFF
    • インターネットには接続しない

 

書いたプログラム

処理フロー

  1. みんなで挑戦を押す
  2. Homeボタンを押して「設定」へ
  3. 日付を1日進める
  4. Homeでゲームに復帰し、募集終了
  5. ワットを回収し、1へ戻る(ループ)

ソースコード

2020/12/5追記:NintendoSwitch Ver.11.0アップデート対応済(変更点はこちら

2021/9/20追記:NintendoSwitch Ver.13.0アップデート対応済(詳細はこちら

2022/10/23追記:NintendoSwitch Ver.15.0アップデート対応済
※Switch Liteをご利用の方は「#define SWITCH_VER (13)」を「#define SWITCH_VER (12)」に書き換えてご利用ください。

/* ★NintendoSwitchのファームウェアVer11に対応版(2020/12/1)★
 * ★NintendoSwitchのファームウェアVer13に対応版(2021/9/20)★
 * ★NintendoSwitchのファームウェアVer15に対応版(2022/10/23)★
 * ★自動ワット稼ぎ★
巣穴に「ねがいのかたまり」を投げ入れてA。
「みんなで挑戦」の手前でArduinoをSwitchに挿すだけ。
*/

#include <SwitchControlLibrary.h>

#define HOLDTIME (95)
#define INTERVAL (105)

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

void PushHome(int delay_time_ms);
void PushA(int delay_time_ms);
void PushB(int delay_time_ms);
void move_for(char* Direction); // ex: "right" "left" "up" "down"
void move_for(char* Direction, int delay_time_ms);
void move_for(char* Direction, int hold_time_ms, int delay_time_ms);

void setup() {
  
  PushHome(1000);
  PushHome(1000);
  PushHome(1000);
  PushHome(1000);
  PushHome(1000);
  PushHome(5000); // 5秒待つ
  PushHome(1000);

  delay(100);
}

void loop() {

  // 開始 みんなで挑戦の直前から。
  PushA(4000); // 通信待機中・・・
  
  // Homeボタンを押して設定の画面へ移動
  PushHome(1000);

  // Home画面で「設定」を選ぶ
  move_for("down");
  move_for("right");
  move_for("right");
  move_for("right");
  move_for("right");
  move_for("right");
  PushA(1500);

  // 設定画面で「日付と時刻」を開く
  move_for("down", 1500, (int)INTERVAL/4); // 「↓」長押し
  move_for("right");

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

  // 時間設定(現在の日付と時刻を選ぶ)
  move_for("down");
  move_for("down");
  PushA(500);

  // 時刻設定(日付の部分のみ回していく
  // 時間の変更
  move_for("right");
  move_for("right");
  move_for("up");
  PushA(INTERVAL);
  PushA(INTERVAL);
  PushA(INTERVAL);
  PushA(INTERVAL);
  PushHome(2000);
  PushA(1000);
  // ↑ここまでで設定画面おわり。

  // 募集終了処理
  PushB(500);  // 「募集終了」を選択
  PushA(1000); // 「はい」
  PushA(4500); // 「はい」

  // ★フィールド画面に戻ってくる(watt回収)
  // There's energy pouring out from the den! [Enter]
  PushA(500);  // 1回目は「A」
  // You gained 2,000W! [Quit]
  PushB(2500);  // 2回目は「B」(日付が1日に戻った時との共通処理のため遅めに)
  // [Enter]
  PushA(1500);  // 3回目は「A」(募集画面に入る)

}

void PushHome(int delay_time_ms){
  SwitchControlLibrary().PressButtonHome();
  delay(210);
  SwitchControlLibrary().ReleaseButtonHome();
  delay(delay_time_ms);
  return;
}

void PushA(int delay_time_ms){
  SwitchControlLibrary().PressButtonA();
  delay(HOLDTIME);
  SwitchControlLibrary().ReleaseButtonA();
  delay(delay_time_ms);
  return;
}
void PushB(int delay_time_ms){
  SwitchControlLibrary().PressButtonB();
  delay(HOLDTIME);
  SwitchControlLibrary().ReleaseButtonB();
  delay(delay_time_ms);
  return;
}

void move_for(char* Direction){
  // ex: "right" "left" "up" "down"
  
  switch(Direction[0]){
    case 'r':
    case 'R':
    SwitchControlLibrary().MoveHat(2); // right
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(INTERVAL);
    break;

    case 'l':
    case 'L':
    SwitchControlLibrary().MoveHat(6); // left
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(INTERVAL);
    break;

    case 'u':
    case 'U':
    SwitchControlLibrary().MoveHat(0); // up
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(INTERVAL);
    break;

    case 'd':  
    case 'D':
    SwitchControlLibrary().MoveHat(4); // down
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(INTERVAL);
    break;

    default:
    break;  
  }
  
}

void move_for(char* Direction, int delay_time){
  // ex: "right" "left" "up" "down"
  
  switch(Direction[0]){
    case 'r':
    case 'R':
    SwitchControlLibrary().MoveHat(2); // right
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time);
    break;

    case 'l':
    case 'L':
    SwitchControlLibrary().MoveHat(6); // left
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time);
    break;

    case 'u':
    case 'U':
    SwitchControlLibrary().MoveHat(0); // up
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time);
    break;

    case 'd':  
    case 'D':
    SwitchControlLibrary().MoveHat(4); // down
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time);
    break;

    default:
    break;  
  }
  
}

void move_for(char* Direction, int hold_time_ms, int delay_time_ms){
  // ex: "right" "left" "up" "down"
  
  switch(Direction[0]){
    case 'r':
    case 'R':
    SwitchControlLibrary().MoveHat(2); // right
    delay(hold_time_ms);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time_ms);
    break;

    case 'l':
    case 'L':
    SwitchControlLibrary().MoveHat(6); // left
    delay(hold_time_ms);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time_ms);
    break;

    case 'u':
    case 'U':
    SwitchControlLibrary().MoveHat(0); // up
    delay(hold_time_ms);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time_ms);
    break;

    case 'd':  
    case 'D':
    SwitchControlLibrary().MoveHat(4); // down
    delay(hold_time_ms);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time_ms);
    break;

    default:
    break;  
  }

}

 

f:id:tangential_star:20201108131008g:plain

動作例(再掲)


あとがき

今回は自動でワット回収ができるプログラムを紹介しました。

実は、このプログラムのみは、日本語版・英語版・中国語版(繁体字)で動作を確認済です。ソースコードのコメント行でゲーム中のセリフを英語で書いているのは、英語版の文字送り速度に合わせてDelay()の数値を調整したからなのです。
余談ですが、文字送り速度はゲーム中の設定から「早い 普通 遅い」と選べますが、同じ「早い」でも英語の「Fast」とは文字の送られる時間が違います(日本語や中国語のほうが短いです)。

理由は明白で、我々漢字圏の人は2バイト文字なので単純計算で英語版の文字送りの2倍速になるんですね(流石に2倍はないかもですが)。

日本語版でしかデバッグしていないArduinoでの自動化プログラムを英語版で使うと「あれ、なんで動作がズレるんだ?」となりますが、意外な落とし穴が文字送り速度に隠れているんですね(体験談)。

ちなみに、本ブログでは原則として日本語版でのみ動作確認したものしか載せません。ただ、もしかしたら、プログラム中の定数「INTERVAL」や「HOLDTIME」を増やすとうまく動くかもしれません。

 

余談が長くなってしまいました。

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

 

前の記事:

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

次の記事:

【Arduino自動化04】パッチルドン自動受け取り(中国語・英語対応)

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

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

2つ目の記事は、剣盾DLC第2段カンムリ雪原で新たに増えたワットショップ、雪中渓谷の「目玉商品」交換に主眼をおいたArduino Leonardo自動化の記事です。

ソースコードの紹介と、使い方を載せていきます。

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

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

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

 

概要

本記事では、日付バグの併用による目玉商品の無限回収を実装します。
2020/12/5追記:NintendoSwitch Ver.11.0アップデート対応済です。
2021/9/20追記:NintendoSwitch Ver.13.0アップデート対応済です。
2022/10/23追記:NintendoSwitch Ver.15.0アップデート対応済です。

f:id:tangential_star:20201108025830j:plain
f:id:tangential_star:20201108025408g:plain
雪中渓谷のワットショップで「目玉商品」を自動購入し、日付更新

今回のもくじです。

 

作ったきっかけ

色々なWebサイトを見て調べた限りでは、DLC対応のArduino自動化プログラムで、この「目玉商品の自動回収」は見当たらなかったので作りました。ぼんぐりの回収とレアアイテムの回収が同時にできてハッピーです。

ちなみに、私はまだ見たことありませんが、ここのワットショップでは「ドリームボール」もラインナップにあるそうです。ほしい…

f:id:tangential_star:20201108040932j:plain
f:id:tangential_star:20201108041013p:plain
無限回収していると、まれに「ぼんぐり10個セット」や「サンのみ」、
「キョダイパウダー」など魅力的なラインナップに巡り会える。

 

使い方

ソースコードは本ページ最下部(コチラ)にございます。「使い方はいいから早くソースコードを寄越せ!」という方は本項を読み飛ばしてください。

一応、日付更新・ワット回収部分・話しかけ部分に工夫しており、任意の日付から始めてもうまく稼働すると思います(つまり予め1/1に戻したり31日まである月に変更したりしなくてOK)。

事前準備

正しく動作するための条件は下記の通りです。

  • ポケモン剣盾側の設定
    • しっかりと充分なワットをあらかじめ貯めておく
    • 一度はワットショップのおじさんに話しかけておく
      (初回の専用ルート云々のくだりを回収しておく)
    • ワットショップおじさんの隣にある巣穴に手動で柱を立てておく
    • 自転車からは降りておく
    • Xでメニューを開いた際のカーソルを「タウンマップ」にあわせておく
  • NintendoSwitch側の設定
    • Switch設定「時刻と時刻」の「インターネットで時間をあわせる」をOFF
    • インターネットには接続しない

ポケモン剣盾での操作

基本的に難しい操作はないのですが、雪中渓谷に「空飛ぶタクシー」で移動し、ワットショップの隣(奥)にある巣穴に「ねがいのかたまり」を投げ入れてください。

あとは、「自転車に乗っていないこと」「Xボタンでメニューを開いたときに『タウンマップ』がカーソルされていること」さえクリアしていれば多分動きます。

f:id:tangential_star:20201108103542j:plain
f:id:tangential_star:20201108025830j:plain
Xボタンでメニューを開いた際に、「タウンマップ」にカーソルがあっていればOK
f:id:tangential_star:20201108103408j:plain
f:id:tangential_star:20201108103538j:plain
自転車から降りて、ワットショップの隣の巣穴に「ねがいのかたまり」を投げ入れる
f:id:tangential_star:20201108103927p:plain
f:id:tangential_star:20201108103824p:plain
ワットを回収し、「みんなで挑戦」にカーソルをあてたら準備OK

レイドバトルの「みんなで 挑戦!」を押す前の状態で、スケッチを書き込んだArduino LeonardoをSwitchに差し込むと、自動化が始まります。

挿して3~5秒ほど、何度かHomeボタンが押されるような挙動をするかもしれませんが、これは仕様です(SwitchがArduinoをコントローラーとして認識するまでにかかる時間を調整しています)。

挿してから数秒後、5秒ほどなんの操作もしていない時間がありますが、このタイミングでHome画面(Switchでゲームを選ぶ画面)になっていればOKです。もし、なっていなければ手動で1度Homeボタンを押しておいてください。

書いたプログラム

処理フロー

setup()関数内の PushHome()連打は、挿してから認識されるまでの時間合わせです。

処理フローとしては、下記になります。

  1. 「みんなで挑戦」を押して、日付を進める
  2. 雪中渓谷に空を飛ぶ
  3. ワットショップに向かい、目玉商品を購入
  4. 雪中渓谷に空を飛ぶ
  5. 巣穴に向かい、ワット回収。
  6. 1に戻る(ループ)

空を飛ぶのは、天候や出現ポケモンによる負荷の違い?によって移動する向きが微妙にずれたり、オフセット誤差が溜まったりするのでこれらを是正するために入れています。効率ではなく安定性重視です。筆者環境では、このソースコードで3日間放置できました。

ワット回収ならびにワットショップ購入部分に工夫してあり、日付更新は、任意の月・日付から始められます。「1月1日から始めないと動かない」「31日ある月じゃないと動かない」みたいな煩雑な前準備は不要なはずです。

ソースコード

2020/12/5追記:NintendoSwitch Ver.11.0アップデート対応済(変更点はこちら

2021/9/20追記:NintendoSwitch Ver.13.0アップデート対応済(詳細はこちら

2022/10/23追記:NintendoSwitch Ver.15.0アップデート対応済
※Switch Liteをご利用の方は「#define SWITCH_VER (13)」を「#define SWITCH_VER (12)」に書き換えてご利用ください。

/* ★NintendoSwitchのファームウェアVer11に対応版(2020/12/1)★
 * ★NintendoSwitchのファームウェアVer13に対応版(2021/9/20)★
 * ★NintendoSwitchのファームウェアVer15に対応版(2022/10/23)★
 * 
★カンムリの雪原 目玉商品自動回収
※十分にWattをためておくこと!

参考URL: https://qiita.com/sobassy/items/cb707e50f2f27a851886
インストールしたライブラリ:https://github.com/celclow/SwitchControlLibrary
インストールしたライブラリ2:https://okwave.jp/qa/q9702388.html
変更したBoard.txtの内容:https://qiita.com/Eitok/items/ab29e0e6404dfc709823
  ●変更1
    #leonardo.vid.1=0x2341
    #leonardo.pid.1=0x8036
    leonardo.vid.1=0x0f0d
    leonardo.pid.1=0x0092
  ●変更2
    #leonardo.build.vid=0x2341
    #leonardo.build.pid=0x8036
    leonardo.build.vid=0x0f0d
    leonardo.build.pid=0x0092

★使い方
 - - - -
Step1: Nintendo Switchの設定(日付)の「インターネットで自動設定」をOFFに。【重要】
-Step2: おっさんの右上のDennにねがいのかたまりを投げて、手動で作った柱を準備【重要】
-Step2: Xでメニューを開いたときにタウンマップにカーソルがあっていること【重要】
-Step2: じてんしゃは降りておくこと【重要】
Step3: オンライン通信を切断しておく
Step4: 柱のWattを回収し、「みんなで挑戦」にカーソルをあわせて待機。
 - - - - -
Step5: ArduinoをSwitchに接続。
Step6: 何回かHomeボタン繰り返し押されるような挙動をする。
Step7: 3秒くらいHomeがおされていないな?というふうになったときにHome画面ならOK
 ※違うなら急いで手動でHomeボタンを押す!
Step8: Homeが1回押されて自動処理開始

*/

#include <SwitchControlLibrary.h>

#define HOLDTIME (95)
#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 PushHome(int delay_time_ms);
void PushA(int delay_time_ms);
void PushB(int delay_time_ms);
void PushX(int delay_time_ms);
void PushL(int delay_time_ms);
void move_for(char* Direction); // ex: "right" "left" "up" "down"
void move_for(char* Direction, int delay_time_ms);
void move_for(char* Direction, int hold_time_ms, int delay_time_ms);

void setup() {

  PushHome(1000);
  PushHome(1000);
  PushHome(1000);
  PushHome(1000);
  PushHome(1000);
  PushHome(3000); // 3秒待つ
  PushHome(1000);

  delay(100);
}

void loop() {

  // 開始 みんなで挑戦の直前から。
  PushA(4000); // 通信待機中・・・
  
  // Homeボタンを押して設定の画面へ移動
  PushHome(1000);

  // Home画面で「設定」を選ぶ
  move_for("down");
  move_for("right");
  move_for("right");
  move_for("right");
  move_for("right");
  move_for("right");
  PushA(1500);

  // 設定画面で「日付と時刻」を開く
  move_for("down", 1500, (int)INTERVAL/4); // 「↓」長押し
  move_for("right");

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

  // 時間設定(現在の日付と時刻を選ぶ)
  move_for("down");
  move_for("down");
  PushA(500);

  // 時刻設定(日付の部分のみ回していく
  // 時間の変更
  move_for("right");
  move_for("right");
  move_for("up");
  PushA(INTERVAL);
  PushA(INTERVAL);
  PushA(INTERVAL);
  PushA(INTERVAL);
  PushHome(2000);
  PushA(1000);
  // ↑ここまでで設定画面おわり。

  // 募集終了処理
  PushB(500);  // 「募集終了」を選択
  PushA(1000); // 「はい」
  PushA(4500); // 「はい」


  // ★フィールド画面に戻ってきて空を飛んでおっさんに話しかける
  PushX(700);  // Xでメニューを開く
  PushA(2700); // Aでタウンマップを開く

  // PushX(150);
  SwitchControlLibrary().MoveLeftStick((128+70), (128+100)); // 右下(下強め)にカーソル合わせ
  delay(170);
  SwitchControlLibrary().MoveLeftStick((128), (128)); // 真ん中に戻す
  delay(100);

  // 空を飛ぶ(A)
  PushA(650);
  PushA(1700);// 天候によって画面切り替わりの時間がかわるっぽい。1700だと足りない場合あり?要検証
  // おっさんに向かって走る
  SwitchControlLibrary().MoveLeftStick((128+100), (128-115)); // 右上(ちょい上強め)を向く
  delay(230);
  SwitchControlLibrary().MoveLeftStick((128), (128)); // 真ん中に戻す
  delay(100);
  PushL(400);
  SwitchControlLibrary().MoveLeftStick((128), (128-128)); // 上にあるく
  delay(1800);
  SwitchControlLibrary().MoveLeftStick((128), (128)); // 真ん中に戻す
  
  PushA(650); // いらっしゃいませ
  PushA(650); // 何をご覧になりますか?
  move_for("d");
  PushA(650); // 今日の目玉商品は… or 目玉商品は売り切れです
  PushA(650); // ●●! 早いもの勝ち お値段 たったの ●●W  or 他に見たいものはありますか?
  PushA(650); // 買う?   or 普通の商品
  PushA(2600); // はい(購入処理入るので遅い)→お目が高い!お買い上げありがとうございます
  PushB(2600); // ●●は ●● を 手に入れた!(SEなる) ★ここ以降はBにして共通処理
  PushB(750);
  PushB(550);
  PushB(550);
  PushB(550);
  PushB(550);
  PushB(550); // 余計なB(1日にループした際の共通処理&2個セットのときなど2行に分かれたときの共通処理&きのみ購入時の1行ズレ吸収)

 
  // ★フィールド画面に戻ってきて空を飛んでDennに歩く
  PushX(700);  // Xでメニューを開く
  PushA(2700); // Aでタウンマップを開く
  // PushX(150);
  SwitchControlLibrary().MoveLeftStick((128+70), (128+100)); // 右下(下強め)にカーソル合わせ
  delay(170);
  SwitchControlLibrary().MoveLeftStick((128), (128)); // 真ん中に戻す
  delay(100);

  // 空を飛ぶ(A)
  PushA(650);
  PushA(1700);
  
  // Dennに向かって走る
  SwitchControlLibrary().MoveLeftStick((128+28), (128-115)); // 右上(上強め)を向く
  delay(230);
  SwitchControlLibrary().MoveLeftStick((128), (128)); // 真ん中に戻す
  delay(100);
  PushL(400);
  SwitchControlLibrary().MoveLeftStick((128), (128-128)); // 上にあるく
  delay(4300);
  SwitchControlLibrary().MoveLeftStick((128), (128)); // 真ん中に戻す

  // ★Denに話しかける(Watt回収)
  // There's energy pouring out from the den! [Enter]
  PushA(500);  // 1回目は「A」
  // You gained 2,000W! [Quit]
  PushB(2500);  // 2回目は「B」(日付が1日に戻った時との共通処理のため遅めに)
  // [Enter]
  PushA(1500);  // 3回目は「A」(募集画面に入る)

}

void PushHome(int delay_time_ms){
  SwitchControlLibrary().PressButtonHome();
  delay(210);
  SwitchControlLibrary().ReleaseButtonHome();
  delay(delay_time_ms);
  return;
}

void PushA(int delay_time_ms){
  SwitchControlLibrary().PressButtonA();
  delay(HOLDTIME);
  SwitchControlLibrary().ReleaseButtonA();
  delay(delay_time_ms);
  return;
}
void PushB(int delay_time_ms){
  SwitchControlLibrary().PressButtonB();
  delay(HOLDTIME);
  SwitchControlLibrary().ReleaseButtonB();
  delay(delay_time_ms);
  return;
}
void PushX(int delay_time_ms){
  SwitchControlLibrary().PressButtonX();
  delay(HOLDTIME);
  SwitchControlLibrary().ReleaseButtonX();
  delay(delay_time_ms);
  return;
}
void PushL(int delay_time_ms){
  SwitchControlLibrary().PressButtonL();
  delay(HOLDTIME);
  SwitchControlLibrary().ReleaseButtonL();
  delay(delay_time_ms);
  return;
}
void move_for(char* Direction){
  // ex: "right" "left" "up" "down"
  
  switch(Direction[0]){
    case 'r':
    case 'R':
    SwitchControlLibrary().MoveHat(2); // right
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(INTERVAL);
    break;

    case 'l':
    case 'L':
    SwitchControlLibrary().MoveHat(6); // left
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(INTERVAL);
    break;

    case 'u':
    case 'U':
    SwitchControlLibrary().MoveHat(0); // up
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(INTERVAL);
    break;

    case 'd':  
    case 'D':
    SwitchControlLibrary().MoveHat(4); // down
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(INTERVAL);
    break;

    default:
    break;  
  }
  
}

void move_for(char* Direction, int delay_time){
  // ex: "right" "left" "up" "down"
  
  switch(Direction[0]){
    case 'r':
    case 'R':
    SwitchControlLibrary().MoveHat(2); // right
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time);
    break;

    case 'l':
    case 'L':
    SwitchControlLibrary().MoveHat(6); // left
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time);
    break;

    case 'u':
    case 'U':
    SwitchControlLibrary().MoveHat(0); // up
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time);
    break;

    case 'd':  
    case 'D':
    SwitchControlLibrary().MoveHat(4); // down
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time);
    break;

    default:
    break;  
  }
  
}

void move_for(char* Direction, int hold_time_ms, int delay_time_ms){
  // ex: "right" "left" "up" "down"
  
  switch(Direction[0]){
    case 'r':
    case 'R':
    SwitchControlLibrary().MoveHat(2); // right
    delay(hold_time_ms);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time_ms);
    break;

    case 'l':
    case 'L':
    SwitchControlLibrary().MoveHat(6); // left
    delay(hold_time_ms);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time_ms);
    break;

    case 'u':
    case 'U':
    SwitchControlLibrary().MoveHat(0); // up
    delay(hold_time_ms);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time_ms);
    break;

    case 'd':  
    case 'D':
    SwitchControlLibrary().MoveHat(4); // down
    delay(hold_time_ms);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time_ms);
    break;

    default:
    break;  
  }

}

 

/* ★NintendoSwitchのファームウェアVer11に対応版(2020/12/1)★
 * ★NintendoSwitchのファームウェアVer13に対応版(2021/9/20)★
 * ★カンムリの雪原 目玉商品自動回収★

※十分にWattをためておくこと!
★使い方 - - - - Step1: Nintendo Switchの設定(日付)の「インターネットで自動設定」をOFFに。【重要】 -Step2: おっさんの右上のDennにねがいのかたまりを投げて、手動で作った柱を準備【重要】 -Step2: Xでメニューを開いたときにタウンマップにカーソルがあっていること【重要】 -Step2: じてんしゃは降りておくこと【重要】 Step3: オンライン通信を切断しておく Step4: 柱のWattを回収し、「みんなで挑戦」にカーソルをあわせて待機。 - - - - - Step5: ArduinoをSwitchに接続。 Step6: 何回かHomeボタン繰り返し押されるような挙動をする。 Step7: 3秒くらいHomeがおされていないな?というふうになったときにHome画面ならOK  ※違うなら急いで手動でHomeボタンを押す! Step8: Homeが1回押されて自動処理開始 */ #include <SwitchControlLibrary.h> #define HOLDTIME (95) #define INTERVAL (105) #define SWITCH_VER (13)
// 2021/9/20、SwitchのVer13アップデートに伴う追記
// Switchのバージョンを整数で入力(例:12.2.1⇒12,13.0.0⇒13)
void PushHome(int delay_time_ms); void PushA(int delay_time_ms); void PushB(int delay_time_ms); void PushX(int delay_time_ms); void PushL(int delay_time_ms); void move_for(char* Direction); // ex: "right" "left" "up" "down" void move_for(char* Direction, int delay_time_ms); void move_for(char* Direction, int hold_time_ms, int delay_time_ms); void setup() { PushHome(1000); PushHome(1000); PushHome(1000); PushHome(1000); PushHome(1000); PushHome(3000); // 3秒待つ PushHome(1000); delay(100); } void loop() { // 開始 みんなで挑戦の直前から。 PushA(4000); // 通信待機中・・・ // Homeボタンを押して設定の画面へ移動 PushHome(1000); // Home画面で「設定」を選ぶ move_for("down"); move_for("right"); move_for("right"); move_for("right"); move_for("right"); move_for("right"); PushA(1500); // 設定画面で「日付と時刻」を開く move_for("down", 1500, (int)INTERVAL/4); // 「↓」長押し move_for("right"); #if (SWITCH_VER >= 13) // Switchのアプデで「ドックの更新」項目が追加されたので // 日付変更をする場合には「↓」キー長押しが必要に。 move_for("down", (int)780, (int)INTERVAL/2); #else // ver12まで(13アプデ前)は、1ページに収まるのでそのままでOK for(int i=0; i<4; i++){ move_for("down", (int)HOLDTIME/2, (int)INTERVAL/2); } #endif PushA(500); // 時間設定(現在の日付と時刻を選ぶ) move_for("down"); move_for("down"); PushA(500); // 時刻設定(日付の部分のみ回していく // 時間の変更 move_for("right"); move_for("right"); move_for("up"); PushA(INTERVAL); PushA(INTERVAL); PushA(INTERVAL); PushA(INTERVAL); PushHome(2000); PushA(1000); // ↑ここまでで設定画面おわり。 // 募集終了処理 PushB(500); // 「募集終了」を選択 PushA(1000); // 「はい」 PushA(4500); // 「はい」 // ★フィールド画面に戻ってきて空を飛んでおっさんに話しかける PushX(700); // Xでメニューを開く PushA(2700); // Aでタウンマップを開く // PushX(150); SwitchControlLibrary().MoveLeftStick((128+70), (128+100)); // 右下(下強め)にカーソル合わせ delay(170); SwitchControlLibrary().MoveLeftStick((128), (128)); // 真ん中に戻す delay(100); // 空を飛ぶ(A) PushA(650); PushA(1700);// 天候によって画面切り替わりの時間がかわるっぽい。1700だと足りない場合あり?要検証 // おっさんに向かって走る SwitchControlLibrary().MoveLeftStick((128+100), (128-115)); // 右上(ちょい上強め)を向く delay(230); SwitchControlLibrary().MoveLeftStick((128), (128)); // 真ん中に戻す delay(100); PushL(400); SwitchControlLibrary().MoveLeftStick((128), (128-128)); // 上にあるく delay(1800); SwitchControlLibrary().MoveLeftStick((128), (128)); // 真ん中に戻す PushA(650); // いらっしゃいませ PushA(650); // 何をご覧になりますか? move_for("d"); PushA(650); // 今日の目玉商品は… or 目玉商品は売り切れです PushA(650); // ●●! 早いもの勝ち お値段 たったの ●●W  or 他に見たいものはありますか? PushA(650); // 買う?  or 普通の商品 PushA(2600); // はい(購入処理入るので遅い)→お目が高い!お買い上げありがとうございます PushB(2600); // ●●は ●● を 手に入れた!(SEなる) ★ここ以降はBにして共通処理 PushB(750); PushB(550); PushB(550); PushB(550); PushB(550); PushB(550); // 余計なB(1日にループした際の共通処理&2個セットのときなど2行に分かれたときの共通処理&きのみ購入時の1行ズレ吸収) // ★フィールド画面に戻ってきて空を飛んでDennに歩く PushX(700); // Xでメニューを開く PushA(2700); // Aでタウンマップを開く // PushX(150); SwitchControlLibrary().MoveLeftStick((128+70), (128+100)); // 右下(下強め)にカーソル合わせ delay(170); SwitchControlLibrary().MoveLeftStick((128), (128)); // 真ん中に戻す delay(100); // 空を飛ぶ(A) PushA(650); PushA(1700); // Dennに向かって走る SwitchControlLibrary().MoveLeftStick((128+28), (128-115)); // 右上(上強め)を向く delay(230); SwitchControlLibrary().MoveLeftStick((128), (128)); // 真ん中に戻す delay(100); PushL(400); SwitchControlLibrary().MoveLeftStick((128), (128-128)); // 上にあるく delay(4300); SwitchControlLibrary().MoveLeftStick((128), (128)); // 真ん中に戻す // ★Denに話しかける(Watt回収) // There's energy pouring out from the den! [Enter] PushA(500); // 1回目は「A」 // You gained 2,000W! [Quit] PushB(2500); // 2回目は「B」(日付が1日に戻った時との共通処理のため遅めに) // [Enter] PushA(1500); // 3回目は「A」(募集画面に入る) } void PushHome(int delay_time_ms){ SwitchControlLibrary().PressButtonHome(); delay(210); SwitchControlLibrary().ReleaseButtonHome(); delay(delay_time_ms); return; } void PushA(int delay_time_ms){ SwitchControlLibrary().PressButtonA(); delay(HOLDTIME); SwitchControlLibrary().ReleaseButtonA(); delay(delay_time_ms); return; } void PushB(int delay_time_ms){ SwitchControlLibrary().PressButtonB(); delay(HOLDTIME); SwitchControlLibrary().ReleaseButtonB(); delay(delay_time_ms); return; } void PushX(int delay_time_ms){ SwitchControlLibrary().PressButtonX(); delay(HOLDTIME); SwitchControlLibrary().ReleaseButtonX(); delay(delay_time_ms); return; } void PushL(int delay_time_ms){ SwitchControlLibrary().PressButtonL(); delay(HOLDTIME); SwitchControlLibrary().ReleaseButtonL(); delay(delay_time_ms); return; } void move_for(char* Direction){ // ex: "right" "left" "up" "down" switch(Direction[0]){ case 'r': case 'R': SwitchControlLibrary().MoveHat(2); // right delay(HOLDTIME); SwitchControlLibrary().MoveHat(8); // center delay(INTERVAL); break; case 'l': case 'L': SwitchControlLibrary().MoveHat(6); // left delay(HOLDTIME); SwitchControlLibrary().MoveHat(8); // center delay(INTERVAL); break; case 'u': case 'U': SwitchControlLibrary().MoveHat(0); // up delay(HOLDTIME); SwitchControlLibrary().MoveHat(8); // center delay(INTERVAL); break; case 'd': case 'D': SwitchControlLibrary().MoveHat(4); // down delay(HOLDTIME); SwitchControlLibrary().MoveHat(8); // center delay(INTERVAL); break; default: break; } } void move_for(char* Direction, int delay_time){ // ex: "right" "left" "up" "down" switch(Direction[0]){ case 'r': case 'R': SwitchControlLibrary().MoveHat(2); // right delay(HOLDTIME); SwitchControlLibrary().MoveHat(8); // center delay(delay_time); break; case 'l': case 'L': SwitchControlLibrary().MoveHat(6); // left delay(HOLDTIME); SwitchControlLibrary().MoveHat(8); // center delay(delay_time); break; case 'u': case 'U': SwitchControlLibrary().MoveHat(0); // up delay(HOLDTIME); SwitchControlLibrary().MoveHat(8); // center delay(delay_time); break; case 'd': case 'D': SwitchControlLibrary().MoveHat(4); // down delay(HOLDTIME); SwitchControlLibrary().MoveHat(8); // center delay(delay_time); break; default: break; } } void move_for(char* Direction, int hold_time_ms, int delay_time_ms){ // ex: "right" "left" "up" "down" switch(Direction[0]){ case 'r': case 'R': SwitchControlLibrary().MoveHat(2); // right delay(hold_time_ms); SwitchControlLibrary().MoveHat(8); // center delay(delay_time_ms); break; case 'l': case 'L': SwitchControlLibrary().MoveHat(6); // left delay(hold_time_ms); SwitchControlLibrary().MoveHat(8); // center delay(delay_time_ms); break; case 'u': case 'U': SwitchControlLibrary().MoveHat(0); // up delay(hold_time_ms); SwitchControlLibrary().MoveHat(8); // center delay(delay_time_ms); break; case 'd': case 'D': SwitchControlLibrary().MoveHat(4); // down delay(hold_time_ms); SwitchControlLibrary().MoveHat(8); // center delay(delay_time_ms); break; default: break; } }

f:id:tangential_star:20201205131649g:plain

2020/12/5対応;動作例(NintendoSwitchVer11アプデ対応済)

 

あとがき

剣盾の自動化は、今年の2/2にArduino Leonardoを買って以来、色々と試してきましたが、こんなふうにDLCが出てから更に魅力的になったと思います。

入手方法や個数が実質的に限られていたアイテム・ポケモンがちゃんと後からでも手に入れられるようになることは、改造やセーブデータ改竄など非合法な方法を撲滅する上でも必要だと思います。一方で、きのみ集めやレイド周回、ウッウロボガチャなど、通常プレイでは苦行と言わざるを得ないパートが残っているのもまた事実で、やりこみ要素としてのバランスは難しいのでしょう。

ここは、ゲームに対するプレイスタイルに依るところが大きいので、それぞれがポリシーを持って向き合っていただければと思います。

なお、本記事を始めとするArduinoを使った自動化は、コントローラー操作の代替手段の一つです。いわば、連射コントローラーや、マクロ対応コントローラーと同じカテゴリのものです。すなわち、ポケモン剣盾の仕様の範囲内で完結でき、前述の非合法的な手段(改造やセーブデータ改竄など)を使わない、プレイスタイルの一つとして位置づけられると考えます。

本記事を読んでいただいた皆様にはそれぞれに考え方があるかと存じますが、それぞれのプレイスタイルに応じた使い方を演出いただければ幸いです。 

 

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

 

前の記事:

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

次の記事:

【Arduino自動化03】ワット稼ぎ・自動回収

 

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

本記事では、

  • 機材とソフトウェアの準備
  • ArduinoIDE(開発環境)の導入
  • サンプルプログラムを動かす(コンパイルと書き込み)
  • ArduinoNintendo Switchにつなぐ(動作確認)

を紹介します。

もくじは下記の通りです。

 

準備するもの(PC以外)

最低限、準備するものは「switch本体」「Arduino Leonardo」「ケーブル」の3つです。

ただ、自動化することを前提にする場合は、switchの給電をしながらArduinoをつなぎたい場面が多く、上記に加え「純正充電器(Switchについてるやつ)」「ホリのUSBハブスタンド(または純正のswitchドック)」があるとさらに捗ります。

給電しながらSwitchとArduinoをつなぐ場合
給電せずSwitchとArduinoをつなぐ場合
機材構成イメージ(左:おすすめ/右:最低限の構成)

ちなみに、ArduinoとSwitch本体をつなぐケーブルは、USBハブスタンドやドックを使う場合はUSB Aオス、直接つなぐ場合にはUSB Cオスでそれぞれケーブルの種類が変わるので注意しましょう。USBケーブルはデータ通信可能なものなら適当に変換アダプタを噛ませてもOKです。ただし、充電ACアダプターは任天堂純正のものを使いましょう。

なお、当然のことですが、PCを使ってArduinoにプログラムを書き込むので、PCとArduinoをつなぐUSBケーブルも必要に応じてご用意ください(PCのUSB端子をあらかじめ確認しておきましょう)。

Arduino Leonardo
NintendoSwitch用USBハブスタンド
NintendoSwitch純正ACアダプター
USB microB-USB A通信アダプタ
筆者が使っている機材

2021年1月5日追記:Arduino Leonardoのみ、商品リンク貼っておきます。

 

2021年2月4日追記:その他筆者使用機材は下記記事にまとめました。

【Arduino自動化 番外編3】筆者の使用機材一覧【紹介記事】

 

準備するもの(PCソフトウェア)

ハードウェアは買えば終わりですが、ソフトウェアはダウンロードとインストールの作業が必要になります。PCに慣れている人なら20-30分ほどで終わるかと思います。

大まかには

  1. ArduinoIDEのインストール
  2. AVR更新
  3. ライブラリ(STL・SwitchControlLibraryの2つ)のインストール
  4. Arduinoのボード情報更新

になります。 

筆者はWindows 10なので基本的にスクショも説明もこれに準じます。あしからず。

Arduino IDEのダウンロード

基本的に、PCはWindowsだろうがMacだろうがLinuxだろうが、Arduino公式がサポートしているものであればなんでもOKです。ちなみに筆者の使用PCはWindows 10です。

公式サイト(https://www.arduino.cc/en/software)から自身にあったバージョンのものをダウンロード・インストールしてください。

なお、Windows App版は色々と不具合があるようなのでおすすめしません。仕様を理解できる人以外は素直にインストーラー版のものをダウンロードしてください。

ダウンロードするのは、Legacy IDE (1.8.X)です*1

【重要】Arduino IDEのバージョンは「Legacy(1.8.X)」を選ぶこと

Arduino公式Webでのダウンロードリンクの場所

Windowsの人(10含む)は、インストーラー版がおすすめ

ちなみに、ダウンロードの画面に進むと、寄付(Donation)を募られます。支援したい方やArduinoに協賛・共感できる人は是非とも、金額を選択または入力して「Contribute & Download」を押しましょう。無論、持ち合わせがない人や今回の寄付を見送る人は「Just Download」でも問題ありません。

ダウンロードしたら、そのままインストールしてください。Windowsインストーラー版の人は「arduino-x.x.x-windows.exe(x.x.xはバージョン)」をダブルクリックすると勝手にインストールされるはずです。

 

Arduino AVR boards 1.8.2のインストール

Arduino IDEをインストールしたら、まずはAVR boardsをインストールします。これは、Arduino Leonardoをちゃんと使えるようにするためのおまじないです。おそらく、ダウンロード時にデフォルトでインストールされているはずですが、もしなければインストールしてください。

ArduinoIDEを起動し、上部のメニューバーから「ツール」→「ボード」→「ボードマネージャ」を押し、出てきた画面で「Arduino Leonardo」と検索すると出てくるはずです。

なお、2020/11/7現在、AVR boardsの最新版は1.8.3ですが、1.8.2にしないと次にインストールする「ArudunoSTL」と競合してコンパイルができないという既知のバグ(同様の投稿)があるようなので、もし、1.8.3がすでにインストールされていたら1.8.2にダウングレードしてください

(上級者向けインフォメーション:AVR boardsを1.8.3のまま進める場合は、次にインストールするArduinoSTLのバージョンを1.3.3にしてください)。

Arduino AVR Boardsは「ボードマネージャ」からインストールできる。

最新版は1.8.3だが、1.8.2にしないとエラーになる既知のバグあり(2020/11/7現在)。

 

ArduinoSTLのインストール

次に、ArduinoSTLをインストールします。STLというのはStandard Template Libraryの略です。ライブラリというのは、よく使うプログラムの機能をひとまとめにしたパッケージのことです。

インストール方法は、公式WebからZIP形式でダウンロードして所定フォルダにインストールする方法と、ArduinoIDE上でライブラリマネージャを使う方法があります。本記事では、バージョン管理が楽でわかりやすい後者を採用します。

上部のメニューバーから「スケッチ」→「ライブラリをインクルード」→「ライブラリを管理」を押し、ライブラリマネージャを開きます。そこで、「Arduino STL」と検索し、インストールを押してください。

なお、2020/11/7現在のバージョンは1.1.0です*2上記の手順でAVR boardsを1.8.2にダウングレードした人は必ず「1.1.0」を選択してインストールしてください。

インストールが終わったら、一度ArduinoIDEを閉じてください。

ArduinoSTLは「ライブラリマネージャ」からインストールできる

 

 SwitchControlLibraryのダウンロード

本記事では、Arduino Leonardoで、Switchコントローラー機能をプログラムするにあたって、「SwitchControlLibrary」というライブラリを使います。「SwitchControlLibrary」はGithubhttps://github.com/celclow/SwitchControlLibrary)からダウンロードできます。

【重要】2021年2月27日追記:今年の1月24日にこのライブラリのメジャーアップデート(ver 2.0.0)がありました。下方互換性が無いため、本記事を参考にする場合は「ver 1.0.0」をダウンロードしてください。

f:id:tangential_star:20210227023006p:plain
f:id:tangential_star:20210227023016p:plain
SwitchControlLibrary(ver1.0.0)のダウンロード手順(2021/2/27画像差し替え)
※2021/1/24にver2.0.0が公開されましたが、当ブログでは旧バージョンのver1.0.0を利用します。

なお、本ライブラリはcelclow氏がMITライセンスにて無償で配布しているものとなります。ライブラリの詳細説明は他サイトや同梱のReadMeに譲りますが、そもそも無保証のものであるという前提と、有志による提供であることを念頭に使用しましょう。

ZIPをダウンロードしたら解凍し、Arduinoのライブラリフォルダにフォルダごと入れてください。なお、この作業はArduino IDEが終了している状態で行うことを推奨します

ArduinoのライブラリフォルダはWindows版の場合、下記2種類あります。どちらでも同じように動くはずですが、個人的にはユーザドキュメント側のほうが良いと思います。

  • ユーザドキュメント直下のArduinoフォルダ【おすすめ】
     (例 C:\Users\<ユーザ名>\Documents\Arduino\libraries )
  • 本体インストールフォルダ(Program files(x86))のArduinoフォルダ
     (例 C:\Program Files (x86)\Arduino\libraries )

Windowsインストーラー版の場合、ドキュメントフォルダ直下にArduinoフォルダがある。Arduino→librariesにフォルダごとドラッグ&ドロップでライブラリの追加が完了する。

 

boards.txtの書き換え

実は、ここまでの作業で開発環境は完成しているのですが、NintendoSwitchの自動化にはあとひとつ、ステップを踏む必要があります。

この状態でプログラムを書いて、Arduino LeonardoをNintendo Switchにつないでも、Switch本体からコントローラーとして認識されず、自動化ができません。そこで、ArduinoをSwitchコントローラーとして騙すために、ボード情報を書き換えます。

この作業はArduinoIDEを終了している状態で行うことを強く推奨します。

Windows版の場合、ユーザの権限などによって参照される「boards.txt」の場所が違うらしく、下記フォルダに同じファイル構成で存在します。よくわからなければAppDataフォルダの方を更新してみて、様子を見てみましょう。Switchに挿して動かなければ、ここのboards.txtの書き換えが怪しいです。

なお、環境によって、boards.txtがどこにあるのか、あるいは複数あるのかなどが変わります。ともかく、下記フォルダを辿ってみてください*3

 ※AppDataフォルダが見つからない場合、「隠しファイル」の表示をオンにしてください。
 ※Windows標準の「メモ帳」では正しく動かない報告があります。テキストエディタを利用してください。

  • AppDataフォルダ内【原則こちらを書き換える】
    C:\Users\<ユーザ名>\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.8.2
  • Program filesフォルダ内【上記でうまく行かなければこちらも書き換える】
    C:\Program Files (x86)\Arduino\hardware\arduino\avr

AppDataフォルダのboards.txtを書き換えよう。

書き換える内容は下記4箇所です。デフォルトのboard.txtなら285行目・286行目・311行目・312行目が書き換え対象になると思います。

  • leonardo.vid.1=0x2341 ⇒ leonardo.vid.1=0x0f0d
  • leonardo.pid.1=0x8036 ⇒ leonardo.pid.1=0x0092
  • leonardo.build.vid=0x2341 ⇒ leonardo.build.vid=0x0f0d
  • leonardo.build.pid=0x8036 ⇒ leonardo.build.pid=0x0092

※280行目~320行目「Arduino Leonardo」の設定項目部分(書き換え済)

 

余談ですが、今回書き換えたvidとpidはそれぞれ、「ベンダー・アイディ」「プロダクト・アイディ」と呼ばれるもの。要するに、Switchがこの情報を参照してコントローラーの種類を把握しているので、ここを書き換えれば、Switchをだまくらかせる仕組みです。今回使う「SwitchControlLibrary」では、ホリの「ポッ拳DXプロパッド」に擬態させるので、上記の「board.txt」のleonardo.vid.1・leonardo.build.vidを「0x0f0d」に、leonardo.pid.1・leonardo.build.pidを「0x0092」にそれぞれ変更します。

本来、Arduino Leonardoはvid=0x2341,pid=0x8036だが、これらを
vid=0x0f0d,pid=0x0092に書き換えて、ホリのポッ拳DXコントローラーに擬態する。

なお、ネットで拾ってきた情報だと↓のような騙し方があるようです。
プログラミングやエンジニアリングに興味のある方は色々と調べてみると面白いかもしれません。

VID,PID → 対応するコントローラー
0x0f0d, 0x00c1 → HORI HORIPAD for Nintendo Switch
0x0f0d, 0x0092→ HORI Pokken Tournament DX Pro Pad(今回擬態したもの)
0x057e, 0x2009 → Nintendo Switch Pro Controller
0x057e, 0x2007 → Nintendo Switch Joy-Con (Right)
0x057e, 0x2006 → Nintendo Switch Joy-Con (Left)

 

サンプルスケッチのコンパイル

ここまでお疲れさまでした。以上で開発環境のインストールは完了です。

念の為、動くことを確認するために、ArduinoIDEを起動して、「ファイル」→「新規作成」を押して、下記スケッチをコピペしてください。
ちなみに、「スケッチ」というのはArduinoのプログラムという意味です。

 

※Aを連打するだけのスケッチ(プログラム)

 

 コピペしたら、ArduinoIDEの検証ボタン(左上のチェックマーク)をクリックします。下側にステータスバー(コンソール)に「コンパイルが完了しました」と出れば正常にコンパイル機械語に変換)ができています。なお、もし、「エラーが発生しました」などが出てくる場合は、その内容でGoogleやYahooで検索すると、似たような内容が出てくるので、それで対処してください。

 

そのままArduinoをPCとつないで、こんどは「マイコンボードに書き込み」をクリックします。この際、「ツール」→「ボード」→「Arduino Leonardo」にチェックが入っていることを確認してください。また、「ツール」→「シリアルポート」→Arduino Leonardoが刺さっているCOMポート番号になっていることを確認してください。

「ボードへの書き込みが完了しました」となれば正常終了です。

ボード・シリアルポートがArduino Leonardoになっていることを確認

 

動作確認

ここまでできていれば、あとは実際に動作確認のみです。

スケッチを書き込んだArduino LeonardoをNintendoSwitchに差し込みます。

差し込んでからおおよそ3~5秒ほどでコントローラー(ポッ拳DXコントローラー)と認識して入力を受付始めます。

上記のサンプルプログラムはひらすらAを連打するプログラムですので、A連打で動作確認できる場所で動作確認します。

 

ポケモン剣盾なら、ワイルドエリアの「ハシノマはらっぱ」にいる穴掘り兄弟で試すとわかりやすいです。兄弟の前でArduino LeonardoをSwitchに差し込むと、ひたすら話しかけてくれます。これでワットがある限りいつまでも穴を掘り続けてくれますね。

「ハシノマはらっぱ」の位置
穴掘り兄弟でA連打
ハシノマ原っぱの穴掘り兄弟で動作確認。A連打がわかりやすい。


以上、Arduino Leonardoを使ったポケモン剣盾の自動化にあたり、開発環境の構築と、サンプルスケッチの動作確認でした。
かなり大変だったかと思いますが、ここまでできてしまえば後はいろんなWebサイトからプログラムを拝借して使うもよし、自分でプログラムを書いて自動化するもよし、素敵な自動化ライフが待っていることでしょう。

 

このブログ記事が、その一助となれば幸いです。

 

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

 

【注意】ライブラリやボード、Arduino IDEのアップデートは慎重に

以下2024/1/7追記:(Switch自動化をこれからやろうと思っている人に向けて)

Switch自動化の環境構築を目的としてArduino IDEを導入した場合は、不用意にアップデートをしないようにしてください(無論、自己責任です。セキュリティ的な脆弱性などをはらむ可能性があるので)。

Arduino IDE側のおせっかい機能(正しい話なのですが…)により、アップデートを促す内容が出てくることがあります。よくわからない人は、下記画像のような「新しいバージョンが入手可能になりました」とか「ボードとライブラリにアップデートがあります」という文言が出てきても無視をしてください

アップデートを促すポップアップが表示されるが、Switch自動化のために導入した場合は無視しよう。
(アップデートすると、せっかく構築した環境が上書きされてしまう)

不用意にアップデートをすると、せっかく構築した環境が変わってしまい、例えば、ソースコードコンパイルできなくなったり、コンパイルはできても、SwitchからArduinoが認識されなくなったりします

具体的には、ボード(Arduino AVR)のバージョンが変わるとboards.txtが書き換えられてしまうため、SwitchがArduinoをコントローラーとして認識できなくなってしまいます。他にも、その他予期しない部分のバージョン競合が起こる可能性があります。

また、ライブラリのアップデートにおいても、ArduinoSTLのバージョンは、上記Arduino AVR(ボード)のバージョンと相互に干渉するため、これらのバージョンを正しく理解して更新せねばなりません。

このあたりは、他のツール類やソフトウェアにも当てはまります。アップデートをすることで、何が変化しどうなるのか、自身が正しく理解できるように努めてください。

(追記ここまで)

 

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

 

次の記事:

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

*1:本記事では、公開当初に動作確認ができた組み合わせでのバージョンを紹介しております。筆者は2022/9頃に2.0.0に更新をしてコンパイル不可に陥った経験があるためArduino Legacy IDEに戻す運用をしました。2024年現在は治っている可能性はあります。Arduino IDE 2.2.XでのSwitch自動化の動作確認の報告はあるようです。すでにArduino IDE 2.X.Xで動作している方はダウングレードは不要です

*2:2022/12/25追記:先の手順でArduino AVRを1.8.2にしたらSTLは必ず1.1.0にしてください。やむなくArduino AVRを1.8.3にする場合は、STLを1.3.3にしてください

*3:2023/1/7追記:コンパイルの際に使われているboards.txtの場所については、Arduino IDEの「環境設定」内部の「設定」タブにある「より詳細な情報を表示する」のチェックボックスを「コンパイル」側に入れて、任意のinoファイルをコンパイル(検証)することで、コンソール(ログ欄)の3行目あたりに「Using board 'leonardo' from platform in folder: <boards.txtの場所>」と表示されます。どうしても見つからない場合はこちらを確認してください