From a7d3ab34380ed419f4dc7fc8f66ea6b56833065f Mon Sep 17 00:00:00 2001 From: Mariano Gappa Date: Tue, 25 Jun 2024 22:13:46 +0100 Subject: [PATCH] Calculate all actions, not just one per type. --- exampleclient/ui.go | 80 ++++++++++--------------------------- truco/action_reveal_card.go | 11 ----- truco/actions.go | 15 +++++-- truco/truco.go | 60 ++++++++++++++++++---------- 4 files changed, 72 insertions(+), 94 deletions(-) diff --git a/exampleclient/ui.go b/exampleclient/ui.go index 0cc8918..b9d2ed9 100644 --- a/exampleclient/ui.go +++ b/exampleclient/ui.go @@ -35,8 +35,7 @@ func (u *ui) Close() { } func (u *ui) play(playerID int, gameState truco.GameState) (truco.Action, error) { - err := u.render(playerID, gameState, PRINT_MODE_NORMAL) - if err != nil { + if err := u.render(playerID, gameState, PRINT_MODE_NORMAL); err != nil { return nil, err } @@ -45,65 +44,24 @@ func (u *ui) play(playerID int, gameState truco.GameState) (truco.Action, error) } var ( - action truco.Action - input string + action truco.Action + possibleActions = _deserializeActions(gameState.PossibleActions) ) for { num := u.pressAnyNumber() - var actionName string - var err error - actionName, input, err = numToAction(num, gameState) - if err != nil { - continue - } - if actionName == truco.SAY_ENVIDO_QUIERO || actionName == truco.SAY_SON_BUENAS || actionName == truco.SAY_SON_MEJORES { - input = fmt.Sprintf(`{"name":"%v","score":%d}`, actionName, gameState.Hands[gameState.TurnPlayerID].EnvidoScore()) - } - if actionName == "reveal_card" { - err := u.render(playerID, gameState, PRINT_MODE_WHICH_CARD_REVEAL) - if err != nil { - return nil, err - } - var card truco.Card - for { - which := u.pressAnyNumber() - if which > len(gameState.Hands[gameState.TurnPlayerID].Unrevealed) { - continue - } - if which == 0 { - return u.play(playerID, gameState) - } - card = gameState.Hands[gameState.TurnPlayerID].Unrevealed[which-1] - break - } - jsonCard, _ := json.Marshal(card) - input = fmt.Sprintf(`{"name":"reveal_card","card":%v}`, string(jsonCard)) - } - - action, err = truco.DeserializeAction([]byte(input)) - if err != nil { - fmt.Printf("Invalid action: %v\n", err) + if num > len(possibleActions) { continue } + action = possibleActions[num-1] break } return action, nil } -func numToAction(num int, state truco.GameState) (string, string, error) { - actions := state.CalculatePossibleActions() - if num > len(actions) { - return "", "", fmt.Errorf("Invalid action") - } - - return actions[num-1], fmt.Sprintf(`{"name":"%v"}`, actions[num-1]), nil -} - type printMode int const ( PRINT_MODE_NORMAL printMode = iota - PRINT_MODE_WHICH_CARD_REVEAL PRINT_MODE_SHOW_ROUND_RESULT PRINT_MODE_END ) @@ -159,7 +117,7 @@ func (u *ui) render(playerID int, state truco.GameState, mode printMode) error { printAt(0, my-4, unrevealed) switch mode { - case PRINT_MODE_NORMAL, PRINT_MODE_WHICH_CARD_REVEAL: + case PRINT_MODE_NORMAL: lastActionString, err := getLastActionString(you, state) if err != nil { return err @@ -223,15 +181,11 @@ func (u *ui) render(playerID int, state truco.GameState, mode printMode) error { if state.TurnPlayerID == playerID { if mode == PRINT_MODE_NORMAL { actionsString := "" - for i, action := range state.PossibleActions { + for i, action := range _deserializeActions(state.PossibleActions) { action := spanishAction(action, state) actionsString += fmt.Sprintf("%d. %s ", i+1, action) } printAt(0, my-2, actionsString) - } else if mode == PRINT_MODE_WHICH_CARD_REVEAL { - printAt(0, my-2, "¿Cuál carta querés tirar?") - unrevealed = getCardsString(hand.Unrevealed, true, true) - printAt(0, my-1, unrevealed) } } else { _, my := termbox.Size() @@ -416,10 +370,11 @@ func spanishScore(score int) string { return fmt.Sprintf("%d buenas", score-14) } -func spanishAction(action string, state truco.GameState) string { - switch action { +func spanishAction(action truco.Action, state truco.GameState) string { + switch action.GetName() { case truco.REVEAL_CARD: - return "tirar carta" + _action := action.(*truco.ActionRevealCard) + return getCardString(_action.Card) case truco.SAY_ENVIDO: return "envido" case truco.SAY_REAL_ENVIDO: @@ -443,11 +398,20 @@ func spanishAction(action string, state truco.GameState) string { case truco.SAY_SON_BUENAS: return "son buenas" case truco.SAY_SON_MEJORES: - score := state.Hands[state.TurnPlayerID].EnvidoScore() - return fmt.Sprintf("%v son mejores", score) + _action := action.(*truco.ActionSaySonMejores) + return fmt.Sprintf("%v son mejores", _action.Score) case truco.SAY_ME_VOY_AL_MAZO: return "me voy al mazo" default: return "???" } } + +func _deserializeActions(as []json.RawMessage) []truco.Action { + _as := []truco.Action{} + for _, a := range as { + _a, _ := truco.DeserializeAction(a) + _as = append(_as, _a) + } + return _as +} diff --git a/truco/action_reveal_card.go b/truco/action_reveal_card.go index bceffdd..d16cd41 100644 --- a/truco/action_reveal_card.go +++ b/truco/action_reveal_card.go @@ -25,17 +25,6 @@ func (a ActionRevealCard) IsPossible(g GameState) bool { playerID: g.CurrentPlayerID(), } - // Note that CalculatePossibleActions will call this without arguments - // in this case, let's try all unrevealed cards - if a.Card == (Card{}) { - result := false - for _, card := range g.Hands[g.CurrentPlayerID()].Unrevealed { - step.card = card - result = result || g.CardRevealSequence.CanAddStep(step, g) - } - return result - } - return g.CardRevealSequence.CanAddStep(step, g) } diff --git a/truco/actions.go b/truco/actions.go index 3980d61..2aee42a 100644 --- a/truco/actions.go +++ b/truco/actions.go @@ -9,9 +9,6 @@ func (a act) GetName() string { } func (a act) YieldsTurn(g GameState) bool { - // if a.Name == SAY_ENVIDO_NO_QUIERO { - // log.Printf("Player %d started the envido sequence, player %v just said no quiero, yields should return: %v but I'm returning true\n", g.EnvidoSequence.StartingPlayerID, g.TurnPlayerID, g.TurnPlayerID != g.EnvidoSequence.StartingPlayerID) - // } return true } @@ -19,6 +16,14 @@ func newActionSayEnvido() Action { return ActionSayEnvido{act: act{Name: SAY_ENVIDO}} } +func newActionSayRealEnvido() Action { + return ActionSayRealEnvido{act: act{Name: SAY_REAL_ENVIDO}} +} + +func newActionSayFaltaEnvido() Action { + return ActionSayFaltaEnvido{act: act{Name: SAY_FALTA_ENVIDO}} +} + func newActionSayEnvidoNoQuiero() Action { return ActionSayEnvidoNoQuiero{act: act{Name: SAY_ENVIDO_NO_QUIERO}} } @@ -58,3 +63,7 @@ func newActionSaySonMejores(score int) Action { func newActionRevealCard(card Card) Action { return ActionRevealCard{act: act{Name: REVEAL_CARD}, Card: card} } + +func newActionSayMeVoyAlMazo() Action { + return ActionSayMeVoyAlMazo{act: act{Name: SAY_ME_VOY_AL_MAZO}} +} diff --git a/truco/truco.go b/truco/truco.go index 593030f..d4f04de 100644 --- a/truco/truco.go +++ b/truco/truco.go @@ -34,7 +34,7 @@ type GameState struct { // each action is run (i.e. GameState.RunAction). // The actions are strings, which are the names of the actions. In the case of REVEAL_CARD, // the card is not specified. - PossibleActions []string `json:"possibleActionTypes"` + PossibleActions []json.RawMessage `json:"possibleActions"` // EnvidoSequence is the sequence of envido actions that have been taken in the current round. // Example sequence is: [SAY_ENVIDO, SAY_REAL_ENVIDO, SAY_ENVIDO_QUIERO] @@ -171,7 +171,7 @@ func (g *GameState) startNewRound() { g.EnvidoFinished = false g.RoundFinished = false g.TrucoQuieroOwnerPlayerId = -1 - g.PossibleActions = g.CalculatePossibleActions() + g.PossibleActions = _serializeActions(g.CalculatePossibleActions()) } func (g *GameState) RunAction(action Action) error { @@ -215,7 +215,7 @@ func (g *GameState) RunAction(action Action) error { } } - g.PossibleActions = g.CalculatePossibleActions() + g.PossibleActions = _serializeActions(g.CalculatePossibleActions()) return nil } @@ -280,30 +280,38 @@ var ( errGameIsEnded = errors.New("game is ended") ) -func (g GameState) CalculatePossibleActions() []string { - allActions := []Action{ - ActionRevealCard{act: act{Name: "reveal_card"}}, - ActionSayEnvido{act: act{Name: "say_envido"}}, - ActionSayRealEnvido{act: act{Name: "say_real_envido"}}, - ActionSayFaltaEnvido{act: act{Name: "say_falta_envido"}}, - ActionSayEnvidoQuiero{act: act{Name: "say_envido_quiero"}}, - ActionSayEnvidoNoQuiero{act: act{Name: "say_envido_no_quiero"}}, - ActionSayTruco{act: act{Name: "say_truco"}}, - ActionSayTrucoQuiero{act: act{Name: "say_truco_quiero"}}, - ActionSayTrucoNoQuiero{act: act{Name: "say_truco_no_quiero"}}, - ActionSayQuieroRetruco{act: act{Name: "say_quiero_retruco"}}, - ActionSayQuieroValeCuatro{act: act{Name: "say_quiero_vale_cuatro"}}, - ActionSaySonBuenas{act: act{Name: "say_son_buenas"}}, - ActionSaySonMejores{act: act{Name: "say_son_mejores"}}, - ActionSayMeVoyAlMazo{act: act{Name: "say_me_voy_al_mazo"}}, +func (g GameState) CalculatePossibleActions() []Action { + envidoScore := g.Hands[g.TurnPlayerID].EnvidoScore() + + allActions := []Action{} + + for _, card := range g.Hands[g.TurnPlayerID].Unrevealed { + allActions = append(allActions, newActionRevealCard(card)) } - actions := []string{} + + allActions = append(allActions, + newActionSayEnvido(), + newActionSayRealEnvido(), + newActionSayFaltaEnvido(), + newActionSayEnvidoQuiero(envidoScore), + newActionSayEnvidoNoQuiero(), + newActionSayTruco(), + newActionSayTrucoQuiero(), + newActionSayTrucoNoQuiero(), + newActionSayQuieroRetruco(), + newActionSayQuieroValeCuatro(), + newActionSaySonBuenas(), + newActionSaySonMejores(envidoScore), + newActionSayMeVoyAlMazo(), + ) + + possibleActions := []Action{} for _, action := range allActions { if action.IsPossible(g) { - actions = append(actions, action.GetName()) + possibleActions = append(possibleActions, action) } } - return actions + return possibleActions } func SerializeAction(action Action) []byte { @@ -369,3 +377,11 @@ type RoundResult struct { TrucoWinnerPlayerID int `json:"trucoWinnerPlayerID"` TrucoPoints int `json:"trucoPoints"` } + +func _serializeActions(as []Action) []json.RawMessage { + _as := []json.RawMessage{} + for _, a := range as { + _as = append(_as, json.RawMessage(SerializeAction(a))) + } + return _as +}