クリスマスイブなのでペラップにWe Wish a Merry Christmasを歌ってもらった
Pokémon RNG Advent Calendar 2017 24日目の記事です。
ペラップ演奏会をしました。忙しい人はラスト30秒を見てください。
先人はこちら:
使ったseedとか (第5世代はMACアドレスによってseedが変わるので他の人は使えないが)
- プラチナ DSLite
周波数=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(); }