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

ますたーです。あけましておめでとうございます。2021年もよろしくお願いいたします。

 

今回は、ポケモンキャンプで「カレー」を自動で調理するArduino Leonardo自動化の記事です。

なお、Arduino Leonardo自動化の導入と、機材構成については導入記事をご覧ください。

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

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

 

概要

本記事では、ポケモン剣盾の「ポケモンキャンプ」の「カレー」づくりを自動で行います。「クラボのみ」を6個ずつ消費(食材不要)して、マホミル級のカレー完全放置作ってくれます。カレーのあかしを持ったポケモンの厳選が効率的にできます。 

2021/6/9追記:ポケモン捕獲までの完全自動化に成功しました。合わせてご参考ください⇒【Arduino自動化09ex】「カレーのあかし」持ちポケモンの完全自動厳選【キャンプでカレー】

f:id:tangential_star:20210102002716g:plain
f:id:tangential_star:20210102102016p:plain
ポケモンキャンプのカレー作りを自動化。食材不要・クラボのみ6個でマホミル級になる

 

それでは、今回の目次です。

 

つくったきっかけ

Twitterのタイムラインを眺めていたところ「カレーのあかし」を持ったポケモンが手に入る場所についてまとめた投稿を見かけて、何故か猛烈に『カレーずきなモルペコ』が欲しい!」と思ってしまったので作りました。

 

調理後、まれに「カレーのあかし」を持ったポケモンが見つかる

最初にカレー作りの目的について紹介します。「目的なんかわかりきっている!使い方とソースコードだけ寄越せ!」という方は読み飛ばしてください⇒読み飛ばす

 

まず、ワイルドエリア・ヨロイじま・カンムリせつげん以外の道路上(例えば9番道路など)で、「ポケモンキャンプ」でカレーを作ると、時々、その香りに釣られてポケモンがやってきます。話しかけると仲間になってくれます。

f:id:tangential_star:20210102102901g:plain
f:id:tangential_star:20210102103030p:plain
カレー調理後、香りに釣られてポケモンが遊びに来る。話しかけると仲間になってくれる

さらに、カレー調理後にやってきたポケモン「カレーのあかし」リボンを必ず持っているという特徴があります。

いわゆる「証厳選」をしたことがある人はご存知かと思いますが、「○○のあかし」を持つポケモンは野生でのみ出現します。ところが、そのポケモンが証を持っているかどうかは捕まえないと分かりません。しかも、その所持率はおおよそ2%で、なんと証の種類もランダムです。狙った証をつけるのは至難の業と言えます。

一方で、カレーを作った後の野生のポケモンは必ず「カレーのあかし」を持っているため、狙った証を100%つけることができます。今回のお目当ては、「カレーのあかし」を持ったモルペコです(モルペコの特性は「はらぺこスイッチ」ですし、「カレーずき」の二つ名はまさにピッタリですよね)。

f:id:tangential_star:20210102011021p:plain
f:id:tangential_star:20210102011451g:plain
「カレーのあかし」を持ったポケモンは、登場時に「カレーずきな」という二つ名が付く

なお、野生ポケモンが来てくれる確率は、手持ちポケモンのなつき度と、作ったカレーのランクによって変わります。

有志による検証によれば、最もポケモンが出やすいカレーのランクは「マホミル級」で、その確率は1/7(約14%)だそうです。ちなみに、左記は手持ちがなつき度MAX6匹の状態でのお話です。なつき度はカレーを作ると上がるので、カレーずかん埋めも兼ねて、とりあえず無限にカレーを作り続けるのが良いでしょう(適当)。

f:id:tangential_star:20210102102016p:plain
f:id:tangential_star:20210102120251p:plain
「マホミル級」のカレーを作ると野生のポケモンが来やすい。確率は最大で1/7ほど

 

「マホミル級」のカレーづくり

完全に余談です。直接は関係無いので、事前準備まで読み飛ばしもOKです⇒読み飛ばす

前述の通り、カレー調理後に最もポケモンが出やすいのは「マホミル級」なのですが、作中で無限に買うことができる「きのみ(クラボのみ・モモンのみ・オレンのみ・カゴのみ)」で「マホミル級」を出すのは結構シビアです。

具体的には、6個以上のきのみを入れて、一切のミスなく上手に調理できれば「マホミル級」になります。火起こしと真心はともかく、かき混ぜがかなり難しいです。

f:id:tangential_star:20210102115521g:plain
f:id:tangential_star:20210102115539g:plain
f:id:tangential_star:20210102115602g:plain
「あおいで!」「まぜて!」「まごころ こめて!」美味しいカレーが出来上がる

一応、食材屋でごくまれに購入できる2200円食材「しっぽのくんせい」「ゆでタマゴ」「フサパック」「モーモーチーズ」や、マックスレイドバトルでまれに手に入る「キョダイパウダー」、ワイルドエリアで拾える「ながねぎ」を使うと、完全放置(無操作)でも「マホミル級」が確定しますが、入手が困難だったり、試行回数を考えるとコスパが悪かったりします。

また、150円食材や400円食材、950円食材では「マホミル級」を幾分作りやすくなりますが、こちらは完全放置というわけには行きません。

なので、私にて色々試したり考えたりした結果、食材は入れず、調理は超一流のシェフ(Arduino Leonardo)におまかせすることにしました

f:id:tangential_star:20210102105423p:plain
f:id:tangential_star:20210102105432p:plain
まれに食材屋で2,200円の食材が販売される。これらを使うと「マホミル級」以上が確定

 

手持ちときのみを揃える(事前準備)

「カレーのあかし」を持ったポケモンを効率的に呼ぶためには、事前の準備として、「最高になついたポケモン6匹」と「大量のきのみ」が必要です。

なつき度(なかよし度)を最大ランクまで上げるには、キャンプでの触れ合いが不可欠です。カレーを沢山作って一緒に過ごしてください。なお、性格に合ったカレーの味だとなかよし度が上がりやすいそうです。それぞれのポケモンの好みに合わせてカレーを作ってあげてください。

f:id:tangential_star:20210102121606p:plain
f:id:tangential_star:20210102121615p:plain
ナックルシティ民家の少年が教えてくれる。なつき度MAXなら「なかよしリボン」も貰える
f:id:tangential_star:20210102123917g:plain
f:id:tangential_star:20210102124425g:plain
話しかけた時に5つのハートがでたり、戦闘時にチラッとコチラを見たらなかよし度MAXだ

続いて、きのみの調達です。

前述の通り平均して7調理ごとに1回しかポケモンには会えない上に、1回毎に少なくとも6個単位できのみを消費するため、大量のきのみが必要になります。地道に木を揺らしていくのは手間暇かかるため、余りがちなお金で無制限にきのみを購入できるブラッシータウンの「きのみショップ」を利用します。DLCを購入している人はヨロイじまのきのみショップでもOKです(ヨロイじまだと4種類から買えます)。

1個80円で買えるので、「クラボのみ」を999個買ってください。8万円を切ります。

買ったきのみは「リュックの一番上」においてください。クラボのみはきのみの種類順で1番になるのでリュックの一番上に来ているはずですが、もし一番上じゃなかったら適宜並び替えてください。

※「クラボのみ」でなくても大丈夫です。本プログラムは「モモンのみ」「オレンのみ」「カゴのみ」のいずれも動作確認できています。無論、「リュックの一番上」においてください。

f:id:tangential_star:20210102122035p:plain
f:id:tangential_star:20210102122044p:plain
ブラッシータウンかヨロイじまの「きのみショップ」で購入できる。999個でも79920円だ


欲しいポケモンが出てくる道路に行こう (準備)

カレー作り後に現れるポケモンは、シンボルエンカウントではなく、草むら・水上で「!」と共に出現するポケモンから選ばれます。また、前述の通りワイルドエリアやDLCの島々では出現しません。これらを勘案して、自分の欲しいポケモンを図鑑の分布などを見ながら探してください。

なお、本記事ではモルペコが欲しいのでルートナイントンネルの右側の9番道路(=スパイクタウンはずれ)に行きます。 

f:id:tangential_star:20210102134430p:plain
f:id:tangential_star:20210102133513j:plain
「カレーのあかし」を持ったポケモンの出現場所について
左:「ポケモン徹底攻略」より画像引用・改変     右:だま氏のTwitter投稿@monst_dama)より画像引用
f:id:tangential_star:20210102132327p:plain
f:id:tangential_star:20210102121233p:plain

「モルペコ」を狙うには、なつき度MAXの6匹を連れて「スパイクタウンはずれ」に行こう

 

プログラムの使い方

下記が必要な条件です。特に重要な準備については前述の通りです。その他は、普通にプレイしていれば満たしているはずですが、念の為合わせて確認してください。

  1. なかよし度MAX のポケモン6匹が手持ちにいる
  2. 充分な量の「きのみ(クラボのみ999個など)」がリュックの一番上にある
  3. 食材を1つ以上持っている(一切消費しませんが、食材欄が空っぽだとうまく動きません)
  4. 充分な量の「モンスターボール」「スーパーボール」「ハイパーボール」いずれかを持っている(これらのいずれかにしか入りません。原則としてモンスターボールが優先されます)
  5. ボックスが空いている

これらを満たしたら、メニューから「ポケモンキャンプ」を開いてください。

そして、ポケモンキャンプが開いたら、手動で一度Xボタンを押し、カーソルを「料理」に合わせてからBボタンでメニューを閉じてください(重要)。

この状態でArduino Leonardoを挿したら、あとは勝手に調理をしてくれます。調理後、10秒ほどかけて自動でキョロキョロしてくれるので、目当てのポケモンがいたらArduino Leonardoを抜いてください。

f:id:tangential_star:20210102141132p:plain
f:id:tangential_star:20210102141141p:plain
事前準備の上、目的の道路に着いたら「ポケモンキャンプ」を開こう
f:id:tangential_star:20210102141454p:plain
f:id:tangential_star:20210102141503p:plain
キャンプでXボタンを押した時に、カーソルが「料理」に合う状態にしてからBを押そう

 

プログラムのソースコード

ポケモンキャンプでカーソルが「料理」に合う状態でメニューを閉じてからArduinoを挿すだけの簡単設計です。全自動で「調理⇒調理後キョロキョロ」をひたすら繰り返してくれます。目当てのポケモンが見つかったら引っこ抜いてください。

2021/6/9追記:ポケモン捕獲までの完全自動化に成功しました。合わせてご参考ください⇒【Arduino自動化09ex】「カレーのあかし」持ちポケモンの完全自動厳選【キャンプでカレー】

 

所有する「クラボのみ」の数(1~999)と、1回の調理で消費するきのみの量(1~10)をプログラム中でそれぞれ「CHERI_BERRY」「USING_BERRY」で指定することができます。

#define CHERI_BERRY (999) // 「クラボのみ」の所有数
#define USING_BERRY (6) // 1回の調理で何個のきのみを利用するか

残りの量が消費予定量を上回った場合にプログラムは自動で止まるように設計していますので、手持ちのきのみの個数を勘案の上、必要に応じて書き換えて使ってください。

なお、「USING_BERRY」の数ですが、5個以下だと確定で「ソーナンス級」になります。「マホミル級」のカレーを作るには、最低でも6個は必要です。また、6個にしていても、20回くらいに1回くらいの割合で何故かソーナンス級になることがあります。理由は分かりませんが、なんとなく心配な人や、試行回数よりも精度を求めるという人は「10個」にしてください。一応、筆者としては「6」または「10」のいずれかを推奨します。

それではソースコードです。

/* 
 *  全自動カレー作りc⌒っ.ω.)っ 
 *  (c) 2021 ますたーの忘備録
 *  https://tangential-star.hatenablog.jp/
*/

#include <SwitchControlLibrary.h>

#define HOLDTIME (95) // 1回のキー入力の長押し時間
#define KAKIMAZE_CYCLE (435) // かき混ぜ時周期(1回転の必要ミリ秒)
#define RENDA_CYCLE (150) // 連打のサイクル(1回仰ぐのにかかるミリ秒)
#define CHERI_BERRY (999) // 「クラボのみ」の所有数(これをオーバーしないように止まります)
#define USING_BERRY (6) // 1回の調理で何個のきのみを利用するか
 // ↑6,7,10で「マホミル級」検証済。1,5は「ソーナンス級」検証済。
 // メモ:6個の時、極稀にソーナンス級になることがあった。理由は不明。心配な人は10で。
#define AIJO_BASETIME 3200 // 愛情を込めるタイミング
#define AIJO_OFFSET 60 // きのみの数でズレる単位時間(ミリ秒)

void PushRL(int delay_time_ms);
int PushKey(char* keyname, int holdtime, int delaytime);
void TiltLeftStick(int direction_deg, double power, int holdtime, int delaytime);

int CheriBerryNum = 0;

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

void loop() {
  int i=0;
  unsigned long int current_time=0;
  unsigned long int start_time=0;
  unsigned long int temp_time=0;
  float holdA = 0;
  int isholding = 0;
  float temp_deg = 0;
  int isfirsttime =0;
  int aijo_kome = AIJO_BASETIME+AIJO_OFFSET*USING_BERRY;

  if(CheriBerryNum < USING_BERRY){
    // 残りの「クラボのみ」がUSING_BERRY個未満ならプログラムをストップ
    for(;;) delay(1000);  
  }
  
  // メニューを開く
  PushKey("X",    HOLDTIME, 1000);
  // 料理を選択
  PushKey("A",    HOLDTIME, 750);
  // 「料理を始める」
  PushKey("A",    HOLDTIME, 2500);
  // 食材⇒いれない
  PushKey("A",    HOLDTIME, 350); // 空白のA
  PushKey("+",    HOLDTIME, 550);
  PushKey("A",    HOLDTIME, 350); // 空白のA
  // きのみ⇒「クラボのみ(一番上)」USING_BERRY個
  #if(USING_BERRY == 10)
    PushKey("A",    HOLDTIME, 550);
    PushKey("Down", HOLDTIME, 550);
    PushKey("A",    HOLDTIME, 1500); // クラボのみが10個まな板の上に乗るのを待つ
  #else
    PushKey("A", HOLDTIME, 550);
    for(i=0;i<USING_BERRY-1;i++)PushKey("UP",HOLDTIME, 150);
    PushKey("A", HOLDTIME, 180*USING_BERRY);
    PushKey("+", HOLDTIME, 350); // +で材料を決定
  #endif
  // A押してから確実に5秒ジャストで引き渡し
  for( start_time=millis(), current_time=start_time,isfirsttime=1 ; current_time - start_time < 5000 ; current_time=millis() ){
    // ループ初回のみAを押す
    if(isfirsttime){
      // 選んだきのみで始めますか?⇒はい
      PushKey("A", 100, 300);
      isfirsttime=0;
    }
  }
  // 火起こし「21秒」
  for( start_time=millis(), current_time=start_time, isholding=0 ; current_time - start_time < 21000 ; current_time=millis() ){

     // RENDA_CYCLEミリ秒ごとにAを押す
     temp_time = (current_time - start_time) % (RENDA_CYCLE+1); // 経過ミリ秒のRENDA_CYCLE剰余を計算
     holdA = (float)temp_time / (float)RENDA_CYCLE * 100.0; // 剰余から100%に変換
     if( holdA <= 35.0 ){ // RENDA_CYCLEの3.5割の時間はA押し、それ以外はAを離す
       if(!isholding){
         SwitchControlLibrary().PressButtonA();
         isholding = 1;
       }
     }else{
       if(isholding){
         SwitchControlLibrary().ReleaseButtonA();
         isholding = 0;
       }
     }
  }
  if(isholding) SwitchControlLibrary().ReleaseButtonA();

  // かき混ぜ「18秒」
  for( start_time=millis(), current_time=start_time ; current_time - start_time < 18000 ; current_time=millis() ){
     // KAKIMAZE_CYCLEミリ秒ごとに1周スティック回転
     temp_time = (current_time - start_time) % (KAKIMAZE_CYCLE+1); // 経過ミリ秒のKAKIMAZE_CYCLE剰余を計算
     temp_deg = (float)temp_time / (float)KAKIMAZE_CYCLE * 360.0; // 剰余から360°角度に変換
     TiltLeftStick( (int)temp_deg, 1.0, 0, 0); // 経過時間とKAKIMAZE_CYCLEの周期に応じた角度に倒す
  }
  TiltLeftStick( 0, 0.0, 0, 0); // スティックを初期位置に戻す

  // 愛情込め~配膳「20秒」
  for( start_time=millis(), current_time=start_time,isfirsttime=1 ; current_time - start_time < 20000 ; current_time=millis() ){
    // 愛情込めは3.8秒
    temp_time = (current_time - start_time);
    if( temp_time > aijo_kome && isfirsttime==1){ // aijo_komeミリ秒を超えたタイミングで愛情込め
      if(isfirsttime) PushKey("A", 100, 300); // 愛情込め
      isfirsttime=0;
    }
  }
  PushKey("A", 100, 300); // 配膳されたカレーを眺めた後のA
  // もぐもぐ~マホミル級のおいしさ「13秒」
  delay(13000); // カレー実食中・・・
  PushKey("A", 100, 2000); // フィールドに戻る

  // あたりを見回してカレー好きのポケモンがいないか確認(目視で確認してね!)
  TiltLeftStick( 90, 0.5, 2000, 1000); // 右側を見る。
  TiltLeftStick( 270, 0.5, 4000, 1000); // 左側を見る。
  TiltLeftStick( 90, 0.5, 2000, 1000); // 右側を見る。
  TiltLeftStick( 0, 0.0, 0, 0); // スティックを初期位置に戻す

  // 3秒待ったら次のカレーを作ります。
  delay(3000);
  CheriBerryNum -= 10; // 手持ちの「クラボのみ」個数を10個減らす

}

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 TiltLeftStick(int direction_deg, double power, int holdtime, int delaytime){
  double rad = (double)direction_deg*PI/180.0; // 弧度法(ラジアン)変換
  int x, y;
  x = (double)128*sin(rad)*power;
  y = (double)-128*cos(rad)*power;
  x += 128; y += 128;
  if(x >= 255) x=255; if(x <= 0) x=0;
  if(y >= 255) y=255; if(y <= 0) y=0;

  SwitchControlLibrary().MoveLeftStick(x,y);
  if(holdtime> 0){ // holdtime=0のときは押しっぱなし。
    delay(holdtime);
    SwitchControlLibrary().MoveLeftStick(128,128); // 傾きを直す
  }
  if(delaytime>0) delay(delaytime);
  return;
}

 

f:id:tangential_star:20210102002716g:plain
f:id:tangential_star:20210102102901g:plain
左:ループの様子。 右:ポケモンを見つけたらArduinoを抜いてコントローラーを挿そう


あとがき

改めまして、新年あけましておめでとうございます(執筆:2021年1月2日)。昨年の11月にこのブログを始めて、なんとか更新を続けることができています。

アクセス数も順調に伸びてきていて、時には「はてなスター」をいただいたり、読者が増えたり、コメントで「マイコン導入のきっかけになった」と報告をいただいたり、 など、まだまだ駆け出しの当ブログですが、皆様にモチベーションを支えられて更新が続けられているなぁ、と感じます。これからもどうぞ応援のほどよろしくお願いいたします。

 

さて、今回はポケモンキャンプの「カレーづくり自動化」にフォーカスを当てた記事でしたが、やはり自分の思ったとおりにプログラムが動くのは気持ちが良いものですね。今回のプログラムは試行錯誤しながら作ったので、達成感もひとしおでした。

特に、自分がスティック入力をしていないのにカレーが自動でかき混ぜられている様子を見るのが楽しかったです。

f:id:tangential_star:20210102115521g:plain
f:id:tangential_star:20210102115539g:plain
(再掲)全自動で「火起こし」「かき混ぜ」をする様子

前々回の記事では、スティック入力に対応した雛形をつくりましたが、1方向に倒し続ける動作はもちろん、回転させるなどの一連の動きをコントロールできるのは、より人間の作業に近いものを扱えるようで嬉しく思いますね。

もちろん、マクロ対応コントローラーでは絶対真似できない芸当ですし、人間でもこんなに正確に操作はできないので、今回の例はまさにArduino Leonardoならではの自動化とも言えると思います(言い過ぎかな)。

 

話が逸れましたが、以降も精進して参りますので今後ともどうぞよろしくお願いいたします。

 

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

 

2021/6/9追記:ポケモン捕獲までの完全自動化に成功しました。合わせてご参考ください⇒【Arduino自動化09ex】「カレーのあかし」持ちポケモンの完全自動厳選【キャンプでカレー】 

前回記事:【Arduino自動化08】バトルタワー自動周回【BP稼ぎ】

次回記事:【Arduino自動化10】きのみ・ぼんぐり自動回収

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

 

おまけ(パッチルドンのはなみず)

この記事の中のどこにも入れられなかったのですが、どうしても紹介したかったことが1つあったので追伸として。

 

パッチルドンといえばいつも凍えていて鼻水を垂らしていますよね。

でも、カレーを食べている時だけ、パッチルドンの震えも鼻水も止まっているのです。

上でさんざんGIF動画の中に映っていましたが、気づきましたか?

 

f:id:tangential_star:20210102153141g:plain

カレーをもぐもぐ食べている時だけ、パッチルドンのはなみずと震えが止まっている

 

以上です。今年もよろしくお願いいたします。c⌒っ.ω.)っ

【Arduino自動化08】バトルタワー自動周回【BP稼ぎ】

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

今回は、「バトルタワー」自動周回で、BPを稼ぐArduino Leonardo自動化の記事です。

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

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

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

 

概要

本記事では、シュートシティの「バトルタワー」自動周回を実装します。

f:id:tangential_star:20201229104124p:plain
f:id:tangential_star:20201229144836g:plain
バトルタワーを自動周回(1周あたり3分~6分ほど)。1周ごとに2BP貰える

目次です。

 

経緯

バトルタワー周回という「いまさら」感が強いタイミングでの記事化となりますが、実は、当ブログのアクセス状況を確認すると、ダイマックスアドベンチャーの自動周回記事が(アクセス数も検索流入も)大変盛況なのです。

どうやら、従来のマクロ対応コントローラーでできることをマイコン(本ブログだとArduino Leonardo)に対応させたいという需要は一定数あるらしく、それならこのブログでも取り上げる価値があるかな?と思ったので記事化しました。

BP(バトルポイント)は、お金やワットとは引き換えられないもの(いじっぱりミントなど)も多いため、そういう意味でも需要はあると思います。

 

この記事のスタンス

本記事では、下記の前々回・前回(第6回・第7回)の記事に引き続き、マクロ対応コントローラーの代替用の雛形をベースにArduino Leonardo用にプログラムを書いていきます。例のごとく、入力するコマンド列が予め分かっているものを活用します。

なお、本ブログで扱うコマンド列は、私が考案したものではありません。ダイマックスアドベンチャーの記事でも紹介した、あずき氏によるものです。当該ブログ記事を下記にて引用します。合わせてご参考ください。

azukiss.hatenablog.com

 

バトルタワー自動周回のやりかた

バトルタワーの自動周回には、以下の条件を満たしている必要があります。

  1. バトルタワー「シングルバトル」ランクが「マスターボール級」であること
  2. 自動周回用のパーティーを準備していること

1のマスターランク到達は前提ですが、今作では禁止伝説級のポケモンが使用できるのでゴリ押しで攻略可能です。1時間ほどでマスターランクに到達できると思います。

2の自動周回用パーティーですが、

の3匹を準備してください。なお、それぞれのPPは最大値まで増やしておきましょう。

自前で準備が難しければレンタルチーム(要Nintendo Online加入)でも可能です(参考チームID:0000 0000 5MJ4 0K)。

f:id:tangential_star:20201229133747p:plain
f:id:tangential_star:20201229133714p:plain
自動周回は、シングルバトルが「マスターボール級」前提。まだの人はまず攻略しよう
f:id:tangential_star:20201229130956p:plain
f:id:tangential_star:20201229130109p:plain
メニューの「VS」からチームのレンタルが可能(要Nintendo Online加入)。

コマンド列ですが、原則としてAボタン連打で攻略していき、ポケモン入れ替えなどのために「↑」や「B」を押す、というイメージです。下記を御覧ください。

 

自動周回のコマンド入力列(あずき氏のブログ記事より引用・一部改変)

1 2 3 4 5 6 7 8
9 10 11 12 13 14 15,16
R,R(連打)

※指定が無い部分のキー入力間隔は約1.5秒

要するに、この16コマンドをひたすら繰り返すことで、バトルタワーを延々と攻略してBPを稼いでくれるということです。すごいですね。

 

自動化コマンドの実装

前回の記事で紹介した雛形・関数の要領で、前述の16コマンドを入力していきます。雛形は下記テキストボックスからコピペも可能です。今回はスティック入力が無いので、「PushKey("入力キー", 長押しミリ秒, 待機ミリ秒 ); 」を16行並べるだけです。

 

Arduino Leonardo自動化用 プログラム雛形

 

前述のコマンド列を関数に当てはめると下記の様になります。この雛形の中に下記「loop(){」と「}」の間16行を埋め込むだけでプログラムになります。

こちらは説明用に抜粋したプログラムの一部です。プログラム全文は⇒コチラをクリックして読み飛ばす

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

void loop() {
  // ↓ここに繰り返すコマンド列を入れよう
  PushKey("A",    HOLDTIME, 1500); // 1: A HOLTIMEミリ秒長押し 1.5秒待機
  PushKey("A",    HOLDTIME, 1500); // 2: A HOLTIMEミリ秒長押し 1.5秒待機
  PushKey("A",    HOLDTIME, 1500); // 3: A HOLTIMEミリ秒長押し 1.5秒待機
  PushKey("A",    HOLDTIME, 1500); // 4: A HOLTIMEミリ秒長押し 1.5秒待機
  PushKey("UP",   HOLDTIME, 1500); // 5: ↑HOLTIMEミリ秒長押し 1.5秒待機
  PushKey("A",    HOLDTIME, 1500); // 6: A HOLTIMEミリ秒長押し 1.5秒待機
  PushKey("A",    HOLDTIME, 1500); // 7: A HOLTIMEミリ秒長押し 1.5秒待機
  PushKey("UP",   HOLDTIME, 1500); // 8: ↑HOLTIMEミリ秒長押し 1.5秒待機
  PushKey("A",    HOLDTIME, 1500); // 9: A HOLTIMEミリ秒長押し 1.5秒待機
  PushKey("A",    HOLDTIME, 1500); // 10:A HOLTIMEミリ秒長押し 1.5秒待機
  PushKey("A",    HOLDTIME, 1500); // 11:A HOLTIMEミリ秒長押し 1.5秒待機
  PushKey("A",    HOLDTIME, 1500); // 12:A HOLTIMEミリ秒長押し 1.5秒待機
  PushKey("B",    HOLDTIME, 1500); // 13:B HOLTIMEミリ秒長押し 1.5秒待機
  PushKey("UP",   HOLDTIME, 1500); // 14:↑HOLTIMEミリ秒長押し 1.5秒待機
  PushKey("R",    HOLDTIME, 150 ); // 15:R HOLTIMEミリ秒長押し ほぼ待機なし
  PushKey("R",    HOLDTIME, 150 ); // 16:R HOLTIMEミリ秒長押し ほぼ待機なし
  // ↑ここに繰り返すコマンド列を入れよう
}

なお、今回は15個目のRと16個目のRの間を連打するので、それぞれの待機時間を150ミリ秒(充分短い時間)にしています。なお、この間が極端に短すぎる(例えば10ミリ秒などに設定する)と、Switch側がボタンの押下状態を認識できずコマンドミスすることがあるようです。注意しましょう。

 

プログラムの使い方

前述の通り、攻略用3匹のみのパーティーを準備の上、シュートシティの上側にあるバトルタワーへ行き、受付の前でArduino Leonardoを差し込むだけです。
なお、初回は「手持ち」にカーソルが合っていると思いますので、上記のレンタルチームを活用している人は、手動でそちらにカーソルをあわせておいてください。

f:id:tangential_star:20201229143158p:plain
f:id:tangential_star:20201229133747p:plain
f:id:tangential_star:20201229133714p:plain
f:id:tangential_star:20201229143220p:plain
攻略用チームが選ばれるように準備の上、バトルタワーの受付前でArduinoを差し込む。

 

プログラムのソースコード

雛形は前回の記事と同一です。

/* 
 *  バトルタワー自動周回
*/

/* マクロコンのコマンドをソースコード化するための雛形【Newバージョン】

loop(){」のすぐ下に繰り返したいコマンドを書いていくだけで、
Arduino Leonardo用のソースコードができあがる簡単設計。

書き方としては1行ずつ↓を書いていく。
・ボタン入力:「PushKey("入力キー", 長押しミリ秒, 待機ミリ秒 ); 」または
・スティック:「TiltLeftStick(真上を基準に傾ける角度(0-360),傾きの強さ(0.0-1.0),長押しミリ秒, 待機ミリ秒)」
 ※スティック入力に関しては、長押しミリ秒を「0」にすると傾けっぱなしになります。

たとえば、「Aボタンを1.5秒間押してその後3秒待機する」場合には、
  PushKey( "A" , 1500 , 3000 );
と書けばオーケー。
たとえば、「スティックを3秒間右に傾けてその後2秒待機する」場合には、
  TiltLeftStick(90, 1.0, 3000, 2000);
と書けばオーケー。

なお、プログラムはすべて「半角英数字」で書くこと!

ちなみに「//」の右側の文字はプログラム上で無視されるので開発用コメントを残せる。
*/
#include <SwitchControlLibrary.h>

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

void PushRL(int delay_time_ms);
int PushKey(char* keyname, int holdtime, int delaytime);
void TiltLeftStick(int direction_deg, double power, int holdtime, int delaytime);

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

void loop() {
  // ↓ここに繰り返すコマンド列を入れよう
  PushKey("A",    HOLDTIME, 1500); // 1: A HOLTIMEミリ秒長押し 1.5秒待機
  PushKey("A",    HOLDTIME, 1500); // 2: A HOLTIMEミリ秒長押し 1.5秒待機
  PushKey("A",    HOLDTIME, 1500); // 3: A HOLTIMEミリ秒長押し 1.5秒待機
  PushKey("A",    HOLDTIME, 1500); // 4: A HOLTIMEミリ秒長押し 1.5秒待機
  PushKey("UP",   HOLDTIME, 1500); // 5: ↑HOLTIMEミリ秒長押し 1.5秒待機
  PushKey("A",    HOLDTIME, 1500); // 6: A HOLTIMEミリ秒長押し 1.5秒待機
  PushKey("A",    HOLDTIME, 1500); // 7: A HOLTIMEミリ秒長押し 1.5秒待機
  PushKey("UP",   HOLDTIME, 1500); // 8: ↑HOLTIMEミリ秒長押し 1.5秒待機
  PushKey("A",    HOLDTIME, 1500); // 9: A HOLTIMEミリ秒長押し 1.5秒待機
  PushKey("A",    HOLDTIME, 1500); // 10:A HOLTIMEミリ秒長押し 1.5秒待機
  PushKey("A",    HOLDTIME, 1500); // 11:A HOLTIMEミリ秒長押し 1.5秒待機
  PushKey("A",    HOLDTIME, 1500); // 12:A HOLTIMEミリ秒長押し 1.5秒待機
  PushKey("B",    HOLDTIME, 1500); // 13:B HOLTIMEミリ秒長押し 1.5秒待機
  PushKey("UP",   HOLDTIME, 1500); // 14:↑HOLTIMEミリ秒長押し 1.5秒待機
  PushKey("R",    HOLDTIME, 150 ); // 15:R HOLTIMEミリ秒長押し ほぼ待機なし
  PushKey("R",    HOLDTIME, 150 ); // 16:R HOLTIMEミリ秒長押し ほぼ待機なし
  // ↑ここに繰り返すコマンド列を入れよう
}

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 TiltLeftStick(int direction_deg, double power, int holdtime, int delaytime){
  double rad = (double)direction_deg*PI/180.0; // 弧度法(ラジアン)変換
  int x, y;
  x = (double)128*sin(rad)*power;
  y = (double)-128*cos(rad)*power;
  x += 128; y += 128;
  if(x >= 255) x=255; if(x <= 0) x=0;
  if(y >= 255) y=255; if(y <= 0) y=0;

  SwitchControlLibrary().MoveLeftStick(x,y);
  if(holdtime> 0){ // holdtime=0のときは押しっぱなし。
    delay(holdtime);
    SwitchControlLibrary().MoveLeftStick(128,128); // 傾きを直す
  }
  if(delaytime>0) delay(delaytime);
  return;
}

 

f:id:tangential_star:20201229144836g:plain
f:id:tangential_star:20201229145153p:plain
自動周回で手に入れたBPで「ようきミント」「こだわりスカーフ」などを交換しよう


あとがき

本記事では、Arduino Leonardoを使ったバトルタワー自動周回(BP稼ぎ)について紹介をしました。

パーティーをいくつも作っていると「こだわりメガネ」「こだわりスカーフ」が足りなくなったり、不意の事故で「きあいのタスキ」「ふうせん」などを野生戦で消費してしまったりしますよね。ほかにも、育成用に欠かせない「ようきミント」「いじっぱりミント」なども不足しがちです。このあたりの道具が引き換えられるのはありがたいですね。

 

今回のバトルタワー然り、前回のトーナメント然り、前々回のダイマックスアドベンチャー然り、ポケモンには対人戦の準備に関わる「周回」が切っても切り離せないですね。無論、こういったエンドレスに遊べるコンテンツを通してやりこみや対人戦前の調整をするのが目的になるのでしょうが、アイテム回収を目的にすると少しツライものがあります。この観点において、マクロ対応コントローラーやマイコンは、各人のゲームとの関わり方の選択肢を増やしてくれるので、うまく活用していきたいものですね。

 

本記事が皆様のポケモン自動化ライフの一助となることを願っています。

 

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

 

前回記事:

【Arduino自動化07】トーナメント自動周回【マクロコン代替】

前々回記事:

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

次の記事:

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

導入記事:

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

 

【Arduino自動化07】トーナメント自動周回【マクロコン代替】

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

今回は、「トーナメント」を自動周回するArduino Leonardo自動化の記事です。前回の記事に引き続き、マクロ対応コントローラーで自動化していたコマンドをArduino Leonardoで実装します。今回はJoy-Conのスティック入力操作にもチャレンジします。ゆえに、これを読むとArduino Leonardoでマクロ対応コントローラーの「完全代替」ができるかもしれません。

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

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

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

 

概要

本記事では、シュートシティの「トーナメント」自動周回を実装します。

f:id:tangential_star:20201213004402p:plain
f:id:tangential_star:20201213004416g:plain
トーナメントを自動周回(1周8分ほど)。各種ガンテツボールやかえんだまが手に入る。

 

今回の目次です。

 

作ったきっかけ

実は、私もマクロ対応コントローラーは持っています。剣盾発売当初から今年の2月まではずっと愛用していたのですが、ずっと下記4点をネックに感じていました。

  1. 方向キーを輪ゴムなどでアナログに固定しなければならない(安定しない)
  2. 無線コントローラーだと充電しないと使えない(使い続けられない)
  3. やることを変えるたびにマクロ登録をし直さないといけない(面倒くさい)
  4. Homeボタンがマクロに登録できない(設定画面に入れない)

Arduino Leonardoは、これらを全てを解決できるからという判断で購入し、今に至るわけです。結果、良かったと思っています(2台買いました)。

f:id:tangential_star:20201213004749j:plain
f:id:tangential_star:20201213004738j:plain
マクロ対応コントローラーを使っていたが、結局Arduino Leonardoに落ち着いた。

 

この記事のスタンス

前回の記事では、「決められたコマンド入力」が分かっているものをArduino Leonardoで動く自動化プログラムを作りましたが、今回はその改良版で、Joy-Conのスティック入力にも対応させます。

したがって、もし読者の皆様にて「入力したいキーの順番があらかじめ決まっている」ものがあれば、スティック入力を含めてプログラムを自分で書ける雛形としてご利用いただけると思います(他のサイトで紹介されているマクロコントローラーの自動化コマンドなど)。ソースコードだけ欲しいという方はどうぞ⇒ 読み飛ばす

 

トーナメント自動周回のやり方

様々なブログでも紹介されている、かなり有名でオールドスタイルなやり方ですが、努力値AS振りザシアンLv.100@くちたけん(わざ:アイアンヘッドのみ;PP最大値まで増やしておく)1匹のみを手持ちに準備し、コマンドを入力し続けるだけです。ザシアンがいない人は、Lv.100サザンドラ@こだわりメガネ(わざ:あくのはどうのみ)でも多少効率が落ちますがOKです。

f:id:tangential_star:20201213004956p:plain
f:id:tangential_star:20201213005002p:plain
手持ち最適解は「アイアンヘッド」のみを覚えた AS極振りザシアン@くちたけん 1匹。

肝心の入力コマンドですが、基本的に「A連打、ちょっとだけB」というすごくシンプルな入力です。ただし、スティック上方向を起点(0度)として、時計回りにおおよそ15度~22度の向きに傾ける必要があり、この角度が手動だとかなりシビアです。ズレるとキチンと再戦ができず、ループが途切れてしまいます。

輪ゴムやテープなどでアナログに固定しなければならないマクロ対応コントローラーでは多少ツライですが、この点、Arduino Leonardoであればスティック入力のズレが起こることなく確実に再戦できます。

f:id:tangential_star:20201213012104p:plain
f:id:tangential_star:20201213013140g:plain
スティックを真上から約15~22度の方向に倒すことで、賞品受け取り後に再戦できる


Arduinoでの自動化の実装

上述の通り、今回のコマンドはかなりシンプルで、スティックを倒しながらA連打+Bを1回というものです。プログラムに起こすと、下記の様になります。

こちらは説明用に抜粋したプログラムの一部です。⇒ 完成版プログラムまで読み飛ばす

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

void loop() {
  // ↓ここに繰り返すコマンド列を入れよう
  TiltLeftStick(17, 1.0, 0, 0); // 17度の方向・強さMAX・傾けっぱなし・待機時間0
  PushKey("A",    HOLDTIME, 150); // A HOLTIMEミリ秒長押し 0.15秒待機
  PushKey("A",    HOLDTIME, 150); // A HOLTIMEミリ秒長押し 0.15秒待機
  PushKey("A",    HOLDTIME, 150); // A HOLTIMEミリ秒長押し 0.15秒待機
  PushKey("A",    HOLDTIME, 150); // A HOLTIMEミリ秒長押し 0.15秒待機
  PushKey("A",    HOLDTIME, 150); // A HOLTIMEミリ秒長押し 0.15秒待機
  PushKey("A",    HOLDTIME, 150); // A HOLTIMEミリ秒長押し 0.15秒待機
  PushKey("A",    HOLDTIME, 150); // A HOLTIMEミリ秒長押し 0.15秒待機
  PushKey("A",    HOLDTIME, 150); // A HOLTIMEミリ秒長押し 0.15秒待機
  PushKey("A",    HOLDTIME, 150); // A HOLTIMEミリ秒長押し 0.15秒待機
  PushKey("B",    HOLDTIME, 150); // B HOLTIMEミリ秒長押し 0.15秒待機

  // ↑ここに繰り返すコマンド列を入れよう
}

今回は「スティックを右上に傾ける」「Aボタンを9回押す」「Bボタンを1回押す」コマンドなので、書き換えはわずか11行で完成します。簡単ですね。

構成としては、前回の記事と同様、「loop(){」とそれに対応する「}」の間に自動化するコマンドを1行ずつ書き込むだけの簡単設計です。新たに「TiltLeftStick()」という関数を実装したので、スティック入力の自動化にも対応しています

 

  TiltLeftStick(17, 1.0, 0, 0); // 17°の向き、傾きMAXで倒し続ける。

関数の仕様の話をしてもしょうがないですが、要するにJoy-Con左スティック入力は「どの向き」に「どのくらい倒すか」を指定することで実現できると理解いただければOKです。また、「倒し続ける時間」「スティックを戻した後の待機時間」はそれぞれ「ミリ秒」で指定できます。

なお、倒し続ける時間・待機時間(3つ目・4つ目)をそれぞれ「0」「0」と指定すると倒し続ける(スティック位置を戻さない)こともできます。

上記例だと17°の方向に傾きMAXでスティックを倒し続けるようになっています。

f:id:tangential_star:20201213101728p:plain

実装した「TiltLeftStick()」関数は極座標系のイメージ。倒す向きと強さをそれぞれ指定する

 

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

前述の通り、手持ちをLv100ザシアン@くちたけん 1匹のみにして、シュートシティの右上の方にあるポケモンリーグ本部へ行き、受付の前でArduino Leonardoを差し込むだけです。

f:id:tangential_star:20201213113132p:plain
f:id:tangential_star:20201213113250p:plain
f:id:tangential_star:20201213113200p:plain
f:id:tangential_star:20201213113241p:plain
手持ちはザシアン1匹。シュートシティのポケモンリーグ本部の受付前でArduinoを差し込む

 

プログラムのソースコード

今回のプログラムは前回の記事に機能を追加したものです。読者の皆様が流用して1から使いやすいように、さらにキレイに作っています。

今回はJoy-Con左スティック入力にも対応したので、このソースコードを全文コピペして、loop()の中身だけ好みのものに変更すれば、オリジナルのマクロコントローラーとしても使うことができると思います。興味があればチャレンジしてみてください。

 

/* 
 *  トーナメント自動周回
*/

/* マクロコンのコマンドをソースコード化するための雛形【Newバージョン】

loop(){」のすぐ下に繰り返したいコマンドを書いていくだけで、
Arduino Leonardo用のソースコードができあがる簡単設計。

書き方としては1行ずつ↓を書いていく。
・ボタン入力:「PushKey("入力キー", 長押しミリ秒, 待機ミリ秒 ); 」または
・スティック:「TiltLeftStick(真上を基準に傾ける角度(0-360),傾きの強さ(0.0-1.0),長押しミリ秒, 待機ミリ秒)」
 ※スティック入力に関しては、長押しミリ秒を「0」にすると傾けっぱなしになります。

たとえば、「Aボタンを1.5秒間押してその後3秒待機する」場合には、
  PushKey( "A" , 1500 , 3000 );
と書けばオーケー。
たとえば、「スティックを3秒間右に傾けてその後2秒待機する」場合には、
  TiltLeftStick(90, 1.0, 3000, 2000);
と書けばオーケー。

なお、プログラムはすべて「半角英数字」で書くこと!

ちなみに「//」の右側の文字はプログラム上で無視されるので開発用コメントを残せる。
*/
#include <SwitchControlLibrary.h>

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

void PushRL(int delay_time_ms);
int PushKey(char* keyname, int holdtime, int delaytime);
void TiltLeftStick(int direction_deg, double power, int holdtime, int delaytime);

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

void loop() {
  // ↓ここに繰り返すコマンド列を入れよう
  TiltLeftStick(17, 1.0, 0, 0); // 17度の方向・強さMAX・傾けっぱなし・待機時間0
  PushKey("A",    HOLDTIME, 150); // A HOLTIMEミリ秒長押し 0.15秒待機
  PushKey("A",    HOLDTIME, 150); // A HOLTIMEミリ秒長押し 0.15秒待機
  PushKey("A",    HOLDTIME, 150); // A HOLTIMEミリ秒長押し 0.15秒待機
  PushKey("A",    HOLDTIME, 150); // A HOLTIMEミリ秒長押し 0.15秒待機
  PushKey("A",    HOLDTIME, 150); // A HOLTIMEミリ秒長押し 0.15秒待機
  PushKey("A",    HOLDTIME, 150); // A HOLTIMEミリ秒長押し 0.15秒待機
  PushKey("A",    HOLDTIME, 150); // A HOLTIMEミリ秒長押し 0.15秒待機
  PushKey("A",    HOLDTIME, 150); // A HOLTIMEミリ秒長押し 0.15秒待機
  PushKey("A",    HOLDTIME, 150); // A HOLTIMEミリ秒長押し 0.15秒待機
  PushKey("B",    HOLDTIME, 150); // B HOLTIMEミリ秒長押し 0.15秒待機

  // ↑ここに繰り返すコマンド列を入れよう
}

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 TiltLeftStick(int direction_deg, double power, int holdtime, int delaytime){
  double rad = (double)direction_deg*PI/180.0; // 弧度法(ラジアン)変換
  int x, y;
  x = (double)128*sin(rad)*power;
  y = (double)-128*cos(rad)*power;
  x += 128; y += 128;
  if(x >= 255) x=255; if(x <= 0) x=0;
  if(y >= 255) y=255; if(y <= 0) y=0;

  SwitchControlLibrary().MoveLeftStick(x,y);
  if(holdtime> 0){ // holdtime=0のときは押しっぱなし。
    delay(holdtime);
    SwitchControlLibrary().MoveLeftStick(128,128); // 傾きを直す
  }
  if(delaytime>0) delay(delaytime);
  return;
}

 

f:id:tangential_star:20201213004416g:plain
f:id:tangential_star:20201213112920p:plain
自動周回ではまれにガンテツボールや「かえんだま」「どくどくだま」が入手できる

 

あとがき

今回もマクロ対応コントローラーの代替としてプログラムを実装・紹介しました。新たにスティック入力に対応できるようになったことで、Arduino Leonardoがまさにマクロ対応コントローラーの「完全代替」に一歩近づいたかな、と感じています。

思えば、私が今年2020年の2月にArduinoを買ったきっかけになったのが、まさにトーナメントの自動周回でコントローラーのスティック入力がうまく固定できなかったから、だったのですよね。せっかくデジタルに入力制御ができるマクロ対応コントローラーなのに、肝心の入力がアナログだという矛盾をはらんでいて、個人的に矛盾だらけだなぁと思ったものです。

ゲーム中でも、スティック入力操作を使う動作は沢山ありますし、剣盾なら「カレーづくり」や「マホミルの進化(リザードンポーズ)」、なによりも「町中の移動」や「タマゴ孵化」などでしょうか。今回の雛形を使えば、これらの自動化もおいおい実装できるようになるかもしれませんね。

 

なにはともあれ、皆様のポケモン自動化ライフが豊かになることを願っています。

 

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

 

前回記事:

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

次の記事:

【Arduino自動化08】バトルタワー自動周回【BP稼ぎ】 

導入記事:

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

 

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

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

今回は、「ダイマックスアドベンチャー」を自動周回し、完全放置で「マックスこうせき」を集めるArduino Leonardo自動化の記事です。

さらに、ソースコードの簡単な解説も紹介しますので、これを読むとArduino Leonardoを使った自動化ツール(ちょっとしたマクロ対応コントローラーの代わり)を自力で作れるようになるかもしれません。Arduinoを使った剣盾自動化プログラミングに興味のある方の一助になればと思います。

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

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

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

 

2021年5月4日追記:Switch・剣盾を2台お持ちの方であれば、デリバードのレイドバトルを周回することで「マックスこうせき」をより効率的に回収できます。もしよければ、そちらもご参考ください。
【Arduino自動化18】ローカルレイド自動配布

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

2021年10月10日追記:Switch・剣盾を2台お持ちの方に向けて、「完全自動」でデリバードのレイドバトルを周回できるプログラムを開発しました!Arduinoも2台必要ですが、その分パワフルな自動化です。
【Arduino自動化20】Switch2台で「完全」自動!レイドバトル自動周回【デリバード・色違いレイドなど】

 

概要

本記事では、「ダイマックスアドベンチャー(エンドレスモード)」の自動周回を実装します。

f:id:tangential_star:20201205223049p:plain
f:id:tangential_star:20201205222733g:plain
ダイマックスアドベンチャーを自動周回。完全放置で1週20分ほど。

今回の目次です。今回はプログラムの書き方も交えますが、説明はいい、早く寄越せという方はどうぞ。 ⇒ 読み飛ばす

 

作ったきっかけ

実は、今回の記事で紹介するプログラムの流れ自体は、私が考案したものではありません。Twitterのタイムラインを眺めていたところ、あずき(@Azukiss_poke)氏によるマクロ対応コントローラーを使った自動周回方法のツイート(下記)が流れてきて、これをArduinoで実装するか、と思い至った次第です。要するにArduino Leonardoがあればマクロコンの代わりになる」というわけですね(暴論)。 

 

この記事のスタンス

本記事で扱う内容は、「決められたコマンド入力」が分かっているものをArduino Leonardoで動く自動化プログラムを作った、というものです。今までのものと異なり、決められたコマンドがあったので、それをプログラムに書き起こしやすいようにソースコード化しました。

ゆえに、もし本記事を読んでいる皆様のほうで「入力したいキーの順番があらかじめ決まっている」のであれば、それを基にプログラムを自分で書ける雛形としてご利用いただけるかもしれません(他のサイトで紹介されているマクロコントローラーの自動化コマンドなど)。

 

Arduinoでの自動化にチャレンジ

今回は、あずき氏が下記ブログで紹介している「ダイマックスアドベンチャーエンドレスモードの自動周回方法」をArduino Leonardoで使えるプログラムに書き起こしていきます。出来上がったプログラムは後述します。 ⇒ソースコード

 

azukiss.hatenablog.com

 

自動周回のコマンド入力列(引用)

1 2 3 4 5 6 7 8
4s
9 10 11 12 13 14 15 16
3s B(1.5s)

※指定が無い部分のキー入力間隔は約2秒

 

上表はこのブログから引用したコマンド入力列ですが、要するに、この16コマンドをひたすら繰り返すことで、ダイマックスアドベンチャー(エンドレスモード)を延々と攻略してくれるということです。

なので、早速、これらのコマンド入力部分のみをプログラムにしてみます。

こちらは説明用に抜粋したプログラムの一部です。完成版プログラムは こちら からどうぞ。

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

void
loop() { // ↓ここに繰り返すコマンド列を入れよう PushKey("down", HOLDTIME, 2000); // 1 ↓ 2秒待機 PushKey("A", HOLDTIME, 2000); // 2 A 2秒待機 PushKey("A", HOLDTIME, 2000); // 3 A 2秒待機 PushKey("A", HOLDTIME, 2000); // 4 A 2秒待機 PushKey("A", HOLDTIME, 2000); // 5 A 2秒待機 PushKey("A", HOLDTIME, 4000); // 6 A 4秒待機 PushKey("down", HOLDTIME, 2000); // 7 ↓ 2秒待機 PushKey("A", HOLDTIME, 2000); // 8 A 2秒待機 PushKey("down", HOLDTIME, 2000); // 9 ↓ 2秒待機 PushKey("A", HOLDTIME, 2000); // 10 A 2秒待機 PushKey("A", HOLDTIME, 2000); // 11 A 2秒待機 PushKey("down", HOLDTIME, 2000); // 12 ↓ 2秒待機 PushKey("A", HOLDTIME, 2000); // 13 A 2秒待機 PushKey("A", HOLDTIME, 2000); // 14 A 2秒待機 PushKey("B", HOLDTIME, 3000); // 15 B 3秒待機  PushKey("B", 1500 , 2000); // 16 B【1.5秒長押し】2秒待機  // ↑ここに繰り返すコマンド列を入れよう }

このように、「void loop(){」と、これに対応する閉じカッコ「}」の間に、延々と繰り返す入力内容を挟むだけでArduinoのソースコードは完成します。

 

なお、今回のプログラムではキー入力を「PushKey();」という関数で実装します。細かいプログラムの仕様の話などをしてもしょうがないので割愛しますが、よくわからない人は「どのキーが何秒間押されて、その後何秒間やすむのか」をひたすら並べるとプログラムになる、とだけご理解いただければOKです。

今回は、ひたすら「押す」⇒「待つ」を16コマンド分繰り返すだけなので、プログラムの書き換える部分も16行で済みます。簡単ですね。

なお、書き換える部分ですが、1コマンドごとに「PushKey」を並べるだけです。

  PushKey("A", HOLDTIME, 2000); 

上記「PushKey("A", HOLDTIME, 2000);」の中で、「"A"」と書いている部分=どのキーを押すか、その次=何秒間押し続けるか、最後=キーを離した後に何秒間待つかをそれぞれ表しています。なお、「HOLDTIME」は95に設定しているので「95ミリ秒(=0.095秒)長押し」、すなわち普通にAボタンをポチッと押した後に2秒間待つ、というコマンドになっています。

この要領でプログラムを完成させていきます。全文は後述します。⇒ソースコード

 

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

基本的にあずき氏のブログ記事に載っている通りですが、軽くこちらでも掲載します。

まず、Switchの本体を「機内モード」にします。そして、どうぐの「ボール」欄の一番上には「いらないボールを大量に準備」してください。あとは、ダイマックスアドベンチャー(エンドレスモード)を取り仕切るおっさんの目の前に立ったらArduinoを差し込むだけです。

f:id:tangential_star:20201205223106p:plain
f:id:tangential_star:20201205223058p:plain
「ボール」の先頭はいらないものを大量に準備し、本体を「機内モード」にしておく

なお、挑戦の前後には強制的にレポートが書かれてしまうので、貴重なボールが消費されてしまうなどのリスクがあることを理解した上で、使用しましょう。

 

ソースコード

今回のプログラムはかなりシンプルです。また、読者の皆様が流用して1から使いやすいように、今までの記事よりもきれいめに作っています。

今回のソースコードを全文コピペして、loop()の中身のコマンドを好みのものに変更することで、皆様好みのマクロコントローラーとしても使うことができると思います。興味があればチャレンジしてみてください。

2020/12/13追記:スティック入力にも対応したプログラムを作りました。合わせてご参考いただけます⇒【Arduino自動化07】トーナメント自動周回【マクロコン代替】

/* マクロコンのコマンド列をソースコード化するための雛形

loop(){」のすぐ下に繰り返したいコマンドを書いていくだけで、
Arduino Leonardo用のソースコードができあがる簡単設計です。
1行ずつ「PushKey("入力キー", 長押しミリ秒, 待機ミリ秒 ); 」を書いてください。

たとえば、「Aボタンを1.5秒間押してその後3秒待機する」場合には、
  PushKey( "A" , 1500 , 3000 );
と書けばオーケーです。
使えるのは "A", "B", "X", "Y", "ZR, "ZL", "R", "L", "+", "-", "Home" 
  "Up", "Down", "Right", "Left" の15キーです。同時押しはできません。
 
なお、プログラムは「半角英数字」で書きましょう(全角はスペース含め絶対NGです)。
*/ #include <SwitchControlLibrary.h> #define HOLDTIME (95) // 1回のキー入力の長押し時間 void PushRL(int delay_time_ms); int PushKey(char* keyname, int holdtime, int delaytime); void setup() { // コントローラーとして認識されるためにRLを7回ほどカチャカチャする for(int i=0;i<7;i++)PushRL(300); delay(1000); } void loop() { // ↓ここに繰り返すコマンド列を入れよう PushKey("down", HOLDTIME, 2000); // 1 ↓ 2秒待機 PushKey("A", HOLDTIME, 2000); // 2 A 2秒待機 PushKey("A", HOLDTIME, 2000); // 3 A 2秒待機 PushKey("A", HOLDTIME, 2000); // 4 A 2秒待機 PushKey("A", HOLDTIME, 2000); // 5 A 2秒待機 PushKey("A", HOLDTIME, 4000); // 6 A 4秒待機 PushKey("down", HOLDTIME, 2000); // 7 ↓ 2秒待機 PushKey("A", HOLDTIME, 2000); // 8 A 2秒待機 PushKey("down", HOLDTIME, 2000); // 9 ↓ 2秒待機 PushKey("A", HOLDTIME, 2000); // 10 A 2秒待機 PushKey("A", HOLDTIME, 2000); // 11 A 2秒待機 PushKey("down", HOLDTIME, 2000); // 12 ↓ 2秒待機 PushKey("A", HOLDTIME, 2000); // 13 A 2秒待機 PushKey("A", HOLDTIME, 2000); // 14 A 2秒待機 PushKey("B", HOLDTIME, 3000); // 15 B 3秒待機  PushKey("B", 1500 , 2000); // 16 B【1.5秒長押し】2秒待機  // ↑ここに繰り返すコマンド列を入れよう } 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); SwitchControlLibrary().ReleaseButtonA(); delay(delaytime); break; case 'B': case 'b': // B SwitchControlLibrary().PressButtonB(); delay(holdtime); SwitchControlLibrary().ReleaseButtonB(); delay(delaytime); break; case 'X': case 'x': // X SwitchControlLibrary().PressButtonX(); delay(holdtime); SwitchControlLibrary().ReleaseButtonX(); delay(delaytime); break; case 'Y': case 'y': // Y SwitchControlLibrary().PressButtonY(); delay(holdtime); SwitchControlLibrary().ReleaseButtonY(); delay(delaytime); break; case 'L': case 'l': // L SwitchControlLibrary().PressButtonL(); delay(holdtime); SwitchControlLibrary().ReleaseButtonL(); delay(delaytime); break; case 'R': case 'r': // R SwitchControlLibrary().PressButtonR(); delay(holdtime); SwitchControlLibrary().ReleaseButtonR(); delay(delaytime); break; case 'H': case 'h': // Home SwitchControlLibrary().PressButtonHome(); delay(holdtime); SwitchControlLibrary().ReleaseButtonHome(); delay(delaytime); break; case '+': case 'p': case 'P': // Plus SwitchControlLibrary().PressButtonPlus(); delay(holdtime); SwitchControlLibrary().ReleaseButtonPlus(); delay(delaytime); break; case '-': case 'm': case 'M': // Minus SwitchControlLibrary().PressButtonMinus(); delay(holdtime); 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); SwitchControlLibrary().ReleaseButtonZR(); delay(delaytime); } if(keyname[1]=='L'||keyname[1]=='l'){ SwitchControlLibrary().PressButtonZL(); delay(holdtime); SwitchControlLibrary().ReleaseButtonZL(); delay(delaytime); } break; case 'r': case 'R': // right SwitchControlLibrary().MoveHat(2); delay(holdtime); SwitchControlLibrary().MoveHat(8); delay(delaytime); break; case 'l': case 'L': // left SwitchControlLibrary().MoveHat(6); delay(holdtime); SwitchControlLibrary().MoveHat(8); delay(delaytime); break; case 'u': case 'U': // up SwitchControlLibrary().MoveHat(0); delay(holdtime); SwitchControlLibrary().MoveHat(8); delay(delaytime); break; case 'd': case 'D': // down SwitchControlLibrary().MoveHat(4); delay(holdtime); SwitchControlLibrary().MoveHat(8); delay(delaytime); break; case 'H': case 'h': // Home SwitchControlLibrary().PressButtonHome(); delay(holdtime); SwitchControlLibrary().ReleaseButtonHome(); delay(delaytime); default: break; } }else{ return -1; } strlen(keyname); }

 

f:id:tangential_star:20201205222733g:plain
f:id:tangential_star:20201205223042p:plain
自動周回で手に入れた「マックスこうせき」で「とくせいパッチ」を手に入れよう

 

あとがき

今回は、マクロコントローラーで自動化されていたものをArduino Leonardoで置き換えたらどのように実装されるかにフォーカスして紹介しました。

自明かとは思いますが、Arduinoによるポケモン剣盾自動化プログラムはとどのつまりマクロ対応コントローラーによるコマンド入力自動化と実質なんら変わりありません。むしろ、キー入力配列の上限にかなり余裕があり、柔軟な入力制御にも対応できる分だけArduinoはマクロ対応コントローラーよりも高機能とも言えるかもしれませんね。

要するに、マクロ対応コントローラーにせよArduinoにせよ、人が入力しているコマンドをプログラムに置き換える手段ですので、自分の工夫次第でいかようにでも動かすことができるのがプログラミングの醍醐味だと思います。

 

今までプログラミングをしてこなかった方も、もしこの記事を読んで「自動化にチャレンジしてみたい」と少しでも思えたのであれば幸いです。また、今までマクロ対応コントローラーを利用してきた方のうち、「マクロの中にHomeボタンが割り当てられない」という経験をされた方には、ぜひともArduinoでの自動化にもチャレンジしてみて欲しいと思います。

皆様のポケモン自動化ライフがより豊かになることを祈っています。

 

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

 

2020/12/13追記:スティック入力にも対応したプログラムを作りました。
是非合わせて御覧ください⇒ 【Arduino自動化07】トーナメント自動周回【マクロコン代替】
 

前記事:

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

導入記事:

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

 

【速報】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開発環境の導入