Sign in to follow this  
Mizipzor

Need help with AI application

Recommended Posts

Trying to learn som AI. In this little program the "creatures" are supposed to find the number twenty. The program check which of the creatures that was the closest, mate them to create new creatures and then overwrite the creatures with the new generation. However, when Im printing the second generation I get some pretty wierd numbers. I guess that means I somewhere leave an array when I calculate. I think the problem is in the "next generation gene construction" part but I post the entire code just in case. Anyone see what Im doing wrong? where I leave that array? Also, those calculations can be quite complicated (at least for me :P)... thats why I screwed up now I guess, but ask if you cant figure out why Im doing something and Ill try to explain (of course). main.cpp
#include <windows.h>
#include <iostream>
#include <conio.h>
#include <vector>

#include "creature.h"
#include "constants.h"

using namespace std;

// global instance of creature class
creature creature[CREATURES];

struct testStruct {
	int id;
	int offset;
};

void nextGeneration();

int main(int argc, char *argv[])
{
	// we want to be able to randomize
	srand(GetTickCount());
	
	cout << "ALL CREATURES: \n\n";
	
	for(int i = 0; i < CREATURES; i++) {
		cout << "#" << i << ": ";
		creature[i].printCells();
		cout << "\tTotal: " << creature[i].calculateTotal();
		cout << "\tOffset: " << creature[i].calculateOffset();
		cout << endl;
	}
	
	nextGeneration();
	
	cout << "\n\nALL CREATURES: \n\n";
	
	for(int i = 0; i < CREATURES; i++) {
		cout << "#" << i << ": ";
		creature[i].printCells();
		cout << "\tTotal: " << creature[i].calculateTotal();
		cout << "\tOffset: " << creature[i].calculateOffset();
		cout << endl;
	}

	getch();
	return 1;
}

void nextGeneration() {
	const int slotsInNextGen = CREATURES/2;
	int slotsLeft = slotsInNextGen;
	
	testStruct selected[slotsInNextGen];
	for(int i = 0; i < slotsInNextGen; i++) {
		selected[i].id = 99;	// if this is unedited we know something is wrong
		selected[i].offset = CELL_SIZE*10;	// high number so there is only creatures later
	}
	
	// this is to be done for all creatures
	for(int c = 0; c < CREATURES; c++) {
		// every creature test if it has a place in the next generation
		for(int i = 0; i < slotsInNextGen; i++) {
			// if the current creatures offset is lower than the creature already listed here, take its place!
			if(creature[c].calculateOffset() < selected[i].offset) {
				if(slotsLeft == 0) {	// no slots left? battle for the slots!
					selected[i].id = c;
					selected[i].offset = creature[c].calculateOffset();
				}
				
				if(slotsLeft != 0) {	// if there is slots left, dont replace yet
					int anotherSlot = i+1;	// just add one, maybe were lucky :)
					if(anotherSlot > slotsInNextGen || selected[anotherSlot].id != 99) {	// if slot is out of range or not unoccupied
						for(int i = 0; i < CREATURES; i++) {	// test the entire array for an id of 99 (=unedited)
							if(selected[i].id == 99) {			// if found, take it
								anotherSlot = i;
								break;
							}
						}
					}						
							
					selected[anotherSlot].id = c;
					selected[anotherSlot].offset = creature[c].calculateOffset();
					slotsLeft--;
				}
				break;	// next creature (to prevent one creature from getting more than one slot)
			}
			
			// otherwise just skip to the next element, ultimately finishing the loop without a place (youre dead then... bwaha)
		}
	}
	
	cout << "\nCREATURES SELECTED FOR NEXT GENERATION: \n\n";
	for(int i = 0; i < slotsInNextGen; i++)
		cout << i << ": #" << selected[i].id << "\tOffset:\t" << selected[i].offset << endl;

	// ******* NEXT GENERATION GENE CONSTRUCTION ********
	
	int newGene[CREATURES][CELL_SIZE];	// the array to hold one new gene for each creature in the next generation
	int parent = 0;	// the parent we take the gene from	
	
	for(int parent = 0; parent < slotsInNextGen; parent += 2) {				// parent += 2 because they mate in couples	
		for(int offspring = parent; offspring < parent+2; offspring++) {	// each couple make two offsprings
		
			for(int i = 0; i < CELL_SIZE/2; i++)
				newGene[offspring][i] = creature[ selected[ parent ].id ].getCellRaw(i);
				
			for(int i = 0; i < CELL_SIZE/2; i++) {
				// take the later half in second gene
				// parent+1 so we get the next one in the list for selected creatures for the next generation (they cant mate with themselves)
				newGene[offspring][CELL_SIZE-i] = creature[ selected[ parent+1 ].id ].getCellRaw(CELL_SIZE-i);
			}
				
			// mutation
			for(int i = 0; i < MUTATION_RATE; i++) {
				if(i == 0)
					newGene[offspring][CELL_SIZE/2] = rand()%2;
					
				if(i != 0) {
					newGene[offspring][CELL_SIZE/2+i] = rand()%2;	// we work in both directions simultanously from the middle
					newGene[offspring][CELL_SIZE/2-i] = rand()%2;
				}
			}
		}
	}
	
	// ******** NEXT GENERATION CREATION ********
	
	for(int i = 0; i < CREATURES; i++) {		
		for(int j = 0; j < CELL_SIZE; j++)
			creature[i].writeCellRaw(j, newGene[i][j]);			
	}			
}

creature.h
#ifndef CREATURE_INCLUDED
#define CREATURE_INCLUDED

#include "constants.h"

class creature {
public:
	creature();	//constructor
	void randomizeCells();
	void printCells();
	
	int calculateTotal();
	int calculateOffset();
	
	int getCellRaw(int specifiedCell);	// return the binary digit at the specified cell
	void writeCellRaw(int specifiedCell, int newBinary);
	
	int abs(int i);	// makes sure a number if positive
	
private:
	int cell[CELL_SIZE];
};

#endif

creature.cpp
#include "creature.h"
#include <iostream>

using namespace std;

creature::creature() {
	randomizeCells();
}

void creature::randomizeCells() {
	// fill them with junk	
	for(int i = 0; i < CELL_SIZE; i++)
		cell[i] = rand()%2;
}

void creature::printCells() {
	for(int i = 0; i < CELL_SIZE; i++)
		cout << cell[i];
}

int creature::calculateTotal() {
	// holder for the total number
	int total = 0;
	for(int i = 0; i < CELL_SIZE; i++)
		total += cell[i];
	return total;
}

int creature::calculateOffset() {
	int worth = this->calculateTotal() - TARGET_NUMBER;
	return abs(worth);
}

int creature::getCellRaw(int specifiedCell) {
	return cell[specifiedCell];
}

void creature::writeCellRaw(int specifiedCell, int newBinary) {
	cell[specifiedCell] = newBinary;
	return;
}

int creature::abs(int i) {
	if(i >= 0)
		return i;
		
	if(i < 0) {
		i *= -1;
		return i;
	}
}

constants.h
#ifndef CONSTANTS
#define CONSTANTS

const int TARGET_NUMBER = 20;
const int CELL_SIZE = 20;
const int CREATURES = 12;	// CREATURES/2 must be even
const int MUTATION_RATE = 1;

#endif

Share this post


Link to post
Share on other sites
Maybe you can be a bit more specific about where the error occurs? Your current question corresponds to it doesn't work fix it for me and I don't think many people are that eager to debug your application.

Greetz,

Illco

Share this post


Link to post
Share on other sites
No sorry, didnt mean it sound that way. I said I think Ive located the error to the // ******* NEXT GENERATION GENE CONSTRUCTION ******** part, look for the comment in the code. Been stuck with the problem for a few hours now. Took a break but before that I posted the problem here. I know its a bit unspecific but maybe one of the reeeally good guys helps, that just looks at a loop for two secs and hit me with fifteen things Ive couldve done better. :P

Share this post


Link to post
Share on other sites
Ok, I've gone to that part. Here might be something to check. First you declare a new array:

int newGene[CREATURES][CELL_SIZE];


Then a loop kicks in, running parent within [0,slotsInNextGen-1].

for(int parent = 0; parent < slotsInNextGen; parent += 2) {


Then a sub-loop is used which loops offspring within [parent,parent+1].

for(int offspring = parent; offspring < parent+2; offspring++) {


And then offspring is used to index the array:

newGene[offspring][i] =


This is a bit tricky but try to check the bounds. First, we need to be sure that slotsInNextGen remains below CREATURES, because that is the array size. I couldn't check that quickly but you can. Then, more fishy, offspring loops based on parent. Parent's maximum value as specified by the loop is slotsInNextGen-1. And offspring's maximum value is parent+1. So offspring's value could be slotsInNextGen. So even if slotsInNextGen is always below CREATURES, offspring's value is not necessarily so. Summarizing: I think offspring can become just one too large at times.

Greetz,

Illco

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this