66/100 Dias de Golang - Jogo usando bubbletea e lipgloss - Parte 2
Table of Contents
#
Jogo usando bubbletea e lipgloss - Parte 2
Ontem criamos a base do jogo e estruturamos o projeto, hoje faremos a lógica usando o bubbletea e o lipgloss.
Vamos começar criando as estilizações dos textos. A documentação do lipgloss é muito legal e tem vários exemplos de como usar a biblioteca.
var (
estiloJogador = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("2"))
estiloComputador = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("1"))
estiloVencedor = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("10"))
estiloPlacar = lipgloss.NewStyle().Foreground(lipgloss.Color("11"))
)
E depois passmos para a estrutura do bubbletea, seguindo o padrão Model, View e Update.
Nossa model:
type model struct {
playerCard Carta
cpuCard Carta
baralho []Carta
posicao int
vencedor string
playerPoints int
cpuPoints int
}
O update, que faz a lógica de capturar os inputs e executa as regras do código. Nesse caso pega as duas próximas posições e envia para uma outra função para determinar quem é o vencedor.
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
if msg.String() == "q" {
return m, tea.Quit
} else if msg.String() == " " {
if m.posicao+1 < len(m.baralho) {
m.playerCard = m.baralho[m.posicao]
m.cpuCard = m.baralho[m.posicao+1]
m.posicao += 2
m.vencedor = determinarVencedor(m.playerCard, m.cpuCard, &m)
} else {
return m, tea.Quit
}
}
}
return m, nil
}
func determinarVencedor(p, c Carta, m *model) string {
if p.Forca > c.Forca {
m.playerPoints += 1
return "Jogador"
}
m.cpuPoints += 1
return "Computador"
}
E a view faz a renderização dos elementos, aqui passamos a string para os estilos criados.
func (m model) View() string {
playerView := estiloJogador.Render(fmt.Sprintf("Você: %s%s", m.playerCard.Valor, m.playerCard.Naipe))
cpuView := estiloComputador.Render(fmt.Sprintf("Computador: %s%s", m.cpuCard.Valor, m.cpuCard.Naipe))
resultado := estiloVencedor.Render(fmt.Sprintf("Vencedor: %s", m.vencedor))
placar := estiloPlacar.Render(fmt.Sprintf("Pontos:\nJogador: %d | Computador: %d", m.playerPoints, m.cpuPoints))
return fmt.Sprintf("%s | %s\n%s\n%s\nPressione espaço para jogar, 'q' para sair.", playerView, cpuView, resultado, placar)
}
E no main criamos o baralho e instânciamos o bubbletea:
func main() {
baralho := criarBaralho()
embaralhar(baralho)
p := tea.NewProgram(model{
baralho: baralho,
})
if _, err := p.Run(); err != nil {
fmt.Printf("Erro ao iniciar o programa: %v", err)
os.Exit(1)
}
}
Código completo:
package main
import (
"fmt"
"os"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
)
var (
estiloJogador = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("2"))
estiloComputador = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("1"))
estiloVencedor = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("10"))
estiloPlacar = lipgloss.NewStyle().Foreground(lipgloss.Color("11"))
)
type model struct {
playerCard Carta
cpuCard Carta
baralho []Carta
posicao int
vencedor string
playerPoints int
cpuPoints int
}
func (m model) Init() tea.Cmd {
return nil
}
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
if msg.String() == "q" {
return m, tea.Quit
} else if msg.String() == " " {
if m.posicao+1 < len(m.baralho) {
m.playerCard = m.baralho[m.posicao]
m.cpuCard = m.baralho[m.posicao+1]
m.posicao += 2
m.vencedor = determinarVencedor(m.playerCard, m.cpuCard, &m)
} else {
return m, tea.Quit
}
}
}
return m, nil
}
func determinarVencedor(p, c Carta, m *model) string {
if p.Forca > c.Forca {
m.playerPoints += 1
return "Jogador"
}
m.cpuPoints += 1
return "Computador"
}
func (m model) View() string {
playerView := estiloJogador.Render(fmt.Sprintf("Você: %s%s", m.playerCard.Valor, m.playerCard.Naipe))
cpuView := estiloComputador.Render(fmt.Sprintf("Computador: %s%s", m.cpuCard.Valor, m.cpuCard.Naipe))
resultado := estiloVencedor.Render(fmt.Sprintf("Vencedor: %s", m.vencedor))
placar := estiloPlacar.Render(fmt.Sprintf("Pontos:\nJogador: %d | Computador: %d", m.playerPoints, m.cpuPoints))
return fmt.Sprintf("%s | %s\n%s\n%s\nPressione espaço para jogar, 'q' para sair.", playerView, cpuView, resultado, placar)
}
func main() {
baralho := criarBaralho()
embaralhar(baralho)
p := tea.NewProgram(model{
baralho: baralho,
})
if _, err := p.Run(); err != nil {
fmt.Printf("Erro ao iniciar o programa: %v", err)
os.Exit(1)
}
}