Compare commits

..

No commits in common. '53922bcd9120a20deb5475b9e1d74cc04364b825' and '78d70bf2a0bac84065e5ff9646107815df256e14' have entirely different histories.

@ -289,6 +289,3 @@ fast_light_speed = 1.0
# -1: No limit
# N: Some value in-between
undo_limit = -1
[ai]
lag_secs = 2.0

@ -5,80 +5,29 @@ pub(crate) struct AiPlugin;
impl Plugin for AiPlugin {
fn build(&self, app: &mut App) {
app.init_state::<PlayState>()
.init_resource::<AiMove>()
.init_state::<AiDrama>()
// Bogo AI Systems
.add_systems(
Update,
(
bogo_ai_thinking
.run_if(in_state(AiDrama::Thinking)),
bogo_ai_holding
.run_if(in_state(AiDrama::Holding)),
)
.run_if(in_state(PlayState::AiBogo))
.run_if(in_state(GameState::Play))
.run_if(in_state(TurnState(Side::A)))
.add_systems(Update,
bogo_ai.run_if(in_state(PlayState::AiBogo))
);
}
}
#[derive(Debug, States, Hash, Default, PartialEq, Eq, Clone, Component)]
pub(crate) enum PlayState {
Human,
#[default]
AiBogo,
}
#[derive(Debug, States, Hash, Default, PartialEq, Eq, Clone)]
enum AiDrama {
// Before AI picks up a piece
enum PlayState {
#[default]
Thinking,
// When AI picks up piece
Holding,
Human,
AiBogo,
}
/// The move the AI will commit
#[derive(Debug, Resource, Default)]
struct AiMove(Move);
// Bogo AI logic
fn bogo_ai_thinking(
board: Res<Board>,
query: Query<(Entity, &BoardIndex), With<Piece>>,
fn bogo_ai(
mut board: ResMut<Board>,
mut move_events: EventWriter<Move>,
time: Res<Time>,
mut next_drama: ResMut<NextState<AiDrama>>,
mut timer: Local<Timer>,
mut commands: Commands,
mut selected: ResMut<AiMove>,
tweaks: Res<Assets<Tweaks>>,
tweaks_file: Res<tweak::GameTweaks>,
) {
let tweak = tweaks
.get(tweaks_file.handle.clone())
.expect("Load tweakfile");
let lag = tweak.get::<f32>("ai_lag_secs").unwrap();
let timer_duration = Duration::from_secs_f32(lag);
// Initialize timer
if timer.duration() != timer_duration {
timer.set_duration(Duration::from_secs_f32(1.0));
timer.set_mode(TimerMode::Once);
}
// Timer before committing move
if !timer.finished() {
timer.tick(time.delta());
} else {
info!("AI finished thinking");
info!("Timer: {:?}", timer);
// TODO: Assuming AI is Side::A
let ai_side = Side::A;
// Determine which moves to do
let (from, to) = {
let on = board.on(ai_side);
let set: Vec<(&BoardIndex, HashSet<BoardIndex>)> = on
.iter()
@ -97,72 +46,5 @@ fn bogo_ai_thinking(
let n_i = r % m.1.len();
let n_bi = m.1.iter().nth(n_i).unwrap();
(m_bi.clone(), n_bi.clone())
};
// Pick up selected piece
query
.iter()
.find_map(|(e, bi)| {
(*bi == from).then_some(e)
})
.iter()
.for_each(|e| {
commands.entity(*e).insert(Selected);
});
*selected = AiMove(Move { from, to: Some(to), ..default() });
// Pass off to next state in the "drama"
next_drama.set(AiDrama::Holding);
// Reset timer for next time
timer.reset();
}
}
fn bogo_ai_holding(
selected: Res<AiMove>,
time: Res<Time>,
mut timer: Local<Timer>,
mut board: ResMut<Board>,
mut move_events: EventWriter<Move>,
mut next_drama: ResMut<NextState<AiDrama>>,
tweaks: Res<Assets<Tweaks>>,
tweaks_file: Res<tweak::GameTweaks>,
) {
let tweak = tweaks
.get(tweaks_file.handle.clone())
.expect("Load tweakfile");
let lag = tweak.get::<f32>("ai_lag_secs").unwrap();
let timer_duration = Duration::from_secs_f32(lag);
// Initialize timer
if timer.duration() != timer_duration {
timer.set_duration(Duration::from_secs_f32(1.0));
timer.set_mode(TimerMode::Once);
}
// Timer before committing move
if !timer.finished() {
timer.tick(time.delta());
} else {
info!("AI Holding");
info!("Timer: {:?}", timer);
// Apply selected moves
board
.move_piece(selected.0.from, selected.0.to.unwrap())
.unwrap()
.iter()
.for_each(|ai_move| {
// De-select the piece
move_events.send(ai_move.clone());
});
// Pass off to next state in the "drama"
next_drama.set(AiDrama::Thinking);
timer.reset();
}
move_events.send(Move { from: *m_bi, to: Some(*n_bi), ..default() });
}

@ -85,18 +85,13 @@ impl Plugin for Display3dPlugin {
.run_if(resource_exists::<tweak::GameTweaks>),
switch_sides
.run_if(in_state(GameState::Play))
.run_if(state_changed::<game::TurnState>)
.run_if(in_state(ai::PlayState::Human)),
.run_if(state_changed::<game::TurnState>),
vantage_point
.run_if(in_state(GameState::Play))
.run_if(in_state(PlayState::AiBogo))
.run_if(in_state(TurnState(Side::B)))
.run_if(any_component_added::<Selected>().or_else(any_component_removed::<Selected>())),
vantage_point
.run_if(in_state(GameState::Play))
.run_if(in_state(PlayState::Human))
.run_if(not(state_changed::<TurnState>))
.run_if(any_component_added::<Selected>().or_else(any_component_removed::<Selected>())),
.run_if(not(state_changed::<game::TurnState>))
.run_if(any_component_added::<Selected>()
.or_else(any_component_removed::<Selected>())
),
update_pieces
.run_if(resource_exists::<tweak::GameTweaks>)
.run_if(in_state(GameState::Play))
@ -575,7 +570,7 @@ fn set_models(
let scene = tweak.get::<String>(key).unwrap();
let new_handle = gltf.named_scenes.get(scene.as_str()).expect("Game board model");
if *new_handle != *handle {
debug!("Updating piece for {:?}", entity);
info!("Updating piece for {:?}", entity);
*handle = new_handle.clone();
}
}

@ -22,11 +22,9 @@ impl Plugin for MenuPlugin {
handle_button_press::<GameState>,
handle_button_press::<MenuState>,
handle_button_press::<TutorialState>,
handle_button_press::<PlayState>,
)
.run_if(any_component_changed::<Interaction>()),
)
.add_systems(Update, manage_ai_button.run_if(state_changed::<ai::PlayState>))
.add_systems(Update, handle_escape.run_if(just_pressed(KeyCode::Escape)));
}
}
@ -203,44 +201,6 @@ fn init_play_menu(
});
});
// Opponent button
parent
.spawn((
ButtonAction(ai::PlayState::AiBogo),
ButtonBundle {
style: Style {
padding: UiRect::all(Val::Px(2.0)),
margin: UiRect::all(Val::Px(2.0)),
..default()
},
image: UiImage {
texture: button_handle.clone(),
..default()
},
..default()
},
))
.with_children(|parent| {
parent.spawn(TextBundle {
text: Text {
sections: vec![TextSection {
value: "Opponent: AI".into(),
style: TextStyle {
color: Color::WHITE,
font_size: 12.0,
font: font_handle.clone(),
},
}],
..default()
},
style: Style {
margin: UiRect::all(Val::Px(10.0)),
..default()
},
..default()
});
});
// Credits button
parent
.spawn((
@ -385,28 +345,3 @@ fn handle_button_press<S: States + Clone + Component>(
next_state.set(ba.clone())
});
}
fn manage_ai_button(
mut curr: Res<State<ai::PlayState>>,
mut query: Query<(&mut ButtonAction<PlayState>, &Children)>,
mut texts: Query<&mut Text>,
) {
query.iter_mut().for_each(|(mut ba, children)| {
ba.0 = match curr.get() {
PlayState::AiBogo => PlayState::Human,
PlayState::Human => PlayState::AiBogo,
};
children.iter().for_each(|c| {
texts.get_mut(*c).iter_mut().for_each(|t| {
t.sections.iter_mut().for_each(|s| {
s.value = match ba.0 {
PlayState::AiBogo => "Opponent: AI".into(),
PlayState::Human => "Opponent: Human".into()
}
});
});
});
});
}

Loading…
Cancel
Save