//-----------------------------ctor--------------------------------------- // //------------------------------------------------------------------------ CController::CController(int cxClient, int cyClient): m_bSuccess(false), m_vPadPos(SVector2D(RandFloat()*cxClient, 50)), m_cxClient(cxClient), m_cyClient(cyClient) { //create a starting postion for the landers SVector2D vStartPos = SVector2D(WINDOW_WIDTH/2, cyClient-50); //create the user controlled lander m_pUserLander = new CLander(cxClient, cyClient, PI, vStartPos, m_vPadPos); //set up the VB for the landing pad for (int i=0; i<NumPadVerts; ++i) { m_vecPadVB.push_back(Pad[i]); } //setup the stars for (int i=0; i<NumStars; ++i) { m_vecStarVB.push_back(SPoint(RandInt(0, cxClient), RandInt(100, cyClient))); } }
void CController::ResetEnvironment(){ m_vecSweepers.clear(); m_vecObjects.clear(); m_NumSweepers = CParams::iNumSweepers; m_NumSuperMines = CParams::iNumSuperMines; //let's create the mine sweepers for (int i=0; i<m_NumSweepers; ++i) { m_vecSweepers.push_back(CMinesweeper()); } //initialize super mines in random positions within the application window // such that they aren't spawned on a sweeper for (int i=0; i<m_NumSuperMines; ++i) { SVector2D position; // don't spawn on sweepers. keep finding another location if they do. boolean collision = false; do{ position = SVector2D(RandFloat() * cxClient, RandFloat() * cyClient); collision = false; for(int i=0; i < m_vecSweepers.size(); i++){ if(Vec2DLengthSquared(position-m_vecSweepers[i].Position()) <= mineSpawnThreshold){ collision = true; break; } } }while(collision); m_vecObjects.push_back(CCollisionObject(CCollisionObject::SuperMine, position)); } // Spawn mines for (int i=0; i<m_NumMines; ++i) { SVector2D position; // don't spawn on super mines. boolean collision = false; do{ position = SVector2D(RandFloat() * cxClient, RandFloat() * cyClient); collision = false; for(int i=0; i < m_vecObjects.size(); i++){ if(m_vecObjects[i].getType() == CCollisionObject::SuperMine){ if(Vec2DLengthSquared(position-m_vecObjects[i].getPosition()) <= mineSpawnThreshold){ collision = true; break; } } } }while(collision); m_vecObjects.push_back(CCollisionObject(CCollisionObject::Mine, position)); } }
void SceneController::updateSimulationOpenMP() { // NN uses STL (it's not ported into the QTL) auto mines = vecMines.toStdVector(); #pragma omp parallel for for (int i = 0; i < vecSweepers.size(); ++i) { int grabHit; // update the NN and position if (!vecSweepers[i].Update(mines)) { // error in processing the neural net gsInfo->setText("ERROR: Wrong amount of NN inputs!"); m_bInternalError = true; continue; } // keep minesweepers in our viewport vecSweepers[i].WarpWorld(0, 0, vpWidth, vpHeight); #pragma omp critical // see if it's found a mine if ((grabHit = vecSweepers[i].CheckForMine(mines, MainWindow::s.dMineScale)) != -1) { // mine found so replace the mine with another at a random position vecMines[grabHit] = SVector2D(RandFloat() * vpWidth, RandFloat() * vpHeight); // we have discovered a mine so increase fitness vecSweepers[i].IncrementFitness(); } // update the chromos fitness score vecThePopulation[i].dFitness = vecSweepers[i].Fitness(); } }
void Controller::checkCollision() { for(int i = 0; i < CParams::iNumSweepers; i++) for(int j = 0; j < CParams::iNumMines; j++) if(mineSweepers[i]->collidesWithItem(a_mines[j])) if(a_mines[j] != NULL) { mineSweepers[i]->scene()->removeItem(a_mines[j]); double x = RandFloat() * CParams::iWindowWidth; double y = RandFloat() * CParams::iWindowHeight; a_mines[j]->setPos(x,y); v_mines[j] = SVector2D(SVector2D(x,y)); mineSweepers[i]->scene()->addItem(a_mines[j]); mineSweepers[i]->increaseFitness(1); } }
//-------------------------------------------Reset()-------------------- // // Resets the sweepers position, MinesGathered and rotation // //---------------------------------------------------------------------- void CMinesweeper::Reset(vector<CCollisionObject> &objects) { double threshold = (CParams::dMineScale+5)*(CParams::dMineScale+5); boolean collision = false; do{ //reset the sweepers positions but don't spawn on mines m_vPosition = SVector2D((RandFloat() * CParams::WindowWidth), (RandFloat() * CParams::WindowHeight)); collision = false; for(int i=0; i < objects.size(); i++){ if(objects[i].getType() == CCollisionObject::SuperMine){ if(Vec2DLengthSquared(m_vPosition-objects[i].getPosition()) <= threshold){ collision = true; break; } } } }while(collision); //and the MinesGathered m_dMinesGathered = 0; m_dSuperMinesGathered = 0; //and the rotation m_dRotation = RandFloat()*CParams::dTwoPi; minesLeft = minesRight = minesForwardLeft = minesForwardRight = false; return; }
int CMinesweeper::ResetTrial(int generation) { double reward = m_MemoryMap.TMazeRewardF(m_bReverse, m_vPosition.x, m_vPosition.y); m_dFitness += generation > 0 ? reward : 0; //m_dFitness += generation > 0 ? m_MemoryMap.TMazeReward(m_bReverse) : 0; m_vPosition = SVector2D(180, 50); m_dRotation = 0; //reset its memory m_MemoryMap.Reset(); m_bActive = true; if (reward < 0.01) { return 0; } if (m_bReverse) { if (reward > 0.9) { return -1; } else { return 1; } } else { if (reward > 0.9) { return 1; } else { return -1; } } }
//------------------------------- NewRun --------------------------------- // // reinitializes all the variables for a new run //------------------------------------------------------------------------ void CController::NewRun() { //change position of landing pad m_vPadPos = SVector2D(50+ RandFloat()*(m_cxClient-100), 50); //reset the spaceship m_pUserLander->Reset(m_vPadPos); }
//-----------------------------------constructor------------------------- // //----------------------------------------------------------------------- CMinesweeper::CMinesweeper(): m_dRotation(RandFloat()*CParams::dTwoPi), m_lTrack(0.16), m_rTrack(0.16), m_dFitness(0), m_dScale(CParams::iSweeperScale), m_iClosestMine(0) { //create a random start position m_vPosition = SVector2D((RandFloat() * CParams::WindowWidth), (RandFloat() * CParams::WindowHeight)); }
//-------------------------------------------Reset()-------------------- // // Resets the sweepers position, fitness and rotation // //---------------------------------------------------------------------- void CMinesweeper::Reset() { //reset the sweepers positions m_vPosition = SVector2D((RandFloat() * CParams::WindowWidth), (RandFloat() * CParams::WindowHeight)); //and the fitness m_dFitness = 0; //and the rotation m_dRotation = RandFloat()*CParams::dTwoPi; return; }
//-----------------------------Reset()------------------------------------ // // Resets the sweepers position, energy level and rotation // //------------------------------------------------------------------------ void CMinesweeper::Reset() { //reset the sweepers positions m_vPosition = SVector2D(180, 200); //and the energy level m_dFitness = 0; //and the rotation m_dRotation = RandFloat() * CParams::dTwoPi; //reset its memory m_MemoryMap.Reset(); }
//-----------------------------Reset()------------------------------------ // // Resets the sweepers position, fitness and rotation // //------------------------------------------------------------------------ void CMinesweeper::Reset() { //reset the sweepers positions m_vPosition = SVector2D(180, 200); //and the fitness m_dFitness = 0; //and the rotation m_dRotation = 0; //reset its memory m_MemoryMap.Reset(); }
//-----------------------------Reset()------------------------------------ // // Resets the sweepers position, fitness and rotation // //------------------------------------------------------------------------ void CMinesweeper::Reset() { //reset the sweepers positions m_vPosition = SVector2D(180, 50); //and the fitness m_dFitness = 0; //and the rotation m_dRotation = 0; m_bReverse = false; //reset its memory m_MemoryMap.Reset(); m_bActive = true; }
//-----------------------------------constructor------------------------- // //----------------------------------------------------------------------- CMinesweeper::CMinesweeper(): m_dRotation(RandFloat()*CParams::dTwoPi), m_dMinesGathered(0), m_dSuperMinesGathered(0), m_dScale(CParams::iSweeperScale), m_iClosestMine(0), m_iClosestSuperMine(0), minesForwardLeft(false), minesForwardRight(false), minesLeft(false), minesRight(false), active(true) { //create a random start position m_vPosition = SVector2D((RandFloat() * CParams::WindowWidth), (RandFloat() * CParams::WindowHeight)); }
//---------------------------------------constructor--------------------- // // initilaize the sweepers, their brains and the GA factory // //----------------------------------------------------------------------- CController::CController(vector<Bot*> bots): m_NumSweepers(CParams::iNumSweepers), m_pGA(NULL), m_bFastRender(false), m_iTicks(0), m_NumMines(CParams::iNumMines), m_iGenerations(0), cxClient(CParams::WindowWidth), cyClient(CParams::WindowHeight) { //let's create the mine sweepers for (int i=0; i<m_NumSweepers; ++i) { m_vecSweepers.push_back(bots[i]); } //get the total number of weights used in the sweepers //NN so we can initialise the GA m_NumWeightsInNN = m_vecSweepers[0]->GetNumberOfWeights(); //calculate the neuron placement in the weight vector vector<int> SplitPoints = m_vecSweepers[0]->CalculateSplitPoints(); //initialize the Genetic Algorithm class m_pGA = new CGenAlg(m_NumSweepers, CParams::dMutationRate, CParams::dCrossoverRate, m_NumWeightsInNN, SplitPoints); //Get the weights from the GA and insert into the sweepers brains m_vecThePopulation = m_pGA->GetChromos(); for (int i=0; i<m_NumSweepers; i++) m_vecSweepers[i]->PutWeights(m_vecThePopulation[i].vecWeights); //initialize mines in random positions within the application window for (int i=0; i<m_NumMines; ++i) { m_vecMines.push_back(SVector2D(RandFloat() * cxClient, RandFloat() * cyClient)); } }
// Synchronize the number of mine objects with the given value. void SceneController::updateMineObjects(int number) { int diff = number - vecMines.size(); if (diff > 0) { // initialize mines in random positions within the viewport for (int i = diff; i; --i) vecMines.push_back(SVector2D(RandFloat() * vpWidth, RandFloat() * vpHeight)); } else if (diff < 0) vecMines.resize(number); // wrap mines around the current viewport for (auto i = vecMines.begin(); i < vecMines.end(); ++i) { i->x = fmod(i->x, vpWidth); i->y = fmod(i->y, vpHeight); } }
//--------------------------------- ctor --------------------------------- // //------------------------------------------------------------------------ CGun::CGun(): m_iTicksToNextBullet(CParams::iFiringRate), m_dScale(CParams::dGunScale), m_bAutoGun(true) { //set its position m_vPos = SVector2D(CParams::WindowWidth/2, 20); //create the vertex buffer for (int i=0; i<NumGunVerts; ++i) { m_vecGunVB.push_back(gun[i]); } //create the bullets for (i=0; i<CParams::iMaxBullets; ++i) { m_vecBullets.push_back(CBullet()); } }
//-----------------------------------constructor------------------------- // //----------------------------------------------------------------------- CMinesweeper::CMinesweeper(): m_dRotation(RandFloat() * CParams::dTwoPi), m_lTrack(0), m_rTrack(0), m_dFitness(0), m_dScale(CParams::iSweeperScale), m_bCollided(false) { //create a static start position m_vPosition = SVector2D(180, 200); //create the sensors CreateSensors(m_Sensors, CParams::iNumSensors, CParams::dSensorRange); //initialize its memory m_MemoryMap.Init(CParams::WindowWidth, CParams::WindowHeight); }
void Controller::init() { for(int i = 0; i < CParams::iNumMines; i++) { a_mines[i] = new mines(); double x = (RandFloat() * CParams::iWindowWidth); double y = (RandFloat() * CParams::iWindowHeight); a_mines[i]->setPos(x,y); v_mines.push_back(SVector2D(x,y)); } int a = CParams::iNumSweepers; for (int i = 0; i < CParams::iNumSweepers; ++i) { mineSweepers[i] = new Minesweeper(); SVector2D pos(RandFloat() * CParams::iWindowWidth, RandFloat() * CParams::iWindowHeight); mineSweepers[i]->setPos(pos.x,pos.y); mineSweepers[i]->setPosition(pos); mineSweepers[i]->setMines(v_mines); } numWeightsInNN = mineSweepers[0]->GetNumOfWeights(); gAlgo = new CGenAlg(CParams::iNumSweepers, CParams::dMutationRate, CParams::dCrossoverRate, numWeightsInNN); }
//-----------------------------------constructor------------------------- // //----------------------------------------------------------------------- CMinesweeper::CMinesweeper(): m_dRotation(0), m_lTrack(0), //m_rTrack(0), m_dFitness(0), m_dScale(CParams::iSweeperScale), m_bCollided(false) { m_Color = CreatePen(PS_SOLID, 1, RGB(rand() % 205 + 50, rand() % 205 + 50, rand() % 205 + 50)); //create a static start position m_vPosition = SVector2D(180, 50); //create the sensors CreateSensors(m_Sensors, CParams::iNumSensors, CParams::dSensorRange); //initialize its memory m_MemoryMap.Init(CParams::WindowWidth, CParams::WindowHeight); }
CLander::CLander(int cxClient, int cyClient, double rot, SVector2D pos, SVector2D pad):m_vPos(pos), m_vPadPos(pad), m_vVelocity(SVector2D(0,0)), m_dRotation(rot), m_dMass(SHIPS_MASS), m_dScale(LANDER_SCALE), m_cxClient(cxClient), m_cyClient(cyClient), m_dFitness(0), m_cTick(0), m_iPadX(cxClient/2), m_bCheckedIfLanded(false) { m_vStartPos = m_vPos; m_dStartRotation = rot; //set up the vertex buffer for the lander shape for (int i=0; i<NumLanderVerts; ++i) { m_vecShipVB.push_back(lander[i]); } m_vecShipVBTrans = m_vecShipVB; //and for the jet shape for (i=0; i<NumJetVerts; ++i) { m_vecJetVB.push_back(jet[i]); } m_vecJetVBTrans = m_vecJetVB; }
//-------------------------------------Update----------------------------- // // This is the main workhorse. The entire simulation is controlled from here. // // The comments should explain what is going on adequately. //------------------------------------------------------------------------- bool CController::Update() { if (!hasTrained) { if (hasRendered) { mlp.Train(); hasTrained = true; } } //run the sweepers through CParams::iNumTicks amount of cycles. During //this loop each sweeper is constantly updated with the appropriate //information from its surroundings. The output from the learning algorithm is obtained //and the sweeper is moved. If it encounters a mine its MinesGathered is //updated appropriately, if (m_iTicks++ < CParams::iNumTicks) { for (int i=0; i<m_vecSweepers.size(); ++i) { if(!m_vecSweepers[i].IsActive()) continue; //update the position if (!m_vecSweepers[i].Update(m_vecObjects, m_vecSweepers, mlp)) { //error in processing the learning algorithm MessageBox(m_hwndMain, "An error occured while processing!", "Error", MB_OK); return false; } //see if it's found an object int GrabHit = m_vecSweepers[i].CheckForMine(m_vecObjects, CParams::dMineScale); if (GrabHit >= 0) { if(m_vecObjects[GrabHit].getType() == CCollisionObject::Mine) { //we have discovered a mine so increase MinesGathered m_vecSweepers[i].IncrementMinesGathered(); SVector2D newPosition; // object hit, so respawn it, but not on super mines boolean collision = false; do{ newPosition = SVector2D(RandFloat() * cxClient, RandFloat() * cyClient); collision = false; for(int i=0; i < m_vecObjects.size(); i++){ if(m_vecObjects[i].getType() == CCollisionObject::SuperMine){ if(Vec2DLengthSquared(newPosition-m_vecObjects[i].getPosition()) <= mineSpawnThreshold){ collision = true; break; } } } }while(collision); m_vecObjects[GrabHit].setPosition(newPosition); } } GrabHit = m_vecSweepers[i].CheckForSuperMine(m_vecObjects, CParams::dMineScale); if (GrabHit >= 0) { if(m_vecObjects[GrabHit].getType() == CCollisionObject::SuperMine) { m_vecObjects.erase(m_vecObjects.begin()+GrabHit); // Set sweeper inactive so we dont update it anymore m_vecSweepers[i].SetInactive(); } } } } //Time to update the sweepers for the next iteration else { // Update MinesGathered average and max int max = 0; int total = 0; for (int i=0; i<m_vecSweepers.size(); ++i) { int mg = m_vecSweepers[i].MinesGathered(); total += mg; if (mg > max) max = mg; } double average = ((double)total / m_NumSweepers); m_vecAvMinesGathered.push_back(average); m_vecMaxMinesGathered.push_back(total); // Update minesweepers remaining total = 0; for (int i=0; i<m_vecSweepers.size(); ++i) { if(m_vecSweepers[i].IsActive()) total++; } m_vecSweepersActive.push_back(total); //increment the iteration counter ++m_iIterations; //reset cycles m_iTicks = 0; // Respawn SuperMines Each Generation ResetEnvironment(); } if(isFirstTick) isFirstTick = false; return true; }
// This is the main workhorse. The entire simulation is controlled from here. // The comments should explain what is going on adequately. void SceneController::updateSimulation() { // Run the sweepers through iNumTicks amount of cycles. During this loop // each sweepers NN is constantly updated with the appropriate information // from its surroundings. The output from the NN is obtained and the sweeper // is moved. If it encounters a mine its fitness is updated appropriately. if (m_iTicks++ < MainWindow::s.iNumTicks) { if (MainWindow::s.bMultithreading) // For multi-threaded simulation we are using a helper function, // which incorporates OpenMP instructions. updateSimulationOpenMP(); else { // NN uses STL (it's not ported into the QTL) auto mines = vecMines.toStdVector(); for (int i = 0; i < vecSweepers.size(); ++i) { int grabHit; // update the NN and position if (!vecSweepers[i].Update(mines)) { // error in processing the neural net gsInfo->setText("ERROR: Wrong amount of NN inputs!"); m_bInternalError = true; return; } // keep minesweepers in our viewport vecSweepers[i].WarpWorld(0, 0, vpWidth, vpHeight); // see if it's found a mine if ((grabHit = vecSweepers[i].CheckForMine(mines, MainWindow::s.dMineScale)) != -1) { // mine found so replace the mine with another at a random position vecMines[grabHit] = SVector2D(RandFloat() * vpWidth, RandFloat() * vpHeight); // we have discovered a mine so increase fitness vecSweepers[i].IncrementFitness(); } // update the chromos fitness score vecThePopulation[i].dFitness = vecSweepers[i].Fitness(); } } } // Another generation has been completed. // Time to run the GA and update the sweepers with their new NNs else { // run the GA to create a new population // NN uses STL (it's not ported into the QTL) auto population = vecThePopulation.toStdVector(); vecThePopulation = QVector<SGenome>::fromStdVector(m_pGA->Epoch(population)); // emit current generation stats emit generationStats(m_iGenerations, m_pGA->BestFitness(), m_pGA->AverageFitness()); // insert the new (hopefully) improved brains back into the sweepers for (int i = 0; i < vecSweepers.size(); ++i) { vecSweepers[i].PutWeights(vecThePopulation[i].vecWeights); vecSweepers[i].Respawn(); } // increment the generation counter ++m_iGenerations; // reset cycles m_iTicks = 0; } }