Simplified dealing logic so we always have one set

main
Elijah Voigt 1 year ago
parent e1d438a189
commit 83c15f7c64

1
Cargo.lock generated

@ -3564,6 +3564,7 @@ name = "set"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"bevy", "bevy",
"rand",
"wasm-bindgen", "wasm-bindgen",
] ]

@ -6,6 +6,7 @@ edition = "2021"
[dependencies] [dependencies]
wasm-bindgen = { version = "= 0.2.95" } wasm-bindgen = { version = "= 0.2.95" }
bevy = "0.15" bevy = "0.15"
rand = "0.8.5"
[profile.dev] [profile.dev]
opt-level = 1 opt-level = 1

@ -52,16 +52,16 @@ impl Deck {
} }
pub(crate) fn shuffled() -> Vec<Card> { pub(crate) fn shuffled() -> Vec<Card> {
let rs = RandomState::new();
let mut base = Self::cards(); let mut base = Self::cards();
let len = base.len();
(1..len).into_iter().for_each(|i| { {
let a = rs.hash_one(base[i]) % (len as u64); use rand::seq::SliceRandom;
let b = rs.hash_one(base[i - 1]) % (len as u64); use rand::thread_rng;
if a > b {
base.swap(a as usize, b as usize); let mut rng = thread_rng();
base.as_mut_slice().shuffle(&mut rng);
} }
});
base base
} }

@ -6,9 +6,11 @@ pub struct PlayPlugin;
impl Plugin for PlayPlugin { impl Plugin for PlayPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.add_observer(serve_new_cards) app.add_event::<ServeCards>()
.add_systems(OnEnter(GameState::Main), serve_cards) .add_observer(serve_cards)
.add_systems(Update, rotate_cards); .add_observer(fill_cards)
.add_systems(OnEnter(GameState::Main), deal_table)
.add_systems(Update, spin_cards);
} }
} }
@ -32,7 +34,7 @@ pub(crate) struct PlayLocation {
pub(crate) struct SetNumber(pub u8); pub(crate) struct SetNumber(pub u8);
/// Debug system rotating selected cards for visual flare /// Debug system rotating selected cards for visual flare
fn rotate_cards(mut query: Query<&mut Transform, (With<Card>, With<Selected>)>, time: Res<Time>) { fn spin_cards(mut query: Query<&mut Transform, (With<Card>, With<Selected>)>, time: Res<Time>) {
let dt = time.delta().as_secs_f32(); let dt = time.delta().as_secs_f32();
query.iter_mut().for_each(|mut t| { query.iter_mut().for_each(|mut t| {
t.rotate_z(dt * 0.5); t.rotate_z(dt * 0.5);
@ -116,12 +118,17 @@ fn is_set((a, b, c): (&Card, &Card, &Card)) -> bool {
color && number && pattern && shape color && number && pattern && shape
} }
#[derive(Event, Clone)]
struct ServeCards;
/// When requested, fill in empty spots on the board with cards /// When requested, fill in empty spots on the board with cards
fn serve_cards( fn serve_cards(
_trigger: Trigger<ServeCards>,
cards: Query<(Entity, &DeckOrder)>, cards: Query<(Entity, &DeckOrder)>,
spots: Query<&PlayLocation>, spots: Query<&PlayLocation>,
mut commands: Commands, mut commands: Commands,
) { ) {
info!("Serving cards");
let mut target = (cards.iter().len() - 1) as u8; let mut target = (cards.iter().len() - 1) as u8;
// Iterate over every x, y play location // Iterate over every x, y play location
for this_x in 0..=3 { for this_x in 0..=3 {
@ -148,36 +155,16 @@ fn serve_cards(
} }
} }
fn serve_new_cards( /// Trigger dealing cards when the game starts
_trigger: Trigger<OnAdd, SetNumber>, fn deal_table(mut commands: Commands) {
cards: Query<(Entity, &DeckOrder)>, info!("Dealing table");
spots: Query<&PlayLocation>, commands.trigger(ServeCards);
mut commands: Commands, }
) {
let mut target = (cards.iter().len() - 1) as u8; /// Trigger serving cards when a new set is created
// Iterate over every x, y play location fn fill_cards(_trigger: Trigger<OnAdd, SetNumber>, mut commands: Commands) {
for this_x in 0..=3 { info!("Filling cards");
for this_y in 0..=3 { commands.trigger(ServeCards);
// If this spot does not have a card
if spots
.iter()
.find(|PlayLocation { x, y }| *x == (this_x as u8) && *y == (this_y as u8))
.is_none()
{
if let Some((e, _)) = cards.iter().find(|(_, deck_order)| deck_order.0 == target) {
// Set the selected card to this play location and remove from the deck
commands
.entity(e)
.remove::<DeckOrder>()
.insert(PlayLocation {
x: this_x,
y: this_y,
});
target = target - 1;
}
}
}
}
} }
/// When a card is added to the board, place it on the screen /// When a card is added to the board, place it on the screen
@ -207,7 +194,7 @@ pub(crate) fn check_for_sets(
selected: Query<Entity, With<Selected>>, selected: Query<Entity, With<Selected>>,
mut commands: Commands, mut commands: Commands,
) { ) {
cards let candidate = cards
// Iterate over all combinations of cards on the board // Iterate over all combinations of cards on the board
.iter_combinations() .iter_combinations()
// Only find combinations including currently selected cards // Only find combinations including currently selected cards
@ -237,17 +224,19 @@ pub(crate) fn check_for_sets(
} else { } else {
None None
} }
}) });
.iter()
.for_each(|(a, b, c)| { if let Some((a, b, c)) = candidate {
if !selected.contains(*a) { if !selected.contains(a) {
commands.entity(*a).insert(Selected); commands.entity(a).insert(Selected);
} else if !selected.contains(*b) { } else if !selected.contains(b) {
commands.entity(*b).insert(Selected); commands.entity(b).insert(Selected);
} else if !selected.contains(*c) { } else if !selected.contains(c) {
commands.entity(*c).insert(Selected); commands.entity(c).insert(Selected);
} else { } else {
info!("I cannot hold your hand further..."); info!("I cannot hold your hand further...");
} }
}); } else {
info!("No sets!");
}
} }

@ -1,20 +1,10 @@
TODO: TODO:
* Reset game (click new game button) * "New Game" button
* Track score (number of sets) * Print "no set"/"too many cards" alert
* Make button(s) look pretty * Guarentee there is always a set
* Make buttons react to hover/click! * Better shuffling
* Music!
* Background!
* Print "no set"/"too many cards" messages
* Add "quit game" button
* View all cards with some indication of in-set
* Menu
* About/Credits
* How To Play
Exclude for now:
* deck
* sets
Exclude in wasm: Later:
* quit * View all cards with some indication of in-set
* Music!
* Make button(s) look pretty

Loading…
Cancel
Save