Dave Taylor's Final Cribbage Script


#!/bin/sh

# Cribbage - program to evaluate a cribbage hand and 
# suggest an optimal subset

# In cribbage, you seek cards that add up to 15, sets of 3-4 cards w/ same 
# rank, runs of 3 or more cards and sets of 4 cards of the same suit.

# We'll represent our hand in an array of six cards: hand[0-5] where 
# each card has a value of 1-52, which breaks down into 
# cardnum / 13 = rank and cardnum % 13 = suit

suits[0]="H"; suits[1]="C"; suits[2]="D"; suits[3]="S";
hand[0]=0; hand[1]=0; hand[2]=0; hand[3]=0; hand[4]=0; hand[5]=0;

# combinations of four choose two and four choose three

fourtwo[0]="0 1"; fourtwo[1]="0 2"; fourtwo[2]="0 3"; fourtwo[3]="1 2"
fourtwo[4]="1 3"; fourtwo[5]="2 3"; fourthree[0]="0 1 2"; 
fourthree[1]="0 1 3"; fourthree[2]="0 2 3"; fourthree[3]="1 2 3"

debug=0

showcard()
{
  # given a card value of 0..51 show the suit and rank

  suit=$(( $1 / 13 ))
  rank=$(( ( $1 % 13 ) + 1 ))
  case $rank in
    1)  orank="A" ;;
    11) orank="J" ;;
    12) orank="Q" ;;
    13) orank="K" ;;
     *) orank=$rank ;;
  esac
  showcardvalue=$orank${suits[$suit]}
}

dealhand()
{
   # we need to establish a deck from which to deal 
   # the individual cards (to avoid duplication)

   for i in {0..51}
   do 
     deck[$i]=$i
   done

   # we're not going to "shuffle" the deck because we can 
   # just pick from it randomly instead

   # start with an undealt hand: 
   for card in {0..5} ; do
     hand[$card]=-1
   done

   # now let's deal some cards!
   for card in {0..5} ; do
     until [ ${hand[$card]} -ne -1 ]
     do
       pick=$(( $RANDOM % 52 ))
       hand[$card]=${deck[$pick]}
     done
     deck[$pick]=-1	# we've now dealt it so it's no longer available
   done
}

showhand()
{
   # show our hand neatly

   /bin/echo -n "Hand: "
   for card in {0..4}
   do
     showcard ${hand[$card]}
     /bin/echo -n "$showcardvalue, "
   done
   showcard ${hand[5]}
   echo "$showcardvalue."
}

sorthand()
{
   # hand is dealt, now sort it by card rank...

   index=0
   tempfile=".deleteme"

   for card in {0..5}
   do
     showcard ${hand[$card]} 
     echo "$rank ${hand[$card]}"
   done | sort -n > $tempfile

   while read rank value
   do
     hand[$index]=$value
     index=$(( $index + 1 ))
   done < $tempfile

   rm -f $tempfile
}

Calc4cardValue()
{
  # given four ranks, see if there are any combinations 
  # that add up to 15, pairs, runs or flushes.
  # return total point value of the four card subhand

  points=0 ; runof3=0

  cs0=$9; cs1=${10}; cs2=${11}; cs3=${12}       # suits

  cardrank[0]=$1; cardrank[1]=$2; cardrank[2]=$3; \
  cardrank[3]=$4 # normalized ranks 
  cardrankfull[0]=$5; cardrankfull[1]=$6; cardrankfull[2]=$7; 
  cardrankfull[3]=$8                      # original ranks

  # echo "Calc4cardValue() given original ranks: \
  #      ${cardrankfull[0]} ${cardrankfull[1]} ${cardrankfull[2]} \
  #      ${cardrankfull[3]}"

  # two card combos

  for mysubhand in {0..5}
  do
    sum=0

    for thecard in ${fourtwo[$mysubhand]} 
    do 
      sum=$(( $sum + ${cardrank[$thecard]} ))
    done
    if [ $sum -eq 15 ] ; then
      points=$(( $points + 2 ))
      if [ $debug -eq 1 ] ; then 
        echo "fifteen for two" 
      fi
    fi

    # now let's look at pairs
    #  remember:  ${string:position:length}

    twocards=${fourtwo[$mysubhand]}
    card1=${twocards:0:1}
    card2=${twocards:2}

    if [ ${cardrankfull[$card1]} = ${cardrankfull[$card2]} ] ; then
      if [ $debug -eq 1 ] ; then
        echo "a pair ${cardrankfull[$card1]} and \
                 ${cardrankfull[$card2]} for two"
      fi
      points=$(( $points + 2 ))
    fi
      
  done

  # three card combos

  for mysubhand in {0..3}
  do
    sum=0

    for thecard in ${fourthree[$mysubhand]} 
    do 
      sum=$(( $sum + ${cardrank[$thecard]} ))
    done
    if [ $sum -eq 15 ] ; then
      points=$(( $points + 2 ))
      if [ $debug -eq 1 ] ; then
        echo "three card fifteen for two"
      fi
    fi

    # now let's check for three-card runs
    combo=${fourthree[$mysubhand]}

    if [ $(( ${cardrankfull[${combo:0:1}]} + 1 )) -eq \
              ${cardrankfull[${combo:2:1}]} -a \
         $(( ${cardrankfull[${combo:2:1}]} + 1 )) -eq \
              ${cardrankfull[${combo:4:1}]} ] ; then
      if [ $debug -eq 1 ] ; then
        /bin/echo -n "${cardrankfull[${combo:0:1}]} + \
                ${cardrankfull[${combo:2:1}]} + "
        echo "${cardrankfull[${combo:4:1}]} run for three" 
      fi
      points=$(( $points + 3 ))
      runof3=$(( $runof3 + 1 ))
    fi

  done

  # four cards combos 

  if [ $(( ${cardrank[0]} + ${cardrank[1]} + ${cardrank[2]} + \
            ${cardrank[3]} )) -eq 15 ] ; then
    points=$(( $points + 2 ))
    if [ $debug -eq 1 ] ; then
      echo "four card fifteen for two"
    fi
  fi

  if [ $cs0 -eq $cs1 -a $cs1 -eq $cs2 -a $cs2 -eq $cs3 ] ; then
    if [ $debug -eq 1 ] ; then
      echo "four card flush for four."
    fi
    points=$(( $points + 4 ))
  fi

  if [ $runof3 -eq 2 ] ; then
    if [ $debug -eq 1 ] ; then
      echo "two runs of three = a run of four. minus two"
    fi
    points=$(( $points - 2 ))
  fi

  if [ $debug -eq 1 ] ; then
    echo "Total point value of that hand: $points"
  fi
}


handvalue4()
{
   # given four cards, how much are they worth unto themselves?

   c1=$1; c2=$2; c3=$3; c4=$4
   s1=$(( $c1 / 13 )); s2=$(( $c2 / 13 ))
   s3=$(( $c3 / 13 )); s4=$(( $c4 / 13 ))

   r1=$(( ( $c1 % 13 ) + 1 )); r2=$(( ( $c2 % 13 ) + 1 ))
   r3=$(( ( $c3 % 13 ) + 1 )); r4=$(( ( $c4 % 13 ) + 1 ))

   # now fix rank to normalize for value=10
   case $r1 in 
     11|12|13) nr1=10 ;;
     *) nr1=$r1 ;;
   esac
   case $r2 in
     11|12|13) nr2=10 ;;
     *) nr2=$r2 ;;
   esac
   case $r3 in
     11|12|13) nr3=10 ;;
     *) nr3=$r3 ;;
   esac
   case $r4 in
     11|12|13) nr4=10 ;;
     *) nr4=$r4 ;;
   esac

   ## Ready to start calculating!

   if [ $debug -eq 1 ] ; then
     echo ""
   fi 
   Calc4cardValue $nr1 $nr2 $nr3 $nr4 $r1 $r2 $r3 $r4 $s1 $s2 $s3 $s4
}

if [ $# -gt 0 ] ; then 
  debug=1
fi

dealhand;
sorthand;
showhand;

# six choose four

sixfour[0]="0 1 2 3";  sixfour[1]="0 1 2 4";  sixfour[2]="0 1 2 5";  \
sixfour[3]="0 1 3 4"
sixfour[4]="0 1 3 5";  sixfour[5]="0 1 4 5";  sixfour[6]="0 2 3 4";  \
sixfour[7]="0 2 3 5"
sixfour[8]="0 2 4 5";  sixfour[9]="0 3 4 5";  sixfour[10]="1 2 3 4"; \
sixfour[11]="1 2 3 5"
sixfour[12]="1 2 4 5"; sixfour[13]="1 3 4 5"; sixfour[14]="2 3 4 5"

handvalue=0
besthand=-1

for subhand in {0..14}
do
  if [ $debug -eq 1 ] ; then
    /bin/echo -n "Subhand ${subhand}:" 
  fi
  cardnum=0  # start over
  for thecard in ${sixfour[$subhand]}
  do
    if [ $debug -eq 1 ] ; then
      showcard ${hand[$thecard]}
      /bin/echo -n "  $showcardvalue"
    fi
    oursubhand[$cardnum]=${hand[$thecard]}
    cardnum=$(( $cardnum + 1 ))
  done
  handvalue4 ${oursubhand[0]} ${oursubhand[1]} ${oursubhand[2]} \
                     ${oursubhand[3]}

  if [ $debug -eq 1 ] ; then
    echo ""
  fi

  if [ $points -gt $handvalue ] ; then
    if [ $debug -eq 1 ] ; then
      echo "** hand $subhand is the best yet, adding up to $points points"
    fi
    besthand=$subhand
    handvalue=$points
  fi

done

/bin/echo -n "Your best subhand is worth $handvalue points: "

  for thecard in ${sixfour[$besthand]}
  do
    showcard ${hand[$thecard]}
    /bin/echo -n "  $showcardvalue"
  done

echo ""

exit 0