# 機能設計書 31-スコア計算

## 概要

本ドキュメントは、K-Shoot MANIAのゲームプレイにおけるスコア計算機能の設計を記述する。プレイヤーの判定結果（CRITICAL/NEAR/ERROR）に基づいて最大10,000,000点のスコアを算出し、表示用スコアのアニメーション補間処理を含む。

### 本機能の処理概要

**業務上の目的・背景**：音楽ゲームにおいてプレイヤーのパフォーマンスを定量的に評価するために、統一された採点方式が必要である。スコアは結果画面での表示、ハイスコア記録、インターネットランキング(IR)への送信に使用される基幹データである。

**機能の利用シーン**：ゲームプレイ中のリアルタイムスコア表示、プレイ完了後の結果画面でのスコア確定、スコアファイルへの保存、IRサーバーへのスコア送信時に利用される。

**主要な処理内容**：
1. 全判定対象ノート数（shortnum + shljnum + lshnum + longjnum + analoganjnum + analogjnum）から1ノートあたりの基本配点を算出
2. CRITICAL判定は+2ポイント、NEAR判定は+1ポイント、ERROR判定は0ポイントとして加重合計を計算
3. 全ノートCRITICALの場合はパーフェクトスコア10,000,000点を保証
4. 表示用スコアは200msかけてアニメーション補間（イージング）を行う

**関連システム・外部連携**：IRサーバーへのスコア送信（ir_send_score）で使用される。結果画面（result.hsp）でのスコアファイル保存にも使用される。

**権限による制御**：特になし。全プレイヤーに同一の計算ロジックが適用される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 5 | ゲームプレイ画面 | 主画面 | CRITICAL(+2)/NEAR(+1)/ERROR(0)による最大10,000,000点のスコア計算 |
| 6 | リザルト画面 | 結果表示画面 | 合計スコア(0-10,000,000)とD/C/B/A/AA/AAAグレードをImage画像で表示 |

## 機能種別

計算処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| critical | int | Yes | CRITICAL判定回数 | 0以上の整数 |
| near | int | Yes | NEAR判定回数 | 0以上の整数 |
| errorn | int | Yes | ERROR判定回数 | 0以上の整数 |
| shortnum | int | Yes | BTチップノート判定数 | 0以上の整数 |
| shljnum | int | Yes | BTロングノート判定数 | 0以上の整数 |
| lshnum | int | Yes | FXチップ→ロング判定数 | 0以上の整数 |
| longjnum | int | Yes | FXロングノート判定数 | 0以上の整数 |
| analoganjnum | int | Yes | レーザースラム判定数 | 0以上の整数 |
| analogjnum | int | Yes | レーザー追従判定数 | 0以上の整数 |
| totalcombo | int | Yes | 全判定対象の総数 | shortnum+shljnum+lshnum+longjnum+analoganjnum+analogjnum |

### 入力データソース

ゲームプレイ中の判定処理（processButtonNoteJudgment、processLaserNoteJudgment）から加算されるcritical、near、errorn変数。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| totalscore | int | 確定スコア（0〜10,000,000） |
| totalscore_disp | int | 表示用スコア（アニメーション補間後） |
| tochu | int | プレイ途中フラグ（1=未完了, 0=全判定完了） |

### 出力先

- 画面表示: ゲームプレイ画面のリアルタイムUI（play_draw_frame.hsp）
- 画面表示: 結果画面のスコア表示（result.hsp）
- ファイル: プレイヤー別スコアファイル（.ksc）

## 処理フロー

### 処理シーケンス

```
1. プレイ途中判定
   └─ critical + near + errorn < totalcombo であれば tochu=1（途中）
2. 基本配点計算
   └─ dstat = 10,000,000 / 全判定ノート数 / 2
3. スコア算出
   ├─ 全CRITICAL判定の場合 → totalscore = 10,000,000
   └─ それ以外 → totalscore = int(dstat * (critical * 2 + near))
4. 表示用スコア算出
   ├─ スコアが変化した場合 → 補間開始時刻と基準値を記録
   ├─ 変化後200ms以内 → 線形補間で表示スコアを算出
   └─ 変化後200ms以降 → 確定スコアをそのまま表示
```

### フローチャート

```mermaid
flowchart TD
    A[calculateTotalScore呼び出し] --> B{critical+near+errorn < totalcombo?}
    B -->|Yes| C[tochu=1]
    B -->|No| D[tochu=0]
    C --> E{全判定ノート数 > 0?}
    D --> E
    E -->|Yes| F["dstat = 10000000 / 全判定ノート数 / 2"]
    E -->|No| G[dstat = 0]
    F --> H{critical = totalcombo?}
    G --> I[totalscore = 0]
    H -->|Yes| J[totalscore = 10000000]
    H -->|No| K["totalscore = int(dstat * (critical*2 + near))"]
    J --> L[calculateDisplayedTotalScore呼び出し]
    K --> L
    I --> L
    L --> M{スコア変化あり?}
    M -->|Yes| N[補間基準値・時刻を記録]
    M -->|No| O{200ms以内?}
    N --> O
    O -->|Yes| P[線形補間でtotalscore_dispを算出]
    O -->|No| Q[totalscore_disp = totalscore]
    P --> R[完了]
    Q --> R
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-31-01 | CRITICAL配点 | CRITICAL判定は2ポイントとして計算 | 全てのCRITICAL判定時 |
| BR-31-02 | NEAR配点 | NEAR判定は1ポイントとして計算 | 全てのNEAR判定時 |
| BR-31-03 | ERROR配点 | ERROR判定は0ポイント（加算なし） | 全てのERROR判定時 |
| BR-31-04 | パーフェクト保証 | 全CRITICALの場合は10,000,000点を直接代入 | critical = totalcombo |
| BR-31-05 | スコア上限 | スコアの最大値は10,000,000点 | 常時 |
| BR-31-06 | 表示補間 | スコア変化時は200msで線形補間 | リアルタイムUI表示時 |

### 計算ロジック

```
// 基本配点
dstat = 10,000,000 / (shortnum + shljnum + lshnum + longjnum + analoganjnum + analogjnum) / 2

// スコア計算
if critical == totalcombo:
    totalscore = 10,000,000
else:
    totalscore = int(dstat * (critical * 2 + near))

// 表示用スコア計算（アニメーション補間）
if t - totalscore_disp_baset < 200:
    totalscore_disp = totalscore_disp_base + (totalscore - totalscore_disp_base) * (t - totalscore_disp_baset) / 200
else:
    totalscore_disp = totalscore
```

## データベース操作仕様

### 操作別データベース影響一覧

本機能はデータベースを使用しない。スコアデータはファイルベースで管理される。

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| スコア保存 | score/{player}/{dir}.ksc | WRITE | 結果画面でスコアをファイルに書き出し |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ゼロ除算防止 | 全判定ノート数が0の場合 | dstat=0として処理（スコアは0点） |

### リトライ仕様

リトライは不要。計算処理のため失敗時のリカバリは不要。

## トランザクション仕様

トランザクション管理は不要。メモリ上の変数操作のみ。

## パフォーマンス要件

毎フレーム（約16.6ms間隔）で呼び出されるため、高速に処理される必要がある。整数演算が主体であり、パフォーマンス上の問題はない。

## セキュリティ考慮事項

スコアデータはローカルファイルに保存され、IR送信時にはサーバー側で検証される。クライアント側での改ざん防止は限定的。

## 備考

- スコア計算はon_update_play内のcalculateTotalScore関数で毎フレーム実行される
- 表示用スコアのアニメーション補間は視覚的なフィードバックのためで、実際のスコア値には影響しない
- パーフェクト保証（全CRITICAL→10,000,000）は浮動小数点誤差による端数を防ぐための処理

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

スコア計算に関わる変数群の初期化と定義を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | play_game_logic.hsp | `src/scene/play/play_game_logic.hsp` | initGamePlayVariables関数でスコア関連変数（totalscore, totalscorep, totalscore_disp_base等）の初期化を確認 |

**読解のコツ**: HSPでは`ddim`は浮動小数点数配列、`dim`は整数配列を定義する。`dstat`は倍精度浮動小数点で基本配点を保持する。

#### Step 2: エントリーポイントを理解する

メインループからスコア計算がどのように呼び出されるかを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | play_update.hsp | `src/scene/play/play_update.hsp` | on_update_play関数内でcalculateTotalScoreとcalculateDisplayedTotalScoreの呼び出し位置を確認 |

**主要処理フロー**:
1. **147行目**: `calculateTotalScore` - 確定スコアの計算
2. **151行目**: `calculateDisplayedTotalScore` - 表示用スコアの計算（補間処理）

#### Step 3: スコア計算ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | play_game_logic.hsp | `src/scene/play/play_game_logic.hsp` | calculateTotalScore関数（252-265行目）で基本配点とスコア算出ロジックを理解 |
| 3-2 | play_game_logic.hsp | `src/scene/play/play_game_logic.hsp` | calculateDisplayedTotalScore関数（267-278行目）で表示用スコアの補間処理を理解 |

**主要処理フロー**:
- **253行目**: `tochu=(critical+near+errorn<totalcombo)` - プレイ途中判定
- **255-256行目**: 全判定ノート数から基本配点`dstat`を算出
- **260-261行目**: 全CRITICAL時にパーフェクトスコア10,000,000を直接代入
- **263行目**: `totalscore=int(dstat*(critical*2+near))` - 通常のスコア算出
- **268-270行目**: スコア変化時に補間基準値と時刻を記録
- **272-273行目**: 200ms以内の線形補間で表示スコアを算出

#### Step 4: 判定結果の加算元を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | play_button_note.hsp | `src/scene/play/play_button_note.hsp` | processButtonNoteJudgment関数でcritical++、near++、errorn++が加算される箇所を確認 |
| 4-2 | play_laser_note.hsp | `src/scene/play/play_laser_note.hsp` | processLaserNoteJudgment関数でanalogscoreが加算される箇所を確認 |

### プログラム呼び出し階層図

```
on_update_play (play_update.hsp)
    |
    +-- processButtonNoteJudgment (play_button_note.hsp)
    |       +-- critical++, near++, errorn++ の加算
    |
    +-- processLaserNoteJudgment (play_laser_note.hsp)
    |       +-- critical++, analogscore++ の加算
    |
    +-- calculateTotalScore (play_game_logic.hsp:252-265)
    |       +-- tochu判定
    |       +-- dstat基本配点算出
    |       +-- totalscore算出
    |
    +-- calculateDisplayedTotalScore (play_game_logic.hsp:267-278)
            +-- 補間基準値記録
            +-- totalscore_disp算出
```

### データフロー図

```
[入力]                      [処理]                           [出力]

判定結果                    calculateTotalScore
critical  ─────────────┐
near      ─────────────┤   dstat = 10M/全ノート数/2
errorn    ─────────────┤   totalscore = dstat*(C*2+N)        totalscore ──────> result.hsp
shortnum  ─────────────┤                                     totalscore_disp -> play_draw_frame.hsp
shljnum   ─────────────┤   calculateDisplayedTotalScore
longjnum  ─────────────┤   線形補間(200ms)
analoganjnum ──────────┤
analogjnum ────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| play_game_logic.hsp | `src/scene/play/play_game_logic.hsp` | ソース | calculateTotalScore、calculateDisplayedTotalScore関数の実装 |
| play_update.hsp | `src/scene/play/play_update.hsp` | ソース | メインループからスコア計算関数を呼び出すオーケストレーション |
| play_button_note.hsp | `src/scene/play/play_button_note.hsp` | ソース | BT/FXノート判定によるcritical/near/errornの加算 |
| play_laser_note.hsp | `src/scene/play/play_laser_note.hsp` | ソース | レーザーノート判定によるcritical/errornの加算 |
| play_init.hsp | `src/scene/play/play_init.hsp` | ソース | start_play関数での変数初期化（initGamePlayVariables呼び出し） |
| play_draw_frame.hsp | `src/scene/play/play_draw_frame.hsp` | ソース | totalscore_dispの画面描画 |
| result.hsp | `src/scene/result.hsp` | ソース | 結果画面でのスコア表示・保存 |
