Merge "Implemented soft reset functionality to debug mode. Hard reset to follow."
diff --git a/go/src/hearts/img/uistate/uistate.go b/go/src/hearts/img/uistate/uistate.go
index 74ccb18..53f7fd3 100644
--- a/go/src/hearts/img/uistate/uistate.go
+++ b/go/src/hearts/img/uistate/uistate.go
@@ -109,6 +109,7 @@
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
+ GameChan chan bool // pass in a bool to stop receiving updates from the current game
DiscGroups map[string]*DiscStruct // contains a set of addresses and game start data for each advertised game found
M sync.Mutex
}
diff --git a/go/src/hearts/img/view/view.go b/go/src/hearts/img/view/view.go
index 9169a6b..5600864 100644
--- a/go/src/hearts/img/view/view.go
+++ b/go/src/hearts/img/view/view.go
@@ -1289,6 +1289,9 @@
debugPassImage := u.Texs["Clubs-2.png"]
debugPassPos := coords.MakeVec(u.WindowSize.X-2*buttonDim.X, u.WindowSize.Y-buttonDim.Y)
u.Buttons["hand"] = texture.MakeImgWithoutAlt(debugPassImage, debugPassPos, buttonDim, u)
+ debugRestartImage := u.Texs["Restart.png"]
+ debugRestartPos := coords.MakeVec(u.WindowSize.X-3*buttonDim.X, u.WindowSize.Y-buttonDim.Y)
+ u.Buttons["restart"] = texture.MakeImgWithoutAlt(debugRestartImage, debugRestartPos, buttonDim, u)
}
// Helper function that returns the largest int in a non-negative int array (not index of largest int)
diff --git a/go/src/hearts/logic/table/table.go b/go/src/hearts/logic/table/table.go
index 4eece8a..a8a8d6b 100644
--- a/go/src/hearts/logic/table/table.go
+++ b/go/src/hearts/logic/table/table.go
@@ -37,7 +37,7 @@
heartsBroken: false,
firstTrick: true,
winCondition: 100,
- dir: direction.None,
+ dir: direction.Right,
}
}
@@ -395,6 +395,7 @@
p.ResetTricks()
p.ResetScore()
}
+ t.trick = make([]*card.Card, len(t.players))
t.NewRound()
t.dir = direction.Right
}
diff --git a/go/src/hearts/sync/client.go b/go/src/hearts/sync/client.go
index 63d6442..c7f4194 100644
--- a/go/src/hearts/sync/client.go
+++ b/go/src/hearts/sync/client.go
@@ -109,7 +109,7 @@
} else {
fmt.Println("Syncgroup joined")
if u.LogSG != logName {
- resetGame(logName, false, u)
+ ResetGame(logName, false, u)
}
return true
}
diff --git a/go/src/hearts/sync/server.go b/go/src/hearts/sync/server.go
index 38ed5f4..68b1147 100644
--- a/go/src/hearts/sync/server.go
+++ b/go/src/hearts/sync/server.go
@@ -169,7 +169,7 @@
} else {
fmt.Println("Syncgroup created")
if logSGName != u.LogSG {
- resetGame(logSGName, true, u)
+ ResetGame(logSGName, true, u)
}
return string(value), logSGName
}
@@ -218,14 +218,25 @@
}
}
-func resetGame(logName string, creator bool, u *uistate.UIState) {
+func ResetGame(logName string, creator bool, u *uistate.UIState) {
+ u.M.Lock()
+ defer u.M.Unlock()
+ go sendTrueIfExists(u.GameChan)
u.PlayerData = make(map[int]int)
u.CurPlayerIndex = -1
u.LogSG = logName
+ u.CurTable.NewGame()
if !creator {
tmp := strings.Split(logName, "-")
gameID, _ := strconv.Atoi(tmp[len(tmp)-1])
u.GameID = gameID
}
- go UpdateGame(u)
+ u.GameChan = make(chan bool)
+ go UpdateGame(u.GameChan, u)
+}
+
+func sendTrueIfExists(ch chan bool) {
+ if ch != nil {
+ ch <- true
+ }
}
diff --git a/go/src/hearts/sync/watch.go b/go/src/hearts/sync/watch.go
index a52b82d..877fce5 100644
--- a/go/src/hearts/sync/watch.go
+++ b/go/src/hearts/sync/watch.go
@@ -80,18 +80,43 @@
}
}
-func UpdateGame(u *uistate.UIState) {
- stream, err := WatchData(LogName, fmt.Sprintf("%d", u.GameID), u)
- fmt.Println("STARTING WATCH FOR GAME", u.GameID)
+func UpdateGame(quit chan bool, u *uistate.UIState) {
+ file, err := os.OpenFile("/sdcard/test.txt", os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666)
if err != nil {
- fmt.Println("WatchData error:", err)
- }
- file, err2 := os.OpenFile("/sdcard/test.txt", os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666)
- if err2 != nil {
- fmt.Println("err2:", err2)
+ fmt.Println("err:", err)
}
fmt.Fprintf(file, fmt.Sprintf("\n***NEW GAME: %d\n", u.GameID))
defer file.Close()
+ scanner := ScanData(LogName, fmt.Sprintf("%d", u.GameID), u)
+ m := make(map[string][]byte)
+ keys := make([]string, 0)
+ for scanner.Advance() {
+ k := scanner.Key()
+ var v []byte
+ if err := scanner.Value(&v); err != nil {
+ fmt.Println("Value error:", err)
+ }
+ id := strings.Split(k, "/")[0]
+ if id == fmt.Sprintf("%d", u.GameID) {
+ m[k] = v
+ keys = append(keys, k)
+ }
+ }
+ sort.Sort(scanSorter(keys))
+ for _, key := range keys {
+ select {
+ case <-quit:
+ return
+ default:
+ value := m[key]
+ handleGameUpdate(file, key, value, u)
+ }
+ }
+ stream, err2 := WatchData(LogName, fmt.Sprintf("%d", u.GameID), u)
+ fmt.Println("STARTING WATCH FOR GAME", u.GameID)
+ if err2 != nil {
+ fmt.Println("WatchData error:", err2)
+ }
updateBlock := make([]nosql.WatchChange, 0)
for {
if updateExists := stream.Advance(); updateExists {
@@ -99,63 +124,67 @@
updateBlock = append(updateBlock, c)
if !c.Continued {
sort.Sort(updateSorter(updateBlock))
- handleGameUpdate(file, updateBlock, u)
+ for _, c := range updateBlock {
+ select {
+ case <-quit:
+ return
+ default:
+ if c.ChangeType == nosql.PutChange {
+ key := c.Row
+ var value []byte
+ if err := c.Value(&value); err != nil {
+ fmt.Println("Value error:", err)
+ }
+ handleGameUpdate(file, key, value, u)
+ } else {
+ fmt.Println("Unexpected ChangeType: ", c.ChangeType)
+ }
+ }
+ }
updateBlock = make([]nosql.WatchChange, 0)
}
}
}
}
-func handleGameUpdate(file *os.File, changes []nosql.WatchChange, u *uistate.UIState) {
- for _, c := range changes {
- if c.ChangeType == nosql.PutChange {
- key := c.Row
- curTime := time.Now().UnixNano() / 1000000
- var value []byte
- if err := c.Value(&value); err != nil {
- fmt.Println("Value error:", err)
- }
- valueStr := string(value)
- fmt.Fprintf(file, fmt.Sprintf("key: %s\n", key))
- fmt.Fprintf(file, fmt.Sprintf("value: %s\n", valueStr))
- fmt.Fprintf(file, fmt.Sprintf("time: %v\n", curTime))
- tmp := strings.Split(key, "/")
- if len(tmp) == 3 {
- keyTime, _ := strconv.ParseInt(strings.Split(tmp[2], "-")[0], 10, 64)
- fmt.Fprintf(file, fmt.Sprintf("diff: %d milliseconds\n\n", curTime-keyTime))
- } else {
- fmt.Fprintf(file, "\n")
- }
- fmt.Println(key, valueStr)
- keyType := strings.Split(key, "/")[1]
- switch keyType {
- case "log":
- updateType := strings.Split(valueStr, "|")[0]
- switch updateType {
- case Deal:
- onDeal(valueStr, u)
- case Pass:
- onPass(valueStr, u)
- case Take:
- onTake(valueStr, u)
- case Play:
- onPlay(valueStr, u)
- case TakeTrick:
- onTakeTrick(valueStr, u)
- case Ready:
- onReady(valueStr, u)
- }
- case "players":
- switch strings.Split(key, "/")[3] {
- case "player_number":
- onPlayerNum(key, valueStr, u)
- case "settings_sg":
- onSettings(key, valueStr, u)
- }
-
- }
- } else {
- fmt.Println("Unexpected ChangeType: ", c.ChangeType)
+func handleGameUpdate(file *os.File, key string, value []byte, u *uistate.UIState) {
+ curTime := time.Now().UnixNano() / 1000000
+ valueStr := string(value)
+ fmt.Fprintf(file, fmt.Sprintf("key: %s\n", key))
+ fmt.Fprintf(file, fmt.Sprintf("value: %s\n", valueStr))
+ fmt.Fprintf(file, fmt.Sprintf("time: %v\n", curTime))
+ tmp := strings.Split(key, "/")
+ if len(tmp) == 3 {
+ keyTime, _ := strconv.ParseInt(strings.Split(tmp[2], "-")[0], 10, 64)
+ fmt.Fprintf(file, fmt.Sprintf("diff: %d milliseconds\n\n", curTime-keyTime))
+ } else {
+ fmt.Fprintf(file, "\n")
+ }
+ fmt.Println(key, valueStr)
+ keyType := strings.Split(key, "/")[1]
+ switch keyType {
+ case "log":
+ updateType := strings.Split(valueStr, "|")[0]
+ switch updateType {
+ case Deal:
+ onDeal(valueStr, u)
+ case Pass:
+ onPass(valueStr, u)
+ case Take:
+ onTake(valueStr, u)
+ case Play:
+ onPlay(valueStr, u)
+ case TakeTrick:
+ onTakeTrick(valueStr, u)
+ case Ready:
+ onReady(valueStr, u)
+ }
+ case "players":
+ switch strings.Split(key, "/")[3] {
+ case "player_number":
+ onPlayerNum(key, valueStr, u)
+ case "settings_sg":
+ onSettings(key, valueStr, u)
}
}
}
@@ -474,6 +503,24 @@
return iKey < jKey
}
+type scanSorter []string
+
+func (ss scanSorter) Len() int {
+ return len(ss)
+}
+
+// Swaps the positions of two changes in the array
+func (ss scanSorter) Swap(i, j int) {
+ ss[i], ss[j] = ss[j], ss[i]
+}
+
+// Compares two changes-- one card is less than another if it has an earlier timestamp
+func (ss scanSorter) Less(i, j int) bool {
+ iKey := ss[i]
+ jKey := ss[j]
+ return iKey < jKey
+}
+
func PlayCard(ch chan bool, playerId int, u *uistate.UIState) string {
c := u.DropTargets[0].GetCardHere()
if c == nil {
diff --git a/go/src/hearts/touchhandler/touchhandler.go b/go/src/hearts/touchhandler/touchhandler.go
index 32db10b..a76f12d 100644
--- a/go/src/hearts/touchhandler/touchhandler.go
+++ b/go/src/hearts/touchhandler/touchhandler.go
@@ -290,6 +290,8 @@
view.LoadTableView(u)
} else if b == u.Buttons["hand"] {
view.LoadPassOrTakeOrPlay(u)
+ } else if b == u.Buttons["restart"] {
+ sync.ResetGame(u.LogSG, u.IsOwner, u)
} else if b == u.Buttons["pass"] {
pressButton(b, u)
}
@@ -376,6 +378,8 @@
view.LoadTableView(u)
} else if b == u.Buttons["hand"] {
view.LoadPassOrTakeOrPlay(u)
+ } else if b == u.Buttons["restart"] {
+ sync.ResetGame(u.LogSG, u.IsOwner, u)
} else if b == u.Buttons["take"] {
pressButton(b, u)
}
@@ -440,6 +444,8 @@
view.LoadTableView(u)
} else if b == u.Buttons["hand"] {
view.LoadPassOrTakeOrPlay(u)
+ } else if b == u.Buttons["restart"] {
+ sync.ResetGame(u.LogSG, u.IsOwner, u)
} else if b == u.Buttons["takeTrick"] {
pressButton(b, u)
}
@@ -550,6 +556,8 @@
view.LoadTableView(u)
} else if b == u.Buttons["hand"] {
view.LoadPassOrTakeOrPlay(u)
+ } else if b == u.Buttons["restart"] {
+ sync.ResetGame(u.LogSG, u.IsOwner, u)
}
}
}
@@ -721,7 +729,7 @@
func unpressButtons(u *uistate.UIState) []*staticimg.StaticImg {
pressed := make([]*staticimg.StaticImg, 0)
for _, b := range u.Buttons {
- if b.GetDisplayingImage() == false {
+ if b != nil && b.GetDisplayingImage() == false {
u.Eng.SetSubTex(b.GetNode(), b.GetImage())
b.SetDisplayingImage(true)
pressed = append(pressed, b)
@@ -811,5 +819,7 @@
view.LoadTableView(u)
} else if b == u.Buttons["hand"] {
view.LoadPassOrTakeOrPlay(u)
+ } else if b == u.Buttons["restart"] {
+ sync.ResetGame(u.LogSG, u.IsOwner, u)
}
}