// Konstanten:

// Wertigkeiten der Flags für spezielle Blätter:
var soft=1;                  // Softhand (mit As als 11)
var first=2;                 // Blatt, das aus einer Karte besteht
var second=4;                // Blatt, das aus zwei Karten besteht 
var Dd_poss=8;               // Double down: jetzt oder später erlaubt (bei 0-2 Karten)
var Split_poss=16;           // Teilen: jetzt oder später erlaubt (bei 0-2 Karten)
var noBJ=32;                 // Kein Black Jack möglich (z.B. nach Splitting)



// == Black-Jack-Hand =================================================== 

// Klasse für Black-Jack-Hände, d.h. jede Instanz entspricht einer
// möglichen Kombination von Karten, die ein Spieler oder die Bank
// in Händen hält, wobei zwischen äquivaleten Händen nicht unter-
// schieden wird (die Flags Dd_poss und Splitt_pos erlauben Entsprechungen
// zu Blättern, bei denen Teil- und Doppelregeln im weiteren Spielverlauf
// [z.B. nach Teilen] nicht mehr möglich sind).

function BJ_Hand(KartSum, Flags)
// Konstruktor:
{
  // Eigenschaften:
  this.KartSum=KartSum;       // Summe der Kartenwerte (As möglichst mit 11, max. 22)
  this.Flags=Flags;           // Summe der Flags (soft, first, second, Dd_poss, Split_poss)

  this.GewinnErwStand=-100;   // Init. für Gewinnerw. bei Stand
  this.GewinnErwOpt=-100;     // Initialisierung für Gewinnerw. bei opt.Spiel
  this.ZugOpt="";             // Initialisierung für optimalen Zug

  // Methoden:
  this.AsString=Bezeichnung;  // eindeutige Kennung
  this.Flag=Flag;             // Bestimmung eines Flags
  this.IsBJ=IsBJ;             // Flag, ob Black Jack
  this.Ziehe=Ziehe;           // Kartenblatt nach dem Ziehen einer Karte

  this.WvHandNachKarte=WvHandNachKarte;
                              // Wahr.vert. nach Ziehung einer Karte
}


function Bezeichnung()
// derart gleich bezeichnete Hände sind spielerisch äquivalent:
{
  if (this.KartSum==22)
    return "verk";
  if (this.IsBJ())
    return "BJ";
  if (this.Flags>0)
    return this.KartSum+"f"+this.Flags;

  return this.KartSum+"";
}


function Flag(Gewicht)
// für ein oder mehrere Gewichte (z.B. Flag(soft+second))
{
  return ((this.Flags & Gewicht)==Gewicht);
}

function IsBJ()
{
  return (this.Flag(second) && (this.KartSum==21) && !(this.Flag(noBJ)));
}

function Ziehe(Karte)
// ermittelt neue BJ-Hand, die durch Ziehen einer Karte zur
// aktuellen BJ-Hand entsteht (Karte=2..11).
// 11s ist das Pseudo-Blatt, das aus einem Ass besteht, aber (z.B. nach einem
// Splitt keinen Black Jack hervorbringen kann).
{
  var ret,sum, flagsneu, As11Anz;

  if (this.KartSum==0)
    // es handelt sich um die erste Karte:
    return new BJ_Hand(Karte,this.Flags+first+ (Karte==11 ? soft : 0) ); 

  if (this.Flag(first))
  {
    // es handelt sich um die zweite Karte:
    flagsneu=second + ((this.KartSum==11) || (Karte==11) ? soft : 0);
    sum=this.KartSum+Karte;
    if ((sum==21) && this.Flag(noBJ))
      flagsneu=flagsneu+noBJ;                    // Sonderfall "kein Black Jack" nur bei 21 möglich
    if (sum==22)
      sum=12;
    // prüfe, ob bestehende Flags Dd_poss und Split_poss beibehalten werden:
    if (this.Flag(Dd_poss))
    {
      if ((sum>=9) && (sum<=11))
        flagsneu=flagsneu+Dd_poss;
      if ( (sum>=19) && (sum<=20) && ((flagsneu & soft)==soft) )
        flagsneu=flagsneu+Dd_poss;
    }
    if (this.Flag(Split_poss))
      if (this.KartSum==Karte)
        flagsneu=flagsneu+Split_poss;
    return new BJ_Hand(sum,flagsneu);
  }    
 
  // es handelt sich mind. um die dritte Karte:
  As11Anz= (this.Flag(soft) ? 1 : 0) + ((Karte==11) ? 1 : 0);
  sum=this.KartSum+Karte;
  if ((sum>=22) && (As11Anz>0))
  {
    As11Anz--;
    sum=sum-10;
  }
  if (sum>22)
   sum=22; 
  return new BJ_Hand(sum, (As11Anz>0) ? soft : 0 );
}

function WvHandNachKarte(WvKartenwerte)
// erstellt eine Wahr.vert. für die BJ-Hände, wenn ausgehend von aktueller
// Hand eine Karte gemäß der der Wahr.vert. WvKartenwerte gezogen wird:
{
  var ret,s,Karte,HandNeu;
  ret=new WahrVert();
  for (s in WvKartenwerte.List())
  {
    Karte=WvKartenwerte.ErgebnisLfd(s); 
    HandNeu=this.Ziehe(Karte);
    ret.AddProb(HandNeu,WvKartenwerte.ProbLfd(s));
  }
  return ret;
}


// =======================================================================





// == Black-Jack-Hands =================================================== 

// Klasse für alle Black-Jack-Hände, d.h. jede Instanz entspricht einem
// Container, der alle möglichen Black-Hände enthält. Bankkarte und die
// Wahr.vert. der Kartenwerte sind als vorgegebene Konstanten vorausge-
// setzt:

function BJ_Hands(Bankkarte, WvKartenwerte, RegelVariante, BJ_Check,Draw17s)
// Konstruktor:
{
  var BJ;
  // Eigenschaften:
  this.Bankkarte=Bankkarte;          // erste Karte der Bank
  this.WvKartenwerte=WvKartenwerte;  // Wahr.vert. der Karten
  this.RegelVariante=RegelVariante   // Splitting-Variante
                                      // 0: kein Teilen und Doppeln nach Teilen
                                      // 1: mehrfaches Teilen möglich
                                      // 2: Doppeln und Teilen nach Teilen
                                      // 3: Doppeln, aber kein Teilen nach Teilen
  this.BJ_Check=BJ_Check;            // Flag für US-Variante
  this.WvBankBlatt=WvBankBlatt(Bankkarte,WvKartenwerte,Draw17s);      //Wahr.vert.d.Bank
  this.BJ_Bank=this.WvBankBlatt.Prob(new BJ_Hand(21,second+soft));   // Wahr. für direkt aufgedeckten Bank-BJ
  if (this.BJ_Check)
  {
    BJ=new BJ_Hand(21,second+soft);
    // Wahr. für direkt aufgedeckten Bank-BJ (bei der US-Variante):
    this.BJ_BankDirekt=this.WvBankBlatt.Prob(BJ);
    this.WvBankBlatt.SetProb(BJ,0);
    this.WvBankBlatt.Normiere();        //bedingte Wahr.vert. der Bank (bedingt zum Ereignis "kein BJ")
  }
  else  
    this.BJ_BankDirekt=0; 
  
  this.HandsAnalysiert=new Set();    // bereits analysierte Hände

  // Methoden:
  this.GewinnErwStand=GewinnErwStand;
  this.GewinnErwOpt=GewinnErwOpt;
  this.GewinnErwDraw=GewinnErwDraw;
  this.GewinnErwDraw1=GewinnErwDraw1;

  this.Analysiere=Analysiere;
}

function GewinnErwStand(Hand)
// Gewinnerwartung des Spielers, falls er mit Hand nicht mehr zieht
// (liest gespeicherten Wert bzw. berechnet ggf. vorher):
{
  var HandRef;
  HandRef=this.HandsAnalysiert.ElementRef(Hand);
  if (ObjectIsUndefined(HandRef))
  { 
    this.Analysiere(Hand);
    HandRef=Hand;
  }
  return HandRef.GewinnErwStand;
}

function GewinnErwOpt(Hand)
// Gewinnerwartung des Spielers, falls er mit Hand optimal weiterspielt
// (liest gespeicherten Wert bzw. berechnet ggf. vorher):
{
  var HandRef;
  HandRef=this.HandsAnalysiert.ElementRef(Hand);
  if (ObjectIsUndefined(HandRef))
  { 
    this.Analysiere(Hand);
    HandRef=Hand;
  }
  return HandRef.GewinnErwOpt;
}

function ZugOpt(Hand)
// optimaler Zug für Hand
// (liest gespeicherten Wert bzw. berechnet ggf. vorher):
{
  var HandRef;
  HandRef=this.HandsAnalysiert.ElementRef(Hand);
  if (ObjectIsUndefined(HandRef))
  { 
    this.Analysiere(Hand);
    HandRef=Hand;
  }
  return HandRef.ZugOpt;
}

function GewinnErwDraw(Hand)
// Gewinnerwartung des Spielers, falls er eine Karte zieht und optimal
// weiterspielt:
{
  var ret, s, WvNeu;
  ret=0;
  WvNeu=Hand.WvHandNachKarte(this.WvKartenwerte);
  for (s in WvNeu.List())
    ret=ret+this.GewinnErwOpt(WvNeu.ErgebnisLfd(s))*WvNeu.ProbLfd(s);
  return ret;
}

function GewinnErwDraw1(Hand)
// Gewinnerwartung des Spielers, falls er genau eine weitere Karte zieht:
{
  var ret, s, WvNeu;
  ret=0;
  WvNeu=Hand.WvHandNachKarte(this.WvKartenwerte);
  for (s in WvNeu.List())
    ret=ret+this.GewinnErwStand(WvNeu.ErgebnisLfd(s))*WvNeu.ProbLfd(s);
    
  return ret;
}

function Analysiere(Hand)
// analysierte die Black-Jack-Hand Hand (Referenz "Hand" wird eingebaut!)
{
  var ErwAkt, s, sum, HandNeu, Hand, k, ProbRepeat, FlagsNeu;

  this.HandsAnalysiert.AddElement(Hand);  // Einträge erfolgen sogleich ...
  
   // berechne Erwartung bei Stand:
  sum=0;
  for (s in this.WvBankBlatt.List())
    sum=sum+Gewinn(this.WvBankBlatt.ErgebnisLfd(s),Hand)*this.WvBankBlatt.ProbLfd(s);
  Hand.GewinnErwStand=sum;
  Hand.GewinnErwOpt=sum;
  Hand.ZugOpt="Stand";

  // vergleiche nun mit Erwartung für das Ziehen einer weiteren Karte:
  ErwAkt=this.GewinnErwDraw(Hand);
  if (this.BJ_Check && (Hand.KartSum==0))
    // Modifikation für amerikan. Variante: BJ der Bank gewinnt sofort (außer gegen BJ des Spielers):
    ErwAkt=this.BJ_BankDirekt*(1-2*this.WvKartenwerte.Prob(10)*this.WvKartenwerte.Prob(11))*(-1)+(1-this.BJ_BankDirekt)*ErwAkt;
  
  if (ErwAkt>Hand.GewinnErwOpt)
  {
    Hand.GewinnErwOpt=ErwAkt;
    Hand.ZugOpt="Draw";
  }
  
  // berechne ggf. Erwartung bei Double-Down:
  if (Hand.Flag(Dd_poss+second))
  {
    if (Hand.Flag(soft))
      HandNeu=new BJ_Hand(Hand.KartSum-10,second);
    else
      HandNeu=new BJ_Hand(Hand.KartSum,second);
    ErwAkt=2*this.GewinnErwDraw1(HandNeu);

    if (ErwAkt>Hand.GewinnErwOpt)
    {
      Hand.GewinnErwOpt=ErwAkt;
      Hand.ZugOpt="Dd";
    }
  }  

  // berechne ggf. Erwartung beim Teilen:
  if (Hand.Flag(Split_poss+second))
  {
    // bestimme zu splittende Karte:
    if (Hand.Flag(soft))
      k=11;
    else
      k=Hand.KartSum/2;                       // Splitting von "k-k"?

    if ((this.RegelVariante==0) || (this.RegelVariante==3))
    {
      // kein Resplit möglich:
      if (k==11)
      {
        HandNeu=new BJ_Hand(11,first+soft+noBJ);
        // zu geteiltem As nur noch eine Karte:
        ErwAkt=2*this.GewinnErwDraw1(HandNeu);
      }
      else
      {
        FlagsNeu=first;
        if ((this.RegelVariante==2) || (this.RegelVariante==3))
          FlagsNeu=FlagsNeu+Dd_poss;                       // ggf. Double down nach Split
        if (k==10)
          FlagsNeu=FlagsNeu+noBJ;                          // kein Black Jack nach Split von 10-10
        HandNeu=new BJ_Hand(k,FlagsNeu);
        ErwAkt=2*this.GewinnErwDraw(HandNeu);
      }
    }
    else
    {
      // Regelvarianten 1 und 2, d.h.
      // Resplit ist möglich; zunächst Wahrscheinlichkeit für Folge-Splits:
      ProbRepeat=this.WvKartenwerte.Prob(k);
 
      // beachte: Erw(Teile k-k) = 2*(ProbRepeat*Erw(Teile k-k) + Summe[i ungleich k; Prob(i)*Erw(i+k)], also
      // Erw(Teile k-k)=2/(1-2*ProbRepeat)*Summe[...], wobei die Summe aus dem Fall "Ziehen zur Einzelkarte k"
      // berechenbar ist:

      if (k==11)
      {
        FlagsNeu=first+soft+noBJ;
        // zu geteiltem As nur noch eine Karte:
        sum=    this.GewinnErwDraw1(new BJ_Hand(11,FlagsNeu))
        sum=sum-this.GewinnErwStand(new BJ_Hand(12,soft))*this.WvKartenwerte.Prob(11);
        ErwAkt=2/(1-2*ProbRepeat)*sum;
      }
      else
      {
        FlagsNeu=first;
        if (this.RegelVariante==2)
           FlagsNeu=FlagsNeu+Dd_poss;                       // ggf. Double down nach Split
        if (k==10)
          FlagsNeu=FlagsNeu+noBJ;                           // kein Black Jack nach Split von 10-10
        sum=    this.GewinnErwDraw(new BJ_Hand(k,FlagsNeu))
        sum=sum-this.GewinnErwOpt(new BJ_Hand(2*k,((k==5) && (this.Regelvariante==2)) ? second+Dd_poss : 0))*this.WvKartenwerte.Prob(k);
        ErwAkt=2/(1-2*ProbRepeat)*sum;
      }
    }

    if (ErwAkt>Hand.GewinnErwOpt)
    {
      Hand.GewinnErwOpt=ErwAkt;
      Hand.ZugOpt="Split";
    }
  }
}


// =======================================================================





function WvBankBlatt(Bankkarte,WvKartenwerte,Draw17s)
// berechnet die Endverteilung der Bank in Abhängigkeit der 
// (ersten) Bankkarte sowie Wahr.vert. der Kartenwerte
{
  var WvAlt,WvNeu,Karte,Hand,s,WvEnd;
  WvNeu=new WahrVert();
  Hand=new BJ_Hand(Bankkarte, ((Bankkarte==11) ? soft :0) +first);
  WvNeu.AddProb(Hand, 1.0);
  WvEnd=new WahrVert();

  do
  { 
    // Ziehe eine (weitere) Karte, sofern noch nicht 17 erreicht:
    WvAlt=WvNeu.Copy();
    WvNeu=new WahrVert(); 
    for (s in WvAlt.List())
    {
      Hand=WvAlt.ErgebnisLfd(s);
      if ((Hand.KartSum<=16) || (Draw17s && Hand.Flag(soft) && (Hand.KartSum==17)))
        // Bank zieht bis 16 (und ggf. auch bei soft-17):
        WvNeu.AddWv(WvAlt.ProbLfd(s), Hand.WvHandNachKarte(WvKartenwerte));
      else 
        // Bank zieht über 16 nicht mehr (auch bei Softhands, außer ggf. bei 17):
        WvEnd.AddProb(Hand, WvAlt.ProbLfd(s));
    }
  }
  while (WvNeu.SumProb()>0)
  
  // Endverteilung ist erreicht; wandle nun Softhands etc. in Hardhands um:
  WvNeu=new WahrVert(); 
  for (s in WvEnd.List())
  {
    Hand=WvEnd.ErgebnisLfd(s);
    if (!Hand.IsBJ())
      Hand.Flags=0;                                      // nur Black Jack wird separat berücksichtigt
    WvNeu.AddProb(Hand, WvEnd.ProbLfd(s));    
  }
  return WvNeu;
}


function Gewinn(BankHand, SpielerHand)
// Gewinn(saldo) abhängig von den BJ-Händen von Bank und Spieler:
{
  if (SpielerHand.KartSum>21)
    return -1;

  if (SpielerHand.IsBJ())
  {
   if (BankHand.IsBJ())
     return 0;
   else
     return 1.5;
  }

  if (BankHand.IsBJ())
    return -1;

  if (BankHand.KartSum>21)
    return 1;
  if (SpielerHand.KartSum>BankHand.KartSum)
    return 1;
  if (SpielerHand.KartSum<BankHand.KartSum)
    return -1;
  return 0;
}



// == Black-Jack-Analyse =================================================

// Klasse zur Analyse des Black-Jack-Spiels für alle möglichen 
// Bankkarten und alle möglichen Black-Jack-Hände, d.h. jede Instanz 
// entspricht einem Container, der zu allen möglichen Black-Jack-Händen
// und allen Bankkarten Analysen der Strategien enthält.
// Wahr.vert. der Kartenwerte sind als vorgegebene Konstanten vorausge-
// setzt:
// Um Probleme bei unmöglichen Black-Jack-Händen zu vermeiden, muss die
// Wahrscheinlichkeitesverteilung der Kartenwerte für jede Karte eine 
// positive Wahrscheinlichkeit aufweisen.

function BJ_Analyse(WvKartenwerte, RegelVariante, BJ_Check, Draw17s, Details)
// Konstruktor:
{
  // Eigenschaften:
  this.WvKartenwerte=WvKartenwerte;  // Wahr.vert. der Karten
  this.RegelVariante=RegelVariante;  // Regelvariante bzgl."nach Splitt" (0..3)
  this.BJ_Check=BJ_Check;            // direkter Black-Jack-Check der Bank (US-Regel)
  this.Draw17s=Draw17s;              // Bank zieht bei soft-17
  this.Details=Details;
  this.BJ_Hands=new Array();

  // Methoden:
  this.Compute=Compute;
  this.PrintResult=PrintResult;
}

function Compute()
// führt die gesamte Berechnung zu einer vorgegebenen Wahr.vert. der
// Kartenwerte durch:
{
  var Bankkarte;
  for (Bankkarte=2;Bankkarte<=11;Bankkarte++)
  {
    this.BJ_Hands[Bankkarte]=new BJ_Hands(Bankkarte, this.WvKartenwerte, this.RegelVariante, this.BJ_Check,this.Draw17s);
    this.BJ_Hands[Bankkarte].Analysiere(new BJ_Hand(0,Dd_poss+Split_poss));

    this.BJ_Hands[Bankkarte].Analysiere(new BJ_Hand(0,0));                  //ohne Split, Dd
    this.BJ_Hands[Bankkarte].Analysiere(new BJ_Hand(10,second+Split_poss));  //ohne Dd.
    // letztere wg. der BJ-Hände, die in den Strategie-Tabellen vorkommen
  }
}

function PrintResult(subtitle)
// gibt das gesamte Ergebnis in Form einer HTML-Seite aus:
{
  var txt,s,b, Hand, sum, Hand_; ;
  txt="";
  txt=txt+"<html><head><title>Black-Jack-Analyse</title></head>\n";
  txt=txt+"<body bgcolor='#DDDDDD'>";
  txt=txt+"<center><big><big><b>Optimal Blackjack Strategy</b></big></big></center>";
  txt=txt+"<center><small>"+subtitle+"</small></center>";
  txt=txt+"<br><table><tr valign='top'>";
  if (this.Details)
  {
    txt=txt+LeereTabellenZeile(11);
    txt=txt+'<tr height="14"><td align="left" valign="bottom" colspan="8" rowspan="2"><small>';
    txt=txt+'For each situation you find the optimal expectation';
    txt=txt+' (win minus stake) and the optimal decision:</small></td><td></td><td></td><td></td></tr>';
    txt=txt+'<tr><td align="center" width="67"' + tdcolor("Draw") + '><small><b>Draw</b></small></td>';
    txt=txt+'<td align="center" width="67"' + tdcolor("Dd") + '><small><b>Double d.</b></small></td>';
    txt=txt+'<td align="center" width="67"' + tdcolor("Split") + '><small><b>Split</b></small></td></tr>';
    txt=txt+LeereTabellenZeile(11);
  }

  txt=txt+td("Bank:<br>Player");
  for (b=2;b<=11;b++)
    txt=txt+td(b);  
  txt=txt+"</tr>\n";

  for (s=20;s>=11;s--)
  {
    txt=txt+"<tr>"+td(s);
    Hand=new BJ_Hand(s,0);
    for (b=2;b<=11;b++)
      txt=txt+StrategieOutput(this.BJ_Hands[b].HandsAnalysiert.Element(Hand.AsString()),this.Details);
    txt=txt+"</tr>\n";
  }

  for (s=20;s>=13;s--)
  {
    txt=txt+"<tr>"+td(s+" soft");
    Hand=new BJ_Hand(s,soft);
    for (b=2;b<=11;b++)
      txt=txt+StrategieOutput(this.BJ_Hands[b].HandsAnalysiert.Element(Hand.AsString()),this.Details);
    txt=txt+"</tr>\n";
  }

  txt=txt+LeereTabellenZeile(11);

  for (s=20;s>=19;s--)
  {
    txt=txt+"<tr>"+td(s+" soft");
    Hand=new BJ_Hand(s,second+soft+Dd_poss);
    for (b=2;b<=11;b++)
      txt=txt+StrategieOutput(this.BJ_Hands[b].HandsAnalysiert.Element(Hand.AsString()),this.Details);
    txt=txt+"</tr>\n";
  }

  for (s=11;s>=9;s--)
  {
    txt=txt+"<tr>"+td(s);
    Hand=new BJ_Hand(s,second+Dd_poss);
    for (b=2;b<=11;b++)
      txt=txt+StrategieOutput(this.BJ_Hands[b].HandsAnalysiert.Element(Hand.AsString()),this.Details);
    txt=txt+"</tr>\n";
  }

  txt=txt+LeereTabellenZeile(11);

  for (s=11;s>=2;s--)
  {
    txt=txt+"<tr>"+td(s+"-"+s);
    if (s==11)
      Hand=new BJ_Hand(12,soft+second+Split_poss);
    else 
      Hand=new BJ_Hand(2*s,second+ (s==5 ? Dd_poss : 0) +Split_poss);

    for (b=2;b<=11;b++)
      txt=txt+StrategieOutput(this.BJ_Hands[b].HandsAnalysiert.Element(Hand.AsString()),this.Details);
    txt=txt+"</tr>\n";

    if ((s==5) && (this.RegelVariante==1))
    {
      txt=txt+"<tr>"+td("5-5Respl.");
      Hand=new BJ_Hand(10,second+Split_poss);
      for (b=2;b<=11;b++)
        txt=txt+StrategieOutput(this.BJ_Hands[b].HandsAnalysiert.Element(Hand.AsString()),this.Details);
      txt=txt+"</tr>\n";
    }
  }

  txt=txt+LeereTabellenZeile(11);

  sum=0;
  Hand=new BJ_Hand(0,Split_poss+Dd_poss);
  txt=txt+"<tr>"+td("<small>Expected gains<br>depending on<br>dealer's up card</small>");
  for (b=2;b<=11;b++)
  {
    txt=txt+td("<small>"+Math.round(this.BJ_Hands[b].HandsAnalysiert.Element(Hand.AsString()).GewinnErwOpt*10000)/100 + "%</small>");
    sum=sum+this.BJ_Hands[b].HandsAnalysiert.Element(Hand.AsString()).GewinnErwOpt*this.WvKartenwerte.Prob(b);
  }
  txt=txt+"</tr>\n";

  txt=txt+"</table><br>";  
  txt=txt+"Expected gain at the beginning of a game: <b>"+Math.round(sum*100000)/1000 +"%</b><br>";
  if (this.WvKartenwerte.Prob(10)<=1/3)
    txt=txt+"(Insurance is <b>not</b> favourably)";
  else
  {
    sum=sum+this.WvKartenwerte.Prob(11)* (3*this.WvKartenwerte.Prob(10)-1)/2;
    txt=txt+"Insurance is favourably and increases the everage to ";
    txt=txt+"<b>"+Math.round(sum*100000)/1000 +"%</b>";
  }

  txt=txt+"<br><br><small><i>Without any warranty</i></small><br>";
  txt=txt+"(C) Jörg Bewersdorff, 2002-<br>";
  txt=txt+"The mathematical background is described in my book <i>Luck, Logic and White Lies: The Mathematics of Games</i> (publisher: AK Peters).<br>";
  txt=txt+"<small><a href='http://www.bewersdorff-online.de/index_e.htm' target='_top'>www.bewersdorff-online.de</a>, ";
  txt=txt+"<a href='mailto:mail@bewersdorff-online.de'>mail@bewersdorff-online.de</a></small>";
  txt=txt+"</body></html>";
  return txt;
}


// =======================================================================

function LeereTabellenZeile(SpaltenZahl)
{
  var b,ret;
  ret='<tr height="12">';
  for (b=1;b<=SpaltenZahl;b++)
    ret=ret+td(" ");
  ret=ret+"</tr>\n";
  return ret;
}


function td(inhalt)
{
  var txt;
  switch (inhalt)
  {
    case "Stand":  txt="<font color='#AAAAAA'>Stand</font>"; break;
    case "Draw":   txt="<font color='#33CC33'>Draw</font>";  break;
    case "Split":  txt="<font color='#FF0000'>Split</font>"; break;
    case "Dd":     txt="<font color='#0000FF'>D.d.</font>";  break;
    default:       txt=inhalt;
  }
  return "<td align='center' width='67'>"+txt+"</td>";
}

function tdcolor(Zug)
{
  switch (Zug)
  {
    case "Draw":   return ' bgcolor="#44CC44"';
    case "Split":  return ' bgcolor="#FF6666"'; 
    case "Dd":     return ' bgcolor="#6666FF"';
    default:       return '';
  }    
}

function StrategieOutput(Hand,DetailFlag)
{
  var erw,color;
  if (!DetailFlag)
    return td(Hand.ZugOpt);
  else
  {
    erw=Hand.GewinnErwOpt;
    erw=new String(Math.round(erw*10000)/10000);
    if (erw.indexOf(".")==-1)
      erw=erw+".";
    while (erw.indexOf(".")+4>=erw.length)       // vier Nachkommastellen
      erw=erw+"0";
    return '<td align="right" width="67"' + tdcolor(Hand.ZugOpt) + '><small>'+erw+'</small></td>';
  }
}

