Cleaned up boolean if statements, and other requested changes
Added Face type
Created more polished, functional Pass screen

Change-Id: I877a6c9b633893e1bfd5803701bce5a5cf7d5bbe
diff --git a/go/src/hearts/assets/Club.png b/go/src/hearts/assets/Club.png
new file mode 100644
index 0000000..987d86b
--- /dev/null
+++ b/go/src/hearts/assets/Club.png
Binary files differ
diff --git a/go/src/hearts/assets/Diamond.png b/go/src/hearts/assets/Diamond.png
new file mode 100644
index 0000000..d7dba1c
--- /dev/null
+++ b/go/src/hearts/assets/Diamond.png
Binary files differ
diff --git a/go/src/hearts/assets/Heart.png b/go/src/hearts/assets/Heart.png
new file mode 100644
index 0000000..53e2773
--- /dev/null
+++ b/go/src/hearts/assets/Heart.png
Binary files differ
diff --git a/go/src/hearts/assets/Spade.png b/go/src/hearts/assets/Spade.png
new file mode 100644
index 0000000..51a0631
--- /dev/null
+++ b/go/src/hearts/assets/Spade.png
Binary files differ
diff --git a/go/src/hearts/assets/acrossArrow.png b/go/src/hearts/assets/acrossArrow.png
new file mode 100644
index 0000000..4aaa946
--- /dev/null
+++ b/go/src/hearts/assets/acrossArrow.png
Binary files differ
diff --git a/go/src/hearts/assets/blue.png b/go/src/hearts/assets/blue.png
new file mode 100644
index 0000000..e35155c
--- /dev/null
+++ b/go/src/hearts/assets/blue.png
Binary files differ
diff --git a/go/src/hearts/assets/croupierName.png b/go/src/hearts/assets/croupierName.png
new file mode 100644
index 0000000..8a5a1b6
--- /dev/null
+++ b/go/src/hearts/assets/croupierName.png
Binary files differ
diff --git a/go/src/hearts/assets/gray.jpeg b/go/src/hearts/assets/gray.jpeg
new file mode 100644
index 0000000..a47db1a
--- /dev/null
+++ b/go/src/hearts/assets/gray.jpeg
Binary files differ
diff --git a/go/src/hearts/assets/leftArrow.png b/go/src/hearts/assets/leftArrow.png
new file mode 100644
index 0000000..3361ac6
--- /dev/null
+++ b/go/src/hearts/assets/leftArrow.png
Binary files differ
diff --git a/go/src/hearts/assets/passPressed.png b/go/src/hearts/assets/passPressed.png
new file mode 100644
index 0000000..cd8c0aa
--- /dev/null
+++ b/go/src/hearts/assets/passPressed.png
Binary files differ
diff --git a/go/src/hearts/assets/passUnpressed.png b/go/src/hearts/assets/passUnpressed.png
new file mode 100644
index 0000000..1c5db41
--- /dev/null
+++ b/go/src/hearts/assets/passUnpressed.png
Binary files differ
diff --git a/go/src/hearts/assets/rightArrow.png b/go/src/hearts/assets/rightArrow.png
new file mode 100644
index 0000000..048b571
--- /dev/null
+++ b/go/src/hearts/assets/rightArrow.png
Binary files differ
diff --git a/go/src/hearts/assets/white.png b/go/src/hearts/assets/white.png
new file mode 100644
index 0000000..e878403
--- /dev/null
+++ b/go/src/hearts/assets/white.png
Binary files differ
diff --git a/go/src/hearts/img/staticImg.go b/go/src/hearts/img/staticImg.go
new file mode 100644
index 0000000..e5309c5
--- /dev/null
+++ b/go/src/hearts/img/staticImg.go
@@ -0,0 +1,100 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package img
+
+import (
+	"golang.org/x/mobile/exp/sprite"
+	"hearts/logic/card"
+)
+
+func NewStaticImg() *StaticImg {
+	return &StaticImg{}
+}
+
+// Static Images may be buttons, drop targets, or any other image that is not a card object
+type StaticImg struct {
+	node  *sprite.Node
+	image sprite.SubTex
+	// alt may or may not be used
+	// can be used as the 'pressed' image if the StaticImg instance is a button
+	// also can be used as a 'blank' image if the StaticImg instance may disappear
+	alt      sprite.SubTex
+	x        float32
+	y        float32
+	initialX float32
+	initialY float32
+	width    float32
+	height   float32
+	// cardHere is used if the StaticImg instance is a drop target
+	cardHere *card.Card
+}
+
+func (s *StaticImg) GetNode() *sprite.Node {
+	return s.node
+}
+
+func (s *StaticImg) GetImage() sprite.SubTex {
+	return s.image
+}
+
+func (s *StaticImg) GetAlt() sprite.SubTex {
+	return s.alt
+}
+
+func (s *StaticImg) GetX() float32 {
+	return s.x
+}
+
+func (s *StaticImg) GetY() float32 {
+	return s.y
+}
+
+func (s *StaticImg) GetInitialX() float32 {
+	return s.initialX
+}
+
+func (s *StaticImg) GetInitialY() float32 {
+	return s.initialY
+}
+
+func (s *StaticImg) GetWidth() float32 {
+	return s.width
+}
+
+func (s *StaticImg) GetHeight() float32 {
+	return s.height
+}
+
+func (s *StaticImg) GetCardHere() *card.Card {
+	return s.cardHere
+}
+
+func (s *StaticImg) SetNode(n *sprite.Node) {
+	s.node = n
+}
+
+func (s *StaticImg) SetImage(t sprite.SubTex) {
+	s.image = t
+}
+
+func (s *StaticImg) SetAlt(t sprite.SubTex) {
+	s.alt = t
+}
+
+func (s *StaticImg) SetPos(newX float32, newY float32, newWidth float32, newHeight float32) {
+	s.x = newX
+	s.y = newY
+	s.width = newWidth
+	s.height = newHeight
+}
+
+func (s *StaticImg) SetInitialPos(newX float32, newY float32) {
+	s.initialX = newX
+	s.initialY = newY
+}
+
+func (s *StaticImg) SetCardHere(c *card.Card) {
+	s.cardHere = c
+}
diff --git a/go/src/hearts/logic/card/card.go b/go/src/hearts/logic/card/card.go
new file mode 100644
index 0000000..50691d6
--- /dev/null
+++ b/go/src/hearts/logic/card/card.go
@@ -0,0 +1,115 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package card
+
+import (
+	"golang.org/x/mobile/exp/sprite"
+)
+
+type Suit string
+type Face int
+
+const (
+	Heart   Suit = "H"
+	Diamond Suit = "D"
+	Spade   Suit = "S"
+	Club    Suit = "C"
+)
+
+const (
+	Two Face = iota + 2
+	Three
+	Four
+	Five
+	Six
+	Seven
+	Eight
+	Nine
+	Ten
+	Jack
+	Queen
+	King
+	// note: in Hearts, Aces are high
+	Ace
+)
+
+func NewCard(f Face, suit Suit) *Card {
+	return &Card{
+		s:    suit,
+		face: f,
+	}
+}
+
+type Card struct {
+	s        Suit
+	face     Face
+	node     *sprite.Node
+	x        float32
+	y        float32
+	initialX float32
+	initialY float32
+	width    float32
+	height   float32
+}
+
+func (c *Card) GetSuit() Suit {
+	return c.s
+}
+
+func (c *Card) GetFace() Face {
+	return c.face
+}
+
+func (c *Card) GetNode() *sprite.Node {
+	return c.node
+}
+
+func (c *Card) GetX() float32 {
+	return c.x
+}
+
+func (c *Card) GetY() float32 {
+	return c.y
+}
+
+func (c *Card) GetInitialX() float32 {
+	return c.initialX
+}
+
+func (c *Card) GetInitialY() float32 {
+	return c.initialY
+}
+
+func (c *Card) GetWidth() float32 {
+	return c.width
+}
+
+func (c *Card) GetHeight() float32 {
+	return c.height
+}
+
+func (c *Card) SetNode(n *sprite.Node) {
+	c.node = n
+}
+
+func (c *Card) SetPos(newX float32, newY float32, newWidth float32, newHeight float32) {
+	c.x = newX
+	c.y = newY
+	c.width = newWidth
+	c.height = newHeight
+}
+
+func (c *Card) SetInitialPos(newX float32, newY float32) {
+	c.initialX = newX
+	c.initialY = newY
+}
+
+func (c *Card) WorthPoints() bool {
+	worthPoints := false
+	if c.s == Heart || (c.s == Spade && c.face == Queen) {
+		worthPoints = true
+	}
+	return worthPoints
+}
diff --git a/go/src/hearts/logic/player/player.go b/go/src/hearts/logic/player/player.go
new file mode 100644
index 0000000..9d5be79
--- /dev/null
+++ b/go/src/hearts/logic/player/player.go
@@ -0,0 +1,92 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package player
+
+import (
+	"hearts/logic/card"
+)
+
+func NewPlayer(index int) *Player {
+	return &Player{
+		hand:        nil,
+		tricks:      make([]*card.Card, 0),
+		score:       0,
+		playerIndex: index,
+	}
+}
+
+type Player struct {
+	hand        []*card.Card
+	tricks      []*card.Card
+	score       int
+	playerIndex int
+}
+
+func (p *Player) GetHand() []*card.Card {
+	return p.hand
+}
+
+func (p *Player) GetScore() int {
+	return p.score
+}
+
+func (p *Player) GetPlayerIndex() int {
+	return p.playerIndex
+}
+
+func (p *Player) AddToHand(card *card.Card) {
+	p.hand = append(p.hand, card)
+}
+
+func (p *Player) TakeTrick(cards []*card.Card) {
+	p.tricks = append(p.tricks, cards...)
+}
+
+func (p *Player) UpdateScore(score int) {
+	p.score += score
+}
+
+func (p *Player) CalculateScore() int {
+	score := 0
+	for _, c := range p.tricks {
+		if c.GetSuit() == card.Heart {
+			score += 1
+		} else if c.GetSuit() == card.Spade && c.GetFace() == card.Queen {
+			score += 13
+		}
+	}
+	return score
+}
+
+func (p *Player) ResetTricks() {
+	p.tricks = nil
+}
+
+func (p *Player) HasSuit(suit card.Suit) bool {
+	for _, c := range p.hand {
+		if c.GetSuit() == suit {
+			return true
+		}
+	}
+	return false
+}
+
+func (p *Player) HasOnlyHearts() bool {
+	if p.HasSuit(card.Club) || p.HasSuit(card.Diamond) || p.HasSuit(card.Spade) || !p.HasSuit(card.Heart) {
+		return false
+	}
+	return true
+}
+
+func (p *Player) HasAllPoints() bool {
+	for _, c := range p.hand {
+		if c.GetSuit() == card.Diamond || c.GetSuit() == card.Club {
+			return false
+		} else if c.GetSuit() == card.Spade && c.GetFace() != card.Queen {
+			return false
+		}
+	}
+	return true
+}
diff --git a/go/src/hearts/logic/table/table.go b/go/src/hearts/logic/table/table.go
new file mode 100644
index 0000000..027caa8
--- /dev/null
+++ b/go/src/hearts/logic/table/table.go
@@ -0,0 +1,187 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package table
+
+import (
+	"hearts/logic/card"
+	"hearts/logic/player"
+	"math/rand"
+)
+
+func NewTable(p []*player.Player) *Table {
+	return &Table{
+		players:      p,
+		trick:        make([]*card.Card, len(p)),
+		firstPlayed:  -1,
+		allCards:     nil,
+		heartsBroken: false,
+		firstTrick:   true,
+		winCondition: 100,
+	}
+}
+
+type Table struct {
+	// players contains all players in the game, indexed by playerIndex
+	players []*player.Player
+	// trick contains all cards in the current trick, indexed by the playerIndex of the player who played them
+	trick []*card.Card
+	// firstPlayed is the index in trick of the card played first
+	firstPlayed int
+	// allCards contains all 52 cards in the deck. GenerateCards() populates this
+	allCards []*card.Card
+	// heartsBroken returns true if a heart has been played yet in the round, otherwise false
+	heartsBroken bool
+	// firstTrick returns true if the current trick is the first in the round, otherwise false
+	firstTrick bool
+	// winCondition is the number of points needed to win the game
+	// traditionally 100, could set higher or lower for longer or shorter game
+	winCondition int
+}
+
+func (t *Table) GetPlayers() []*player.Player {
+	return t.players
+}
+
+func (t *Table) SetFirstPlayed(index int) {
+	t.firstPlayed = index
+}
+
+// This function generates a traditional deck of 52 cards, with 13 in each of the four suits
+// Each card has a suit (Club, Diamond, Spade, or Heart)
+// Each card also has a number from 2-14, where 11 through 14 represent Jack, Queen, King and Ace, respectively
+func (t *Table) GenerateCards() {
+	cardsPerSuit := 13
+	t.allCards = make([]*card.Card, 0)
+	cardFaces := []card.Face{card.Two, card.Three, card.Four, card.Five, card.Six, card.Seven, card.Eight, card.Nine,
+		card.Ten, card.Jack, card.Queen, card.King, card.Ace}
+	for i := 0; i < cardsPerSuit; i++ {
+		t.allCards = append(t.allCards, card.NewCard(cardFaces[i], card.Club))
+		t.allCards = append(t.allCards, card.NewCard(cardFaces[i], card.Diamond))
+		t.allCards = append(t.allCards, card.NewCard(cardFaces[i], card.Spade))
+		t.allCards = append(t.allCards, card.NewCard(cardFaces[i], card.Heart))
+	}
+}
+
+func (t *Table) PlayCard(c *card.Card, playerIndex int) {
+	t.trick[playerIndex] = c
+	if c.GetSuit() == card.Heart && !t.heartsBroken {
+		t.heartsBroken = true
+	}
+}
+
+func (t *Table) ValidPlay(c *card.Card, playerIndex int) bool {
+	player := t.players[playerIndex]
+	if t.firstPlayed == playerIndex {
+		if !t.firstTrick {
+			if c.GetSuit() != card.Heart || t.heartsBroken {
+				return true
+			} else {
+				if player.HasOnlyHearts() {
+					return true
+				}
+			}
+		} else if c.GetSuit() == card.Club && c.GetFace() == card.Two {
+			return true
+		}
+	} else {
+		firstPlayedSuit := t.trick[t.firstPlayed].GetSuit()
+		if c.GetSuit() == firstPlayedSuit || !player.HasSuit(firstPlayedSuit) {
+			if !t.firstTrick {
+				return true
+			} else if !c.WorthPoints() {
+				return true
+			} else if player.HasAllPoints() {
+				return true
+			}
+		}
+	}
+	return false
+}
+
+func (t *Table) SendTrick() {
+	trickSuit := t.trick[t.firstPlayed].GetSuit()
+	highestCardFace := card.Two
+	highestIndex := -1
+	for i := 0; i < len(t.trick); i++ {
+		curCard := t.trick[i]
+		if curCard.GetSuit() == trickSuit && curCard.GetFace() >= highestCardFace {
+			highestCardFace = curCard.GetFace()
+			highestIndex = i
+		}
+	}
+	// clear trick
+	t.players[highestIndex].TakeTrick(t.trick)
+	t.trick = make([]*card.Card, len(t.players))
+	if t.firstTrick {
+		t.firstTrick = false
+	}
+}
+
+func (t *Table) ScoreRound() {
+	allPoints := 26
+	roundScores := make([]int, len(t.players))
+	shotMoon := false
+	shooter := -1
+	for i := 0; i < len(t.players); i++ {
+		roundScores[i] = t.players[i].CalculateScore()
+		if roundScores[i] == allPoints {
+			shotMoon = true
+			shooter = i
+		}
+	}
+	if shotMoon {
+		for i := 0; i < len(t.players); i++ {
+			if i == shooter {
+				roundScores[i] = 0
+			} else {
+				roundScores[i] = allPoints
+			}
+		}
+	}
+	// sending scores to players
+	for i := 0; i < len(t.players); i++ {
+		t.players[i].UpdateScore(roundScores[i])
+	}
+}
+
+func (t *Table) Deal() {
+	numPlayers := len(t.players)
+	if t.allCards == nil {
+		t.GenerateCards()
+	}
+	shuffle := rand.Perm(len(t.allCards))
+	for i := 0; i < len(t.allCards); i++ {
+		t.players[i%numPlayers].AddToHand(t.allCards[shuffle[i]])
+	}
+}
+
+// returns -1 if the game hasn't been won, playerIndex of the winner if it has
+// to-do: return a list of players in the event of a tie
+func (t *Table) EndRound() int {
+	t.ScoreRound()
+	lowestScore := -1
+	winningPlayer := -1
+	winTriggered := false
+	for _, p := range t.players {
+		p.ResetTricks()
+		if p.GetScore() >= t.winCondition {
+			winTriggered = true
+		}
+		if p.GetScore() < lowestScore || lowestScore == -1 {
+			lowestScore = p.GetScore()
+			winningPlayer = p.GetPlayerIndex()
+		}
+	}
+	if winTriggered {
+		return winningPlayer
+	}
+	return -1
+}
+
+func (t *Table) NewRound() {
+	t.heartsBroken = false
+	t.firstTrick = true
+	t.Deal()
+}
diff --git a/go/src/hearts/main.go b/go/src/hearts/main.go
index e2bfe76..5f13480 100644
--- a/go/src/hearts/main.go
+++ b/go/src/hearts/main.go
@@ -7,11 +7,18 @@
 import (
 	"image"
 	"log"
-	"math"
+	"sort"
+	"strconv"
 	"time"
 
+	_ "image/jpeg"
 	_ "image/png"
 
+	"hearts/img"
+	"hearts/logic/card"
+	"hearts/logic/player"
+	"hearts/logic/table"
+
 	"golang.org/x/mobile/app"
 	"golang.org/x/mobile/asset"
 	"golang.org/x/mobile/event/paint"
@@ -25,33 +32,49 @@
 )
 
 var (
-	startTime = time.Now()
-	eng       = glsprite.Engine()
-	scene     *sprite.Node
-	cards     []*sprite.Node
-	//cardsXY and initialCardsXY are in Pt
-	cardsXY        [][]float32
-	initialCardsXY [][]float32
-	curCardIndex   = -1
-	//lastMouseXY is in Px: divide by ppp to get Pt
+	startTime      = time.Now()
+	eng            = glsprite.Engine()
+	scene          *sprite.Node
+	cards          []*card.Card
+	backgroundImgs []*img.StaticImg
+	emptySuitImgs  []*img.StaticImg
+	dropTargets    []*img.StaticImg
+	buttons        []*img.StaticImg
+	curCard        *card.Card
+	numPlayers     = 4
+	// lastMouseXY is in Px: divide by ppp to get Pt
 	lastMouseXY = []float32{-1, -1}
-	cardWidth   = float32(50)
-	cardHeight  = float32(50)
-	//windowSize is in Pt
-	windowSize = []float32{-1, -1}
-	//ppp stands for pixels per pt
+	cardSize    = 35
+	cardWidth   = float32(cardSize)
+	cardHeight  = float32(cardSize)
+	// windowSize is in Pt
+	windowSize    = []float32{-1, -1}
+	padding       = float32(5)
+	topPadding    = float32(7)
+	bottomPadding = float32(5)
+	// ppp stands for pixels per pt
 	ppp float32
-	//to-do: test and fine-tune these thresholds
+	// to-do: test and fine-tune these thresholds
 	swipeMoveThreshold = 70
 	swipeTimeThreshold = .5
 	swipeStart         time.Time
 	animSpeedScaler    = .1
 	animRotationScaler = .15
+	d                  Direction
+)
+
+type Direction string
+
+const (
+	right  Direction = "R"
+	across Direction = "A"
+	left   Direction = "L"
 )
 
 func main() {
 	app.Main(func(a app.App) {
 		var sz size.Event
+		d = right
 		for e := range a.Events() {
 			switch e := app.Filter(e).(type) {
 			case size.Event:
@@ -62,117 +85,214 @@
 				windowSize[1] = float32(sz.HeightPt)
 				pixelsX := float32(sz.WidthPx)
 				ppp = pixelsX / windowSize[0]
-				adjustCards(oldWidth, oldHeight)
+				adjustImgs(oldWidth, oldHeight)
 			case touch.Event:
-				onTouch(e)
+				onTouch(e, d)
 			case paint.Event:
-				onPaint(sz)
+				onPaint(sz, d)
 				a.EndPaint(e)
 			}
 		}
 	})
 }
 
-func onTouch(t touch.Event) {
+func onTouch(t touch.Event, dir Direction) {
 	switch t.Type.String() {
 	case "begin":
+		// i goes from the end backwards so that it checks cards displayed on top of other cards first
 		for i := len(cards) - 1; i >= 0; i-- {
-			if t.X/ppp >= getCardX(i) &&
-				t.Y/ppp >= getCardY(i) &&
-				t.X/ppp <= cardWidth+getCardX(i) &&
-				t.Y/ppp <= cardHeight+getCardY(i) {
+			curCard = cards[i]
+			if t.X/ppp >= curCard.GetX() &&
+				t.Y/ppp >= curCard.GetY() &&
+				t.X/ppp <= curCard.GetWidth()+curCard.GetX() &&
+				t.Y/ppp <= curCard.GetHeight()+curCard.GetY() {
 				swipeStart = time.Now()
-				curCardIndex = i
-				node := getCardNode(i)
+				node := curCard.GetNode()
 				node.Arranger = nil
 				lastMouseXY[0] = t.X
 				lastMouseXY[1] = t.Y
 				return
+			} else {
+				curCard = nil
+			}
+		}
+		for _, b := range buttons {
+			if t.X/ppp >= b.GetX() &&
+				t.Y/ppp >= b.GetY() &&
+				t.X/ppp <= b.GetWidth()+b.GetX() &&
+				t.Y/ppp <= b.GetHeight()+b.GetY() {
+				eng.SetSubTex(b.GetNode(), b.GetAlt())
+				for _, d := range dropTargets {
+					passCard := d.GetCardHere()
+					if passCard != nil {
+						animate(passCard, dir, t)
+						d.SetCardHere(nil)
+					}
+				}
 			}
 		}
 	case "move":
-		if curCardIndex > -1 {
-			eng.SetTransform(cards[curCardIndex], f32.Affine{
-				{cardWidth, 0, getCardX(curCardIndex) + (t.X-lastMouseXY[0])/ppp},
-				{0, cardHeight, getCardY(curCardIndex) + (t.Y-lastMouseXY[1])/ppp},
+		if curCard != nil {
+			newX := curCard.GetX() + (t.X-lastMouseXY[0])/ppp
+			newY := curCard.GetY() + (t.Y-lastMouseXY[1])/ppp
+			width := curCard.GetWidth()
+			height := curCard.GetHeight()
+			eng.SetTransform(curCard.GetNode(), f32.Affine{
+				{width, 0, newX},
+				{0, height, newY},
 			})
-			setCardX(curCardIndex, getCardX(curCardIndex)+(t.X-lastMouseXY[0])/ppp)
-			setCardY(curCardIndex, getCardY(curCardIndex)+(t.Y-lastMouseXY[1])/ppp)
+			curCard.SetPos(newX, newY, width, height)
 			lastMouseXY[0] = t.X
 			lastMouseXY[1] = t.Y
 		}
 	case "end":
-		if curCardIndex > -1 {
-			xDiff := getCardX(curCardIndex) - getInitialX(curCardIndex)
-			yDiff := getCardY(curCardIndex) - getInitialY(curCardIndex)
-			timeDiff := time.Since(swipeStart).Seconds()
-			if (math.Abs(float64(xDiff))+math.Abs(float64(yDiff))) >= float64(swipeMoveThreshold) && timeDiff <= float64(swipeTimeThreshold) {
-				animate(xDiff, yDiff, t)
-			} else {
-				eng.SetTransform(cards[curCardIndex], f32.Affine{
-					{cardWidth, 0, getInitialX(curCardIndex)},
-					{0, cardHeight, getInitialY(curCardIndex)},
-				})
-				setCardX(curCardIndex, getInitialX(curCardIndex))
-				setCardY(curCardIndex, getInitialY(curCardIndex))
+		if curCard != nil {
+			successfulDrop := false
+			for _, d := range dropTargets {
+				// checking to see if card was dropped onto a drop target
+				if t.X/ppp >= d.GetX() &&
+					t.Y/ppp >= d.GetY() &&
+					t.X/ppp <= d.GetWidth()+d.GetX() &&
+					t.Y/ppp <= d.GetHeight()+d.GetY() {
+					lastDroppedCard := d.GetCardHere()
+					if lastDroppedCard != nil {
+						resetCardPosition(lastDroppedCard)
+					}
+					oldY := curCard.GetInitialY()
+					suit := curCard.GetSuit()
+					newX := d.GetX()
+					newY := d.GetY()
+					width := curCard.GetWidth()
+					height := curCard.GetHeight()
+					eng.SetTransform(curCard.GetNode(), f32.Affine{
+						{width, 0, newX},
+						{0, height, newY},
+					})
+					curCard.SetPos(newX, newY, width, height)
+					d.SetCardHere(curCard)
+					successfulDrop = true
+					// realign suit the card just left
+					realignSuit(suit, oldY)
+				} else {
+					// checking to see if card was removed from a dop target
+					if d.GetCardHere() == curCard {
+						d.SetCardHere(nil)
+					}
+				}
+			}
+			if !successfulDrop {
+				resetCardPosition(curCard)
 			}
 		}
-		curCardIndex = -1
+		for _, b := range buttons {
+			eng.SetSubTex(b.GetNode(), b.GetImage())
+		}
+		curCard = nil
 	}
 }
 
-func adjustCards(oldWidth, oldHeight float32) {
-	for i := 0; i < len(cards); i++ {
-		node := getCardNode(i)
-		oldX := getCardX(i)
-		newX := (oldX+cardWidth/2)/oldWidth*windowSize[0] - cardWidth/2
-		oldY := getCardY(i)
-		newY := (oldY+cardHeight/2)/oldHeight*windowSize[1] - cardHeight/2
+func resetCardPosition(c *card.Card) {
+	newX := c.GetInitialX()
+	newY := c.GetInitialY()
+	eng.SetTransform(c.GetNode(), f32.Affine{
+		{c.GetWidth(), 0, newX},
+		{0, c.GetHeight(), newY},
+	})
+	c.SetPos(newX, newY, c.GetWidth(), c.GetHeight())
+	realignSuit(c.GetSuit(), newY)
+}
+
+// returns coordinates for images with same width and height but in new positions proportional to the screen
+func adjustKeepDimensions(oldX, oldY, oldInitialX, oldInitialY, oldImgWidth, oldImgHeight, oldWindowWidth, oldWindowHeight float32) (float32, float32, float32, float32, float32, float32) {
+	newX := (oldX+oldImgWidth/2)/oldWindowWidth*windowSize[0] - oldImgWidth/2
+	newY := (oldY+oldImgHeight/2)/oldWindowHeight*windowSize[1] - oldImgHeight/2
+	newInitialX := (oldInitialX+oldImgWidth/2)/oldWindowWidth*windowSize[0] - oldImgWidth/2
+	newInitialY := (oldInitialY+oldImgHeight/2)/oldWindowHeight*windowSize[1] - oldImgHeight/2
+	return newX, newY, newInitialX, newInitialY, oldImgWidth, oldImgHeight
+}
+
+// returns coordinates for images with position, width and height scaled proportional to the screen
+func adjustScaleDimensions(oldX, oldY, oldInitialX, oldInitialY, oldImgWidth, oldImgHeight, oldWindowWidth, oldWindowHeight float32) (float32, float32, float32, float32, float32, float32) {
+	newImgWidth := oldImgWidth / oldWindowWidth * windowSize[0]
+	newImgHeight := oldImgHeight / oldWindowHeight * windowSize[1]
+	newX := oldX / oldWindowWidth * windowSize[0]
+	newY := oldY / oldWindowHeight * windowSize[1]
+	newInitialX := oldInitialX / oldWindowWidth * windowSize[0]
+	newInitialY := oldInitialY / oldWindowHeight * windowSize[1]
+	return newX, newY, newInitialX, newInitialY, newImgWidth, newImgHeight
+}
+
+func adjustImgArray(imgs []*img.StaticImg, oldWindowWidth, oldWindowHeight float32) {
+	for _, s := range imgs {
+		node := s.GetNode()
+		oldImgWidth := s.GetWidth()
+		oldImgHeight := s.GetHeight()
+		oldX := s.GetX()
+		oldY := s.GetY()
+		oldInitialX := s.GetInitialX()
+		oldInitialY := s.GetInitialY()
+		newX, newY, newInitialX, newInitialY, newImgWidth, newImgHeight := adjustScaleDimensions(oldX, oldY,
+			oldInitialX, oldInitialY, oldImgWidth, oldImgHeight, oldWindowWidth, oldWindowHeight)
 		eng.SetTransform(node, f32.Affine{
-			{cardWidth, 0, newX},
-			{0, cardHeight, newY},
+			{newImgWidth, 0, newX},
+			{0, newImgHeight, newY},
 		})
-		setCardX(i, newX)
-		setCardY(i, newY)
-		oldInitialX := getInitialX(i)
-		newInitialX := (oldInitialX+cardWidth/2)/oldWidth*windowSize[0] - cardWidth/2
-		oldInitialY := getInitialY(i)
-		newInitialY := (oldInitialY+cardHeight/2)/oldHeight*windowSize[1] - cardHeight/2
-		setInitialX(i, newInitialX)
-		setInitialY(i, newInitialY)
+		s.SetPos(newX, newY, newImgWidth, newImgHeight)
+		s.SetInitialPos(newInitialX, newInitialY)
 	}
 }
 
-func animate(xDiff float32, yDiff float32, touch touch.Event) {
-	index := curCardIndex
-	curCardIndex = -1
-	node := getCardNode(index)
+func adjustImgs(oldWindowWidth, oldWindowHeight float32) {
+	if windowSize[0] > -1 && oldWindowWidth > -1 {
+		padding = padding * windowSize[0] / oldWindowWidth
+	}
+	for _, c := range cards {
+		node := c.GetNode()
+		oldCardWidth := c.GetWidth()
+		oldCardHeight := c.GetHeight()
+		oldX := c.GetX()
+		oldInitialX := c.GetInitialX()
+		oldY := c.GetY()
+		oldInitialY := c.GetInitialY()
+		newX, newY, newInitialX, newInitialY, newCardWidth, newCardHeight := adjustScaleDimensions(oldX, oldY,
+			oldInitialX, oldInitialY, oldCardWidth, oldCardHeight, oldWindowWidth, oldWindowHeight)
+		eng.SetTransform(node, f32.Affine{
+			{newCardWidth, 0, newX},
+			{0, newCardHeight, newY},
+		})
+		c.SetPos(newX, newY, newCardWidth, newCardHeight)
+		c.SetInitialPos(newInitialX, newInitialY)
+	}
+	adjustImgArray(dropTargets, oldWindowWidth, oldWindowHeight)
+	adjustImgArray(backgroundImgs, oldWindowWidth, oldWindowHeight)
+	adjustImgArray(buttons, oldWindowWidth, oldWindowHeight)
+	adjustImgArray(emptySuitImgs, oldWindowWidth, oldWindowHeight)
+}
+
+func animate(animCard *card.Card, dir Direction, touch touch.Event) {
+	node := animCard.GetNode()
 	startTime := -1
 	node.Arranger = arrangerFunc(func(eng sprite.Engine, node *sprite.Node, t clock.Time) {
 		if startTime == -1 {
 			startTime = int(t)
 		}
 		moveSpeed := float32(int(t)-startTime) * float32(animSpeedScaler)
-		x := getCardX(index)
-		y := getCardY(index)
-		if math.Abs(float64(xDiff)) > math.Abs(float64(yDiff)) {
-			if xDiff > 0 {
-				x = x + moveSpeed
-			} else {
-				x = x - moveSpeed
-			}
-		} else {
-			if yDiff > 0 {
-				y = y + moveSpeed
-			} else {
-				y = y - moveSpeed
-			}
+		x := animCard.GetX()
+		y := animCard.GetY()
+		width := animCard.GetWidth()
+		height := animCard.GetHeight()
+		switch dir {
+		case right:
+			x = x + moveSpeed
+		case left:
+			x = x - moveSpeed
+		case across:
+			y = y - moveSpeed
 		}
-		setCardX(index, x)
-		setCardY(index, y)
+		animCard.SetPos(x, y, width, height)
 		position := f32.Affine{
-			{cardWidth, 0, x + cardWidth/2},
-			{0, cardHeight, y + cardHeight/2},
+			{width, 0, x + width/2},
+			{0, height, y + height/2},
 		}
 		position.Rotate(&position, float32(t)*float32(animRotationScaler))
 		position.Translate(&position, -.5, -.5)
@@ -180,9 +300,9 @@
 	})
 }
 
-func onPaint(sz size.Event) {
+func onPaint(sz size.Event, dir Direction) {
 	if scene == nil {
-		loadScene()
+		loadPassScreen(dir)
 	}
 	gl.ClearColor(1, 1, 1, 1)
 	gl.Clear(gl.COLOR_BUFFER_BIT)
@@ -197,59 +317,146 @@
 	return n
 }
 
-//x and y should be in Pt
-func addCard(x float32, y float32, spriteTex sprite.SubTex) {
+func initializeGame() *table.Table {
+	players := make([]*player.Player, 0)
+	for i := 0; i < numPlayers; i++ {
+		players = append(players, player.NewPlayer(i))
+	}
+	return table.NewTable(players)
+}
+
+func realignSuit(suitName card.Suit, oldY float32) {
+	cardsToAlign := make([]*card.Card, 0)
+	for _, c := range cards {
+		if c.GetSuit() == suitName && c.GetY() == oldY {
+			cardsToAlign = append(cardsToAlign, c)
+		}
+	}
+	var emptySuitImg *img.StaticImg
+	switch suitName {
+	case card.Club:
+		emptySuitImg = emptySuitImgs[0]
+	case card.Diamond:
+		emptySuitImg = emptySuitImgs[1]
+	case card.Spade:
+		emptySuitImg = emptySuitImgs[2]
+	case card.Heart:
+		emptySuitImg = emptySuitImgs[3]
+	}
+	if len(cardsToAlign) == 0 {
+		eng.SetSubTex(emptySuitImg.GetNode(), emptySuitImg.GetImage())
+	} else {
+		eng.SetSubTex(emptySuitImg.GetNode(), emptySuitImg.GetAlt())
+	}
+	for i, c := range cardsToAlign {
+		width := c.GetWidth()
+		height := c.GetHeight()
+		diff := float32(len(cardsToAlign))*(padding+width) - (windowSize[0] - padding)
+		x := padding + float32(i)*(padding+width)
+		if diff > 0 && i > 0 {
+			x -= diff * float32(i) / float32(len(cardsToAlign)-1)
+		}
+		y := oldY
+		c.SetPos(x, y, width, height)
+		c.SetInitialPos(x, y)
+		eng.SetTransform(c.GetNode(), f32.Affine{
+			{width, 0, x},
+			{0, height, y},
+		})
+	}
+}
+
+func addCard(c *card.Card, texs map[string]sprite.SubTex, numInSuit, clubCount, diamondCount, spadeCount, heartCount int) {
+	var texKey string
+	var suitCount float32
+	var heightScaler float32
+	switch c.GetSuit() {
+	case card.Club:
+		texKey = "Clubs-"
+		suitCount = float32(clubCount)
+		heightScaler = 4
+	case card.Diamond:
+		texKey = "Diamonds-"
+		suitCount = float32(diamondCount)
+		heightScaler = 3
+	case card.Spade:
+		texKey = "Spades-"
+		suitCount = float32(spadeCount)
+		heightScaler = 2
+	case card.Heart:
+		texKey = "Hearts-"
+		suitCount = float32(heartCount)
+		heightScaler = 1
+	}
+	log.Println(c.GetFace())
+	log.Println(card.Two)
+	switch c.GetFace() {
+	case card.Jack:
+		texKey += "Jack"
+	case card.Queen:
+		texKey += "Queen"
+	case card.King:
+		texKey += "King"
+	case card.Ace:
+		texKey += "Ace"
+	default:
+		texKey += strconv.Itoa(int(c.GetFace()))
+	}
+	texKey += ".png"
+	log.Println(texKey)
 	n := newNode()
-	eng.SetSubTex(n, spriteTex)
-	eng.SetTransform(n, f32.Affine{
-		{cardWidth, 0, x},
-		{0, cardHeight, y},
+	eng.SetSubTex(n, texs[texKey])
+	c.SetNode(n)
+	diff := suitCount*(padding+cardWidth) - (windowSize[0] - padding)
+	x := padding + float32(numInSuit)*(padding+cardWidth)
+	if diff > 0 && numInSuit > 0 {
+		x -= diff * float32(numInSuit) / (suitCount - 1)
+	}
+	y := windowSize[1] - heightScaler*(cardHeight+padding) - bottomPadding
+	width := cardWidth
+	height := cardHeight
+	c.SetPos(x, y, width, height)
+	c.SetInitialPos(x, y)
+	eng.SetTransform(c.GetNode(), f32.Affine{
+		{width, 0, x},
+		{0, height, y},
 	})
-	cards = append(cards, n)
-	cardsXY = append(cardsXY, []float32{x, y})
-	initialCardsXY = append(initialCardsXY, []float32{x, y})
 }
 
-func getCardX(cardIndex int) float32 {
-	return cardsXY[cardIndex][0]
+func addImgWithoutAlt(t sprite.SubTex, x, y, width, height float32) *img.StaticImg {
+	n := newNode()
+	eng.SetSubTex(n, t)
+	eng.SetTransform(n, f32.Affine{
+		{width, 0, x},
+		{0, height, y},
+	})
+	s := img.NewStaticImg()
+	s.SetNode(n)
+	s.SetImage(t)
+	s.SetPos(x, y, width, height)
+	s.SetInitialPos(x, y)
+	return s
 }
 
-func setCardX(cardIndex int, newX float32) {
-	cardsXY[cardIndex][0] = newX
+func addImgWithAlt(t sprite.SubTex, alt sprite.SubTex, x, y, width, height float32, displayImage bool) *img.StaticImg {
+	n := newNode()
+	if displayImage {
+		eng.SetSubTex(n, t)
+	}
+	eng.SetTransform(n, f32.Affine{
+		{width, 0, x},
+		{0, height, y},
+	})
+	s := img.NewStaticImg()
+	s.SetNode(n)
+	s.SetImage(t)
+	s.SetAlt(alt)
+	s.SetPos(x, y, width, height)
+	s.SetInitialPos(x, y)
+	return s
 }
 
-func getCardY(cardIndex int) float32 {
-	return cardsXY[cardIndex][1]
-}
-
-func setCardY(cardIndex int, newY float32) {
-	cardsXY[cardIndex][1] = newY
-}
-
-func getCardNode(cardIndex int) *sprite.Node {
-	return cards[cardIndex]
-}
-
-func getInitialX(cardIndex int) float32 {
-	return initialCardsXY[cardIndex][0]
-}
-
-func getInitialY(cardIndex int) float32 {
-	return initialCardsXY[cardIndex][1]
-}
-
-func setInitialX(cardIndex int, newX float32) {
-	initialCardsXY[cardIndex][0] = newX
-}
-
-func setInitialY(cardIndex int, newY float32) {
-	initialCardsXY[cardIndex][1] = newY
-}
-
-func loadScene() {
-	cards = make([]*sprite.Node, 0)
-	cardsXY = make([][]float32, 0)
-	initialCardsXY = make([][]float32, 0)
+func loadPassScreen(dir Direction) {
 	texs := loadTextures()
 	scene = &sprite.Node{}
 	eng.Register(scene)
@@ -257,10 +464,162 @@
 		{1, 0, 0},
 		{0, 1, 0},
 	})
-	for _, v := range texs {
-		x := windowSize[0]/2 - cardWidth/2
-		y := windowSize[1]/2 - cardHeight/2
-		addCard(x, y, v)
+	t := initializeGame()
+	t.Deal()
+	cards = t.GetPlayers()[1].GetHand()
+	dropTargets = make([]*img.StaticImg, 0)
+	backgroundImgs = make([]*img.StaticImg, 0)
+	emptySuitImgs = make([]*img.StaticImg, 0)
+	buttons = make([]*img.StaticImg, 0)
+	sort.Sort(cardSorter(cards))
+	clubCount := 0
+	diamondCount := 0
+	spadeCount := 0
+	heartCount := 0
+	for i := 0; i < len(cards); i++ {
+		switch cards[i].GetSuit() {
+		case card.Club:
+			clubCount++
+		case card.Diamond:
+			diamondCount++
+		case card.Spade:
+			spadeCount++
+		case card.Heart:
+			heartCount++
+		}
+	}
+	suitCounts := []int{clubCount, diamondCount, spadeCount, heartCount}
+	numSuits := 4
+	numDropTargets := 3
+	// adding blue banner for croupier header
+	image := texs["blue.png"]
+	headerX := float32(0)
+	headerY := float32(0)
+	headerWidth := windowSize[0]
+	var headerHeight float32
+	if 2*cardHeight < headerWidth/4 {
+		headerHeight = 2 * cardHeight
+	} else {
+		headerHeight = headerWidth / 4
+	}
+	header := addImgWithoutAlt(image, headerX, headerY, headerWidth, headerHeight)
+	backgroundImgs = append(backgroundImgs, header)
+	// adding croupier name on top of banner
+	image = texs["croupierName.png"]
+	var width float32
+	var height float32
+	if headerHeight-topPadding > headerWidth/6 {
+		width = headerWidth / 2
+		height = width / 3
+	} else {
+		height = 2 * headerHeight / 3
+		width = height * 3
+	}
+	x := headerX + (headerWidth-width)/2
+	y := headerY + (headerHeight-height+topPadding)/2
+	headerText := addImgWithoutAlt(image, x, y, width, height)
+	backgroundImgs = append(backgroundImgs, headerText)
+	// adding blue background banner for drop targets
+	topOfHand := windowSize[1] - 5*(cardHeight+padding) - (2 * padding / 5) - bottomPadding
+	image = texs["blue.png"]
+	x = float32(0)
+	passBannerY := topOfHand - (2 * padding)
+	width = windowSize[0]
+	height = cardHeight + (4 * padding / 5)
+	newImg := addImgWithoutAlt(image, x, passBannerY, width, height)
+	backgroundImgs = append(backgroundImgs, newImg)
+	// adding drop targets
+	for i := 0; i < numDropTargets; i++ {
+		image := texs["white.png"]
+		width := cardWidth
+		height := cardHeight
+		x := windowSize[0]/2 - (width+float32(numDropTargets)*(padding+width))/2 + float32(i)*(padding+width)
+		y := passBannerY + (2 * padding / 5)
+		newTarget := addImgWithoutAlt(image, x, y, width, height)
+		dropTargets = append(dropTargets, newTarget)
+	}
+	// adding pass button
+	pressedImg := texs["passPressed.png"]
+	unpressedImg := texs["passUnpressed.png"]
+	width = cardWidth
+	height = cardHeight / 2
+	x = windowSize[0]/2 + (float32(numDropTargets)*(padding+width)-width)/2
+	passY := passBannerY + (2 * padding / 5)
+	newButton := addImgWithAlt(unpressedImg, pressedImg, x, passY, width, height, true)
+	buttons = append(buttons, newButton)
+	// adding arrow below pass button
+	var a *img.StaticImg
+	if dir == right {
+		image := texs["rightArrow.png"]
+		width := cardWidth
+		height := cardHeight / 2
+		x := windowSize[0]/2 + (float32(numDropTargets)*(padding+cardWidth)-width)/2
+		y := passY + cardHeight/2
+		a = addImgWithoutAlt(image, x, y, width, height)
+	} else if dir == left {
+		image := texs["leftArrow.png"]
+		width := cardWidth
+		height := cardHeight / 2
+		x := windowSize[0]/2 + (float32(numDropTargets)*(padding+cardWidth)-width)/2
+		y := passY + cardHeight/2
+		a = addImgWithoutAlt(image, x, y, width, height)
+	} else {
+		image := texs["acrossArrow.png"]
+		width := cardWidth / 4
+		height := cardHeight / 2
+		x := windowSize[0]/2 + (float32(numDropTargets)*(padding+cardWidth)-width)/2
+		y := passY + cardHeight/2
+		a = addImgWithoutAlt(image, x, y, width, height)
+	}
+	backgroundImgs = append(backgroundImgs, a)
+	// adding gray background banners for each suit
+	for i := 0; i < numSuits; i++ {
+		image := texs["gray.jpeg"]
+		x := float32(0)
+		y := windowSize[1] - float32(i+1)*(cardHeight+padding) - (2 * padding / 5) - bottomPadding
+		width := windowSize[0]
+		height := cardHeight + (4 * padding / 5)
+		newImg := addImgWithoutAlt(image, x, y, width, height)
+		backgroundImgs = append(backgroundImgs, newImg)
+	}
+	// adding suit image to any empty suit in hand
+	for i, c := range suitCounts {
+		var texKey string
+		switch i {
+		case 0:
+			texKey = "Club.png"
+		case 1:
+			texKey = "Diamond.png"
+		case 2:
+			texKey = "Spade.png"
+		case 3:
+			texKey = "Heart.png"
+		}
+		image := texs[texKey]
+		alt := texs["gray.png"]
+		x := windowSize[0]/2 - cardWidth/3
+		y := windowSize[1] - float32(4-i)*(cardHeight+padding) + cardHeight/6 - bottomPadding
+		width := 2 * cardWidth / 3
+		height := 2 * cardHeight / 3
+		display := c == 0
+		newSuitImg := addImgWithAlt(image, alt, x, y, width, height, display)
+		emptySuitImgs = append(emptySuitImgs, newSuitImg)
+	}
+	// adding clubs
+	for i := 0; i < clubCount; i++ {
+		addCard(cards[i], texs, i, clubCount, diamondCount, spadeCount, heartCount)
+	}
+	// adding diamonds
+	for i := clubCount; i < clubCount+diamondCount; i++ {
+		addCard(cards[i], texs, i-clubCount, clubCount, diamondCount, spadeCount, heartCount)
+	}
+	// adding spades
+	for i := clubCount + diamondCount; i < clubCount+diamondCount+spadeCount; i++ {
+		addCard(cards[i], texs, i-clubCount-diamondCount, clubCount, diamondCount, spadeCount, heartCount)
+	}
+	// adding hearts
+	for i := clubCount + diamondCount + spadeCount; i < clubCount+diamondCount+spadeCount+heartCount; i++ {
+		addCard(cards[i], texs, i-clubCount-diamondCount-spadeCount, clubCount, diamondCount, spadeCount, heartCount)
 	}
 }
 
@@ -273,7 +632,9 @@
 		"Spades-2.png", "Spades-3.png", "Spades-4.png", "Spades-5.png", "Spades-6.png", "Spades-7.png", "Spades-8.png",
 		"Spades-9.png", "Spades-10.png", "Spades-Jack.png", "Spades-Queen.png", "Spades-King.png", "Spades-Ace.png",
 		"Hearts-2.png", "Hearts-3.png", "Hearts-4.png", "Hearts-5.png", "Hearts-6.png", "Hearts-7.png", "Hearts-8.png",
-		"Hearts-9.png", "Hearts-10.png", "Hearts-Jack.png", "Hearts-Queen.png", "Hearts-King.png", "Hearts-Ace.png"}
+		"Hearts-9.png", "Hearts-10.png", "Hearts-Jack.png", "Hearts-Queen.png", "Hearts-King.png", "Hearts-Ace.png",
+		"Club.png", "Diamond.png", "Spade.png", "Heart.png", "gray.jpeg", "blue.png", "white.png", "passPressed.png",
+		"passUnpressed.png", "leftArrow.png", "rightArrow.png", "acrossArrow.png", "croupierName.png"}
 	for _, f := range files {
 		a, err := asset.Open(f)
 		if err != nil {
@@ -289,7 +650,15 @@
 		if err != nil {
 			log.Fatal(err)
 		}
-		allTexs[f] = sprite.SubTex{t, image.Rect(0, 0, 100, 100)}
+		imgWidth, imgHeight := t.Bounds()
+		if f == "Club.png" || f == "Diamond.png" || f == "Spade.png" || f == "Heart.png" || f == "rightArrow.png" ||
+			f == "leftArrow.png" || f == "acrossArrow.png" || f == "passUnpressed.png" || f == "passPressed.png" ||
+			f == "croupierName.png" {
+			allTexs[f] = sprite.SubTex{t, image.Rect(1, 1, imgWidth-1, imgHeight-1)}
+		} else {
+			allTexs[f] = sprite.SubTex{t, image.Rect(0, 0, imgWidth, imgHeight)}
+		}
+
 	}
 	return allTexs
 }
@@ -297,3 +666,31 @@
 type arrangerFunc func(e sprite.Engine, n *sprite.Node, t clock.Time)
 
 func (a arrangerFunc) Arrange(e sprite.Engine, n *sprite.Node, t clock.Time) { a(e, n, t) }
+
+type cardSorter []*card.Card
+
+func (cs cardSorter) Len() int {
+	return len(cs)
+}
+
+func (cs cardSorter) Swap(i, j int) {
+	cs[i], cs[j] = cs[j], cs[i]
+}
+
+func (cs cardSorter) Less(i, j int) bool {
+	if cs[i].GetSuit() == cs[j].GetSuit() {
+		return cs[i].GetFace() < cs[j].GetFace()
+	} else {
+		switch cs[i].GetSuit() {
+		case card.Club:
+			return true
+		case card.Diamond:
+			return cs[j].GetSuit() != card.Club
+		case card.Spade:
+			return cs[j].GetSuit() == card.Heart
+		case card.Heart:
+			return false
+		}
+	}
+	return true
+}