Put switch chan case in goroutine

Change-Id: I8999f36d237600ffd694a0bb81bf9d87d35d1894
diff --git a/go/Makefile b/go/Makefile
index f49facf..2144da3 100644
--- a/go/Makefile
+++ b/go/Makefile
@@ -26,12 +26,10 @@
 delete:
 	rm -rf tmp/$(name)
 
-# Naming collisions for different instances of syncbase for the same user?
-# Easy way to make --v23.permissions.literal?
 .PHONY:
 syncbase: delete bin/syncbased credentials tmp
 	$(eval blessing := $(shell bin/principal dump --v23.credentials=./credentials -s=true))
-	$(eval email := $(subst dev.v.io/u/,,$(blessing)))
+	$(eval email := $(subst dev.v.io:u:,,$(blessing)))
 	bin/syncbased \
 		--v=5 \
 		--alsologtostderr=false \
@@ -52,4 +50,5 @@
 
 all: fmt 
 
-	#--name=/192.168.86.254:8101/croupier/$(name) \
\ No newline at end of file
+# Switch mountpoints by replacing the --name flag in syncbase with the following line:
+# --name=/192.168.86.254:8101/croupier/$(name) \
\ No newline at end of file
diff --git a/go/src/hearts/assets/Period.png b/go/src/hearts/assets/Period.png
new file mode 100644
index 0000000..10e1329
--- /dev/null
+++ b/go/src/hearts/assets/Period.png
Binary files differ
diff --git a/go/src/hearts/img/reposition/reposition.go b/go/src/hearts/img/reposition/reposition.go
index 449eae8..9d894b1 100644
--- a/go/src/hearts/img/reposition/reposition.go
+++ b/go/src/hearts/img/reposition/reposition.go
@@ -62,7 +62,7 @@
 func SetTableDropColors(u *uistate.UIState) {
 	blueTargetIndex := u.CurTable.WhoseTurn()
 	for i, d := range u.DropTargets {
-		if i == blueTargetIndex {
+		if i == blueTargetIndex && u.CurTable.AllDonePassing() {
 			u.Eng.SetSubTex(d.GetNode(), d.GetAlt())
 			d.SetDisplayingImage(false)
 		} else {
@@ -106,46 +106,52 @@
 }
 
 // Animation for the 'pass' action, when app is in the table view
-func AnimateTableCardPass(cards []*card.Card, toPlayer int, u *uistate.UIState) {
+func AnimateTableCardPass(cards []*card.Card, toPlayer int, quit chan bool, u *uistate.UIState) {
 	for cardNum, animCard := range cards {
-		cardDim := animCard.GetDimensions()
-		dropTargetXY := u.DropTargets[toPlayer].GetCurrent()
-		dropTargetDim := u.DropTargets[toPlayer].GetDimensions()
-		targetCenter := dropTargetXY.PlusVec(dropTargetDim.DividedBy(2))
-		xPlayerBlockSize := 2*u.PlayerIconDim.X + u.Padding
-		yPlayerBlockSize := u.TopPadding + 2*u.TableCardDim.Y + 3*u.Padding + u.PlayerIconDim.Y
-		blockEdge := targetCenter.MinusVec(cardDim.Times(1.5).Plus(u.Padding))
-		var destination *coords.Vec
-		switch toPlayer {
-		case 0:
-			destination = coords.MakeVec(
-				blockEdge.X+float32(cardNum)*(u.Padding+cardDim.X),
-				u.WindowSize.Y-yPlayerBlockSize-u.TableCardDim.Y)
-		case 1:
-			destination = coords.MakeVec(
-				xPlayerBlockSize,
-				blockEdge.Y+float32(cardNum)*(u.Padding+cardDim.Y))
-		case 2:
-			destination = coords.MakeVec(
-				blockEdge.X+float32(cardNum)*(u.Padding+cardDim.X),
-				yPlayerBlockSize)
-		case 3:
-			destination = coords.MakeVec(
-				u.WindowSize.X-xPlayerBlockSize-u.TableCardDim.X,
-				blockEdge.Y+float32(cardNum)*(u.Padding+cardDim.Y))
-		}
+		destination := DetermineTablePassPosition(animCard, cardNum, toPlayer, u)
 		if cardNum < len(cards)-1 {
-			animateCardNoChannel(animCard, destination, cardDim, u)
+			animateCardNoChannel(animCard, destination, animCard.GetDimensions(), u)
 		} else {
 			c := make(chan bool)
-			animateCardMovement(c, animCard, destination, cardDim, u)
-			<-c
+			animateCardMovement(c, animCard, destination, animCard.GetDimensions(), u)
+			SwitchOnChan(c, quit, func() {}, u)
 		}
 	}
 }
 
+// Returns a vec containing a card's position after being passed to the player with index playerIndex
+func DetermineTablePassPosition(c *card.Card, cardNum, playerIndex int, u *uistate.UIState) *coords.Vec {
+	cardDim := u.TableCardDim
+	dropTargetXY := u.DropTargets[playerIndex].GetCurrent()
+	dropTargetDim := u.DropTargets[playerIndex].GetDimensions()
+	targetCenter := dropTargetXY.PlusVec(dropTargetDim.DividedBy(2))
+	xPlayerBlockSize := 2*u.PlayerIconDim.X + u.Padding
+	yPlayerBlockSize := u.TopPadding + 2*u.TableCardDim.Y + 3*u.Padding + u.PlayerIconDim.Y
+	blockEdge := targetCenter.MinusVec(cardDim.Times(1.5).Plus(u.Padding))
+	var destination *coords.Vec
+	switch playerIndex {
+	case 0:
+		destination = coords.MakeVec(
+			blockEdge.X+float32(cardNum)*(u.Padding+cardDim.X),
+			u.WindowSize.Y-yPlayerBlockSize-u.TableCardDim.Y)
+	case 1:
+		destination = coords.MakeVec(
+			xPlayerBlockSize,
+			blockEdge.Y+float32(cardNum)*(u.Padding+cardDim.Y))
+	case 2:
+		destination = coords.MakeVec(
+			blockEdge.X+float32(cardNum)*(u.Padding+cardDim.X),
+			yPlayerBlockSize)
+	case 3:
+		destination = coords.MakeVec(
+			u.WindowSize.X-xPlayerBlockSize-u.TableCardDim.X,
+			blockEdge.Y+float32(cardNum)*(u.Padding+cardDim.Y))
+	}
+	return destination
+}
+
 // Animation for the 'take' action, when app is in the table view
-func AnimateTableCardTake(cards []*card.Card, p *player.Player, u *uistate.UIState) {
+func AnimateTableCardTake(cards []*card.Card, p *player.Player, quit chan bool, u *uistate.UIState) {
 	for cardNum, animCard := range cards {
 		destinationPos := p.GetPassedFrom()[cardNum].GetInitial()
 		if cardNum < len(cards)-1 {
@@ -153,20 +159,20 @@
 		} else {
 			c := make(chan bool)
 			animateCardMovement(c, animCard, destinationPos, animCard.GetDimensions(), u)
-			<-c
+			SwitchOnChan(c, quit, func() {}, u)
 		}
 	}
 }
 
 // Animation for the 'play' action, when app is in the table view
-func AnimateTableCardPlay(animCard *card.Card, playerInt int, u *uistate.UIState) {
+func AnimateTableCardPlay(animCard *card.Card, playerInt int, quit chan bool, u *uistate.UIState) {
 	destination := u.DropTargets[playerInt]
 	destinationPos := destination.GetCurrent()
 	destinationDim := destination.GetDimensions()
 	ch := make(chan bool)
 	animateCardMovement(ch, animCard, destinationPos, destinationDim, u)
-	<-ch
-	animCard.SetFrontDisplay(u.Eng)
+	onDone := func() { animCard.SetFrontDisplay(u.Eng) }
+	SwitchOnChan(ch, quit, onDone, u)
 }
 
 // Animation for the 'pass' action, when app is in the hand view
@@ -244,8 +250,8 @@
 
 // Animate playing of a card in the split view
 // Should not be called when the player whose hand is being displayed is the player of the card
-func AnimateSplitCardPlay(c *card.Card, player int, u *uistate.UIState) {
-	dropTarget := u.DropTargets[(u.CurPlayerIndex+player)%u.NumPlayers]
+func AnimateSplitCardPlay(c *card.Card, player int, quit chan bool, u *uistate.UIState) {
+	dropTarget := u.DropTargets[(player-u.CurPlayerIndex+u.NumPlayers)%u.NumPlayers]
 	toPos := dropTarget.GetCurrent()
 	toDim := dropTarget.GetDimensions()
 	texture.PopulateCardImage(c, u.Texs, u.Eng, u.Scene)
@@ -259,7 +265,7 @@
 	}
 	ch := make(chan bool)
 	animateCardMovement(ch, c, toPos, toDim, u)
-	<-ch
+	SwitchOnChan(ch, quit, func() {}, u)
 }
 
 func AnimateInSplit(u *uistate.UIState) {
@@ -349,7 +355,7 @@
 }
 
 // Animation for when a trick is taken, when app is in the table view
-func AnimateTableCardTakeTrick(cards []*card.Card, dir direction.Direction, u *uistate.UIState) {
+func AnimateTableCardTakeTrick(cards []*card.Card, dir direction.Direction, quit chan bool, u *uistate.UIState) {
 	for i, animCard := range cards {
 		destination := determineDestination(animCard, dir, u.WindowSize)
 		if i < len(cards)-1 {
@@ -357,7 +363,7 @@
 		} else {
 			c := make(chan bool)
 			animateCardMovement(c, animCard, destination, animCard.GetDimensions(), u)
-			<-c
+			SwitchOnChan(c, quit, func() {}, u)
 		}
 	}
 }
@@ -457,12 +463,12 @@
 // cardIndex has an X of the total number of cards in hand, and a Y of the position within the hand of the current card
 // padding has an X of the padding along the top edge, and a Y of the padding along each other edge
 func SetCardPositionTable(c *card.Card, playerIndex int, cardIndex *coords.Vec, u *uistate.UIState) {
-	pos := cardPositionTable(playerIndex, cardIndex, u)
+	pos := CardPositionTable(playerIndex, cardIndex, u)
 	c.SetInitial(pos)
 	c.Move(pos, u.TableCardDim, u.Eng)
 }
 
-func cardPositionTable(playerIndex int, cardIndex *coords.Vec, u *uistate.UIState) *coords.Vec {
+func CardPositionTable(playerIndex int, cardIndex *coords.Vec, u *uistate.UIState) *coords.Vec {
 	var x float32
 	var y float32
 	switch playerIndex {
@@ -505,3 +511,24 @@
 	c.SetInitial(pos)
 	c.Move(pos, u.CardDim, u.Eng)
 }
+
+func RemoveAnimChan(ch chan bool, u *uistate.UIState) {
+	for i, c := range u.AnimChans {
+		if ch == c {
+			u.AnimChans = append(u.AnimChans[:i], u.AnimChans[i+1:]...)
+			return
+		}
+	}
+}
+
+func SwitchOnChan(animChan, quitChan chan bool, f func(), u *uistate.UIState) {
+	select {
+	case <-quitChan:
+		RemoveAnimChan(quitChan, u)
+		return
+	case <-animChan:
+		RemoveAnimChan(quitChan, u)
+		f()
+		return
+	}
+}
diff --git a/go/src/hearts/img/texture/texture.go b/go/src/hearts/img/texture/texture.go
index 74f4d0e..3179eca 100644
--- a/go/src/hearts/img/texture/texture.go
+++ b/go/src/hearts/img/texture/texture.go
@@ -61,22 +61,21 @@
 	imgs := make([]sprite.SubTex, 0)
 	for _, char := range input {
 		key := ""
-		// if char is a space
 		if char == 32 {
 			key += "Space"
 		} else if char == 33 {
 			key += "Bang"
-			// if char is an apostrophe
 		} else if char == 39 {
 			key += "Apostrophe"
-			// if char is a colon
+		} else if char == 46 {
+			key += "Period"
 		} else if char == 58 {
 			key += "Colon"
-			// if char is a number
 		} else if char >= 48 && char <= 57 {
+			// if char is a number
 			key += string(char)
-			// if char is a letter
 		} else {
+			// if char is a letter
 			key += strings.ToUpper(string(char))
 			if char > 90 {
 				key += "-Lower"
@@ -276,7 +275,7 @@
 		"R-Lower-Gray.png", "S-Lower-Gray.png", "T-Lower-Gray.png", "U-Lower-Gray.png", "V-Lower-Gray.png", "W-Lower-Gray.png",
 		"X-Lower-Gray.png", "Y-Lower-Gray.png", "Z-Lower-Gray.png", "Space-Gray.png", "RoundedRectangle-DBlue.png",
 		"RoundedRectangle-LBlue.png", "RoundedRectangle-Gray.png", "Rectangle-LBlue.png", "Rectangle-DBlue.png", "HorizontalPullTab.png",
-		"VerticalPullTab.png", "NewGame.png", "NewRound.png", "JoinGame.png", "Deal.png",
+		"VerticalPullTab.png", "NewGame.png", "NewRound.png", "JoinGame.png", "Deal.png", "Period.png",
 	}
 	for _, f := range boundedImgs {
 		a, err := asset.Open(f)
diff --git a/go/src/hearts/img/uistate/uistate.go b/go/src/hearts/img/uistate/uistate.go
index 02378bc..d3c8aec 100644
--- a/go/src/hearts/img/uistate/uistate.go
+++ b/go/src/hearts/img/uistate/uistate.go
@@ -26,7 +26,7 @@
 
 const (
 	None      View = "None"
-	Opening   View = "Opening"
+	Arrange   View = "Arrange"
 	Discovery View = "Discovery"
 	Pass      View = "Pass"
 	Take      View = "Take"
@@ -46,10 +46,11 @@
 )
 
 type UIState struct {
-	StartTime      time.Time
-	Images         *glutil.Images
-	Eng            sprite.Engine
-	Scene          *sprite.Node
+	StartTime time.Time
+	Images    *glutil.Images
+	Eng       sprite.Engine
+	Scene     *sprite.Node
+	// the following arrays keep track of all displayed images
 	Cards          []*card.Card
 	TableCards     []*card.Card
 	BackgroundImgs []*staticimg.StaticImg
@@ -57,34 +58,38 @@
 	DropTargets    []*staticimg.StaticImg
 	Buttons        []*staticimg.StaticImg
 	Other          []*staticimg.StaticImg
-	CurCard        *card.Card
-	CurImg         *staticimg.StaticImg
+	CurCard        *card.Card           // the card that is currently clicked on
+	CurImg         *staticimg.StaticImg // the image that is currently clicked on
 	// lastMouseXY is in Px: divide by pixelsPerPt to get Pt
-	LastMouseXY   *coords.Vec
-	NumPlayers    int
-	NumSuits      int
-	CardSize      float32
-	CardScaler    float32
-	TopPadding    float32
-	BottomPadding float32
-	// windowSize is in Pt
-	WindowSize     *coords.Vec
+	LastMouseXY *coords.Vec // the position of the mouse in the most recent frame
+	NumPlayers  int
+	NumSuits    int
+	// the following variables are used for sizing and positioning specifications
+	CardSize       float32
+	CardScaler     float32
+	TopPadding     float32
+	BottomPadding  float32
+	WindowSize     *coords.Vec // windowSize is in Pt
 	CardDim        *coords.Vec
 	TableCardDim   *coords.Vec
 	PlayerIconDim  *coords.Vec
 	PixelsPerPt    float32
 	Overlap        *coords.Vec
 	Padding        float32
-	CurView        View
-	CurTable       *table.Table
-	Done           bool
-	Texs           map[string]sprite.SubTex
-	CurPlayerIndex int
+	CurView        View                     // the screen currently being shown to the user
+	CurTable       *table.Table             // the table of the current game
+	Done           bool                     // true if the app has been quit
+	Texs           map[string]sprite.SubTex // map of all loaded images
+	CurPlayerIndex int                      // the player number of this player
 	Ctx            *context.T
 	Service        syncbase.Service
-	Debug          bool
-	Shutdown       func()
-	GameID		   int
+	Debug          bool        // true if debugging, adds extra functionality to switch between players
+	Shutdown       func()      // used to shut down a v23.Init()
+	GameID         int         // used to differentiate between concurrent games
+	IsOwner        bool        // true if this player is the game creator
+	AnimChans      []chan bool // keeps track of all 'quit' channels in animations so their goroutines can be stopped
+	SGChan         chan bool   // pass in a bool to stop advertising the syncgroup
+	ScanChan       chan bool   // pass in a bool to stop scanning for syncgroups
 }
 
 func MakeUIState() *UIState {
@@ -112,7 +117,7 @@
 		Padding:        float32(5),
 		CurView:        None,
 		Done:           false,
-		CurPlayerIndex: 0,
-		Debug:          true,
+		Debug:          false,
+		AnimChans:      make([]chan bool, 0),
 	}
 }
diff --git a/go/src/hearts/img/view/view.go b/go/src/hearts/img/view/view.go
index f581e75..b2cdf11 100644
--- a/go/src/hearts/img/view/view.go
+++ b/go/src/hearts/img/view/view.go
@@ -25,22 +25,40 @@
 	"golang.org/x/mobile/exp/sprite"
 )
 
-// Opening View: Only temporary, for debugging, while discovery is not integrated
-func LoadOpeningView(u *uistate.UIState) {
-	u.CurView = uistate.Opening
+// TODO(emshack): Flesh out Arrange view to actually arrange players
+func LoadArrangeView(u *uistate.UIState) {
+	u.CurView = uistate.Arrange
 	<-time.After(1 * time.Second)
+	resetAnims(u)
 	resetImgs(u)
-	ResetScene(u)
+	resetScene(u)
 	buttonPos := coords.MakeVec((u.WindowSize.X-2*u.CardDim.X)/2, (u.WindowSize.Y-u.CardDim.Y)/2)
 	buttonDim := coords.MakeVec(2*u.CardDim.X, u.CardDim.Y)
 	buttonImage := u.Texs["Deal.png"]
 	u.Buttons = append(u.Buttons, texture.MakeImgWithoutAlt(buttonImage, buttonPos, buttonDim, u.Eng, u.Scene))
 }
 
+// Waiting view: Displays the word "Waiting". To be displayed when players are waiting for a new round to be dealt
+// TODO(emshack): Integrate this with Arrange view and Score view so that a separate screen is not necessary
+func LoadWaitingView(u *uistate.UIState) {
+	resetAnims(u)
+	resetImgs(u)
+	resetScene(u)
+	center := u.WindowSize.DividedBy(2)
+	maxWidth := u.WindowSize.X - 2*u.Padding
+	scaler := float32(3)
+	textImgs := texture.MakeStringImgCenterAlign("Waiting...", "", "", true, center, scaler, maxWidth, u)
+	for _, img := range textImgs {
+		u.BackgroundImgs = append(u.BackgroundImgs, img)
+	}
+}
+
+// Discovery view: Displays a menu of possible games to join
 func LoadDiscoveryView(discChan chan []string, u *uistate.UIState) {
 	u.CurView = uistate.Discovery
+	resetAnims(u)
 	resetImgs(u)
-	ResetScene(u)
+	resetScene(u)
 	newGameImg := u.Texs["NewGame.png"]
 	newGameDim := coords.MakeVec(2*u.CardDim.X, u.CardDim.Y)
 	newGamePos := coords.MakeVec((u.WindowSize.X-newGameDim.X)/2, u.TopPadding)
@@ -61,8 +79,9 @@
 // Table View: Displays the table. Intended for public devices
 func LoadTableView(u *uistate.UIState) {
 	u.CurView = uistate.Table
+	resetAnims(u)
 	resetImgs(u)
-	ResetScene(u)
+	resetScene(u)
 	scaler := float32(4)
 	maxWidth := 4 * u.TableCardDim.X
 	// adding four drop targets for trick
@@ -238,6 +257,7 @@
 		texture.MakeImgWithoutAlt(deviceIconImage, deviceIconPos, deviceIconDim, u.Eng, u.Scene))
 	//adding cards
 	for _, p := range u.CurTable.GetPlayers() {
+		// cards in hand
 		hand := p.GetHand()
 		for i, c := range hand {
 			texture.PopulateCardImage(c, u.Texs, u.Eng, u.Scene)
@@ -246,6 +266,29 @@
 			u.Eng.SetSubTex(c.GetNode(), c.GetBack())
 			u.TableCards = append(u.TableCards, c)
 		}
+		// cards that have been passed
+		passed := p.GetPassedTo()
+		for i, c := range passed {
+			var passer int
+			switch u.CurTable.GetDir() {
+			case direction.Right:
+				passer = (p.GetPlayerIndex() + 1) % u.NumPlayers
+			case direction.Across:
+				passer = (p.GetPlayerIndex() + 2) % u.NumPlayers
+			case direction.Left:
+				passer = (p.GetPlayerIndex() + 3) % u.NumPlayers
+			}
+			cardIndexVec := coords.MakeVec(float32(len(hand)+len(passed)), float32(len(hand)+i))
+			initial := reposition.CardPositionTable(passer, cardIndexVec, u)
+			c.SetInitial(initial)
+			if !p.GetDoneTaking() {
+				texture.PopulateCardImage(c, u.Texs, u.Eng, u.Scene)
+				c.SetBackDisplay(u.Eng)
+				pos := reposition.DetermineTablePassPosition(c, i, p.GetPlayerIndex(), u)
+				c.Move(pos, u.TableCardDim, u.Eng)
+				u.TableCards = append(u.TableCards, c)
+			}
+		}
 	}
 	if u.Debug {
 		addDebugBar(u)
@@ -269,8 +312,9 @@
 // Score View: Shows current player standings at the end of every round, including the end of the game
 func LoadScoreView(roundScores, winners []int, u *uistate.UIState) {
 	u.CurView = uistate.Score
+	resetAnims(u)
 	resetImgs(u)
-	ResetScene(u)
+	resetScene(u)
 	addHeader(u)
 	addScoreViewHeaderText(u)
 	addPlayerScores(roundScores, u)
@@ -280,8 +324,9 @@
 // Pass View: Shows player's hand and allows them to pass cards
 func LoadPassView(u *uistate.UIState) {
 	u.CurView = uistate.Pass
+	resetAnims(u)
 	resetImgs(u)
-	ResetScene(u)
+	resetScene(u)
 	addHeader(u)
 	addGrayPassBar(u)
 	addPassDrops(u)
@@ -294,8 +339,9 @@
 // Take View: Shows player's hand and allows them to take the cards that have been passed to them
 func LoadTakeView(u *uistate.UIState) {
 	u.CurView = uistate.Take
+	resetAnims(u)
 	resetImgs(u)
-	ResetScene(u)
+	resetScene(u)
 	addHeader(u)
 	addGrayTakeBar(u)
 	addHand(u)
@@ -310,8 +356,9 @@
 // Play View: Shows player's hand and allows them to play cards
 func LoadPlayView(u *uistate.UIState) {
 	u.CurView = uistate.Play
+	resetAnims(u)
 	resetImgs(u)
-	ResetScene(u)
+	resetScene(u)
 	addPlaySlot(u)
 	addHand(u)
 	addPlayHeader(getTurnText(u), false, u)
@@ -326,8 +373,9 @@
 
 func LoadSplitView(reloading bool, u *uistate.UIState) {
 	u.CurView = uistate.Split
+	resetAnims(u)
 	resetImgs(u)
-	ResetScene(u)
+	resetScene(u)
 	addPlayHeader(getTurnText(u), !reloading, u)
 	addSplitViewPlayerIcons(!reloading, u)
 	addHand(u)
@@ -818,9 +866,10 @@
 	u.DropTargets = make([]*staticimg.StaticImg, 0)
 	u.Buttons = make([]*staticimg.StaticImg, 0)
 	u.Other = make([]*staticimg.StaticImg, 0)
+	u.CurCard = nil
 }
 
-func ResetScene(u *uistate.UIState) {
+func resetScene(u *uistate.UIState) {
 	u.Scene = &sprite.Node{}
 	u.Eng.Register(u.Scene)
 	u.Eng.SetTransform(u.Scene, f32.Affine{
@@ -829,6 +878,13 @@
 	})
 }
 
+func resetAnims(u *uistate.UIState) {
+	for _, ch := range u.AnimChans {
+		ch <- true
+	}
+	u.AnimChans = make([]chan bool, 0)
+}
+
 func addDebugBar(u *uistate.UIState) {
 	buttonDim := u.CardDim
 	debugTableImage := u.Texs["BakuSquare.png"]
diff --git a/go/src/hearts/main.go b/go/src/hearts/main.go
index 2dc70cc..e51485c 100644
--- a/go/src/hearts/main.go
+++ b/go/src/hearts/main.go
@@ -110,8 +110,6 @@
 	server.CreateTables(u)
 	// Create watch stream to update game state based on Syncbase updates
 	go watch.Update(u)
-	go watch.PrintStream("Stream 1", u)
-	go watch.PrintStream("Stream 2", u)
 }
 
 func onStop(u *uistate.UIState) {
@@ -125,7 +123,8 @@
 func onPaint(glctx gl.Context, sz size.Event, u *uistate.UIState) {
 	if u.CurView == uistate.None {
 		discChan := make(chan []string)
-		go client.ScanForSG(discChan, u.Ctx)
+		u.ScanChan = make(chan bool)
+		go client.ScanForSG(discChan, u.Ctx, u.ScanChan)
 		view.LoadDiscoveryView(discChan, u)
 	}
 	glctx.ClearColor(1, 1, 1, 1)
diff --git a/go/src/hearts/syncbase/client/main.go b/go/src/hearts/syncbase/client/main.go
index 880bf04..8fccb35 100644
--- a/go/src/hearts/syncbase/client/main.go
+++ b/go/src/hearts/syncbase/client/main.go
@@ -7,11 +7,11 @@
 package client
 
 import (
-	"fmt"
-	"strings"
 	"encoding/json"
+	"fmt"
 	"hearts/img/uistate"
 	"hearts/syncbase/util"
+	"strings"
 	"v.io/v23/context"
 	"v.io/v23/discovery"
 	wire "v.io/v23/services/syncbase/nosql"
@@ -23,7 +23,7 @@
 )
 
 // Searches for new syncgroups being advertised, sends found syncgroups to sgChan
-func ScanForSG(sgChan chan []string, ctx *context.T) {
+func ScanForSG(sgChan chan []string, ctx *context.T, quit chan bool) {
 	mdns, err := mdns.New("")
 	if err != nil {
 		ctx.Fatalf("Plugin failed: %v", err)
@@ -45,6 +45,8 @@
 			}
 		case <-signals.ShutdownOnSignals(ctx):
 			break loop
+		case <-quit:
+			break loop
 		}
 	}
 }
@@ -54,19 +56,19 @@
 	switch u := update.(type) {
 	case discovery.UpdateFound:
 		found := u.Value
-		instances[string(found.Service.InstanceUuid)] = found.Service.InstanceName
-		fmt.Printf("Discovered %q: Instance=%x, Interface=%q, Addrs=%v\n", found.Service.InstanceName, found.Service.InstanceUuid, found.Service.InterfaceName, found.Service.Addrs)
+		instances[string(found.Service.InstanceId)] = found.Service.InstanceName
+		fmt.Printf("Discovered %q: Instance=%x, Interface=%q, Addrs=%v\n", found.Service.InstanceName, found.Service.InstanceId, found.Service.InterfaceName, found.Service.Addrs)
 		if found.Service.InterfaceName == util.CroupierInterface {
 			return found.Service.Addrs
 		}
 	case discovery.UpdateLost:
 		lost := u.Value
-		name, ok := instances[string(lost.InstanceUuid)]
+		name, ok := instances[string(lost.InstanceId)]
 		if !ok {
 			name = "unknown"
 		}
-		delete(instances, string(lost.InstanceUuid))
-		fmt.Printf("Lost %q: Instance=%x\n", name, lost.InstanceUuid)
+		delete(instances, string(lost.InstanceId))
+		fmt.Printf("Lost %q: Instance=%x\n", name, lost.InstanceId)
 	}
 	return nil
 }
@@ -83,8 +85,10 @@
 }
 
 // Joins a set of gamelog and game settings syncgroups
+// TODO(emshack): After joining a syncgroup, advertise user settings data
 func JoinSyncgroups(ch chan bool, logName, settingsName string, u *uistate.UIState) {
 	fmt.Println("Joining syncgroup")
+	u.IsOwner = false
 	app := u.Service.App(util.AppName)
 	db := app.NoSQLDatabase(util.DbName, nil)
 	logSg := db.Syncgroup(logName)
@@ -97,6 +101,7 @@
 		ch <- false
 	} else {
 		fmt.Println("Syncgroup joined")
+		// Set UIState GameID
 		tmp := strings.Split(logName, "-")
 		lasttmp := tmp[len(tmp)-1]
 		tmpMap := make(map[string]interface{})
@@ -105,6 +110,19 @@
 			fmt.Println("ERROR UNMARSHALLING")
 		}
 		u.GameID = int(tmpMap["gameID"].(float64))
+		u.CurPlayerIndex = NumInSG(logName, u) - 1
+		fmt.Println(u.CurPlayerIndex)
 		ch <- true
 	}
 }
+
+func NumInSG(logName string, u *uistate.UIState) int {
+	app := u.Service.App(util.AppName)
+	db := app.NoSQLDatabase(util.DbName, nil)
+	sg := db.Syncgroup(logName)
+	members, err := sg.GetMembers(u.Ctx)
+	if err != nil {
+		fmt.Println(err)
+	}
+	return len(members)
+}
diff --git a/go/src/hearts/syncbase/server/main.go b/go/src/hearts/syncbase/server/main.go
index 0f17dd8..1a711c2 100644
--- a/go/src/hearts/syncbase/server/main.go
+++ b/go/src/hearts/syncbase/server/main.go
@@ -7,11 +7,11 @@
 package server
 
 import (
-	"math/rand"
 	"encoding/json"
 	"fmt"
 	"hearts/img/uistate"
 	"hearts/syncbase/util"
+	"math/rand"
 	"v.io/v23/context"
 	"v.io/v23/discovery"
 	"v.io/v23/security"
@@ -25,7 +25,7 @@
 )
 
 // Advertises a set of game log and game settings syncgroups
-func Advertise(logAddress, settingsAddress string, ctx *context.T) {
+func Advertise(logAddress, settingsAddress string, quit chan bool, ctx *context.T) {
 	ctx, stop := context.WithCancel(ctx)
 	mdns, err := mdns.New("")
 	if err != nil {
@@ -35,14 +35,18 @@
 	gameService := discovery.Service{
 		InstanceName:  "A sample game service",
 		InterfaceName: util.CroupierInterface,
-		Addrs: []string{settingsAddress, logAddress},
+		Addrs:         []string{settingsAddress, logAddress},
 	}
 	fmt.Println(gameService)
-	if _, err := discoveryService.Advertise(ctx, gameService, nil); err != nil {
+	if _, err := discoveryService.Advertise(ctx, &gameService, nil); err != nil {
 		ctx.Fatalf("Advertise failed: %v", err)
 	}
-	<-signals.ShutdownOnSignals(ctx)
-	stop()
+	select {
+	case <-signals.ShutdownOnSignals(ctx):
+		stop()
+	case <-quit:
+		stop()
+	}
 }
 
 // Puts key and value into the syncbase table
@@ -94,6 +98,7 @@
 			fmt.Println("TABLE ERROR: ", err)
 		}
 	}
+	// Add user settings data to represent this player
 	settingsMap := make(map[string]interface{})
 	settingsMap["userID"] = util.UserID
 	settingsMap["avatar"] = util.UserAvatar
@@ -106,9 +111,12 @@
 	settingsTable.Put(u.Ctx, fmt.Sprintf("users/%d/settings", util.UserID), value)
 }
 
-// Creates a new syncgroup
-func CreateSyncgroup(ch chan string, u *uistate.UIState) {
+// Creates a new set of gamelog and game settings syncgroups
+func CreateSyncgroups(ch chan string, u *uistate.UIState) {
 	fmt.Println("Creating Syncgroup")
+	u.IsOwner = true
+	u.CurPlayerIndex = 0
+	// Generate random gameID information to advertise this game
 	gameID := rand.Intn(1000000)
 	gameMap := make(map[string]interface{})
 	gameMap["type"] = "Hearts"
@@ -119,7 +127,8 @@
 	if err != nil {
 		fmt.Println("WE HAVE A HUGE PROBLEM:", err)
 	}
-	sgName := util.MountPoint + "/croupier/" + util.SBName + "/%%sync/gaming-" + string(value)
+	// Create gamelog syncgroup
+	logSGName := util.MountPoint + "/croupier/" + util.SBName + "/%%sync/gaming-" + string(value)
 	allAccess := access.AccessList{In: []security.BlessingPattern{"..."}}
 	permissions := access.Permissions{
 		"Admin":   allAccess,
@@ -128,63 +137,47 @@
 		"Resolve": allAccess,
 		"Debug":   allAccess,
 	}
-	pref := wire.TableRow{util.LogName, ""}
-	prefs := []wire.TableRow{pref}
+	logPref := wire.TableRow{util.LogName, ""}
+	logPrefs := []wire.TableRow{logPref}
 	tables := []string{util.MountPoint + "/croupier"}
-	spec := wire.SyncgroupSpec{
+	logSpec := wire.SyncgroupSpec{
 		Description: "croupier syncgroup",
 		Perms:       permissions,
-		Prefixes:    prefs,
+		Prefixes:    logPrefs,
 		MountTables: tables,
 		IsPrivate:   false,
 	}
 	myInfoCreator := wire.SyncgroupMemberInfo{8, true}
 	app := u.Service.App(util.AppName)
 	db := app.NoSQLDatabase(util.DbName, nil)
-	sg := db.Syncgroup(sgName)
-	err = sg.Create(u.Ctx, spec, myInfoCreator)
+	logSG := db.Syncgroup(logSGName)
+	err = logSG.Create(u.Ctx, logSpec, myInfoCreator)
 	if err != nil {
 		fmt.Println("SYNCGROUP CREATE ERROR: ", err)
 		ch <- ""
 	} else {
 		fmt.Println("Syncgroup created")
 		u.GameID = gameID
-		ch <- sgName
+		ch <- logSGName
 	}
-}
-
-// Creates a new syncgroup
-func CreateSettingsSyncgroup(ch chan string, u *uistate.UIState) {
-	fmt.Println("Creating Settings Syncgroup")
-	sgName := fmt.Sprintf("%s/croupier/%s/%%%%sync/discovery-%d", util.MountPoint, util.SBName, util.UserID)
-	allAccess := access.AccessList{In: []security.BlessingPattern{"..."}}
-	permissions := access.Permissions{
-		"Admin":   allAccess,
-		"Write":   allAccess,
-		"Read":    allAccess,
-		"Resolve": allAccess,
-		"Debug":   allAccess,
-	}
-	pref := wire.TableRow{util.SettingsName, ""}
-	prefs := []wire.TableRow{pref}
-	tables := []string{util.MountPoint + "/croupier"}
-	spec := wire.SyncgroupSpec{
+	// Create game settings syncgroup
+	settingsSGName := fmt.Sprintf("%s/croupier/%s/%%%%sync/discovery-%d", util.MountPoint, util.SBName, util.UserID)
+	settingsPref := wire.TableRow{util.SettingsName, ""}
+	settingsPrefs := []wire.TableRow{settingsPref}
+	settingsSpec := wire.SyncgroupSpec{
 		Description: "croupier syncgroup",
 		Perms:       permissions,
-		Prefixes:    prefs,
+		Prefixes:    settingsPrefs,
 		MountTables: tables,
 		IsPrivate:   false,
 	}
-	myInfoCreator := wire.SyncgroupMemberInfo{8, true}
-	app := u.Service.App(util.AppName)
-	db := app.NoSQLDatabase(util.DbName, nil)
-	sg := db.Syncgroup(sgName)
-	err := sg.Create(u.Ctx, spec, myInfoCreator)
+	settingsSG := db.Syncgroup(settingsSGName)
+	err = settingsSG.Create(u.Ctx, settingsSpec, myInfoCreator)
 	if err != nil {
 		fmt.Println("SYNCGROUP CREATE ERROR: ", err)
 		ch <- ""
 	} else {
 		fmt.Println("Syncgroup created")
-		ch <- sgName
+		ch <- settingsSGName
 	}
 }
diff --git a/go/src/hearts/syncbase/util/util.go b/go/src/hearts/syncbase/util/util.go
index 9581f90..cb293cd 100644
--- a/go/src/hearts/syncbase/util/util.go
+++ b/go/src/hearts/syncbase/util/util.go
@@ -8,16 +8,16 @@
 
 const (
 	// switch back to my mountpoint with the following code:
-	// MountPoint = "users/emshack@google.com"
-	MountPoint        = "/192.168.86.254:8101"
+	MountPoint = "users/emshack@google.com"
+	//MountPoint        = "/192.168.86.254:8101"
 	UserID            = 123
 	UserColor         = 16777215
 	UserAvatar        = "Club.png"
 	UserName          = "Croupier Go Player (the blue)"
-	SBName            = "syncbase1"
+	SBName            = "syncbase"
 	AppName           = "app"
 	DbName            = "db"
 	LogName           = "games"
 	SettingsName      = "table_settings"
-	CroupierInterface = "CroupierSettingsAndGame"
+	CroupierInterface = "CroupierSettingsAndGameEmily"
 )
diff --git a/go/src/hearts/syncbase/watch/watch.go b/go/src/hearts/syncbase/watch/watch.go
index e2fc0ad..9d48658 100644
--- a/go/src/hearts/syncbase/watch/watch.go
+++ b/go/src/hearts/syncbase/watch/watch.go
@@ -24,26 +24,6 @@
 	"v.io/v23/syncbase/nosql"
 )
 
-func PrintStream(prefix string, u *uistate.UIState) {
-	stream, err := client.WatchData(u)
-	if err != nil {
-		fmt.Println("WatchData error:", err)
-	}
-	for {
-		if updateExists := stream.Advance(); updateExists {
-			c := stream.Change()
-			if c.ChangeType == nosql.PutChange {
-				var value []byte
-				if err := c.Value(&value); err != nil {
-					fmt.Println("Value error:", err)
-				}
-				valueStr := string(value)
-				fmt.Println(prefix, valueStr)
-			}
-		}
-	}
-}
-
 func Update(u *uistate.UIState) {
 	stream, err := client.WatchData(u)
 	if err != nil {
@@ -62,15 +42,15 @@
 				updateType := strings.Split(valueStr, "|")[0]
 				switch updateType {
 				case gamelog.Deal:
-					onDeal(valueStr, u)
+					go onDeal(valueStr, u)
 				case gamelog.Pass:
-					onPass(valueStr, u)
+					go onPass(valueStr, u)
 				case gamelog.Take:
-					onTake(valueStr, u)
+					go onTake(valueStr, u)
 				case gamelog.Play:
-					onPlay(valueStr, u)
+					go onPlay(valueStr, u)
 				case gamelog.Ready:
-					onReady(valueStr, u)
+					go onReady(valueStr, u)
 				}
 			} else {
 				fmt.Println("Unexpected ChangeType: ", c.ChangeType)
@@ -85,7 +65,11 @@
 	u.CurTable.GetPlayers()[playerInt].SetHand(curCards)
 	if u.CurTable.AllDoneDealing() {
 		u.CurTable.NewRound()
-		view.LoadTableView(u)
+		if u.CurPlayerIndex >= 0 && u.CurPlayerIndex < u.NumPlayers {
+			view.LoadPassOrTakeOrPlay(u)
+		} else {
+			view.LoadTableView(u)
+		}
 	}
 }
 
@@ -104,15 +88,14 @@
 	for _, c := range curCards {
 		u.CurTable.GetPlayers()[playerInt].RemoveFromHand(c)
 	}
-	if u.CurPlayerIndex >= 0 {
-		u.Cards = u.CurTable.GetPlayers()[u.CurPlayerIndex].GetHand()
-	}
 	u.CurTable.GetPlayers()[playerInt].SetPassedFrom(curCards)
 	u.CurTable.GetPlayers()[receivingPlayer].SetPassedTo(curCards)
 	u.CurTable.GetPlayers()[playerInt].SetDonePassing(true)
 	// UI
 	if u.CurView == uistate.Table {
-		reposition.AnimateTableCardPass(curCards, receivingPlayer, u)
+		quit := make(chan bool)
+		u.AnimChans = append(u.AnimChans, quit)
+		reposition.AnimateTableCardPass(curCards, receivingPlayer, quit, u)
 		reposition.SetTableDropColors(u)
 	} else if u.CurView == uistate.Take && u.CurPlayerIndex == receivingPlayer {
 		view.LoadTakeView(u)
@@ -130,9 +113,6 @@
 		p.AddToHand(c)
 	}
 	u.CurTable.GetPlayers()[playerInt].SetDoneTaking(true)
-	if u.CurPlayerIndex >= 0 {
-		u.Cards = u.CurTable.GetPlayers()[u.CurPlayerIndex].GetHand()
-	}
 	if p.HasTwoOfClubs() {
 		u.CurTable.SetFirstPlayer(p.GetPlayerIndex())
 		// UI
@@ -142,7 +122,9 @@
 	}
 	// UI
 	if u.CurView == uistate.Table {
-		reposition.AnimateTableCardTake(passed, u.CurTable.GetPlayers()[playerInt], u)
+		quit := make(chan bool)
+		u.AnimChans = append(u.AnimChans, quit)
+		reposition.AnimateTableCardTake(passed, u.CurTable.GetPlayers()[playerInt], quit, u)
 		reposition.SetTableDropColors(u)
 	}
 }
@@ -154,9 +136,6 @@
 	u.CurTable.GetPlayers()[playerInt].RemoveFromHand(playedCard)
 	u.CurTable.SetPlayedCard(playedCard, playerInt)
 	u.CurTable.GetPlayers()[playerInt].SetDonePlaying(true)
-	if u.CurPlayerIndex >= 0 {
-		u.Cards = u.CurTable.GetPlayers()[u.CurPlayerIndex].GetHand()
-	}
 	trickOver := true
 	trickCards := u.CurTable.GetTrick()
 	for _, c := range trickCards {
@@ -176,7 +155,9 @@
 	}
 	// UI
 	if u.CurView == uistate.Table {
-		reposition.AnimateTableCardPlay(playedCard, playerInt, u)
+		quit := make(chan bool)
+		u.AnimChans = append(u.AnimChans, quit)
+		reposition.AnimateTableCardPlay(playedCard, playerInt, quit, u)
 		reposition.SetTableDropColors(u)
 		if trickOver {
 			var trickDir direction.Direction
@@ -190,28 +171,38 @@
 			case 3:
 				trickDir = direction.Right
 			}
-			reposition.AnimateTableCardTakeTrick(trickCards, trickDir, u)
+			quit := make(chan bool)
+			u.AnimChans = append(u.AnimChans, quit)
+			reposition.AnimateTableCardTakeTrick(trickCards, trickDir, quit, u)
 		}
 	} else if u.CurView == uistate.Split {
-		if playerInt != u.CurPlayerIndex {
-			reposition.AnimateSplitCardPlay(playedCard, playerInt, u)
-		}
-		reposition.SetSplitDropColors(u)
-		if trickOver {
-			var trickDir direction.Direction
-			switch recipient {
-			case u.CurPlayerIndex:
-				trickDir = direction.Down
-			case (u.CurPlayerIndex + 1) % u.NumPlayers:
-				trickDir = direction.Left
-			case (u.CurPlayerIndex + 2) % u.NumPlayers:
-				trickDir = direction.Across
-			case (u.CurPlayerIndex + 3) % u.NumPlayers:
-				trickDir = direction.Right
+		if roundOver {
+			view.LoadScoreView(roundScores, winners, u)
+		} else {
+			if playerInt != u.CurPlayerIndex {
+				quit := make(chan bool)
+				u.AnimChans = append(u.AnimChans, quit)
+				reposition.AnimateSplitCardPlay(playedCard, playerInt, quit, u)
 			}
-			reposition.AnimateTableCardTakeTrick(trickCards, trickDir, u)
+			reposition.SetSplitDropColors(u)
+			if trickOver {
+				var trickDir direction.Direction
+				switch recipient {
+				case u.CurPlayerIndex:
+					trickDir = direction.Down
+				case (u.CurPlayerIndex + 1) % u.NumPlayers:
+					trickDir = direction.Left
+				case (u.CurPlayerIndex + 2) % u.NumPlayers:
+					trickDir = direction.Across
+				case (u.CurPlayerIndex + 3) % u.NumPlayers:
+					trickDir = direction.Right
+				}
+				quit := make(chan bool)
+				u.AnimChans = append(u.AnimChans, quit)
+				reposition.AnimateTableCardTakeTrick(trickCards, trickDir, quit, u)
+			}
+			view.LoadSplitView(true, u)
 		}
-		view.LoadSplitView(true, u)
 	} else if u.CurView == uistate.Play {
 		if roundOver {
 			view.LoadScoreView(roundScores, winners, u)
@@ -240,16 +231,19 @@
 	// logic
 	playerInt, _ := parsePlayerAndCards(value, u)
 	u.CurTable.GetPlayers()[playerInt].SetDoneScoring(true)
-	if u.CurTable.AllReadyForNewRound() {
+	if u.CurTable.AllReadyForNewRound() && u.IsOwner {
 		newHands := u.CurTable.Deal()
-		success := gamelog.LogDeal(u, playerInt, newHands)
+		success := gamelog.LogDeal(u, u.CurPlayerIndex, newHands)
 		for !success {
-			success = gamelog.LogDeal(u, playerInt, newHands)
+			success = gamelog.LogDeal(u, u.CurPlayerIndex, newHands)
 		}
 	}
 	// UI
-	if playerInt == u.CurPlayerIndex {
-		view.LoadTableView(u)
+	if u.CurTable.AllReadyForNewRound() {
+		if u.SGChan != nil {
+			u.SGChan <- true
+			u.SGChan = nil
+		}
 	}
 }
 
diff --git a/go/src/hearts/touchhandler/touchhandler.go b/go/src/hearts/touchhandler/touchhandler.go
index 5adfe92..78b389b 100644
--- a/go/src/hearts/touchhandler/touchhandler.go
+++ b/go/src/hearts/touchhandler/touchhandler.go
@@ -28,10 +28,10 @@
 		case touch.TypeBegin:
 			beginClickDiscovery(t, u)
 		}
-	case uistate.Opening:
+	case uistate.Arrange:
 		switch t.Type {
 		case touch.TypeBegin:
-			beginClickOpening(t, u)
+			beginClickArrange(t, u)
 		}
 	case uistate.Table:
 		switch t.Type {
@@ -104,15 +104,16 @@
 	buttonList := findClickedButton(t, u)
 	if len(buttonList) > 0 {
 		if buttonList[0] == u.Buttons[0] {
-			logChan := make(chan string)
-			settingsChan := make(chan string)
-			go server.CreateSyncgroup(logChan, u)
-			go server.CreateSettingsSyncgroup(settingsChan, u)
-			logName := <-logChan
-			settingsName := <-settingsChan
+			ch := make(chan string)
+			go server.CreateSyncgroups(ch, u)
+			logName := <-ch
+			settingsName := <-ch
 			if logName != "" && settingsName != "" {
-				go server.Advertise(logName, settingsName, u.Ctx)
-				view.LoadOpeningView(u)
+				u.ScanChan <- true
+				u.ScanChan = nil
+				u.SGChan = make(chan bool)
+				go server.Advertise(logName, settingsName, u.SGChan, u.Ctx)
+				view.LoadArrangeView(u)
 			}
 		} else {
 			for _, b := range u.Buttons {
@@ -122,7 +123,9 @@
 					logAddr := b.GetInfo()[1]
 					go client.JoinSyncgroups(joinDone, logAddr, settingsAddr, u)
 					if success := <-joinDone; success {
-						view.LoadOpeningView(u)
+						u.ScanChan <- true
+						u.ScanChan = nil
+						view.LoadArrangeView(u)
 					} else {
 						fmt.Println("Failed to join")
 					}
@@ -132,12 +135,11 @@
 	}
 }
 
-func beginClickOpening(t touch.Event, u *uistate.UIState) {
+func beginClickArrange(t touch.Event, u *uistate.UIState) {
 	buttonList := findClickedButton(t, u)
 	if len(buttonList) > 0 {
-		fmt.Println("Dealing")
-		allHands := u.CurTable.Deal()
-		gamelog.LogDeal(u, u.CurPlayerIndex, allHands)
+		gamelog.LogReady(u)
+		view.LoadWaitingView(u)
 	}
 }
 
@@ -177,10 +179,18 @@
 		} else {
 			pullTab := u.Buttons[0]
 			if pullTab.GetDisplayingImage() {
+				u.CurImg = u.Buttons[0]
 				for _, img := range u.Other {
 					u.Eng.SetSubTex(img.GetNode(), img.GetAlt())
 					img.SetDisplayingImage(false)
 				}
+				blueBanner := u.Other[0]
+				if blueBanner.GetNode().Arranger == nil {
+					finalX := blueBanner.GetInitial().X
+					finalY := pullTab.GetInitial().Y + pullTab.GetDimensions().Y - blueBanner.GetDimensions().Y
+					finalPos := coords.MakeVec(finalX, finalY)
+					reposition.AnimateImageNoChannel(blueBanner, finalPos, blueBanner.GetDimensions(), u)
+				}
 			}
 		}
 	}
@@ -236,13 +246,17 @@
 	} else if u.CurImg != nil && touchingStaticImg(t, u.Other[0], u) {
 		ch := make(chan bool)
 		success := passCards(ch, u.CurPlayerIndex, u)
+		quit := make(chan bool)
+		u.AnimChans = append(u.AnimChans, quit)
 		go func() {
-			<-ch
-			if !success {
-				fmt.Println("Invalid pass")
-			} else {
-				view.LoadTakeView(u)
+			onDone := func() {
+				if !success {
+					fmt.Println("Invalid pass")
+				} else {
+					view.LoadTakeView(u)
+				}
 			}
+			reposition.SwitchOnChan(ch, quit, onDone, u)
 		}()
 	}
 	u.CurCard = nil
@@ -251,6 +265,9 @@
 
 func beginClickTake(t touch.Event, u *uistate.UIState) {
 	u.CurCard = findClickedCard(t, u)
+	if u.CurCard != nil {
+		u.CurCard.GetNode().Arranger = nil
+	}
 	buttonList := findClickedButton(t, u)
 	if len(buttonList) > 0 {
 		if u.Debug {
@@ -282,13 +299,17 @@
 	if doneTaking {
 		ch := make(chan bool)
 		success := takeCards(ch, u.CurPlayerIndex, u)
+		quit := make(chan bool)
+		u.AnimChans = append(u.AnimChans, quit)
 		go func() {
-			<-ch
-			if !success {
-				fmt.Println("Invalid take")
-			} else {
-				view.LoadPlayView(u)
+			onDone := func() {
+				if !success {
+					fmt.Println("Invalid take")
+				} else {
+					view.LoadPlayView(u)
+				}
 			}
+			reposition.SwitchOnChan(ch, quit, onDone, u)
 		}()
 	}
 }
@@ -306,6 +327,9 @@
 			} else if u.Buttons[2] == buttonList[0] {
 				view.LoadPassOrTakeOrPlay(u)
 			}
+		} else {
+			u.CurImg = u.Buttons[0]
+			view.LoadSplitView(false, u)
 		}
 	}
 }
@@ -324,9 +348,11 @@
 			reposition.ResetCardPosition(u.CurCard, u.Eng)
 			reposition.RealignSuit(u.CurCard.GetSuit(), u.CurCard.GetInitial().Y, u)
 		}
+		quit := make(chan bool)
+		u.AnimChans = append(u.AnimChans, quit)
 		go func() {
-			<-ch
-			view.LoadPlayView(u)
+			onDone := func() { view.LoadPlayView(u) }
+			reposition.SwitchOnChan(ch, quit, onDone, u)
 		}()
 	} else {
 		// check to see if card was removed from a drop target
@@ -345,9 +371,11 @@
 			if u.Buttons[0] == buttonList[0] {
 				ch := make(chan bool)
 				reposition.AnimateOutSplit(ch, u)
+				quit := make(chan bool)
+				u.AnimChans = append(u.AnimChans, quit)
 				go func() {
-					<-ch
-					view.LoadPlayView(u)
+					onDone := func() { view.LoadPlayView(u) }
+					reposition.SwitchOnChan(ch, quit, onDone, u)
 				}()
 			} else if u.Buttons[1] == buttonList[0] {
 				view.LoadTableView(u)
@@ -357,9 +385,11 @@
 		} else {
 			ch := make(chan bool)
 			reposition.AnimateOutSplit(ch, u)
+			quit := make(chan bool)
+			u.AnimChans = append(u.AnimChans, quit)
 			go func() {
-				<-ch
-				view.LoadPlayView(u)
+				onDone := func() { view.LoadPlayView(u) }
+				reposition.SwitchOnChan(ch, quit, onDone, u)
 			}()
 		}
 	}
@@ -397,6 +427,7 @@
 		for !success {
 			gamelog.LogReady(u)
 		}
+		view.LoadWaitingView(u)
 	}
 }