Spaces:
Running
Running
| use crate::core::logic::*; | |
| use crate::core::enums::*; | |
| use crate::core::models::*; | |
| use std::collections::HashMap; | |
| fn create_test_db() -> CardDatabase { | |
| let mut db = CardDatabase { | |
| members: HashMap::new(), | |
| lives: HashMap::new(), | |
| members_vec: vec![None; 1000], | |
| lives_vec: vec![None; 40000], | |
| }; | |
| // Member with cost 5 | |
| db.members.insert(10, MemberCard { | |
| card_id: 10, | |
| card_no: "M-10".to_string(), | |
| name: "Member 10".to_string(), | |
| cost: 5, | |
| ..Default::default() | |
| }); | |
| db.members_vec[10] = Some(db.members[&10].clone()); | |
| // Member with cost 15 | |
| db.members.insert(15, MemberCard { | |
| card_id: 15, | |
| card_no: "M-15".to_string(), | |
| name: "Member 15".to_string(), | |
| cost: 15, | |
| ..Default::default() | |
| }); | |
| db.members_vec[15] = Some(db.members[&15].clone()); | |
| // Live card | |
| db.lives.insert(10050, LiveCard { | |
| card_id: 10050, | |
| card_no: "L-10050".to_string(), | |
| name: "Live 10050".to_string(), | |
| ..Default::default() | |
| }); | |
| db.lives_vec[50] = Some(db.lives[&10050].clone()); | |
| db | |
| } | |
| fn create_test_state() -> GameState { | |
| let mut state = GameState::default(); | |
| state.players[0].player_id = 0; | |
| state.players[1].player_id = 1; | |
| state.phase = Phase::Main; | |
| state | |
| } | |
| fn test_opcode_draw_until() { | |
| let db = create_test_db(); | |
| let mut state = create_test_state(); | |
| state.players[0].deck = vec![1, 2, 3, 4, 5]; | |
| state.players[0].hand = vec![101, 102]; // Hand size 2 | |
| let ctx = AbilityContext { player_id: 0, ..Default::default() }; | |
| // O_DRAW_UNTIL 5 (Draw up to 5) | |
| let bc = vec![O_DRAW_UNTIL, 5, 0, 0, O_RETURN, 0, 0, 0]; | |
| state.resolve_bytecode(&db, &bc, &ctx); | |
| assert_eq!(state.players[0].hand.len(), 5); | |
| assert_eq!(state.players[0].deck.len(), 2); | |
| } | |
| fn test_opcode_reveal_until_type_live() { | |
| let db = create_test_db(); | |
| let mut state = create_test_state(); | |
| // Deck: 10 (member), 15 (member), 10050 (live), 1 (fallback) | |
| state.players[0].deck = vec![1, 10050, 15, 10]; | |
| let ctx = AbilityContext { player_id: 0, ..Default::default() }; | |
| // O_REVEAL_UNTIL 33 (TYPE_CHECK) attr: 1 (Live), target: 6 (Hand) | |
| let bc = vec![O_REVEAL_UNTIL, 33, 1, 6, O_RETURN, 0, 0, 0]; | |
| state.resolve_bytecode(&db, &bc, &ctx); | |
| // Should have popped 10, 15, then 10050. | |
| // 10050 matches Live. It goes to hand. | |
| // 10 and 15 go to discard. | |
| assert!(state.players[0].hand.contains(&10050)); | |
| assert_eq!(state.players[0].discard.len(), 2); // 10 and 15 | |
| assert!(state.players[0].discard.contains(&10)); | |
| assert!(state.players[0].discard.contains(&15)); | |
| assert_eq!(state.players[0].deck.len(), 1); // 1 remains | |
| } | |
| fn test_opcode_reveal_until_cost_ge() { | |
| let db = create_test_db(); | |
| let mut state = create_test_state(); | |
| // Deck: 10 (cost 5), 15 (cost 15), 1 (fallback) | |
| state.players[0].deck = vec![1, 15, 10]; | |
| let ctx = AbilityContext { player_id: 0, ..Default::default() }; | |
| // O_REVEAL_UNTIL 16 (COST_GE) attr: (10 << 1) | 0x40 = 20 | 64 = 84, target: 6 (Hand) | |
| // Wait, attr in logic.rs: min_cost = (a >> 1) & 0x1F | |
| let bc = vec![O_REVEAL_UNTIL, 16, 84, 6, O_RETURN, 0, 0, 0]; | |
| state.resolve_bytecode(&db, &bc, &ctx); | |
| // Should pop 10 (cost 5 < 10), then 15 (cost 15 >= 10). | |
| // 15 goes to hand. 10 goes to discard. | |
| assert!(state.players[0].hand.contains(&15)); | |
| assert_eq!(state.players[0].discard.len(), 1); | |
| assert!(state.players[0].discard.contains(&10)); | |
| } | |
| fn test_opcode_immunity() { | |
| let db = create_test_db(); | |
| let mut state = create_test_state(); | |
| assert!(!state.players[0].has_immunity); | |
| let ctx = AbilityContext { player_id: 0, ..Default::default() }; | |
| // O_IMMUNITY 1 | |
| let bc = vec![O_IMMUNITY, 1, 0, 0, O_RETURN, 0, 0, 0]; | |
| state.resolve_bytecode(&db, &bc, &ctx); | |
| assert!(state.players[0].has_immunity); | |
| // O_IMMUNITY 0 | |
| let bc = vec![O_IMMUNITY, 0, 0, 0, O_RETURN, 0, 0, 0]; | |
| state.resolve_bytecode(&db, &bc, &ctx); | |
| assert!(!state.players[0].has_immunity); | |
| } | |
| fn test_opcode_pay_energy() { | |
| let db = create_test_db(); | |
| let mut state = create_test_state(); | |
| state.players[0].tapped_energy = vec![false, false, false]; | |
| let ctx = AbilityContext { player_id: 0, ..Default::default() }; | |
| // O_PAY_ENERGY 2 | |
| let bc = vec![O_PAY_ENERGY, 2, 0, 0, O_RETURN, 0, 0, 0]; | |
| state.resolve_bytecode(&db, &bc, &ctx); | |
| assert_eq!(state.players[0].tapped_energy.iter().filter(|&&t| t).count(), 2); | |
| } | |
| fn test_opcode_look_deck() { | |
| let db = create_test_db(); | |
| let mut state = create_test_state(); | |
| state.players[0].deck = vec![1, 2, 3, 4, 5]; | |
| let ctx = AbilityContext { player_id: 0, ..Default::default() }; | |
| // O_LOOK_DECK 3 | |
| let bc = vec![O_LOOK_DECK, 3, 0, 0, O_RETURN, 0, 0, 0]; | |
| state.resolve_bytecode(&db, &bc, &ctx); | |
| assert_eq!(state.players[0].looked_cards.len(), 3); | |
| assert_eq!(state.players[0].deck.len(), 2); | |
| assert_eq!(state.players[0].looked_cards, vec![5, 4, 3]); | |
| } | |