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.