// Programa tirado exatamente de Arnow e Weiss

// Introduction to Progamming Using Java

// (traduzido)

// Advertencia: isso nao eh um programa muito bem feito:

// Ache as imperfeicoes (incluindo bugs) e remova-as.

import java.io.*;

class JogoMancala {

int jogadorCorrente = 0;

TabuleiroMancala tabuleiro;

Jogador [] jogadores;

JogoMancala( String nome0, String nome1 ) {

tabuleiro = new TabuleiroMancala();

tabuleiro.prepareAJogar();

jogadores = new Jogador[2];

jogadores[0] = new Jogador( nome0, 0 );

jogadores[1] = new Jogador( nome1, 1 );

jogadorCorrente = 0;

}

public void joga() throws IOException {

mostraTabuleiro();

while( !tabuleiro.partidaTerminou() ) {

int numBuraco = jogadores[jogadorCorrente].selecioneJogada(tabuleiro);

boolean jogaNovamente = tabuleiro.facaJogada( jogadorCorrente, numBuraco );

System.out.println( "Jogador " + jogadorCorrente +

" moveu de " + numBuraco );

mostraTabuleiro();

if( !jogaNovamente ) {

if( jogadorCorrente == 0 ) {

jogadorCorrente = 1;

} else {

jogadorCorrente = 0;

}

} else {

System.out.println( "Jogador " +

jogadorCorrente + " joga novamente" );

}

}

tabuleiro.passaPedrasParaMancalas();

mostraTabuleiro();

if( tabuleiro.pedrasNaMancala(0) > tabuleiro.pedrasNaMancala(1) ) {

System.out.println( jogadores[0].pegaNome() + " ganha" );

} else if( tabuleiro.pedrasNaMancala(1) > tabuleiro.pedrasNaMancala(0) ) {

System.out.println( jogadores[1].pegaNome() + " ganha" );

} else {

System.out.println( "Empate" );

}

}

private void mostraTabuleiro() {

String espacoLinhaMancala = ""; // Usado para colocar espacos na linha

// da mancala

System.out.println( "-----------------------" );

// linha de buracos do jogador 1

System.out.print( " " );

for( int i = 1; i <= tabuleiro.buracosNoJogo; i++ ) {

System.out.print( tabuleiro.pedrasNoBuraco(1, i) + " " );

espacoLinhaMancala += " ";

}

mostraJogador(1);

// linha das mancalas

System.out.print( tabuleiro.pedrasNaMancala(1) + " " );

System.out.print( espacoLinhaMancala );

System.out.println( tabuleiro.pedrasNaMancala(0) );

// linha de buracos do jogador 0

System.out.print( " " );

for( int i = tabuleiro.buracosNoJogo; i >= 1; i-- ) {

System.out.print( tabuleiro.pedrasNoBuraco( 0, i ) + " " ); // livro errado

}

mostraJogador(0);

System.out.println( "-----------------------" );

}

private void mostraJogador( int numDoJogador ) {

// indicador da vez

if( jogadorCorrente == numDoJogador ) {

System.out.print( " -->" );

} else {

System.out.print( " ");

}

// informacao sobre o jogador

System.out.println( "Jogador " + numDoJogador + " (" + jogadores[numDoJogador].pegaNome() + ")" );

}

public static void main( String [] args ) throws IOException {

JogoMancala jogo = new JogoMancala( "Jacques", null );

jogo.joga();

}

}

class TabuleiroMancala {

private Buraco [] buracos;

public static final int buracosNoJogo = 6,

totalBuracos = 2*(buracosNoJogo+1);

TabuleiroMancala() {

buracos = new Buraco[totalBuracos];

for( int numBuraco = 0; numBuraco < totalBuracos; numBuraco++ ) {

buracos[numBuraco] = new Buraco();

}

}

public void prepareAJogar() {

for( int numBuraco = 0; numBuraco < totalBuracos; numBuraco++ ) {

if( ! ehUmaMancala( numBuraco ) ) {

buracos[numBuraco].adicionePedras(4);

}

}

}

public int pedrasNaMancala( int numDoJogador ) {

return buracos[pegaMancala(numDoJogador)].pegaPedras();

}

public int pedrasNoBuraco( int numDoJogador, int numBuraco ) {

return buracos[pegaNumDoBuraco(numDoJogador, numBuraco)].pegaPedras();

}

private int pegaNumDoBuraco( int numDoJogador, int numBuraco ) {

return numDoJogador * (buracosNoJogo+1) + numBuraco;

}

private int pegaMancala( int numDoJogador ) {

return numDoJogador * (buracosNoJogo+1);

}

private boolean ehUmaMancala( int numBuraco ) {

return numBuraco % (buracosNoJogo+1) == 0;

}

public TabuleiroMancala copiaTabuleiro() {

TabuleiroMancala novoTabuleiro = new TabuleiroMancala();

for( int numBuraco = 0; numBuraco < totalBuracos; numBuraco++ ) {

novoTabuleiro.buracos[numBuraco].adicionePedras( this.buracos[numBuraco].pegaPedras() );

}

return novoTabuleiro;

}

public boolean facaJogada( int numJogadorCorrente, int numBuracoEscolhido ) {

int numBuraco = pegaNumDoBuraco( numJogadorCorrente, numBuracoEscolhido );

int pedras = buracos[numBuraco].removePedras();

while( pedras != 0 ) {

numBuraco--;

if( numBuraco < 0 ) {

numBuraco = totalBuracos - 1;

}

if( numBuraco != pegaMancala( numOutroJogador(numJogadorCorrente) ) ) {

buracos[numBuraco].adicionePedras(1);

pedras--;

}

}

if( numBuraco == pegaMancala( numJogadorCorrente ) ) {

return true;

}

if( dono(numBuraco) == numJogadorCorrente && buracos[numBuraco].pegaPedras() == 1 ) {

pedras = buracos[numBuracoOposto(numBuraco)].removePedras();

buracos[pegaMancala(numJogadorCorrente)].adicionePedras(pedras);

}

return false;

}

private int dono( int numBuraco ) {

return numBuraco / (buracosNoJogo + 1);

}

private int numBuracoOposto( int numBuraco ) {

return totalBuracos - numBuraco;

}

private int numOutroJogador( int numDoJogador ) {

if( numDoJogador == 0 ) {

return 1;

} else {

return 0;

}

}

public boolean partidaTerminou() {

for( int jogador = 0; jogador < 2; jogador++ ) {

int pedras = 0;

for( int numBuraco = 1; numBuraco <= buracosNoJogo; numBuraco++ ) {

pedras += buracos[pegaNumDoBuraco(jogador, numBuraco)].pegaPedras();

}

if( pedras == 0 ) {

return true;

}

}

return false;

}

public void passaPedrasParaMancalas() {

for( int jogador = 0; jogador < 2; jogador++ ) {

for( int numBuraco = 1; numBuraco <= buracosNoJogo; numBuraco++ ) {

int pedras = buracos[pegaNumDoBuraco(jogador, numBuraco)].removePedras();

buracos[pegaMancala(jogador)].adicionePedras(pedras);

}

}

}

}

class Buraco {

int pedras;

public Buraco() { this.pedras = 0; }

public int pegaPedras() { return pedras; }

public void adicionePedras( int pedras ) { this.pedras += pedras; }

public boolean estaVazio() { return pedras == 0; }

public int removePedras() {

int pedras = this.pedras;

this.pedras = 0;

return pedras;

}

}

class Jogador {

private String nome;

private int numDoJogador;

public Jogador( String nome, int numDoJogador ) {

this.nome = nome;

this.numDoJogador = numDoJogador;

}

public String pegaNome() {

if( nome != null ) {

return nome;

} else {

return "Computador";

}

}

public int pegaNumDoJogador() {

return this.numDoJogador;

}

public int selecioneJogada( TabuleiroMancala tabuleiro ) throws IOException {

if( nome != null ) {

BufferedReader br = new BufferedReader( new InputStreamReader( System.in ) );

System.out.print( "Entra com numero do buraco da jogada: " );

System.out.flush();

int numBuraco = Integer.parseInt( br.readLine() );

return numBuraco;

}

// Jogador eh computador: devemos determinar a melhor jogada

int melhorJogada = -1;

int jogadaComRepeticao = -1;

int maxPedrasAdicionais = -1;

// tente as possiveis jogadas

for( int numBuraco = 1; numBuraco <= tabuleiro.buracosNoJogo; numBuraco++ ) {

if( tabuleiro.pedrasNoBuraco( numDoJogador, numBuraco ) != 0 ) {

TabuleiroMancala tabuleiroDeTeste = tabuleiro.copiaTabuleiro();

boolean jogaNovamente = tabuleiroDeTeste.facaJogada( numDoJogador, numBuraco );

if( jogaNovamente ) {

jogadaComRepeticao = numBuraco;

}

int pedrasAdicionais = tabuleiroDeTeste.pedrasNaMancala(numDoJogador) -

tabuleiro.pedrasNaMancala(numDoJogador);

if( pedrasAdicionais > maxPedrasAdicionais ) {

maxPedrasAdicionais = pedrasAdicionais;

melhorJogada = numBuraco;

}

}

}

// tentamos todas as possibilidades: escolhe a melhor

if( maxPedrasAdicionais > 1 ) {

return melhorJogada;

} else if( jogadaComRepeticao != -1 ) {

return jogadaComRepeticao;

} else {

return melhorJogada;

}

}

}