Improve card selection
This commit is contained in:
parent
a3f41edc26
commit
fe5fbfc818
|
@ -2,7 +2,7 @@
|
|||
[![CI status](https://gitlab.com/tslocum/crib/badges/master/pipeline.svg)](https://gitlab.com/tslocum/crib/commits/master)
|
||||
[![Donate](https://img.shields.io/liberapay/receives/rocketnine.space.svg?logo=liberapay)](https://liberapay.com/rocketnine.space)
|
||||
|
||||
[**Cribbage.World**](https://cribbage.world) terminal client
|
||||
[**Cribbage.World**](https://cribbage.world) terminal-based client
|
||||
|
||||
## Demo
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"math"
|
||||
"sync"
|
||||
|
||||
"github.com/gdamore/tcell"
|
||||
|
@ -17,10 +18,11 @@ const (
|
|||
type cardStackWidget struct {
|
||||
*cview.Box
|
||||
|
||||
Cards []*cardWidget
|
||||
maxSelection int // TODO != 0 unnecessary?
|
||||
|
||||
Cards []*cardWidget
|
||||
EverSelectable bool
|
||||
Text string
|
||||
|
||||
maxSelection int // TODO != 0 unnecessary?
|
||||
|
||||
sync.RWMutex
|
||||
}
|
||||
|
@ -58,7 +60,7 @@ func (c *cardStackWidget) SetCards(cards joker.Cards) {
|
|||
|
||||
c.Cards = make([]*cardWidget, len(cards))
|
||||
for i := 0; i < len(cards); i++ {
|
||||
c.Cards[i] = NewCardWidget(cards[i])
|
||||
c.Cards[i] = NewCardWidget(cards[i], selectCard)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -76,7 +78,6 @@ func (c *cardStackWidget) Draw(screen tcell.Screen) {
|
|||
}
|
||||
|
||||
stackX, stackY, _, _ := c.GetInnerRect()
|
||||
//log.Fatal(stackX)
|
||||
for i, cardWidget := range c.Cards {
|
||||
lastOffsetY = cardOffsetY
|
||||
|
||||
|
@ -122,6 +123,11 @@ func (c *cardStackWidget) Draw(screen tcell.Screen) {
|
|||
screen.SetContent(stackX+(i*cardBufferX)+2, stackY+cardOffsetY, tcell.RuneBTee, nil, tcell.StyleDefault)
|
||||
}
|
||||
}
|
||||
|
||||
if c.Text != "" && len(c.Cards) > 0 {
|
||||
cview.Print(screen, c.Text, (stackX+((len(c.Cards)-1)*cardBufferX))+(cardWidth/2), stackY, math.MaxInt64, cview.AlignLeft, tcell.ColorDefault)
|
||||
cview.Print(screen, c.Text, (stackX+((len(c.Cards)-1)*cardBufferX))+(cardWidth/2), (stackY+cardHeight)-1, math.MaxInt64, cview.AlignLeft, tcell.ColorDefault)
|
||||
}
|
||||
}
|
||||
|
||||
// MouseHandler returns the mouse handler for this primitive.
|
||||
|
|
|
@ -11,17 +11,29 @@ import (
|
|||
|
||||
type cardWidget struct {
|
||||
*cview.Box
|
||||
|
||||
joker.Card
|
||||
selected bool
|
||||
selected bool
|
||||
selectedFunc func(joker.Card)
|
||||
}
|
||||
|
||||
func NewCardWidget(card joker.Card) *cardWidget {
|
||||
c := cardWidget{Box: cview.NewBox().ShowFocus(false), Card: card}
|
||||
func NewCardWidget(card joker.Card, selectedFunc func(joker.Card)) *cardWidget {
|
||||
c := cardWidget{Box: cview.NewBox().ShowFocus(false), Card: card, selectedFunc: selectedFunc}
|
||||
|
||||
c.Box.SetBorder(true)
|
||||
return &c
|
||||
}
|
||||
|
||||
func (c *cardWidget) Select() {
|
||||
c.selected = !c.selected
|
||||
|
||||
if c.selectedFunc != nil {
|
||||
c.selectedFunc(c.Card)
|
||||
}
|
||||
|
||||
app.Draw()
|
||||
}
|
||||
|
||||
func (c *cardWidget) Draw(screen tcell.Screen) {
|
||||
c.Box.Draw(screen)
|
||||
|
||||
|
@ -118,12 +130,8 @@ func (c *cardWidget) MouseHandler() func(action cview.MouseAction, event *tcell.
|
|||
|
||||
// Process mouse event.
|
||||
if action == cview.MouseLeftClick {
|
||||
setFocus(c)
|
||||
consumed = true
|
||||
|
||||
c.selected = !c.selected
|
||||
|
||||
app.Draw()
|
||||
c.Select()
|
||||
}
|
||||
|
||||
return
|
||||
|
|
5
go.mod
5
go.mod
|
@ -1,6 +1,6 @@
|
|||
module gitlab.com/tslocum/crib
|
||||
|
||||
go 1.14
|
||||
go 1.15
|
||||
|
||||
require (
|
||||
github.com/gdamore/tcell v1.3.1-0.20200608133353-cb1e5d6fa606
|
||||
|
@ -8,5 +8,6 @@ require (
|
|||
gitlab.com/tslocum/cbind v0.1.1
|
||||
gitlab.com/tslocum/cview v1.4.8
|
||||
gitlab.com/tslocum/joker v0.1.3
|
||||
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed // indirect
|
||||
gitlab.com/tslocum/joker-cribbage v0.1.1
|
||||
golang.org/x/sys v0.0.0-20200819171115-d785dc25833f // indirect
|
||||
)
|
||||
|
|
9
go.sum
9
go.sum
|
@ -21,15 +21,18 @@ gitlab.com/tslocum/cbind v0.1.1 h1:JXXtxMWHgWLvoF+QkrvcNvOQ59juy7OE1RhT7hZfdt0=
|
|||
gitlab.com/tslocum/cbind v0.1.1/go.mod h1:rX7vkl0pUSg/yy427MmD1FZAf99S7WwpUlxF/qTpPqk=
|
||||
gitlab.com/tslocum/cview v1.4.8 h1:xYUO+4QUGDbrqIhgqUqXWzCXB1kZDNpmoOR2MwkxNb0=
|
||||
gitlab.com/tslocum/cview v1.4.8/go.mod h1:mSTNW1JUAfb9QlCB9GSaqy97Z3reIAJyUSbFSQcF8GE=
|
||||
gitlab.com/tslocum/joker v0.1.2-0.20200123002530-2570d6c23aff/go.mod h1:bxTQ0FFmBP465r9z76zcm97S4Ld9eCLa3q20TyVM82A=
|
||||
gitlab.com/tslocum/joker v0.1.3 h1:6AVQuc0Rt7LczppZKaAXfr5B5Yg/4sQky2SFaWaF9E4=
|
||||
gitlab.com/tslocum/joker v0.1.3/go.mod h1:bxTQ0FFmBP465r9z76zcm97S4Ld9eCLa3q20TyVM82A=
|
||||
gitlab.com/tslocum/joker-cribbage v0.1.1 h1:oiCKebyppYsl4x1ZJNHQZcSCcHSBHUCMqSFTGDGv1fY=
|
||||
gitlab.com/tslocum/joker-cribbage v0.1.1/go.mod h1:KyNZDgGv6fFmYGpHD9txZCBFuVDgKwCq4mJ4ZAgQ0hw=
|
||||
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed h1:WBkVNH1zd9jg/dK4HCM4lNANnmd12EHC9z+LmcCG4ns=
|
||||
golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed h1:J22ig1FUekjjkmZUM7pTKixYm8DvrYsvrBZdunYeIuQ=
|
||||
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200819171115-d785dc25833f h1:KJuwZVtZBVzDmEDtB2zro9CXkD9O0dpCv4o2LHbQIAw=
|
||||
golang.org/x/sys v0.0.0-20200819171115-d785dc25833f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
|
|
123
main.go
123
main.go
|
@ -5,6 +5,7 @@ import (
|
|||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/gdamore/tcell"
|
||||
|
@ -12,6 +13,7 @@ import (
|
|||
"gitlab.com/tslocum/cbind"
|
||||
"gitlab.com/tslocum/cview"
|
||||
"gitlab.com/tslocum/joker"
|
||||
cribbage "gitlab.com/tslocum/joker-cribbage"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -104,8 +106,6 @@ func connect(address string) {
|
|||
currentGameState = gameState
|
||||
|
||||
if gameState.Player > 0 {
|
||||
setStatusText(currentGameState.Status)
|
||||
|
||||
playerHand := gameState.Hand1
|
||||
oppHand := gameState.Hand2
|
||||
if gameState.Player == 2 {
|
||||
|
@ -120,31 +120,72 @@ func connect(address string) {
|
|||
oppCrib = gameState.Crib
|
||||
}
|
||||
|
||||
if currentGameState.Status == "" {
|
||||
if currentGameState.Phase == PhasePick {
|
||||
if len(playerHand) > 4 {
|
||||
if gameState.Dealer == gameState.Player {
|
||||
currentGameState.Status = "Throw for your crib"
|
||||
} else {
|
||||
currentGameState.Status = "Throw for your opponent's crib"
|
||||
}
|
||||
} else {
|
||||
currentGameState.Status = "Waiting..."
|
||||
}
|
||||
} else if currentGameState.Phase == PhasePeg && currentGameState.Turn != currentGameState.Player {
|
||||
currentGameState.Status = "Waiting..."
|
||||
}
|
||||
}
|
||||
setStatusText(currentGameState.Status)
|
||||
|
||||
starterWidget.Card = currentGameState.Starter
|
||||
|
||||
if currentGameState.Phase == PhasePick {
|
||||
mainHandStack.SetMaxSelection(2)
|
||||
} else if currentGameState.Phase == PhasePeg && currentGameState.Turn == currentGameState.Player {
|
||||
mainHandStack.SetMaxSelection(1)
|
||||
var canPeg bool
|
||||
for i := range playerHand {
|
||||
if cribbage.Sum(currentGameState.ThrowPile.Cards())+cribbage.Value(playerHand[i]) <= 31 {
|
||||
canPeg = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if canPeg {
|
||||
mainHandStack.SetMaxSelection(1)
|
||||
} else {
|
||||
mainHandStack.SetMaxSelection(-1)
|
||||
}
|
||||
} else {
|
||||
mainHandStack.SetMaxSelection(-1)
|
||||
}
|
||||
|
||||
if currentGameState.Phase == PhasePick {
|
||||
if gameState.Dealer == gameState.Player {
|
||||
throwStack.SetCards(oppCrib)
|
||||
} else {
|
||||
mainCribStack.SetCards(playerCrib)
|
||||
oppCribStack.SetCards(joker.Cards{})
|
||||
} else {
|
||||
oppCribStack.SetCards(oppCrib)
|
||||
mainCribStack.SetCards(joker.Cards{})
|
||||
}
|
||||
mainHandStack.SetCards(playerHand)
|
||||
throwStack.SetCards(joker.Cards{})
|
||||
} else if currentGameState.Phase == PhaseScore {
|
||||
mainHandStack.SetCards(playerHand)
|
||||
mainCribStack.SetCards(playerCrib)
|
||||
throwStack.SetCards(oppHand)
|
||||
oppCribStack.SetCards(oppCrib)
|
||||
} else {
|
||||
} else { // Peg
|
||||
throwStack.SetCards(currentGameState.ThrowPile.Cards())
|
||||
mainHandStack.SetCards(playerHand)
|
||||
|
||||
mainCribStack.SetCards(playerCrib)
|
||||
oppCribStack.SetCards(joker.Cards{})
|
||||
|
||||
var throwValue int
|
||||
for i := range currentGameState.ThrowPile {
|
||||
throwValue += cribbage.Value(currentGameState.ThrowPile[i].Card)
|
||||
}
|
||||
throwStack.Text = strconv.Itoa(throwValue)
|
||||
}
|
||||
} else {
|
||||
setStatusText("Waiting for opponent...")
|
||||
|
@ -155,6 +196,8 @@ func connect(address string) {
|
|||
lastPhase = currentGameState.Phase
|
||||
}
|
||||
|
||||
updateGameText()
|
||||
|
||||
statusBuf.Write([]byte(fmt.Sprintf("decode: %+v\n", gameState)))
|
||||
|
||||
app.Draw()
|
||||
|
@ -180,31 +223,50 @@ func connect(address string) {
|
|||
}
|
||||
|
||||
func setupThrowGrid() {
|
||||
grid := cview.NewGrid()
|
||||
if throwGrid == nil {
|
||||
throwGrid = cview.NewGrid()
|
||||
}
|
||||
|
||||
throwGrid.Clear()
|
||||
|
||||
if currentGameState.Phase == PhasePeg {
|
||||
grid.AddItem(throwStack, 0, 0, 1, 1, 0, 0, false)
|
||||
throwGrid.SetColumns(-1)
|
||||
throwGrid.AddItem(throwStack, 0, 0, 1, 1, 0, 0, false)
|
||||
} else {
|
||||
grid.SetColumns((cardBufferX * 5) + cardWidth)
|
||||
throwGrid.SetColumns((cardBufferX * 5) + cardWidth)
|
||||
|
||||
grid.AddItem(throwStack, 0, 0, 1, 1, 0, 0, false)
|
||||
grid.AddItem(oppCribStack, 0, 1, 1, 1, 0, 0, false)
|
||||
throwGrid.AddItem(throwStack, 0, 0, 1, 1, 0, 0, false)
|
||||
throwGrid.AddItem(oppCribStack, 0, 1, 1, 1, 0, 0, false)
|
||||
}
|
||||
throwGrid = grid
|
||||
}
|
||||
|
||||
// Starts at 1
|
||||
func selectCard(cardNumber int) {
|
||||
func selectCardIndex(cardNumber int) {
|
||||
if cardNumber <= 0 || cardNumber > len(mainHandStack.Cards) {
|
||||
return
|
||||
}
|
||||
|
||||
if !mainHandStack.Cards[cardNumber-1].selected {
|
||||
var selected int
|
||||
for _, card := range mainHandStack.Cards {
|
||||
if card.selected {
|
||||
selected++
|
||||
}
|
||||
}
|
||||
if selected >= mainHandStack.GetMaxSelection() {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
mainHandStack.Cards[cardNumber-1].Select()
|
||||
return // TODO
|
||||
|
||||
if mainHandStack.GetMaxSelection() == 1 {
|
||||
for i, card := range mainHandStack.Cards {
|
||||
card.selected = false
|
||||
|
||||
if i == cardNumber-1 {
|
||||
if i == cardNumber-1 && !card.selected {
|
||||
card.selected = true
|
||||
} else {
|
||||
card.selected = false
|
||||
}
|
||||
}
|
||||
return
|
||||
|
@ -225,6 +287,16 @@ func selectCard(cardNumber int) {
|
|||
mainHandStack.Cards[cardNumber-1].selected = !mainHandStack.Cards[cardNumber-1].selected
|
||||
}
|
||||
|
||||
func selectCard(card joker.Card) {
|
||||
if currentGameState.Phase == PhasePeg && currentGameState.Turn == currentGameState.Player {
|
||||
if cribbage.Sum(currentGameState.ThrowPile.Cards())+cribbage.Value(card) > 31 {
|
||||
setStatusText("Can not throw card: illegal move")
|
||||
} else {
|
||||
writeBuffer <- fmt.Sprintf("throw %s", card.Identifier())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func doAction() {
|
||||
var cards joker.Cards
|
||||
for _, card := range mainHandStack.Cards {
|
||||
|
@ -233,7 +305,10 @@ func doAction() {
|
|||
}
|
||||
}
|
||||
|
||||
if len(cards) > 0 {
|
||||
if len(cards) == 1 {
|
||||
selectCard(cards[0])
|
||||
return
|
||||
} else if len(cards) > 1 {
|
||||
for _, card := range cards {
|
||||
writeBuffer <- fmt.Sprintf("throw %s", card.Identifier())
|
||||
}
|
||||
|
@ -247,6 +322,10 @@ func setStatusText(status string) {
|
|||
statusText.SetText(" " + status)
|
||||
}
|
||||
|
||||
func updateGameText() {
|
||||
gameText.SetText(fmt.Sprintf("[%d - %d]", currentGameState.Score1, currentGameState.Score2))
|
||||
}
|
||||
|
||||
func main() {
|
||||
var connectAddress string
|
||||
flag.StringVar(&connectAddress, "server", "wss://play.cribbage.world/crib", "Server address")
|
||||
|
@ -269,7 +348,7 @@ func main() {
|
|||
for i := 1; i <= 6; i++ {
|
||||
i := i // Capture
|
||||
inputConfig.SetRune(tcell.ModNone, '0'+rune(i), func(ev *tcell.EventKey) *tcell.EventKey {
|
||||
selectCard(i)
|
||||
selectCardIndex(i)
|
||||
app.Draw()
|
||||
return nil
|
||||
})
|
||||
|
@ -281,7 +360,7 @@ func main() {
|
|||
return false
|
||||
})
|
||||
|
||||
starterWidget = NewCardWidget(joker.Card{})
|
||||
starterWidget = NewCardWidget(joker.Card{}, nil)
|
||||
mainHandStack = NewCardStackWidget()
|
||||
mainCribStack = NewCardStackWidget()
|
||||
throwStack = NewCardStackWidget()
|
||||
|
@ -300,18 +379,20 @@ func main() {
|
|||
SetRows(cardHeight, 1, cardHeight+1, -1)
|
||||
|
||||
gameText = cview.NewTextView().SetText("[0 - 0]")
|
||||
gameText.SetTextAlign(cview.AlignCenter)
|
||||
statusButton = cview.NewButton("Continue").SetSelectedFunc(doAction)
|
||||
|
||||
statusGrid = cview.NewGrid().
|
||||
SetColumns(1, -1, 1).
|
||||
SetRows(1, 3, 1, -1)
|
||||
statusGrid.AddItem(cview.NewTextView(), 0, 0, 3, 1, 0, 0, false)
|
||||
statusGrid.AddItem(cview.NewTextView(), 0, 1, 1, 2, 0, 0, false)
|
||||
statusGrid.AddItem(cview.NewTextView(), 1, 0, 1, 1, 0, 0, false)
|
||||
statusGrid.AddItem(statusButton, 1, 1, 1, 1, 0, 0, false)
|
||||
statusGrid.AddItem(cview.NewTextView(), 1, 2, 1, 1, 0, 0, false)
|
||||
statusGrid.AddItem(cview.NewTextView(), 2, 1, 1, 1, 0, 0, false)
|
||||
statusGrid.AddItem(cview.NewTextView(), 2, 1, 1, 2, 0, 0, false)
|
||||
statusGrid.AddItem(gameText, 3, 1, 1, 1, 0, 0, false)
|
||||
statusGrid.AddItem(cview.NewTextView(), 0, 0, 3, 1, 0, 0, false)
|
||||
statusGrid.AddItem(cview.NewTextView(), 3, 2, 1, 1, 0, 0, false)
|
||||
|
||||
statusText = cview.NewTextView()
|
||||
|
||||
|
|
Loading…
Reference in New Issue