Inicio     |     Sobre     |     GitHub     |     Games     |     Contato                        

sexta-feira, 12 de abril de 2019

Resumo Semanal de Pesquisa: Controlador para testes de envio e recebimento de informação




Dando continuidade ao projeto sendo desenvolvido, essa semana foi criado um controlador manual como intuito não só de controlar o personagem e testar os comandos do Project Malmo, mas também de facilitar certas ações como adicionar objetos no mapa, ou visualizar os status do agente. Também foi feito um primeiro planejamento da interação entre os sistemas usados e da construção do MECA para essa aplicação. Também foi feito o planejamento de como será o ambiente de testes.


Controlador Manual


   Para fixar o uso dos comandos do Project Malmo e testar o envio e recebimento de informação entre o Minecraft e o Project Malmo em Java foi decidido construir um sistema simples onde fosse possível usar o máximo de informação. Então iniciei o desenvolvimento de um controlador gráfico manual que poderá ser útil não só agora nos testes simples mas também futuramente, facilitando a visualização do funcionamento geral do sistemas.


    O controlador não precisa necessariamente ser usado, o Project Malmo funciona diretamente se executado do código. Há uma verificação se o modo visual está ou não em uso. Inicialmente o controlador possui um botão que inicia o experimento e um que finaliza e fecha o mesmo. Implementei também uma divisão em abas contendo as abas "Control" onde está a interface de controle manual do agente, "View"  onde será possível ver toda a grade de visão do agente, as ultimas ações executadas ou em execução e o que há em sua bolsa. Há uma aba "World" onde será possível modificar o ambiente, criando objetos como blocos, alimentos etc.. E também mais a diante será implementada a aba "Mind" onde será possível acompanhar o funcionamento da mente do agente.


   Até o momento foi implementado apenas o controlador do agente, na próxima semana será dada a continuidade do desenvolvimento do controlador. Serão implementadas as ações de criação de objetos e blocos no ambiente, e também a visualização dos status do agente. A aba Mind será implementada após o uso e funcionamento do MECA nesse projeto.

Ambiente de testes e experimentos

    Jogos digitais costumam oferecer uma estrutura de progressão que faz com que os jogos não sejam nem muito fáceis e nem muito desafiadores, e que de certa forma auxilia o jogador em seu aprendizado. Para ser possível aprender é preciso erros e acertos, inclusive quando se fala de um sistema inteligente, seja usando aprendizado por reforço ou uma arquitetura cognitiva, as falhas e sucessos é o que faz o sistema de certa forma entender as regras.

   Com base nessa ideia de progressão foi criada uma estrutura para o ambiente, uma espécie que playground, onde o agente iniciará o experimento em um ponto central (X = 0, Y = 11 e Z = 0). O ambiente será dividido em 3 áreas que vou chamar de quadrantes.

   Em cada quadrante haverá um aumento significativo na variedade de blocos, na variedade de itens, nos tipos de animais e monstros sendo criados e nas recompensas. Ou seja, quanto mais longe o agente vai, maior será o numero de informações e situações possíveis, maiores serão os perigos, porém maior serão os prêmios. 

Quadrante 1:


Quadrante 2:



Quadrante 3:


Cubos, Estruturas e outros objetos presentes no experimento:



   No desenvolvimento do ambiente para facilitar o controle de objetos, blocos e estruturas geradas eu criei algumas funções que podem ser usadas para criar estruturas como árvores, casas e lagos apenas para ter um controle de posição e quantidade. Algumas regras básicas do desenvolvimento do ambiente são:

  Tendo em mente que os pontos de satisfação do agente caem com o tempo (sua necessidade de riqueza e exploração aumentam com o tempo, as necessidades de se alimentar só se destaca quando a fome aumenta e sua necessidade de sobrevivência se destaca quando perde vida).

  Os objetos aparecem com menor frequência no primeiro quadrante, e com maior frequência respectivamente nos quadrantes 2 e 3.

   Pão só aparece perto de casa, maçãs aparecem perto de árvores, cenouras e melancias aparecem com mais frequência perto de arvores e bolos só aparecem próximos a lagos de lava e cavernas.

   O agente morre se se afogar, se cair na lava, se cair de alturas muito grandes, se a vida for zerada por qualquer motivo (fome ou por ser atacado). Se o agente morrer antes de terminar o tempo de simulação ele renascerá na casa inicial (quadrante 1) e continuará com seu conhecimento e pontuação antes de morrer.

   O conhecimento e pontuação só é zerado quando o tempo de simulação é finalizado e uma nova simulação é iniciada.

   São 33 objetos de contato possíveis para o agente. O mesmo marcará mais pontos se cumprir com maestria todas suas necessidades.

Códigos


Os códigos em desenvolvimento estão disponíveis no GitHub, nessa página <https://github.com/carolhcs/ExpMalmoMeca2/tree/master/src/expmalmomeca2>.

import com.microsoft.msr.malmo.*;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.json.*;
/**
*
* @author carol
*/
public class ExpMalmoMeca2 {
static
{
System.loadLibrary("MalmoJava");
}
/**
* @param args the command line arguments
*/
//funcions
public static WorldState w_state;
public static boolean playJFrame = false; //Verificar se o JFrame está rodando
public static String jfCommands = "null"; //string publica que receberá os comandos
public static int jfTipo = 0; //Tipo (ex: item, bloco, mob)
public static String jfDrawName = "null"; //Nome do que sera criado
public static int jfX, jfY, jfZ = 0; //X, Y e Z (posição) para criar item
public static MECAmalmoJFrame jf = new MECAmalmoJFrame(); //Cria um objeto para receceber os comandos do jframe
//Go experiment
public static void main(String argv[]) {
playJFrame = jf.programPlay; //verifica se está rodando o jframe
//Create a new environment
String missionXML = ""; //Crio uma string que receberá o xml da função a ser usada
MalmoEnvironments Environment = new MalmoEnvironments(); //crio um novo ambiente e defino a variavel que passará a string com o xml
missionXML = Environment.mainWorld(); //passo o valor da função para a string do xml
//Create a new Agent
AgentHost agent_host = new AgentHost();
MalmoAgent agent = new MalmoAgent(); //New MalmoAgent object
agent_host = agent.agent_host; //New Host build in MalmoAgent class
try {
StringVector args = new StringVector();
args.add("ExpMalmoMeca2");
for( String arg : argv )
args.add( arg );
agent_host.parse( args );
}
catch( Exception e ) {
System.err.println( "ERROR: " + e.getMessage() );
System.err.println( agent_host.getUsage() );
System.exit(1);
}
if( agent_host.receivedArgument("help") ) {
System.out.println( agent_host.getUsage() );
System.exit(0);
}
MissionSpec my_mission = null; //Criar missão
try {
my_mission = Environment.newMission(missionXML); //Receber dados de missão da classe environment
Environment.drawMission(); //Desenhar outras especificações da missão em código
MissionRecordSpec my_mission_record = new MissionRecordSpec();
try {
agent_host.startMission( my_mission, my_mission_record );
}
catch (MissionException e) {
System.err.println( "Error starting mission: " + e.getMessage() );
System.err.println( "Error code: " + e.getMissionErrorCode() );
// We can use the code to do specific error handling, eg:
if (e.getMissionErrorCode() == MissionException.MissionErrorCode.MISSION_INSUFFICIENT_CLIENTS_AVAILABLE)
{
// Caused by lack of available Minecraft clients.
System.err.println( "Is there a Minecraft client running?");
}
System.exit(1);
}
} catch (Exception ex) {
Logger.getLogger(ExpMalmoMeca2.class.getName()).log(Level.SEVERE, null, ex);
}
//Loop until mission starts:
WorldState world_state;
System.out.print( "Waiting for the mission to start" );
do {
System.out.print( "." );
try {
Thread.sleep(10);//Thread.sleep(10);
} catch(InterruptedException ex) {
System.err.println( "User interrupted while waiting for mission to start." );
return;
}
world_state = agent_host.getWorldState();
//world_state = agent.world_state;
w_state = world_state;
for( int i = 0; i < world_state.getErrors().size(); i++ )
System.err.println( "Error: " + world_state.getErrors().get(i).getText() );
} while( !world_state.getIsMissionRunning() );
System.out.println( "" );
System.out.println( "Mission running" );
//Commands

playJFrame = jf.programPlay;
if (playJFrame == true){
getStatsJFrame();
sendStatsJFrame();
agent_host.sendCommand(jfCommands);
}
do {
try {
Thread.sleep((long) 0.1);
} catch (InterruptedException ex) {
Logger.getLogger(ExpMalmoMeca2.class.getName()).log(Level.SEVERE, null, ex);
}
world_state = agent_host.getWorldState();
//world_state = agent.world_state;
w_state = world_state;
for( int i = 0; i < world_state.getErrors().size(); i++ ) {
TimestampedString error = world_state.getErrors().get(i);
System.err.println( "Error: " + error.getText() );
}
//Commands
gridView();
//Verifica se o jFrame está rodando, se sim pegar e enviar dados para ele!
playJFrame = jf.programPlay; //jframe está rodando? true or false?
if (playJFrame == true){
getStatsJFrame();
sendStatsJFrame();
agent_host.sendCommand(jfCommands);
System.out.println("Rodando: "+playJFrame+"Comando: "+jfCommands);
}
//Commands End
} while( world_state.getIsMissionRunning() );
System.out.println( "Mission ended" );
//Mission has ended.
//END
}
//Grade de visão do agente
public static void gridView(){
if (w_state.getNumberOfObservationsSinceLastState() > 0){
TimestampedStringVector observations = w_state.getObservations();
if (observations.isEmpty())System.out.println("Observation Vazio!!");
String obs_text = observations.get((int) (observations.size() - 1)).getText();
JSONObject observation = new JSONObject(obs_text);
JSONArray blocks = observation.getJSONArray("floor3x3");
String grid[] = {"","","","","","","","",""};
for (int i = 0; i < 9; ++i) {
String block = blocks.getString(i);
grid[i] = block;
//System.out.println("Posição: "+ i + "=" +block+ "\n");
if (i % 3 == 0) System.out.print("\n");
System.out.print("|"+block+"|");
}
System.out.print("\n");
}
}
public static void getStatsJFrame (){
jfCommands = jf.jfCommands;

}
public static void sendStatsJFrame (){
}
}

import com.microsoft.msr.malmo.*;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.json.*;
/**
*
* @author carol
*/
public class MalmoAgent {
static
{
System.loadLibrary("MalmoJava");
}
AgentHost agent_host = new AgentHost();

public void moveForward(){
agent_host.sendCommand("move 0.5");
}
public void moveBackward(){
agent_host.sendCommand("move -0.5");
}
public void moveLeft(){
agent_host.sendCommand("strafe -0.5");
}
public void moveRight(){
agent_host.sendCommand("strafe 0.5");
}
public void lookUp(){
agent_host.sendCommand("pitch -0.2");
}
public void lookDown(){
agent_host.sendCommand("pitch 0.2");
}
public void turnLeft(){
agent_host.sendCommand("turn -0.5");
}
public void turnRight(){
agent_host.sendCommand("turn 0.5");
}
public void jump(){
agent_host.sendCommand("jump 1");
}
public void crouch(){
agent_host.sendCommand("crouch 1");
}
public void attack(){
agent_host.sendCommand("attack 1");
}
public void use(){
agent_host.sendCommand("use 1");
}
public void justWait(){
try {
Thread.sleep(1);//Wait a second until we are looking in roughly the right direction
} catch (InterruptedException ex) {
Logger.getLogger(ExpMalmoMeca2.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void takeObjectInBag (int position){
String pos = Integer.toString(position);
agent_host.sendCommand("hotbar."+pos+" 1");//Press the hotbar key
agent_host.sendCommand("hotbar."+pos+" 0");//Release hotbar key - agent should now be holding diamond_pickaxe
}
public void stopAgent(){
agent_host.sendCommand("move 0");
agent_host.sendCommand("strafe 0");
agent_host.sendCommand("pitch 0");
agent_host.sendCommand("turn 0");
agent_host.sendCommand("jump 0");
agent_host.sendCommand("crouch 0");
agent_host.sendCommand("attack 0");
agent_host.sendCommand("use 0");
}
//Ações complexas
public void breakBlock(){
}
public void lookForItemInBag(){
}
public void moveToPosition(){
}
public void toRunAway(){
}
public void toStalk(){
}
public void fight(){
}
}


public String mainWorld (){
String environment_clareira = "";
String environment_florest = "";
String environment_simple = "";
//<FlatWorldGenerator generatorString=\"3;7,44*49,73,35:1,159:4,95:13,35:13,159:11,95:10,159:14,159:6,35:6,95:6;12;\"/>
//<FlatWorldGenerator generatorString=\"3;3*7,5*3,2;1;lake,lava_lake\"/>
missionXML = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalon=\"no\" ?>"
+"<Mission xmlns=\"http://ProjectMalmo.microsoft.com\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">"
+"<About><Summary>Experimento a Clareira</Summary></About>"
+"<ServerSection>"
+"<ServerInitialConditions>"
+"<AllowSpawning>true</AllowSpawning>"
+"<AllowedMobs>Pig Sheep Cow Chicken Ozelot Rabbit Villager</AllowedMobs>"
+"<Time><StartTime>12000</StartTime><AllowPassageOfTime>false</AllowPassageOfTime></Time>"
+"<Weather>clear</Weather>"
+"</ServerInitialConditions>"
+"<ServerHandlers>"
+"<FlatWorldGenerator generatorString=\"3;5*7,5*3,2;4;\"/>"
+"<DrawingDecorator>"
+ "<DrawBlock x=\"-27\" y=\"70\" z=\"0\" type=\"air\"/>"
+ "<DrawBlock x=\"5\" y=\"13\" z=\"0\" type=\"redstone_block\"/>"
+ "<DrawItem x=\"7\" y=\"12\" z=\"0\" type=\"diamond\"/>"
+ "<DrawBlock x=\"3\" y=\"12\" z=\"0\" type=\"mob_spawner\" variant=\"Zombie\"/>"
+ "</DrawingDecorator>"
+"<ServerQuitFromTimeUp timeLimitMs=\"120000\"/>"
+"<ServerQuitWhenAnyAgentFinishes/>"
+"</ServerHandlers>"
+"</ServerSection>"
+"<AgentSection mode=\"Survival\">"
+"<Name>MECAgentBot</Name>"
+"<AgentStart>"
+"<Placement x=\"0\" y=\"12\" z=\"0\" yaw=\"90\"/>"
+"<Inventory><InventoryItem slot=\"0\" type=\"diamond_pickaxe\"/></Inventory>"
+"</AgentStart>"
+"<AgentHandlers>"
+"<ObservationFromFullStats/>"
+"<ObservationFromGrid>"
+"<Grid name=\"floor3x3\">"
+"<min x=\"-1\" y=\"-1\" z=\"-1\"/>"
+"<max x=\"1\" y=\"-1\" z=\"1\"/>"
+"</Grid>"
+"</ObservationFromGrid>"
+"<ContinuousMovementCommands turnSpeedDegs=\"180\"/>"
+"</AgentHandlers>"
+"</AgentSection>"
+"</Mission>";
return missionXML;
}
public void drawMission (){
my_mission.setSummary("Experimento Malmo MECA");
my_mission.drawBlock( 5, 10, 0, "redstone_block" );
my_mission.drawBlock( 5, 11, 0, "redstone_block" );
my_mission.drawItem(0,10,12,"diamond_pickaxe");
my_mission.drawItem(0,10,0,"diamond_pickaxe");
my_mission.drawBlock(0,11,15,"mob_spawner");
}


Comunicação entre Sistemas e Estrutura do MECA (versão 1)


   Inicialmente a ideia de comunicação entre os sistemas pode ser esboçada da seguinte forma:


   Observando a figura anterior é possível entendermos que teremos 3 sistemas conversando entre si. O primeiro pode ser considerado como a mente do agente (MECA), responsável por entender o mundo, processar informações e tomar decisões. O segundo pode ser entendido como o corpo do agente (Project Malmo e controladores), é um intermediário entre a mente e o ambiente, responsável por interagir com o ambiente, causar as mudanças e detectar as situações. Já o terceiro é o próprio ambiente (Minecraft), a imagem abaixo talvez represente melhor o funcionamento em conjunto dos 3 sistemas.


   Vale ressaltar que como o controlador ainda está em desenvolvimento e o uso do MECA está iniciando agora, a estrutura acima está sujeita a mudanças. O Controlador é mais uma interface de testes e um facilitador na hora de criar objetos ou até de visualizar as informações do agente e da simulação. A classe MalmoEnvironments contem a estrutura das missões e dos ambientes em XML e no formato de funções capazes de gerar estruturas. A classe MalmoAgent servirá como um intermediário de ações a serem executadas (simples ou complexas). Já o MalmoMain é a classe principal, encarregada de iniciar o experimento e todas as outras classes (p.s.: a execução do controlador é opcional, não interfere na execução das outras classes).

    O processo pode ser dividido em ciclos, após o ambiente ser criado e o experimento iniciar o ciclo consiste em: Agente ver os objetos em seu campo de visão > enviar essas informações ao MECA > o MECA irá processar as informações e definir a melhor ação a ser tomada para aquela situação > a ação definida será enviada para o Project Malmo que irá executar a ação > se a ação causar mudanças no ambiente é nessa etapa que isso acontecerá, e logo após o ciclo é reiniciado. O processamento feito pela arquitetura MECA pode ser feito de mais de uma forma e irá depender da entrada, das informações que o mesmo já possui e da satisfação do agente em relação ao resultado de suas ultimas ações.

   Essa é a estrutura do MECA, com base nessa estrutura vamos desenvolver a mente do nosso agente:


A principio vamos apenas passar para a arquitetura algumas informações que já são de nosso conhecimento (a estrutura dessa arquitetura ainda sofrerá muitas mudanças):


🚧 EM CONSTRUÇÃO...

Referências



Nenhum comentário:

Postar um comentário