O Jogo de Nim

Olá galera,

O pessoal aqui sempre fala para tentar fazer algum código antes e colocar aqui, para tirar dúvida, mas o que vou perguntar aqui não está relacionado com o código em si, e sim em como estruturar o programa.

Tenho que fazer um jogo que funciona da seguinte maneira:

[list]Criar uma pilha de bolas. Ela deve ter entre 10 e 100 bolas[/list]
[list]Sortear um jogador para começar (são dois jogadores)[/list]
[list]As jogadas se resumem em retirar bolas da pilha. Deve-se tirar no mínimo uma bola, e no máximo metade do número de bolas na pilha[/list]
[list]O jogador adversário pode ser um humano, ou o computador (burro ou inteligente)[/list]
[list]O jogador que retirar a última bola perde[/list]

No exercício, devo criar as seguintes classes: Pilha, Jogador e Jogo

Não consegui imaginar a melhor maneira (na verdade nenhuma maneira) para estruturar esse programa.

Algumas coisas que já consegui pensar:
A pilha deve ter o atributo número de bolas. É esse atributo que vai “guiar” o jogo.
O jogador precisa ser humano ou computador. No caso se der humano, recebe jogadas. No caso de ser computador terá dois comportamentos: burro e inteligente.
Já tenho o algoritmo que representa tais comportamentos.

O que não consegui pensar é o comportamento do jogo em si. Nunca fiz nada parecido.
Quais métodos a Pilha, o Jogador e o Jogo devem ter? Não consegui imaginar o funcionamento.

Será que alguém pode me ajudar?


Já criei a classe Pilha que gera o número aleatório de bolas, entre 10 e 100

package nimGame;

/**
 * Pilha de bolas para o jogo de Nim.
 * 
 * @author joaodaniel
 * 
 */
public class Pile {
	/**
	 * Constrói pilha de bolas. O número de bolas pode ser entre 10 e 100.
	 */
	public Pile() {
		while (numBalls < 10) {
			this.numBalls = (int) Math.round(Math.random() * 100);
		}
	}

	/**
	 * Retorna o número de bolas na pilha
	 * 
	 * @return número de bolas
	 */
	public int getNumBalls() {
		return numBalls;
	}

	private int numBalls;
}

Consegui criar também alguma coisa para a classe do Jogo. Defini um atributo que seria o próximo jogador. Para cada o jogada o programa verifica quem é o próximo jogador e pede por sua jogada. O método sortPlayer sorteia o jogador que irá começar a partida.

[code]
package nimGame;

/**

  • Classe do Jogo de Nim
  • @author joaodaniel

/
public class Game {
/
*
* Executa o sorteio do jogador que irá começar a partida
*/
public void sortPlayer() {
double random = Math.random();
if (random < 0.5)
this.nextPlayer = 1;
else
this.nextPlayer = 2;
}

private int nextPlayer;

}[/code]

Estou implementando a classe Jogo. Nela estão os algoritmos que geram as jogadas de cada tipo de jogador. Para gerar o número de bolas retiradas na jogada, precisaria saber o número de bolas que ainda estão na pilha. Mas esse número de bolas é uma variável de instância do objeto Pilha. Como devo buscar essa informação? Estou confuso.

Segue o código:

package nimGame;

/**
 * Jogadores do jogo de Nim Os jogadores podem ser humanos ou computador No caso
 * de serem computador, ainda podem ser inteligentes ou burros
 * 
 * @author joaodaniel
 * 
 */
public class Player {
	/**
	 * Constrói jogador com o parâmetro de ser humano ou não e de ser
	 * inteligente ou não.
	 * 
	 * @param human
	 *            é humano
	 * @param smart
	 *            é inteligente
	 */
	public Player(boolean human, boolean smart) {
		this.human = human;
		this.smart = smart;
	}

	/**
	 * Constrói jogador apenas com o parâmetro de ser humano. O de ser
	 * inteligente ou não é deixado como false por padrão. Este construtor será
	 * usado na criação do usuário principal, que sempre terá que ser humano.
	 * 
	 * @param human
	 *            é humano
	 */
	public Player(boolean human) {
		this.human = human;
	}

	/**
	 * Implementa os algoritmos de jogada para cada tipo de jogador.
	 * 
	 * @return número de bolas retiradas
	 */
	public int play() {
		if (human) {
			// Pede entrada do jogador
		} else if (smart) {
			// Algoritmo do jogador inteligente
		} else {
			// Algoritmo do jogador burro
		}
	}

	private boolean human;
	private boolean smart;
}

Eu o aconselharia a tentar utilizar o TDD (metodologia) para criar esse jogo. Mesmo que você nunca tenha ouvido falar. Tente implementá-lo.

Você irá guiar seu desenvolvimento pelos testes e assim fica mais facil estruturar seu código. Por exemplo:

  • Criar uma pilha de bolas. Ela deve ter entre 10 e 100 bolas.

@Test public void testeSePilhaTemEntreDezECemBolas() { PilhaBolas pilha = new PilhaBolas(); assertTrue( pilha.getNumeroBolas() > 10 ); assertTrue( pilha.getNumeroBolas() < 100 ); }

Ao fazer o teste acima você já descobriu que vai precisar de uma classe PilhaBolas que tem o atributo numeroBolas. E sabe também que no construtor precisará preencher esse numeroBolas.

  • As jogadas se resumem em retirar bolas da pilha. Deve-se tirar no mínimo uma bola, e no máximo metade do número de bolas na pilha

@Test public void testeSeRetiraNoMinimoUmaBola() { PilhaBolas pilha = new PilhaBolas(); int numeroBolas = pilha.getNumeroBolas(); pilha.retirarBola(2); assertTrue( numeroBolas - pilha.getNumeroBolas() > 0 ); //retirou mais do que uma bola preenche o requisito de retirar no minimo uma bola }

@Test public void testeSeRetiraNoMaximoMetadeDoNumeroDeBolas() { PilhaBolas pilha = new PilhaBolas(); int numeroBolas = pilha.getNumeroBolas(); pilha.retirarBola(2); int bolasRetiradas = numeroBolas - pilha.getNumeroBolas(); assertTrue( bolasRetiradas <= bolasRetiradas / 2 ); //retirou mais do que uma bola preenche o requisito de retirar no minimo uma bola }

Ao realizar esses testes você já percebe que precisa de um método para retirar bolas e que recebe como parametro o numero de bolas que irá retirar.

Por exemplo, ao escrever esses testes percebi que você precisa receber o numero de bolas que a pilha tem como parametro no construtor senão fica impossível testar. (porque você não tem algo conhecido). Consequentemente a responsabilidade por sortear o numero de bolas fica para a classe Jogo. ESSA É A IMPORTÂNCIA DO TDD COLABORA MUITO PARA PROJETAR ALGO.

Obs: Como só percebi isso no final os testes precisariam ser refatorados. Mas o importante é a idéia.
Obs2: Poderia ter outros testes como testar se retira a quantidade correta de bolas da pilha, verificar se o jogador é humano ou computador, …

Rafael, estou doido pra começar a aprender a programar utilizando TDD.

O livro que estou estudando menciona TDD mais a frente, e estava esperando chegar lá. Mas estou achando quase impossível executar esse projeto sem recorrer ao TDD.
Vou dar uma olhada no que tem lá no livro para ver se ajuda também. Você sabe onde posso encontrar mais material sobre TDD? Já dei uma olhada em um blog (Coding Dojo Floripa) que tem bastante coisa. Vou ler ele com calma também!

Valeu pela ajuda!

Te digo que “nunca” estudei TDD (olhei apenas os videos e links do Coding Dojo Floripa). Tentei implementar o TDD em um projeto que tenho em produção mais utilizá-lo com banco de dados, com chamadas remotas e em um sistema que foi mal projetado é bem mais complicado e desanimador. Ainda não tive tempo de empregá-lo 100%.

Já para implementá-lo em projetos como esse jogo parece ser mais fácil (me avisem se estiver errado). Inclusive estou criando o projeto desse jogo utilizando TDD para praticar. Se quiser trocar idéias estou a disposição. Acredito que é uma ótima oportunidade para coloca-lo em prática.

Uai Rafael, vou tentando aqui, e a gente vai trocando idéia!
Estou configurando o JUnit aqui e vou encarar ele! Hehe

Só mais algumas informações que você vai precisar pra fazer o jogo:
O jogador burro escolhe aleatoriamente qualquer número entre 1 e a metade do número de bolas na pilha.
Já o inteligente escolhe o número de bolas suficiente pra transformar o número de bolas na pilha uma potência de 2 menos 1. Isto é: 1, 3, 7, 15, 31 ou 63.

Opa… tranquilo?

Estou com o jogo pronto aqui desde o inicio de dezembro. Mas, havia deixado ele esquecido aqui.

Hoje disponibilizei ele no github se você quiser dar uma olhada:

Se fizesse o jogo hoje, mudaria o nome dos testes.
Motivo: http://www.urubatan.com.br/introduzindo-bdd/

Se alguém quiser opinar sobre o código agradeço.