Code from my Doodle Jump Genetic Algorithm

Game Functions

void spawn_players(PLAY** players_list)
{
	for (int index=0;index<numberPlayers; index++)
	{
		players_list[index]->Xpos=215;
		players_list[index]->Ypos=120;
		players_list[index]->score=0;
		players_list[index]->jump=10; //Arbitrary value that can't be obtain naturally in the program
		players_list[index]->jumpTime=0;
		players_list[index]->alive=TRUE;
		players_list[index]->keyboard=0;
		for (int index2=0; index2<3; index2++)
		{
			players_list[index]->color[index2]=random_int_generator(0,255);
		}
	}
}


void move_player(PLAY* player)
{
	if (player->keyboard==0) //No movements
	{
		player->Xpos=player->Xpos;
	}
	if (player->keyboard==1 && player->Xpos+50<largeurFenetre()) // to right
	{
		player->Xpos=player->Xpos+lateralSpeed;
	}
	if (player->keyboard==2 && player->Xpos>0)	//to left
	{
		player->Xpos=player->Xpos-lateralSpeed;
	}
}


void platform_bounce(PLAY* player, PLA** platforms_list)
{
	for (int index=0;index<6;index++)
	{
		if ((((platforms_list[index]->Ypos)+15<=player->Ypos)&&((platforms_list[index]->Ypos)+25>=player->Ypos))&&(((platforms_list[index]->Xpos)-48<=player->Xpos)&&((platforms_list[index]->Xpos)+69>=player->Xpos)))
		{
			player->jump=index;
			player->Ypos=player->Ypos+jumpSpeed;
			player->jumpTime=1;
		    score_up(player);
			break;
		}
	}
	if (player->jumpTime!=0)
	{
		player->Ypos=player->Ypos+jumpSpeed;
		player->jumpTime=player->jumpTime+1;
		if (player->jumpTime>=40)
		{
			player->jumpTime=0;
		}
		rafraichisFenetre();
	}
	else
	{
		player->Ypos=player->Ypos-fallSpeed;
		rafraichisFenetre();
	}
}


void score_up(PLAY* player)
{
	player->score=player->score+1;
}


int death_player(PLAY* player, int playersCount)
{
	if (player->Ypos<=0)
	{
		player->alive=FALSE;
		playersCount=playersCount-1;
	}
	return(playersCount);
}

Genome

PLAY** malloc_players_list(void)
{
	PLAY** players_list;
	players_list=(PLAY**)malloc(sizeof(PLAY*)*numberPlayers);
	for (int index=0; index<numberPlayers; index++)
	{
		players_list[index]=(PLAY*)malloc(sizeof(PLAY));
	}
    spawn_players(players_list);
    for (int index=0; index<numberPlayers; index++)
	{   for (int indexDepth=0; indexDepth<3; indexDepth++)
        {
            for (int indexLine=0; indexLine<3;indexLine++)
            {
                for (int indexColumn=0; indexColumn<3;indexColumn++)
                {
                    players_list[index]->genome[indexDepth][indexLine][indexColumn]=random_float_generator(1);
                }
            }
        }
	}
	return(players_list);
}

Crossovers and Mutations

PLAY crossover(PLAY** players_list)
{
    PLAY playerTempo; //Used to easily return the nex genome at the end of the function
    int mask[3][3][3];
    int maskInverted[3][3][3];
    int indexPlayer1;
    int indexPlayer2;
    // generation of a random mask
    for (int indexDepth=0; indexDepth<3; indexDepth++)
    {
        for (int indexLine=0;indexLine<3;indexLine++)
        {
            for (int indexColumn=0; indexColumn<3; indexColumn++)
            {
                mask[indexDepth][indexLine][indexColumn]=random_int_generator(0,1);
            }
        }
    }
    // creation of an inverted mask
    for (int indexDepth=0; indexDepth<3; indexDepth++)
    {
        for (int indexLine=0;indexLine<3;indexLine++)
        {
            for (int indexColumn=0; indexColumn<3; indexColumn++)
            {
                switch(mask[indexDepth][indexLine][indexColumn])
                {
                    case 0:
                        maskInverted[indexDepth][indexLine][indexColumn]=1;
                        break;

                    case 1:
                        maskInverted[indexDepth][indexLine][indexColumn]=0;
                        break;
                        
                }
            }
        }
    }
    //Selection of the two best players by their score
    indexPlayer1=0;
    indexPlayer2=1;
    for (int index=0;index<numberPlayers;index++)
    {
        if ((players_list[indexPlayer1]->score<=players_list[index]->score)&&(players_list[index]->score!=players_list[indexPlayer2]->score))
        {
            indexPlayer1=index;
        }
        if ((players_list[indexPlayer2]->score<=players_list[index]->score)&&(players_list[index]->score!=players_list[indexPlayer1]->score))
        {
            indexPlayer2=index;
        }
    }
    //Application of the mask
    for (int indexDepth=0; indexDepth<3; indexDepth++)
    {
        for (int indexLine=0;indexLine<3;indexLine++)
        {
            for (int indexColumn=0;indexColumn<3;indexColumn++)
            {
                playerTempo.genome[indexDepth][indexLine][indexColumn]=((players_list[indexPlayer1]->genome[indexDepth][indexLine][indexColumn])*(mask[indexDepth][indexLine][indexColumn])+(players_list[indexPlayer2]->genome[indexDepth][indexLine][indexColumn])*(maskInverted[indexDepth][indexLine][indexColumn]));
            }
        }
    }
    return(playerTempo);
}


void mutation(PLAY** players_list)
{
    int mutationsNumber;
    int randomDepthIndex;
    int randomLineIndex;
    int randomColumnIndex;
    int mutationChances;
    float slightMutationTemp;
    mutationsNumber=random_int_generator(2,10); //Random selection of the number of potential mutations
    int toMutateIndexes[mutationsNumber-1];
    for (int index=0; index<mutationsNumber-1; index++)
    {
        toMutateIndexes[index]=random_int_generator(0, numberPlayers-1); //Random selection of the player to potentially mutate
    }
    for (int index=0; index<mutationsNumber-1; index++)
    {
        randomLineIndex=random_int_generator(0,2); //Those three are for choosing randomly a
        randomColumnIndex=random_int_generator(0,2); // gene from a player and mutate it
        randomDepthIndex=random_int_generator(0,2);
        mutationChances=random_int_generator(0,2);
        switch(mutationChances)
        {
            case 0: //no mutations
                break;
            
            case 1: //Slight mutation, adapted from the algogen one
                slightMutationTemp=(random_float_generator(1)-0.05)+(players_list[toMutateIndexes[index]]->genome[randomDepthIndex][randomLineIndex][randomColumnIndex]);
                if (slightMutationTemp<=0)
                {
                    slightMutationTemp=0;
                }
                if (slightMutationTemp>=1)
                {
                    slightMutationTemp=1;
                }
                players_list[toMutateIndexes[index]]->genome[randomDepthIndex][randomLineIndex][randomColumnIndex]=slightMutationTemp;        
                break;
            
            case 2: //Random mutation
                players_list[toMutateIndexes[index]]->genome[randomDepthIndex][randomLineIndex][randomColumnIndex]=random_float_generator(1);
                break;
        }

    }
}


int natural_selection(PLAY** players_list)
{
    PLAY storeNewGenome;
    int minimalValue;
    int mediumValue;
    int maximalValue;
    int playersExtinction; //Used to print the number of changed players
    playersExtinction=0;
    storeNewGenome=crossover(players_list);
    minimalValue=32000; //Arbitrary value that can't be reach by a mistrained player
    maximalValue=0;
    //Determination of a medium score value
    for (int index=0; index<numberPlayers;index++)
    {
        if (players_list[index]->score<=minimalValue)
        {
            minimalValue=players_list[index]->score;
        }
        if (players_list[index]->score>=maximalValue)
        {
            maximalValue=players_list[index]->score;
        }
    }
    mediumValue=(0.99*maximalValue-1.22*minimalValue)/2; //Values chosen after some tests
    //Determination of all the indexes of players whose genomes must be changed by the crossover one and replacement of those genomes
    for (int index=0; index<numberPlayers;index++)
    {
        if (players_list[index]->score<mediumValue)
        {
            for (int indexDepth=0; indexDepth<3; indexDepth++)
            {
                for (int indexLine=0;indexLine<3;indexLine++)
                {
                    for (int indexColumn=0;indexColumn<3;indexColumn++)
                    {
                        players_list[index]->genome[indexDepth][indexLine][indexColumn]=storeNewGenome.genome[indexDepth][indexLine][indexColumn];
                    }
                }
            }
            playersExtinction=playersExtinction+1;
        }
    }
    mutation(players_list);
    return(playersExtinction);
}

1 thought on “Code from my Doodle Jump Genetic Algorithm

Comments are closed.