Simplify the better dealer
This commit is contained in:
parent
bff92e51ab
commit
37d39b4521
@ -11,6 +11,7 @@ pub struct Deck {
|
||||
pub aces: Vec<Card>,
|
||||
pub suits: Vec<u8>,
|
||||
pub cards: Vec<CardMetadata>,
|
||||
pub instantly_accepted: Vec<Card>,
|
||||
}
|
||||
|
||||
pub struct Setup {
|
||||
@ -89,6 +90,16 @@ impl Ruleset {
|
||||
cards.push(CardMetadata {suit: b'a', rank});
|
||||
}
|
||||
|
||||
Deck { aces, suits, cards }
|
||||
|
||||
// instantly accepted
|
||||
let first_arcana = self.n_suits * self.n_cards_per_suit;
|
||||
let mut instantly_accepted = vec![];
|
||||
for a in aces.iter() {
|
||||
instantly_accepted.push(Card(a.0 + 1)) // twos
|
||||
}
|
||||
instantly_accepted.push(Card(first_arcana));
|
||||
instantly_accepted.push(Card(first_arcana + self.n_arcana - 1));
|
||||
|
||||
Deck { aces, suits, cards, instantly_accepted }
|
||||
}
|
||||
}
|
@ -8,10 +8,13 @@ pub struct Deal {
|
||||
|
||||
impl Deal {
|
||||
pub fn deal(setup: &Setup, rng: &mut impl Rng) -> Deal {
|
||||
let mut tries = 0;
|
||||
loop {
|
||||
if let Some(d) = Self::deal1(setup, rng) {
|
||||
println!("Generated ({} tries)", tries);
|
||||
return d;
|
||||
}
|
||||
tries += 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,7 +46,9 @@ impl Deal {
|
||||
if !is_arcana {
|
||||
// we can't put a card in the well if it's blocked, so make sure it's unblocked
|
||||
if let Some(c) = slots[0].pop() {
|
||||
Self::find_home(setup, rng, 1.0, c, None, Some(0), &mut slots, &max_height);
|
||||
if !Self::find_home(setup, rng, 1.0, c, None, Some(0), &mut slots, &max_height) {
|
||||
return None
|
||||
}
|
||||
}
|
||||
|
||||
exclude = Some(0); // don't place the new card in the auxiliary slot
|
||||
@ -51,14 +56,23 @@ impl Deal {
|
||||
|
||||
let card = wells[w].pop().expect("card must be present");
|
||||
|
||||
Self::find_home(setup, rng, 1.0, card, None, exclude, &mut slots, &max_height);
|
||||
if !Self::find_home(setup, rng, 1.0, card, None, exclude, &mut slots, &max_height) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// do some moves from acceptors to random slots
|
||||
const MAX_I: i32 = 48;
|
||||
for i in 0..MAX_I+1 {
|
||||
let src = rng.gen_range(0..slots.len());
|
||||
if let Some(accepted_card) = Self::pop_accepted_card(setup, src, &mut slots) {
|
||||
Self::find_home(setup, rng, ((MAX_I - i) as f64)/(MAX_I as f64), accepted_card, Some(src), None, &mut slots, &max_height);
|
||||
let odds = ((MAX_I - i) as f64)/(MAX_I as f64);
|
||||
if !Self::find_home(
|
||||
setup, rng,
|
||||
odds,
|
||||
accepted_card, Some(src), None, &mut slots, &max_height
|
||||
) {
|
||||
return None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -68,14 +82,18 @@ impl Deal {
|
||||
for i in 0..slots.len() {
|
||||
while slots[i].len() > max_height[i] {
|
||||
let card = slots[i].pop().expect("must be a card");
|
||||
Self::find_home(setup, rng, 0.0, card, None, None, &mut slots, &max_height);
|
||||
if !Self::find_home(setup, rng, 0.0, card, None, None, &mut slots, &max_height) {
|
||||
return None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
slots.remove(0); // get rid of the auxiliary slot
|
||||
if !Self::fix_instantly_accepted(setup, &mut slots) {
|
||||
for s in 0..slots.len() {
|
||||
if setup.deck.instantly_accepted.contains(slots[s].last().expect("each slot must contain cards")) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
for s in slots.iter() {
|
||||
assert_eq!(tower_height, s.len());
|
||||
@ -132,7 +150,7 @@ impl Deal {
|
||||
return (second_to_top, top);
|
||||
}
|
||||
|
||||
fn find_home(setup: &Setup, rng: &mut impl Rng, acceptor_odds: f64, card: Card, source: Option<usize>, exclude: Option<usize>, slots: &mut [Vec<Card>], max_height: &[usize]) {
|
||||
fn find_home(setup: &Setup, rng: &mut impl Rng, acceptor_odds: f64, card: Card, source: Option<usize>, exclude: Option<usize>, slots: &mut [Vec<Card>], max_height: &[usize]) -> bool {
|
||||
// if a card is sitting on an acceptor, it could have been moved there
|
||||
// from somewhere else
|
||||
let mut acceptors = vec![];
|
||||
@ -144,6 +162,8 @@ impl Deal {
|
||||
for s in 0..slots.len() {
|
||||
if Some(s) == exclude {
|
||||
// don't place it here, ever
|
||||
} else if slots[s].len() == max_height[s] - 1 && setup.deck.instantly_accepted.contains(&card) {
|
||||
// can't place an instantly accepted card at the bottom of a slot
|
||||
} else {
|
||||
if accepts(setup, slots[s].last().cloned(), card) {
|
||||
acceptors.push(s);
|
||||
@ -164,40 +184,10 @@ impl Deal {
|
||||
|
||||
if let Some(a) = acceptor.or(start_point).or(source) {
|
||||
slots[a].push(card);
|
||||
} else {
|
||||
panic!("should not ever happen");
|
||||
}
|
||||
}
|
||||
|
||||
fn fix_instantly_accepted(setup: &Setup, slots: &mut [Vec<Card>]) -> bool {
|
||||
let first_arcana = setup.ruleset.n_suits * setup.ruleset.n_cards_per_suit;
|
||||
let mut instantly_accepted = vec![];
|
||||
for &a in &setup.deck.aces {
|
||||
instantly_accepted.push(Card(a.0 + 1)) // twos
|
||||
}
|
||||
instantly_accepted.push(Card(first_arcana));
|
||||
instantly_accepted.push(Card(first_arcana + setup.ruleset.n_arcana - 1));
|
||||
|
||||
for s in 0..slots.len() {
|
||||
let (second_to_last, last) = Self::peek2(&slots[s]);
|
||||
|
||||
if let Some(last) = last {
|
||||
if instantly_accepted.contains(&last) {
|
||||
if let Some(c) = second_to_last {
|
||||
if instantly_accepted.contains(&c) {
|
||||
return false
|
||||
}
|
||||
|
||||
let n = slots[s].len();
|
||||
(slots[s][n-2],slots[s][n-1]) = (last, c);
|
||||
}
|
||||
else {
|
||||
return false; // confusing nonsense situation
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
fn pop_accepted_card(setup: &Setup, src: usize, slots: &mut [Vec<Card>]) -> Option<Card> {
|
||||
|
Loading…
Reference in New Issue
Block a user