KI für 4 gewinnt



  • Hallo alle,

    ich versuche jetzt seit einiger Zeit meine KI zum laufen zu kriegen, aber es funktioniert einfach nicht.

    Evtl könnte jemand drüberschauen und mir sagen wo ich den Fehler mache...

    Hier sind meine Klassen:

    TreeElement-Klasse: Soll einen Knoten im (Min-Max)Baum represäntieren.
    Die chars 'b' (Computer) und 'r' (Spieler) zeigen wessen Ebene gerade dran ist.
    Globals::play_slot_rec() wirft den entsprechenden Stein in den Slot, und Globals::remove_slot entfernt ihn wieder (sollte).

    Globals::isSlotFull() überprüft nur ob nicht eh schon 7 Steine in dem Slot sind.

    Als heuristik verwende ich folgende Funktion:
    500+10*result.p_anz_2+40*result.p_anz_3+50000*result.p_anz_4 - 10*result_opponent.p_anz_2-5000000*result_opponent.p_anz_3-5000000*result_opponent.p_anz_4;

    Wobei in result (bzw result_opponent) die jeweiligen 2er,3er und 4er Kombinationen stehen.

    #include "Tree_Element.h"
    #include <limits>
    
    TreeElement::TreeElement()
    {
    	for(int i=0;i<7;i++)
    	{
    		childs[i]=NULL;
    	}
    }
    
    TreeElement::TreeElement(short move, int i_currentDepth, int maxDepth)
    {
    	for(int i=0;i<7;i++)
    	{
    		childs[i]=NULL;
    	}
    	this->maxDepth = maxDepth;
    	currentDepth = i_currentDepth+1;
    	my_move = move;
    }
    
    TreeElement::~TreeElement()
    {
    	for(int i=0;i<7;i++)
    	{
    		if(childs[i]!=NULL)
    		{
    			delete childs[i];
    		}
    	}
    }
    
    // builds recursion and returns the best value
    int TreeElement::getCalc()
    {
    	// save results
    	int res[7];
    
    	char c;
    	if(currentDepth%2==1)
    		c='b';
    	else
    		c='r';
    
    	// make the play
    	int line = Globals::play_slot_rec(my_move, c);
    
    	// Check for remaining moves
    	int possible_moves = 0;
    	for(int i=0;i<7;i++)
    	{
    		if(!Globals::isSlotFull(i))
    		{
    			++possible_moves;
    			break; // Break since at least 1 possible move left
    		}
    	}
    
    	if(currentDepth == maxDepth || possible_moves == 0) // recursion end reached, return
    	{
    		Globals::Anz_all result;
    		result.p_anz_2=0;
    		result.p_anz_3=0;
    		result.p_anz_4=0;
    		Globals::Anz_all result_opponent;
    		result_opponent.p_anz_2=0;
    		result_opponent.p_anz_3=0;
    		result_opponent.p_anz_4=0;
    		result = Globals::getAllCounts('b');
    		result_opponent = Globals::getAllCounts('r');
    		Globals::remove_slot(my_move,line);
    		// Heuristik
    		int ret_best = 500+10*result.p_anz_2+40*result.p_anz_3+5000*result.p_anz_4 - 10*result_opponent.p_anz_2-40*result_opponent.p_anz_3-5000*result_opponent.p_anz_4;
    		return ret_best;
    	}
    	// still not deep enough
    	else
    	{
    		// build nodes + call recursion
    		for(int i=0;i<7;i++)
    		{
    			// only make childs for possible plays
    			if(!Globals::isSlotFull(i))
    			{
    				childs[i] = new TreeElement(i, currentDepth, maxDepth);
    				res[i] = childs[i]->getCalc();
    			}
    		}
    	}
    
    	// at the end, undo the play
    	Globals::remove_slot(my_move,line);
    
    	// Get the best result
    	int best_res = 0;
    	bool first=true;
    
    	for(int i=0;i<7;i++)
    	{
    		if(childs[i]!=NULL)
    		{
    			if(first)
    			{
    				best_res = res[i];
    				first=false;
    			}
    			// player returns min
    			else if(c=='r')
    			{
    				if(res[i]>best_res)
    					best_res = res[i];
    			}
    			// CPU returns max
    			else
    			{
    				if(res[i]<best_res)
    					best_res = res[i];
    			}
    		}
    	}
    	return best_res;	
    }
    
    int TreeElement::startFromRoot()
    {
    	// this will save the index of the best play
    	int best_res = -1;
    	int res[7];
    
    	// build nodes + call recursion
    	for(int i=0;i<7;i++)
    	{
    		// only make childs for possible plays
    		if(!Globals::isSlotFull(i))
    		{
    			childs[i] = new TreeElement(i, currentDepth, maxDepth);
    			res[i] = childs[i]->getCalc();
    		}
    	}
    
    	// try to figure the result
    	int max=INT_MIN;
    	for(int i=0;i<7;i++)
    	{
    		if(childs[i]!=NULL)
    		{
    			if(res[i]>=max)
    			{
    				max=res[i];
    				best_res = i;
    			}
    		}
    	}
    	return best_res;
    
    }
    

    Aufruf passiert dann im Main mit:

    TreeElement *t = new TreeElement(1, 0, 7);
    int ki_play = t->startFromRoot();
    Globals::play_slot(ki_play, 'b');
    

    Ich hoffe jemand von euch kann mir hier helfen, ich stehe atm ziemlich auf der Leitung...

    Edit:
    Ich hab jetzt ein paar Fehler gefunden (neuer Code is oben eingefügt), jedoch beginne ich daran zu zweifeln dass meine Heuristik gut ist ...

    Kennt jemand eine Seite (oder hat schon selbst so eine KI gemacht) wo eine gute heuristik beschrieben wird?


Anmelden zum Antworten