A stupider dealer. More interesting boards?
This commit is contained in:
parent
24dbdb9a57
commit
a936329a55
@ -8,17 +8,6 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
fn deal1(setup: &Setup, rng: &mut impl Rng) -> Option<Deal> {
|
||||
let n_usable_cards = setup.ruleset.usable_n_cards();
|
||||
|
||||
// there are n - 1 final slots, because we don't use the middle one
|
||||
@ -39,41 +28,10 @@ impl Deal {
|
||||
let mut wells = Self::generate_wells(setup, rng);
|
||||
let mut pops = Self::plan_pops(&wells, rng);
|
||||
|
||||
while let Some(w) = pops.pop() {
|
||||
let is_arcana = w >= setup.ruleset.n_suits as usize;
|
||||
|
||||
let mut exclude = None;
|
||||
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() {
|
||||
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
|
||||
}
|
||||
|
||||
let card = wells[w].pop().expect("card must be present");
|
||||
|
||||
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) {
|
||||
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
|
||||
}
|
||||
}
|
||||
while let Some((w, n)) = pops.pop() {
|
||||
for _ in 0..n {
|
||||
let card = wells[w].pop().expect("card must be present");
|
||||
Self::find_home(setup, rng, card, None, None, &mut slots, &max_height, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,24 +40,28 @@ 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");
|
||||
if !Self::find_home(setup, rng, 0.0, card, None, None, &mut slots, &max_height) {
|
||||
return None
|
||||
}
|
||||
Self::find_home(setup, rng, card, None, None, &mut slots, &max_height, false);
|
||||
}
|
||||
}
|
||||
|
||||
slots.remove(0); // get rid of the auxiliary slot
|
||||
let mut shuffles = 0;
|
||||
for s in 0..slots.len() {
|
||||
if setup.deck.instantly_accepted.contains(slots[s].last().expect("each slot must contain cards")) {
|
||||
return None;
|
||||
let extra_shuf = shuffles + 1;
|
||||
while setup.deck.instantly_accepted.contains(slots[s].last().expect("each slot must contain cards")) {
|
||||
slots[s].shuffle(rng);
|
||||
shuffles = extra_shuf
|
||||
}
|
||||
}
|
||||
for _ in shuffles..2 {
|
||||
slots.choose_mut(rng).unwrap().shuffle(rng);
|
||||
}
|
||||
|
||||
for s in slots.iter() {
|
||||
assert_eq!(tower_height, s.len());
|
||||
}
|
||||
|
||||
return Some(Deal { slots } )
|
||||
return Deal { slots }
|
||||
}
|
||||
|
||||
fn generate_wells(setup: &Setup, rng: &mut impl Rng) -> Vec<Vec<Card>> {
|
||||
@ -132,7 +94,7 @@ impl Deal {
|
||||
wells
|
||||
}
|
||||
|
||||
fn plan_pops(wells: &[Vec<Card>], rng: &mut impl Rng) -> Vec<usize> {
|
||||
fn plan_pops(wells: &[Vec<Card>], rng: &mut impl Rng) -> Vec<(usize, usize)> {
|
||||
let mut pops = vec![];
|
||||
for (well, contents) in wells.iter().enumerate() {
|
||||
for _ in 0..contents.len() {
|
||||
@ -140,67 +102,58 @@ impl Deal {
|
||||
}
|
||||
}
|
||||
pops.shuffle(rng);
|
||||
pops
|
||||
|
||||
let mut rle = vec![];
|
||||
let mut current: Option<usize> = None;
|
||||
let mut count = 0;
|
||||
while let Some(nxt) = pops.pop() {
|
||||
if current == Some(nxt) && count < 4 {
|
||||
count += 1;
|
||||
} else {
|
||||
if let Some(prev) = current {
|
||||
rle.push((prev, count))
|
||||
}
|
||||
current = Some(nxt);
|
||||
count = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(prev) = current {
|
||||
if count > 0 {
|
||||
rle.push((prev, count))
|
||||
}
|
||||
}
|
||||
|
||||
rle
|
||||
}
|
||||
|
||||
fn peek2(stack: &Vec<Card>) -> (Option<Card>, Option<Card>) {
|
||||
let mut iter = stack.iter().rev();
|
||||
let top = iter.next().cloned();
|
||||
let second_to_top = iter.next().cloned();
|
||||
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]) -> bool {
|
||||
fn find_home(setup: &Setup, rng: &mut impl Rng, card: Card, source: Option<usize>, exclude: Option<usize>, slots: &mut [Vec<Card>], max_height: &[usize], allow_too_tall: bool) {
|
||||
// if a card is sitting on an acceptor, it could have been moved there
|
||||
// from somewhere else
|
||||
let mut acceptors = vec![];
|
||||
|
||||
// if a card is sitting on a start point, it could not have been moved
|
||||
// there from somewhere else
|
||||
let mut start_points = vec![];
|
||||
|
||||
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) {
|
||||
} else if false { // 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) {
|
||||
if allow_too_tall && accepts(setup, slots[s].last().cloned(), card) {
|
||||
acceptors.push(s);
|
||||
} else if slots[s].len() < max_height[s] {
|
||||
acceptors.push(s);
|
||||
}
|
||||
|
||||
if slots[s].len() < max_height[s] {
|
||||
start_points.push(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut acceptor = acceptors.choose(rng).cloned();
|
||||
let start_point = start_points.choose(rng).cloned();
|
||||
if !rng.gen_bool(acceptor_odds) {
|
||||
// don't use an acceptor even though we could
|
||||
acceptor = None;
|
||||
}
|
||||
let acceptor = acceptors.choose(rng).cloned();
|
||||
|
||||
if let Some(a) = acceptor.or(start_point).or(source) {
|
||||
if let Some(a) = acceptor.or(source) {
|
||||
slots[a].push(card);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
panic!("should never happen")
|
||||
}
|
||||
}
|
||||
|
||||
fn pop_accepted_card(setup: &Setup, src: usize, slots: &mut [Vec<Card>]) -> Option<Card> {
|
||||
let (card0, card1) = Self::peek2(&slots[src]);
|
||||
|
||||
if let Some(c1) = card1 {
|
||||
if accepts(&setup, card0, c1) {
|
||||
slots[src].pop().expect("we just peeked at this");
|
||||
return Some(c1);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn accepts(setup: &Setup, prev: Option<Card>, next: Card) -> bool {
|
||||
|
Loading…
Reference in New Issue
Block a user