Further improvements to the smart dealer
This commit is contained in:
parent
89b0dce6b9
commit
0b3d45378f
@ -1,6 +1,6 @@
|
||||
progression={
|
||||
-- level 1
|
||||
--ruleset:new(5,1,9,0),
|
||||
-- ruleset:new(5,1,9,0),
|
||||
-- level 2
|
||||
-- ruleset:new(5,2,9,0),
|
||||
-- level 3
|
||||
|
@ -80,13 +80,21 @@ impl<'a> Board<'a> {
|
||||
}
|
||||
|
||||
pub fn display(&self) {
|
||||
fn display_cards(setup: &Setup, cards: &[Card]) {
|
||||
print!("- ");
|
||||
for c in cards {
|
||||
let meta = setup.deck.cards[c.0 as usize];
|
||||
print!("{}{:02} ", meta.suit as char, meta.rank);
|
||||
}
|
||||
print!("\n");
|
||||
}
|
||||
println!("Wells:");
|
||||
for w in &self.wells {
|
||||
println!("- {:?}", w.contents);
|
||||
display_cards(self.setup, &w.contents);
|
||||
}
|
||||
println!("\nSlots:");
|
||||
for s in &self.slots {
|
||||
println!("- {:?}", s.contents);
|
||||
display_cards(self.setup, &s.contents);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,21 +12,21 @@ mod zobrist;
|
||||
|
||||
|
||||
fn main() {
|
||||
/*
|
||||
let ruleset = Ruleset {
|
||||
n_slots: 11,
|
||||
n_suits: 5,
|
||||
n_cards_per_suit: 10,
|
||||
n_arcana: 25
|
||||
};
|
||||
/*
|
||||
*/
|
||||
let ruleset = Ruleset {
|
||||
n_slots: 11,
|
||||
n_suits: 4,
|
||||
n_cards_per_suit: 13,
|
||||
n_arcana: 22
|
||||
};
|
||||
*/
|
||||
/*
|
||||
/*
|
||||
let ruleset = Ruleset {
|
||||
n_slots: 5,
|
||||
n_suits: 1,
|
||||
@ -51,11 +51,25 @@ fn main() {
|
||||
};
|
||||
*/
|
||||
let setup = ruleset.compile().expect("compilation should succeed");
|
||||
let mut board = Board::new(&setup);
|
||||
board.deal(Deal::deal(&setup, &mut rand::thread_rng()));
|
||||
board.display();
|
||||
/*
|
||||
for _ in 0..10000 {
|
||||
Deal::deal(&setup, &mut rand::thread_rng());
|
||||
}
|
||||
*/
|
||||
|
||||
println!("is_winnable: {}", is_winnable(board));
|
||||
let mut winnable = 0;
|
||||
let mut total = 0;
|
||||
loop {
|
||||
let mut board = Board::new(&setup);
|
||||
board.deal(Deal::deal(&setup, &mut rand::thread_rng()));
|
||||
board.display();
|
||||
|
||||
if is_winnable(board) {
|
||||
winnable += 1;
|
||||
}
|
||||
total += 1;
|
||||
println!("winnable: {}/{} ({}%)", winnable, total, (100.0 * winnable as f32)/(total as f32));
|
||||
}
|
||||
|
||||
// println!("Legal moves: {:#?}", board.legal_moves());
|
||||
|
||||
|
@ -17,10 +17,11 @@ impl Deal {
|
||||
fn deal1(setup: &Setup, rng: &mut impl Rng) -> Option<Deal> {
|
||||
// don't use the middle slot
|
||||
let n_slots = (setup.ruleset.n_slots - 1) as usize;
|
||||
let aux_slot = n_slots;
|
||||
let n_usable_cards = setup.ruleset.usable_n_cards();
|
||||
let tower_height = n_usable_cards as usize / n_slots;
|
||||
|
||||
let mut slots: Vec<Vec<Card>> = vec![vec![]; n_slots];
|
||||
let mut slots: Vec<Vec<Card>> = vec![vec![]; n_slots+1];
|
||||
|
||||
let split_point =
|
||||
if setup.ruleset.n_arcana == 0 { 0 }
|
||||
@ -53,37 +54,41 @@ impl Deal {
|
||||
}
|
||||
pops.shuffle(rng);
|
||||
|
||||
while let Some(w) = pops.pop() {
|
||||
fn find_home(card: Card, exclude: Option<usize>, setup: &Setup, slots: &mut [Vec<Card>], tower_height: usize, rng: &mut impl Rng) {
|
||||
let mut acceptors = vec![];
|
||||
let mut not_full = vec![];
|
||||
for s in 0..slots.len() {
|
||||
if Some(s) != exclude && slots[s].len() < tower_height {
|
||||
if accepts(setup, slots[s].last().cloned(), card) {
|
||||
acceptors.push(s)
|
||||
}
|
||||
fn find_home(card: Card, exclude: Option<usize>, setup: &Setup, slots: &mut [Vec<Card>], aux_slot: usize, tower_height: usize, rng: &mut impl Rng) {
|
||||
let mut acceptors = vec![];
|
||||
let mut not_full = vec![];
|
||||
for s in 0..slots.len() {
|
||||
let not_too_tall = slots[s].len() < if s == aux_slot { 1 } else { tower_height };
|
||||
if Some(s) != exclude {
|
||||
if not_too_tall && accepts(setup, slots[s].last().cloned(), card) {
|
||||
acceptors.push(s)
|
||||
}
|
||||
if not_too_tall {
|
||||
not_full.push(s);
|
||||
}
|
||||
}
|
||||
|
||||
acceptors.shuffle(rng);
|
||||
not_full.shuffle(rng);
|
||||
if rng.gen_bool(0.5) && acceptors.len() > 0 {
|
||||
let a = acceptors.first().unwrap();
|
||||
slots[*a].push(card);
|
||||
} else if let Some(a) = not_full.first() {
|
||||
slots[*a].push(card);
|
||||
} else if let Some(e) = exclude {
|
||||
slots[e].push(card)
|
||||
} else {
|
||||
panic!("should not ever happen")
|
||||
}
|
||||
}
|
||||
|
||||
acceptors.shuffle(rng);
|
||||
not_full.shuffle(rng);
|
||||
if rng.gen_bool(0.5) && acceptors.len() > 0 {
|
||||
let a = acceptors.first().unwrap();
|
||||
slots[*a].push(card);
|
||||
} else if let Some(a) = not_full.first() {
|
||||
slots[*a].push(card);
|
||||
} else if let Some(e) = exclude {
|
||||
slots[e].push(card)
|
||||
} else {
|
||||
panic!("should not ever happen")
|
||||
}
|
||||
}
|
||||
|
||||
while let Some(w) = pops.pop() {
|
||||
let card = virtual_wells[w].pop().expect("card must be present");
|
||||
find_home(card, None, setup, &mut slots, tower_height, rng);
|
||||
find_home(card, None, setup, &mut slots, aux_slot, tower_height, rng);
|
||||
|
||||
// move any card that is on an acceptor to a random slot
|
||||
for _ in 0..4 {
|
||||
for _ in 0..15 {
|
||||
let mut sources: Vec<usize> = (0..slots.len()).collect();
|
||||
sources.shuffle(rng);
|
||||
for src in sources {
|
||||
@ -94,13 +99,19 @@ impl Deal {
|
||||
if let Some(t) = top {
|
||||
if accepts(&setup, second_to_top, t) {
|
||||
slots[src].pop();
|
||||
find_home(t, Some(src), setup, &mut slots, tower_height, rng);
|
||||
find_home(t, Some(src), setup, &mut slots, aux_slot, tower_height, rng);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(top) = slots[n_slots].pop() {
|
||||
assert!(slots[n_slots].len() == 0);
|
||||
find_home(top, Some(n_slots), setup, &mut slots, aux_slot, tower_height, rng);
|
||||
assert!(slots[n_slots].len() == 0);
|
||||
}
|
||||
|
||||
let mut instantly_accepted = vec![];
|
||||
for &a in &setup.deck.aces {
|
||||
instantly_accepted.push(Card(a.0 + 1)) // twos
|
||||
@ -108,9 +119,7 @@ impl Deal {
|
||||
instantly_accepted.push(Card(first_arcana));
|
||||
instantly_accepted.push(Card(first_arcana + setup.ruleset.n_arcana - 1));
|
||||
|
||||
// NOTE: We never used the free cell. The free cell can dig one deeper
|
||||
// So in theory most of these deals should be solvable using the freecell
|
||||
for s in 0..slots.len() {
|
||||
for s in 0..n_slots {
|
||||
let mut iter = slots[s].iter().rev();
|
||||
let last = iter.next().cloned();
|
||||
let second_to_last = iter.next().cloned();
|
||||
@ -132,6 +141,13 @@ impl Deal {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for s in 0..n_slots {
|
||||
assert!(slots[s].len() == tower_height)
|
||||
}
|
||||
|
||||
slots.pop(); // get rid of aux slot
|
||||
|
||||
return Some(Deal { slots });
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user