Finished split view functionality

Change-Id: I28b0350a8356b612f94fc6755e2107181f39daff
diff --git a/go/Makefile b/go/Makefile
index 416578f..f2acc35 100644
--- a/go/Makefile
+++ b/go/Makefile
@@ -19,7 +19,7 @@
 	mkdir -p $@
 
 credentials: bin/principal
-	principal seekblessings --v23.credentials ./credentials
+	bin/principal seekblessings --v23.credentials ./credentials
 	touch $@
 
 .PHONY:
@@ -32,7 +32,7 @@
 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)))
-	syncbased \
+	bin/syncbased \
 		--v=5 \
 		--alsologtostderr=false \
 		--root-dir=tmp/syncbase_$(id) \
diff --git a/go/src/hearts/assets/trickDrop.png b/go/src/hearts/assets/trickDrop.png
index 0c98e17..6efb791 100644
--- a/go/src/hearts/assets/trickDrop.png
+++ b/go/src/hearts/assets/trickDrop.png
Binary files differ
diff --git a/go/src/hearts/assets/trickDropBlue.png b/go/src/hearts/assets/trickDropBlue.png
index 2470322..b29989c 100644
--- a/go/src/hearts/assets/trickDropBlue.png
+++ b/go/src/hearts/assets/trickDropBlue.png
Binary files differ
diff --git a/go/src/hearts/img/reposition/reposition.go b/go/src/hearts/img/reposition/reposition.go
index 790b2b0..449eae8 100644
--- a/go/src/hearts/img/reposition/reposition.go
+++ b/go/src/hearts/img/reposition/reposition.go
@@ -10,6 +10,7 @@
 	"hearts/img/coords"
 	"hearts/img/direction"
 	"hearts/img/staticimg"
+	"hearts/img/texture"
 	"hearts/img/uistate"
 	"hearts/logic/card"
 	"hearts/logic/player"
@@ -71,6 +72,19 @@
 	}
 }
 
+func SetSplitDropColors(u *uistate.UIState) {
+	blueTargetIndex := u.CurTable.WhoseTurn()
+	for i, d := range u.DropTargets {
+		if (u.CurPlayerIndex+i)%u.NumPlayers == blueTargetIndex {
+			u.Eng.SetSubTex(d.GetNode(), d.GetAlt())
+			d.SetDisplayingImage(false)
+		} else {
+			u.Eng.SetSubTex(d.GetNode(), d.GetImage())
+			d.SetDisplayingImage(true)
+		}
+	}
+}
+
 // Drags card curCard along with the mouse
 func DragCard(t touch.Event, u *uistate.UIState) {
 	tVec := coords.MakeVec(t.X, t.Y)
@@ -208,7 +222,7 @@
 
 // Animation for the 'play' action, when app is in the hand view
 func AnimateHandCardPlay(ch chan bool, animCard *card.Card, u *uistate.UIState) {
-	imgs := []*staticimg.StaticImg{u.Other[0], u.DropTargets[0]}
+	imgs := []*staticimg.StaticImg{u.BackgroundImgs[0], u.DropTargets[0]}
 	for _, i := range imgs {
 		dims := i.GetDimensions()
 		to := coords.MakeVec(i.GetCurrent().X, i.GetCurrent().Y-u.WindowSize.Y)
@@ -220,7 +234,7 @@
 
 // Animation to bring in the play slot when app is in the hand view and it is the player's turn
 func AnimateInPlay(u *uistate.UIState) {
-	imgs := []*staticimg.StaticImg{u.Other[0], u.DropTargets[0]}
+	imgs := []*staticimg.StaticImg{u.BackgroundImgs[0], u.DropTargets[0]}
 	for _, i := range imgs {
 		dims := i.GetDimensions()
 		to := coords.MakeVec(i.GetCurrent().X, i.GetCurrent().Y+u.WindowSize.Y/3+u.TopPadding)
@@ -228,6 +242,96 @@
 	}
 }
 
+// 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]
+	toPos := dropTarget.GetCurrent()
+	toDim := dropTarget.GetDimensions()
+	texture.PopulateCardImage(c, u.Texs, u.Eng, u.Scene)
+	switch player {
+	case (u.CurPlayerIndex + 1) % u.NumPlayers:
+		c.Move(coords.MakeVec(-toDim.X, 0), toDim, u.Eng)
+	case (u.CurPlayerIndex + 2) % u.NumPlayers:
+		c.Move(coords.MakeVec((u.WindowSize.X-toDim.X)/2, -toDim.Y), toDim, u.Eng)
+	case (u.CurPlayerIndex + 3) % u.NumPlayers:
+		c.Move(coords.MakeVec(u.WindowSize.X, 0), toDim, u.Eng)
+	}
+	ch := make(chan bool)
+	animateCardMovement(ch, c, toPos, toDim, u)
+	<-ch
+}
+
+func AnimateInSplit(u *uistate.UIState) {
+	topOfBanner := u.WindowSize.Y - 4*u.CardDim.Y - 5*u.Padding - u.BottomPadding - 40
+	tableImgs := make([]*staticimg.StaticImg, 0)
+	bannerImgs := make([]*staticimg.StaticImg, 0)
+	cards := make([]*card.Card, 0)
+	bannerImgs = append(bannerImgs, u.Other...)
+	bannerImgs = append(bannerImgs, u.Buttons[0])
+	tableImgs = append(tableImgs, u.DropTargets...)
+	tableImgs = append(tableImgs, u.BackgroundImgs[:u.NumPlayers]...)
+	cards = append(cards, u.TableCards...)
+	for _, card := range cards {
+		from := card.GetCurrent()
+		to := coords.MakeVec(from.X, from.Y+topOfBanner)
+		animateCardNoChannel(card, to, card.GetDimensions(), u)
+	}
+	for _, img := range tableImgs {
+		from := img.GetCurrent()
+		to := coords.MakeVec(from.X, from.Y+topOfBanner)
+		AnimateImageNoChannel(img, to, img.GetDimensions(), u)
+	}
+	for i, img := range bannerImgs {
+		from := img.GetCurrent()
+		to := coords.MakeVec(from.X, from.Y+topOfBanner-10)
+		if i == 0 {
+			oldDim := img.GetDimensions()
+			newDim := coords.MakeVec(oldDim.X, oldDim.Y-10)
+			newTo := coords.MakeVec(to.X, to.Y+10)
+			AnimateImageNoChannel(img, newTo, newDim, u)
+		} else {
+			AnimateImageNoChannel(img, to, img.GetDimensions(), u)
+		}
+	}
+}
+
+func AnimateOutSplit(ch chan bool, u *uistate.UIState) {
+	topOfBanner := u.WindowSize.Y - 4*u.CardDim.Y - 5*u.Padding - u.BottomPadding - 40
+	tableImgs := make([]*staticimg.StaticImg, 0)
+	bannerImgs := make([]*staticimg.StaticImg, 0)
+	cards := make([]*card.Card, 0)
+	bannerImgs = append(bannerImgs, u.Other...)
+	bannerImgs = append(bannerImgs, u.Buttons[0])
+	tableImgs = append(tableImgs, u.DropTargets...)
+	tableImgs = append(tableImgs, u.BackgroundImgs[:u.NumPlayers]...)
+	cards = append(cards, u.TableCards...)
+	for _, card := range cards {
+		from := card.GetCurrent()
+		to := coords.MakeVec(from.X, from.Y-topOfBanner)
+		animateCardNoChannel(card, to, card.GetDimensions(), u)
+	}
+	for _, img := range tableImgs {
+		from := img.GetCurrent()
+		to := coords.MakeVec(from.X, from.Y-topOfBanner)
+		AnimateImageNoChannel(img, to, img.GetDimensions(), u)
+	}
+	for i, img := range bannerImgs {
+		from := img.GetCurrent()
+		to := coords.MakeVec(from.X, from.Y-topOfBanner+10)
+		if i == 0 && i < len(bannerImgs)-1 {
+			oldDim := img.GetDimensions()
+			newDim := coords.MakeVec(oldDim.X, oldDim.Y+10)
+			newTo := coords.MakeVec(to.X, to.Y-10)
+			AnimateImageNoChannel(img, newTo, newDim, u)
+		} else if i < len(bannerImgs)-1 {
+			AnimateImageNoChannel(img, to, img.GetDimensions(), u)
+		} else {
+			animateImageMovement(ch, img, to, img.GetDimensions(), u)
+		}
+	}
+}
+
 func determineDestination(animCard *card.Card, dir direction.Direction, windowSize *coords.Vec) *coords.Vec {
 	switch dir {
 	case direction.Right:
diff --git a/go/src/hearts/img/view/view.go b/go/src/hearts/img/view/view.go
index c56a5c3..b33319b 100644
--- a/go/src/hearts/img/view/view.go
+++ b/go/src/hearts/img/view/view.go
@@ -231,6 +231,7 @@
 	if u.Debug {
 		addDebugBar(u)
 	}
+	reposition.SetTableDropColors(u)
 }
 
 // Decides which view of the player's hand to load based on what steps of the round they have completed
@@ -294,7 +295,7 @@
 	resetScene(u)
 	addPlaySlot(u)
 	addHand(u)
-	addPlayHeader(getTurnText(u), u)
+	addPlayHeader(getTurnText(u), false, u)
 	if u.Debug {
 		addDebugBar(u)
 	}
@@ -304,47 +305,54 @@
 	}
 }
 
-func LoadSplitView(u *uistate.UIState) {
+func LoadSplitView(reloading bool, u *uistate.UIState) {
 	u.CurView = uistate.Split
 	resetImgs(u)
 	resetScene(u)
+	addPlayHeader(getTurnText(u), !reloading, u)
+	addSplitViewPlayerIcons(!reloading, u)
 	addHand(u)
-	addPlayHeader(getTurnText(u), u)
-	addSplitViewPlayerIcons(u)
 	if u.Debug {
 		addDebugBar(u)
 	}
+	reposition.SetSplitDropColors(u)
+	if !reloading {
+		reposition.AnimateInSplit(u)
+	}
 }
 
 func ChangePlayMessage(message string, u *uistate.UIState) {
 	// remove text and replace with message
 	var emptyTex sprite.SubTex
-	for i := u.NumSuits; i < len(u.BackgroundImgs); i++ {
-		u.Eng.SetSubTex(u.BackgroundImgs[i].GetNode(), emptyTex)
+	for _, img := range u.Other {
+		u.Eng.SetSubTex(img.GetNode(), emptyTex)
 	}
-	u.BackgroundImgs = u.BackgroundImgs[:u.NumSuits]
 	u.Eng.SetSubTex(u.Buttons[0].GetNode(), emptyTex)
+	u.Other = make([]*staticimg.StaticImg, 0)
 	u.Buttons = make([]*staticimg.StaticImg, 0)
-	addPlayHeader(message, u)
+	addPlayHeader(message, false, u)
 }
 
-func addSplitViewPlayerIcons(u *uistate.UIState) {
+func addSplitViewPlayerIcons(beforeSplitAnimation bool, u *uistate.UIState) {
 	topOfBanner := u.WindowSize.Y - 4*u.CardDim.Y - 5*u.Padding - u.BottomPadding - 40
 	splitWindowSize := coords.MakeVec(u.WindowSize.X, topOfBanner+u.TopPadding)
 	dropTargetImage := u.Texs["trickDrop.png"]
 	dropTargetAlt := u.Texs["trickDropBlue.png"]
 	dropTargetDimensions := u.CardDim
-	playerIconDimensions := u.CardDim.Minus(2)
+	playerIconDimensions := u.CardDim.Minus(4)
 	// first drop target
 	dropTargetX := (splitWindowSize.X - u.CardDim.X) / 2
 	dropTargetY := splitWindowSize.Y/2 + u.Padding
+	if beforeSplitAnimation {
+		dropTargetY -= topOfBanner
+	}
 	dropTargetPos := coords.MakeVec(dropTargetX, dropTargetY)
 	u.DropTargets = append(u.DropTargets,
 		texture.MakeImgWithAlt(dropTargetImage, dropTargetAlt, dropTargetPos, dropTargetDimensions, true, u.Eng, u.Scene))
 	// first player icon
 	playerIconImage := u.CurTable.GetPlayers()[u.CurPlayerIndex].GetIconImage()
 	u.BackgroundImgs = append(u.BackgroundImgs,
-		texture.MakeImgWithoutAlt(playerIconImage, dropTargetPos.Plus(1), playerIconDimensions, u.Eng, u.Scene))
+		texture.MakeImgWithoutAlt(playerIconImage, dropTargetPos.Plus(2), playerIconDimensions, u.Eng, u.Scene))
 	// card on top of first drop target
 	dropCard := u.CurTable.GetTrick()[u.CurPlayerIndex]
 	if dropCard != nil {
@@ -354,6 +362,9 @@
 	}
 	// second drop target
 	dropTargetY = (splitWindowSize.Y - u.CardDim.Y) / 2
+	if beforeSplitAnimation {
+		dropTargetY -= topOfBanner
+	}
 	dropTargetX = splitWindowSize.X/2 - 3*u.CardDim.X/2 - u.Padding
 	dropTargetPos = coords.MakeVec(dropTargetX, dropTargetY)
 	u.DropTargets = append(u.DropTargets,
@@ -361,7 +372,7 @@
 	// second player icon
 	playerIconImage = u.CurTable.GetPlayers()[(u.CurPlayerIndex+1)%len(u.CurTable.GetPlayers())].GetIconImage()
 	u.BackgroundImgs = append(u.BackgroundImgs,
-		texture.MakeImgWithoutAlt(playerIconImage, dropTargetPos.Plus(1), playerIconDimensions, u.Eng, u.Scene))
+		texture.MakeImgWithoutAlt(playerIconImage, dropTargetPos.Plus(2), playerIconDimensions, u.Eng, u.Scene))
 	// card on top of second drop target
 	dropCard = u.CurTable.GetTrick()[(u.CurPlayerIndex+1)%len(u.CurTable.GetPlayers())]
 	if dropCard != nil {
@@ -372,13 +383,16 @@
 	// third drop target
 	dropTargetX = (splitWindowSize.X - u.CardDim.X) / 2
 	dropTargetY = splitWindowSize.Y/2 - u.Padding - u.CardDim.Y
+	if beforeSplitAnimation {
+		dropTargetY -= topOfBanner
+	}
 	dropTargetPos = coords.MakeVec(dropTargetX, dropTargetY)
 	u.DropTargets = append(u.DropTargets,
 		texture.MakeImgWithAlt(dropTargetImage, dropTargetAlt, dropTargetPos, dropTargetDimensions, true, u.Eng, u.Scene))
 	// third player icon
 	playerIconImage = u.CurTable.GetPlayers()[(u.CurPlayerIndex+2)%len(u.CurTable.GetPlayers())].GetIconImage()
 	u.BackgroundImgs = append(u.BackgroundImgs,
-		texture.MakeImgWithoutAlt(playerIconImage, dropTargetPos.Plus(1), playerIconDimensions, u.Eng, u.Scene))
+		texture.MakeImgWithoutAlt(playerIconImage, dropTargetPos.Plus(2), playerIconDimensions, u.Eng, u.Scene))
 	// card on top of third drop target
 	dropCard = u.CurTable.GetTrick()[(u.CurPlayerIndex+2)%len(u.CurTable.GetPlayers())]
 	if dropCard != nil {
@@ -388,6 +402,9 @@
 	}
 	// fourth drop target
 	dropTargetY = (splitWindowSize.Y - u.CardDim.Y) / 2
+	if beforeSplitAnimation {
+		dropTargetY -= topOfBanner
+	}
 	dropTargetX = splitWindowSize.X/2 + u.CardDim.X/2 + u.Padding
 	dropTargetPos = coords.MakeVec(dropTargetX, dropTargetY)
 	u.DropTargets = append(u.DropTargets,
@@ -395,7 +412,7 @@
 	// fourth player icon
 	playerIconImage = u.CurTable.GetPlayers()[(u.CurPlayerIndex+3)%len(u.CurTable.GetPlayers())].GetIconImage()
 	u.BackgroundImgs = append(u.BackgroundImgs,
-		texture.MakeImgWithoutAlt(playerIconImage, dropTargetPos.Plus(1), playerIconDimensions, u.Eng, u.Scene))
+		texture.MakeImgWithoutAlt(playerIconImage, dropTargetPos.Plus(2), playerIconDimensions, u.Eng, u.Scene))
 	// card on top of fourth drop target
 	dropCard = u.CurTable.GetTrick()[(u.CurPlayerIndex+3)%len(u.CurTable.GetPlayers())]
 	if dropCard != nil {
@@ -429,12 +446,12 @@
 		texture.MakeImgWithoutAlt(headerImage, headerPos, headerDimensions, u.Eng, u.Scene))
 }
 
-func addPlayHeader(message string, u *uistate.UIState) {
+func addPlayHeader(message string, beforeSplitAnimation bool, u *uistate.UIState) {
 	// adding blue banner
 	headerImage := u.Texs["Rectangle-DBlue.png"]
 	var headerDimensions *coords.Vec
 	var headerPos *coords.Vec
-	if u.CurView == uistate.Play {
+	if u.CurView == uistate.Play || beforeSplitAnimation {
 		headerDimensions = coords.MakeVec(u.WindowSize.X, float32(50))
 		headerPos = coords.MakeVec(0, 0)
 	} else {
@@ -442,7 +459,7 @@
 		topOfHand := u.WindowSize.Y - 4*(u.CardDim.Y+u.Padding) - u.BottomPadding
 		headerPos = coords.MakeVec(0, topOfHand-headerDimensions.Y-u.Padding)
 	}
-	u.BackgroundImgs = append(u.BackgroundImgs,
+	u.Other = append(u.Other,
 		texture.MakeImgWithoutAlt(headerImage, headerPos, headerDimensions, u.Eng, u.Scene))
 	// adding pull tab
 	pullTabImage := u.Texs["HorizontalPullTab.png"]
@@ -453,14 +470,9 @@
 	// adding text
 	color := "DBlue"
 	scaler := float32(4)
-	var center *coords.Vec
-	if u.CurView == uistate.Play {
-		center = coords.MakeVec(u.WindowSize.X/2, headerPos.Y+20)
-	} else {
-		center = coords.MakeVec(u.WindowSize.X/2, headerPos.Y+10)
-	}
+	center := coords.MakeVec(u.WindowSize.X/2, headerPos.Y+headerDimensions.Y-30)
 	maxWidth := u.WindowSize.X - pullTabDim.X*2 - u.Padding*4
-	u.BackgroundImgs = append(u.BackgroundImgs,
+	u.Other = append(u.Other,
 		texture.MakeStringImgCenterAlign(message, color, color, true, center, scaler, maxWidth, u)...)
 }
 
@@ -470,7 +482,7 @@
 	blueRectImg := u.Texs["RoundedRectangle-LBlue.png"]
 	blueRectDim := coords.MakeVec(u.WindowSize.X-4*u.BottomPadding, topOfHand+u.CardDim.Y)
 	blueRectPos := coords.MakeVec(2*u.BottomPadding, -blueRectDim.Y)
-	u.Other = append(u.Other,
+	u.BackgroundImgs = append(u.BackgroundImgs,
 		texture.MakeImgWithoutAlt(blueRectImg, blueRectPos, blueRectDim, u.Eng, u.Scene))
 	// adding drop target
 	dropTargetImg := u.Texs["trickDrop.png"]
diff --git a/go/src/hearts/logic/table/table.go b/go/src/hearts/logic/table/table.go
index 74ed5ba..f374dc4 100644
--- a/go/src/hearts/logic/table/table.go
+++ b/go/src/hearts/logic/table/table.go
@@ -40,7 +40,7 @@
 		heartsBroken: false,
 		firstTrick:   true,
 		winCondition: 100,
-		dir:          direction.Right,
+		dir:          direction.None,
 	}
 }
 
diff --git a/go/src/hearts/syncbase/server/main.go b/go/src/hearts/syncbase/server/main.go
index 32da5c6..e4f4fe6 100644
--- a/go/src/hearts/syncbase/server/main.go
+++ b/go/src/hearts/syncbase/server/main.go
@@ -85,8 +85,8 @@
 	app := u.Service.App(appName)
 	db := app.NoSQLDatabase(dbName, nil)
 	sg := db.Syncgroup(sgName)
-	myInfo := wire.SyncgroupMemberInfo{8}
-	_, err := sg.Join(u.Ctx, myInfo)
+	myInfoJoiner := wire.SyncgroupMemberInfo{8, false}
+	_, err := sg.Join(u.Ctx, myInfoJoiner)
 	if err == nil {
 		fmt.Println("Successfully joined syncgroup")
 	} else {
@@ -101,7 +101,8 @@
 			Prefixes:    prefs,
 			MountTables: tables,
 			IsPrivate:   false}
-		err := sg.Create(u.Ctx, spec, myInfo)
+		myInfoCreator := wire.SyncgroupMemberInfo{8, true}
+		err := sg.Create(u.Ctx, spec, myInfoCreator)
 		if err != nil {
 			fmt.Println("SYNCGROUP CREATE ERROR: ", err)
 		}
diff --git a/go/src/hearts/syncbase/watch/watch.go b/go/src/hearts/syncbase/watch/watch.go
index 7979459..db2f4fc 100644
--- a/go/src/hearts/syncbase/watch/watch.go
+++ b/go/src/hearts/syncbase/watch/watch.go
@@ -169,6 +169,26 @@
 			}
 			reposition.AnimateTableCardTakeTrick(trickCards, trickDir, 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
+			}
+			reposition.AnimateTableCardTakeTrick(trickCards, trickDir, u)
+		}
+		view.LoadSplitView(true, u)
 	} else if u.CurView == uistate.Play {
 		if roundOver {
 			view.LoadScoreView(roundScores, winners, u)
diff --git a/go/src/hearts/touchhandler/touchhandler.go b/go/src/hearts/touchhandler/touchhandler.go
index 89d63af..2d8de91 100644
--- a/go/src/hearts/touchhandler/touchhandler.go
+++ b/go/src/hearts/touchhandler/touchhandler.go
@@ -22,54 +22,70 @@
 func OnTouch(t touch.Event, u *uistate.UIState) {
 	switch u.CurView {
 	case uistate.Opening:
-		switch t.Type.String() {
-		case "begin":
+		switch t.Type {
+		case touch.TypeBegin:
 			beginClickOpening(t, u)
 		}
 	case uistate.Table:
-		switch t.Type.String() {
-		case "begin":
-			beginClickTable(t, u)
+		switch t.Type {
+		case touch.TypeBegin:
+			if u.Debug {
+				beginClickTable(t, u)
+			}
 		}
 	case uistate.Pass:
-		switch t.Type.String() {
-		case "begin":
+		switch t.Type {
+		case touch.TypeBegin:
 			beginClickPass(t, u)
-		case "move":
+		case touch.TypeMove:
 			moveClickPass(t, u)
-		case "end":
+		case touch.TypeEnd:
 			endClickPass(t, u)
 		}
 	case uistate.Take:
-		switch t.Type.String() {
-		case "begin":
+		switch t.Type {
+		case touch.TypeBegin:
 			beginClickTake(t, u)
-		case "move":
-			moveClickTake(t, u)
-		case "end":
-			endClickTake(t, u)
+		case touch.TypeMove:
+			if u.CurCard != nil {
+				moveClickTake(t, u)
+			}
+		case touch.TypeEnd:
+			if u.CurCard != nil {
+				endClickTake(t, u)
+				u.CurCard = nil
+			}
 		}
 	case uistate.Play:
-		switch t.Type.String() {
-		case "begin":
+		switch t.Type {
+		case touch.TypeBegin:
 			beginClickPlay(t, u)
-		case "move":
-			moveClickPlay(t, u)
-		case "end":
-			endClickPlay(t, u)
+		case touch.TypeMove:
+			if u.CurCard != nil {
+				moveClickPlay(t, u)
+			}
+		case touch.TypeEnd:
+			if u.CurCard != nil {
+				endClickPlay(t, u)
+			}
 		}
 	case uistate.Split:
-		switch t.Type.String() {
-		case "begin":
+		switch t.Type {
+		case touch.TypeBegin:
 			beginClickSplit(t, u)
-		case "move":
-			moveClickSplit(t, u)
-		case "end":
-			endClickSplit(t, u)
+		case touch.TypeMove:
+			if u.CurCard != nil {
+				moveClickSplit(t, u)
+			}
+		case touch.TypeEnd:
+			if u.CurCard != nil {
+				endClickSplit(t, u)
+				u.CurCard = nil
+			}
 		}
 	case uistate.Score:
-		switch t.Type.String() {
-		case "begin":
+		switch t.Type {
+		case touch.TypeBegin:
 			beginClickScore(t, u)
 		}
 	}
@@ -89,27 +105,9 @@
 }
 
 func beginClickTable(t touch.Event, u *uistate.UIState) {
-	if u.Debug {
-		buttonList := findClickedButton(t, u)
-		if len(buttonList) > 0 {
-			if u.Buttons[0] == buttonList[0] {
-				u.CurPlayerIndex = 0
-				view.LoadPassOrTakeOrPlay(u)
-			} else if u.Buttons[1] == buttonList[0] {
-				u.CurPlayerIndex = 1
-				view.LoadPassOrTakeOrPlay(u)
-			} else if u.Buttons[2] == buttonList[0] {
-				u.CurPlayerIndex = 2
-				view.LoadPassOrTakeOrPlay(u)
-			} else if u.Buttons[3] == buttonList[0] {
-				u.CurPlayerIndex = 3
-				view.LoadPassOrTakeOrPlay(u)
-			} else if u.Buttons[4] == buttonList[0] {
-				view.LoadTableView(u)
-			} else if u.Buttons[5] == buttonList[0] {
-				view.LoadPassOrTakeOrPlay(u)
-			}
-		}
+	buttonList := findClickedButton(t, u)
+	if len(buttonList) > 0 {
+		updateViewFromTable(buttonList[0], u)
 	}
 }
 
@@ -229,38 +227,33 @@
 }
 
 func moveClickTake(t touch.Event, u *uistate.UIState) {
-	if u.CurCard != nil {
-		reposition.DragCard(t, u)
-	}
+	reposition.DragCard(t, u)
 }
 
 func endClickTake(t touch.Event, u *uistate.UIState) {
-	if u.CurCard != nil {
-		// check to see if card was removed from a drop target
-		removeCardFromTarget(u.CurCard, u)
-		// add card back to hand
-		reposition.ResetCardPosition(u.CurCard, u.Eng)
-		reposition.RealignSuit(u.CurCard.GetSuit(), u.CurCard.GetInitial().Y, u)
-		doneTaking := true
-		for _, d := range u.DropTargets {
-			if d.GetCardHere() != nil {
-				doneTaking = false
-			}
-		}
-		if doneTaking {
-			ch := make(chan bool)
-			success := takeCards(ch, u.CurPlayerIndex, u)
-			go func() {
-				<-ch
-				if !success {
-					fmt.Println("Invalid take")
-				} else {
-					view.LoadPlayView(u)
-				}
-			}()
+	// check to see if card was removed from a drop target
+	removeCardFromTarget(u.CurCard, u)
+	// add card back to hand
+	reposition.ResetCardPosition(u.CurCard, u.Eng)
+	reposition.RealignSuit(u.CurCard.GetSuit(), u.CurCard.GetInitial().Y, u)
+	doneTaking := true
+	for _, d := range u.DropTargets {
+		if d.GetCardHere() != nil {
+			doneTaking = false
 		}
 	}
-	u.CurCard = nil
+	if doneTaking {
+		ch := make(chan bool)
+		success := takeCards(ch, u.CurPlayerIndex, u)
+		go func() {
+			<-ch
+			if !success {
+				fmt.Println("Invalid take")
+			} else {
+				view.LoadPlayView(u)
+			}
+		}()
+	}
 }
 
 func beginClickPlay(t touch.Event, u *uistate.UIState) {
@@ -270,7 +263,7 @@
 		if u.Debug {
 			if u.Buttons[0] == buttonList[0] {
 				u.CurImg = u.Buttons[0]
-				view.LoadSplitView(u)
+				view.LoadSplitView(false, u)
 			} else if u.Buttons[1] == buttonList[0] {
 				view.LoadTableView(u)
 			} else if u.Buttons[2] == buttonList[0] {
@@ -281,44 +274,83 @@
 }
 
 func moveClickPlay(t touch.Event, u *uistate.UIState) {
-	if u.CurCard != nil {
-		reposition.DragCard(t, u)
-	}
+	reposition.DragCard(t, u)
 }
 
 func endClickPlay(t touch.Event, u *uistate.UIState) {
-	if u.CurCard != nil {
-		if !dropCardOnTarget(u.CurCard, t, u) {
-			// check to see if card was removed from a drop target
+	if dropCardOnTarget(u.CurCard, t, u) {
+		ch := make(chan bool)
+		if err := playCard(ch, u.CurPlayerIndex, u); err != "" {
+			view.ChangePlayMessage(err, u)
 			removeCardFromTarget(u.CurCard, u)
 			// add card back to hand
 			reposition.ResetCardPosition(u.CurCard, u.Eng)
 			reposition.RealignSuit(u.CurCard.GetSuit(), u.CurCard.GetInitial().Y, u)
+		}
+		go func() {
+			<-ch
+			view.LoadPlayView(u)
+		}()
+	} else {
+		// check to see if card was removed from a drop target
+		removeCardFromTarget(u.CurCard, u)
+		// add card back to hand
+		reposition.ResetCardPosition(u.CurCard, u.Eng)
+		reposition.RealignSuit(u.CurCard.GetSuit(), u.CurCard.GetInitial().Y, u)
+	}
+}
+
+func beginClickSplit(t touch.Event, u *uistate.UIState) {
+	u.CurCard = findClickedCard(t, u)
+	buttonList := findClickedButton(t, u)
+	if len(buttonList) > 0 {
+		if u.Debug {
+			if u.Buttons[0] == buttonList[0] {
+				ch := make(chan bool)
+				reposition.AnimateOutSplit(ch, u)
+				go func() {
+					<-ch
+					view.LoadPlayView(u)
+				}()
+			} else if u.Buttons[1] == buttonList[0] {
+				view.LoadTableView(u)
+			} else if u.Buttons[2] == buttonList[0] {
+				view.LoadPassOrTakeOrPlay(u)
+			}
 		} else {
 			ch := make(chan bool)
-			if err := playCard(ch, u.CurPlayerIndex, u); err != "" {
-				view.ChangePlayMessage(err, u)
-			}
+			reposition.AnimateOutSplit(ch, u)
 			go func() {
 				<-ch
 				view.LoadPlayView(u)
 			}()
 		}
 	}
-	u.CurCard = nil
-}
-
-func beginClickSplit(t touch.Event, u *uistate.UIState) {
-	buttonList := findClickedButton(t, u)
-	if len(buttonList) > 0 {
-		view.LoadPlayView(u)
-	}
 }
 
 func moveClickSplit(t touch.Event, u *uistate.UIState) {
+	reposition.DragCard(t, u)
 }
 
 func endClickSplit(t touch.Event, u *uistate.UIState) {
+	if dropCardHere(u.CurCard, u.DropTargets[0], t, u) {
+		ch := make(chan bool)
+		if err := playCard(ch, u.CurPlayerIndex, u); err != "" {
+			view.ChangePlayMessage(err, u)
+			removeCardFromTarget(u.CurCard, u)
+			// add card back to hand
+			reposition.ResetCardPosition(u.CurCard, u.Eng)
+			reposition.RealignSuit(u.CurCard.GetSuit(), u.CurCard.GetInitial().Y, u)
+		} else {
+			reposition.RealignSuit(u.CurCard.GetSuit(), u.CurCard.GetInitial().Y, u)
+		}
+	} else {
+		// check to see if card was removed from a drop target
+		removeCardFromTarget(u.CurCard, u)
+		// add card back to hand
+		reposition.ResetCardPosition(u.CurCard, u.Eng)
+		reposition.RealignSuit(u.CurCard.GetSuit(), u.CurCard.GetInitial().Y, u)
+	}
 }
 
 func beginClickScore(t touch.Event, u *uistate.UIState) {
@@ -366,72 +398,75 @@
 		}
 	}
 	// if the pass is not valid, don't pass any cards
-	if u.CurTable.ValidPass(cardsPassed) && !u.CurTable.GetPlayers()[playerId].GetDonePassing() {
-		success := gamelog.LogPass(u, cardsPassed)
-		for !success {
-			success = gamelog.LogPass(u, cardsPassed)
-		}
-		// UI component
-		pullTab := u.Buttons[0]
-		blueBanner := u.BackgroundImgs[1]
-		imgs := []*staticimg.StaticImg{pullTab, blueBanner}
-		for _, d := range dropsToReset {
-			imgs = append(imgs, d)
-			d.SetCardHere(nil)
-		}
-		var blankTex sprite.SubTex
-		for _, i := range imgs {
-			u.Eng.SetSubTex(i.GetNode(), blankTex)
-		}
-		reposition.AnimateHandCardPass(ch, u.Other, cardsPassed, u)
-		return true
+	if !u.CurTable.ValidPass(cardsPassed) || u.CurTable.GetPlayers()[playerId].GetDonePassing() {
+		return false
 	}
-	return false
+	success := gamelog.LogPass(u, cardsPassed)
+	for !success {
+		success = gamelog.LogPass(u, cardsPassed)
+	}
+	// UI component
+	pullTab := u.Buttons[0]
+	blueBanner := u.BackgroundImgs[1]
+	imgs := []*staticimg.StaticImg{pullTab, blueBanner}
+	for _, d := range dropsToReset {
+		imgs = append(imgs, d)
+		d.SetCardHere(nil)
+	}
+	var blankTex sprite.SubTex
+	for _, i := range imgs {
+		u.Eng.SetSubTex(i.GetNode(), blankTex)
+	}
+	reposition.AnimateHandCardPass(ch, u.Other, cardsPassed, u)
+	return true
 }
 
 func takeCards(ch chan bool, playerId int, u *uistate.UIState) bool {
 	player := u.CurTable.GetPlayers()[playerId]
 	passedCards := player.GetPassedTo()
-	if len(passedCards) == 3 {
-		success := gamelog.LogTake(u)
-		for !success {
-			success = gamelog.LogTake(u)
-		}
-		reposition.AnimateHandCardTake(ch, u.Other, u)
-		return true
+	if len(passedCards) != 3 {
+		return false
 	}
-	return false
+	success := gamelog.LogTake(u)
+	for !success {
+		success = gamelog.LogTake(u)
+	}
+	reposition.AnimateHandCardTake(ch, u.Other, u)
+	return true
 }
 
 func playCard(ch chan bool, playerId int, u *uistate.UIState) string {
 	c := u.DropTargets[0].GetCardHere()
-	if c != nil {
-		// checks to make sure that:
-		// -player has not already played a card this round
-		// -all players have passed cards
-		// -the play is in the right order
-		// -the play is valid given game logic
-		if u.CurTable.GetPlayers()[playerId].GetDonePlaying() {
-			return "You have already played a card in this trick"
-		}
-		if !u.CurTable.AllDonePassing() {
-			return "Not all players have passed their cards"
-		}
-		if !u.CurTable.ValidPlayOrder(playerId) {
-			return "It is not your turn"
-		}
-		if err := u.CurTable.ValidPlayLogic(c, playerId); err != "" {
-			return err
-		}
-		u.DropTargets[0].SetCardHere(nil)
-		success := gamelog.LogPlay(u, c)
-		for !success {
-			success = gamelog.LogPlay(u, c)
-		}
-		reposition.AnimateHandCardPlay(ch, c, u)
-		return ""
+	if c == nil {
+		return "No card has been played"
 	}
-	return "No card has been played"
+	// checks to make sure that:
+	// -player has not already played a card this round
+	// -all players have passed cards
+	// -the play is in the right order
+	// -the play is valid given game logic
+	if u.CurTable.GetPlayers()[playerId].GetDonePlaying() {
+		return "You have already played a card in this trick"
+	}
+	if !u.CurTable.AllDonePassing() {
+		return "Not all players have passed their cards"
+	}
+	if !u.CurTable.ValidPlayOrder(playerId) {
+		return "It is not your turn"
+	}
+	if err := u.CurTable.ValidPlayLogic(c, playerId); err != "" {
+		return err
+	}
+	u.DropTargets[0].SetCardHere(nil)
+	success := gamelog.LogPlay(u, c)
+	for !success {
+		success = gamelog.LogPlay(u, c)
+	}
+	// no animation when in split view
+	if u.CurView == uistate.Play {
+		reposition.AnimateHandCardPlay(ch, c, u)
+	}
+	return ""
 }
 
 func pressButton(b *staticimg.StaticImg, u *uistate.UIState) {
@@ -446,6 +481,7 @@
 	}
 }
 
+// checks all drop targets to see if a card was dropped there
 func dropCardOnTarget(c *card.Card, t touch.Event, u *uistate.UIState) bool {
 	for _, d := range u.DropTargets {
 		// checking to see if card was dropped onto a drop target
@@ -453,27 +489,39 @@
 			lastDroppedCard := d.GetCardHere()
 			if lastDroppedCard != nil {
 				reposition.ResetCardPosition(lastDroppedCard, u.Eng)
-				if u.CurView == uistate.Pass || u.CurView == uistate.Play {
-					reposition.RealignSuit(lastDroppedCard.GetSuit(), lastDroppedCard.GetInitial().Y, u)
-				} else if u.CurView == uistate.Table {
-					u.Eng.SetSubTex(lastDroppedCard.GetNode(), lastDroppedCard.GetBack())
-					lastDroppedCard.Move(lastDroppedCard.GetCurrent(), u.TableCardDim, u.Eng)
-				}
+				reposition.RealignSuit(lastDroppedCard.GetSuit(), lastDroppedCard.GetInitial().Y, u)
 			}
 			oldY := c.GetInitial().Y
 			suit := c.GetSuit()
 			u.CurCard.Move(d.GetCurrent(), c.GetDimensions(), u.Eng)
 			d.SetCardHere(u.CurCard)
 			// realign suit the card just left
-			if u.CurView == uistate.Pass || u.CurView == uistate.Play {
-				reposition.RealignSuit(suit, oldY, u)
-			}
+			reposition.RealignSuit(suit, oldY, u)
 			return true
 		}
 	}
 	return false
 }
 
+// checks one specific drop target to see if a card was dropped there
+func dropCardHere(c *card.Card, d *staticimg.StaticImg, t touch.Event, u *uistate.UIState) bool {
+	if !touchingStaticImg(t, d, u) {
+		return false
+	}
+	lastDroppedCard := d.GetCardHere()
+	if lastDroppedCard != nil {
+		reposition.ResetCardPosition(lastDroppedCard, u.Eng)
+		reposition.RealignSuit(lastDroppedCard.GetSuit(), lastDroppedCard.GetInitial().Y, u)
+	}
+	oldY := c.GetInitial().Y
+	suit := c.GetSuit()
+	u.CurCard.Move(d.GetCurrent(), c.GetDimensions(), u.Eng)
+	d.SetCardHere(u.CurCard)
+	// realign suit the card just left
+	reposition.RealignSuit(suit, oldY, u)
+	return true
+}
+
 func removeCardFromTarget(c *card.Card, u *uistate.UIState) bool {
 	for _, d := range u.DropTargets {
 		if d.GetCardHere() == c {
@@ -495,3 +543,23 @@
 	withinYBounds := t.Y/u.PixelsPerPt >= s.GetCurrent().Y && t.Y/u.PixelsPerPt <= s.GetDimensions().Y+s.GetCurrent().Y
 	return withinXBounds && withinYBounds
 }
+
+func updateViewFromTable(b *staticimg.StaticImg, u *uistate.UIState) {
+	if u.Buttons[0] == b {
+		u.CurPlayerIndex = 0
+		view.LoadPassOrTakeOrPlay(u)
+	} else if u.Buttons[1] == b {
+		u.CurPlayerIndex = 1
+		view.LoadPassOrTakeOrPlay(u)
+	} else if u.Buttons[2] == b {
+		u.CurPlayerIndex = 2
+		view.LoadPassOrTakeOrPlay(u)
+	} else if u.Buttons[3] == b {
+		u.CurPlayerIndex = 3
+		view.LoadPassOrTakeOrPlay(u)
+	} else if u.Buttons[4] == b {
+		view.LoadTableView(u)
+	} else if u.Buttons[5] == b {
+		view.LoadPassOrTakeOrPlay(u)
+	}
+}