// August 1999
package net.sf.nebulacards.util;
import java.util.Enumeration;
import net.sf.nebulacards.main.NullPlayingCard;
import net.sf.nebulacards.main.PileOfCards;
import net.sf.nebulacards.main.PlayingCard;
import net.sf.nebulacards.main.Rules;
import net.sf.nebulacards.main.Tableau;
/**
* Some routines that might be useful to those programming computer players.
* All methods are static, so you do not have to instantiate this class.
*
* @author James Ranson
*/
public class Think
{
/**
* Determine which cards in the given hand can be played.
*
* @param h The hand to be checked.
* @param t The cards that are on the table so far.
* @param bp All the cards that have been played during this hand.
* @param rules A rule set whose validPlay method is to be used.
* @return The cards that are legal plays.
*/
public static PileOfCards validPlays( PileOfCards h,
Tableau t,
PileOfCards bp,
Rules rules )
{
PileOfCards vp = new PileOfCards();
Enumeration cards = h.elements();
while (cards.hasMoreElements())
{
PlayingCard c = (PlayingCard)cards.nextElement();
if (rules.validPlay( bp, t, h, c ))
{
vp.add( c );
}
}
return vp;
}
/**
* Determine who currently has the highest card on the table.
*
* @deprecated Use Rules.whoWinsTrick(Tableau)
* @see Rules#whoWinsTrick(Tableau)
* @param t The cards on the table.
* @return Table position of the person who has the highest card
*/
public static int aheadNow( Tableau t, Rules rules )
{
return rules.whoWinsTrick( t );
}
/**
* Determine what card(s) can be played to take the lead in this trick.
*
* @param vp Possible plays (These <b>must</b> be valid otherwise the result could be erroneous.
* @param t The trick as it stands now.
* @param rules A rule set.
* @param position The table position of the player whose hand we are testing.
* @return All cards in vp that would be the highest in the trick.
*/
public static PileOfCards takeLead( PileOfCards vp, Tableau t,
int position, Rules rules )
{
PileOfCards results = new PileOfCards();
Tableau tableau = new Tableau( t );
if (tableau.howManyCardsNotNull() == 0)
tableau.setLead( position );
Enumeration cards = vp.elements();
while (cards.hasMoreElements())
{
PlayingCard c = (PlayingCard)cards.nextElement();
tableau.set( position, c );
if (rules.whoWinsTrick( tableau ) == position)
results.add( c );
}
return results;
}
/**
* Find the card with the highest value.
*
* @return The highest card.
* @param h The cards to examine.
* @param aceHigh True if aces are higher than kings.
*/
public static PlayingCard highCard( PileOfCards h, boolean aceHigh )
{
PlayingCard high = NullPlayingCard.getInstance();
Enumeration cards = h.elements();
while (cards.hasMoreElements())
{
PlayingCard c = (PlayingCard)cards.nextElement();
if (higherThan( c, high, aceHigh ))
high = c;
}
return high;
}
/**
* Find the card with the lowest pip count.
*
* @return The lowest card.
* @param h The cards to examine.
* @param aceHigh True if aces are higher than kings.
*/
public static PlayingCard lowCard( PileOfCards h, boolean aceHigh )
{
Enumeration cards = h.elements();
if (!cards.hasMoreElements())
return NullPlayingCard.getInstance();
PlayingCard low = (PlayingCard)cards.nextElement();
while (cards.hasMoreElements())
{
PlayingCard c = (PlayingCard)cards.nextElement();
if (higherThan( low, c, aceHigh ))
low = c;
}
return low;
}
/**
* Calculate the probability that someone can take the lead in a trick.
*
* @param tableau The cards that are in the trick so far.
* @param h The cards that might be in the player's hand.
* @param bp All the cards that have been played so far
* @param rules A rule set.
* @param position The table position of the player whose hand is being tested.
* @return A probability from 0 (impossible) to 1 (certain).
*/
public static float canBeat( PileOfCards h, Tableau tableau,
int position, PileOfCards bp, Rules rules )
{
if (tableau == null || tableau.howManyCardsNotNull() == 0)
return (float)1.0;
if (h == null || h.howManyCardsNotNull() == 0)
return (float)0.0;
PileOfCards tl = takeLead( h, tableau, position, rules );
if (tl.howManyCardsNotNull() == 0)
return 0;
PileOfCards vp = validPlays( h, tableau, bp, rules );
float f = 0;
Enumeration tlCards = tl.elements();
while (tlCards.hasMoreElements())
{
PlayingCard c = (PlayingCard)tlCards.nextElement();
if (vp.contains(c))
f += 2.0 / vp.howManyCardsNotNull();
else
f += 1.0;
}
float p = f / (float)vp.howManyCardsNotNull();
p = (float)( p > 1.0 ? 1.0 : p ); // make sure we're not above 1.0
return p;
}
/**
* A temporary replacement for PlayingCard.higherThan()
* @param AceHigh Should aces be considered higher than kings.
* @return True if "a" is strictly higher than "b".
*/
protected static boolean higherThan( PlayingCard a, PlayingCard b,
boolean AceHigh )
{
if (b.isNull())
return (!a.isNull());
if (AceHigh) {
if (a.getValue() == 1 && b.getValue() != 1) return true;
if (b.getValue() == 1) return false; // can't be higher than an ace
// neither card is an ace, so just do a pip comparison
return (a.getValue() > b.getValue());
}
else // if aces are low, than just do a pip comparison
return (a.getValue() > b.getValue());
}
}