Pular para o conteúdo principal

victorstein.dev

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)
	}
}

Jogo do baralho

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)
	}
}