Como lidar com certificados SSL inválidos no Java

As vezes trabalhando com SOAP, talvez você tenha o caso de https, SSL, com certificado inválido.

Nesses casos é possível configurar a aplicação para aceitar qualquer certificado.

Por exemplo, um erro comum quando a aplicação não aceita um certificado inválido:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
run:
AxisFault
 faultCode: {http://schemas.xmlsoap.org/soap/envelope/}Server.userException
 faultSubcode: 
 faultString: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
 faultActor: 
 faultNode: 
 faultDetail: 
	{http://xml.apache.org/axis/}stackTrace:javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1611)
	at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:187)
	at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:181)
	at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1035)
	at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:124)
	at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:516)
	at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:454)
	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:884)
	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1112)
	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1139)
	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1123)
	at org.apache.axis.components.net.JSSESocketFactory.create(JSSESocketFactory.java:186)
	at org.apache.axis.transport.http.HTTPSender.getSocket(HTTPSender.java:191)
	at org.apache.axis.transport.http.HTTPSender.writeToSocket(HTTPSender.java:404)
	at org.apache.axis.transport.http.HTTPSender.invoke(HTTPSender.java:138)
	at org.apache.axis.strategies.InvocationStrategy.visit(InvocationStrategy.java:32)
	at org.apache.axis.SimpleChain.doVisiting(SimpleChain.java:118)
	at org.apache.axis.SimpleChain.invoke(SimpleChain.java:83)
	at org.apache.axis.client.AxisClient.invoke(AxisClient.java:165)
	at org.apache.axis.client.Call.invokeEngine(Call.java:2784)
	at org.apache.axis.client.Call.invoke(Call.java:2767)
	at org.apache.axis.client.Call.invoke(Call.java:2443)
	at org.apache.axis.client.Call.invoke(Call.java:2366)
	at org.apache.axis.client.Call.invoke(Call.java:1812)
	at com.siemens.hipath.hipath8000.assistant.api.v310.soap.HiPath8000AssistantAPISoapBindingStub.getApiServerVersion(HiPath8000AssistantAPISoapBindingStub.java:1977)
	at complexclient.ComplexClient.main(ComplexClient.java:20)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:294)
	at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:200)
	at sun.security.validator.Validator.validate(Validator.java:218)
	at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:126)
	at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:209)
	at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:249)
	at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1014)
	... 22 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:174)
	at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:238)
	at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:289)
	... 28 more
 
	{http://xml.apache.org/axis/}hostname:patrick-c318421

Para contornar isso você pode aceitar qualquer certificado na sua aplicação, da seguinte forma:

package complexclient;
 
import java.net.MalformedURLException;
import java.net.URL;
import java.rmi.RemoteException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.security.SecureRandom;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.xml.rpc.ServiceException;
 
public class ComplexClient {
 
    public static void main(String[] args) throws Exception {
        // Configure the SSLContext with a TrustManager
        SSLContext ctx = SSLContext.getInstance("TLS");
        ctx.init(new KeyManager[0], new TrustManager[] {new DefaultTrustManager()}, new SecureRandom());
        SSLContext.setDefault(ctx);
 
        ... código da sua aplicação aqui ...
    }
 
    private static class DefaultTrustManager implements X509TrustManager {
 
        @Override
        public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException {
        }
 
        @Override
        public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException {
        }
 
        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }
 
    }
}
Posted in Java at maio 28th, 2012. 4 Comments.

Construção de um Agente Inteligente que Jogue Mario

Com esse post você vai obter o resultado abaixo:


Nas últimas semanas eu veio estudando a fundo a técnica de inteligência artificial de redes neurais. Não é toa que praticamente os meus dois últimos posts foram sobre esse assunto.

Tudo começou com a ideia de criar um agente inteligente que conseguisse jogar Mario sozinho, a minha pretensão nunca foi muito grande, eu apenas tinha a ideia de fazer algo simples que funcionasse, mas não tinha a grande pretensão de fazer um super agente inteligente capaz de passar por vários níveis diferentes de dificuldade do jogo Mario. Partindo disso, com o único objetivo de aprendizado, eu decidi usar a técnica de redes neurais e fazer o Mario passar pela primeira fase.

Para simplificar mais ainda, eu fiz por padrão o Mario andar para a direita e a única ação que é aplicada inteligência artificial é a decisão se o Mario deve ou não pular.

O código do jogo Mario eu obtive do site: http://www.marioai.org/gameplay-track/getting-started, esse é o site da competição que tem o foco na criação de agentes inteligentes e criação de fases para o Mario, usando inteligência artificial. Eles não disponibilizam o código da parte de inteligência artificial, cabe a cada participante implementar o seu algoritmo e enviar para a competição, o melhor agente inteligente vence. Eu também não tinha a ideia de vencer essa competição, não tenho nível e conhecimento suficiente para isso ainda.

Antes de entrarmos em código e implementação, é importante entender do que consiste a técnica de redes neurais.

De forma resumida, uma rede neural é constituída por um neurônio (perceptron), que possui a seguinte estrutra:

  • Dendritos;
  • Corpo celular;
  • Axônio.

O dendrito(s) corresponde(m) as entradas (inputs) do neurônio, o corpo celular é responsável pelo processamento e o axônio representa a saída (output).

O algoritmo de uma rede neural se resume em:

  • Os dendritos recebem um valor de entrada cada um, esse valor é multiplicado por um peso, uma soma ponderada na verdade;
  • O neurônio, corpo celular, recebe a soma ponderada e através de uma verificação matemática, decide o valor de saída para o neurônio. Isso é conhecido por função de ativação, que em muitas vezes se resume em um if que testa se a soma é maior ou menor que zero;
  • O axônio transmite essa saída

Você pode pensar “Hum muito bem, onde está a inteligência artificial nisso?”, a inteligência artificial está no próximo passo do algoritmo, o neurônio deve ser treinado, ele deve receber um conjunto de valores de entrada para os dendritos e a saída válida, saída conhecida para esse conjunto de entradas. Com posse disso o neurônio é treinado, e o grande segredo de uma rede neural é o ajuste dos pesos que são multiplicados pelas entradas no dendritos, nessa parte que consta a inteligência artificial. O grande foco e obter os pesos ideias para que a rede neural se comporte da melhor forma, depois de encontrar esses pesos basta em usá-los sempre.

Na verdade tudo é matemática.

Agora que está claro como tudo acontece vamos ver a implementação. Vamos começar pelas estruturas de dados mais básicas e avançamos para as mais complexas.

Dendrito

Dendrite.java

package br.pucpr.neuralnetwork;
 
// Classe que representa um dendrito
public class Dendrite {
	// Valor para o dendrito
	private int value;
 
	// Método construtor
	// aceita como parâmetro:
	// * value = valor para o dendrito
	public Dendrite(int value) {
		this.value = value;
	}
 
	// Obtém o valor atual do dendrito
	public int getValue() {
		return value;
	}
}

Axônio

Axon.java

package br.pucpr.neuralnetwork;
 
// Classe que representa um axônio
public class Axon {
	// Sinal de saída
	private int sign;
 
	// Obtém o sinal do axônio
	public int getSign() {
		return sign;
	}
 
	// Define o sinal para o axônio
	public void setSign(int sign) {
		this.sign = sign;
	}
 
	// Transforma o sinal em um valor booleano
	public boolean signToBoolean() {
		if (sign == -1) {
			return false;
		}
		return true;
	}
}

Neurônio

Neuron.java

package br.pucpr.neuralnetwork;
 
// Classe que representa um neurônio
public class Neuron {
	// Dendritos
	private Dendrite[] dendrites;
	// Axônio
	private Axon axon;
	// Pesos
	private float[] weights;
	// Pesos padrões
	private float[] defaultWeights;
	// Tipo da função de ativação
	private String activationType;
	// Constante de aprendizado
	private float constantLearning;
 
	// Método construtor
	// aceita como pârametros:
	// * numberDendrites = Número de dendritos
	// * defaultWeights = Pesos padrão
	// * activationType = tipo da função de ativação
	public Neuron(int numberDendrites, float[] defaultWeights, String activationType) {
		// Define os pesos padrões
		this.defaultWeights = defaultWeights;
 
		// Se não for definida o tipo da função de ativação,
		// então define como sign
		if (activationType == null) {
			this.activationType = "sign";
		}
 
		// Pesos
		weights = new float[numberDendrites];
		// Dendritos
		dendrites = new Dendrite[numberDendrites];
 
		// Cria valores iniciais randômicos para os pesos
		for (int i = 0; i < weights.length; i++) {
			weights[i] = Util.random(-1, 1);
		}
 
		// Constante de aprendizado
		constantLearning = (float)0.0001;
		// Axônio
		axon = new Axon();
	}
 
	// Soma os dendritos com os seus pesos
	// média ponderada
	public float sumDendrites() {
		float sum = 0;
 
		if (defaultWeights != null && defaultWeights.length > 0) {
			for (int j = 0; j < defaultWeights.length; j++) {
				weights[j] = defaultWeights[j];
			}
		}
 
		for (int i = 0; i < weights.length; i++) {
			sum += dendrites[i].getValue() * weights[i];
		}
		return sum;
	}
 
	// Método de ativação
	// dependendo da soma e do tipo de ativação
	// envia o sinal -1 ou 1 para o axônio
	public void activation() {
		float sum = sumDendrites();
 
		axon.setSign(1);
		if (sum < 0) {
			axon.setSign(-1);
		}
	}
 
	// Treina o neurônio, afim de obter os melhores pesos para os dendritos
	// aceita como parâmetros:
	// * numberTimes = número de épocas
	// * percentageCorrect = percentual correto para o treinamento ser considerado bem sucedido
	// * examplesTraining = exemplos para o treinamento
	public void train(int numberTimes, int percentageCorrect, Point[] examplesTraining) {
		System.out.println("Treinamento iniciado...");
 
		// Quantidade de treinamento verificado
		int totalVerified = 0;
		// Quantidade de treinamento verificado errado
		int totalVerifiedWrong = 0;
		// Quantidade de treinamento verificado correto
		int totalVerifiedCorrect = 0;
 
		// Repete até o número de épocas ser satisfeito
		for (int i = 0; i < numberTimes; i++) {
			// Percorre todos os exemplos de treinamento
			for (int j = 0; j < examplesTraining.length; j++) {
				// Obtém a saída adivinhada pelo neurônio
				int result = guess(examplesTraining[j]);
				// Calcula o fator de mudança do peso baseado no erro
				// erro = saída desejada - saída adivinhada
				// multiplica pela constante de aprendizado
				float weightChange = constantLearning * (examplesTraining[j].getOutput() - result);
				// Ajusta os pesos baseado no fator de mudança * a entrada
				for (int k = 0; k < weights.length; k++) {
					weights[k] += weightChange * examplesTraining[j].getVals()[k];
				}
 
				// Contabiliza se o valor adivinhado foi correto ou não
				if (result == examplesTraining[j].getOutput()) {
					totalVerifiedCorrect++;
				} else {
					totalVerifiedWrong++;
				}
			}
		}
 
		// Quantidade de treinamentos verificados
		totalVerified = totalVerifiedWrong + totalVerifiedCorrect;
		float totalPercentageCorrect = ((100 * totalVerifiedCorrect ) / totalVerified);
 
		System.out.println("Treinamento terminado...");
		System.out.println("Resultados obtidos:");
		System.out.println(" - Número de épocas executadas: " + numberTimes);
 
		String indicativeSuccess = "bem sucedido";
 
		if (totalPercentageCorrect < percentageCorrect) {
			indicativeSuccess = "mal sucedido";
		}
 
		System.out.println(" - Indicativo de sucesso: Treinamento " + indicativeSuccess);
		System.out.println(" - Porcentagem correto: " + totalPercentageCorrect);
		System.out.println(" - Pesos:");
 
		if (defaultWeights != null && defaultWeights.length > 0) {
			for (int j = 0; j < defaultWeights.length; j++) {
				weights[j] = defaultWeights[j];
			}
		}
 
		for (int i = 0; i < weights.length; i++) {
			System.out.println("   - Peso " + i + ": " + weights[i]);	
		}
	}
 
	// Método que adivinha a saída esperada
	// baseada nas entradas, de acordo com os pesos
	// calculados
	public int guess(Point point) {
		// Define os valores para os dendritos
		setDendrites(point.getVals());
		// Faz a ativação
		activation();
		// Sinal de ativação
		return axon.getSign();
	}
 
	// Define os valores para os dendritos
	// de acordo com um array de valores
	public void setDendrites(int[] vals) {
		for (int i = 0; i < vals.length; i++) {
			dendrites[i] = new Dendrite(vals[i]);
		}
	}
 
	// Obtém a constante de aprendizado
	public float getConstantLearning() {
		return constantLearning;
	}
 
	// Define uma nova constante de aprendizado
	public void setConstantLearning(float constantLearning) {
		this.constantLearning = constantLearning;
	}
 
	// Obtém o axônio
	public Axon getAxon() {
		return axon;
	}
 
	// Obtém o tipo da função de ativação usada
	public String getActivationType() {
		return activationType;
	}
}

Ponto

Point.java

package br.pucpr.neuralnetwork;
 
// Classe que representa um ponto de treinamento
public class Point {
	// Valores de entrada
	private int[] vals;
	// Saída esperada
	private int output;
 
	// Método construtor
	// aceita os parâmetros:
	// * obs1 = tipo de obstáculo na posição 1
	// * obs2 = tipo de obstáculo na posição 2
	// * output = saída esperada
	public Point(int obs1, int obs2, int output) {
		vals = new int[3];
		vals[0] = obs1;
		vals[1] = obs2;
		// Bias para quando as entradas forem zero
		vals[2] = 1;
		this.output = output;
	}
 
	// Valores de entrada
	public int[] getVals() {
		return vals;
	}
 
	// Saída esperada
	public int getOutput() {
		return output;
	}	
}

Agente Inteligente

NeuralNetworkAgent.java

package ch.idsia.ai.agents.controllers;
 
import br.pucpr.neuralnetwork.Neuron;
import br.pucpr.neuralnetwork.Point;
import ch.idsia.ai.agents.Agent;
import ch.idsia.mario.engine.sprites.Mario;
import ch.idsia.mario.environments.Environment;
 
// Classe que representa um agente inteligente que utiliza rede neural
public class NeuralNetworkAgent extends BasicAIAgent implements Agent {
 
	// Neurônio
	private Neuron neuron;
	// Pontos para treinamento
	private Point[] examplesTraining;
 
	public NeuralNetworkAgent() {
		super("NeuralNetworkAgent");
 
		// Instância um neurônio
		// Com 3 dendritos, obstáculo 1, obstáculo 2 e 
		// bias para quando as primeiras entradas forem zero
		neuron = new Neuron(3, null, "sign");
 
		// Com pesos padrões
		// float[] defaultWeights = new float[3];
		// defaultWeights[0] = (float)0.12533271;
		// defaultWeights[1] = (float)-0.15752053;
		// defaultWeights[2] = (float)-0.22475332;
		// neuron = new Neuron(3, defaultWeights, "sign");
 
		// Cria os pontos para o treinamento
		setExamplesTraining();
 
		// Realiza o treinamento
		neuron.train(300, 43, examplesTraining);
 
		reset();
	}
 
	public void reset() {
		action = new boolean[Environment.numberOfButtons];
		action[Mario.KEY_RIGHT] = true;
	}
 
	public boolean[] getAction() {
		// Através dos pesos calculados no treinamento
		// tenta jogar Mario sozinho
		// Define o valor para os dendritos baseado nos obstáculos do jogo
		int[] vals = new int[2];
		vals[0] = mergedObservation[11][13];
		vals[1] = mergedObservation[11][12];
		neuron.setDendrites(vals);
 
		// Realiza ativação do neurônio, afim de obter o sinal de saída
		neuron.activation();
 
		// De acordo com o neurônio faz o Mario pular ou não
		if (neuron.getAxon().signToBoolean()) {
			if (isMarioAbleToJump) {
				action[Mario.KEY_JUMP] = true;	
			}
		} else {
			action[Mario.KEY_JUMP] = false;
		}
 
		return action;
	}
 
	// Cria os pontos para o treinamento
	public void setExamplesTraining() {
		examplesTraining = new Point[6];
		examplesTraining[0] = new Point(0, 0, -1);
		examplesTraining[1] = new Point(-10, 0, 1);
		examplesTraining[2] = new Point(20, 0, 1);
		examplesTraining[3] = new Point(-10, -10, 1);
		examplesTraining[4] = new Point(2, 0, 1);
		examplesTraining[5] = new Point(-11, 0, 1);
	}
}

Main

Main.java

package ch.idsia.scenarios;
 
import ch.idsia.ai.agents.Agent;
import ch.idsia.ai.agents.controllers.NeuralNetworkAgent;
import ch.idsia.maibe.tasks.BasicTask;
import ch.idsia.mario.environments.Environment;
import ch.idsia.mario.environments.MarioEnvironment;
import ch.idsia.tools.CmdLineOptions;
 
/**
 * Created by IntelliJ IDEA. User: Sergey Karakovskiy, sergey at idsia dot ch Date: Mar 17, 2010 Time: 8:28:00 AM
 * Package: ch.idsia.scenarios
 */
public class Main
{
    public static void main(String[] args)
    {
    	// final String argsString = "-vis on";
    	// args = argsString.split("\\s");
        final CmdLineOptions cmdLineOptions = new CmdLineOptions(args);
        final Environment environment = new MarioEnvironment();
        // final Agent agent = new ForwardAgent();
        // final Agent agent = cmdLineOptions.getAgent();
        final Agent agent = new NeuralNetworkAgent();
        // final Agent a = AgentsPool.load("ch.idsia.controllers.agents.controllers.ForwardJumpingAgent");
        final BasicTask basicTask = new BasicTask(environment, agent);
        basicTask.reset(cmdLineOptions);
        basicTask.runOneEpisode();
 
        System.out.println("cmdLineOptions.getLevelLength() = " + cmdLineOptions.getLevelLength());
        System.out.println(environment.getEvaluationInfoAsString());
        System.exit(0);
    }
}

Vamos entender como as classes acima se juntam para implementar a rede neural, a classe NeuralNetworkAgent.java possui os exemplos de treinamento, esses exemplos foram captados quando eu estava realmente jogando, por isso que a saída é conhecida, é o que se espera que o Mario faça quando ele tiver obstáculos pela frente. Além dos exemplos essa classe define o comportamento inicial do Mario que é andar para direita, a classe também realiza o treinamento, e com posse dos pesos ela abre a tela do jogo e coloca o Mario para jogar sozinho com inteligência. No código incluído está para toda vez os pesos serem calculados, é possível passar pesos padrões para o neurônio, essa parte do código está comentada, se você descomentar já irá ver o Mario jogando com os melhores pesos que eu encontrei.

A classe Point.java descreve os pontos ou ponto de entrada, ela recebe a informação se existem obstáculos na posição 1 e na posição 2 e a saída que deve existir.

A classe Dendrite.java descreve um dendrito e o seu valor de entrada.

A classe Axon.java descreve o axônio do neurônio, o sinal de saída, que também é transformado em um valor booleano.

A classe Neuron.java por sua vez que realiza todo o trabalho, cálculo dos melhores pesos e o emprego da inteligência artificial. Poder conter vários dendritos (várias entradas), uma única saída, os pesos para cada entrada e a constante de aprendizado. Inicialmente os pesos são valores randômicos, ao entrar no treinamento, os melhores pesos tentam ser encontrados, não sempre isso acontece, vai depender da quantidade de exemplos de treinamento e a quantidade de épocas. As épocas são quantas vezes o algoritmo vai ser repetido para tentar encontrar os melhores pesos para a rede neural. A constante de aprendizado é usada para alterar os pesos e tentar achar o melhor peso, as referências bibliográficas afirmam que quanto menor a constante de aprendizado, mais vai demorar para encontrar os pesos, mas os pesos encontrados são melhores e mais úteis para o funcionamento da rede.

A classe Main.java que executa o jogo e coloca todas as classes para trabalhar afim de obter a rede neural.

É claro que para o Mario rodar, é necessário ter toda o código fonte do Mario, disponibilizado no endereço que eu mencionei no começo do texto. Os códigos apresentados são apenas um agente inteligente que foi embutido no jogo do Mario.

Eu não vou entrar em mais detalhes do algoritmo, com posse dessas informações e comentários você já deve ser capaz de entender tudo que está acontecendo.

O que eu escrevi nesse texto não representa a verdade absoluta, eu ainda estou estudando o assunto, por isso algumas coisas podem estar erradas ou podem ser feitas de uma forma muito melhor. Apenas quero ajudar e propagar o conhecimento.

O código fonte está disponível em: http://github.com/patrickespake/Mario-Neural-Network-Agent

Posted in Algoritmo, Java, Rede Neural at maio 10th, 2010. 2 Comments.

Mario AI Championship 2010

Nas últimas semanas eu estou trabalhando na criação de um agente inteligente que jogue Mario. Esse agente está sendo desenvolvido para a competição “Mario AI Championship 2010″, http://www.marioai.org/.

A organização da competição disponibiliza o código fonte do Mario portado para Java. A base do código fonte permite configurar níveis de dificuldades diferentes, com poucos e muitos inimigos, é possível definir o tamanho do cenário, que é gerado de forma procedural, e o FPS do jogo.

Vence a competição o desenvolvedor que criar o melhor agente inteligente que consiga jogar Mario da melhor forma, levando em consideração matar os inimigos e coletar itens do cenário.

Para analisar todas possibilidades eu fui atrás para descobrir todas as ações que o Mario pode realizar e os sensores do ambiente do jogo.

Ações do Mario

Sensores do Ambiente

Com posse dessas informações a ideia agora é desenvolver um agente inteligente que use redes neurais para jogar Mario sozinho.

Nos próximos posts eu espero explicar e demonstrar como é a construção desse agente inteligente.

Posted in Algoritmo, Java, Jogo at abril 19th, 2010. No Comments.

 Assinar RSS Feed