\*Here is the program bj-strat, which calculates blackjackstrategy numbers.  The program reads the point count values for cardsfrom the command line, and prints the corresponding count strategy onthe standard output.  Running time for the program is approximately twominutes on the VS-2000, for the Hi-Opt I or Wong High-Low strategy, forthe count range +/- 10, if the infinite deck approximation is used.  Fora finite number of decks, the time required is roughly 35 minutes, forthe range +/- 6.Usage:        The first ten arguments to the program should be the pointvalues of the cards two through ace.  After the card values, thefollowing additional arguments are permitted, in any order:-a value        value of ace in side count-n decks        number of decks (infinite deck approximation if omitted)-d              double-on-splits is allowed-h              dealer hits soft 17-r low high     only consider true count values from low to high, inclusive-s step         only consider true count values that are multiples of stepUse the -a option if a side count is used for *playing* purposes.  Thevalue of the ace is is the number of points to add to the runningcount for each ``missing'' ace, i.e. if 26 cards are left and no acesare left, add 2 * value to the running count.  Do *not* use this optionif a side count is used for *betting* purposes.        If the -r and -s options are omitted, the program considersthe full range of count values.Examples:1) Hi-Opt I numbers from -6 to 6; double on splits allowed, single deck:bj-strat 0 1 1 1 1 0 0 0 -1 0  -d  -n 1  -r -6 62) High-Low with ace side count, -10 to +10 range, 2 decks:bj-strat 1 1 1 1 1 0 0 0 -1 -1  -n 2  -a 1  -r -10 103) Wong halves numbers from -20 to +20; dealer hits soft 17, infinite deck:bj-strat 1 2 2 3 2 1 0 -1 -2 -2  -h  -r -40 40  -s 2Output numbers must be divided by 2 in this case, because the halvescount actually uses card values 1/2 to 1 1/2, not 1 to 3.  This methodis used because the program only accepts integer card values.Output:        In the output, the symbol * next to a number indicates thatthe strategy changes in the opposite direction from that normallyexpected, e.g. if the number 7* appears in the pair split table, youshould split only when the count is less than 7.  The notation a/bindicates that the player should stand/double/split when the count isin the range from a to b; the notation a^b indicates that the playershould stand/double/split _unless_ the count is between a and b.        I have commented out the program lines that print ranges.Currently, the program only prints the strategy change number closestto zero if a range of numbers is involved.  These lines are near theend of the of the program, and can be uncommented to print ranges, ifdesired.        The more extreme values in the strategy tables (e.g. greaterthan +/- 20 for High-Low or Hi-Opt I) probably should not be taken tooseriously.  The approximation used to generate decks with specifiedpoint counts tends to break down at extreme values.How it works:        The approach used in the program is fairly straightforward.First, I generate a ``typical'' deck for each true count in the rangeI'm interested in.  Next, I assume I have an infinite deck of thiscomposition.  I calculate the player's ideal strategy for each ofthese decks, and look for the point count(s) at which the correctstrategy for a situation changes.        The assumption of an infinite deck simplifies the calculationsand saves computer time, but introduces a small amount of inaccuracy.My results should be good for multiple deck play, and may also beadequate for single deck.  (Last summer, during the BJ comparisoncontest, Matt Wilding found no measurable difference in performancebetween my strategy numbers for the Hi-Opt I and the publishednumbers).        I use the following formula to construct a ``typical'' deckfor a given true count.  It is based on altering the frequency ofcards in proportion to their point values in the counting system,until the desired true count is achieved.  (Stanford Wong and PeterGriffin used similar formulas in their work).  This formula assumesthat the count is balanced, i.e. the point value of a complete deck iszero.Let Fo[i] = proportion of cards of rank i in a normal deck,            i.e. 4/13 if i=10, 1/13 if 2 <= i <= 9 or i = AceLet Fj[i] be the proportion of cards of rank i in a ``typical''            deck with a true count of jLet V[i] be the point value for card i in the counting systemthen Fj[i] = Fo[i] * (1 - (j/52)*V[i]/SS)     where SS = sum over i in 2..Ace of Fo[i] * V[i]**2        The above formula is used for the infinite deck approximation.To approximate a finite number of decks, I first remove the dealer'supcard and player's cards, if known, from a finite deck.  I then adjustcards' frequencies in proportion to their point count values.  Finally,I assume I have an infinite deck of the resulting composition.  (Thisis what Stanford Wong did to estimate strategy numbers for a finite deck).        If an ace side count is used, I combine the main count andside count into a single point count system Vc, and use Vc instead ofV in all calculations.  Let Va be the value of the ace in the sidecount (zero if a side count is not used).then Vc[i]   = V[i] - Va / 13, for i in 2..10     Vc[Ace] = V[Ace] + (12/13) * Va        To determine the correct strategy for a given deck, I performan exact probability calculation (i.e. simulation is not used at all).I calculate the player's expectation standing on a given hand vs. agiven dealer hand as follows:standing_value(p, d) =  if (dealer stands on d) then    if (p beats d) then +1    else if (d beats p) then -1    else 0  else <--- dealer hits    sum over c in 2..ace      probablity[c] * standing_value(p, d + c)Each value calculated is stored in a table, to avoid calculating thesame values twice.  The program tries to look up the answer in thetable first, and performs the calculation only if necessary.        The player's expectation hitting is calculated as follows:hitting_value(p, d) =  sum over c in 2..ace    if (p + c is over 21) then probability[c] * -1    else      probability[c] * maximum(hitting_value (p + c, d),                               standing_value(p + c, d))        Hitting values are also stored in a table, to avoid redundantcalculations.   The strategy calls for a player to hit if his hittingvalue is greater than his standing value.        Constructing tables for doubling down and splitting isstraightforward; the hit and stand tables make it easy to compute thevalues for the other tables. *//* -------------------------------------------------------------------- *//* Copyright (c) 1990, 1991  Steven C. Markowitz.  All rights reserved. */#include <stdio.h>#define ACE 11#define FALSE 0#define TRUE 1#define HARD 0#define SOFT 1#define OVER 2#define DUMMY 0#ifdef __STDC__extern void *calloc();#define FREE(x) free((void *) (x))#elseextern char *calloc();#define FREE(x) free((char *) (x))#endiffloat max(x, y)     double x, y;{  return ((x > y) ? x : y);}float min(x, y)     double x, y;{  return ((x < y) ? x : y);}typedef int boolean;typedef int Card;typedef float Deck[12];  /* deck[i] = proportion of cards in deck                         that are of type i.  Deck[0] and deck[1]                         are not used. */typedef float Method[12]; /* method [i] = point value of card i in                           counting method.  Method[0] and method[1]                           are not used. *//* A total represents a blackjack hand;   it may be hard, soft or over 21 */typedef  struct {    int tag;    int value;  } Total;/* A table holds real numbers.  Some table elements may not have been   calculated yet; this is indicated by the unknown flag.  */#define TOTALS 32 /* number of distinct blackjack totals */#define CARDS  10 /* number different types of cards in a deck */typedef  struct {    boolean unknown;    float value;  } Mfloat;typedef Mfloat **Table;/* A strategy describes the correct strategy for   playing blackjack, for a given deck composition */typedef  struct {    Deck  deck;    boolean dbs, soft17;    Table standing_values,   /* player's expectation when standing */          hitting_values,    /* player's expectation hitting */          doubling_values,   /* player's expectation doubling down */          splitting_values;  /* player's expectation splitting */  } Strategy;/* A threshold t indicates the count at which a player should change strategy.   There are six types of thresholds:   POOR -- always hit/never double/never split   RICH -- always stand/double/split   NORMAL -- stand/double/split only if true count exceeds t.change_rich   REVERSE -- stand/double/split when true count is less than t.change_poor   RANGE -- stand/double/split if t.change_rich < true_count < t.change_poor   REVRANGE -- stand/double/split UNLESS t.change_poor < count < t.change_rich   */#define POOR     0#define RICH     1#define NORMAL   2#define REVERSE  3#define RANGE    4#define REVRANGE 5typedef  struct {    int type, change_poor, change_rich;  } Threshold;Threshold *hit_thresholds[TOTALS][CARDS],          *double_thresholds[TOTALS][CARDS],          *split_thresholds[CARDS][CARDS];/* Operations on totals: *//* make_hard: returns a hard total with a specified value */Total make_hard(value)     int value;{  Total t;    t.tag = HARD;  t.value = value;  return t;}/* make_soft: returns a soft total with a specified value */Total make_soft(value)     int value;{  Total t;    t.tag = SOFT;  t.value = value;  return t;}/* make_over: returns a total that is over 21 */Total make_over(){  Total t;  t.tag = OVER;  t.value = NULL;  return t;}/* c2t: returns total corresponding to a given card */Total c2t(c)     Card c;{  if (c == ACE)    return make_soft(c);  else    return make_hard(c);}/* over21: returns true if total t is over 21, false otherwise */boolean over21(t)     Total t;{  return (t.tag == OVER);}boolean soft21(t)     Total t;{  return ((t.tag == SOFT) && (t.value == 21));}/* sum: returns the total obtained by adding a card c to a total t */Total sum(t, c)     Total t;     Card c;{  int new_value;  Total new_total;    if (t.tag == OVER)    return t;    new_value = t.value + c;  if ((t.tag) == SOFT)    new_value = new_value - 10;  if (c == ACE)    new_value = new_value - 10;    if (new_value > 21) {    new_total.tag = OVER;    new_total.value = NULL;  }  else if ((new_value <= 11) && ((t.tag == SOFT) || (c == ACE))) {    new_total.tag = SOFT;    new_total.value = new_value + 10;  }  else {    new_total.tag = HARD;    new_total.value = new_value;  }  return new_total;}/* Operations on tables *//* t_create: constructs and returns a new table with the specified   number of rows and columns, and all elements unknown */Table t_create(rows, columns)int rows, columns;{  int i,j;  Table tab = (Table) calloc((unsigned) (rows + 1), sizeof(Mfloat *));    for (i = 0; i < rows; i++) {    tab[i] = (Mfloat *) calloc((unsigned) columns, sizeof(Mfloat));    for (j = 0; j < columns; j++)      tab[i][j].unknown = TRUE;  }  tab[rows] = NULL;  return tab;}Table tt_create(){  return t_create(TOTALS, TOTALS);}Table ct_create(){  return t_create(TOTALS, CARDS);}Table pt_create(){  return t_create(CARDS, CARDS);}/* t_destroy: frees storage associated with a table */void t_destroy(tab)     Table tab;{  int i;  for (i = 0; tab[i]; i++)    FREE(tab[i]);  FREE(tab);}/* tt_fetch: returns the table element indexed by totals t1 and t2 */Mfloat tt_fetch(tab, t1, t2)     Table tab;     Total t1, t2;{  return tab[t2i(t1)][t2i(t2)];}/* tt_store: stores value into a the table   location specified by totals t1 and t2 */void tt_store(tab, t1, t2, value)     Table tab;     Total t1, t2;     double value;{  int i = t2i(t1);  int j = t2i(t2);    tab[i][j].unknown = FALSE;  tab[i][j].value = (float) value;}/* ct_fetch: returns the table element indexed by total tot and card c */Mfloat ct_fetch(tab, tot, c)     Table tab;     Total tot;     Card c;{  return tab[t2i(tot)][c2i(c)];}/* ct_store: stores value into the table   location specified by total tot and card c */void ct_store(tab, tot, c, value)     Table tab;     Total tot;     Card c;     double value;{  int i = t2i(tot);  int j = c2i(c);    tab[i][j].unknown = FALSE;  tab[i][j].value = (float) value;}/* pt_fetch: returns the table element indexed by cards c1 and c2 */Mfloat pt_fetch(tab, c1, c2)     Table tab;     Card c1, c2;{  return tab[c2i(c1)][c2i(c2)];}/* pt_store: stores value into a the table   location specified by cards c1 and c2 */void pt_store(tab, c1, c2, value)     Table tab;     Card c1, c2;     double value;{  int i = c2i(c1);  int j = c2i(c2);    tab[i][j].unknown = FALSE;  tab[i][j].value = (float) value;}/* t2i: returns the table index corresponding to a total */int t2i(t)     Total t;{  switch (t.tag) {  case OVER:               /* over 21 corresponds to index 31 */    return 31;  case HARD:               /* hard totals 2..10 correspond to indexes 0 to 8 */    if (t.value <= 10)     /* hard 11-21 corresponds to indexes 20 to 30 */      return t.value - 2;    else      return(t.value + 9);  case SOFT:               /* soft totals correspond to indexes 9 to 19 */    return t.value - 2;  }}/* returns the table index corresponding to a card */int c2i(c)     Card c;{ return (c - 2);           /* cards 2..ace correspond to indexes 0 to 9 */} /* Operations on strategies *//* s_create: constructs and returns strategy object for specified deck */Strategy *s_create(d, dbs, soft17)     Deck d;     boolean dbs, soft17;{  Card c;  Strategy *s = (Strategy *) calloc(1, sizeof(Strategy));    for (c = 2; c <= ACE; c++)    s->deck[c] = d[c];  s->dbs = dbs;  s->soft17 = soft17;  s->standing_values  = tt_create();  s->hitting_values   = ct_create();  s->doubling_values  = ct_create();  s->splitting_values = pt_create();    return s;}/* s_destroy: frees heap space allocated for strategy object */void s_destroy(s)     Strategy *s;{  t_destroy(s->standing_values);  t_destroy(s->hitting_values);  t_destroy(s->doubling_values);  t_destroy(s->splitting_values);  FREE(s);}boolean final(s, t)     Strategy *s;     Total t;{  return ((t.tag == OVER) || (t.value > 17) ||          (t.value == 17) && ((t.tag == HARD) || (! s->soft17)));}/* standing_value: returns player's expectation standing with player_hand   when dealer has dealer_hand.  If check_bj is true then the dealer's   next card must not give him soft 21; otherwise the next card may be of   any value */float standing_value(s, player_hand, dealer_hand, check_bj)     Strategy *s;     Total player_hand, dealer_hand;     boolean check_bj;{  extern float correct_bj();  Mfloat answer;    answer = tt_fetch(s->standing_values, player_hand, dealer_hand);  if (answer.unknown) {    float expectation;        if (over21(player_hand))      expectation = -1.0;    else if (final(s, dealer_hand))      if (over21(dealer_hand) || (dealer_hand.value < player_hand.value))        expectation = 1.0;      else if (dealer_hand.value > player_hand.value)        expectation = -1.0;      else        expectation = 0.0;    else {      Card c;            expectation = 0.0;      for (c = 2; c <= ACE; c++) {        Total new_hand;                new_hand = sum(dealer_hand, c);        expectation = expectation +          s->deck[c] * standing_value(s, player_hand, new_hand, FALSE);      }     }    tt_store(s->standing_values, player_hand, dealer_hand, expectation);          if (check_bj)      return correct_bj(expectation, player_hand, dealer_hand, s->deck);    else return expectation;  }  else {    /* answer already calculated */    if (check_bj)      return correct_bj(answer.value, player_hand, dealer_hand, s->deck);    else return answer.value;  }}/* correct_bj: adjust expectation to take into account   the fact that the dealer cannot have soft 21 */float correct_bj(expectation, player_hand, dealer_hand, d)     double expectation;     Total player_hand, dealer_hand;     Deck d;{  float bj_prob, adjustment;  if ((dealer_hand.tag == HARD) && (dealer_hand.value == 10))    bj_prob = d[ACE];  else if ((dealer_hand.tag == SOFT) && (dealer_hand.value == ACE))    bj_prob = d[10];  else bj_prob = 0.0;  if (over21(player_hand) || (player_hand.value < 21))    adjustment = 1.0;  else adjustment = 0.0;  return((expectation + adjustment * bj_prob) / (1.0 - bj_prob));}/* hitting_value: returns player's expectation   hitting with player_hand when dealer has upcard. */float hitting_value(s, player_hand, upcard)     Strategy *s;     Total player_hand;     Card  upcard;{  Mfloat answer;    answer = ct_fetch(s->hitting_values, player_hand, upcard);  if (answer.unknown) {    float expectation;        if (over21(player_hand))      expectation = -1.0;    else {      Card c;            expectation = 0.0;      for (c = 2; c <= ACE; c++) {        Total new_hand;                new_hand = sum(player_hand, c);        expectation = expectation +          s->deck[c] * max(standing_value(s, new_hand, c2t(upcard), TRUE),                           hitting_value (s, new_hand, upcard));      }    }    ct_store(s->hitting_values, player_hand, upcard, expectation);    return expectation;  }  else    return answer.value;}/* hit: returns TRUE if player should hit player_hand   vs. upcard; otherwise returns FALSE */boolean hit(s, player_hand, upcard)     Strategy *s;     Total player_hand;     Card  upcard;{  return(hitting_value (s, player_hand, upcard) >         standing_value(s, player_hand, c2t(upcard), TRUE));}/* doubling_value: returns player's expectation   doubling down with player_hand vs. upcard. */float doubling_value(s, player_hand, upcard)     Strategy *s;     Total player_hand;     Card  upcard;{  Mfloat answer;    answer = ct_fetch(s->doubling_values, player_hand, upcard);  if (answer.unknown) {    Card c;    float expectation = 0.0;        for (c = 2; c <= ACE; c++) {      Total new_hand;            new_hand = sum(player_hand, c);      expectation = expectation +        2.0 * s->deck[c] * standing_value(s, new_hand, c2t(upcard), TRUE);    }    ct_store(s->doubling_values, player_hand, upcard, expectation);    return expectation;  }  else    return answer.value;}/* double_down: returns TRUE if player should double down   with player_hand vs. upcard; otherwise returns FALSE */boolean double_down(s, player_hand, upcard)     Strategy *s;     Total player_hand;     Card  upcard;{  return(doubling_value(s, player_hand, upcard) >         max(standing_value(s, player_hand, c2t(upcard), TRUE),             hitting_value (s, player_hand, upcard)));}/* splitting_value: returns player's expectation splitting   a pair of rank pair when the dealer has upcard. */float splitting_value(s, pair, upcard)     Strategy *s;     Card pair, upcard;{  Mfloat answer;    answer = pt_fetch(s->splitting_values, pair, upcard);  if (answer.unknown) {    Card c;    float expectation = 0.0;        for (c = 2; c <= ACE; c++) {      Total new_hand;            new_hand = sum(c2t(pair), c);      if (pair == ACE)      expectation = expectation +        2.0 * s->deck[c] * standing_value(s, new_hand, c2t(upcard), TRUE);      else        expectation = expectation +          2.0 * s->deck[c] *            max(standing_value(s, new_hand, c2t(upcard), TRUE),                s->dbs ?                max(hitting_value (s, new_hand, upcard),                    doubling_value(s, new_hand, upcard))                : hitting_value(s, new_hand, upcard));    }    pt_store(s->splitting_values, pair, upcard, expectation);    return expectation;  }  else    return answer.value;}/* split: returns TRUE if pair should be split vs. upcard, otherwise FALSE */boolean split(s, pair, upcard)     Strategy *s;     Card pair, upcard;{  Total player_hand;  player_hand = sum(c2t(pair), pair);  return (splitting_value(s, pair, upcard) >          max(standing_value(s, player_hand, c2t(upcard), TRUE),              max(hitting_value (s, player_hand, upcard),                  doubling_value(s, player_hand, upcard))));}/* make_deck: constructs and returns typical deck having a true count of   count, where counting_method[i] indicates the value of cards of rank i   in the counting system, for 2 <= i <= ACE, decks is the number of decks   in use (zero means infinite deck), p1 and p2 are the player's cards and   upcard is the dealer's upcard.  P1, p2 and upcard are ignored if zero. */Deck *make_deck(counting_method, true_count, decks, p1, p2, upcard)     Method counting_method;     double true_count;     int decks;     Card p1, p2, upcard;{  Card c;  Deck *d;  Deck base_deck;  float total_cards = 52.0 * decks;  int undealt_cards = total_cards;  float mean = 0.0, variance = 0.0;  for (c = 2; c <= ACE; c++)      base_deck[c] = ((c == 10) ? 4.0 : 1.0) / 13.0;  if (decks > 0) {    if (p1 > 0) {      base_deck[p1] = base_deck[p1] - 1.0 / total_cards;      undealt_cards--;    }    if (p2 > 0) {      base_deck[p2] = base_deck[p2] - 1.0 / total_cards;      undealt_cards--;    }    if (upcard > 0) {      base_deck[upcard] = base_deck[upcard] - 1.0 / total_cards;      undealt_cards--;    }    for (c = 2; c <= ACE; c++)      base_deck[c] = base_deck[c] * total_cards / undealt_cards;  }    for (c = 2; c <= ACE; c++)    mean = mean + base_deck[c] * counting_method[c];  for (c = 2; c <= ACE; c++)    variance = variance +      base_deck[c] * counting_method[c] * counting_method[c];  variance = variance - mean * mean;  d = (Deck *) calloc(1, sizeof(Deck));  for (c = 2; c <= ACE; c++)    (*d)[c] = base_deck[c] *      (1.0 - (true_count / 52.0 + mean) * (counting_method[c] - mean) /       variance);  return d;}  /* main: takes a counting method description from the command line and prints   the corresponding count strategy adjustments on the standard output */main(argc, argv)     int argc;     char **argv;{  boolean dbs = FALSE,          soft17 = FALSE,          found_decks = FALSE,          found_range = FALSE,          found_step = FALSE,          found_side_count = FALSE;  int main_count[12];      /* point values of cards in main count */  Method counting_method;  /* point values of cards after combining                             main count and ace side count */  Card c, c2, pair;  Strategy *s;  Deck *d;  int lower, upper, step, true_count;  int decks = 0;  int ace_side_value = 0;  float sum_of_squares;  extern void error(),   /* prints specified error message and halt program */         error_usage();  /* prints usage error message and halts program */  extern int parse_int();  /* read counting method from command line */  if (argc < 11)    error_usage();  for (c = 2; c <= ACE; c++)    main_count[c] = parse_int(*++argv);  /* read remaining arguments */  argc = argc - 11;  while ((argc)  && ((*++argv)[0] == '-')) {    if (((*argv)[1] == 'd') || ((*argv)[1] == 'h')) {      char next;      while ((next = *++*argv) != '\0')        switch (next) {        case 'd':          dbs = TRUE;          break;        case 'h':          soft17 = TRUE;          break;        default:          error_usage();          break;        }      argc--;    }    else if ((! strcmp(*argv, "-n")) && (! found_decks) && (argc >= 2)) {      found_decks = TRUE;      decks = parse_int(*++argv);      argc = argc - 2;    }    else if ((! strcmp(*argv, "-a")) && (! found_side_count) && (argc >= 2)) {      found_side_count = TRUE;      ace_side_value = parse_int(*++argv);      argc = argc - 2;    }    else if ((! strcmp(*argv, "-r")) && (! found_range) && (argc >= 3)) {      found_range  = TRUE;      lower = parse_int(*++argv);      upper = parse_int(*++argv);      argc = argc - 3;    }    else if ((! strcmp(*argv, "-s")) && (! found_step) && (argc >= 2)) {      found_step = TRUE;      step = parse_int(*++argv);      argc = argc - 2;    }    else      error_usage();  }  if (argc > 0)    error_usage();  if (found_decks && decks <= 0)    error("number of decks must be positive");  {    /* adjust counting method for ace side count and check       for illegal counting method (unbalanced or all zero) */        int adjusted_value;    int total_points = 0;    boolean all_zero = TRUE;    for (c = 2; c <= ACE; c++) {      if (c == ACE)        adjusted_value = 13 * main_count[c] + ace_side_value * 12;      else        adjusted_value = 13 * main_count[c] - ace_side_value;      if (c == 10)         total_points += 4 * adjusted_value;      else        total_points += adjusted_value;      if (adjusted_value != 0)        all_zero = FALSE;      counting_method[c] = adjusted_value / 13.;    }    if (total_points != 0)      error("unbalanced count not allowed");    if (all_zero)      if (ace_side_value == 0)        error("all card values are zero");      else error("ace side count cancels out main count");  }  if (found_range && (lower > upper))    error("lower limit greater than upper limit");  if (found_step)    if (step < 1)      error("step value must be positive");    else ; /* step value OK */  else    step = 1;  /* print title and copyright notice */  fprintf(stderr, "bj-strat version 1.2 -- May 11, 1991\n");  fprintf(stderr, "Copyright (c) 1990, 1991  Steven C. Markowitz.  ");  fprintf(stderr, "All rights reserved.\n");  {    /* trim lower and upper limits to legal range */    float vmin = counting_method[2];    float vmax = vmin;    float total_cards = 52.0 * decks;    float lowest_allowed, highest_allowed;        sum_of_squares = 0.0;    for (c = 2; c <= ACE; c++)      sum_of_squares = sum_of_squares +        ((c == 10) ? 4.0 : 1.0) / 13.0 *          (counting_method[c] * counting_method[c]);    for (c = 3; c <= ACE; c++) {      float card_value = counting_method[c];      vmin = min(vmin, card_value);      vmax = max(vmax, card_value);    }    lowest_allowed = 52.0 *      ((sum_of_squares +        (decks ? 3 * vmax * (vmin - vmax) / total_cards : 0)) /       (vmin + (decks ? 3 * (vmax - vmin) / total_cards : 0)))        + 0.5 * step;    highest_allowed = 52.0 *      ((sum_of_squares +        (decks ? 3 * vmin * (vmax - vmin) / total_cards : 0)) /       (vmax + (decks ? 3 * (vmin - vmax) / total_cards : 0)))        - 0.5 * step;        if (found_range) {      lower = max((double) lower, lowest_allowed);      upper = min((double) upper, highest_allowed);    }    else {      lower = lowest_allowed;      upper = highest_allowed;    }    lower = step * (lower / step);    upper = step * (upper / step);  }  /* initialize threshold tables using strategy for most negative deck */  fprintf(stderr, "Calculating strategy for most negative deck\n");  if (decks == 0) {    d = make_deck(counting_method, lower - 0.5 * step, decks,                  DUMMY, DUMMY, DUMMY);    s = s_create(*d, dbs, soft17);    FREE(d);  }  for (c = 2; c <= ACE; c++) {    Total player_hand;    Threshold *t;    int i;    if (decks > 0) {      d = make_deck(counting_method, lower - 0.5 * step, decks,                    DUMMY, DUMMY, c);      s = s_create(*d, dbs, soft17);      FREE(d);    }    for (i = 12; i <= 21; i++) {      t = (Threshold *) calloc(1, sizeof(Threshold));      player_hand = make_hard(i);      t->type = hit(s, player_hand, c) ? POOR : RICH;      hit_thresholds[t2i(player_hand)][c2i(c)] = t;    }    for (i = 17; i <= 21; i++) {      t = (Threshold *) calloc(1, sizeof(Threshold));      player_hand = make_soft(i);      t->type = hit(s, player_hand, c) ? POOR : RICH;      hit_thresholds[t2i(player_hand)][c2i(c)] = t;    }    for (i = 4; i <= 11; i++) {      t = (Threshold *) calloc(1, sizeof(Threshold));      player_hand = make_hard(i);      t->type = double_down(s, player_hand, c) ? RICH : POOR;      double_thresholds[t2i(player_hand)][c2i(c)] = t;    }    for (c2 = 2; c2 <= c; c2++) {      if (decks > 0) {        s_destroy(s);        d = make_deck(counting_method, lower - 0.5 * step, decks, ACE, c, c2);        s = s_create(*d, dbs, soft17);        FREE(d);      }      t = (Threshold *) calloc(1, sizeof(Threshold));      player_hand = sum(c2t(c2), ACE);      t->type = double_down(s, player_hand, c) ? RICH : POOR;      double_thresholds[t2i(player_hand)][c2i(c)] = t;      if (c2 != c) {        t = (Threshold *) calloc(1, sizeof(Threshold));        player_hand = sum(c2t(c), ACE);        t->type = double_down(s, player_hand, c2) ? RICH : POOR;        double_thresholds[t2i(player_hand)][c2i(c2)] = t;      }      if (c == ACE) {        t = (Threshold *) calloc(1, sizeof(Threshold));        t->type = split(s, ACE, c2) ? RICH : POOR;        split_thresholds[c2i(ACE)][c2i(c2)] = t;      }      else if (c == c2) {        t = (Threshold *) calloc(1, sizeof(Threshold));        t->type = split(s, c, ACE) ? RICH : POOR;        split_thresholds[c2i(c)][c2i(ACE)] = t;      }     }    if (c != ACE)      for (pair = 2; pair <= 10; pair++) {        if (decks > 0) {          s_destroy(s);          d = make_deck(counting_method, lower - 0.5 * step, decks,                        pair, pair, c);          s = s_create(*d, dbs, soft17);          FREE(d);        }        t = (Threshold *) calloc(1, sizeof(Threshold));        t->type = split(s, pair, c) ? RICH : POOR;        split_thresholds[c2i(pair)][c2i(c)] = t;      }    if (decks > 0)      s_destroy(s);  }  if (decks == 0)    s_destroy(s);  /* calculate strategy changes for other counts */  for (true_count = lower; true_count <= upper; true_count += step) {    extern void update_threshold();    fprintf(stderr, "Considering true count of %3d\n", true_count);    if (decks == 0) {      d = make_deck(counting_method, true_count + 0.5 * step, decks,                    DUMMY, DUMMY, DUMMY);      s = s_create(*d, dbs, soft17);      FREE(d);    }    for (c = 2; c <= ACE; c++) {      Total player_hand;      Threshold *t;      int i;      if (decks > 0) {        d = make_deck(counting_method, true_count + 0.5 * step, decks,                      DUMMY, DUMMY, c);        s = s_create(*d, dbs, soft17);        FREE(d);      }      for (i = 12; i <= 21; i++) {        player_hand = make_hard(i);        t = hit_thresholds[t2i(player_hand)][c2i(c)];        update_threshold(t, (! hit(s, player_hand, c)), true_count);      }      for (i = 17; i <= 21; i++) {        player_hand = make_soft(i);        t = hit_thresholds[t2i(player_hand)][c2i(c)];        update_threshold(t, (! hit(s, player_hand, c)), true_count);      }      for (i = 4; i <= 11; i++) {        player_hand = make_hard(i);        t = double_thresholds[t2i(player_hand)][c2i(c)];        update_threshold(t, double_down(s, player_hand, c), true_count);      }      for (c2 = 2; c2 <= c; c2++) {        if (decks > 0) {          s_destroy(s);          d = make_deck(counting_method, true_count + 0.5 * step, decks,                        ACE, c, c2);          s = s_create(*d, dbs, soft17);          FREE(d);        }        player_hand = sum(c2t(c2), ACE);        t = double_thresholds[t2i(player_hand)][c2i(c)];        update_threshold(t, double_down(s, player_hand, c), true_count);        if (c2 != c) {          player_hand = sum(c2t(c), ACE);          t = double_thresholds[t2i(player_hand)][c2i(c2)];          update_threshold(t, double_down(s, player_hand, c2), true_count);        }        if (c == ACE) {          t = split_thresholds[c2i(ACE)][c2i(c2)];          update_threshold(t, split(s, ACE, c2), true_count);        }        else if (c == c2) {          t = split_thresholds[c2i(c)][c2i(ACE)];          update_threshold(t, split(s, c, ACE), true_count);        }             }      if (c != ACE)        for (pair = 2; pair <= 10; pair++) {          if (decks > 0) {            s_destroy(s);            d = make_deck(counting_method, true_count + 0.5 * step, decks,                          pair, pair, c);            s = s_create(*d, dbs, soft17);            FREE(d);          }          t = split_thresholds[c2i(pair)][c2i(c)];          update_threshold(t, split(s, pair, c), true_count);        }      if (decks > 0)        s_destroy(s);    }    if (decks == 0)      s_destroy(s);  }  /* print out the results */  /* print strategy header */  printf("%21s%s", "", "Blackjack Count Strategy Adjustments\n\n");  printf("%16s%s", "", "Cards:    2   3   4   5   6   7   8   9  10 Ace\n");  printf("%16s%s", "", "Values:");  for (c = 2; c <= ACE; c++)    printf("%4d",  main_count[c]);  printf("\n");  if (found_side_count)    printf("%27s%s%d\n", "", "Ace side count value:  ", ace_side_value);  printf("\n");  {    int length;    if (decks == 0)      length = 60;    else if (decks == 1)      length = 53;    else      length = 54;    if (dbs)      length = length - 3;    if (soft17)      length = length - 5;        printf("%*s", (79 - length) / 2, "");    if (decks > 0)      printf("%d deck%s, ", decks, ((decks > 1) ? "s" : ""));    else      printf("Infinite deck, ");    printf("%s%s", (dbs ? "" : "no "), "double on splits, dealer ");    printf("%s%s", (soft17 ? "hits " : "stands on "), "soft 17\n\n\n");  }  {    extern void print_threshold();    Total player_hand;    int i;    /* hit/stand strategy */    printf("%30s%s", "", "Hit/Stand Strategy\n\n");    printf("%32s%s", "", "Dealer's Upcard\n\n");    printf("Player's Total%6d%6d%6d%6d%6d%6d%6d%6d%6d%7s\n\n",           2, 3, 4, 5, 6, 7, 8, 9, 10, "Ace");    for (i = 21; i >= 12; i--) {      player_hand = make_hard(i);      printf("   Hard %2d        ", i);      for (c = 2; c <= ACE; c++)        print_threshold(hit_thresholds[t2i(player_hand)][c2i(c)],                        "Hit", "...");      printf("\n");    }    printf("\n");    for (i = 21; i >= 17; i--) {      player_hand = make_soft(i);      printf("   Soft %2d        ", i);      for (c = 2; c <= ACE; c++)        print_threshold(hit_thresholds[t2i(player_hand)][c2i(c)],                        "Hit", "...");      printf("\n");    }    printf("\n\n");    /* double down strategy */    printf("%29s%s", "", "Double Down Strategy\n\n");    printf("%32s%s", "", "Dealer's Upcard\n\n");    printf("Player's Total%6d%6d%6d%6d%6d%6d%6d%6d%6d%7s\n\n",         2, 3, 4, 5, 6, 7, 8, 9, 10, "Ace");        for (i = 11; i >= 4; i--) {      player_hand = make_hard(i);      printf("   Hard %2d        ", i);      for (c = 2; c <= ACE; c++)        print_threshold(double_thresholds[t2i(player_hand)][c2i(c)],                        "...", "dbl");      printf("\n");    }    printf("\n");    for (i = 20; i >= 13; i--) {      player_hand = make_soft(i);      printf("   Soft %2d        ", i);      for (c = 2; c <= ACE; c++)        print_threshold(double_thresholds[t2i(player_hand)][c2i(c)],                        "...", "dbl");      printf("\n");    }    printf("\n\n");    /* pair split strategy */    printf("%30s%s", "", "Pair Split Strategy\n\n");    printf("%32s%s", "", "Dealer's Upcard\n\n");    printf("Player's Pair %6d%6d%6d%6d%6d%6d%6d%6d%6d%7s\n\n",         2, 3, 4, 5, 6, 7, 8, 9, 10, "Ace");        for (pair = ACE; pair >= 2; pair--) {      if (pair == ACE)        printf("   Ace,Ace        ");      else        printf("   %3d,%-3d        ", pair, pair);      for (c = 2; c <= ACE; c++)        print_threshold(split_thresholds[c2i(pair)][c2i(c)],                        "...", "split");      printf("\n");    }  }}/* parse_int: returns the integer whose printed form is the string s. */int parse_int(s)     char *s;{  int answer;  char next_char = '\0';  if ((sscanf(s, "%d %c", &answer, &next_char) > 0) && (next_char == '\0'))    return answer;  else {    fprintf(stderr, "not an integer -- %s\n", s);    exit(1);  }}/* update threshold: change strategy threshold value, if appropriate,   based on information for current count.  If strategy changes at more than   two counts, remember only the changes for the two counts closest to zero. */void update_threshold(t, new_action_rich, true_count)     Threshold *t;     boolean new_action_rich; /* true if player should stand/double/split */     int true_count;{  if (new_action_rich)    if (t->type == POOR) {      t->type = NORMAL;      t->change_rich = true_count;    }    else if ((t->type == REVERSE) ||             (t->type == RANGE) && (t->change_rich <= abs(true_count))) {      t->type = REVRANGE;      t->change_rich = true_count;    }    else ; /* no change in strategy */  else if (t->type == RICH) {    t->type = REVERSE;    t->change_poor = true_count;  }  else if ((t->type == NORMAL) ||           (t->type == REVRANGE) && (t->change_poor <= abs(true_count))) {      t->type = RANGE;      t->change_poor = true_count;    }  else ; /* no change in strategy */}/* print threshold: prints a string representation   of a threshold on the standard output */void print_threshold(t, poor_symbol, rich_symbol)     Threshold *t;     char *poor_symbol, *rich_symbol;{  switch (t->type) {  case POOR:    printf("%-6s", poor_symbol);    break;  case RICH:    printf("%-6s", rich_symbol);    break;  case NORMAL:    printf("%3d   ", t->change_rich);    break;  case REVERSE:    printf("%3d*  ", t->change_poor);    break;/* uncomment the next six lines to print data for ranges *//*  case RANGE:    printf("%-d/%-d ", t->change_rich, t->change_poor);    break;  case REVRANGE:    printf("%-d^%-d ", t->change_poor, t->change_rich);    break; */  case RANGE:  case REVRANGE:    if ((abs(t->change_rich) < abs(t->change_poor)) ||        (t->change_rich = abs(t->change_poor)))      printf("%3d   ", t->change_rich);    else printf("%3d*  ", t->change_poor);    break;  }}void error_usage(){  fprintf(stderr, "usage: bj-strat v2 v3 v4 v5 v6 v7 v8 v9 v10 vAce ");  fprintf(stderr, "[-dh][-n decks][-r low high]\n");  exit(1);}void error(message)     char *message;{  fprintf(stderr, "error: %s\n", message);  exit(1);}
