better split ace logic; more args
This commit is contained in:
parent
1106f1484f
commit
b2115a4a7e
1 changed files with 27 additions and 14 deletions
41
src/main.rs
41
src/main.rs
|
|
@ -13,8 +13,8 @@ fn main() -> anyhow::Result<()> {
|
||||||
// TODO: Use anyhow for error handling, get rid of unwraps
|
// TODO: Use anyhow for error handling, get rid of unwraps
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
match args.mode {
|
match args.mode {
|
||||||
Mode::Interactive => interactive_play(args.show_count),
|
Mode::Interactive => interactive_play(args),
|
||||||
Mode::OldMan => old_man(),
|
Mode::OldMan => old_man(args),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -32,19 +32,23 @@ struct Args {
|
||||||
|
|
||||||
#[arg(long, default_value_t = false)]
|
#[arg(long, default_value_t = false)]
|
||||||
show_count: bool,
|
show_count: bool,
|
||||||
|
|
||||||
|
#[arg(long, default_value_t = 6)]
|
||||||
|
decks: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn interactive_play(show_count: bool) -> anyhow::Result<()> {
|
fn interactive_play(args: Args) -> anyhow::Result<()> {
|
||||||
// TODO: Make a way to reset bank
|
// TODO: Make a way to reset bank
|
||||||
let term = Term::stdout();
|
let term = Term::stdout();
|
||||||
let mut bank: u32 = load_bank()?.unwrap_or(1_000);
|
let mut bank: u32 = load_bank()?.unwrap_or(1_000);
|
||||||
|
|
||||||
let mut table = Table::new(6, bank).with_hit_on_soft_17();
|
let mut table = Table::new(args.decks, bank).with_hit_on_soft_17();
|
||||||
let mut last_bet: Option<u32> = None;
|
let mut last_bet: Option<u32> = None;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
println!("\nMoney in the bank: ${bank}");
|
println!("\nMoney in the bank: ${bank}");
|
||||||
if show_count {
|
// TODO: show normalized card count
|
||||||
|
if args.show_count {
|
||||||
println!("Card count: {}", table.count());
|
println!("Card count: {}", table.count());
|
||||||
println!("Cards in shoe: {}", table.shoe_count());
|
println!("Cards in shoe: {}", table.shoe_count());
|
||||||
}
|
}
|
||||||
|
|
@ -84,7 +88,7 @@ fn interactive_play(show_count: bool) -> anyhow::Result<()> {
|
||||||
println!();
|
println!();
|
||||||
|
|
||||||
let mut turn = table.deal_hand(bet);
|
let mut turn = table.deal_hand(bet);
|
||||||
let split_turn = interactive_play_turn(&mut turn, &mut table, show_count)?;
|
let split_turn = interactive_play_turn(&mut turn, &mut table, args.show_count)?;
|
||||||
if split_turn.is_none() {
|
if split_turn.is_none() {
|
||||||
table.dealers_turn()?;
|
table.dealers_turn()?;
|
||||||
let result = table.results(turn)?;
|
let result = table.results(turn)?;
|
||||||
|
|
@ -92,7 +96,7 @@ fn interactive_play(show_count: bool) -> anyhow::Result<()> {
|
||||||
print_result(&result);
|
print_result(&result);
|
||||||
} else {
|
} else {
|
||||||
let mut split_turn = split_turn.unwrap();
|
let mut split_turn = split_turn.unwrap();
|
||||||
interactive_play_turn(&mut split_turn, &mut table, show_count)?;
|
interactive_play_turn(&mut split_turn, &mut table, args.show_count)?;
|
||||||
table.dealers_turn()?;
|
table.dealers_turn()?;
|
||||||
let result = table.results(turn)?;
|
let result = table.results(turn)?;
|
||||||
let split_result = table.results(split_turn)?;
|
let split_result = table.results(split_turn)?;
|
||||||
|
|
@ -215,7 +219,6 @@ fn print_result(result: &EndState) {
|
||||||
println!("You got: ${}", result.returns);
|
println!("You got: ${}", result.returns);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Make this use a lookup table, this if logic is gnarly
|
|
||||||
fn basic_strategy(
|
fn basic_strategy(
|
||||||
hand: &Hand,
|
hand: &Hand,
|
||||||
dealer_showing: &Card,
|
dealer_showing: &Card,
|
||||||
|
|
@ -229,9 +232,8 @@ fn basic_strategy(
|
||||||
// Got a pair, maybe should split
|
// Got a pair, maybe should split
|
||||||
// We check can_split right at the get-go, because if we can't we just follow the Hard
|
// We check can_split right at the get-go, because if we can't we just follow the Hard
|
||||||
// Total table.
|
// Total table.
|
||||||
let aces = hand.cards()[0].value == "A";
|
|
||||||
match hand.value() {
|
match hand.value() {
|
||||||
12 if aces => PlayerChoice::Split,
|
12 if hand.has_ace() => PlayerChoice::Split,
|
||||||
20 => PlayerChoice::Stand,
|
20 => PlayerChoice::Stand,
|
||||||
18 => match dv {
|
18 => match dv {
|
||||||
2..=6 => PlayerChoice::Split,
|
2..=6 => PlayerChoice::Split,
|
||||||
|
|
@ -353,7 +355,7 @@ fn basic_strategy_play_turn(
|
||||||
/// addition to points/comps which he would use to eat brunch for free.
|
/// addition to points/comps which he would use to eat brunch for free.
|
||||||
///
|
///
|
||||||
/// Does this actually work, or was the driver full of it?
|
/// Does this actually work, or was the driver full of it?
|
||||||
fn old_man() -> anyhow::Result<()> {
|
fn old_man(args: Args) -> anyhow::Result<()> {
|
||||||
const START: u32 = 100_000;
|
const START: u32 = 100_000;
|
||||||
const PER_DAY: u32 = 400;
|
const PER_DAY: u32 = 400;
|
||||||
const MIN_BET: u32 = 15;
|
const MIN_BET: u32 = 15;
|
||||||
|
|
@ -361,7 +363,7 @@ fn old_man() -> anyhow::Result<()> {
|
||||||
// Walk away when we're up by this much
|
// Walk away when we're up by this much
|
||||||
const MAX_WIN: u32 = 100;
|
const MAX_WIN: u32 = 100;
|
||||||
// Walk away when we're down by this much
|
// Walk away when we're down by this much
|
||||||
const MAX_LOSS: u32 = MAX_WIN;
|
const MAX_LOSS: u32 = 100;
|
||||||
// Run sim for this many days
|
// Run sim for this many days
|
||||||
const DAYS: u16 = 30;
|
const DAYS: u16 = 30;
|
||||||
|
|
||||||
|
|
@ -372,7 +374,7 @@ fn old_man() -> anyhow::Result<()> {
|
||||||
for day in 1..=DAYS {
|
for day in 1..=DAYS {
|
||||||
bank -= PER_DAY;
|
bank -= PER_DAY;
|
||||||
|
|
||||||
let mut table = Table::new(6, PER_DAY).with_hit_on_soft_17();
|
let mut table = Table::new(args.decks, PER_DAY).with_hit_on_soft_17();
|
||||||
let mut rounds = 0;
|
let mut rounds = 0;
|
||||||
while table.player_chips() > MIN_BET
|
while table.player_chips() > MIN_BET
|
||||||
&& table.player_chips() < (PER_DAY + MAX_WIN)
|
&& table.player_chips() < (PER_DAY + MAX_WIN)
|
||||||
|
|
@ -465,6 +467,17 @@ mod tests {
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
PlayerChoice::Stand,
|
PlayerChoice::Stand,
|
||||||
)
|
);
|
||||||
|
|
||||||
|
// Always split aces
|
||||||
|
assert_eq!(
|
||||||
|
basic_strategy(
|
||||||
|
&Hand::from([("", "A"), ("", "A")].to_vec()),
|
||||||
|
&Card::from(("", "2")),
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
PlayerChoice::Split,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue