对拍器在此。https://www.luogu.com/discuss/81283
献忠!
AC代码
mod oiread {use std::{io::{stdin, Read},ops::{Add, Mul, Neg},};pub fn next() -> u8 {let mut a = stdin().lock();let mut c = [0u8];match a.read(&mut c) {Ok(0) => b'\n', // End Of FileOk(1) => c[0],_ => panic!(),}}pub fn get_char() -> char {next().into()}pub fn read_inum<T>() -> TwhereT: Add<Output = T> + Mul<Output = T> + From<u8> + Neg<Output = T>,{let mut ans: T = T::from(0);let mut flag = false;let mut c = next();while c < b'0' || c > b'9' {if c == b'-' {flag = true;}c = next();}while c >= b'0' && c <= b'9' {ans = ans * T::from(10) + T::from(c - b'0');c = next();}if flag {-ans} else {ans}}pub fn read_unum<T>() -> TwhereT: Add<Output = T> + Mul<Output = T> + From<u8>,{let mut ans: T = T::from(0);let mut c = next();while c < b'0' || c > b'9' {c = next();}while c >= b'0' && c <= b'9' {ans = ans * T::from(10) + T::from(c - b'0');c = next();}ans}pub fn read_i64() -> i64 {read_inum::<i64>()}pub fn read_str() -> String {let mut res = String::new();let mut c = next();while c == b' ' || c == b'\n' || c == b'\r' {c = next();}while c != b' ' && c != b'\n' && c != b'\r' {res.push(c as char);c = next();}res}pub fn read_u8s() -> Vec<u8> {let mut res = Vec::new();let mut c = next();while c == b' ' || c == b'\n' || c == b'\r' {c = next();}while c != b' ' && c != b'\n' && c != b'\r' {res.push(c);c = next();}res}
}use std::collections::VecDeque;
use std::fmt;
use std::fmt::Display;
use std::mem::swap;
use std::process::exit;use oiread::read_i64 as read;
use oiread::read_str;#[derive(PartialEq, Eq, Clone, Copy)]
enum BaseType {Atk,Def,Peach,
}
impl From<String> for BaseType {fn from(value: String) -> Self {match value.as_str() {"P" => BaseType::Peach,"K" => BaseType::Atk,"D" => BaseType::Def,x => panic!("Base Card Type Error : {}", x),}}
}
impl Display for BaseType {fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {write!(f,"{}",match *self {BaseType::Atk => "K",BaseType::Def => "D",BaseType::Peach => "P",})}
}#[derive(PartialEq, Eq, Clone, Copy)]
enum SkillType {Fight,ReqAtk,ReqDef,Cancel,
}
impl From<String> for SkillType {fn from(value: String) -> Self {match value.as_str() {"F" => SkillType::Fight,"N" => SkillType::ReqAtk,"W" => SkillType::ReqDef,"J" => SkillType::Cancel,x => panic!("Skill Card Type Error : {}", x),}}
}
impl Display for SkillType {fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {write!(f,"{}",match *self {SkillType::Fight => "F",SkillType::ReqAtk => "N",SkillType::ReqDef => "W",SkillType::Cancel => "J",})}
}#[derive(PartialEq, Eq, Clone, Copy)]
enum CardType {Base(BaseType),Skill(SkillType),Equip,
}
impl From<String> for CardType {fn from(value: String) -> Self {match value.as_str() {"P" | "K" | "D" => CardType::Base(value.into()),"F" | "N" | "W" | "J" => CardType::Skill(value.into()),"Z" => CardType::Equip,x => panic!("Card Type Error : {}", x),}}
}
impl Display for CardType {fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {match *self {CardType::Base(card) => write!(f, "{}", card),CardType::Skill(card) => write!(f, "{}", card),CardType::Equip => write!(f, "Z"),}}
}
#[cfg(feature = "debug")]
impl CardType {fn show(&self) -> &'static str {match *self {CardType::Base(card) => match card {BaseType::Atk => "杀",BaseType::Def => "闪",BaseType::Peach => "桃",},CardType::Skill(card) => match card {SkillType::Fight => "决斗",SkillType::ReqAtk => "南蛮入侵",SkillType::ReqDef => "万箭齐发",SkillType::Cancel => "无懈可击",},CardType::Equip => "诸葛连弩",}}
}#[derive(PartialEq, Debug, Clone, Copy)]
enum Identity {MainPig,ZhongPig,FanPig,
}
impl From<String> for Identity {fn from(value: String) -> Self {match value.as_str() {"MP" => Self::MainPig,"ZP" => Self::ZhongPig,"FP" => Self::FanPig,x => panic!("Error Pig Identity: {}", x),}}
}
#[cfg(feature = "debug")]
impl Identity {fn show(&self) -> &'static str {match *self {Identity::MainPig => "主公",Identity::ZhongPig => "忠臣",Identity::FanPig => "反贼",}}
}#[derive(Clone, Copy, PartialEq, Eq)]
enum ActType {None,Zhong,Fan,
}#[derive(PartialEq, Eq, Clone, Copy)]
enum State {None,SimFan,Fan,Zhong,
}
#[cfg(feature = "debug")]
impl State {fn show(&self) -> &'static str {match *self {State::None | State::SimFan => " ",State::Fan | State::Zhong => "暴露",}}
}#[derive(Clone, Copy)]
struct Act {tp: ActType,card: CardType,src: usize,dst: Option<usize>,
}
impl Act {fn new(tp: ActType, card: CardType, src: usize, dst: Option<usize>) -> Self {Self { tp, card, src, dst }}
}struct Pig {tp: Identity,hp: isize,pos: usize,state: State,cards: Vec<CardType>,equip: bool,alive: bool,attacked: bool,
}
impl Pig {const MAX_HP: isize = 4;fn new(pos: usize) -> Self {let tp = Identity::from(read_str());if pos == 0 {assert_eq!(tp, Identity::MainPig);}let mut cards = Vec::new();for _ in 0..4 {cards.push(CardType::from(read_str()));}Self {tp,hp: Self::MAX_HP,state: State::None,cards,pos,equip: false,alive: true,attacked: false,}}fn is_known(&self) -> bool {self.tp == Identity::MainPig || self.state == State::Zhong || self.state == State::Fan}fn get_card(&mut self, pool: &mut Pool, cnt: usize) {for _ in 0..cnt {if let Some(c) = pool.get() {self.cards.push(c);}}}fn get_enemy(&self, players: &Vec<Pig>) -> Option<usize> {if Identity::FanPig == self.tp {return Some(0);}// [self.pos+1, self.pos+2, ... n-1, 0, 1, 2, ... self.pos-1 ]let mut range = (0..players.len()).collect::<Vec<usize>>();range.rotate_left(self.pos + 1);for i in range {if i == self.pos || !players[i].alive {continue;}let pig = &players[i];match self.tp {Identity::MainPig => {if let State::Fan | State::SimFan = pig.state {return Some(i);}}Identity::ZhongPig => {if State::Fan == pig.state {return Some(i);}}Identity::FanPig => unreachable!(),}}None}fn get_enemy_dis1(&self, players: &Vec<Pig>) -> Option<usize> {// [self.pos+1, self.pos+2, ... n-1, 0, 1, 2, ... self.pos-1 ]let mut range = (0..players.len()).collect::<Vec<_>>();range.rotate_left(self.pos + 1);for i in range {if i == self.pos || !players[i].alive {continue;}let pig = &players[i];match self.tp {Identity::MainPig => {if let State::Fan | State::SimFan = pig.state {return Some(i);}}Identity::ZhongPig => {if State::Fan == pig.state {return Some(i);}}Identity::FanPig => {if State::Zhong == pig.state || pig.tp == Identity::MainPig {return Some(i);}}}break;}None}fn ask(&self, asked_card: CardType) -> Option<usize> {for (i, card) in self.cards.iter().enumerate() {if *card == asked_card {return Some(i);}}None}fn try_act(&self, players: &Vec<Pig>) -> Option<(usize, Act)> {for i in 0..self.cards.len() {let card = &self.cards[i];match card {CardType::Equip => {return Some((i, Act::new(ActType::None, CardType::Equip, self.pos, None)));}CardType::Base(card) => match card {BaseType::Atk => {if !self.equip && self.attacked {continue;}let enemy = self.get_enemy_dis1(players);if enemy.is_some() {return Some((i,Act::new(match self.tp {Identity::MainPig => ActType::None,Identity::ZhongPig => ActType::Zhong,Identity::FanPig => ActType::Fan,},CardType::Base(BaseType::Atk),self.pos,enemy,),));}}BaseType::Def => {}BaseType::Peach => {if self.hp != Self::MAX_HP {return Some((i,Act::new(ActType::None,CardType::Base(BaseType::Peach),self.pos,Some(self.pos),),));}}},CardType::Skill(card) => match card {SkillType::Fight => {let enemy = self.get_enemy(players);if enemy.is_some() {return Some((i,Act::new(match self.tp {Identity::MainPig => ActType::None,Identity::ZhongPig => ActType::Zhong,Identity::FanPig => ActType::Fan,},CardType::Skill(SkillType::Fight),self.pos,enemy,),));}}SkillType::ReqAtk => {return Some((i,Act::new(ActType::None,CardType::Skill(SkillType::ReqAtk),self.pos,None,),))}SkillType::ReqDef => {return Some((i,Act::new(ActType::None,CardType::Skill(SkillType::ReqDef),self.pos,None,),))}SkillType::Cancel => {}},}}None}
}fn main() {let (n, m) = (read() as usize, read() as usize);let mut players = Vec::new();for i in 0..n {players.push(Pig::new(i));}let mut pool = Pool::new(m);// game startloop {for now_pig_id in 0..players.len() {if !players[now_pig_id].alive {continue;}// turn start#[cfg(feature = "debug")]println!("Begin: {} // {}", now_pig_id + 1, players[0].cards.len());players[now_pig_id].attacked = false;players[now_pig_id].get_card(&mut pool, 2);#[cfg(feature = "debug")]show(&mut players);loop {if !players[now_pig_id].alive {break;}let act = players[now_pig_id].try_act(&players);if act.is_none() {break;}let (card_id, act) = act.unwrap();players[now_pig_id].cards.remove(card_id);assert_eq!(act.src, now_pig_id);// use cardmatch act.tp {ActType::None => {}ActType::Zhong => players[now_pig_id].state = State::Zhong,ActType::Fan => players[now_pig_id].state = State::Fan,}match act.card {CardType::Base(card) => match card {BaseType::Atk => {assert!(act.dst.is_some());players[now_pig_id].attacked = true;let d = act.dst.unwrap();let t = players[d].ask(CardType::Base(BaseType::Def));if let Some(card_id) = t {players[d].cards.remove(card_id);} else {players[d].hp -= 1;check_dead(&mut players, &mut pool, now_pig_id, d);}}BaseType::Peach => {assert!(players[now_pig_id].hp < Pig::MAX_HP);players[now_pig_id].hp += 1;}BaseType::Def => unreachable!(),},CardType::Skill(card) => match card {SkillType::Fight => {#[cfg(feature = "debug")]println!("决斗!->{} // {}",act.dst.unwrap() + 1,players[0].cards.len());// check Cancelassert!(act.dst.is_some());let effect = check_cancel(act, &mut players);if effect {let mut wait = now_pig_id;let mut now = act.dst.unwrap();loop {if wait == 0 && players[now].tp == Identity::ZhongPig {break;}let t = players[now].ask(CardType::Base(BaseType::Atk));if t.is_none() {break;};players[now].cards.remove(t.unwrap());swap(&mut now, &mut wait);}players[now].hp -= 1;check_dead(&mut players, &mut pool, wait, now);}}SkillType::ReqAtk => {// loop every pig, check Cancel, req atklet s = now_pig_id;// s+1, s+2 .. n-1 0 1 .. s-1let mut range = (0..players.len()).collect::<Vec<_>>();range.rotate_left(s + 1);for i in range {if !players[i].alive || i == s {continue;}let effect = check_cancel(Act::new(ActType::None,CardType::Skill(SkillType::ReqAtk),s,Some(i),),&mut players,);#[cfg(feature = "debug")]println!("effect = {effect} // {}", players[0].cards.len());if !effect {continue;}let t = players[i].ask(CardType::Base(BaseType::Atk));if let Some(card_id) = t {players[i].cards.remove(card_id);} else {players[i].hp -= 1;check_dead(&mut players, &mut pool, s, i);}}}SkillType::ReqDef => {// same as beforelet s = now_pig_id;// s+1, s+2 .. n-1 0 1 .. s-1let mut range = (0..players.len()).collect::<Vec<_>>();range.rotate_left(s + 1);for i in range {if !players[i].alive || i == s {continue;}let effect = check_cancel(Act::new(ActType::None,CardType::Skill(SkillType::ReqDef),s,Some(i),),&mut players,);if !effect {continue;}let t = players[i].ask(CardType::Base(BaseType::Def));if let Some(card_id) = t {players[i].cards.remove(card_id);} else {players[i].hp -= 1;check_dead(&mut players, &mut pool, s, i);}}}SkillType::Cancel => unreachable!(),},CardType::Equip => {players[now_pig_id].equip = true;}}// end card//println!("use card : {} to {:?}", act.card, act.dst);}// end turn//println!("end turn.------------------------");//out_result(&players);}}
}fn check_cancel(act: Act, players: &mut Vec<Pig>) -> bool {let mut now_act = act;let mut effect = true;loop {let res = who_use_cancel(now_act, players);if res.is_none() {break;}let (i, j, tp) = res.unwrap();players[i].cards.remove(j);#[cfg(feature = "debug")]println!("{}:无懈可击! // {}", i + 1, players[0].cards.len());effect = !effect;now_act = Act::new(tp, CardType::Skill(SkillType::Cancel), i, Some(now_act.src));}effect
}fn who_use_cancel(act: Act, players: &mut Vec<Pig>) -> Option<(usize, usize, ActType)> {assert!(act.dst.is_some());let s = act.src;let t = act.dst.unwrap();if !players[t].is_known() && !players[s].is_known() {// both unknownreturn None;}// s, s+1, ..., n-1, 0, 1, ..., s-1let mut range = (0..players.len()).collect::<Vec<_>>();range.rotate_left(s);for i in range {if !players[i].alive {continue;}match players[i].tp {Identity::MainPig | Identity::ZhongPig => {if ((players[t].state == State::Zhong || players[t].tp == Identity::MainPig)&& (act.tp != ActType::Zhong))|| act.tp == ActType::Fan{for j in 0..players[i].cards.len() {if players[i].cards[j] == CardType::Skill(SkillType::Cancel) {if players[i].tp != Identity::MainPig {players[i].state = State::Zhong;}return Some((i, j, ActType::Zhong));}}}}Identity::FanPig => {if (players[t].state == State::Fan && act.tp != ActType::Fan)|| act.tp == ActType::Zhong{for j in 0..players[i].cards.len() {if players[i].cards[j] == CardType::Skill(SkillType::Cancel) {players[i].state = State::Fan;return Some((i, j, ActType::Fan));}}}}}}None
}fn check_dead(players: &mut Vec<Pig>, pool: &mut Pool, src: usize, dst: usize) {if players[dst].tp == Identity::MainPig && players[src].state == State::None {players[src].state = State::SimFan;}if players[dst].hp <= 0 {let t = players[dst].ask(CardType::Base(BaseType::Peach));if let Some(card_id) = t {players[dst].cards.remove(card_id);players[dst].hp += 1;} else {players[dst].alive = false;players[dst].cards.clear();players[dst].equip = false;// check resultcheck_game_over(players);if players[dst].tp == Identity::FanPig {players[src].get_card(pool, 3);} else if players[dst].tp == Identity::ZhongPig && src == 0 {players[0].cards.clear();players[0].equip = false;}}}
}fn check_game_over(players: &Vec<Pig>) {if !players[0].alive {// game over; FP winprintln!("FP");out_result(players);exit(0);}for pig in players {if pig.tp == Identity::FanPig && pig.alive {return;}}// game over; MP winprintln!("MP");out_result(players);exit(0);
}fn out_result(players: &Vec<Pig>) {for pig in players {if pig.alive {println_card(&pig.cards);} else {println!("DEAD");}}
}fn println_card(cards: &Vec<CardType>) {for (i, card) in cards.iter().enumerate() {print!("{}", card);if i < cards.len() - 1 {print!(" ");}}println!("");
}struct Pool {pool: VecDeque<CardType>,last: Option<CardType>,
}
impl Pool {fn new(cnt: usize) -> Self {let mut pool = VecDeque::new();for _ in 0..cnt {pool.push_back(CardType::from(read_str()));}Self { pool, last: None }}// data is wrong.// if pool is empty, return the last card.fn get(&mut self) -> Option<CardType> {if !self.pool.is_empty() {self.last = self.pool.pop_front();}return self.last;}
}#[cfg(feature = "debug")]
fn show(players: &mut Vec<Pig>) {for i in 0..players.len() {print!("{}:{{{}}}({})hp:",i + 1,players[i].tp.show(),players[i].state.show());for _ in 0..players[i].hp {print!("*");}for x in &players[i].cards {print!("【{}】", x.show());}println!();}
}