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 aces: Vec<Card>,
|
||||||
pub suits: Vec<u8>,
|
pub suits: Vec<u8>,
|
||||||
pub cards: Vec<CardMetadata>,
|
pub cards: Vec<CardMetadata>,
|
||||||
|
pub instantly_accepted: Vec<Card>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Setup {
|
pub struct Setup {
|
||||||
@ -89,6 +90,16 @@ impl Ruleset {
|
|||||||
cards.push(CardMetadata {suit: b'a', rank});
|
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 {
|
impl Deal {
|
||||||
pub fn deal(setup: &Setup, rng: &mut impl Rng) -> Deal {
|
pub fn deal(setup: &Setup, rng: &mut impl Rng) -> Deal {
|
||||||
|
let mut tries = 0;
|
||||||
loop {
|
loop {
|
||||||
if let Some(d) = Self::deal1(setup, rng) {
|
if let Some(d) = Self::deal1(setup, rng) {
|
||||||
|
println!("Generated ({} tries)", tries);
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
tries += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,7 +46,9 @@ impl Deal {
|
|||||||
if !is_arcana {
|
if !is_arcana {
|
||||||
// we can't put a card in the well if it's blocked, so make sure it's unblocked
|
// 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() {
|
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
|
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");
|
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
|
// do some moves from acceptors to random slots
|
||||||
const MAX_I: i32 = 48;
|
const MAX_I: i32 = 48;
|
||||||
for i in 0..MAX_I+1 {
|
for i in 0..MAX_I+1 {
|
||||||
let src = rng.gen_range(0..slots.len());
|
let src = rng.gen_range(0..slots.len());
|
||||||
if let Some(accepted_card) = Self::pop_accepted_card(setup, src, &mut slots) {
|
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,13 +82,17 @@ impl Deal {
|
|||||||
for i in 0..slots.len() {
|
for i in 0..slots.len() {
|
||||||
while slots[i].len() > max_height[i] {
|
while slots[i].len() > max_height[i] {
|
||||||
let card = slots[i].pop().expect("must be a card");
|
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
|
slots.remove(0); // get rid of the auxiliary slot
|
||||||
if !Self::fix_instantly_accepted(setup, &mut slots) {
|
for s in 0..slots.len() {
|
||||||
return None;
|
if setup.deck.instantly_accepted.contains(slots[s].last().expect("each slot must contain cards")) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for s in slots.iter() {
|
for s in slots.iter() {
|
||||||
@ -132,7 +150,7 @@ impl Deal {
|
|||||||
return (second_to_top, top);
|
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
|
// if a card is sitting on an acceptor, it could have been moved there
|
||||||
// from somewhere else
|
// from somewhere else
|
||||||
let mut acceptors = vec![];
|
let mut acceptors = vec![];
|
||||||
@ -144,6 +162,8 @@ impl Deal {
|
|||||||
for s in 0..slots.len() {
|
for s in 0..slots.len() {
|
||||||
if Some(s) == exclude {
|
if Some(s) == exclude {
|
||||||
// don't place it here, ever
|
// 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 {
|
} else {
|
||||||
if accepts(setup, slots[s].last().cloned(), card) {
|
if accepts(setup, slots[s].last().cloned(), card) {
|
||||||
acceptors.push(s);
|
acceptors.push(s);
|
||||||
@ -164,42 +184,12 @@ impl Deal {
|
|||||||
|
|
||||||
if let Some(a) = acceptor.or(start_point).or(source) {
|
if let Some(a) = acceptor.or(start_point).or(source) {
|
||||||
slots[a].push(card);
|
slots[a].push(card);
|
||||||
|
return true;
|
||||||
} else {
|
} else {
|
||||||
panic!("should not ever happen");
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pop_accepted_card(setup: &Setup, src: usize, slots: &mut [Vec<Card>]) -> Option<Card> {
|
fn pop_accepted_card(setup: &Setup, src: usize, slots: &mut [Vec<Card>]) -> Option<Card> {
|
||||||
let (card0, card1) = Self::peek2(&slots[src]);
|
let (card0, card1) = Self::peek2(&slots[src]);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user