oldsql.Triso
Volt-Modder(in)
Hi Com,
ich hoffe ihr könnt mir helfen und zwar sollen wir 4Gewinnt via C programmieren und bei der Strategie sind wir nach dem Negamax-Algorithmus vorgegangen. Nun erkennt er aber gerade nicht, das sich leere Felder auch als Möglichkeit erschließen bzw. wenn der Gegner schon 2 nebeneinander hat, das man dort verteidigen müsste. Vllt. findet jemand den Fehler. Habe hoffentlich ausreichend kommentiert. Die "KI" baut gerne Türmchen und sieht seine eigenen Gewinnmöglichkeiten nicht.
#include "gameField.h"
#include <stdio.h>
Ihr könnt mir auch nur sagen wo der Fehler ist, das würde mir ausreichen. Soweit funktioniert alles, also die anderen Funktionen wie Visualisierung, Felderstellung, Prüfung auf 4 in einer Reihe/Diagonale/Spalte in alle Richtungen passt. Meiner Meinung nach kann es nur die Feldwertberechnung sein, aber ich sehe da einfach nicht den Fehler.
Gruß
ich hoffe ihr könnt mir helfen und zwar sollen wir 4Gewinnt via C programmieren und bei der Strategie sind wir nach dem Negamax-Algorithmus vorgegangen. Nun erkennt er aber gerade nicht, das sich leere Felder auch als Möglichkeit erschließen bzw. wenn der Gegner schon 2 nebeneinander hat, das man dort verteidigen müsste. Vllt. findet jemand den Fehler. Habe hoffentlich ausreichend kommentiert. Die "KI" baut gerne Türmchen und sieht seine eigenen Gewinnmöglichkeiten nicht.
#include "gameField.h"
#include <stdio.h>
Code:
struct MoveValue
{
double Score;
int Column;
};
void countFieldTypes(int **field, int p, int posX, int posY, int modX, int modY, int &occupiedByPlayer, int &free)
{
posX = posX + modX;
posY = posY + modY;
// Wenn die Grenzen überschritten wurden, dann ist die Prüfung für den Weg beendet
if (posX < 0 || posX >= 7) return;
if (posY < 0 || posY >= 6) return;
if (field[posX][posY]== 0) //Wenn das Feld leer ist
{
// wird free erhöht
free++;
}
else if (field[posX][posY]== p) // Feld ist von "mir/aktuellen" belegt
{
occupiedByPlayer++; // Hochzählen von cbp
//index = 3 + Convert.ToInt32(Math.Pow(coinsInRow + 1, 2));
}
else
{
// Feld ist durch Gegner belegt
return;
}
// Es wird solange geprüft, bis die Spielgrenzen erreicht sind,
// da somit Felder, welche noch viele Möglichkeiten bieten, besser bewertet werden.
countFieldTypes(field, p, posX, posY, modX, modY,occupiedByPlayer, free);
}
int faculty(int n)
{
return n == 0 ? 1 : n * faculty(n - 1);
}
int getLineIndex(int **field, int p, int posX, int posY, int modX, int modY)
{
int occupiedByPlayerPart1 = 0;
int free1 = 0;
int occupiedByPlayerPart2 = 0;
int free2 = 0;
countFieldTypes(field, p, posX, posY, modX, modY, occupiedByPlayerPart1,free1);
countFieldTypes(field, p, posX, posY, modX * (-1), modY * (-1), occupiedByPlayerPart2, free2); // für die gegenüberliegende Seiten
// Siehe Zeile 75 -
if (occupiedByPlayerPart1 > 0)
occupiedByPlayerPart1 += 2;
if (occupiedByPlayerPart2 > 0)
occupiedByPlayerPart2 += 2;
// Die leeren Zeilen werden verdoppelt
// Die Anzahl der besetzen Steine mit Fakultät berechnet
return ((free1 + free2) * 3) + faculty(occupiedByPlayerPart1) + faculty(occupiedByPlayerPart2);
} // Freie Felder werden mit 3 multipliziert da es beim Überwiegen noch viele Chancen gibt; ansonsten unterbewertet
int calculateChoiseIndex(int **field, int p, int posX, int posY)
{
//
// 6 1 2 3
// 5 X X X
// 4 XXX
// 3 4XX+XX4
// 2 XXX
// 1 X X X
// 0 3 2 1
// 0123456
//
int indexP1 = 0;
// Die diagonalen müssen als eine Zeile betrachtet werden.
indexP1 += getLineIndex(field, p, posX, posY, -1, 1);
indexP1 += getLineIndex(field, p, posX, posY, 0, 1);
indexP1 += getLineIndex(field, p, posX, posY, 1, 1);
indexP1 += getLineIndex(field, p, posX, posY, -1, 0);
int indexP2 = 0;
// Die diagonalen müssen als eine Zeile betrachtet werden.
indexP2 -= getLineIndex(field, 3 - p, posX, posY, -1, 1);
indexP2 -= getLineIndex(field, 3 - p, posX, posY, 0, 1);
indexP2 -= getLineIndex(field, 3 - p, posX, posY, 1, 1);
indexP2 -= getLineIndex(field, 3 - p, posX, posY, -1, 0);
//field[posX, posY].ChoiseIndexP1 = indexP1;
//field[posX, posY].ChoiseIndexP2 = (-1) * indexP2;
return indexP1 > (indexP2 * (-1)) ? indexP1 : indexP2; // das gleiche wie if(index P1 > (indexP2*(-1))) return indexP1; else indexP2;
}
struct MoveValue bestMove(int **field, int sideToMove, int depth, int maxDepth) //Züge im vorraus berechnen
{ // über maxDepth wird die "cleverness" gesetzt, quasi die Züge im vorraus
// Speichert die beste Score
struct MoveValue best_score;
best_score.Score = -100000; // Default-Wert vorgeben
best_score.Column = 0;
if (depth % 2 == 1)
best_score.Score *= -1;
struct MoveValue mv;
mv.Score = 0;
mv.Column = 0;
//int directWinningChance = 0;
for (int x = 0; x < 7; x++)
{
// Versuche einen Stein in jede der 7 Spalten
mv.Column = x;
if (field[x][6 - 1] != 0)
continue; // Wenn die Spalte voll ist, ignoriere sie
// Die Spalte finden wo man einen Stein setzen kann - y ist die Reihe
int y = 0;
while (y < 6 && field[x][y] != 0)
y++;
field[x][y] = sideToMove;
struct MoveValue cur;
cur.Score = 0;
cur.Column = 0;
cur.Score = calculateChoiseIndex(field, sideToMove, x, y);
if (depth == maxDepth)
{
mv.Score = cur.Score;
//directWinningChance = 1;
}
else // Weiter suchen (Rekursiver Aufruf)
mv.Score = bestMove(field, 3 - sideToMove, depth + 1, maxDepth).Score;
// wenn dieser move besser ist, nutzen diesen anstatt des anderen
if (mv.Score > best_score.Score && depth % 2 == 0)
{
best_score.Score = mv.Score;
best_score.Column = mv.Column;
}
else if (mv.Score < best_score.Score && depth % 2 == 1)
{
best_score.Score = mv.Score;
best_score.Column = mv.Column;
}
// Feld nullen und Zug zurück setzen
field[x][y] = 0;
}
return best_score; // beste Wahl/Score
}
int cpuChoice(int **field, int player, int difficulty) {
return bestMove(field, player, 0, difficulty + 4).Column;
}
Ihr könnt mir auch nur sagen wo der Fehler ist, das würde mir ausreichen. Soweit funktioniert alles, also die anderen Funktionen wie Visualisierung, Felderstellung, Prüfung auf 4 in einer Reihe/Diagonale/Spalte in alle Richtungen passt. Meiner Meinung nach kann es nur die Feldwertberechnung sein, aber ich sehe da einfach nicht den Fehler.
Gruß
Zuletzt bearbeitet:
