Ive been trying to get a genetic algorithm working , that will learn how to play any snes game , ive been trying to get it to beat the first level of super mario world.
so far i am able to generate a random string and that is translated into keystrokes , and they are successfully sent to the SNES emulator , but i have no previous experience with GA's , plus im not fluent in c++ . So im asking for some info on how i should set up this GA, also it needs a way of deciding when to press each key , right now i have it press a key after x amount of milseconds.
im looking to get something like this http://www.youtube.com/watch?v=c7xJNAJys2s
and here is my code(its all in one file as id like to work it out first then ill clean it up), main is at the bottom :\
Code:
#include <windows.h>
#include <iostream>
#include <vector>
#include <Winbase.h>
// rand num generator im using
#include "MersenneTwister.h"
// size of string to generate
#define SIZE 500
#define POP 100
// DXI key codes, only way of sending keystrokes to the snes emulator
#define DIKEYBOARD_UP 0x04C8
#define DIKEYBOARD_LEFT 0x04CB
#define DIKEYBOARD_RIGHT 0x04CD
#define DIKEYBOARD_DOWN 0x04D0
#define DIKEYBOARD_A 0x041E
#define DIKEYBOARD_C 0x042E
#define DIKEYBOARD_D 0x0420
#define DIKEYBOARD_S 0x041F
#define DIKEYBOARD_X 0x042D
#define DIKEYBOARD_Z 0x042C
using namespace std;
//needs alot of work
int place(vector<int> vect, int place)
{
int x = 1;
int num1 = 0;
int num2 = 0;
int num3 = 0;
if(place == 1 || 2 || 3)
{
do
{
if(num1 < vect[x])
{
num1 = vect[x];
}
x++;
}while(x != SIZE);
do
{
if(num2 < vect[x])
{
num2 = vect[x];
}
x++;
}while(x != SIZE);
do
{
if(num3 < vect[x] < num2)
{
num3 = vect[x];
}
x++;
}while(x != SIZE);
}
if(place == 1)
{
return num1;
}
if(place == 2)
{
return num2;
}
if(place == 3)
{
return num3;
}
}
// reads from the addresses and returns their value
int ReadMyAddress(unsigned long lol)
{
// read from pointer , not working
//(DWORD*)ptr = 0xbasepointer;
//ptr = (DWORD*)(*ptr + 0x0ffset);
// BYTE value so i dont have to convert from 4BYTE
BYTE MyBuffer = 0;
// holds the address of the value being read
unsigned long Address = lol;
// holds the process id
DWORD pid = 0;
// handle to process
HANDLE hProcess = 0;
// handle to window
HWND hProc;
// finds window , used to get process ID
hProc = FindWindow(NULL, L"ZSNES");
// error check to see if window is found
if(hProc)
{GetWindowThreadProcessId(hProc, &pid);
}
VirtualProtectEx(hProc, (LPVOID)Address, 256, PAGE_EXECUTE_READWRITE, NULL);
hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
ReadProcessMemory(hProcess, ULongToPtr(Address), &MyBuffer, sizeof(MyBuffer), NULL);
return MyBuffer;
}
// generates the numbers in the array and returns the array
vector<int> genGen ()
{
// sets array size to what was defined
vector<int> ary;
int i = 0;
// populates the array
do
{
MTRand lool;
ary.push_back(lool.randInt(9));
i++;
}
while ( i != SIZE);
// returns the array(size is what was defined up top)
return ary;
}
// Key input func , presses specified key
void Key ( int key)
{
INPUT input;
memset(&input,0,sizeof(INPUT));
input.type=INPUT_KEYBOARD;
input.ki.wScan = key; // direct-input scancode
input.ki.dwFlags=0;
SendInput(1,&input,sizeof(INPUT));
Sleep(50);
input.ki.dwFlags=KEYEVENTF_KEYUP;
SendInput(1,&input,sizeof(INPUT));
}
// fitness funtion, i have a vague idea what to do
int testFit()
{
int Addy_Timer = ReadMyAddress(0x57C00D6);
int Addy_MyHealth = ReadMyAddress(0x57C0F2C);
int Addy_EnemyHealth = ReadMyAddress(0x57C100C);
//int Addy_MyBonus = ReadMyAddress(0x57C1B0C);
//int Addy_EnemyBonus = ReadMyAddress(0x57C1B5C);
signed short int score = ((Addy_MyHealth - Addy_EnemyHealth) + Addy_Timer);
return score;
}
// pushes gene keys
void pressKey (vector<int> aray)
{
int i = 0;
do
{
switch (aray[i]) {
case 0: Key(DIKEYBOARD_X);//c
cout << 'x';
break;
case 1: Key(DIKEYBOARD_Z);//v
cout << 'z';
break;
case 2: Key(DIKEYBOARD_C);//x
cout << 'c';
break;
case 3: Key(DIKEYBOARD_D);//d
cout << 'd';
break;
case 4: Key(DIKEYBOARD_A);//a
cout<< 'a';
break;
case 5: Key(DIKEYBOARD_S);//s
cout << 's';
break;
case 6: Key(DIKEYBOARD_UP);//up
cout<< " UP ";
break;
case 7: Key(DIKEYBOARD_DOWN);//down
cout << " DWN ";
break;
case 8: Key(DIKEYBOARD_LEFT);//left
cout << " LFT ";
break;
case 9: Key(DIKEYBOARD_RIGHT);//right
cout << " RHT ";
break;
}
i++;
Sleep(300);
}
while(i != SIZE);
}
// MAIN
int main(int argc,char * argv[])
{
// finds window , used to get process ID
HWND hProc = FindWindow(NULL, L"ZSNES");
int run = 0;
int strand_c = 0;
int fitness [POP];
vector< vector<int> > strand(POP, vector<int>(SIZE));
vector<int> testfit;
SetForegroundWindow(hProc);
do
{
// generate gene and put in vect
vector<int> vect = genGen();
//output gene string
int x =0;
int generation = 0;
do{
cout << vect[x];
x++;
}
while(x != SIZE);
//Key(0x042E, TRUE);
//sends vector to be processed
pressKey(vect);
//assigns gene a score
int gene = testFit();
//stores the score in vect testfit
testfit[generation] = gene;
// assign current gene to pool
do{
strand [strand_c][run] = vect[run];
run++;
}while(run != SIZE);
strand_c++;
generation++;
// send f1 to reload save
//Key(0x042E, TRUE);//f1
}
while (run != POP);
//place the gene's
return 0;
}
thanks for looking through all that.