【SV自動化02】マリナードタウン「競り」自動化【オシャボ・努力値下げきのみ】

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

今回はポケモンSVのマリナードタウンの「競り」自動化の記事です。オシャボや努力値下げきのみ、ハネ系アイテム、進化の石などの収集とにお役立てください。

ポケモンSV自動化の記事、第2弾となります。

 

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

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

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

 

概要

マリナードタウンの「競り」を自動で落札し続ける自動化です。お金が尽きるまで永遠に商品を購入し続けます。時々、ガンテツボールや「きんのおうかん」などのレアアイテムも取り扱われます。

落札価格は概ね20万~40万ほどですが、時には70万円を超えることもありますので、十分な資金力を持って臨みましょう。おすすめは、学校最強大会でのお金稼ぎとの併用です。

努力値下げきのみ・オシャボ・ハネ系アイテム・進化の石など、概ねポケモン育成に必要なものはここの競りで補うことができます。ちなみに、体感でだいたい18時間で9,999,999円を使い切ります。大豪遊ですね(笑)

マリナードタウンの「競り」はNPCとのオークション。十分なお金を持っておこう!
日付を変更してリセットすれば、次の商品を買える。ガンテツボールは競り落としたい!

時には70万円以上の値が付くことも。いざ落札してもお金が足りないんじゃ格好がつかない

もくじです。いつものように文章たっぷり!

個人的には「余談」は読んでほしい←

 

お金さえあれば確実にアイテムを入手できるが割高な「競り」

マリナードタウンの「競り」の魅力は、なんといってもそのラインナップでしょう。努力値下げきのみ・ガンテツボール・進化の石・きん/ぎんのおうかん・各種ドーピングアイテムなど、冒険のみならずクリア後にも役立つアイテムが目白押しです。パルデア地方で非売アイテムを集めるなら、テーブルシティの「学校最強大会」か、ここマリナードタウンの「競り」か、まさに2つに1つでしょう。

この「競り」は、NPCとオークション形式で購入希望価格を競り合い、落札希望価格が最も高い人がそのアイテムの購入権利を手に入れる、という仕様です。つまり、裏を返せば、お金さえ十分に持っていれば、どんなアイテムも競り落とすことができる、ということです。ただし、一部の商品はかなり割高なので、注意しましょう。

ガンテツボールやきんのおうかんも出品される。きんのおうかんは割高なのでスルー推奨だ
お金さえあれば、努力値下げきのみカンストやガンテツボール複数入手も夢じゃない

 

落札後にセーブ&Switchの日付を進めてリセットで、競りの商品が復活

マリナードタウンの競りは、「ガンテツボール」や「努力値下げきのみ」など魅力的なアイテムを多数取り揃えていますが、販売員が3人しかいないため、狙ったアイテムを大量入手をするのは非常に難しいです。

あまり知られていませんが、落札した後、最短で72分後(ゲーム内の時間で1日経過後の朝)には商品を再入荷してくれるのですが、リアルタイムで72分「起動し続けねばならない」点は、あまりに非効率と言わざるを得ません。

そこで、競りでの落札後にセーブをしてからSwitch本体の日付を1日進めてリセットすることで、元来、1時間以上かかっていた「購入~商品再入荷」までの一連を、わずか2分半で済ませることができます

落札後にセーブ&Switchの日付を進めてリセットで、競りの商品が復活する
落札→セーブ→日付変更→リセットを繰り返せば、何度でも競りに挑戦できるぞ

 

もう一度日付を変更すれば、競りの商品を入れ替えることができる

マリナードタウンの「競り」では前述の通り、ガンテツボールやハネ系アイテムなどの入手手段が限られるアイテムがラインナップされています。その一方で、カレーパウダーやポイントアップ、ぎんのおうかんなど、他にも恒常的な入手手段があるアイテムが出品されることもあります。

競りの特徴として、落札価格が、相場価格よりも釣り上がる(=アイテムの単価としてはかなり割高になる)ことがしばしば起こるため、ショップで購入できるアイテムは競りで購入しないことがコツになります。

そこで、購入したくない商品が出品された場合は、そのままゲーム終了→Switchの日付をもう一度進めることで、商品の厳選(再抽選)ができます

競りでは、予算や相場を超えたら諦める(日付変更してリセットする)のがコツだ
特に「ぎんのおうかん」はデリバードポーチで安く買えるので張り合う理由が無い

 

 

落札価格の相場(目安)は、初期価格の約3.5倍

マリナードタウンの競りでは、屋台の掛け声で最初に示された金額から、NPCを含むプレイヤーが金額を吊り上げていき、最終的に最も提示金額が高い人がその商品の購入権利を得る、という仕様です。

筆者が、7時間かけて163試行を集計・分析したところ、初期提示金額の3.5倍程度が落札価格の実績でした(163試行の算術平均として。163商品それぞれの落札価格の合計3,433,600円から、163商品の初期価格それぞれの合計974,600円を除して計算)。

落札価格はもとより、商品ごとの初期金額・個数もまちまちでしたが、下記アイテムは初期価格が定まっているようです。

【競りの初期価格の例】

  • ガンテツボール・ドリームボールなど:100,000円~
  • きんのおうかん(1個):50,000円~
  • ポイントマックス(3個):30,000円~
  • するどいツメ:5,000円~
  • われたポット・かけたポット:3,000円~
  • ひかりのいしやみのいしたいようのいし:1,500円~
  • メタルコート:1,000円~

前述の通り、初期価格の約3.5倍が落札相場ですから、例えば、ガンテツボールは概ね30万円~40万円ほどで落札できると予想できます。実際、筆者はドリームボールは36万円、ラブラブボールは22.5万円で落札しています。

ドリームボールの初期提示は10万円。このときの落札価格は36万円だった

ただし、時には大きく上振れることもあるため、極力、お金には余裕を持った状態で競りに臨みましょう。ちなみに、筆者が観測した最も大きな落札金額は720,000円でした。

 

人気商品(きんのおうかん・ぎんのおうかん・ポイントアップ)はスルー推奨

さて、競りの特性上、相場を大幅に上回る商品が出ることは前述の通りですが、中でもとりわけ「割高」「値上がり幅が常軌を逸する」商品(便宜的に、ここでは「人気商品」と呼びます)が出ることがあります。

筆者の7時間の検証では、「ポイントアップ」「ポイントマックス」「ぎんのおうかん」「きんのおうかん」の4つは、特に金額が高かったり、価格が釣り上がりやすい人気商品でしたこれらの商品は、可能ならスルーしたほうが財布に優しいです。とりわけ、NPCが入札前に「特殊セリフ」を吐いた場合は、要警戒です(50万円を超える印象です)。

なお、ぎんのおうかん・ポイントアップについてはそれぞれショップ(デリバードポーチ・ラッキーズ)で買えるので、そういう意味でもわざわざ競りで買い集める必要は一切ありません。

入札前に「おじさん がんばっちゃうぞ!」などの特殊なセリフを言うNPCには特に注意。
落札価格がとんでもなく釣り上がっていく。勝てない勝負は挑まないほうが賢明だ


プログラムの仕組み(アルゴリズム

さて、ここからは自動化の仕組みについてです。読み飛ばしOK。

上述の諸々を踏まえると、マリナードタウンの競りを自動化するためには

  • 十分なお金を持っておく(学校最強大会で十分に稼いでおく)
  • Switchの日付変更ができるように「時刻の自動設定」をOFFにしておく
  • 超高額になる人気商品は諦める

という前提で、

  1. 受付に話しかける
  2. A連打で落札する
  3. セーブする
  4. ホーム画面に戻ってSwitchの日付を進める
  5. ゲーム再起動

という手順でプログラムを書けば良いことになります。

今回は上記の「2. A連打で落札する」の部分を、75秒間のA連打に設定することにしました。これは、概ね「ガンテツボールは購入しつつ、高額なぎんのおうかん・きんのおうかんは購入しない」調整の意図です。十分に長くすれば、これらも購入することができますので、お好みとお使いの環境に応じて書き換えると良いかもしれません。

具体的にはソースコードの「A_TIME」のカッコの中の数字を書き換えてください。

#define A_TIME (75) // 何秒間競りに使うか。(A連打時間)

※75秒の意図は、本ページ下部の「【余談】落札価格は初期提示価格の2.7倍以上!」に載せています。

 

自動化の準備(十分なお金を持って受付の前でセーブするだけ)

自動化プログラムを動かす上で、必要な準備は、十分なお金を持って受付の前に立つだけです。シンプルですね。

筆者のおすすめは、左手前に1人でいるおじさんの方です。ハネ系アイテムや努力値下げきのみを取り扱ってくれるため、こだわりがなければこちらが正解でしょう。

準備としては十分なお金を持って、競りの受付のおじさんの前でセーブしてArduinoを挿すだけだ
このおじさんは、努力値下げきのみ・ハネ系アイテムを主に取り扱ってくれるぞ。

 

ソースコード

おまたせしました。ソースコードです。マリナードタウンの「競り」で商品を購入し続けるプログラムです。使い方は、3人いるいずれかの競りの受付の前でArduinoを差し込むだけです。

※Switch Liteをご利用の方は「#define SWITCH_VER (15)」を「#define SWITCH_VER (12)」に書き換えてご利用ください。ただし、筆者未検証です。

/*  ポケモンSV マリナードタウン自動競り
 *   
 *   店の人の前で買ってセーブして日付変更してリセットするだけのプログラム。
 *   【準備】
 *   ・受付の前で立つ。
 *   ・Switchの設定で、日付は自動設定にしないようにしておく
 *   ・十分な金を持っておく!!!
 *  *2022/12/17公開(2022/12/10作成)
 *  *2022/12/22修正:Lite(Ver12)でコンパイルできない問題を解消
 *  (c) 2022 ますたーの忘備録
 *  https://tangential-star.hatenablog.jp/
*/

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


#define A_TIME (75) // 何秒間競りに使うか。(A連打時間)
#define B_TIME (3)  // 会話キャンセル用・競りキャンセル用(B連打時間)

int PushKey(char* keyname, int holdtime, int delaytime);
void Hit_Button_repeatedly(char *keyname, unsigned long int while_sec);
void Save_for_SV(void);
void AuctionReset_in_PortoMarinada(void);


void setup() {
  for(int i=0;i<7;i++)PushKey("R", HOLDTIME, 300);
  delay(1000);
}

void loop() {
  // 1.受付に話して購入するまでA連打
  Hit_Button_repeatedly("A", A_TIME);
  // 2.会話キャンセルB数回
  Hit_Button_repeatedly("B", B_TIME);
  // 3.セーブ
  Save_for_SV();
  // 4.日付変更&リセット
  AuctionReset_in_PortoMarinada();
}

void Save_for_SV(void){
  // ポケモンSV用のセーブ。汎用。
  PushKey("X", HOLDTIME, 1200); // メニューを開く
  PushKey("R", HOLDTIME, 1000); // Rでセーブ(ここまでの 冒険を レポートに 記録しますか?)→はい
  PushKey("A", HOLDTIME, 3200); // ますたーは レポートに しっかり 書き残した! ▼
  PushKey("B", HOLDTIME, 1200); // ダイアログを閉じる
  PushKey("B", HOLDTIME, 1500); // メニューを閉じる
  return;  
}

void AuctionReset_in_PortoMarinada(void){
  // 日付変更→ホーム画面のままゲーム終了、再起動

  
  // Homeボタンを押して設定の画面へ移動
  PushKey("Home", HOLDTIME, 1000);

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

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

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

  PushKey("A", HOLDTIME, 500);

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

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


  // ホーム画面のままゲーム終了
  PushKey("X", HOLDTIME, 500);     // 終了Xを押す→終了しますか?画面
  PushKey("A", HOLDTIME, 4000);    // はい→終了しています・・・
  PushKey("A", HOLDTIME, 1200);    // ゲームタイトルクリック→ユーザを選んでください画面(複数ユーザいる場合)
  PushKey("A", HOLDTIME, 24000);   // A押してから起動までおおよそ15秒(最短目安。環境に合わせて設定すること)
  PushKey("A", HOLDTIME, 23500);   // タイトル画面からフィールド遷移までおおよそ21秒(環境に合わせて設定すること)

  return;
}


void Hit_Button_repeatedly(char *keyname, unsigned long int while_sec){
  // 指定秒数だけボタンを連打(0.3秒間隔)する関数。
  // 第1引数:連打したいボタン名(例:"A")
  // 第2引数:連打したい時間[秒](例:20)
  // 返り値:なし
  unsigned long int current_time=0;
  unsigned long int start_time=0;
  unsigned long int temp_time=0;

  // 200万秒を超える時間を連打することはまずないと思うけど。オーバーフローには気をつけよう。
  if( while_sec > 2147483){
    Hit_Button_repeatedly(keyname, while_sec - 2147483); // 万が一オーバーフローしそうなときは再帰的に対応。
    while_sec = 2147483; // 残りのオーバーフロー分を下記で対応
  }

  for( start_time=millis(), current_time=start_time ; current_time - start_time < (unsigned long)while_sec*1000UL ; current_time=millis() ){
    if( current_time - start_time < (unsigned long)while_sec*1000UL )PushKey(keyname, HOLDTIME, 300); // ひたすら連打
  }
  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);
}

 

【余談】落札価格は初期提示価格の2.7倍以上!

それにしても、マリナードタウンの競りは、意外と「割高」な商品が多いですね。

実は、検証用に、ひたすら落札する様子を累計21時間の録画データで残しており、うち7時間分だけを目視による集計と、手動での表計算で分析したのですが、興味深い事実が判明しました。

実は、「食材」「きのみ」「オシャボ」など6つのカテゴリに分けて、出品される比率(頻度)と、出品されたときの値動きを分析してみましたが、いずれのカテゴリも平均すると、初期提示価格(出品は●●円から!という掛け声の金額)から、2.7倍以上もの金額で落札していたことでした。

競りで出品されるアイテムの比率と、金額の推移を分析。
オシャボ・ドーピングアイテムは、初期提示価格から4倍近い価格まで値上がりすることが分かる
※注:163試行は「75秒カット」込みでの実績です。おうかん・ドーピング類の値上がり幅は、実質的に表より高いことに留意ください

オークションはその性質上、「相場よりも安く買えるか」という部分でチキンレース的に値段を釣り上げていき、ある上限に向けて参加者同士で競り上げていくものです。

例えば、今作ポケモンSVでは「ぎんのおうかん」をデリバードポーチというお店で「20,000円」で購入することができます。…ということは、例えば「ぎんのおうかん10個セット」の適正な相場は「200,000円」であり、通常のオークションであれば、この200,000円を下回るように、入札の(暗黙上の)抑止原則が働きます。

しかし、マリナードタウンの”競り”においては、上述の表の通り3倍近い値動きを見せるものの、初期価格がべらぼうに高い(100,000円スタート)ため、大幅に適正な価格をオーバーすることが容易に想像できます。マリナードタウンの競りの参加者はNPCであり、その”抑止原則”が働かないため、このミスマッチが発生します。

すなわち、マリナードタウンの競りを攻略する上では、「如何に割高な商品への入札を見送り、如何に珍しいアイテムを購入するか」という、ある種、趣向が異なるというゲーム性を理解する必要があります。

75秒A連打の理由

今回の自動化では、あえて「75秒」のA連打という戦略を取りました。

前述の通り、通常のマネーゲームを行う場合は「落札相場を考えてから入札するか否か」という戦略を取るのに対し、今回は「適正価格とは言わずとも、安く買えるものや、値上がり幅が少ない商品については、比較的お得に購入できる」という特性をもつため、「ドーピングアイテム」以外を購入することが最善と判断できるからです。

ドーピングアイテムは、先の表にも記載の通り「400%」近い値上がりをする商品です。値上がり幅が大きいということは、NPCとの入札回数が増える=時間がかかるということです。

この75秒という絶妙な時間に設定することで、ドーピングアイテムの入札中にゲームをリセットしてしまうという力技ですが、不適正な高額商品の購入を避けることができます。

(再掲)入札に長い時間かかるということは、その分値段が釣り上がっているということ。
つまり、75秒経過時点で競りが終わっていなければ、その商品は不適正な価格であると言える

このように、自動化をする上での”創意工夫”ができるところが、プログラマブルマイコンボードの良さであり、試行錯誤ができるポイントだと考えます。
したがって、この文章を読んでいて、上記のプログラムをご利用される皆様が、もっと良い戦略を思いつけばそれは素敵なことですし、そういう意味でも、ソースコードも編集しやすいようにA_TIMEというdefineマクロを準備しております。

プログラムの書き方、というより、攻略する上での楽しさを理解してもらえれば嬉しく思います。

 

あとがき

いやーー、お久しぶりですっ!そして、このポケモンSVから「ますたーの忘備録」を知った皆様にとっても有益な記事であれば嬉しいです。

それにしても、ポケモンSVの発売日が2022年11月18日で今日は12月17日ですから、もうポケモンSVが発売されてからもう1ヶ月が経つんですね。とても早く感じます。

 

さて、ポケモンSV自動化の第2弾として、今回はマリナードタウンの競りを自動化しました。前回第1回では「学校最強大会の攻略(金策)」でしたから、第2弾としてお金の使いどころを自動化できて良かったと思います。

これにより、お金稼ぎ→アイテム周回→…を永遠と繰り返していけば、アイテムで困ることもなくなりますね。

努力値下げきのみのカンストは、精神衛生的にもありがたい。オシャボも嬉しい。

さて、ポケモンSV発売から1ヶ月が経つのに、仕事がとにかく繁忙で、まだ図鑑がまったく埋まっていないどころか、準伝説ポケモンの姿すらみたことが無いという現状なので、また時間を見つけて遊びたいと思います。

もちろん、本ブログもマイペースに続けていけたらと考えますので、引き続きよろしくお願いします

 

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

 

--

本ブログについて:本ブログについて

 

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

ポケモンSVの記事:スカーレットバイオレットArduino自動化 カテゴリーの記事一覧

ポケモン剣盾の記事:ポケモン剣盾Arduino自動化 カテゴリーの記事一覧

ポケモンBDSPの記事:ダイパリメイクArduino自動化 カテゴリーの記事一覧

レジェンズアルセウスの記事:レジェンズアルセウスArduino自動化 カテゴリーの記事一覧

 

YouTubeチャンネル:ますたーの忘備録 - YouTube