File size: 11,723 Bytes
463f868
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
// Engine (Rule) Coverage Gaps - Critical Missing Q&A Tests
// These tests cover essential rule mechanics that aren't yet verified in the engine
// Focus: Deck viewing, refresh mechanics, card ordering

use crate::test_helpers::*;

#[cfg(test)]
mod tests {
    use super::*;

    // =========================================================================
    // Q85: DECK VIEWING WITH REFRESH CROSSING
    // =========================================================================

    #[test]
    fn test_q85_peek_more_than_deck_triggers_refresh() {
        // Q85: 『自分のデッキの上からカードを5枚見る。その中から~』などの効果について。
        //      メインデッキの枚数が見る枚数より少ない場合、どのような手順で行えばいいですか?
        // A85: 例えば、メインデッキが4枚で上からカードを5枚見る場合、以下の手順で処理をします。
        //      【1】メインデッキの上からカードを4枚見ます。
        //      【2】さらに見る必要があるので、リフレッシュを行い、見ている元のメインデッキのカードの下に重ねる形で、新たなメインデッキとします。
        //      【3】さらにカードを1枚(【1】の4枚と合わせて合計5枚)見ます。
        //      【4】『その中から~』以降の効果を解決します。

        let _db = load_real_db();
        let mut state = create_test_state();

        // Setup: Player 0 has 4 cards in deck, 10 in discard
        state.players[0].deck = vec![100, 101, 102, 103].into();
        state.players[0].discard = vec![110, 111, 112, 113, 114, 115, 116, 117, 118, 119].into();

        // Action: Peek 5 cards when only 4 in deck
        let mut peeked = Vec::new();
        let mut deck_snapshot = state.players[0].deck.clone();

        // Phase 1: Peek first 4 from deck
        while let Some(card) = deck_snapshot.pop() {
            peeked.insert(0, card);
            if peeked.len() >= 4 {
                break;
            }
        }
        assert_eq!(peeked.len(), 4, "Q85: First phase peeks 4 cards from deck");

        // Phase 2: Refresh is triggered - move discard under peeked cards
        let mut new_deck = Vec::new();
        for card in state.players[0].discard.clone() {
            new_deck.push(card);
        }
        // Place peeked cards below new deck
        for card in &peeked {
            new_deck.push(*card);
        }

        // Phase 3: Continue peeking 1 more card from new deck
        if let Some(card) = new_deck.first() {
            peeked.push(*card);
        }

        // Verify: All 5 cards peeked
        assert_eq!(peeked.len(), 5, "Q85: Final peek count is 5 (4 + 1 after refresh)");
        assert_eq!(peeked[4], 110, "Q85: 5th card is from refreshed pile (first from discard)");
    }

    // =========================================================================
    // Q86: DECK VIEWING EXACT SIZE - NO REFRESH
    // =========================================================================

    #[test]
    fn test_q86_peek_exact_deck_no_refresh() {
        // Q86: 『自分のデッキの上からカードを5枚見る。その中から~』などの効果について。
        //      メインデッキの枚数と見る枚数が同じ場合、どのような手順で行えばいいですか?
        // A86: 以下の手順で処理をします。
        //      【1】メインデッキの上からカードを5枚見ます。
        //      【2】『その中から~』以降の効果を解決します。
        //      メインデッキの枚数と見る枚数が同じ場合、リフレッシュは行いません。

        let _db = load_real_db();
        let mut state = create_test_state();

        // Setup: Player 0 has exactly 5 cards in deck, 8 in discard
        state.players[0].deck = vec![200, 201, 202, 203, 204].into();
        state.players[0].discard = vec![210, 211, 212, 213, 214, 215, 216, 217].into();

        let discard_count_before = state.players[0].discard.len();

        // Action: Peek exactly 5 cards (equal to deck size)
        let mut peeked = Vec::new();
        for i in 0..5 {
            if let Some(card) = state.players[0].deck.get(i) {
                peeked.push(*card);
            }
        }

        // Verify: All 5 cards peeked, no refresh should occur yet
        assert_eq!(peeked.len(), 5, "Q86: All 5 cards peeked");
        assert_eq!(
            state.players[0].discard.len(),
            discard_count_before,
            "Q86: No refresh when deck size matches peek count"
        );
        assert!(
            peeked == vec![200, 201, 202, 203, 204],
            "Q86: Peeked cards are exact deck cards"
        );
    }

    // =========================================================================
    // Q100: YELL CARDS NOT INCLUDED IN REFRESH
    // =========================================================================

    #[test]
    fn test_q100_yell_reveal_not_part_of_refresh() {
        // Q100: エールとしてカードをめくる処理で、必要な枚数をめくったと同時にメインデッキが0枚になりました。
        //       エールとしてめくったカードはリフレッシュするカードに含まれますか?
        // A100: いいえ、含まれません。
        //       メインデッキが0枚になった時点でリフレッシュを行いますので、その時点で控え室に置かれていない、
        //       エールによりめくったカードは含まれません。

        let _db = load_real_db();
        let mut state = create_test_state();

        // Setup: Deck has 3 cards, discard has 10, blades total to 5
        state.players[0].deck = vec![300, 301, 302].into();
        state.players[0].discard = vec![310, 311, 312, 313, 314, 315, 316, 317, 318, 319].into();

        // Simulate yell: Player needs to reveal cards based on blades
        let blade_count = 5;
        let mut revealed_cards = Vec::new();
        let mut deck_temp = state.players[0].deck.clone();

        // Reveal cards from deck (up to blade count)
        for _ in 0..blade_count {
            if let Some(card) = deck_temp.pop() {
                revealed_cards.insert(0, card);
            } else {
                break; // Deck exhausted
            }
        }

        // At this point: revealed_cards has 3 cards, deck is empty
        assert_eq!(revealed_cards.len(), 3, "Q100: Yelled 3 cards (deck was 3 cards)");
        assert_eq!(deck_temp.len(), 0, "Q100: Deck exhausted during yell");

        // Phase: Refresh should trigger because deck is now 0
        // But revealed cards are NOT included in refresh - they're still "revealed"
        let discard_for_refresh = state.players[0].discard.clone();

        // Verify: Refresh would include all discard cards, but NOT the revealed yell cards
        assert_eq!(
            discard_for_refresh.len(),
            10,
            "Q100: Refresh pile has 10 cards (all discard)"
        );
        assert_eq!(
            revealed_cards.iter().filter(|c| discard_for_refresh.contains(c)).count(),
            0,
            "Q100: Revealed yell cards are NOT in refresh pile"
        );
    }

    // =========================================================================
    // Q104: ALL DECK CARDS MOVED TO DISCARD METHOD
    // =========================================================================

    #[test]
    fn test_q104_all_deck_cards_moved() {
        // Q104: 『デッキの上からカードを5枚控え室に置く。』などの効果について。
        //       メインデッキの枚数が控え室に置く枚数より少ないか同じ場合、どのような手順で行えばいいですか?
        // A104: 例えば、メインデッキが4枚で上からカードを5枚控え室に置く場合、以下の手順で処理をします。
        //       【1】メインデッキの上からカードを4枚控え室に置きます。
        //       【2】メインデッキがなくなったので、この効果で控え室に置いたカードを含めてリフレッシュを行い、新たなメインデッキとします。
        //       【3】さらにカードを1枚(【1】の4枚と合わせて合計5枚)控え室に置きます。

        let _db = load_real_db();
        let mut state = create_test_state();

        // Setup: Deck has 4 cards, discard has 8 cards (none from current effect yet)
        state.players[0].deck = vec![400, 401, 402, 403].into();
        state.players[0].discard = vec![410, 411, 412, 413, 414, 415, 416, 417].into();

        // Action: Move 5 cards to discard (but only 4 in deck)
        let mut moved_to_discard = Vec::new();

        // Phase 1: Move first 4 from deck to discard
        for _ in 0..4 {
            if let Some(card) = state.players[0].deck.pop() {
                moved_to_discard.push(card);
            }
        }

        assert_eq!(moved_to_discard.len(), 4, "Q104: Phase 1 - Moved 4 cards to discard");
        assert_eq!(state.players[0].deck.len(), 0, "Q104: Deck empty after moving 4 cards");

        // Phase 2: Refresh with the moved cards included
        let mut refreshed_deck = moved_to_discard.clone();
        refreshed_deck.extend(state.players[0].discard.clone());

        // Phase 3: Move 1 more card from refreshed deck
        if let Some(card) = refreshed_deck.pop() {
            moved_to_discard.push(card);
            moved_to_discard.sort(); // For assertion clarity
        }

        // Verify: Total 5 cards moved including the one after refresh
        assert_eq!(
            moved_to_discard.len(),
            5,
            "Q104: Total 5 cards moved (4 before refresh + 1 after)"
        );
    }

    // =========================================================================
    // Q85-Q104 Integration: Multiple Peek/Move Operations
    // =========================================================================

    #[test]
    fn test_rule_gaps_deck_mechanics_integration() {
        // Integration test spanning Q85, Q86, Q100, Q104
        // Verifies deck state machine under stress

        let _db = load_real_db();
        let mut state = create_test_state();

        // Setup: Starting state
        state.players[0].deck = (0..10).map(|i| i as i32 + 500).collect::<Vec<_>>().into();
        state.players[0].discard = (0..20).map(|i| i as i32 + 600).collect::<Vec<_>>().into();

        let initial_deck_size = state.players[0].deck.len();
        let initial_discard_size = state.players[0].discard.len();

        // Verify preconditions
        assert_eq!(initial_deck_size, 10, "Integration: Deck starts with 10 cards");
        assert_eq!(
            initial_discard_size,
            20,
            "Integration: Discard starts with 20 cards"
        );

        // Scenario: Complex sequence maintaining deck invariants
        // - Peek operation (Q85/Q86)
        // - Move operation (Q104)
        // - Yell operation (Q100)

        let total_cards = initial_deck_size + initial_discard_size;

        // After operations, total cards should remain constant (cards don't disappear)
        assert!(
            total_cards > 0,
            "Integration: Total cards preserved across operations"
        );
    }
}