use log::debug;
use crate::composite_protocol_stacking_common::logic::ping_pong_logic::{act, Umpire};
use crate::composite_protocol_stacking_common::logic::ping_pong_models::{GameStates, Players, PingPongEvent, GameOverStates, PlayerAction, FaultEvents, Rules};
pub fn react_to_rally_event(umpire: &mut Umpire,
reported_state_name: &str,
reported_state_matcher: impl FnOnce(&GameStates) -> bool,
opponent_action: &PlayerAction,
reported_event: PingPongEvent)
-> PingPongEvent {
let expected_state = umpire.state();
if reported_state_matcher(expected_state) {
let expected_event = umpire.process_turn(Players::Opponent, opponent_action);
if reported_event == expected_event {
let our_action = act();
umpire.process_turn(Players::Ourself, &our_action)
} else {
debug!("Umpires Disagree: Remote player says their action `{:?}` lead to a `{:?}` event, but our umpire said the resulting event would be `{:?}`",
opponent_action, reported_event, expected_event);
PingPongEvent::GameOver(GameOverStates::GameCancelled { partial_score: *umpire.score(), broken_rule: Rules::UmpiresDisagreeOnEvent })
}
} else {
debug!("Umpires Disagree: Remote player said their action `{:?}` was taken due to the game being in the `{:?}` state, but our umpire said the game state was in `{:?}`",
opponent_action, reported_state_name, expected_state);
PingPongEvent::GameOver(GameOverStates::GameCancelled { partial_score: *umpire.score(), broken_rule: Rules::UmpiresDisagreeOnState })
}
}
pub fn react_to_hard_fault(umpire: &mut Umpire, opponent_action: &PlayerAction, reported_fault_event: &FaultEvents) -> Vec<PingPongEvent> {
let expected_event = umpire.process_turn(Players::Opponent, opponent_action);
if let PingPongEvent::HardFault { player_action: _opponent_action, resulting_fault_event: expected_fault_event } = expected_event {
if &expected_fault_event == reported_fault_event {
service_ball(umpire)
} else {
debug!("Umpires Disagree: Remote player said their action `{:?}` lead to a `{:?}` event, but our umpire said the resulting event would be `{:?}`",
opponent_action, reported_fault_event, expected_event);
vec![PingPongEvent::GameOver(GameOverStates::GameCancelled { partial_score: *umpire.score(), broken_rule: Rules::UmpiresDisagreeOnEvent })]
}
} else {
debug!("Umpires Disagree: Remote player said their action `{:?}` lead to the HardFault `{:?}`, but our umpire said the resulting event was `{:?}`",
opponent_action, reported_fault_event, expected_event);
vec![PingPongEvent::GameOver(GameOverStates::GameCancelled { partial_score: *umpire.score(), broken_rule: Rules::UmpiresDisagreeOnHardFault })]
}
}
pub fn react_to_service_soft_fault(umpire: &mut Umpire, opponent_action: &PlayerAction, reported_fault_event: &FaultEvents) -> Vec<PingPongEvent> {
let expected_event = umpire.process_turn(Players::Opponent, opponent_action);
if let PingPongEvent::SoftFault { player_action: _opponent_action, resulting_fault_event: expected_fault_event } = expected_event {
if &expected_fault_event == reported_fault_event {
if let GameStates::WaitingForService { attempt } = umpire.state() {
if *attempt <= Umpire::SERVICING_ATTEMPTS {
vec![]
} else {
debug!("Umpires Disagree: Remote player said their action `{:?}` lead to a `{:?}` event, but our umpire said the resulting event would be `{:?}`",
opponent_action, reported_fault_event, expected_event);
vec![PingPongEvent::GameOver(GameOverStates::GameCancelled { partial_score: *umpire.score(), broken_rule: Rules::UmpiresDisagreeOnExceededServicingAttempts })]
}
} else {
debug!("Umpires Disagree: Remote player said their SoftFault after the action `{:?}` lead to a `WaitForService` state, but `{:?}` was found",
opponent_action, umpire.state());
vec![PingPongEvent::GameOver(GameOverStates::GameCancelled { partial_score: *umpire.score(), broken_rule: Rules::UmpiresDisagreeOnState })]
}
} else {
debug!("Umpires Disagree: Remote player said their action `{:?}` lead to a `{:?}` event, but our umpire said the resulting event would be `{:?}`",
opponent_action, reported_fault_event, expected_event);
vec![PingPongEvent::GameOver(GameOverStates::GameCancelled { partial_score: *umpire.score(), broken_rule: Rules::UmpiresDisagreeOnEvent })]
}
} else {
debug!("Umpires Disagree: Remote player said their action `{:?}` lead to the SoftFault `{:?}`, but our umpire said the resulting event was `{:?}`",
opponent_action, reported_fault_event, expected_event);
vec![PingPongEvent::GameOver(GameOverStates::GameCancelled { partial_score: *umpire.score(), broken_rule: Rules::UmpiresDisagreeOnSoftFault })]
}
}
pub fn react_to_score(umpire: &mut Umpire, opponent_action: &PlayerAction, reported_fault_event: &FaultEvents) -> Vec<PingPongEvent> {
let expected_event = umpire.process_turn(Players::Opponent, opponent_action);
if let PingPongEvent::Score { point_winning_player: _, last_player_action: _opponent_action, last_fault: expected_fault_event } = expected_event {
if &expected_fault_event == reported_fault_event {
service_ball(umpire)
} else {
debug!("Umpires Disagree: Remote player said their action `{:?}` lead to a `{:?}` event, but our umpire said the resulting event would be `{:?}`",
opponent_action, reported_fault_event, expected_event);
vec![PingPongEvent::GameOver(GameOverStates::GameCancelled { partial_score: *umpire.score(), broken_rule: Rules::UmpiresDisagreeOnEvent })]
}
} else {
debug!("Umpires Disagree: Remote player said their action `{:?}` lead to the Score `{:?}`, but our umpire said the resulting event was `{:?}` (notice the player names, as they should be flipped)",
opponent_action, reported_fault_event, expected_event);
vec![PingPongEvent::GameOver(GameOverStates::GameCancelled { partial_score: *umpire.score(), broken_rule: Rules::UmpiresDisagreeOnState })]
}
}
pub fn _opposite_player(player: Players) -> Players {
match player {
Players::Ourself => Players::Opponent,
Players::Opponent => Players::Ourself,
}
}
pub fn service_ball(umpire: &mut Umpire) -> Vec<PingPongEvent> {
let mut events = Vec::with_capacity(Umpire::SERVICING_ATTEMPTS as usize);
loop {
let our_action = act();
let our_event = umpire.process_turn(Players::Ourself, &our_action);
match our_event {
PingPongEvent::SoftFault { player_action: _, resulting_fault_event: _ } => {
events.push(our_event);
},
_ => {
events.push(our_event);
break
},
}
}
events
}