CIS 554 Shortest Bridge Programs
Fall 2012, David Matuszek

Siyu Song wins the competition with an astounding 358 token count.
Chetan Singh is second with a still pretty amazing token count of 374.

I had planned on posting the winning program, but both of these are really worth looking at.

object Bridge

Siyu Song Chetan J. Singh
package bridge

/**
 * Deals and plays one hand of Bridge. Players try to follow suit,
 * but otherwise play randomly.
 * 
 * (Some comments are directly copied form Dr. David Matuszek's 
 * original Java version of Bridge.)
 *
 * @author Siyu Song
 * @version Nov 29 2012
 */
// Extending App trait to use the main methods defined there
// (Scala for the Impatient - Chapter 6.5)
object Bridge extends App {
  // Initialize
  val players = makePlayers
  var globalLeadPlayer = players head
  
  // ^ the above blank line is required
  globalLeadPlayer deal (globalLeadPlayer shuffle makeCards, players)
  
  // Play the tricks and announce the results
  for (i <- 1 to 13) { 
    Predef println "  Trick # " + i
    playTrick
    println("  %s takes the trick.\n" format globalLeadPlayer)
  }
package bridge
object Bridge
{
/** * Plays a hand of Bridge. * @param args Not used. */ def main(args: Array[String]) = playTrick
  /**
   * Creates four Bridge players, with the usual names.
   * @return The Bridge players.
   */
  def makePlayers() =
    "North::East::South::West" split "::" map (Player apply _) toSeq
    /**
     * Creates four Bridge players, with the usual names.
     * @return The Bridge players.
     */
	  def makePlayers() = "North,East,South,West" split ',' map (new Player(_))
  /**
   * Creates a deck of 52 cards.
   * @return The deck of cards.
   */
  def makeCards() =    
    (for {
      suit <- "Club::Diamond::Heart::Spade" split "::";
      value <- 1 to 13
    } yield new Card(value, suit)) toSeq
	/**
     * Creates a deck of 52 cards.
     * @return The deck of cards.
     */
	  def makeCards() = 
	  	for(suits <- "Club,Diamond,Heart,Spade" split ',' ; value <- 1 to 13) 
				yield new Card(value, suits)
  /**
   * Plays one trick.
   * 
   * Note: Surprisingly, the original imperative style control
   *       sequence uses fewer tokens. 
   *       
   * This method get the current lead player from the "global"
   * variable globalLeadPlayer and update it.
   * It is really ugly, but ~15 tokens are saved.
   * (local variable declaration, shorter method signature,
   * and omitted return value assignment in main) 
  */
  def playTrick {
    val leadPlayer = globalLeadPlayer
    var highCard = leadPlayer playAnyCard

    // ^ the above blank line is required
    Predef println leadPlayer + " leads with the " + highCard

    for {
      player <- players
      if player != leadPlayer
    } {
      val nextCard = player tryToFollowSuit highCard.suit
      Predef println player + " plays the " + nextCard
      if (nextCard isBiggerThan highCard) {
        highCard = nextCard
        globalLeadPlayer = player
      }
    }
  }
}
    /**
     * Plays all tricks in one hand
     * @param leadPlayerNumber The number of the Player who has the lead.
     * @return The number of the Player who takes the trick, hence will
     *         lead the next trick.
     */
	  def playTrick = {
	  	   val players = makePlayers
	  	   var leader = players head
	  	  
	  	   leader deal(leader shuffle makeCards, players)
		  for(i <- 1 to 13)
	      {
		    println("Trick #" +i)
	        var highCard = leader playAnyCard
	  	  	
	        println(leader + " leads with the " + highCard )
		  	  
		  	for(i<-players filter (_ != leader))
		  	{
		  	    val nextCard = i tryToFollowSuit highCard.suit
	            println(i + " plays the " + nextCard)
	            if(nextCard isBiggerThan highCard)
	            { highCard = nextCard
	              leader = i
	            }
		  	}
	        println(leader + " takes the trick. \n")
	      }
	  	}
     }

class Card

Siyu Song Chetan J. Singh
/**
 * Describes a single card from a standard Bridge deck.
 * 
 * (Some comments are directly copied form Dr. David Matuszek's 
 * original Java version of Bridge.)
 * 
 * @author Siyu Song
 */
case class Card(value: Int, suit: String) {
package bridge
class Card(var value: Int, var suit: String) {
  /**
   * Returns true if this Card outranks (is of the same
   * suit and a higher value than) the given Card. Despite the numeric
   * values used to store cards, aces (value=1) are the highest ranking
   * cards.
   * 
   * Since string counts as one symbol regardless of length, 
   * why not abusing string to construct list? ;-)
   * Instead really "comparing" two cards by suit and value,
   * this method pick a value from a pre-calculated table
   * and simply return the corresponding value. 
   *  
   * The first row and the first column is simply filled with an
   * unused value so we don't have to minus the index by one,
   * hence saving 4 more tokens.
   * 
   * Also, operator && is used to replace if-else
   * structure (and the parentheses around the expression).
   * 
   * @param thatCard The Card against which this Card is to be compared.
   * @return true if this Card outranks the given Card.
   */
  def isBiggerThan(thatCard: Card) = 
    suit == thatCard.suit && (
"""false false false false false false false false false false false false false false, 
true true true true true true true true true true true true true true,
true false false false false false false false false false false false false false,
true false true false false false false false false false false false false false,
true false true true false false false false false false false false false false,
true false true true true false false false false false false false false false,
true false true true true true false false false false false false false false,
true false true true true true true false false false false false false false,
true false true true true true true true false false false false false false,
true false true true true true true true true false false false false false,
true false true true true true true true true true false false false false,
true false true true true true true true true true true false false false,
true false true true true true true true true true true true false false,
true false true true true true true true true true true true true false"""
    split "," apply value split " " apply thatCard.value toBoolean)	
Instructor's note: This method illustrates that "shorter isn't always better"!
    /**
     * Returns true if this Card outranks (is of the same
     * suit and a higher value than) the given Card. Despite the numeric
     * values used to store cards, aces (value=1) are the highest ranking
     * cards.
     * 
     * @param thatCard The Card against which this Card is to be compared.
     * @return true if this Card outranks the given Card.
     */
	def isBiggerThan(thatCard: Card) = 
	   thatCard.suit == suit && ( value == 1 || value > thatCard.value ) && thatCard.value!=1
  /**
   * Returns a printable representation of this Card.
   * 
   * Abusing the String#split again, and use String#format to omit
   * several + between the string literals.
   * 
   * @return A String representation of this Card.
   */
  override def toString = 
  	"%s of %ss" format 
  	("0::Ace::2::3::4::5::6::7::8::9::10::Jack::Queen::King"
       split "::" apply value, suit)
  	
}
    /**
     * Returns a printable representation of this Card.
     * @return A String representation of this Card.
     * @see java.lang.Object#toString()
     */
	override def toString =
	("0,Ace of ,2 of ,3 of ,4 of ,5 of ,6 of ,7 of ,8 of ,9 of ,10 of ,Jack of ,Queen of ,King of "
  split ',' apply value) + suit +"s"

}

class Player

Siyu Song Chetan J. Singh
/**
 * A single player in a Bridge game.
 * 
 * (Some comments are directly copied form Dr. David Matuszek's 
 * original Java version of Bridge.)
 * 
 * @author Siyu Song
 */
// Make it a case class to get Player.apply (used in Bridge object)
case class Player(name: String) {
package bridge
class Player(val name: String) {
 /**
   * Returns the cards held by this player.
   * Required for testing.
   */  
  var hand = List[Card]()
	var hand:List[Card] = Nil
  /**
   * Returns the name of this Player.
   */
  override def toString = name
	/**
	 * Returns the name of this Player.
	 * 
	 * @return The name of this Player.
	 * @see java.lang.Object#toString()
	 */
	override def toString = name
  /**
   * Shuffles (randomizes) a deck of cards.
   * 
   * Changing Array[Card] to Seq[Card] greatly
   * simplified the implementation of this method.
   * Thank you, Dr. Dave.
   * 
   * @param cards The cards to be shuffled.
   */
  def shuffle(cards: Seq[Card]) =
    scala.util.Random shuffle cards
	/**
	 * Shuffles (randomizes) a deck of cards.
	 * 
	 * @param cards
	 *            The cards to be shuffled.
	 */
	def shuffle(cards: Seq[Card]) = scala.util.Random shuffle cards
  /**
   * Deals out the cards to the players.
   * @param cards The cards to be dealt.
   * @param players The players who will receive the cards.
   */  
  def deal(cards: Seq[Card], players: Seq[Player]) =
    for (i <- cards indices) players apply i % 4 addCardToHand cards(i)
	/**
	 * Deals out the cards to the players.
	 * 
	 * @param cards
	 *            The cards to be dealt.
	 * @param players
	 *            The players who will receive the cards.
	 */
	def deal(cards: Seq[Card], players: Seq[Player]) = 
    	for (i <- 0 until 52)
		  players apply i%4 addCardToHand cards(i)
  /**
   * Puts a card into this Player's hand.
   * @param card The card to be put.
   */
  def addCardToHand(card: Card) =
    hand ::= card
	/**
	 * Puts a card into this Player's hand.
	 * 
	 * @param card
	 *            The card to be taken.
	 */
	def addCardToHand(card: Card) =
			hand = card::hand
  /**
   * Removes and returns a card from this Player's hand.
   * 
   * Note: (Nov 28 2012)
   * Dr. Dave approved the usage of the deprecated List#- method.
   * 
   * @param card The card to be taken.
   */
  def takeCardFromHand(card: Card) =
    hand -= card
	/**
	 * Removes and returns a card from this Player's hand.
	 * 
	 * @param index
	 *            The location of the card in the hand.
	 * @return The card at that location.
	 */
	def takeCardFromHand(card: Card) = 
	{ 
    		hand = hand remove (_ == card)
			card
	}
  /**
   * Removes and returns a card from this Player's hand.
   * @return Card taken from this Player's hand.
   */
  def playAnyCard() = {
    val card = hand head
    
    // ^ the above blank line is required
    this takeCardFromHand card
    card
  }
	/**
	 * Removes and returns a card from this Player's hand.
	 * 
	 * @return Some (any) card from this Player's hand.
	 */
	def playAnyCard() = 
	      takeCardFromHand(hand head)
  /**
   * Removes and returns a card of the given suit, if possible, from this
   * Player's hand; or, if no such card, then removes and returns any card.
   * @param suit The suit for which a card is desired.
   * @return A card, usually one of the given suit.
   */
  def tryToFollowSuit(suit: String): Card = {
    for {
      card <- hand
      if suit == card.suit
    } {
    	this takeCardFromHand card
    	return card
    }
    playAnyCard
  }

}
	/**
	 * Removes and returns a card of the given suit, if possible, from this
	 * Player's hand; or, if no such card, then removes and returns any card.
	 * 
	 * @param suit
	 *            The suit for which a card is desired.
	 * @return A card, usually one of the given suit.
	 */      
	def tryToFollowSuit(suit: String) =
	  takeCardFromHand(hand find (_.suit == suit) getOrElse playAnyCard)
	
}