React Mastermind
Tags: javascript, react
Published: 2021-01-05 16:47:14

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](https://escribapetrus.github.io/mastermind-react/).

##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.

{% gist https://gist.github.com/escribapetrus/ad66ad9d0df00da325cd83a8d3c9f93d %}

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.

{% gist https://gist.github.com/escribapetrus/e85e697bbe11d524490f0b8f4451e7b7 %}

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?

{% gist https://gist.github.com/escribapetrus/c92be9bb192e3d3d08c2c0e3139a4622 %}

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__.

{% gist https://gist.github.com/escribapetrus/350896c9ac5858988edbcbf10960584e %}

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.

{% gist https://gist.github.com/escribapetrus/090acb41c2f73ce6c860d00a6b964812 %}

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](https://github.com/escribapetrus/mastermind-react), [jogar o jogo pelo browser](https://escribapetrus.github.io/mastermind-react/) 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.

2. Mastermind in Haskell, por Christophe Delord. [Acesse aqui](http://christophe.delord.free.fr/haskell/mastermind.html).

3. 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.

4. Para criar esse Context, foi indispensável o tutorial do Guilherme Rodz. Obrigado, meu caro! [Acesse aqui](https://www.youtube.com/watch?v=FsCBw9X9U84&t=707s).