// Arquivo que faz as inicializações e coloca o EP para rodar:
/*
(***************************************************************************)
(* Caetano Jimenez Carezzato                                               *)
(* Exercício-Programa 01                                                   *)
(* Curso 51 - Turma 45  -- Professor: Carlos Eduardo Ferreira              *)
(* Computador: Pentium 100                                                 *)
(* Compilador: JDK 1.1.3 Windows 95 (Não roda em compiladores da Microsoft)*)
(***************************************************************************)
	Este EP não faz tratamento de erros de leitura, suponto que o 
usuário sempre coloque os dados corretamente nos campos.
	Caso um erro desse seja cometido, uma exceção será lançada e tratada pela
máquina virtual.
	Em máquinas unix o EP parece que trava, não exibe as telas direito
e algumas vezes lança alguns erros
*/
import java.awt.*;
import java.io.*;

public class EP_1 extends Frame
{
		public static final int MAX_Pinos = 10, MIN_TPinos = 8, Rodadas = 1000;
// Objetos da interface:
		private static Panel CentralizaTabuleiro;
		private static Panel Tabuleiro;
		private static final Panel Controle = new Panel();
		private static final Panel Botões = new Panel();
		private static final Info info = new Info(Rodadas);

		private static final MenuBar Principal = new MenuBar();
		private static final Menu Arquivo = new Menu("Arquivo");
		private static final Menu Editar = new Menu("Editar");
		private static final Menu Jogar = new Menu("Jogar");
		private static final Menu Ajuda = new Menu("Ajuda");

		private static final CheckboxMenuItem Inicial = new CheckboxMenuItem("Editar o Tabuleiro Inicial");
		private static final CheckboxMenuItem Final = new CheckboxMenuItem("Editar o Tabuleiro Final");
		private static final CheckboxMenuItem SJogar = new CheckboxMenuItem("Ativar Modo Jogar");
		private static final MenuItem Reiniciar = new MenuItem("Reiniciar"), Resetar = new MenuItem("Resetar o Tabuleiro");
		private static MenuItem Abre_F = new MenuItem("Abrir Tabuleiro Final...");
		private static MenuItem Salva_I = new MenuItem("Salvar Tabuleiro Inicial...");
		private static MenuItem Salva_F = new MenuItem("Salvar Tabuleiro Final...");

		private static final CheckboxGroup CG = new CheckboxGroup();
		private static final TextField Restar_N = new TextField("1");
		private static final Checkbox CRestar = new Checkbox("Restar", CG, true);
		private static final Checkbox Restar_Arq = new Checkbox("Restar como no arquivo", CG, false);
		private static final Button Resolver = new Button("Resolver");
		private static Label Status = new Label();
// Variáveis utilizadas
		private static boolean[][][] Tab_I, Tab, Tab_F, Tab_IO;
		private static boolean Edita_I, IO, IO_F, jogar, Pino_P;
		private static Pinos[][] PinosTabuleiro;
		private static Pinos Pino_p;
		private int Largura, Altura, TamanhoPinos;
		private static int[][] Retorno, Testar, Mapa, Jogada;
		private static int[][][] Mapas;
		private static int NPeças, Restar, Jogadas, NJogadas, Tabuleiros, NTabuleiros, P, MA, V, X, Y, i;
		private static File Entrada, Saída;

	public EP_1(int largura, int altura, int TPinos)
	{
		super("EP 1");
		// Atualiza as variáveis:
		Largura = largura;
		Altura = altura;
		TamanhoPinos = TPinos;
		Edita_I = true;
		// Inicia a construção do tabuleiro
		CentralizaTabuleiro = new Panel();
		Tabuleiro = new Panel();
		CentralizaTabuleiro.setLayout(new GridBagLayout());
		if (Largura > 0)
		{ // Enche o tabuleiro e atualiza o vetor, faz atualizações na interface
			Abre_F.enable();
			Salva_I.enable();
			Salva_F.enable();
			Editar.enable();
			Botões.enable();
			Jogar.enable();
			Tabuleiro.setLayout(new GridLayout(Altura, Largura, 0, 0));
			Tabuleiro.resize(Largura * TamanhoPinos, Altura * TamanhoPinos);
			CentralizaTabuleiro.resize(Largura * TamanhoPinos, Altura * TamanhoPinos);
			int i , j;
			PinosTabuleiro = new Pinos[Altura + 1][Largura + 1]; // Gasta mais memória mas universaliza
			Tab_I = new boolean[Altura + 2][Largura + 2][2];
			Tab = new boolean[Altura + 2][Largura + 2][2];
			Tab_F = new boolean[Altura + 2][Largura + 2][2];
			if (IO)
			{
				for (i = 1; i <= Altura; i++)
					for (j = 1; j <= Largura; j++)
				{
					Tabuleiro.add(PinosTabuleiro[i][j] = new Pinos(Color.blue, TamanhoPinos, 0, 0, j, i));
					Tab_I[i][j][0] = Tab_IO[i][j][0];
					Tab_I[i][j][1] = Tab_IO[i][j][1];
				}
				IO = false;
			}
			else
			{
				for (i = 1; i <= Altura; i++)
					for (j = 1; j <= Largura; j++)
				{
					Tabuleiro.add(PinosTabuleiro[i][j] = new Pinos(Color.blue, TamanhoPinos, 0, 0, j, i));
					Tab_I[i][j][0] = Tab_I[i][j][1] = true;
				}
			}
			Tab_IO = new boolean[Altura + 2][Largura + 2][2];
		}
		CentralizaTabuleiro.add(Tabuleiro);
		add("Center", CentralizaTabuleiro);
		// Cria o Menu
		if (Largura == 0) // Se é a primeira vez que entra aqui
		{
			Status.setText("Abra um Arquivo ou crie um Novo");
			Arquivo.add("Novo Tabuleiro Inicial...");
			Arquivo.addSeparator();
			Arquivo.add("Abrir Tabuleiro Inicial...");
			Arquivo.add(Abre_F);
			Arquivo.addSeparator();
			Arquivo.add(Salva_I);
			Arquivo.add(Salva_F);
			Arquivo.addSeparator();
			Arquivo.add("Sair");
			Editar.add(Inicial);
			Editar.add(Final);
			Editar.addSeparator();
			Editar.add("Encher o Tabuleiro");
			Editar.add("Esvaziar o Tabuleiro");
			Editar.add(Resetar);
			Editar.addSeparator();
			Editar.add("Mudar Tamanho dos Pinos...");
			Jogar.add(SJogar);
			Jogar.add(Reiniciar);
			Ajuda.add("Sobre o EP 1...");
			Principal.add(Arquivo);
			Principal.add(Editar);
			Principal.add(Jogar);
			Principal.setHelpMenu(Ajuda);
			Controle.setLayout(new BorderLayout());
			Botões.add(CRestar);
			Botões.add(Restar_N);
			Botões.add(Restar_Arq);
			Botões.add(Resolver);
			Abre_F.disable();
			Salva_I.disable();
			Salva_F.disable();
					Editar.disable();
					Botões.disable();
					Jogar.disable();
		}
		// Adiciona tudo
		jogar = false;
		SJogar.setState(false);
		Restar_Arq.disable();
		Reiniciar.disable();
		Inicial.setState(true);
		Final.setState(false);
		setMenuBar(Principal);
		Controle.add("North", Botões);
		Controle.add("South", Status);
		add("South", Controle);
		resize(420,420);
		pack();
		setResizable(false);
		show();
	}
	public static void main(String[] args)
	{
		new EP_1(0, 0, 32);  // Cria a nossa frame
	}
// Métodos:
// Métodos para a resolução

	private void Resolve_Tabuleiro()
	{ // Faz as preliminares para Resolver o tabuleiro
		this.disable();
		this.setCursor(Frame.WAIT_CURSOR);
		info.frame = this;
		info.Lista.clear();
		boolean Teste = info.Mostra();
		info.Jogadas.setText("Jogadas: 0");
		info.Tabuleiros.setText("Tabuleiros: 0");
		info.Tempo.setText("");
		info.Controles.disable();
		info.Lista.disable();
		info.disable();
		long Tempo_I = System.currentTimeMillis();
		int i, j;
		NPeças = Jogadas = Tabuleiros = P = NJogadas = NTabuleiros = 0;
		Restar = Integer.parseInt(Restar_N.getText()); // Copia para Tab que é o temporário e conta as peças
		for (i = 1; i <= Altura; i++)
			for (j = 1; j <= Largura; j++)
			{
				if (Tab[i][j][0] = Tab_I[i][j][0]) NPeças++;
				Tab[i][j][1] = Tab_I[i][j][1];
			}
		Retorno = new int[NPeças][3];
		if (!(Monta_Teste() && Resolver())) // Se o tabuleiro não é válido ou não foi resolvido
		{
			info.disable();
			this.enable();
			info.hide();
			Mensagem.MostraMensagem(this, "Resolver", "Esse tabuleiro não tem solução");
			this.setCursor(Frame.DEFAULT_CURSOR);
			Status.setText("Edite o tabuleiro usando o mouse");
		}
		else // Monta a saída
		{
			Info.Tempo.setText("Tempo: " + String.valueOf((float) (System.currentTimeMillis() - Tempo_I) / 1000) + " segundos");
			String Direção = new String();
			for (i = 0; i < NPeças - Restar; i++)
			{
				switch (Retorno[i][2])
				{
				case 0: Direção = "Para Cima";
					break;
				case 1: Direção = "Para a Direita";
					break;
				case 2: Direção = "Para Baixo";
					break;
				case 3: Direção = "Para a Esquerda";
					break;
				}
				info.Lista.addItem(String.valueOf(i + 1) + ") " + String.valueOf(Retorno[i][1] + "  ") + String.valueOf(Retorno[i][0]) + "  " + Direção); // Inverte as cordenadas
			}
			info.Jogadas.setText("Jogadas: " + String.valueOf((float)NJogadas/Rodadas + Jogadas));
			info.Tabuleiros.setText("Tabuleiros: " + String.valueOf((float)NTabuleiros/Rodadas + Tabuleiros));
			info.enable();
			info.Passo = 0;
			info.Passos = NPeças - Restar;
			info.PinosTabuleiro = PinosTabuleiro;
			info.Retorno = Retorno;
			info.Controles.enable();
			info.Próxima();
			info.Lista.enable();
			Inicial.setState(true);
			Final.setState(false);
			Status.setText("Edite o tabuleiro usando o mouse");
		}
	}

	private boolean Resolver()
	{ // função que resolve o tabuleiro.
		P = 1;
		Mapa = Mapeia(P);
		Jogada[P][1] = V; // número de jogadas
		Jogada[P][0] = 0; // jogada atual
		do
		{
			if (NJogadas >= Rodadas) // Atualiza as informações a cada n Rodadas
			{
				info.Jogadas.setText("Jogadas: " + String.valueOf(++Jogadas));
				NJogadas -= Rodadas;
			}
			Mapa = Mapas[P];
			if (Jogada[P][0] < Jogada[P][1]) // Têm jogadas a fazer
			{
				NJogadas++;
				i = Jogada[P][0];
				Jogada[P][0]++;
				X = Mapa[i][0];
				Y = Mapa[i][1];

				if (Mapa[i][2] == 0) //Vai movimentar para cima
				{
					Tab[X][Y][0] = Tab[X - 1][Y][0] = false;
					Tab[X - 2][Y][0] = true;
				}
				else if (Mapa[i][2] == 1) //Vai movimentar para direita
				{
					Tab[X][Y][0] = Tab[X][Y + 1][0] = false;
					Tab[X][Y + 2][0] = true;
				}
				else if (Mapa[i][2] == 2) //Vai movimentar para baixo
				{
					Tab[X][Y][0] = Tab[X + 1][Y][0] = false;
					Tab[X + 2][Y][0] = true;
				}
				else //Vai movimentar para esquerda
				{
					Tab[X][Y][0] = Tab[X][Y - 1][0] = false;
					Tab[X][Y - 2][0] = true;
				}
				if (((NPeças - P == Restar) && Testa())) //Se deu certo
				{
					int i, n;
					for (i = 0; i < P; i++)
					{
						n = i + 1;
						X = Mapas[n][Jogada[n][0] - 1][0];
						Y = Mapas[n][Jogada[n][0] - 1][1];
						Retorno[i][0] = X;
						Retorno[i][1] = Y;
						Retorno[i][2] = Mapas[n][Jogada[n][0] - 1][2];
					}
					return true;
				}
				else if (NPeças - P > Restar)// Se ainda não deu:
				{
					P++; // número da jogada
					Mapeia(P);
					Jogada[P][1] = V; // número de jogadas
					Jogada[P][0] = 0; // jogada atual
					if (V == 0)
					{
						NTabuleiros++; //Se um tabuleiro foi concluído
						if (NTabuleiros == Rodadas) // Atualiza info
						{
							info.Tabuleiros.setText("Tabuleiros: " + String.valueOf(++Tabuleiros));
							NTabuleiros = 0;
						}
					}
				} else P++; // Vai adicionar para que a funcao funcione direito
			}
			else
			{
				P--;
				if (P == 0) return false;
				i = Jogada[P][0] - 1;
				Mapa = Mapas[P];
				X = Mapa[i][0];
				Y = Mapa[i][1];
				// Deu errado, então vai desfazer e tentar de novo:
				if (Mapa[i][2] == 0) //Vai desmovimentar de cima
				{
					Tab[X][Y][0] = Tab[X - 1][Y][0] = true;
					Tab[X - 2][Y][0] = false;
				}
				else if (Mapa[i][2] == 1) //Vai desmovimentar da direita
				{
					Tab[X][Y][0] = Tab[X][Y + 1][0] = true;
					Tab[X][Y + 2][0] = false;
				}
				else if (Mapa[i][2] == 2) //Vai desmovimentar de baixo
				{
					Tab[X][Y][0] = Tab[X + 1][Y][0] = true;
					Tab[X + 2][Y][0] = false;
				}
				else //Vai desmovimentar da esquerda
				{
					Tab[X][Y][0] = Tab[X][Y - 1][0] = true;
					Tab[X][Y - 2][0] = false;
				}
			}
		}
		while (true);
	}

	private int[][] Mapeia(int Posição)
	{
		// Esta função mapeia todas as jogadas para um determinado tabuleiro, retorna null se não tem jogadas
		int i, j;
		V = 0;
		// Vai tentar ir contra o movimento porque assim testa-se mais tabuleiros que poderão resultar na resposta porque movimento contrários são nexessários mas são minoria
		Mapa = Mapas[Posição]; // Tem certeza que o vetor vai dar 
		for (i = 1; i < MA; i++) // Analiza a primeira metade
			for (j = 1; j <= Largura; j++)
			{
				if (Tab[i][j][0]) // Se é pino
				{
					if ((Tab[i - 1][j][0]) && (!Tab[i - 2][j][0]) && (Tab[i - 2][j][1])) // Se dá para cima
					{
						Mapa[V][0] = i;
						Mapa[V][1] = j;
						Mapa[V][2] = 0;
						V++;
					}
					if ((Tab[i][j - 1][0]) && (!Tab[i][j - 2][0]) && (Tab[i][j - 2][1])) // Se dá para esquerda
					{
						Mapa[V][0] = i;
						Mapa[V][1] = j;
						Mapa[V][2] = 3;
						V++;
					}
					if ((Tab[i][j + 1][0]) && (!Tab[i][j + 2][0]) && (Tab[i][j + 2][1])) // Se dá para direita
					{
						Mapa[V][0] = i;
						Mapa[V][1] = j;
						Mapa[V][2] = 1;
						V++;
					}
					if ((Tab[i + 1][j][0]) && (!Tab[i + 2][j][0]) && (Tab[i + 2][j][1])) // Se dá para baixo
					{
						Mapa[V][0] = i;
						Mapa[V][1] = j;
						Mapa[V][2] = 2;
						V++;
					}
				}
			}
		for (i = MA; i <= Altura; i++) // Analiza a segunda metade
			for (j = 1; j <= Largura; j++)
			{
				if (Tab[i][j][0]) // Se é pino
				{
					if ((Tab[i + 1][j][0]) && (!Tab[i + 2][j][0]) && (Tab[i + 2][j][1])) // Se dá para baixo
					{
						Mapa[V][0] = i;
						Mapa[V][1] = j;
						Mapa[V][2] = 2;
						V++;
					}
					if ((Tab[i][j - 1][0]) && (!Tab[i][j - 2][0]) && (Tab[i][j - 2][1])) // Se dá para esquerda
					{
						Mapa[V][0] = i;
						Mapa[V][1] = j;
						Mapa[V][2] = 3;
						V++;
					}
					if ((Tab[i][j + 1][0]) && (!Tab[i][j + 2][0]) && (Tab[i][j + 2][1])) // Se dá para direita
					{
						Mapa[V][0] = i;
						Mapa[V][1] = j;
						Mapa[V][2] = 1;
						V++;
					}
					if ((Tab[i - 1][j][0]) && (!Tab[i - 2][j][0]) && (Tab[i - 2][j][1])) // Se dá para cima
					{
						Mapa[V][0] = i;
						Mapa[V][1] = j;
						Mapa[V][2] = 0;
						V++;
					}
				}
			}
		if (V == 0) return null; // Se não empilhou nada
		return Mapa;
	}

	private boolean Monta_Teste()
	{// Faz preliminares, realizando uma série de testes
		int i, j, V = 0, pinos = 0, X = 0;
		for (i = 1; i <= Altura; i++) // Vai calcular o número de pinos
			for (j = 1; j <= Largura; j++)
				if (Tab[i][j][0]) pinos++;
		if (CRestar.getState()) // Se quer que reste N
		{
			MA = Altura / 2; // Coloca o centro no centro
			if (pinos <= Restar) return false; // Testa se vai haver movimentos
			Mapas = new int[NPeças + 1][4 * (NPeças)][3]; // Tem certeza que o vetor vai dar(Isto gasta mais memória mas deixa o EP 4 vezes mais rápido
			Jogada = new int[NPeças + 1][2]; // Tem certeza que o vetor vai dar(Isto gasta mais memória mas deixa o EP 4 vezes mais rápido
			return true;
		}
		V = 0;
		for (i = 1; i <= Altura; i++)
			for (j = 1; j <= Largura; j++)
				if (Tab_F[i][j][0]) // Totaliza o tabuleiro final
				{
					X += i;
					V++;
				}
		if (V > 0) // Se existem pinos para restar
		{
			MA = X / pinos; // Mexe no centro
			Restar = V;
			Testar = new int[V][2]; // Vai montar o vetor de teste
			V = 0;
			for (i = 1; i <= Altura; i++)
				for (j = 1; j <= Largura; j++)
					if (Tab_F[i][j][0])
			{
				Testar[V][0] = i;
				Testar[V][1] = j;
				V++;
			}
			if (pinos <= Restar) return false; // Se restar menos do que tem
			Mapas = new int[NPeças + 1][4 * (NPeças)][3]; // Tem certeza que o vetor vai dar 
			Jogada = new int[NPeças + 1][2]; // Tem certeza que o vetor vai dar(Isto gasta mais memória mas deixa o EP 4 vezes mais rápido
			return true;
		}
		return false;
	}

	private boolean Testa()
	{ // Faz o teste para ver se restou corretamente
		NTabuleiros++;
		if (NTabuleiros == Rodadas) // Atualiza info
		{
			info.Tabuleiros.setText("Tabuleiros: " + String.valueOf(++Tabuleiros));
			NTabuleiros = 0;
		}
		if (CRestar.getState()) // Se pede Restar N, presiza restar, sem ser possível fazer mais nenhum movimento
		{
			Mapeia(0);
			if (V > 0) return false;
			return true;
		}
		int i; // Se pede Restar como tabuleiro, testa as peças
		for (i = 0; i < Restar; i++) if (!Tab[Testar[i][0]][Testar[i][1]][0]) return false;
		return true;
	}
// Fim das funções que resolvem o tabuleiro

	// Início das funções que respondem ao usuário
	public void PinoPressionado(Pinos P)
	{
		if (jogar) // Se o usuário está jogando
		{
			if ((P.Status == 0) && !Pino_P) // Se é pino e não tem nenhum pressionado verifica se o movimento é válido e colore
			{
				int Y = P.Tabuleiro_X, X = P.Tabuleiro_Y;
				if ((Tab[X - 1][Y][0] && !Tab[X - 2][Y][0] && Tab[X - 2][Y][1]) || (Tab[X + 1][Y][0] && !Tab[X + 2][Y][0] && Tab[X + 2][Y][1]) || (Tab[X][Y - 1][0] && !Tab[X][Y - 2][0] && Tab[X][Y - 2][1]) || (Tab[X][Y + 1][0] && !Tab[X][Y + 2][0]) && Tab[X][Y + 2][1]) // Se for mexível
				{
					P.MudaStatus(3);
					Pino_P = true;
					Pino_p = P;
				}
			}
			else if (P.Status == 3) // Se é pino pressionado
			{
				P.MudaStatus(0);
				Pino_P = false;
			}
			else if ((P.Status == 1) && Pino_P) // Se seleciono e clicou num buraco
			{
				int Y1 = Pino_p.Tabuleiro_X, X1 = Pino_p.Tabuleiro_Y, Y2 = P.Tabuleiro_X, X2 = P.Tabuleiro_Y;
				if ( ( ((X1 - X2) == 2) || ((X1 - X2) == -2) && ((Y1 - Y2) == 0)) || (((Y1 - Y2) == 2) || ((Y1 - Y2) == -2)) && ((X1 - X2) == 0)) // Se é válido e corresponde ao selecionado
				{
					Pino_p.MudaStatus(1);
					Tab[X1][Y1][0] = false;
					P.MudaStatus(0);
					Tab[X2][Y2][0] = true;
					PinosTabuleiro[(X1 + X2)/2][(Y1+Y2)/2].MudaStatus(1);
					Tab[(X1 + X2)/2][(Y1 + Y2)/2][0] = false;
					Pino_P = false;
				}
			}
		}
		else if (Edita_I) // Se é o tabuleiro Inicial:
		{
			if (P.Status == 0) // Se é pino, vira buraco
			{
				Tab_I[P.Tabuleiro_Y][P.Tabuleiro_X][0] = false;
				P.MudaStatus(1);
			}
			else if (P.Status == 1) // Se é buraco, vira vazio
			{
				Tab_I[P.Tabuleiro_Y][P.Tabuleiro_X][1] = false;
				P.MudaStatus(2);
			}
			else // Se é vazio, vira pino
			{
				Tab_I[P.Tabuleiro_Y][P.Tabuleiro_X][0] = true;
				Tab_I[P.Tabuleiro_Y][P.Tabuleiro_X][1] = true;
				P.MudaStatus(0);
			}
		}
		else // Se é o tabuleiro Final:
		{
			if (P.Status == 0) // Se é pino, vira buraco
			{
				Tab_F[P.Tabuleiro_Y][P.Tabuleiro_X][0] = false;
				P.MudaStatus(1);
			}
			else if (P.Status == 1) // Se é buraco, vira pino
			{
				Tab_F[P.Tabuleiro_Y][P.Tabuleiro_X][0] = true;
				P.MudaStatus(0);
			} // Se é vazio não muda
		}
	}

	public void MostraTabuleiro()
	{
		if (Edita_I)
		{
			int i, j;
			for (i = 1; i <= Altura; i++)
				for (j = 1; j <= Largura; j++)
			{
				if (Tab_I[i][j][0]) // Se é pino
					PinosTabuleiro[i][j].MudaStatus(0);
					else if (Tab_I[i][j][1]) // Se é buraco
						PinosTabuleiro[i][j].MudaStatus(1);
						else // Se é vazio
							PinosTabuleiro[i][j].MudaStatus(2);
			}
		}
		else
		{
			int i, j;
			for (i = 1; i <= Altura; i++)
				for (j = 1; j <= Largura; j++)
			{
				if (!Tab_I[i][j][1]) // Se no tabuleiro inicial é vazio, aqui também é
				{
					PinosTabuleiro[i][j].MudaStatus(2);
					Tab_F[i][j][0] = Tab_F[i][j][1] = false;
				}
				else if (Tab_F[i][j][0]) // Se é pino
					{
						PinosTabuleiro[i][j].MudaStatus(0);
						Tab_F[i][j][0] = Tab_F[i][j][1] = true;
					}
					else // Se é buraco
						{
							PinosTabuleiro[i][j].MudaStatus(1);
							Tab_F[i][j][0] = false;
							Tab_F[i][j][1] = true;

						}
			}
		}

	}

	
	public void Novo_OK(int L, int H)
	{ //Vai criar um tabuleiro novo
		if ((L > MAX_Pinos) || (H > MAX_Pinos) || (L < 1) || (H < 1))
		{
			Mensagem.MostraMensagem(this, "Erro", "O número de colunas e linhas deve estar entre 1 e " + String.valueOf(MAX_Pinos) + "   ");
		}
		else
		{
			Status.setText("Edite o tabuleiro usando o mouse");
			Largura = L;
			Altura = H;
			dispose();
			new EP_1(Largura, Altura, TamanhoPinos);
		}
	}

	public void Novo_Tamanho()
	{ // vai mudar de tamanho
			if ((TamanhoPinos = Integer.parseInt(Tamanho.T.getText())) < MIN_TPinos)
			{
				Mensagem.MostraMensagem(this, "Erro", "O tamanho dos pinos deve ser no mínimo " + String.valueOf(MIN_TPinos) + "   ");
			}
			else
			{
				for (int i = 1; i <= Altura; i++)
					for (int j = 1; j <= Largura; j++) PinosTabuleiro[i][j].MudaTamanho(TamanhoPinos);
				pack();
			}
	}

	public boolean Ler_Arq(File NomeArq)
	{// Lê os arquivos
		try
		{
			FileInputStream Entrada = new FileInputStream(NomeArq);
			DataInputStream arquivo = new DataInputStream(Entrada);
			int largura = arquivo.readInt();
			int altura = arquivo.readInt();
			if (IO_F && !((Largura == largura) && (altura == altura))) return false;
			Largura = largura;
			Altura = altura;
			Tab_IO = new boolean[Altura + 2][Largura + 2][2];
			int i, j;
			for (i = 1; i <= Altura; i++)
				for (j = 1; j <= Largura; j++)
			{
				Tab_IO[i][j][0] = arquivo.readBoolean();
				Tab_IO[i][j][1] = arquivo.readBoolean();
			}
			Entrada.close();
		}
		catch (IOException e)
		{
			return false;
		}
		if (!IO_F)// Se é tabuleiro inicial
		{
			Novo_OK(Largura, Altura); // Cria um tabuleiro novo
		}
		else // se só vai ler o tabuleiro final
		{
			int i, j;
			for (i = 1; i <= Altura; i++)
				for (j = 1; j <= Largura; j++)
			{
				Tab_F[i][j][0] = Tab_IO[i][j][0];
				Tab_F[i][j][1] = Tab_IO[i][j][0];
			}
		}
		Status.setText("Edite o tabuleiro usando o mouse");
		IO_F = false;
		MostraTabuleiro();
		return true;
	}

	public boolean Gravar_Arq(File NomeArq)
	{//Grava o arquivo
		if ((NomeArq.delete()) || !NomeArq.exists())
		{
			try
			{
				FileOutputStream Saída = new FileOutputStream(NomeArq);
				DataOutputStream arquivo = new DataOutputStream(Saída);
				arquivo.writeInt(Largura);
				arquivo.writeInt(Altura);
				int i, j;
				for (i = 1; i <= Altura; i++)
					for (j = 1; j <= Largura; j++)
				{ // Grava
					arquivo.writeBoolean(Tab_IO[i][j][0]);
					arquivo.writeBoolean(Tab_IO[i][j][1]);
				}
				Saída.close();
			}
			catch (IOException e)
			{
				return false;
			}
			Tab_IO = new boolean[Altura][Largura][2];
			return true;
		}
		return false;
	}


    public boolean handleEvent(Event e)
	{ // Função para reconhecer o pedido de saída do usuário
		if (e.id == Event.WINDOW_DESTROY)
		{
			return action(e, "Sair");
		}
		else if ((e.id == Event.ACTION_EVENT) && (e.target instanceof Pinos))
			PinoPressionado(((Pinos) e.target));
		return super.handleEvent(e);
	}


	public boolean action(Event evt, Object arg)
	{// Reconhece as ações do usuário
		if (evt.target instanceof Checkbox) // Reconhece de forma compatível com diversas VM
		{
			if (CRestar.getState())
			{
				Restar_N.enable();
			}
			else
			{
				Restar_N.disable();
			}
			return true;
		}
		else if ("Novo Tabuleiro Inicial...".equals(arg))
		{
			Novo.MostraMensagem(this);
			if (!Novo.Continuar)
				return true;
			Novo_OK(Integer.parseInt(Novo.X.getText()), Integer.parseInt(Novo.Y.getText()));
			return true;
		}
		else if ("Abrir Tabuleiro Inicial...".equals(arg))
		{
			IO = true;
			Arquivos.MostraMensagem(this, "Abrir", "Digite o nome do Arquivo:");
			if (!Arquivos.Continuar)
			{
				IO = false;
				return true;
			}
			Entrada = new File(Arquivos.Nome_Arq.getText());
			if (!(Entrada.exists() && Ler_Arq(Entrada)))
			{
				Mensagem.MostraMensagem(this, "Erro", "Não foi possível ler do arquivo especificado");
			}
			return true;
		}
		else if ("Abrir Tabuleiro Final...".equals(arg))
		{
			IO_F = true;
			Arquivos.MostraMensagem(this, "Abrir", "Digite o nome do Arquivo:");
			if (!Arquivos.Continuar)
			{
				IO_F = false;
				return true;
			}
			Entrada = new File(Arquivos.Nome_Arq.getText());
			if (!(Entrada.exists() && Ler_Arq(Entrada)))
			{
				Mensagem.MostraMensagem(this, "Erro", "Não foi possível ler do arquivo especificado");
			}
			return true;
		}
		else if ("Salvar Tabuleiro Inicial...".equals(arg))
		{
			Tab_IO = Tab_I;
			Arquivos.MostraMensagem(this, "Gravar", "Digite o nome do Arquivo:");
			if (!Arquivos.Continuar) return true;
			show();
			Saída = new File(Arquivos.Nome_Arq.getText());
			if (!Gravar_Arq(Saída))
			{
				Mensagem.MostraMensagem(this, "Erro", "Não foi possível gravar o arquivo especificado");
			}
			return true;
		}
		else if ("Salvar Tabuleiro Final...".equals(arg))
		{
			Tab_IO = Tab_F;
			Arquivos.MostraMensagem(this, "Gravar", "Digite o nome do Arquivo:");
			if (!Arquivos.Continuar) return true;
			Saída = new File(Arquivos.Nome_Arq.getText());
			show();
			if (!Gravar_Arq(Saída))
			{
				Mensagem.MostraMensagem(this, "Erro", "Não foi possível gravar o arquivo especificado");
			}
			return true;
		}
		else if ("Encher o Tabuleiro".equals(arg))
		{
			boolean[][][] Tab_T;
			if (Edita_I) Tab_T = Tab_I;
			else Tab_T = Tab_F;
			int i, j;
			for (i = 1; i <= Altura; i++)
				for (j = 1; j <= Largura; j++)
					if (Tab_T[i][j][1])
					{
						Tab_T[i][j][0] = true;
						PinosTabuleiro[i][j].MudaStatus(0);
					}
			return true;
		}
		else if ("Esvaziar o Tabuleiro".equals(arg))
		{
			boolean[][][] Tab_T;
			if (Edita_I) Tab_T = Tab_I;
			else Tab_T = Tab_F;
			int i, j;
			for (i = 1; i <= Altura; i++)
				for (j = 1; j <= Largura; j++)
					if (Tab_T[i][j][1])
					{
						Tab_T[i][j][0] = false;
						PinosTabuleiro[i][j].MudaStatus(1);
					}
			return true;
		}
		else if ("Resetar o Tabuleiro".equals(arg))
		{
			if (Edita_I)
			{
				int i, j;
				for (i = 1; i <= Altura; i++)
					for (j = 1; j <= Largura; j++)
					{
						Tab_I[i][j][0] = Tab_I[i][j][1] = false;
						PinosTabuleiro[i][j].MudaStatus(2);
					}
			}
			return true;
		}
		else if ("Mudar Tamanho dos Pinos...".equals(arg))
		{
			Tamanho.MostraMensagem(this);
			if (!Tamanho.Continuar)
				return true;
			Novo_Tamanho();
			return true;
		}
		else if ("Reiniciar".equals(arg))
		{
			Pino_P = false;
			MostraTabuleiro();
			int i, j;
			for (i = 1; i <= Altura; i++)
				for (j = 1; j <= Largura; j++)
				{
					Tab[i][j][0] = Tab_I[i][j][0];
					Tab[i][j][1] = Tab_I[i][j][1];
				}
			return true;
		}
		else if (evt.target instanceof CheckboxMenuItem)
		{// vai testar qual dos botões foi pressionado de forma compatível com diversas VM
			if (SJogar.getState() != jogar)
			{
				jogar = SJogar.getState();
				if (jogar)
				{
					Reiniciar.enable();
					Editar.disable();
					Edita_I = true;
					Inicial.setState(true);
					Final.setState(false);
					Resetar.enable();
					MostraTabuleiro();
					int i, j;
					for (i = 1; i <= Altura; i++)
						for (j = 1; j <= Largura; j++)
						{
							Tab[i][j][0] = Tab_I[i][j][0];
							Tab[i][j][1] = Tab_I[i][j][1];
						}
					Status.setText("Selecione a posição inicial e final para mover");
				}
				else
				{
					Reiniciar.disable();
					Editar.enable();
					MostraTabuleiro();
					Status.setText("Edite o tabuleiro usando o mouse");
				}
			}
			else if (Inicial.getState() && Final.getState()) // Se o usuário selecionou diferente
			{
				Restar_Arq.enable();
				Edita_I = !Edita_I;
				Resetar.enable(Edita_I);
				Inicial.setState(Edita_I);
				Final.setState(!Edita_I);
				MostraTabuleiro();
			}
			else
			{
				Inicial.setState(Edita_I);
				Final.setState(!Edita_I);
			}
			return true;
		}
		else if ("Sobre o EP 1...".equals(arg))
		{
			Mensagem.MostraMensagem(this, "Sobre o EP 1", "EP 1 Desenvolvido por Caetano Jimenez Carezzato      ");
		}
		else if ("Sair".equals(arg))
		{
			Component c[] = getComponents();
			for (int i = 0; i < c.length; i++)
				c[i].handleEvent(evt);
			dispose();
			System.exit(0);
			return true;
		}
		else if ("Resolver".equals(arg))
		{
			if (jogar) // se está jogando
			{
				Reiniciar.disable();
				SJogar.setState(false);
				jogar = false;
				Editar.enable();
				Status.setText("Edite o tabuleiro usando o mouse");
				int i, j;
				for (i = 1; i <= Altura; i++)
					for (j = 1; j <= Largura; j++)
				{ // Vai fazer o jogo como inicial
					Tab_I[i][j][0] = Tab[i][j][0];
					Tab_I[i][j][1] = Tab[i][j][1];
				}
			}
			Edita_I = true;
			Inicial.setState(true);
			Final.setState(false);
			Resetar.enable();
			MostraTabuleiro();
			Resolve_Tabuleiro();
			return true;
		}
		return false;
	}
}