ポケポケとは
ポケモンカードというTCGを原作として、ルールなどがスマホ向けに大幅に変えられたスマホゲーム。
(正式名称: Pokémon Trading Card Game Pocket)
暇なときにやるけど、ランクマッチが全然勝てない。(カイリューではやはり辛いか?)
シミュレータ
言語にはjavascriptを使用している。
3時間で適当に作ったからコードはかなり汚い。
// 配列のシャッフル
const shuffle = (arr) => {
for (let i = arr.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[arr[i], arr[j]] = [arr[j], arr[i]];
}
return arr;
};
// arrから特定のkeyの要素のインデックスを検索
const kiof = (arr, key, k = true) => {
return arr.findIndex((c) => c[key] == k);
};
// from->toへfrom[i]を移動 (a回)
const move = (from, to, i, a = 1) => {
if (from.length < 1) return;
while (a--) {
to.push(from[i]);
from.splice(i, 1);
}
};
// オーキド
const okido = {
name: "okido",
use() {
move(hand, trush, kiof(hand, "name", this.name));
move(stack, hand, 0, 2);
},
};
// モンスターボール
const monbo = {
name: "monbo",
use() {
move(hand, trush, kiof(hand, "name", this.name));
shuffle(stack);
if (kiof(stack, "isSeed") == -1) return;
move(stack, hand, kiof(stack, "isSeed"));
},
};
// ナンジャモ
const nanjamo = {
name: "nanjamo",
use() {
move(hand, trush, kiof(hand, "name", this.name));
const t = hand.length;
move(hand, stack, 0, t);
shuffle(stack);
move(stack, hand, 0, t);
},
};
// ポケモン通信
const poketsu = {
name: "poketsu",
use(i) {
shuffle(stack);
if (kiof(stack, "isPoke") == -1) {
move(hand, trush, kiof(hand, "name", this.name));
return;
}
[hand[i], stack[kiof(stack, "isPoke")]] = [
stack[kiof(stack, "isPoke")],
hand[i],
];
move(hand, trush, kiof(hand, "name", this.name));
},
};
// 不思議なアメ
const ame = {
name: "ame",
use() {
move(hand, trush, kiof(hand, "name", this.name));
},
};
// ミニリュー
const miniryu = {
name: "miniryu",
isPoke: true,
isSeed: true,
evo1: "hakuryu",
evo2: "kairyu",
};
// ハクリュー
const hakuryu = {
name: "hakuryu",
isPoke: true,
evo1: "kairyu",
};
// カイリュー
const kairyu = {
name: "kairyu",
isPoke: true,
};
// その他(トレーナーズ)
const trainer = {
name: "trainer",
};
// その他(ポケモン)
const poke = {
name: "poke",
isPoke: true,
};
// その他(タネポケモン)
const seed = {
name: "seed",
isPoke: true,
isSeed: true,
};
// 1ターン
const myturn = () => {
//進化できない状態を解除
for (let i = 0; i < bench.length; i++) {
if (bench[i].newBorn) {
delete bench[i].newBorn;
}
}
// サポートカード(オーキド/ナンジャモ)は1ターン1回まで
let support = true;
// ターン初めに1枚ドロー
move(stack, hand, 0);
// モンボ使用
while (kiof(hand, "name", "monbo") != -1) {
monbo.use();
}
// オーキド使用
if (kiof(hand, "name", "okido") != -1) {
okido.use();
support = false;
}
// モンボ使用
while (kiof(hand, "name", "monbo") != -1) {
monbo.use();
}
// ベンチにタネを配置
while (kiof(hand, "isSeed") != -1 && bench.length <= 4) {
hand[kiof(hand, "isSeed")].newBorn = true;
move(hand, bench, kiof(hand, "isSeed"));
}
// ポケモンの進化
for (let i = 0; i < bench.length; i++) {
const e1 = kiof(hand, "name", bench[i].evo1);
const e2 = kiof(hand, "name", bench[i].evo2);
if (!bench[i].newBorn && e2 != -1 && kiof(hand, "name", "ame") != -1) {
bench[i] = hand[e2];
hand.splice(e2, 1);
ame.use();
} else if (!bench[i].newBorn && e1 != -1) {
hand[e1].newBorn = true;
bench[i] = hand[e1];
hand.splice(e1, 1);
}
}
// ナンジャモ使用
if (support && kiof(hand, "name", "nanjamo") != -1 && hand.length > 1) {
nanjamo.use();
}
// モンボ使用
while (kiof(hand, "name", "monbo") != -1) {
monbo.use();
}
// ベンチにタネを配置
while (kiof(hand, "isSeed") != -1 && bench.length <= 4) {
hand[kiof(hand, "isSeed")].newBorn = true;
move(hand, bench, kiof(hand, "isSeed"));
}
// ポケ通使用
while (kiof(hand, "name", "poketsu") != -1) {
let dup = -1;
let seen = {};
hand.forEach((c, i) => {
if (seen[c.name]) dup = i;
if (c.isPoke) seen[c.name] = true;
});
if (dup !== -1) {
poketsu.use(dup);
} else {
break;
}
}
// ポケモンの進化
for (let i = 0; i < bench.length; i++) {
const e1 = kiof(hand, "name", bench[i].evo1);
const e2 = kiof(hand, "name", bench[i].evo2);
if (!bench[i].newBorn && e2 != -1 && kiof(hand, "name", "ame") != -1) {
bench[i] = hand[e2];
hand.splice(e2, 1);
ame.use();
} else if (!bench[i].newBorn && e1 != -1) {
hand[e1].newBorn = true;
bench[i] = hand[e1];
hand.splice(e1, 1);
}
}
};
// 1ゲーム
const game = () => {
stack = [...deck];
hand = [];
trush = [];
bench = [];
shuffle(stack);
// 手札にタネポケモンが来るまで抽選
while (kiof(hand, "isSeed") == -1) {
move(hand, stack, 0, hand.length);
move(stack, hand, 0, 5);
}
// ターン数
for (let i = 0; i < T; i++) {
myturn();
}
};
//
// 基本的にここから下をいじる
//
// 計測回数
const N = 100000;
let hit = 0;
// ターン数
const T = 4;
// 使用デッキ
const deck = [
miniryu,
miniryu,
hakuryu,
hakuryu,
kairyu,
kairyu,
okido,
okido,
monbo,
monbo,
ame,
ame,
poketsu,
nanjamo,
seed,
seed,
trainer,
trainer,
trainer,
trainer,
];
let stack = [];
let hand = [];
let trush = [];
let bench = [];
for (let i = 0; i < N; i++) {
game();
// 計測する確率の条件
if (kiof(bench, "name", "kairyu") !== -1) {
++hit;
}
// 進捗を表示
if (i % Math.floor(N / 1000) == 0) {
process.stdout.write(`\rwip: ${Math.floor((i / N) * 1000) / 10}%`);
}
}
process.stdout.write(`\rresult: ${Math.floor((hit / N) * 100000) / 1000}%\n`);
使ってみた
一応、このシミュレータで色々求めたので書いておく。
(博士2、モンボ2、アメ2、ポケ通1、ナンジャモ1、N=100000)
タネ2枚 | タネ4枚 | タネ5枚 | |
2ターン目1進化 | 60.499% | 51.025% | 48.274% |
3ターン目1進化 | 77.051% | 71.381% | 68.476% |
2ターン目2進化 | 36.69% | 30.462% | 29.01% |
3ターン目2進化 | 67.704% | 61.565% | 58.42% |
さいごに
だいたいの使い方はコメントに書いたので、使いたい人は各自で使ってみてほしい。
ポケモン通信のロジックなどがかなり適当なので、精度はまあまあといったところだろうか?
(qiita見てる人ってポケポケやってるの?)