【Arduino自動化13】全自動ポケモン逃がし

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

今回は、ボックスのポケモンを全自動で逃がし続ける自動化記事です。前回の全自動タマゴ受け取り&孵化とは対称的ですね。

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

 

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

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

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

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

 

概要

本記事では、ボックスのポケモンを自動で逃がすプログラムを紹介します。孵化厳選などで溢れたボックスを整理できます。

f:id:tangential_star:20210121234428g:plain
f:id:tangential_star:20210121233732p:plain
完全放置でボックスのポケモンを逃がせる。1ボックスあたり約2分半だ

 

目次です。プログラムまで読み飛ばす方は⇒コチラからどうぞ

 

 

「いちらん」を使って歯抜け状態のポケモンボックスを左詰めに

効率的に逃がすためにも、まずは余談でボックス整理方法から。

タマゴ孵化で色厳選をすると、どうしてもボックスが孵化したポケモンで溢れてしまいます。そんなとき、1匹1匹を手動で逃がすのはとても大変です。

そんな時こそ自動化プログラムの出番…と言いたいところですが、前提として、自動化プログラムは「ボックスが歯抜け状態だと使えない」という欠点があります。

孵化したポケモンの中で「高個体値」「理想個体」「色違い」のポケモンを残そうと別ボックスに移動させてしまうと、どうしてもボックスの中が歯抜け状態になります。つまり、いわゆる「自動ポケモン逃がし」プログラムが使えなくなってしまいます。そこで、手動でポケモンを整列させる必要がありますが、1匹ずつずらすのも大変です。

f:id:tangential_star:20210122001659p:plain
f:id:tangential_star:20210122001952g:plain
左写真のように「歯抜け」があると自動化できない。右写真のように整列させる必要がある

実は、ボックスの機能「いちらん」を使うことで、効率的にポケモンたちを左詰めにできます。具体的には、他のボックスから「はんい」モード(緑のカーソル状態)で「いちらん」を経由して移動させると、空いている箇所に左詰めに自動で挿入してくれます。もし、今まで1匹ずつずらしていた人には、目からウロコのテクニックです。

f:id:tangential_star:20210121235612g:plain

ボックスの「いちらん」機能を使えば、1匹ずつずらさなくてもポケモンを左詰めにできる

 

逃がすポケモンの数をプログラムに書き込み

自動化プログラムの使い方に話を移します。

まずは、逃がすポケモンの数をプログラムに書き込みます。具体的には、「NUM_RELEASE_POKEMON」で指定しますので、ここに数字を入力してください。

例えば、8ボックス埋まっている場合は「30*8」または「240」と入力すればOKです。もちろん、30の倍数以外にも対応できます。

// 何匹、逃がしますか?
#define NUM_RELEASE_POKEMON (30*8+21) 

f:id:tangential_star:20210122215552g:plain

この画像なら、ボックス10~17までの8ボックスと21匹なので「30*8+21」と書けばOK

なお、前述の通り、ボックスのポケモンは「歯抜け」が無い状態でかつ、左詰めに整列させておいてください。

これが終わったら、B連打でボックスを閉じ、メニューを閉じ、フィールド画面に戻ってください(メニュー画面でカーソル位置が「ポケモン」なら準備完了です)。 

f:id:tangential_star:20210122221406p:plain
f:id:tangential_star:20210122221839g:plain
Xボタンでポケモンにカーソルが合った状態なら、自動でボックスを開いて逃がしてくれる

 

ソースコード

ポケモンをボックスに左詰めで整列させておき、Xでポケモンにカーソルが合う状態で、Arduinoを挿すだけの簡単設計です。

/* 
 *  ボックスのポケモン全自動逃がし
 *  【ボックスは30匹左詰めで埋まっていること】
 *  Xボタンでメニュー開いた時に「ポケモン」にカーソルが合っていること
 *  
 *  (c) 2021 ますたーの忘備録
 *  https://tangential-star.hatenablog.jp/
*/
#include <SwitchControlLibrary.h>

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

// 何匹、逃がしますか?
#define NUM_RELEASE_POKEMON (30*8+21) 

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

// 現在、何匹逃したか
int current_poke = 0;

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

  current_poke = 0;

  // Xでメニュー画面を開く
  PushKey("X", HOLDTIME, 700);  // メニューを開き
  // ポケモンを開く
  PushKey("A", HOLDTIME, 1500); // ポケモンを開く
  PushKey("R", HOLDTIME, 1800); // ボックスへ
  
}


void loop() {

  if(current_poke >= NUM_RELEASE_POKEMON) for(;;); // 逃がす上限になったらプログラム終了

  PushKey("A", HOLDTIME, 350);  // ○○をどうする?
  PushKey("up", HOLDTIME, 250); // 
  PushKey("up", HOLDTIME, 250); // ⇒にがす
  PushKey("A", HOLDTIME, 800);  // 本当に逃がしますか?
  PushKey("up", HOLDTIME, 350); // ⇒はい
  PushKey("A", HOLDTIME, 1100);  // ○○を 逃がしてあげた ばいばい ○○
  PushKey("A", HOLDTIME, 300);  // ▼

  current_poke++; // 逃がしたポケモンの数をカウント


  if( current_poke %6 == 0 ){
    for(int i=0;i<5;i++)PushKey("left", HOLDTIME, 250); // 左にカーソルを戻し
    PushKey("down", HOLDTIME, 350); // 次のポケモンへ
  }else{
    PushKey("right", HOLDTIME, 350); // 次のポケモンへ
  }
  if( current_poke %30 == 0){
    PushKey("down", HOLDTIME, 350); // カーソルを左上に
    PushKey("down", HOLDTIME, 350); // もどして、
    PushKey("R", HOLDTIME, 800); // 30匹逃がし終わったら次のボックスへ
  }

}

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);
}

 

あとがき

前回(第12回)全自動タマゴ受け取り&孵化の記事ではタマゴを受け取っては孵すを繰り返していましたが、今回の記事では打って変わって、ひたすらポケモンを逃がす記事でした。

私は孵化厳選した際に余ったポケモンたちを逃がすのが本当にめんどくさく、いつもポケモンバンクポケモンHomeに預けるのを繰り返していました。ところが、これらにも容量が上限あることに最近気づいてしまい、止む無く「逃がす」ことの重要性に気づいたのです。また、前回実装したタマゴ自動孵化プログラムのおかげで、気分が乗らなくてもタマゴ孵化が捗ってしまい、気づいたらボックスが埋まってしまうということも多くなったため、現在は重宝しています。

 

こうやって自分の手で「作って」「使って」みると、「世の中にすでにある自動化」はニーズがあるんだなぁ、と真の意味で納得できるということに気づかされます。本ブログが、皆様の需要にも応えられるように、世の中のものもしっかりと調べて行こうかなと思った次第です。

個人的には、第9回のポケモンキャンプでカレー自動調理は非常に満足の行く出来だったのですが、本当にニーズがないのか本記事にはなかなかアクセスがありません(ちなみに、「ポケモン カレー 自動化」で調べると、まだまだ駆け出しの本ブログでは珍しく、検索上位にランクインします。よかったら見てね←)

 

話が逸れましたが、本記事ならびに本ブログが皆様のポケモン自動化ライフの一助となれば幸いです。引き続き応援のほど、よろしくお願いいたします。

 

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

 

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

前回記事:【Arduino自動化12】全自動タマゴ受け取り&孵化

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