Spaces:
Running
Running
| use crate::core::logic::*; | |
| use crate::core::enums::*; | |
| fn test_refresh_on_empty_draw() { | |
| let mut state = GameState::default(); | |
| state.players[0].deck = vec![]; | |
| state.players[0].discard = vec![1, 2, 3]; | |
| let db = CardDatabase { | |
| members: std::collections::HashMap::new(), | |
| lives: std::collections::HashMap::new(), | |
| members_vec: vec![], | |
| lives_vec: vec![], | |
| }; | |
| // Drawing 1 card should trigger refresh | |
| state.draw_cards(0, 1); | |
| assert_eq!(state.players[0].hand.len(), 1); | |
| assert_eq!(state.players[0].deck.len(), 2); | |
| assert!(state.players[0].discard.is_empty()); | |
| assert!(state.players[0].deck_refreshed_this_turn); | |
| } | |
| fn test_refresh_on_look_at_top_x() { | |
| let mut state = GameState::default(); | |
| state.players[0].deck = vec![10]; // Only 1 card in deck | |
| state.players[0].discard = vec![1, 2, 3]; | |
| let db = CardDatabase { | |
| members: std::collections::HashMap::new(), | |
| lives: std::collections::HashMap::new(), | |
| members_vec: vec![], | |
| lives_vec: vec![], | |
| }; | |
| let ctx = AbilityContext { | |
| player_id: 0, | |
| ..AbilityContext::default() | |
| }; | |
| // O_LOOK_DECK, Value 3 (Look at top 3) | |
| // Rule 10.2.2.2: Refresh because deck (1) < needed (3) | |
| let bytecode = vec![O_LOOK_DECK, 3, 0, 0, O_RETURN, 0, 0, 0]; | |
| state.resolve_bytecode(&db, &bytecode, &ctx); | |
| // After refresh, deck should have 1 (original) + 3 (refreshed) = 4 cards | |
| assert_eq!(state.players[0].deck.len(), 4); | |
| assert!(state.players[0].discard.is_empty()); | |
| assert!(state.players[0].deck_refreshed_this_turn); | |
| // Looked cards should contain 3 cards (top of deck) | |
| assert_eq!(state.players[0].looked_cards.len(), 3); | |
| // Original card (10) MUST be one of them (the top one) | |
| assert_eq!(state.players[0].looked_cards[0], 10); | |
| } | |
| fn test_refresh_order_preservation() { | |
| let mut state = GameState::default(); | |
| state.players[0].deck = vec![10, 20]; // 20 is on top | |
| state.players[0].discard = vec![1, 2, 3]; | |
| // Force refresh | |
| state.resolve_deck_refresh(0); | |
| // Rule 10.2.3: Existing cards (10, 20) stay on top | |
| // pop() should get 20, then 10. | |
| assert_eq!(state.players[0].deck.pop(), Some(20)); | |
| assert_eq!(state.players[0].deck.pop(), Some(10)); | |
| // Refreshed cards are at the bottom | |
| assert_eq!(state.players[0].deck.len(), 3); | |
| } | |
| fn test_refresh_on_look_and_choose() { | |
| let mut state = GameState::default(); | |
| state.players[0].deck = vec![10]; // Only 1 card | |
| state.players[0].discard = vec![1, 2, 3]; | |
| let db = CardDatabase { | |
| members: std::collections::HashMap::new(), | |
| lives: std::collections::HashMap::new(), | |
| members_vec: vec![], | |
| lives_vec: vec![], | |
| }; | |
| let ctx = AbilityContext { | |
| player_id: 0, | |
| choice_index: 0, // Pick the top card | |
| ..AbilityContext::default() | |
| }; | |
| // O_LOOK_AND_CHOOSE, Value 3, Attr 1 (Discard rest) | |
| // Rule 10.2.2.2: Refresh because deck (1) < needed (3) | |
| let bytecode = vec![O_LOOK_AND_CHOOSE, 3, 1, 0, O_RETURN, 0, 0, 0]; | |
| state.resolve_bytecode(&db, &bytecode, &ctx); | |
| // After refresh, deck should have 1 + 3 = 4 cards. | |
| // Hand got 1 card. | |
| // Discard got 2 cards (rest of 3). | |
| // Final deck should have original 1 card left? | |
| // Wait, let's trace: | |
| // Deck: [10] | |
| // Refresh(3) triggers -> Discard [1,2,3] shuffled and put at bottom. | |
| // Deck: [?, ?, ?, 10] (top is 10) | |
| // Pop 3: 10, ?, ? | |
| // Choice 0: 10 goes to hand. | |
| // Rest of pop: [?, ?] go to discard. | |
| // Remaining in deck: [?] (the one that wasn't popped) | |
| assert_eq!(state.players[0].hand.len(), 1); | |
| assert_eq!(state.players[0].hand[0], 10); | |
| assert_eq!(state.players[0].discard.len(), 2); | |
| assert_eq!(state.players[0].deck.len(), 1); | |
| } | |