Devido à natureza da pergunta, tenho que incluir muitas informações básicas (porque minha pergunta é: como restringir isso?) Dito isso, ele pode ser resumido (da melhor maneira possível) como:
Quais métodos existem para encontrar ótimos locais em espaços de pesquisa combinatória extremamente grandes?
fundo
Na comunidade de super-jogos assistida por ferramentas, procuramos fornecer entradas especialmente criadas (não geradas em tempo real) para um console ou emulador de videogame, a fim de minimizar alguns custos (geralmente o tempo até a conclusão). A forma como isso é feito atualmente está jogando o jogo quadro-a-quadro e especificar a entrada para cada quadro, muitas vezes refazer partes da corrida muitas vezes (por exemplo, o recentemente publicado corrida para The Legend of Zelda: Ocarina of Time tem um total de 198.590 tentativas).
Fazer com que essas corridas obtenham seu objetivo geralmente se resume a dois fatores principais: planejamento de rota e travessia. O primeiro é muito mais "criativo" que o segundo.
O planejamento de rotas é determinar para que lado o jogador deve navegar em geral para concluir o jogo, e geralmente é a parte mais importante da corrida. Isso é análogo a escolher qual método de classificação usar, por exemplo. A melhor classificação de bolha do mundo simplesmente não superará a classificação rápida em 1 milhão de elementos.
No desejo de perfeição, no entanto, a travessia (como a rota é realizada) também é um fator imenso. Continuando a analogia, é assim que o algoritmo de classificação é implementado. Algumas rotas nem sequer podem ser executadas sem quadros de entrada muito específicos. Esse é o processo mais tedioso de assistência à ferramenta e é o que faz com que a produção de uma execução concluída leve meses ou até anos. Não é um processo difícil (para um humano), porque se resume a tentar diferentes variações da mesma idéia até que uma seja considerada melhor, mas os humanos podem apenas tentar tantas variações em seu tempo de atenção. A aplicação de máquinas a esta tarefa parece apropriada aqui.
Meu objetivo agora é tentar automatizar o processo de travessia em geral para o sistema Nintendo 64 . O espaço de busca para este problema é muito grande demais para atacar com uma abordagem de força bruta. Um segmento n-frame de uma execução N64 possui 2 30n entradas possíveis, o que significa meros 30 quadros de entrada (um segundo a 30FPS) possui 2 900 entradas possíveis; seria impossível testar essas soluções em potencial, sem falar nas de duas horas.
No entanto, não estou interessado em tentar (ou melhor, nem vou tentar) a otimização global total de uma execução completa. Em vez disso, gostaria de, com uma entrada inicial, aproximar o ótimo local para um segmento específico de uma corrida (ou o n ótimo local mais próximo , para uma espécie de otimização semi-global) . Ou seja, dada uma rota e uma travessia inicial dessa rota: procure nos vizinhos dessa travessia para minimizar o custo, mas não degenere tentando todos os casos que possam resolver o problema.
Meu programa deve, portanto, pegar um estado inicial, um fluxo de entrada, uma função de avaliação e gerar o ótimo local minimizando o resultado da avaliação.
Estado atual
Atualmente, tenho toda a estrutura cuidada. Isso inclui a avaliação de um fluxo de entrada através da manipulação do emulador, instalação e desmontagem, configuração etc. E como um espaço reservado, o otimizador é um algoritmo genético muito básico. Ele simplesmente avalia uma população de fluxos de entrada, armazena / substitui o vencedor e gera uma nova população, modificando o fluxo do vencedor. Esse processo continua até que alguns critérios arbitrários sejam atendidos, como tempo ou número de geração.
Observe que a parte mais lenta deste programa será, de longe, a avaliação de um fluxo de entrada . Isso ocorre porque isso envolve emular o jogo por n frames. (Se eu tivesse tempo, escreveria meu próprio emulador que fornecia ganchos para esse tipo de coisa, mas, por enquanto, resta sintetizar mensagens e modificar a memória para um emulador existente de outro processo.) No meu computador principal, que é bastante moderno, a avaliação de 200 quadros leva aproximadamente 14 segundos. Como tal, eu preferiria um algoritmo (dada a opção) que minimize o número de avaliações de funções.
Eu criei um sistema na estrutura que gerencia emuladores simultaneamente. Como tal , posso avaliar vários fluxos de uma só vez com uma escala de desempenho linear, mas, na prática, o número de emuladores em execução pode ser de apenas 8 a 32 (e 32 está realmente pressionando) antes que o desempenho do sistema se deteriore. Isso significa (dada a escolha), um algoritmo que pode processar enquanto uma avaliação está sendo realizada seria altamente benéfico, porque o otimizador pode fazer algum trabalho pesado enquanto aguarda uma avaliação.
Como teste, minha função de avaliação (para o jogo Banjo Kazooie ) era somar, por quadro, a distância do jogador a um ponto do gol. Isso significava que a solução ideal era chegar o mais próximo possível desse ponto o mais rápido possível. Limitando a mutação apenas ao stick analógico, levou um dia para obter uma solução adequada . (Isso foi antes de eu implementar a simultaneidade.)
Depois de adicionar simultaneidade, ativei a mutação do pressionamento do botão A e fiz a mesma função de avaliação em uma área que exigia pulos. Com 24 emuladores em execução, demorou cerca de 1 hora para atingir a meta a partir de um fluxo de entrada inicialmente em branco, mas provavelmente precisaria durar dias para chegar a algo próximo do ideal.
Problema
O problema que enfrento é que não conheço o suficiente sobre o campo de otimização matemática para saber como modelar corretamente meu problema de otimização ! Posso seguir a idéia conceitual de muitos algoritmos, como descrito na Wikipedia, por exemplo, mas não sei como categorizar meu problema ou selecionar o algoritmo de última geração para essa categoria.
Pelo que sei, tenho um problema combinatório com uma vizinhança extremamente grande . Além disso, a função de avaliação é extremamente descontínua, sem gradiente e com muitos planaltos . Além disso, não há muitas restrições, embora eu tenha prazer em adicionar a capacidade de expressá-las, se isso ajudar a resolver o problema; Gostaria de permitir especificar que o botão Iniciar não deve ser usado, por exemplo, mas esse não é o caso geral.
Questão
Então, minha pergunta é: como faço para modelar isso? Que tipo de problema de otimização estou tentando resolver? Qual algoritmo devo usar? Não tenho medo de ler trabalhos de pesquisa, então deixe-me saber o que devo ler!
Intuitivamente, um algoritmo genético não poderia ser o melhor, porque realmente não parece aprender. Por exemplo, se pressionar Iniciar parece sempre piorar a avaliação (porque interrompe o jogo), deve haver algum tipo de designer ou cérebro que aprende: "pressionar Iniciar a qualquer momento é inútil". Mas mesmo esse objetivo não é tão trivial quanto parece, porque às vezes pressionar o começo é o ideal, como na chamada "pausa para trás - longos saltos" em Super Mario 64 ! Aqui, o cérebro precisaria aprender um padrão muito mais complexo: "pressionar Iniciar é inútil, exceto quando o jogador está nesse estado muito específico e continuará com alguma combinação de pressionar os botões ".
Parece que eu deveria (ou a máquina poderia aprender a) representar a entrada de alguma outra maneira mais adequada à modificação. A entrada por quadro parece muito granular, porque o que é realmente necessário são "ações", que podem abranger vários quadros ... mas muitas descobertas são feitas quadro a quadro, por isso não posso descartar totalmente (o a pausa mencionada para trás e salto em distância requer precisão no nível do quadro). Também parece que o fato de que as entradas são processadas em série deve ser algo que possa ser capitalizado, mas não sei como.
Atualmente, estou lendo sobre a pesquisa Tabu (reativa), a pesquisa de bairro em grande escala, a otimização baseada no ensino-aprendizagem e a otimização de colônias de formigas.
Esse problema é simplesmente muito difícil de resolver com algo além de algoritmos genéticos aleatórios? Ou é realmente um problema trivial que foi resolvido há muito tempo? Obrigado pela leitura e obrigado antecipadamente por quaisquer respostas.