Problem in C with NegaMax / Alpha-Beta (Connect 4)

Started by
58 comments, last by Jaap85 11 years, 11 months ago
Ok i'll have a look.

For my example, here is a cleaner explanation:

Test column 3
FREE column 3 / SCORE: 1000
BEST column 3 (score 1000)
Test column 2
FREE column 2 / SCORE: 1000
Test column 4
FREE column 4 / SCORE: 1000
Test column 1
FREE column 1 / SCORE: 1000
Test column 5
FREE column 5 / SCORE: 1000
Test column 0
FREE column 0 / SCORE: 3
Test column 6
FREE column 6 / SCORE: 1000


produced by:
18786785.png

Can you see the problem ? It always happened in those cases.



This is weird...

Initial call for negamax:
When i changed the code you've shown above, goes wrong.
But like this, it works (except the problem i've told before):


y = InsererJeton(grille, emplacements, x, joueur^1);
scoreCoup = IA_NegaMaxAlphaBeta(4, -1000000000, 1000000000, grille, emplacements, colonne, emplacement, joueur);


Is it normal that i've to write "!joueur" and not simply "joueur" ?
Advertisement
I edited my previous post. It looks like your initial call to IA_NegaMaxAlphaBeta was pretty messed up. It should be virtually identical to the recursive call made inside of IA_NegaMaxAlphaBeta, except instead of beta you can use the fixed value 1000000000.
Think i tried that too, but i'm going to test it and i'll tell you.


Yep i already tested it. makes things worse (let's just say... not better).
Where can be the problem ? wacko.png
I would change the depth from 4 to 1 or even 0 and try to use a debugger to see what's going on.
Ok, it works better since i've changed something in my eval function.
But there is still the same problem... When it can loose, it doesn't block the player (because the score of that column is the lower -> OK for the MIN but should be the biggest value to make things right).
Do you understand what i mean ? It's the same thing i told you above, just look at the image and the debug code to help you if it's not clear in your mind.
I really don't know what could be crap in all of that sad.png
At this point it's not clear to me exactly what code you are running. Please, post your code, the position on which you think it's doing the wrong thing, what it's doing, and what you think it should be doing.
When AI can win, it does. But when it can lose, it doesn't block me.
Here are 2 examples:

1) When it can win

Scores returned by columns:

Test column 3
FREE column 3 / SCORE: 107
BEST column 3 (score 107)
Test column 2
FREE column 2 / SCORE: 105
Test column 4
FREE column 4 / SCORE: 105
Test column 1
FREE column 1 / SCORE: 103
Test column 5
FREE column 5 / SCORE: 1000
BEST column 5 (score 1000)
Test column 0
FREE column 0 / SCORE: 102
Test column 6
FREE column 6 / SCORE: 102


It's ok because if you look on the screenshot, AI (in yellow) wins it in column 5.
p41.png


2) When it can lose

Scores returned by columns:

Test column 3
FREE column 3 / SCORE: 1000
BEST column 3 (score 1000)
Test column 2
FREE column 2 / SCORE: 105
Test column 4
FREE column 4 / SCORE: 1000
Test column 1
FREE column 1 / SCORE: 1000
Test column 5
FREE column 5 / SCORE: 1000
Test column 0
FREE column 0 / SCORE: 1000
Test column 6
FREE column 6 / SCORE: 1000


As you can see, it should have play in column 2 to block me. But it didn't because column 2 has the lower score (and it's everytime like that mellow.png )
So the first highest score it sees is: column 3 (with 1000).
p42.png


Can you see the problem ?
I think I've found the problem:
if (check(grille, emplacements, colonne, emplacement, joueur) == 4)
{
if (joueur == 0)
{
return -1000;
}

return 1000;
}


That code should just be

if (check(grille, emplacements, colonne, emplacement, joueur) == 4)
{
return -1000;
}


If the previous player just won, you lost, regardless of whether you are player 0 or 1.
Still the same.
Here is all my code, maybe you'll find something wrong:

Negamax function (think it's all good for this one)

int IA_NegaMaxAlphaBeta(int profondeur, int alpha, int beta, int grille[LIGNES][COLONNES], int emplacements[COLONNES], int colonne, int emplacement, int joueur)
{
int x = COLONNES/2, y, i, k = 1, nbAlign;

nbAlign = check(grille, emplacements, colonne, emplacement, joueur);
if (nbAlign == 4)
{
return -1000;
}

if (GrillePleine(emplacements))
{
return SCORE_NUL;
}

if (profondeur == 0)
{
return IA_Evaluation(grille, joueur, nbAlign);
}

for(i = 0; i < COLONNES && alpha < beta; i++)
{
x += i*k;
k = -k;

if (emplacements[x] > -1)
{
y = InsererJeton(grille, emplacements, x, joueur);
alpha = max(alpha, -IA_NegaMaxAlphaBeta(profondeur-1, -beta, -alpha, grille, emplacements, x, y, joueur^1));
AnnulerJeton(grille, emplacements, y, x);
}
}

return alpha;
}



The eval function (maybe the way i've returned the score is wrong ?)

int IA_Evaluation(int grille[LIGNES][COLONNES], int joueur, int nbAlign)
{
int x, y, colscore, rowscore, score = 0;

for(y = 0; y < LIGNES; y++)
{
rowscore = abs((LIGNES/2) - y);
rowscore = (LIGNES/2) - rowscore;

for(x = 0; x < COLONNES; x++)
{
colscore = abs((COLONNES/2) - x);
colscore = (COLONNES/2) - colscore;

if (grille[y][x] == 0)
{
score -= (rowscore + colscore);
}
else
{
if (grille[y][x] == 1)
{
score += (rowscore + colscore);
}
}
}
}

if (nbAlign == 3)
{
if (joueur == 0)
{
score -= SCORE_3J;
}
else
{
score += SCORE_3J;
}
}
else
{
if (nbAlign == 2)
{
if (joueur == 0)
{
score -= SCORE_2J;
}
else
{
score += SCORE_2J;
}
}
else
{
if (nbAlign == 1)
{
if (joueur == 0)
{
score -= SCORE_1J;
}
else
{
score += SCORE_1J;
}
}
}
}

if (joueur == 0)
{
return score;
}

return -score;
}



And the initial call to negamax (you've suggested a minus sign on negamax but i can't find that anywhere, it's every time without minus sign when it's initial call).
However, i have to make something strange just before calling negamax (insert coin "joueur^1" instead of "joueur" and that's not logic).
This is the initial code as right now:

int x = COLONNES/2, y, i, k = 1, scoreCoup, scoreMeilleur = -INFINI, col = -1;

for(i = 0; i < COLONNES; i++)
{
x += i*k;
k = -k;
if (emplacements[x] > -1)
{
y = InsererJeton(grille, emplacements, x, joueur^1);
scoreCoup = IA_NegaMaxAlphaBeta(MAXPROFONDEUR, -INFINI, INFINI, grille, emplacements, colonne, emplacement, joueur);
if (scoreCoup > scoreMeilleur)
{
scoreMeilleur = scoreCoup;
col = x;
}
AnnulerJeton(grille, emplacements, y, x);
}
}
Your initial call is obviously broken, and even you recognize that there's something wrong with it. So write it correctly:

  • The call to InsererJeton should use joueur without the "^1".
  • The return value of IA_NegaMaxAlphaBeta should be negated.
  • The initial call to IA_NegaMaxAlphaBeta should have "joueur^1" and -scoreCoup as beta, instead of INFINI.
  • Also, why are you not passing x and y to IA_NegaMaxAlphaBeta as you do in the recursive call? Fix that too.

If all that doesn't work, find an easy position where it does the wrong thing (you already had a good one earlier, but I don't know if that one will still fail), try to reduce MAXPROFONDEUR as much as possible while still showing the problem, and then use a debugger. If you don't know how to use a debugger effectively, this is about the best opportunity you'll find.

This topic is closed to new replies.

Advertisement