0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

カウンター魔法バトルの計算ミス(シュミレーション問題)

Last updated at Posted at 2025-03-18

Paizaのカウンター魔法バトルを解いてたら、見事にハマった。
攻撃がフィボナッチっぽいと思ったら…。
同じミスをしないよう、技術メモを残しておく。

問題概要

ターン制バトルで、パイザ君とモンスターが「カウンター魔法」で攻撃し合う。
ただし、攻撃計算が特殊!

📌 攻撃ルール

  • 1回目・2回目の攻撃は 固定で1
  • 3回目以降は以下の計算:
    パイザ君の攻撃 = モンスターの直近2回の合計
    モンスターの攻撃 = (パイザ君の前回攻撃 × 2) + (前々回の攻撃)
  • パイザ君の体力 H が 0 以下になったターンを出力


NGコード:

let H = Number(input);
let n = 0;  
let damageFromMonster = [];
let damageFromPaiza = [];
damageFromMonster.push(1);
damageFromPaiza.push(1);

while (H > 0) {
    n++;
    let attackPaiza = damageFromMonster[n - 1] + damageFromMonster[n - 2];
    let attackMonster = damageFromPaiza[n - 1] * 2 + damageFromPaiza[n - 2];

    H -= attackMonster;
    damageFromPaiza.push(attackPaiza);
    damageFromMonster.push(attackMonster);
}

console.log(n);

💀 ミスのポイント

  • 初回の攻撃を考慮してない!
    H がズレる
  • 配列のインデックスエラー発生!
    n=1 のとき n-2-1 になり、エラー


OKコード:修正後

let H = Number(input) - 2;  // 最初の2回分を引く
let n = 2;  // 3回目からカウント
let damageFromPaiza = [1, 1];  
let damageFromMonster = [1, 1];  

while (H > 0) {
    let attackPaiza = damageFromMonster[n - 1] + damageFromMonster[n - 2];  
    let attackMonster = damageFromPaiza[n - 1] * 2 + damageFromPaiza[n - 2];  

    H -= attackMonster;  
    damageFromPaiza.push(attackPaiza);
    damageFromMonster.push(attackMonster);

    n++;
}

console.log(n);

✅ 修正ポイント

  • 最初の 2回分の攻撃をHから引く ことでズレを修正
  • 配列の 初期値を [1,1] にしてインデックスエラーを防ぐ
  • n=2 から開始 し、3回目以降を計算


さらに高速化

累積ダメージ(sum)を使うと、毎回 H -= attackMonsterしなくてOK!

const rl = require('readline').createInterface({input: process.stdin});
rl.on('line',(input) => {
    
    const H = Number(input);

    const damageFromPaiza = [1, 1]; // パイザ君から受けた攻撃
    const damageFromMonster = [1, 1]; // モンスターから受けた攻撃

    let i = 2;  
    let sum = 2; // すでにモンスターの1回目と2回目のダメージを加算済み

    while (sum < H) {  
        damageFromPaiza.push(damageFromMonster[i - 2] + damageFromMonster[i - 1]); // パイザ君の攻撃 = 前2回のモンスターの攻撃の合計
        damageFromMonster.push(damageFromPaiza[i - 2] + 2 * damageFromPaiza[i - 1]); // モンスターの攻撃 = (前回のパイザ君の攻撃 * 2) + (前々回のパイザ君の攻撃)
        sum += damageFromMonster[i]; // モンスターの攻撃を累積ダメージに加算
        i += 1;  // 次のターンへ
    }
    console.log(i);
    rl.close()
})

🚀 改善点

  • sum を使って 累積ダメージを管理(ループの条件判定がシンプル)
  • H -= attackMonstersum < H に変更(無駄な計算を減らす)


まとめ

  • 配列の初期値 を設定しないと インデックスエラー になる
  • 最初のダメージ を考慮しないと H の減り方がズレる
  • 累積ダメージ sum を使うと高速化できる!

僕の失敗談と解決話!

0
0
6

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?