クリスマスイブなのでペラップにWe Wish a Merry Christmasを歌ってもらった

Pokémon RNG Advent Calendar 2017 24日目の記事です。

ペラップ演奏会をしました。忙しい人はラスト30秒を見てください。

先人はこちら:

使ったseedとか (第5世代はMACアドレスによってseedが変わるので他の人は使えないが)

周波数=400Hz
seed=0x1612c3c5, iseed=610a0397, f=30
A4, A4, A4, B4flat, A4
  • ホワイト DSi(00-22-aa-38-54-68)
周波数=325Hz
2081/05/24 22:13:59 key=40(↑)
iseed=5c1d2d0cd37c0907 seed=37deba833913e966 f=97 (46)
F4, F4, G4, F4, E4, G4, G4, G4, F4, E4, G4, F4, G4, E4, F4
  • ブラック DS Lite (00-21-47-72-91-b3)
周波数=255Hz
2056/06/25 17:37:21 key=00
iseed=b1b95766f2f478a9 seed=627ba589ac411cb1 f=72 (24)
C4, D4, D4, D4, C4, C4, D4, C4, C4, D4

seed検索のソースコードは以下。おだんぽよさんのPokeRNGを利用しています。

#include <iostream>
#include <cstdio>
#include <cstdint>
#include <ctime>
#include <vector>
#include "PokeRNG/Calc5GenSeed.hpp"
#include "PokeRNG/CalcOffset.hpp"

using namespace std;

typedef uint32_t u32;
typedef uint64_t u64;
typedef int64_t s64;

struct AbstractRNG {
    virtual int rand(int n) = 0;
};

struct LCG64bit : AbstractRNG {
    u64 seed;

    LCG64bit(u64 s) : seed(s) {}

    int rand(int n) {
        seed = seed * 0x5D588B656C078965 + 0x269EC3;
        return (seed >> 32) * n >> 32;
    }
};

struct LCG32bit : AbstractRNG {
    u32 seed;

    LCG32bit(u32 s) : seed(s) {}

    int rand(int n) {
        seed = seed * 0x41c64e6d + 0x6073;
        return (seed >> 16) % n;
    }
};

bool valid_seed(AbstractRNG &rng, double baseFreq, vector<double> expectedFreqs, double allowRatio = 1.015) {
    for (double expected : expectedFreqs) {
        double got = ((rng.rand(8192)) / 8192.0 * 0.25 + 1) * baseFreq;
        double ratio;
        if (expected < got) {
                ratio = got / expected;
        } else {
            ratio = expected / got;
        }
        if (ratio >= allowRatio) {
            return false;
        }
    }
    return true;
}


u32 prev_seed(u32 seed) {
    return seed * 0xEEB9EB65 + 0x0A3561A1;
}

bool good_seed(u32 seed) {
    int i;
    for (i = 0; i < 10; i ++) seed = prev_seed(seed);
    for (; i < 40; i ++) {
        u32 upper = seed >> 24;
        u32 hour = (seed >> 16) & 0xff;
        u32 frame = seed & 0xffff;
        u32 second = (frame - 17) / 60 + 10;
        if (12 * 24 + second - 256 <= upper && upper <= 12 * 24 + second + 60 - 256
            && hour < 24 && 0x0270 <= frame && frame <= 0x0400) {
            return true;
        }
        seed = prev_seed(seed);
    }
    return false;
}

constexpr double C4 = 261.626;
constexpr double D4 = 293.665;
constexpr double E4 = 329.628;
constexpr double F4 = 349.228;
constexpr double G4 = 391.995;
constexpr double A4 = 440.000;
constexpr double B4flat = 466.164;

// 中音 (ホワイト1 + DSi)
int main1() {
    vector<double> expected = { F4, F4, G4, F4, E4, G4, G4, G4, F4, E4, G4, F4, G4, E4, F4 };
    double base = 325;

#pragma omp parallel for
    for (long i = 946652400; i < 4102412400; i ++) {
        PokeRNG::Parameters5Gen<PokeRNG::ROMType::W1JaDSi> param;
        PokeRNG::Calc5GenSeed calc_seed;
        PokeRNG::CalcOffset calc_offset;
        param.set_mac_addr(0x00, 0x22, 0xaa, 0x38, 0x54, 0x68);
        param.set_timer0(0x1233);
        time_t time = i;
        struct tm date;
        localtime_r(&time, &date);
        param.set_year(date.tm_year + 1900 - 2000);
        param.set_month(date.tm_mon + 1);
        param.set_day(date.tm_mday);
        param.set_hour(date.tm_hour);
        param.set_minute(date.tm_min);
        param.set_second(date.tm_sec);
        for (int key = 0; key < 0x100; key ++) {
            if ((key & 0x30) == 0x30 || (key & 0xc0) == 0xc0) continue;

            param.set_key(0x2fff ^ key);
            PokeRNG::u64 seed = calc_seed(param);
            calc_offset.bw1(seed, true, true);
            LCG64bit lcg(calc_offset.get_seed());
            int ofs = (int)calc_offset.get_offset();
            for (int i = 0; i < 100; i ++) {
                LCG64bit l = lcg;
                if (valid_seed(l, base, expected, 1.02))
#pragma omp critical
                {
                    printf("%04d/%02d/%02d %02d:%02d:%02d ", date.tm_year + 1900, date.tm_mon + 1, date.tm_mday, date.tm_hour, date.tm_min, date.tm_sec);
                    printf("key=%02x seed=%016lx %016lx f=%d (%d)\n", key, seed, lcg.seed, ofs + i, i);
                }
                lcg.rand(1);
            }
        }
    }

    return 0;
}

// 低音 (ブラック1 + DSLite)
int main2() {
    vector<double> expected = { C4, D4, D4, D4, C4, C4, D4, C4, C4, D4 };
    double base = 255;

#pragma omp parallel for
    for (long i = 946652400; i < 4102412400; i ++) {
        PokeRNG::Parameters5Gen<PokeRNG::ROMType::B1Ja> param;
        PokeRNG::Calc5GenSeed calc_seed;
        PokeRNG::CalcOffset calc_offset;
        param.set_mac_addr(0x00, 0x21, 0x47, 0x72, 0x91, 0xb3);
        time_t time = i;
        struct tm date;
        localtime_r(&time, &date);
        param.set_year(date.tm_year + 1900 - 2000);
        param.set_month(date.tm_mon + 1);
        param.set_day(date.tm_mday);
        param.set_hour(date.tm_hour);
        param.set_minute(date.tm_min);
        param.set_second(date.tm_sec);
        int key = 0;
        param.set_key(0x2fff ^ key);
        PokeRNG::u64 seed = calc_seed(param);
        calc_offset.bw1(seed, true, true);
        LCG64bit lcg(calc_offset.get_seed());
        int ofs = (int)calc_offset.get_offset();
        for (int i = 0; i < 30; i ++) {
            LCG64bit l = lcg;
            if (valid_seed(l, base, expected, 1.015))
#pragma omp critical
            {
                printf("%04d/%02d/%02d %02d:%02d:%02d ", date.tm_year + 1900, date.tm_mon + 1, date.tm_mday, date.tm_hour, date.tm_min, date.tm_sec);
                printf("key=%02x seed=%016lx %016lx f=%d (%d)\n", key, seed, lcg.seed, ofs + i, i);
            }
            lcg.rand(1);
        }
    }

    return 0;
}

// 高音 (Pt)
int main3() {
    vector<double> expected = { A4, A4, A4, B4flat, A4 };
    double base = 400;

#pragma omp parallel for
    for (s64 seed = 0; seed < 0x20000000; seed ++) {
        LCG32bit lcg(seed);
        if (valid_seed(lcg, base, expected, 1.008) && good_seed(seed)) {
#pragma omp critical
            printf("%08x\n", (u32)seed);
        }
    }

    return 0;
}

int main() {
    return main2();
}
筆者: oupo (連絡先: oupo.nejiki@gmail.com)