Click here to Skip to main content
15,880,891 members
Articles / Artificial Intelligence
Article

8 Queens Solution with Genetic Algorithm

Rate me:
Please Sign up or sign in to vote.
4.96/5 (53 votes)
19 Oct 20055 min read 339.1K   14.6K   86   70
Using Genetic Algorithm to solve the 8 Queens problem.

Image 1

Genetic Algorithm, Theory

There are so many books and so many resources on the Web about Genetic Algorithms. The best that I can do is quote some nice descriptions from my preferred sites.

"Genetic algorithms are a part of evolutionary computing, which is a rapidly growing area of artificial intelligence. As you can guess, genetic algorithms are inspired by Darwin's theory about evolution. Simply said, solution to a problem solved by genetic algorithms is evolved."

The GA begins, like any other optimization algorithm, by defining the optimization variables. It ends like other optimization algorithms too, by testing for convergence. A path through the components of the GA is shown as a flowchart in Figure 1.

Image 2

Fig. 1 - A path through the components of the GA

Define cost function and cost

For each problem there is a cost function. For example, maximum of a 3D surface with peaks and valleys when displayed in variable space. Cost, a value for fitness, is assigned to each solution.

Chromosomes and genes

A gene is a number between 0 to n-1. A chromosome is an array of these genes. It could be an answer. Population in each generation has determined the number of chromosomes.

Create a random initial population

An initial population is created from a random selection of chromosomes. The number of generations needed for convergence depends on the random initial population.

Decode the chromosome and find the cost

To find the assigned cost for each chromosome a cost function is defined. The result of the cost function called is called cost value. Finally, the average of cost values of each generation converges to the desired answer.

Mating and next generation

Those chromosomes with a higher fitness (lesser cost) value are used to produce the next generation. The offsprings are a product of the father and the mother, whose composition consists of a combination of genes from them (this process is known as "crossing over"). If the new generation contains a chromosome that produces an output that is close enough or equal to the desired answer then the problem has been solved. If this is not the case, then the new generation will go through the same process as their parents did. This will continue until a solution is reached.

About the 8 queens problem

In chess, a queen can move as far as she pleases, horizontally, vertically, or diagonally. A chess board has 8 rows and 8 columns. The standard 8 by 8 queen's problem asks how to place 8 queens on an ordinary chess board so that none of them can hit any other in one move. Here we solve this problem with a genetic algorithm for a n (n is between 8 and 30) queen problem.

Using the code

We first describe the variables and the functions:

Variables:

  • int ChromosomeMatrix[30][1000]: This variable is a matrix of numbers between 0 to ChessBoardLenght-1. For example, if ChessBoardLength=8, ChromosomeMatrix could be {4,6,0,2,7,5,3,1} so that the first number defines the place of the queen in the first row, the second number defines the place of the queen in the second row and so on.
  • int CostMatrix[1000]: For each chromosome matrix, a cost value is defined. The best value is 0 and when no queen can take the other one.
  • int CrossOverMatrix[30][1000]: For generating children from parents, a crossover matrix is needed that decides which gene must be selected from the two parents.
  • int Population, int Iteration, float Mutationrate: These variables are genetic algorithm parameters.
  • int ChessBoardLength: This determines how many rows and columns a chessboard has.
  • int area[30][30]: This variable is a chess board matrix.

Functions:

void CGAQueen::Clear()
{
    // to Reset All cells 
    for (int i=0;i<ChessBorad;i++)
        for (int j=0;j<ChessBorad;j++)
            area[i][j]=0;
}

This function is used to clear the chess board (area[][]) with 0s.

void CGAQueen::InitialPopulation() 
{
    int random;
    bool bCheck;
    for (int index=0;index<=Population-1;index++)
        for (int a=0;a<ChessBorad;a++)
        {
            random=rand();
            bCheck=1;
            for (int b=0;b<a;b++)
            if (random%ChessBorad==ChromosomeMatrix[b][index])
                bCheck=0;
            if (bCheck)
                ChromosomeMatrix[a][index]=random%ChessBorad;
            else
                a--;
        }
}

This function is used to generate the initial population. This generation is a purely random generation. With this function, ChromosomeMatrix[][] is valued with random numbers between 0 and ChessBoardLength-1. The number of ChromosomeMatrix is equal to Population.

void CGAQueen::FillArea(int index)
{
    Clear();
    for (int i=0;i<ChessBoradLenght;i++)
        area[i][ChromosomeMatrix[i][index]]=1;
}

This function is used to fill the chess board with a chromosome. For example, if ChromosomeMatrix = {3,6,8,5,1,4,0,7,9,2}, the first number defines the column of the queen in the first row, the second number defines the column of the queen in the second row and so on. The area is shown in fig. 2 – here ChessBoardLength =10.

Image 3

Fig. 2 - The chess board with ChromosomeMatrix={ 3,6,8,5,1,4,0,7,9,2}

int CGAQueen::CostFunc(int index)
{
    int costValue=0;
    int m,n;
    int i,j;
    for(i=0;i<ChessBoradLenght;i++)
    {    
        j=ChromosomeMatrix[i][index];
        m=i+1;
        n=j-1;
        while(m<ChessBoradLenght    && n>=0)
        {
            if(area[m][n]==1)
                costValue++; 
            m++;
            n--;
        }

        m=i+1;
        n=j+1;
        while(m<ChessBoradLenght && n<ChessBoradLenght )
        {        
            if(area[m][n]==1)
                costValue++;            
            m++;
            n++;
        }
        m=i-1;
        n=j-1;
        while(m>=0 && n>=0)
        {        
            if(area[m][n]==1)
                costValue++; 
            m--;
            n--;
        }
        m=i-1;
        n=j+1;
        while(m>=0 && n<ChessBoradLenght)
        {        
            if(area[m][n]==1)
                costValue++;            
            m--;
            n++;
        }
    }
    return costValue;
}

This function is used to determines the cost value for each ChromosomeMatrix[][] and keeps it in CostMatrix[]. For example, for chromosome = { 2,6,9,3,5,0,4,1,7,8 }, the cost value will be 2. (See fig. 3.)

Image 4

Fig. 3 - Because of these two queens that hit each other, the cost value is 2.

void CGAQueen::PopulationSort()
{
    bool k=1;
    int Temp;
    while (k)
    {
        k=0;
        for (int i=0;i<=Population-2;i++)
        {
            if (CostMatrix[i]>CostMatrix[i+1])    
            {
                Temp=CostMatrix[i];
                CostMatrix[i]=CostMatrix[i+1];
                CostMatrix[i+1]=Temp;
                
            for (int j=0;j<ChessBoradLenght;j++)
            {
                Temp=ChromosomeMatrix[j][i];
                ChromosomeMatrix[j][i]=ChromosomeMatrix[j][i+1];
                ChromosomeMatrix[j][i+1]=Temp;
            }            
            k=1;
            }
        }
    }
}

This function is used to sort the new generation according to their cost value. The best (minimum) is placed on top and the worst (maximum) is placed in the bottom.

void CGAQueen::GenerateCrossOverMatrix()
{
    int randomCrossOver;
    for (int index=0;index<=Population-1;index++)
        for (int a=0;a<ChessBoradLenght;a++)
        {
            randomCrossOver=rand();
            CrossOverMatrix[a][index]=randomCrossOver%2;
        }
}

This function is used to generate the cross over matrix. This matrix contains 0s and 1s.

void CGAQueen::Mating()
{
    int TempMatrix[30][2];
    int TempMatrix0[30],TempMatrix1[30];
    int Temp,j,k;

    …
}

This function is used to generate children from parents using CrossOverMatrix. It is a way to do this job. Genes are drawn from p0 and p1. A gene is drawn from one parent and it is appended to the offspring (child) chromosome. The corresponding gene is deleted in the other parent (see figure 4). This step is repeated until both parent chromosomes are empty and the offspring contains all genes involved.

Image 5

Fig. 4 The Cross Over method

void CGAQueen::ApplyMutation()
{
    int randomChromosome;
    int randomGen0,randomGen1;
    int Temp;
    int NumberOfMutation=int(MutationRate*(Population-1)*ChessBoradLenght);
    for(int k=0;k<=NumberOfMutation;k++)
    {
        randomChromosome=0;
        while((randomChromosome=rand()%Population)==00;
        randomGen0=rand()%ChessBoradLenght;
        while((randomGen1=rand()%ChessBoradLenght)==randomGen0);
        Temp=ChromosomeMatrix[randomGen0][randomChromosome];
        ChromosomeMatrix[randomGen0][randomChromosome]=
          ChromosomeMatrix[randomGen1][randomChromosome];
        ChromosomeMatrix[randomGen0][randomChromosome]=Temp;
    }
}

This function is used to apply mutation to the current generation. First of all, a random chromosome is selected but the first (best) one in the list. Then, two random genes of this chromosome are selected and replaced with each other. Increasing the number of mutations increases the algorithm’s freedom to search outside the current region of chromosome space.

There is a demo for you to enjoy the genetic algorithm.

Have fun.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Iran (Islamic Republic of) Iran (Islamic Republic of)
I live in Iran . I started hardware programming when I was young. I designed and built some ISA cards for attaching to PC.like ocsiloscope and signal generator. Now I am working for a engineering company and Manager of some project.

Comments and Discussions

 
Questionhi Pin
s n 26-May-08 15:56
s n 26-May-08 15:56 
GeneralBidirectional search Pin
Ayaz Alavi26-Mar-08 0:06
Ayaz Alavi26-Mar-08 0:06 
Generalgood stuff Pin
payamtooba16-Jan-08 18:38
payamtooba16-Jan-08 18:38 
GeneralRe: good stuff Pin
asef31-May-10 3:15
asef31-May-10 3:15 
Questionrandom float number Pin
nhquang26-Oct-06 20:02
nhquang26-Oct-06 20:02 
AnswerRe: random float number Pin
asef30-Oct-06 2:28
asef30-Oct-06 2:28 
GeneralNice work Pin
Hatem Mostafa24-Mar-06 1:12
Hatem Mostafa24-Mar-06 1:12 
GeneralPoor, Misleading, Invalid PinPopular
Medus20-Nov-05 14:56
Medus20-Nov-05 14:56 
If I were marking this as a submission I'd give you 6/10 for effort. But only if the pass grade was a 7.

Whilst your demonstration of genetic algorithms is quite a novel approach to the problem it doesn't actually work. The combination/crossover method does NOT preserve the attributes which made each parent strong - in fact it mangles them, parental strength thus becomes meaningless. This renders the genetic progression wholly ineffective.

In short, this is a mis-application of genetic techniques.


The reason this fails to outperform either pure-random or brute-force approaches is due to a problem ascertaining the relational qualities that make a strong parent - and then blending in a manner preserving these qualities. The line-by-line interpolation of two parents does not automatically make a strong child. It doesn't even swing the balance in favour of a strong child. It just messes up the previous diagonal relationships that made the parents strong.


In a human, each gene has some degree of scope or influence ... the choice between blue or brown eyes for example. Whichever gene we take, mother or father, we are preserving that this is likely a valid gene for eyes... one that works. This compartmentalisation allows us to substitute mother/father sections whilst preserving the genetic order. However, the strength of one horizontal line of a parent in your scheme has no strength or intrinsic value other than that afforded it by the arrangement as a whole. Two strong patterns, when merged, become a mess... an offspring equally likely to be much weaker than its parents.


Of course, you do reach the answer... but thats not a proof of the method. When you consider that there are only 40,000 physical arrangements of those 8 strips ... and much less logical arrangements (that is, when we discount physical arrangements that are logically similar owing to all possible combinations of rotations, edge-to-edge flipping and diagonal flipping) ... then we find that we are just as likely to find the answer by chance.

Why mention the flipping? Well, its important to understanding why the task seems deceptively larger than it is. You either have 40,000 permutations and quite a large number of winning patterns (Due to each pattern having its equally valid rotations and flips) ... or, you cancel out the rotations and flips from the many physical solutions and deal only with the logical solutions, albeit in a much smaller search tree.

Either way, you happen upon a winning answer much faster than anticipated, rather like the so-called birthday paradox.


A better solution to this problem would have been a recursive approach using the same 8 line shuffle. But at least you thought a little about the problem ... many of my students at first attempt try to recursively solve it with *no* constraints at all ... its surprising how many churn out code to evaluate all 172 trillion permutations.

At least you're headed in the right direction by limiting your field of search with the observation that there must be one and only one queen on each row.

But perhaps your randomisation function should ensure that only one in each column are represented too or are you intentionaly introducing weaknesses for your genetic algorithm to discard (It doesn't BTW). Still, a nice introduction to Genetic Algorithms - but readers should note that crossover must be done in such a way as to preserve the relational qualities that made each parent great, otherwise they are wasting their time.

Gotta give you a 1 man.

Regards,
Medus.
GeneralRe: Poor, Misleading, Invalid Pin
Medus20-Nov-05 15:11
Medus20-Nov-05 15:11 
GeneralRe: Poor, Misleading, Invalid Pin
YDLU10-Apr-06 12:02
YDLU10-Apr-06 12:02 
GeneralRe: Poor, Misleading, Invalid Pin
Medus12-Apr-06 8:56
Medus12-Apr-06 8:56 
GeneralRe: Poor, Misleading, Invalid Pin
David Roh20-Aug-06 4:03
David Roh20-Aug-06 4:03 
GeneralRe: Poor, Misleading, Invalid Pin
cristitomi7-Mar-07 4:33
cristitomi7-Mar-07 4:33 
GeneralRe: Poor, Misleading, Invalid Pin
garychapman15-Aug-07 10:12
garychapman15-Aug-07 10:12 
Generalcross over rate Pin
mbedward1-Nov-05 15:48
mbedward1-Nov-05 15:48 
GeneralRe: cross over rate Pin
asef1-Nov-05 18:22
asef1-Nov-05 18:22 
GeneralRe: cross over rate Pin
mbedward2-Nov-05 15:06
mbedward2-Nov-05 15:06 
Generalcontact with u Pin
amin chegeni28-Oct-05 9:00
amin chegeni28-Oct-05 9:00 
GeneralRe: contact with u Pin
asef29-Oct-05 1:06
asef29-Oct-05 1:06 
Generalgood one Pin
zxaar27-Oct-05 23:20
zxaar27-Oct-05 23:20 
GeneralCool Article Pin
Serge R24-Oct-05 6:18
Serge R24-Oct-05 6:18 
GeneralNice one Pin
hairy_hats24-Oct-05 1:28
hairy_hats24-Oct-05 1:28 
GeneralRe: Nice one Pin
asef26-Oct-05 21:10
asef26-Oct-05 21:10 
GeneralRe: Nice one Pin
hairy_hats27-Oct-05 2:44
hairy_hats27-Oct-05 2:44 
GeneralHi Asef great article! Pete in Australia Pin
Petey Boy23-Oct-05 23:05
Petey Boy23-Oct-05 23:05 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.