Thread: Simple Socialising Chat Bots

  1. #1
    Registered User
    Join Date
    Sep 2007
    Posts
    127

    Question Simple Socialising Chat Bots

    Hi,

    I started programming in C++ a few months ago, and I'm also really interested in psychology (hence I'm doing a degree in it). So I've recently started this simple program that relates to human dominance hierarchies, status, insults/ compliments, that kind of thing.

    Basically at present all the program does is generate 4 ridiculously simple chat bots. I call them cretins. Each cretin can either insult or compliment the other cretins. The cretins perceive the status of the other 3 cretins in integer form, so that if cretin 1 insults cretin 2, cretin 2 lowers it's perception of cretin 1's status by 5 points. And the opposite for compliments. Cretins can also laugh at insults- if they see a cretin insult another cretin, they reduce their perception of the insult receiver's status by 1 point.

    At present this might seem like a ludicrously simple way of trying to simulate human behaviour, but as the program gets more complicated, it should hopefully get more convincing. I intend to eventually add in a vast array of social rules and instincts, such as cretins being able to set other cretins as enemies or friends, only talking to other cretins if that cretin is popular enough, considering certain words fashionable ("get lost" or "I like you" will be replaced by banks of pre-set phrases), all kinds of stuff. And obviously, it'll end up like a proper chat room, with cretins speaking to other cretins in private rooms etc.

    Here's the stuff I need help with currently:

    a) Streamlining the code. This program is a LOT longer than it needs to be, I'm sure. I think it could be made shorter by having arrays instead of loads of different functions and variables such as move1, move2 etc.

    b)What do you think the best way of adding in a memory for each cretin would be? I want to make it so that each cretin can remember whether it was insulted by another cretin and then respond. This way cretins will each be able to have proper strategies e.g. tit for tat. A pretty simple but cool thing would be to have escalating insult matches so that they start off with insults of weight 1 but get progressively more as the insults get more aggressive.

    If anyone could help me with these I'd be really grateful. I'd also really appreciate it if you could keep your solutions as simple as possible because like I said I'm a beginner to C++.

    Thanks.

    Code:
    // Cretinpolitics by Ben Greenwood [email protected] 27/11/07
    
    #include <iostream>
    #include <string>
    #include <list>
    using namespace std;
    
    int movecounter = 1;
    
    class cretin {
    private:	
    	std::string name;
    	int id;
    	int	status1;					// How this cretin perceives the status of 
    	int	status2;					// the 4 cretins including itself- Arnold is always
    	int	status3;					// 1, Barry is always 2, Colin is always 3 and 
    	int	status4;					// Dave is 4, whoever pereives who. 
    	int move1;						// Each cretin just has a strategy of
    	int move2;						// 3 preset moves at present. 
    	int move3;
    public:
    	cretin(const std::string& nm, int i,
    			int s1, int s2, int s3, int s4,
    			int m1, int m2, int m3)
    	{
    		name = nm;
    		id = i;
    		status1 = s1;	
    		status2 = s2;
    		status3 = s3;
    		status4 = s4;
    		move1	= m1;
    		move2	= m2;
    		move3	= m3;
    	}
    
    	std::string getname	()	{ return name; };
    	int getid()				{ return id; };
    	int getstatus1()		{ return status1; };
    	int getstatus2()		{ return status2; };
    	int getstatus3()		{ return status3; };
    	int getstatus4()		{ return status4; };
    	int getmove1() 		{return move1; };
    	int getmove2() 		{return move2; };
    	int getmove3() 		{return move3; };
    	void display()
    	{
    		std::cout << id << ": " << name << "\n"
    				  << getstatus1() << "\n" 
    				  << getstatus2() << "\n" 
    				  << getstatus3() << "\n"
    				  << getstatus4() << "\n";
    	}
    	void setstatus1(int s1){status1 = s1;}
    	void setstatus2(int s2){status2 = s2;}
    	void setstatus3(int s3){status3 = s3;}
    	void setstatus4(int s4){status4 = s4;}
    };
    void cretinthink(std::list<cretin>& cretinlist);
    int main() {
    	int cretinscore1;			// These are the final scores that determine who
    	int cretinscore2;			// was the most or least popular
    	int cretinscore3;			// at the end of the session.
    	int cretinscore4;
    
    	std::list<cretin> cretinlist;
    	cretinlist.push_back(cretin("Arnold",1,0,0,0,0, 5,-5,-5));			// Each insult or compliment gets 
    	cretinlist.push_back(cretin("Barry", 2,0,0,0,0,-5, 5, 5));			// the sayer plus or minus 5 points
    	cretinlist.push_back(cretin("Colin", 3,0,0,0,0,-5,-5,-5));			// in the receiver's eyes.
    	cretinlist.push_back(cretin("Dave" , 4,0,0,0,0, 5, 5, 5));
    
    	int choice;
    
    	while(1) 
    	{
    	cout << "\nEnter 1 for next round.\n";
    	cin >> choice;
    	if (choice != 1)
    		break;
    	cretinthink(cretinlist);
    	if (movecounter < 3)
    		movecounter++;
    	else 
    		movecounter = 1;
    	}
    	
    	// The following deals with outputting each cretin's final status ratings
    	// for each of the other cretins in it's opinion.
    
    	std::list<cretin>::iterator iter = cretinlist.begin();
    
    	while (iter != cretinlist.end())
    	{
    		iter->display();
    		iter++;
    	};
    
    // The following deals with outputting each cretin's total popularity score, based
    // on the opinions held of it by all the other cretins. This is not the final picture because
    // in reality people have allies/ enemies etc. Ultimately the aim of the game will, in the 
    // future, be to have as many allies who are willing to defer to you. So there will be some
    // kind of thing like this because something like this will kind of describe how willing others
    // are to defer to you e.g. who among your allies you can insult without them responding or 
    // becoming an enemy. 
    
    	std::list<cretin>::iterator iter2 = cretinlist.begin();
    	iter = cretinlist.begin();
    
    		cretinscore1 = 0;
    		//iter2++;
    
    while (iter->getid() <= 4)
    {
    	if (iter->getid() == 1)
    	{ while (iter2 != cretinlist.end())
    		{ cretinscore1 = cretinscore1 + iter2->getstatus1();
    			iter2++; } 
    	}
    
    	if (iter->getid() == 2)
    	{ while (iter2 != cretinlist.end())
    		{ cretinscore1 = cretinscore1 + iter2->getstatus2();
    			iter2++; } 
    	}
    
    	if (iter->getid() == 3)
    	{ while (iter2 != cretinlist.end())
    		{ cretinscore1 = cretinscore1 + iter2->getstatus3();
    			iter2++; } 
    	}
    
    	if (iter->getid() == 4)
    	{ while (iter2 != cretinlist.end())
    		{ cretinscore1 = cretinscore1 + iter2->getstatus4();
    			iter2++; } 
    	}
    
    		cout << endl << iter->getname() << " ended with a popularity of score of: " << cretinscore1 << endl;
    		cretinscore1 = 0;
    
    		iter2 = cretinlist.begin();
    		if (iter->getid() == 4)		// These 2 lines stop it trying to make iter
    			break;					// go past the last cretin and cause an error. 
    		iter++;
    		cretinscore1 = 0;
    }
    	return 0;
    }
    void cretinthink(std::list<cretin>& cretinlist) 
    {
    	int tempinsult;
    	int targetcretin = 1;
    
    	cout << "Round 1" << endl << endl;
    	std::list<cretin>::iterator iter;
    	std::list<cretin>::iterator iter2;
    	std::list<cretin>::iterator iter3;
    
    while (targetcretin < 5)
    {
    	iter  = cretinlist.begin();		// iter deals with the cretin complimenting/ insulting
    	iter2 = cretinlist.begin();		// iter2 deals with the cretin receiving that stuff
    	iter3 = cretinlist.begin();		// iter3 deals with the cretins observing stuff
    
    	while (iter2->getid() != targetcretin)			// This just sets observer 2 to targetcretin
    	{
    		iter2++;
    	}
    	while (iter != cretinlist.end())
    	{
    		if (movecounter == 1)
    			tempinsult = iter->getmove1();
    		if (movecounter == 2)
    			tempinsult = iter->getmove2();
    		if (movecounter == 3)
    			tempinsult = iter->getmove3();
    
    			// The following checks if an insult or a compliment has been given
    			// and that the sayer and receiver of said insult are not the same cretin
    
    			if ( (tempinsult == -5 || tempinsult == 5) && (iter != iter2) )
    			{
    			if (tempinsult == -5) 
    				{ cout << iter->getname()  << ": Get lost, "
    					   << iter2->getname() << endl; }
    			if (tempinsult == 5) 
    				{ cout << iter->getname()  << ": I like you, "
    					   << iter2->getname() << endl; }
    
    			// The following deals with increasing or decreasing the receiver cretin's 
    			// perceived status of each of the other cretins in status slots 1-4.
    			// This is based on whether the sayer gives that receiver an insult or compliment.
    
    			if (iter->getid() == 1)
    			   { iter2->setstatus1( iter2->getstatus1() + tempinsult ); }
    			if (iter->getid() == 2) 
    			   { iter2->setstatus2( iter2->getstatus2() + tempinsult ); }
    			if (iter->getid() == 3)
    			   { iter2->setstatus3( iter2->getstatus3()  + tempinsult ); }
    			if (iter->getid() == 4)
    			   { iter2->setstatus4( iter2->getstatus4()  + tempinsult ); }
    
    			// LAUGHTER CODE.
    			// The following code deals with how each of the other cretins in the 
    			// room perceive the receiver of an insult, to give insults some kind of 
    			// benefit to the sayer of them. Basically they laugh at the receiver
    			// and this decreases the receiver's status in their eyes.
    
    			if (tempinsult == -5) 
    				{
    				iter3 = cretinlist.begin();
    					// The following line checks if the observer cretin pointed to by
    					// iter3 is not the last one.		
    						while ( (iter3->getid() <= 4) )
    						{ 
    					// The following cannot be part of the while loop because if it is
    					// then as soon as iter3->getid() = iter2->getid() the loop will
    					// stop even if iter2->getid() is not the last id number.					
    							if (
    								( iter3->getid() != iter2->getid() )
    							 && (iter3->getid() != iter->getid() )
    								)
    							{ 
    								cout << iter3->getname() << ": lol." << endl; 
    
    								// The following 8 lines decrease the status of the insult
    								// receiver in the eyes of the current observer.
    
    								if (iter2->getid() == 1)
    								  { iter3->setstatus1( iter3->getstatus1()-1 ); }
    								if (iter2->getid() == 2) 
    								{ iter3->setstatus2( iter3->getstatus2()-1 ); }
    								if (iter2->getid() == 3)
    								  { iter3->setstatus3( iter3->getstatus3()-1 ); }
    								if (iter2->getid() == 4)
    								 { iter3->setstatus4( iter3->getstatus4()-1 ); }
    							}
    						if (iter3->getid() == 4)		
    							break;	
    						iter3++;
    						} 					
    
    				}
    			}
    	iter++;
    	}
    	targetcretin++;
    }
    }

  2. #2
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    It seems like a lot of things could be done as arrays or vectors, e.g. your status1, status2, etc can be an array of status[number_of_cretins] instead - that would simplify some of the other code too, as you could use the ID to index the status, etc.

    I don't know if it's a bug or what, but the cretinscore2..4 are never used, only cretinscore1 is being used.

    It's probably just that I'm extra sensitive right now, but this is the third time today that I've said this:
    Code:
    	if (choice != 1)
    		break;
    	cretinthink(cretinlist);
    Do NOT USE RECURSION AS A repetition mechanism. This code does not benefit from calling the same function over and over - it will just crash it eventually.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  3. #3
    Registered User
    Join Date
    Sep 2007
    Posts
    127
    Thanks.

    Actually you're right about cretinscore2..4. They don't need to be there, I should have removed them.

    About re-calling cretinthink over and over, okay, fair enough. Like I said I'm new to this stuff. I appreciate the advice.

    Also with replacing status1, status2 etc. with an array, yeah that's definitely what I want to do. That way obviously my number of cretins wouldn't be so limited. I could also use something similar for each cretin's ability to remember stuff, such as past insults etc.

    I seem to remember trying that but getting problems with setting it up as part of a class. Don't you have a problem though when you make a constructor for it? Because say you've got int status[9] that gives you an array of 9 cretin statuses. Well, then when you come to make the constructor surely you would need something like

    Code:
    cretin(const std::string& nm, int i,
    			int s1, int s2, int s3, int s4....
    			int s9)
    	{
    		name = nm;
    		id = i;
    		status[1] = s1;	
    		status[2] = s2;
    		status[3] = s3;
    And so on all the way up to status[9]? Which kind of defeats the point of having an array because you've still got to write out s1... s9. Or is there a way around this?

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    Along with learning about arrays, comes learning about for loops.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #5
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by bengreenwood View Post
    Thanks.

    I seem to remember trying that but getting problems with setting it up as part of a class. Don't you have a problem though when you make a constructor for it? Because say you've got int status[9] that gives you an array of 9 cretin statuses. Well, then when you come to make the constructor surely you would need something like

    Code:
    cretin(const std::string& nm, int i,
    			int s1, int s2, int s3, int s4....
    			int s9)
    	{
    		name = nm;
    		id = i;
    		status[1] = s1;	
    		status[2] = s2;
    		status[3] = s3;
    And so on all the way up to status[9]? Which kind of defeats the point of having an array because you've still got to write out s1... s9. Or is there a way around this?

    Aside from Salem's comment to learn about for-loops, perhaps you could consider setting your status array to a constant value [such as zero], and then have a member function that takes an index and a value for setting the value of a status?

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  6. #6
    Registered User
    Join Date
    Sep 2007
    Posts
    127
    I really appreciate your help but I'm a bit confused by this. Why is it that you can't just do this as in the following program? If you use int variables instead of arrays it works fine- but it won't compile with arrays.

    That said I think I see what you're getting at with having a different function than the constructor function for defining what goes into the status array. I just don't understand why you have to do it that way instead.

    Code:
    #include <iostream>
    using namespace std;
    
    class cretin {
    private:	
    	int statusarray[3];
    public:
    	cretin( int sa[3] )
    	{
    		statusarray[3] = sa[3];
    	}
    };
    
    int main() {
    	cretin arnold( {1, 1, 1} );
    	return 0;
    }
    Last edited by bengreenwood; 11-28-2007 at 03:48 AM.

  7. #7
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    No, that won't work. C and C++ does not allow assigning an array, or passing a list of constants as an array.

    What I'm suggesting is that you don't even pass the status as arguments to your constructor, but that you automatically set the status to a "good" value, then, if needed, modify the value immediately after construction. Or if you wish, pass in ONE value [e.g. 0, 1, or 3] to set as the starting status. [But I will immediately confess that I don't quite understand how your status is being used].

    Going to "how status is used", I get the impression that there's one status for each other bot, in each bot. Another option is to have a 2D array [or vector] that holds this data, that is external to the bots themselves, and held by a "botcollection" or some such [which also holds all the bots].

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  8. #8
    Registered User
    Join Date
    Sep 2007
    Posts
    127
    Yeah, that's right, there's one status for each bot, in each bot. That way, each bot can have it's own "opinion" as to what the status of each of the other bots is.

    Also, "status" refers to social status, the same as in people, but simplified. In reality, how you perceive a person's social status is of course affected in ways much more complicated than just receiving insults or compliments- for example, how many allies they have, whether they adhere to social norms, whether they tolerate crap from others, etc. I just used insults/ compliments as a very simple way of getting started with the program. But ultimately, there is such a thing as social status, and different people have different levels of it, in the perception of others- so you can represent it numerically. Well that's the theory anyway.

    BTW, Would it make more sense to have a 2D vector with all the data about the bots in then, instead of arrays? Is that complicated? Ultimately I want to make it so that you can have as many bots in there as you want, basically.

  9. #9
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    I'm not sure what makes most sense - because I can't say I fully understand what your code does, and less so of what your actual plans are [after all, the code is not small and trivial, so it's not that easy to grasp].

    Here's some more random thoughts, that you may take as much or little of as you like.

    The other option is to "let each bot manage who it knows". For example, if you have hundreds of bots, just like in a real world scenario when you "know" 100 people, you don't really KNOW more than a few dozen of those people well, right? So the bots would "have relations" with only some of all the bots, and keep a status along with the link to the other bots it knows.

    I would also think that the "I've been insulted" or "I've been complimented" is part of the bot. So you probably want a function that takes a bot [or a bot ID] and an insult/compliment for that bot. Let that bot then figure out whether this is a good, bad or unimportant thing for it's status of that particular "collegue bot".

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  10. #10
    Registered User
    Join Date
    Sep 2007
    Posts
    127
    The other option is to "let each bot manage who it knows". For example, if you have hundreds of bots, just like in a real world scenario when you "know" 100 people, you don't really KNOW more than a few dozen of those people well, right? So the bots would "have relations" with only some of all the bots, and keep a status along with the link to the other bots it knows.
    Yeah, you're definitely right there. I'm thinking that in the final program, there'll be like a main chat room, with loads of smaller, private rooms. The private rooms will be populated by groups of bots talking amongst themselves. For example some bots will have the urge to talk with others that are similar to them- e.g. in terms of the insults/ compliments they choose to use (in the final program each bot will choose from dozens of pre-set insults/ compliments- perhaps randomly, or perhaps instinctively via their preset personality).

    Most bots will also have a preference for hanging out with bots of high status. Couple this with some kind of group affiliation type thing, and maybe they'll end up conflicting with each other over who is in what group, who is allowed in what room etc.

    This could make it a pretty cool game to play as a human- basically your objective would be to get as high a status as possible, obviously, and you would do this by complimenting the right people, following the right social norms for popular groups etc. until you have worked your way up the ladder. Also worth mentioning here is...

    I would also think that the "I've been insulted" or "I've been complimented" is part of the bot. So you probably want a function that takes a bot [or a bot ID] and an insult/compliment for that bot. Let that bot then figure out whether this is a good, bad or unimportant thing for it's status of that particular "collegue bot".
    You're right again- this is critical to the program doing what I want it to. With this kind of thing, bots will be able to do things like retaliate to insults (how a bot does this will be determined by it's pre-set personality file). Say a bot gets insulted with a high strength insult, and there are loads of observers in the main room- if it fails to retaliate publicly, this will negatively affect it's status in the eyes of those observer bots. Maybe they'll all start laughing at it, too.

    This relates to what I was saying above about private groups of bots, because obviously, if someone is the kind of person who gets laughed at and made fun of like that, the group will probably want to kick them out.

    I should probably say here that I certainly don't approve of this kind of bullying behaviour- I'm not saying it's right or anything. I'm just saying it happens, probably due to social instincts a lot of the time- hence you could simulate it without the need for the normal kind of really complex programming you get in other chat bots. I know a bit about it because I've had this kind of thing happen to me so it interests me.

  11. #11
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Ah, yes, so you have "Listening to others" effect too.

    It's certainly an interesting subject.

    I still think you should have a mechanism where each bot has it's own member function to "hear" insults [either directly towards them, or said to another bot].

    And you also probably want each bot to track "who it knows" and "whether it listens to another individual" [perhaps based on the talking bot's status?] - it is easier to solve this problem by having each bot proces "what it hears" than to write some code to do it from "the outside" - sure, it's the same amount of processing involved [or perhaps a tad more this way], but it makes the code much easier to write, because there are at most three different status to consider for each individual that actually listens to something:
    1. The talker (sender?).
    2. The talked-to (recipient?).
    3. "myself".

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 4
    Last Post: 07-05-2004, 07:41 PM
  2. Requesting Java Chat Client Maintenence
    By ygfperson in forum A Brief History of Cprogramming.com
    Replies: 6
    Last Post: 04-02-2003, 01:57 PM
  3. Msvc Aim Chat Bot ???
    By Unregistered in forum C++ Programming
    Replies: 0
    Last Post: 09-19-2001, 08:46 AM
  4. Simple Chat program. Help.
    By knave in forum C++ Programming
    Replies: 0
    Last Post: 09-16-2001, 02:35 AM
  5. Rough Portable Chat Design Sketch
    By ggs in forum A Brief History of Cprogramming.com
    Replies: 0
    Last Post: 08-27-2001, 07:44 AM