Got app running on phone
Separated score view into helper functions
Change-Id: I7c96022ff4b9954d57d3bd2987872d756f0852cb
diff --git a/go/src/hearts/AndroidManifest.xml b/go/src/hearts/AndroidManifest.xml
new file mode 100644
index 0000000..1e434ff
--- /dev/null
+++ b/go/src/hearts/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2015 The Go Authors. All rights reserved.
+Use of this source code is governed by a BSD-style
+license that can be found in the LICENSE file.
+-->
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="io.v.go.examples.aaavolley"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="19" />
+
+ <!-- http://developer.android.com/guide/topics/manifest/manifest-intro.html#perms -->
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+ <uses-permission android:name="android.permission.INTERNET"/>
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+
+ <application android:label="aaavolley" android:debuggable="true">
+
+ <activity android:name="org.golang.app.GoNativeActivity"
+ android:label="aaavolley"
+ android:configChanges="orientation|keyboardHidden">
+ <meta-data android:name="android.app.lib_name" android:value="network" />
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
\ No newline at end of file
diff --git a/go/src/hearts/img/texture/texture.go b/go/src/hearts/img/texture/texture.go
index 9da057d..78763c0 100644
--- a/go/src/hearts/img/texture/texture.go
+++ b/go/src/hearts/img/texture/texture.go
@@ -218,6 +218,10 @@
return s
}
+func RemoveImg(s *staticimg.StaticImg, u *uistate.UIState) {
+ u.Eng.Unregister(s.GetNode())
+}
+
// Loads all images for the app
func LoadTextures(eng sprite.Engine) map[string]sprite.SubTex {
allTexs := make(map[string]sprite.SubTex)
diff --git a/go/src/hearts/img/view/view.go b/go/src/hearts/img/view/view.go
index 4c45f81..0155c51 100644
--- a/go/src/hearts/img/view/view.go
+++ b/go/src/hearts/img/view/view.go
@@ -237,7 +237,7 @@
func LoadPassOrTakeOrPlay(u *uistate.UIState) {
p := u.CurTable.GetPlayers()[u.CurPlayerIndex]
if p.GetDoneTaking() || u.CurTable.GetDir() == direction.None {
- LoadPlayView(u)
+ LoadPlayView("", u)
} else if p.GetDonePassing() {
LoadTakeView(u)
} else {
@@ -251,76 +251,9 @@
resetImgs(u)
resetScene(u)
addHeader(u)
- top := u.CardDim.Y
- scaler := float32(4)
- maxWidth := u.WindowSize.X / 4
- totalScores := make([]int, 0)
- for _, p := range u.CurTable.GetPlayers() {
- totalScores = append(totalScores, p.GetScore())
- }
- maxRoundScore := maxInt(roundScores)
- maxTotalScore := maxInt(totalScores)
- // adding score text
- center := coords.MakeVec(u.WindowSize.X/4, top)
- u.BackgroundImgs = append(u.BackgroundImgs,
- texture.MakeStringImgCenterAlign("Score:", "", "", true, center, scaler, maxWidth, u)...)
- // adding game text
- center = coords.MakeVec(u.WindowSize.X/2, top)
- u.BackgroundImgs = append(u.BackgroundImgs,
- texture.MakeStringImgCenterAlign("Round", "", "", true, center, scaler, maxWidth, u)...)
- // adding total text
- center = coords.MakeVec(3*u.WindowSize.X/4, top)
- u.BackgroundImgs = append(u.BackgroundImgs,
- texture.MakeStringImgCenterAlign("Total", "", "", true, center, scaler, maxWidth, u)...)
- // adding player info
- rowHeight := u.WindowSize.Y / 5
- for i, p := range u.CurTable.GetPlayers() {
- var color string
- // blue divider
- dividerImage := u.Texs["blue.png"]
- dividerDim := coords.MakeVec(u.WindowSize.X, u.Padding/2)
- dividerPos := coords.MakeVec(0, top+(float32(i)+.5)*rowHeight)
- u.BackgroundImgs = append(u.BackgroundImgs,
- texture.MakeImgWithoutAlt(dividerImage, dividerPos, dividerDim, u.Eng, u.Scene))
- // player icon
- playerIconImage := p.GetImage()
- playerIconDim := coords.MakeVec(rowHeight/2, rowHeight/2)
- playerIconPos := coords.MakeVec(u.WindowSize.X/4-playerIconDim.X/2, top+(float32(i)+.5)*rowHeight+3*u.Padding)
- u.BackgroundImgs = append(u.BackgroundImgs,
- texture.MakeImgWithoutAlt(playerIconImage, playerIconPos, playerIconDim, u.Eng, u.Scene))
- // player name
- name := p.GetName()
- center = coords.MakeVec(playerIconPos.X+playerIconDim.X/2, playerIconPos.Y+playerIconDim.Y)
- u.BackgroundImgs = append(u.BackgroundImgs,
- texture.MakeStringImgCenterAlign(name, "", "", true, center, scaler, maxWidth, u)...)
- // player round score
- roundScore := roundScores[i]
- if roundScore == maxRoundScore {
- color = "Red"
- } else {
- color = ""
- }
- center = coords.MakeVec(u.WindowSize.X/2, playerIconPos.Y+playerIconDim.Y/2)
- u.BackgroundImgs = append(u.BackgroundImgs,
- texture.MakeStringImgCenterAlign(strconv.Itoa(roundScore), color, color, true, center, scaler, maxWidth, u)...)
- // player total score
- totalScore := p.GetScore()
- if totalScore == maxTotalScore {
- color = "Red"
- } else {
- color = ""
- }
- center = coords.MakeVec(3*u.WindowSize.X/4, playerIconPos.Y+playerIconDim.Y/2)
- u.BackgroundImgs = append(u.BackgroundImgs,
- texture.MakeStringImgCenterAlign(strconv.Itoa(totalScore), color, color, true, center, scaler, maxWidth, u)...)
- }
- // adding play button to move to next round
- pressedImg := u.Texs["playPressed.png"]
- unpressedImg := u.Texs["playUnpressed.png"]
- buttonDim := coords.MakeVec(2*u.CardDim.X, u.CardDim.Y)
- buttonPos := coords.MakeVec((u.WindowSize.X-u.CardDim.X)/2, u.WindowSize.Y-u.CardDim.Y-u.BottomPadding)
- u.Buttons = append(u.Buttons,
- texture.MakeImgWithAlt(unpressedImg, pressedImg, buttonPos, buttonDim, true, u.Eng, u.Scene))
+ addScoreViewHeaderText(u)
+ addPlayerScores(roundScores, u)
+ addScoreButton(u)
}
// Pass View: Shows player's hand and allows them to pass cards
@@ -354,19 +287,31 @@
}
// Play View: Shows player's hand and allows them to play cards
-func LoadPlayView(u *uistate.UIState) {
+func LoadPlayView(err string, u *uistate.UIState) {
u.CurView = uistate.Play
- resetImgs(u)
- resetScene(u)
- addPlaySlot(u)
- addHand(u)
- addPlayHeader(u)
- if u.Debug {
- addDebugBar(u)
- }
- // animate in play slot if relevant
- if u.CurTable.WhoseTurn() == u.CurPlayerIndex && u.CurTable.AllDonePassing() {
- reposition.AnimateInPlay(u)
+ if err == "" {
+ resetImgs(u)
+ resetScene(u)
+ addPlaySlot(u)
+ addHand(u)
+ addPlayHeader(err, u)
+ if u.Debug {
+ addDebugBar(u)
+ }
+ // animate in play slot if relevant
+ if u.CurTable.WhoseTurn() == u.CurPlayerIndex && u.CurTable.AllDonePassing() {
+ reposition.AnimateInPlay(u)
+ }
+ } else {
+ // remove text and replace with err
+ var emptyTex sprite.SubTex
+ for i := u.NumSuits; i < len(u.BackgroundImgs); i++ {
+ u.Eng.SetSubTex(u.BackgroundImgs[i].GetNode(), emptyTex)
+ }
+ u.BackgroundImgs = u.BackgroundImgs[:u.NumSuits]
+ u.Eng.SetSubTex(u.Buttons[0].GetNode(), emptyTex)
+ u.Buttons = make([]*staticimg.StaticImg, 0)
+ addPlayHeader(err, u)
}
}
@@ -379,7 +324,7 @@
texture.MakeImgWithoutAlt(headerImage, headerPos, headerDimensions, u.Eng, u.Scene))
}
-func addPlayHeader(u *uistate.UIState) {
+func addPlayHeader(err string, u *uistate.UIState) {
// adding blue banner
headerImage := u.Texs["Rectangle-DBlue.png"]
headerPos := coords.MakeVec(0, 0)
@@ -394,21 +339,25 @@
texture.MakeImgWithoutAlt(pullTabImage, pullTabPos, pullTabDim, u.Eng, u.Scene))
// adding text
var turnText string
- playerTurnNum := u.CurTable.WhoseTurn()
- if playerTurnNum == -1 || !u.CurTable.AllDonePassing() {
- turnText = "Waiting for other players"
- } else if playerTurnNum == u.CurPlayerIndex {
- turnText = "Your turn"
+ if err != "" {
+ turnText = err
} else {
- name := u.CurTable.GetPlayers()[playerTurnNum].GetName()
- turnText = name + "'s turn"
+ playerTurnNum := u.CurTable.WhoseTurn()
+ if playerTurnNum == -1 || !u.CurTable.AllDonePassing() {
+ turnText = "Waiting for other players"
+ } else if playerTurnNum == u.CurPlayerIndex {
+ turnText = "Your turn"
+ } else {
+ name := u.CurTable.GetPlayers()[playerTurnNum].GetName()
+ turnText = name + "'s turn"
+ }
}
color := "DBlue"
scaler := float32(4)
center := coords.MakeVec(u.WindowSize.X/2, 20)
maxWidth := u.WindowSize.X - pullTabDim.X/2
- nameImgs := texture.MakeStringImgCenterAlign(turnText, color, color, true, center, scaler, maxWidth, u)
- u.BackgroundImgs = append(u.BackgroundImgs, nameImgs...)
+ u.BackgroundImgs = append(u.BackgroundImgs,
+ texture.MakeStringImgCenterAlign(turnText, color, color, true, center, scaler, maxWidth, u)...)
}
func addPlaySlot(u *uistate.UIState) {
@@ -635,6 +584,85 @@
}
}
+func addScoreViewHeaderText(u *uistate.UIState) {
+ top := u.CardDim.Y
+ scaler := float32(4)
+ maxWidth := u.WindowSize.X / 4
+ // adding score text
+ scoreCenter := coords.MakeVec(u.WindowSize.X/4, top)
+ u.BackgroundImgs = append(u.BackgroundImgs,
+ texture.MakeStringImgCenterAlign("Score:", "", "", true, scoreCenter, scaler, maxWidth, u)...)
+ // adding game text
+ gameCenter := coords.MakeVec(u.WindowSize.X/2, top)
+ u.BackgroundImgs = append(u.BackgroundImgs,
+ texture.MakeStringImgCenterAlign("Round", "", "", true, gameCenter, scaler, maxWidth, u)...)
+ // adding total text
+ totalCenter := coords.MakeVec(3*u.WindowSize.X/4, top)
+ u.BackgroundImgs = append(u.BackgroundImgs,
+ texture.MakeStringImgCenterAlign("Total", "", "", true, totalCenter, scaler, maxWidth, u)...)
+}
+
+func addPlayerScores(roundScores []int, u *uistate.UIState) {
+ totalScores := make([]int, 0)
+ for _, p := range u.CurTable.GetPlayers() {
+ totalScores = append(totalScores, p.GetScore())
+ }
+ maxRoundScore := maxInt(roundScores)
+ maxTotalScore := maxInt(totalScores)
+ top := u.CardDim.Y
+ scaler := float32(4)
+ maxWidth := u.WindowSize.X / 4
+ rowHeight := u.WindowSize.Y / 6
+ for i, p := range u.CurTable.GetPlayers() {
+ var color string
+ // blue divider
+ dividerImage := u.Texs["blue.png"]
+ dividerDim := coords.MakeVec(u.WindowSize.X, u.Padding/2)
+ dividerPos := coords.MakeVec(0, top+(float32(i)+.5)*rowHeight)
+ u.BackgroundImgs = append(u.BackgroundImgs,
+ texture.MakeImgWithoutAlt(dividerImage, dividerPos, dividerDim, u.Eng, u.Scene))
+ // player icon
+ playerIconImage := p.GetImage()
+ playerIconDim := coords.MakeVec(rowHeight/2, rowHeight/2)
+ playerIconPos := coords.MakeVec(u.WindowSize.X/4-playerIconDim.X/2, top+(float32(i)+.5)*rowHeight+2*u.Padding)
+ u.BackgroundImgs = append(u.BackgroundImgs,
+ texture.MakeImgWithoutAlt(playerIconImage, playerIconPos, playerIconDim, u.Eng, u.Scene))
+ // player name
+ name := p.GetName()
+ nameCenter := coords.MakeVec(playerIconPos.X+playerIconDim.X/2, playerIconPos.Y+playerIconDim.Y)
+ u.BackgroundImgs = append(u.BackgroundImgs,
+ texture.MakeStringImgCenterAlign(name, "", "", true, nameCenter, scaler, maxWidth, u)...)
+ // player round score
+ roundScore := roundScores[i]
+ if roundScore == maxRoundScore {
+ color = "Red"
+ } else {
+ color = ""
+ }
+ roundCenter := coords.MakeVec(u.WindowSize.X/2, playerIconPos.Y+playerIconDim.Y/2)
+ u.BackgroundImgs = append(u.BackgroundImgs,
+ texture.MakeStringImgCenterAlign(strconv.Itoa(roundScore), color, color, true, roundCenter, scaler, maxWidth, u)...)
+ // player total score
+ totalScore := p.GetScore()
+ if totalScore == maxTotalScore {
+ color = "Red"
+ } else {
+ color = ""
+ }
+ totalCenter := coords.MakeVec(3*u.WindowSize.X/4, playerIconPos.Y+playerIconDim.Y/2)
+ u.BackgroundImgs = append(u.BackgroundImgs,
+ texture.MakeStringImgCenterAlign(strconv.Itoa(totalScore), color, color, true, totalCenter, scaler, maxWidth, u)...)
+ }
+}
+
+func addScoreButton(u *uistate.UIState) {
+ buttonImg := u.Texs["playUnpressed.png"]
+ buttonDim := coords.MakeVec(2*u.CardDim.X, u.CardDim.Y)
+ buttonPos := coords.MakeVec((u.WindowSize.X-u.CardDim.X)/2, u.WindowSize.Y-u.CardDim.Y-u.BottomPadding)
+ u.Buttons = append(u.Buttons,
+ texture.MakeImgWithoutAlt(buttonImg, buttonPos, buttonDim, u.Eng, u.Scene))
+}
+
func resetImgs(u *uistate.UIState) {
u.Cards = make([]*card.Card, 0)
u.TableCards = make([]*card.Card, 0)
diff --git a/go/src/hearts/logic/table/table.go b/go/src/hearts/logic/table/table.go
index ae70f94..073d2b4 100644
--- a/go/src/hearts/logic/table/table.go
+++ b/go/src/hearts/logic/table/table.go
@@ -145,34 +145,44 @@
return t.WhoseTurn() == playerIndex
}
-// Given a card and the index of its player, returns true if this move was valid based on game logic
-func (t *Table) ValidPlayLogic(c *card.Card, playerIndex int) bool {
+// Given a card and the index of its player, returns "" if this move was valid based on game logic
+// Otherwise returns a string explaining the error
+func (t *Table) ValidPlayLogic(c *card.Card, playerIndex int) string {
+ validPlay := ""
player := t.players[playerIndex]
if t.firstPlayer == playerIndex {
if !t.firstTrick {
if c.GetSuit() != card.Heart || t.heartsBroken {
- return true
+ return validPlay
} else {
if player.HasOnlyHearts() {
- return true
+ return validPlay
+ } else {
+ return "Hearts have not been broken"
}
}
} else if c.GetSuit() == card.Club && c.GetFace() == card.Two {
- return true
+ return validPlay
+ } else {
+ return "Must open with the Two of Clubs"
}
} else {
firstPlayedSuit := t.trick[t.firstPlayer].GetSuit()
if c.GetSuit() == firstPlayedSuit || !player.HasSuit(firstPlayedSuit) {
if !t.firstTrick {
- return true
+ return validPlay
} else if !c.WorthPoints() {
- return true
+ return validPlay
} else if player.HasAllPoints() {
- return true
+ return validPlay
+ } else {
+ return "Point cards not allowed in the first round"
}
+ } else {
+ return "Must follow suit"
}
}
- return false
+ return "Invalid play"
}
// Returns true if all players have their initial dealt hands
diff --git a/go/src/hearts/main.go b/go/src/hearts/main.go
index c4c8756..a8da7ff 100644
--- a/go/src/hearts/main.go
+++ b/go/src/hearts/main.go
@@ -7,6 +7,7 @@
package main
import (
+ "flag"
"time"
"v.io/v23"
@@ -14,6 +15,7 @@
"v.io/v23/security"
"v.io/v23/security/access"
"v.io/v23/syncbase"
+ "v.io/x/lib/vlog"
"v.io/x/ref/lib/signals"
"hearts/img/resize"
@@ -78,6 +80,9 @@
}
func onStart(glctx gl.Context, u *uistate.UIState) {
+ vlog.Log.Configure(vlog.OverridePriorConfiguration(true), vlog.LogToStderr(true))
+ vlog.Log.Configure(vlog.OverridePriorConfiguration(true), vlog.Level(0))
+
sgName := "users/emshack@google.com/croupier/syncbase/%%sync/croupiersync"
contextChan := make(chan *context.T)
serviceChan := make(chan syncbase.Service)
@@ -123,6 +128,7 @@
}
func makeServerClient(contextChan chan *context.T, serviceChan chan syncbase.Service) {
+ flag.Set("v23.credentials", "/sdcard/credentials")
context, shutdown := v23.Init()
contextChan <- context
serviceChan <- client.GetService()
diff --git a/go/src/hearts/syncbase/watch/watch.go b/go/src/hearts/syncbase/watch/watch.go
index c1e99ff..df303ce 100644
--- a/go/src/hearts/syncbase/watch/watch.go
+++ b/go/src/hearts/syncbase/watch/watch.go
@@ -94,7 +94,7 @@
} else if u.CurView == uistate.Take && u.CurPlayerIndex == receivingPlayer {
view.LoadTakeView(u)
} else if u.CurView == uistate.Play && u.CurTable.AllDonePassing() {
- view.LoadPlayView(u)
+ view.LoadPlayView("", u)
}
}
@@ -114,7 +114,7 @@
u.CurTable.SetFirstPlayer(p.GetPlayerIndex())
// UI
if u.CurView == uistate.Play && u.CurPlayerIndex != playerInt {
- view.LoadPlayView(u)
+ view.LoadPlayView("", u)
}
}
// UI
@@ -175,7 +175,7 @@
if roundOver {
view.LoadScoreView(roundScores, winners, u)
} else if u.CurPlayerIndex != playerInt {
- view.LoadPlayView(u)
+ view.LoadPlayView("", u)
}
}
// logic
diff --git a/go/src/hearts/touchhandler/touchhandler.go b/go/src/hearts/touchhandler/touchhandler.go
index 5edd64b..768b5c6 100644
--- a/go/src/hearts/touchhandler/touchhandler.go
+++ b/go/src/hearts/touchhandler/touchhandler.go
@@ -246,7 +246,7 @@
if !success {
fmt.Println("Invalid take")
} else {
- view.LoadPlayView(u)
+ view.LoadPlayView("", u)
}
}()
}
@@ -287,13 +287,12 @@
} else {
ch := make(chan bool)
err := playCard(ch, u.CurPlayerIndex, u)
+ if err != "" {
+ view.LoadPlayView(err, u)
+ }
go func() {
<-ch
- if err != "" {
- fmt.Println(err)
- } else {
- view.LoadPlayView(u)
- }
+ view.LoadPlayView("", u)
}()
}
}
@@ -391,16 +390,16 @@
// -the play is in the right order
// -the play is valid given game logic
if u.CurTable.GetPlayers()[playerId].GetDonePlaying() {
- return "Invalid play: The current player has already played a card in this trick"
+ return "You have already played a card in this trick"
}
if !u.CurTable.AllDonePassing() {
- return "Invalid play: Not all players have passed their cards"
+ return "Not all players have passed their cards"
}
if !u.CurTable.ValidPlayOrder(playerId) {
- return "Invalid play: It is not the current player's turn"
+ return "It is not your turn"
}
- if !u.CurTable.ValidPlayLogic(c, playerId) {
- return "Invalid play: This card does not follow game logic"
+ if err := u.CurTable.ValidPlayLogic(c, playerId); err != "" {
+ return err
}
u.DropTargets[0].SetCardHere(nil)
success := gamelog.LogPlay(u, c)
@@ -410,7 +409,7 @@
reposition.AnimateHandCardPlay(ch, c, u)
return ""
}
- return "Invalid play: No card has been played"
+ return "No card has been played"
}
func pressButton(b *staticimg.StaticImg, u *uistate.UIState) {