PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : 4 gewinnt KI


jonas1234
14.06.2004, 10:32
hi alle
hat jemand infos/ansätze/codeausschnitte einer 4gewinnt KI? bin hier ziehmlich hilflos mich mit themen wie minmax prinzip oder alpha beta cutoff am rumschlagen

gruss
jonas


Caesar
14.06.2004, 12:20
hi!
die sache wird auch nicht einfach. hier mal ein link:

http://www.db.fmi.uni-passau.de/Sommercamp2001/VierGewinnt/code.html

gruß,
*Caesar*

jonas1234
24.06.2004, 11:41
hab ne verständniss frage

was ist mit spieltiefe gemeint? kann mir das jemand erklaeren?

Caesar
24.06.2004, 12:14
hi!
wo hast du das gelesen?

jonas1234
24.06.2004, 12:53
meine cheffe hat mir ma was wegen maxTiefe etc erklärt, dort wo dan die rekursion für dern alphabeta ablauf stattfindet

so im stiel von alphabeta(tiefe ..)
if(tiefe=maxTiefe)
etc

komm irgendwie nicht so drauss und der chef ist eben nicht da

hier steht auch was von tiefe
http://ai-depot.com/LogicGames/MiniMax-Optimisations.html

jonas1234
24.06.2004, 13:14
meine cheffe hat mir ma was wegen maxTiefe etc erklärt, dort wo dan die rekursion für dern alphabeta ablauf stattfindet

so im stiel von alphabeta(tiefe ..)
if(tiefe=maxTiefe)
etc

komm irgendwie nicht so drauss und der chef ist eben nicht da

hier steht auch was von tiefe
http://ai-depot.com/LogicGames/MiniMax-Optimisations.html

meint man damit echt, dass man zB bei 7 reihen, 7 verschiedene möglichkeiten hat einen stein reinzuwerfen? und falls eine voll ist hat man nur noch 6 etc

oder wie tief der pc in einem minmaxthree nach zügen sucht?

ups wollte eigentlich nur ändern und nicht ne antwort schreiben

DanDanger
24.06.2004, 22:21
Hi,

was beim MiniMax Algorithmus (um den es hier wohl geht) passiert ist Folgendes :
Ausgehend von der aktuellen Spielsituation werden alle weiteren Möglichkeiten in einem Binären Baum "durchgespielt". (Gute Bsp. dazu: http://www.generation5.org , http://www.ai-junkie.com , google ).
Dabei wird jedem Theoretisch Möglichem Zug eine Punktzahl zugewisen
(z,B. +1 für einen "guten" Zug, -1 für einen "Schlechten" Zug).
Am Ende (bei 4 Gewinnt ist das Ende erreicht, wenn alle Felder besetzt sind)
geht man halt vom Wurzelknoten aus den Baum entlang und sucht den Weg mit
der höchsten (bzw. niedrigsten) Punktzahl. Dementsprechend macht man dann seinen Zug.

Ich kann Dir nur empfehlen :
http://www.aihorizon.com
bzw.
http://www.aihorizon.com/essays/basiccs/trees/minimax.htm

Dort wird ein Completer MiniMax-Code für TicTacToe implementiert (und erklärt).
Das sollte sich ja relativ leicht auf "4 Gewinnt" ummünzen lassen.

Gruss
DanDanger

coldstrongvision
27.06.2004, 12:05
jonas
****

Du baust einen Suchbaum auf. D.h. ausgehend von einem leeren Spielfeld baust du einen Baum für jeden möglichen Zug des Spielers und Gegenspielers auf.
Zb. Tic Tac Toe.
Am Anfang hast du 9 Möglichkeiten dein Kreis zu setzen. Das wäre die Erste Ebene im Baum.
Jetz kommen die Möglichen Antwortzüge von Spieler 2 dazu. Und das "unter jedem" Knoten usw.
Am Ende hast du dann einen großen Baum wo alle Möglichkeiten des Setzens der Kreuze und Kreise drin steht.
Das kannst du dann mit dem alpha beta Algo verbessern. Im Prinzip lässt du dort alle Züge weg wo du weisst das sie dir sowieso nichts bringen, was zur Folge hat das der Suchbaum verkleinert wird.
Das ist für einfache Games, wo man zb. den kompletten Suchbaum aufbauen könnte.

Wirds jetzt komplexer wie zb. beim Schach wo es Milliarden von Möglichkeiten gibt greift man zu dem Trick die Suchtiefe zu beschränken, dh. du wanderst nur vielleicht 5 Züge im Vorraus im Baum runter. Und für die Breite also die Spielzustände verwendet man dann eine Heuristik um den Zuständen eine Bewertung zu verpassen.
Das Ganze hat natürlich zur Folge das du immer nur Ausschnitte des Baumes betrachtest, was zur Folge haben kann das der Rechner nicht zwangsläufig gewinnen muss, das läuft sozusagen auf eine Strategie drauf hinaus das du nach einem Zug suchst der dir innerhalb der Tiefenbeschränkung (zb. 5 Züge im Vorraus) einen Vorteil bringt.

jonas1234
12.07.2004, 09:30
k vielen dank für die vielen info, hab jetzt mal ansatzweise was gebastelt mit minamax, alpha beta ist jedoch noch nicht eingebaut

jedoch spielt meine KI irgendwie zum kotzen, ich komm nicht nach was ich falsch mache, kann mir da jemand helfen? ich post jetzt ma meinen ganzen code, da ich im mom keine moeglichkeit habe das file upzuloaden, das ganze wurde im borland c++builder 6 geschrieben, reine konsolen anwendung (drum ist es grafisch auch ziehmlich schlecht, aber darum gehts mir auch nicht)


//---------------------------------------------------------------------------

#include <stdio.h>
#include <conio.h>
#include <iostream.h>
#include <string.h>
#include <assert.h>

#define X 7
#define Y 6

#define PL 1
#define PC 2
#define MAXTIEFE 7

#define GEWONNEN 1000


class spielfeld
{
public:
// Konstruktor der alle Spieldfelder auf wert 0 setzen
spielfeld();

// Funktion die das Feld zu jeder Situation zeigt
void feldGen();

// Funktion die den Sieger des spiels zurück liefert
int bewerte(void);

// Player or PC Move
int move(int plorpc, spielfeld* nr1);

int pcmove();

int alphabeta(int tiefe, int min, int max);

int minmax(int tiefe, int& bestmove);

int freieZeile(int spalte);


private:
// feld mit 7*6
int feld[X][Y];
int px,py; //variablen was der player gemacht hat
int sumc;
int sump;


};

// Konstruktor

spielfeld::spielfeld()
{
for(int y=0;y<Y;y++)
{
for(int x=0;x<X;x++)
{
// zB feld 1 Reihe 2
feld[x][y]=0;
}
}

}

void was(void) {
}

int spielfeld::freieZeile(int Spalte)
{
for(int y=Y-1;y>=0;y--)
{
if ((y<0) || (y>=Y)) {
was();
}
if ((Spalte<0) || (Spalte>=X)) {
was();
}
if(feld[Spalte][y]==0)
{
return y;
}

}
return -1;
};

int
bewerte4(int v1, int v2, int v3, int v4) {
const int plPoints [4] = { 1,3,9,GEWONNEN };
const int pcPoints [4] = { 1,2,6,GEWONNEN };

int plsum = ((v1==PL) + (v2==PL) + (v3==PL) + (v4==PL));
int pcsum = ((v1==PC) + (v2==PC) + (v3==PC) + (v4==PC));

//if (plPoints[plsum] == GEWONNEN || pcPoints[pcsum] == GEWONNEN)
// plsum = plsum;

if (plsum == 0)
return pcPoints[pcsum];
if (pcsum == 0)
return -plPoints[plsum];

return 0;
}


int
spielfeld::bewerte(void)
{
int a,x,y;
int bew;

bew=0;

for (x=0; x<X-3; x++) {
for(y=0;y<Y;y++) {
int v = bewerte4(feld[x+0][y],
feld[x+1][y],
feld[x+2][y],
feld[x+3][y]);
if (abs(v) == GEWONNEN)
return v;
bew += v;
}
}

for (x=0; x<X; x++) {
for(y=0;y<Y-3;y++) {
int v = bewerte4(feld[x][y+0],
feld[x][y+1],
feld[x][y+2],
feld[x][y+3]);
if (abs(v) == GEWONNEN)
return v;
bew += v;
}
}

for (x=0; x<X-3; x++) {
for(y=0;y<Y-3;y++) {
int v = bewerte4(feld[x+0][y+0],
feld[x+1][y+1],
feld[x+2][y+2],
feld[x+3][y+3]);
if (abs(v) == GEWONNEN)
return v;
bew += v;
}
}

for (x=0; x<X-3; x++) {
for(y=3;y<Y;y++) {
int v = bewerte4(feld[x+0][y-0],
feld[x+1][y-1],
feld[x+2][y-2],
feld[x+3][y-3]);
if (abs(v) == GEWONNEN)
return v;
bew += v;
}
}

return bew;
}


int spielfeld::minmax(int tiefe, int& bestmove) {

int bew;
int move;

//bestmove = 0;
bew = bewerte();
if (tiefe == Y)
return bew;

//if (abs(bew) == GEWONNEN)
// return bew;


if (tiefe & 1) {
// min node
bew = +2*GEWONNEN;

for (int spalte=0; spalte<X; spalte++) {
int z = freieZeile( spalte );
if (z < 0)
continue;

feld[spalte][z] = PL;
int resultat = minmax( tiefe +1, move );
feld[spalte][z] = 0;

if (resultat < bew) {
bew = resultat;
bestmove = spalte;
}
}
}
else {
// max node
bew = -2*GEWONNEN;

for (int spalte=0; spalte<X; spalte++) {
int z = freieZeile( spalte );
if (z < 0)
continue;

feld[spalte][z] = PC;
int resultat = minmax( tiefe +1, move );
feld[spalte][z] = 0;

if (resultat > bew) {
bew = resultat;
//Fehler->
bestmove = spalte;

}
}
}
return bew;
}

int spielfeld::pcmove()
{
int move;
int bew;
int z;

bew = minmax(0, move );

cout << endl << bew;
getch();

z = freieZeile( move );
if (z >= 0) {
assert ( (move>=0) && (move<X) );
feld[move][z] = PC;
}
return move+1;

}

int spielfeld::move(int plorpc, spielfeld* nr1)
{
int player_no;
int a;

int eingabe=-1;

// PC DRAN
if(plorpc == PC)
{
eingabe=pcmove();
clrscr();
nr1->feldGen();
cout << endl << "der pc hat die Reihe " << eingabe << " gewaehlt";
}
else
{


// player Spielstein einfügen + überprüfen ob er überhaupt möglich war
while(eingabe == -1)
{
cout << endl << "In welcher Reihe moechten sie einen Spielstein einfuegen? (Reihe 1-7)" << endl;
cin >> eingabe;

if ((eingabe < 1) || (eingabe > X)) {
cout << endl << "hier ist keine eingabe moeglich";
eingabe = -1;
continue;
}

int z = freieZeile( eingabe-1 );

if (z < 0) {
cout << endl << "Die Reihe ist leider schon voll";
eingabe = -1;
continue;
}

feld[eingabe-1][z] = plorpc;

}

clrscr();
nr1->feldGen();
cout << endl << "sie haben die Reihe " << eingabe << " gewaehlt";


}

}

int spielfeld::alphabeta(int tiefe, int min, int max)
{
tiefe = 0;

if(tiefe!=MAXTIEFE)
{

}
}

void spielfeld::feldGen()
{
int reihe = 0;

cout << "\t\t************---Aktueller Stand---************" << endl << endl;

cout << "\t\t\tReihe: 1 2 3 4 5 6 7" << endl;


while(reihe<Y)

{
cout << "\t\t\t ";

for(int i=0;i<X;i++)
{
if(i!=Y)
cout << "|" << feld[i][reihe];
else
// Abschluss Strich
cout << "|" << feld[i][reihe]<< "|";
}
reihe++;
cout << endl;
}



}


int main()
{
int spieler=0;

spielfeld nr1;
nr1.feldGen();

for(int t=0;t<1000;t++)
{
if(spieler==0)
spieler=1;

// Falls return = 1000 dann hat einer gewonnen
if(nr1.move(spieler, &nr1)==GEWONNEN)
t=1000;

if (spieler ==1)
{
spieler=2;
}
else
{
spieler=1;
}

}

getch();
return 0;
}
//---------------------------------------------------------------------------

Quantumseeker
18.07.2004, 17:48
Hallo,
ich schreibe auch gerade an einem bewertungsalgorithmus, da ich keine tiefe von 7 machen kann ^^
jetzt habe ich die Bewertungsfunktion nicht ganz verstanden. die macht ja im prinzip nichts anderes, als wenn die tiefe null ist, zu bewerten, wie gut ein spielzug meinerseits ist. Könnte mir das jemande erklären?
Weiterhin ist ja ein schlechter Spielzug für meinen gegner ein guter für mich *verwirrt*
Wie müsste da eine solche funktion aussehen? die bewertefunktion des sources ist mir das nicht sehr klar