DEV Community

React Mastermind

O jogo começa com um segredo de quatro cores. Ao todo existem seis cores diferentes que podem ser combinadas de qualquer forma: azul, amarelo, rosa, verde; azul, azul, amarelo, amarelo; azul, azul, azul e azul. Não há limite para cores repetidas.

Para descobrir o segredo, o jogador faz testes, escolhendo cores que o computador compara com o segredo. Se as combinações forem iguais, o jogador ganha; se forem diferentes, joga outro turno. Em 10 turnos, o jogador perde.

Mas é preciso algo a mais para descobrir o segredo em menos que 1296 tentativas aleatórias. Cada teste retorna pontos: a cada ponto preto, há uma cor certa no lugar certo; a cada ponto branco, há uma cor certa no lugar errado.

Agora, vamos criar esse jogo. Para entender como funciona, experimente aqui a versão pronta.

As ferramentas utilizadas

Para criar esse jogo, vamos utilizar duas ferramentas principais. Com o React, vamos criar a interface, gerenciar os estados da aplicação por meio da Context API e operar os inputs do jogador.

Com o Lodash — conjunto de funções que expande[1] as possibilidades de manipulação de estruturas de dados em Javascript, vamos manipular os arrays e objetos para montar testes, comparar testes ao segredo e calcular pontos. Escolhi o Lodash porque a inspiração para recriar esse jogo veio do Mastermind in Haskell[2], uma implementação feita com funções puras que roda no terminal.

Gerando o segredo

Vamos começar pelo mais fácil. O segredo não é nada mais do que uma combinação aleatória de 4 das 6 cores disponíveis. As funções shuffle e take do Lodash nos permitem resolver isso em uma quatro linhas.

Sample colhe elementos aleatórios de arr, que são então mapeados em um novo array, e a partir dele take gera um novo array com os primeiros n elementos. É importante ressaltar que as funções são puras e não alteram a fonte arr. Um beijo para o time lambda 🧙.[3]

Assim, para começar um novo jogo, basta gerar um novo segredo com algo como let secret = genSecret(cores, 4).
Gerando os testes
Gerar o segredo é a parte mais fácil. Agora vamos ver como gerar o teste com as cores escolhidas pelo jogador. Para isso, vamos usar o hook useReducer do React para adicionar, remover e resetar cores no teste, que aqui será chamado de state.

No componente, iniciamos o teste (state) como um array vazio. A cada evento que dispara uma ação do dispatch, um novo objeto teste é emitido de acordo com o tipo da ação (“add”, “remove”, “reset”): adicionando a cor escolhida (action.payload) ao teste, removendo-a ou resetando tudo.

Mais uma vez, as ações não alteram o objeto do teste, mas sim criam um novo objeto que o substitui, a cada ação.

Gerando a pontuação

Essa é a parte mais interessante. Se você leu até aqui, aí vai um desafio: dados um conjunto teste e um conjunto segredo, ambos de quatro elementos, como descobrir quantos são os elementos iguais na posição correta e os elementos iguais na posição errada?
Descobrir as cores certas na posição certa (pontos pretos) é fácil, é claro. Comparamos os arrays lado a lado: se na posição 0 as cores forem iguais, 1; se forem diferentes, 0; e somamos os pontos. Mas e os pontos brancos, isto é, as cores certas na posição errada?

Mais uma vez, o Lodash nos dá uma série de ferramentas para juntar, filtrar e comparar os arrays. solução para o desafio: os pontos brancos são o numero de cores do segredo, menos as cores que o teste não acertou, menos os pontos pretos.

Condições de vitória e derrota

Falamos sobre como começar o jogo — gerar o segredo — e como fazer cada turno — criar um teste, calcular os pontos. Agora, preciso falar sobre o funcionamento geral do jogo, isto é, como registrar os testes realizados e quais são as condições de vitória e derrota.

Para o jogo funcionar, eu preciso de acesso a uma informação em todos os componentes (tabuleiro, header, mão do jogador, app). Essa informação é a lista de todos os testes já realizados.
No React, essa necessidade nos leva diretamente à ideia de uma ferramenta de gerenciamento de estado global da aplicação, como o Redux. Para criar este jogo, optei pela ferramenta nativa do React, a Context API.

A lista de testes (“guesses”) agora pode estar disponível por meio do uso do custom hook useGuesses. A variável guesses lista todos os testes já realizados, e a função setGuesses é usada para incluir novos testes à lista.[4]
Para terminar, precisamos falar sobre como ganhar o jogo, e também como perder. O jogador ganha quando o teste é igual ao segredo, e perde quando já lançou 10 testes errados. Agora que temos a lista completa e constantemente atualizada dos testes, fica fácil implementar essas condições. Para isso, utilizaremos o hook useEffect, um método que roda a cada atualização do componente.

Se o último teste tiver 4 pontos pretos, o jogador ganhou. Se o número de testes for maior que 9, o jogador perdeu.

Conclusão

Desde que eu comecei a programar, meu mentor sempre me disse que criar jogos é uma das maneiras mais eficazes de estudar, treinar, aprender. Isso porque é ao mesmo tempo divertido e complexo.
Neste exercício, recriei o jogo de Mastermind que pode ser jogado pelo browser, no computador ou no celular. Ainda teria muita coisa para falar, como a organização dos componentes do React ou a estilização responsiva com Material UI. Mas acho que nesse artigo consegui explicar o que eu queria: como o jogo funciona logicamente, e como usar funções puras para manipular estruturas de dados para obter os resultados desejados.
Se você gostou, pode conferir o código no meu github, jogar o jogo pelo browser ou deixar o like no artigo. Obrigado e um abraço!

1.Talvez a expressão correta seja “facilita”; afinal, não há razão para as operações feitas com o Lodash não poderem ser feitas com o Javascript puro. Mas “expandir” é mais bonito, vamos concordar.

  1. Mastermind in Haskell, por Christophe Delord. Acesse aqui.

  2. Na primeira versão, eu utilizei a função shuffle do Lodash, que gera um array de elementos embaralhados. Como um colega apontou, dessa maneira o jogo não conseguia gerar segredos com elementos repetidos, e alterei para usar a função sample.

  3. Para criar esse Context, foi indispensável o tutorial do Guilherme Rodz. Obrigado, meu caro! Acesse aqui.

Top comments (0)