Jump to content


Photo

Imperfect A.i.


  • Please log in to reply
128 replies to this topic

#1 gmXpert2000

gmXpert2000

    SoulRed12

  • New Member
  • 1975 posts

Posted 09 July 2008 - 08:54 AM

Many of us can write Artificial Intelligence to instruct the computer to play a game perfectly and unbeatably. This isn't really a good thing, though, as it essentially ruins the game experience; after all, the player has to be able to win. But if one programs it so, the computer mind can be theoretically perfect; it won't make spur of the moment mistakes, it won't misjudge anything, and it won't have accidents.

Imagine a computer playing pacman. It knows where the ghosts are and (if so programmed) it can likely calculate a perfect plan of escape every time. What if, however, we want the computer to emulate a real person? Most people probably won't know for sure which direction to go to retain victory every time; they will occasionally make mistakes leading Pacman to his ghostly doom. The human mind doesn't always work that quickly or that accurately.

Of course, we can't just tell the computer to seek out a ghost so it will lose. For the best results, the game has to get the computer to look like it was actually trying, but just screwed up. Therefore, to combat the "perfect computer", we must provide it some way to be realistically overpowered. "Intentional mistakes" must be introduced to the A.I.

A programmer can achieve this, albeit somewhat roughly, using a call to random(). One can also do something more general to the game's design, such as removing certain abilities from the computer's character so the player has the overall upper hand (i.e. giving the computer slower movement, letting the player shoot but not the computer, etc.). In addition, a third method might consist of "forgetting" to add parts to the A.I. - leave out checking for floor spikes in a platform enemy, for example.

Disappointingly, I haven't seen very many examples of realistically flawed A.I. programming, if any at all.

(For those interested in more concepts of A.I., view the wikipedia article here.)

Here's a basic example of what I'm talking about. Imagine I have a platform game enemy, who follows the player around and can jump over gaps. But I want this enemy to be flawed, so I introduce a call to random() just before he jumps:

if (place_meeting(x,y+1,objBlockParent)) //Make sure we're on the ground
{
	if (!place_meeting(x+hspeed,y+1,objBlockParent)) //If we're going to fall next step
	{
		if (objPlayer.y<=y) //only if player is above or on same level as enemy
		{
			//Jump on random chance.
			if (floor(random(2))) vspeed=-jumpspeed;
		}
	}
}

So I've got a 50% chance of jumping, and 50% chance of falling.

Unfortunately, that's still pretty unrealistic; human's aren't so flawed that they would walk off a cliff for no reason. I need something different.

This time I'm going to tell the enemy to always jump when he reaches a cliff, but also give him a random chance of making it to the other side by sometimes reducing the jump height.

if (place_meeting(x,y+1,objBlockParent)) //Make sure enemy is on the ground
{
	if (!place_meeting(x+hspeed,y+1,objBlockParent)) //If we're going to fall next step
	{
		if (objPlayer.y<=y) //only if player is above or on same level as enemy
		{
			//Jump
			vspeed=-jumpspeed;

			//Random chance to have lesser jump strength
			if (floor(random(2))) vsp+=floor(random(floor(jumpspeed/3))));
		}
	}
}

Now the enemy may or may not make it to the other side. He'll always jump, but sometimes not far enough.


Another area where this kind of A.I. imperfection might be necessary is inside fighting and strategy games where you can challenge the computer. The computer could be programmed to scan all possible moves and weigh every variable to choose the perfect action every time. Unless, of course, one were to introduce a way for the computer to make an "honest" mistake. Again, not an obvious blunder like moving, in a game of chess, to leave the King wide open (maybe unless the game were on an "easy mode" setting), but an imperfect choice of which the player can take advantage should he or she be skilled enough to do so.



On the contrary to all this, some may argue that even if a computer is programmed "perfectly", the A.I. is only as smart as its designers. Were this assumed true, then as designers are "flawed" humans, it would follow that this is all a non-issue because then a computer could not ever be completely perfect in the first place.

Speaking of chess above, this subject comes into play with chess during man vs. computer competitions. The computers are programmed by top-rate computer scientists, but have still been beaten by "mere humans". You can find articles about science's efforts to determine, using chess, whether man is ultimately smarter than computers, by following these two links:

http://query.nytimes...751C0A960958260
http://www.wired.com...s/2002/10/55839


I feel I've been pretty thorough on this subject. I hope I haven't introduced too much information.

Anyways, the platform enemy example I gave above isn't necessarily completely realistic; however it illustrates the concept of imperfect A.I. fairly well. I'd like to know who has written/thought up examples of this and who knows of other examples. What ways do you introduce flaws to make the computer mind more like that of an average human's? Or is strategy from the human mind already better than A.I. could ever be?
  • 2

#2 Sinaz

Sinaz

    MCP Killer

  • Retired Staff
  • 2751 posts
  • Version:GM8

Posted 11 July 2008 - 08:37 AM

First, I'm so glad someone has started a decent thread on A.I. I was planning on doing the next resurrection thread as a series of discussions on A.I.

Though I usually discourage this, I am going to discuss some A.I. imperfections I added to some of my games without posting examples (sorry, but this stuff is proprietary!) I can at least give you the theory behind my A.I.

First, my game Dwarven War was created as a prototype for card game A.I. systems. I only took it so far, but I learned most of what I wanted to learn in making it.

Dwarven War

The game itself has a perfect-play strategy. If both the human and cpu players play this strategy, then the game is purely in the luck of the cards. I first started out by coding the AI to play perfect strategy. He was nearly unbeatable unless you resolved yourself to perfect strategy as well. So what I did was study the way I play against other people. I tend to make two types of mistakes: a less than optimum play for lack of noticing the appropriate play and a whimsical play, in which I play a card to create an interesting configuration of the field.

To get the AI to mimic these kinds of mistakes, I, as you suggest, used some randomizing functions.

I gave the AI a priority towards "fun" in that it first evaluates the field and takes notice of any locking opportunities (because this is one of the most fun ways to dramatically alter the playing field). It then weighs the openness of the field vs. it's desire to do something silly. This desire is a random check versus a variable that can be set (though not implemented in that version) for difficulty. If the AI hits this threshold, it will make a move purely for the fun-factor and not for the sake of winning. It's interesting because if a whimsical move is too risky, the AI will override its desire to play the silly move in favor of trying to win.

If it fails to make a whimsical move, then it evaluates all of its possible plays and prioritizes them based on value (perfect strategy being the highest valued play.) It then does a random check for error, and if it fails, then it randomly chooses which move it will make. It again has a threashold that can be set that will limit the severity of it's poor play. It may, for instance, cap it to a random chance of the top two valued moves, giving it the illusion that it just miscounted the value of one card vs. the other. Increasing this value can cause the AI to just act retarded when it messes up (like completely devaluing it's highest card in play.)

If the AI succeeds on it's error check, then it simply makes a perfect play.

[edit]
I went digging into my project archives to find the AI for the card game... here is the latest iteration I have:

//1:20 = mistake//1:20 = whimsical//check for double opponent lock//varRandom = random(100);priIdealCard = ds_priority_create();//FIRST first, see if there is a whimsical move:for(i = 0; i < 7; i += 1){    varCard1 = ds_list_find_value(lisPlayer1Fields, i);    varCard2 = ds_list_find_value(lisPlayer2Fields, i);    if(varCard1.sprite_index != sprCardBack){        if(varNewCard.image_index == varCard1.image_index && varNewCard.sprite_index != varCard1.sprite_index){            if(varCard2.image_index < varNewCard.image_index || varCard2.sprite_index == varNewCard.sprite_index){                ds_priority_add(priIdealCard, varCard2, 15);                //show_message("weeeeee!");                varAlert = "weeeeee!";            }        }        if(varNewCard.image_index == varCard2.image_index && varNewCard.sprite_index != varCard2.sprite_index){            if(varCard1.image_index < varNewCard.image_index || varCard1.sprite_index == varNewCard.sprite_index){                ds_priority_add(priIdealCard, varCard1, 15);                //show_message("weeeeee!");                varAlert = "weeeeee!";            }        }    }}//first, find a player 1 card to capture:with(objCard){    if(other.varNewCard.sprite_index != sprite_index && other.varNewCard.image_index > image_index && varLocked == false){        ds_priority_add(other.priIdealCard, id, image_index);    }}//if couldn't find player 1 card to capture,//find own card to upgrade/downgrade:if(ds_priority_size(priIdealCard) == 0 || varRandom < 50){    with(objCard){        if(other.varNewCard != id && other.varNewCard.sprite_index == sprite_index && varLocked == false){            ds_priority_add(other.priIdealCard, id, 14 - image_index);        }    }}if(varRandom < 50 && ds_priority_find_priority(priIdealCard, ds_priority_find_max(priIdealCard)) != 15){    repeat(floor(random(ds_priority_size(priIdealCard) - 1))){        ds_priority_delete_max(priIdealCard);    }     //show_message("oops!");    varAlert = "oops!";}varPlace = ds_priority_find_max(priIdealCard);

There are some todo notes and a lot of clutter. Also, in looking at the code again, I realized that I explained my methodology a little different than I implemented-- but ultimately it's the same. The big thing is that the AI makes a priority queue of most of its possible moves (priIdealCard). It makes the whimsical move a higher possible priority than the most valuable capturable card.

Here is the code for possible mistakes (set to 50% for testing purposes at the time.) Notice how it just deletes a random number of good moves off the top of the queue. Kind of like it never saw the moves in the first place :D It can actually trigger the mistake code and still not make a mistake-- in the cases where the repeat is randomly set to zero, it will still make the best move.

if(varRandom < 50 && ds_priority_find_priority(priIdealCard, ds_priority_find_max(priIdealCard)) != 15){
	repeat(floor(random(ds_priority_size(priIdealCard) - 1))){
		ds_priority_delete_max(priIdealCard);
	} 
	//show_message("oops!");
	varAlert = "oops!";
}
varPlace = ds_priority_find_max(priIdealCard);

[/edit]

In another game of mine, Asteroids rEVOlution, I ended up stumbling on a type of human-like imperfection for the game's AI-based intruders (the flying saucers that come and make a mess of your attempt to beat the highscore.)

For the two higher level intruders, the fighter and interceptor, they had to make an attempt to shoot AT the player. If you've played my Asteroids game, you'd seen that it takes place on the surface of an invisible sphere. I found that calculating an accurately lead shot for the AI was nearly impossible with the kind of geometry I was dealing with (and the amount of math skills my mind possesses.) After a futile attempt to simply calculate the perfect aim for the AI, I went back to the drawing board to, again, see what it is that I as a human do to aim my shots at moving targets (since I'm not actually doing math in my head-- I'm just "feeling" it out.)

I eventually came up with a fuzzy way for the AI to make accurate shots. It's scary how human the AI's attacks became. Their barrage of guestimated volleys cause me a lot of panic.

My strategy came out kinda like this-- first, I figured out a typical engagement range based on what I was comfortable with as a player (the idea being that the AI should behave as if they are playing with the same field of view I am.) I then created a dummy object that would always lead the player's movement by a one-mississippi-two-mississippi method of timing. I then instructed the AI to aim at that dummy with a little random wiggle. I then went through several testing iterations adjusting the timing of the dummy lead until the AI shots failed to lead too far ahead nor lag too far behind. The result was that the AI's accuracy is somewhat inversely proportionate to your speed and frequency of maneuvers. If you are a fast and nimble pilot, the AI has a hard time gaining a bead on you and can actually be totally juked. But if you fly too slow or too straight, the AI will likely finish you off quickly.

I never got around to it, but the next iteration would have been to evaluate whether the shots went wide or shallow and have the AI adjust it's lead based on that. In such a case, the longer you flew at a particular speed, the better the AI would manage to lead his shots. Since the player's speed is capped, it's very easy to just jam the throttle and juke like crazy. Introducing the lead adjustment would force the player to consider braking and accelerating along with its jukes.

This AI, in particular, taught me the value of writing more fuzzy AI systems. Ai that isn't based on the most mathematically perfect approach to a game with a little randomness set to the end result, but instead, programming behavior that feels like a human touch because it mimics what I do when I play. I've since advised other people having trouble with their AI to try this approach.

I have some other ideas-- ideas particular to games like fighters in which AI is based around both reflex reactions and falling prey to feints and bluffs. I'll see if I can't articulate them into another article. Maybe make a simple fighter to demonstrate them.
  • 0

#3 them4n!ac

them4n!ac

    GMC Member

  • New Member
  • 1170 posts

Posted 11 July 2008 - 05:25 PM

Now I'm making a 2d shooter game and I thought a lot about good AI..

I wanted enemies to shoot not so precise at player and have a reason for that.
So I thought about adding some of the psychological characteristics to them.

Like - when enemy sees player, he's a bit shocked
if he hears gunfire at the same time but hasn't been hit by a bullet, he's shocked and aware, he must take some time to concentrate on the task to kill the player
and if he has been hit by a bullet, he's shocked and unable to think clearly, so he either drops the weapon and runs away (if he's scared) or starts shooting up and down and doesn't end until some seconds after the time when he had no bullets left in his weapon.

These psychological characteristics are very easy to add to game but in my opinion it makes the gameplay experience better.

But, I'm against over-randomization of AI actions because they have no reason to do that.
For example, if AI should run & jump over gaps, maybe the jumping force should depend on heart beats?

Heart beats?? Care to elaborate? (use the edit button, though.) :GM071:


here's an easy algorithm for this (jumping example):
//step
if( shock > 20 )//or some other value, or a variable which shows how much the AI is experienced, for example
heart_beat_speed += shock;

heart_beat_speed -= 1;

//jump
shock += gap.size;
if( shock > 20 )
heart_beat_speed += gap.size;

zspeed += max_jump_height - sin( heart_beat_speed );//or a better heartbeat simulator

Edited by them4n!ac, 13 July 2008 - 10:54 PM.

  • 0

#4 Scepheo

Scepheo

    GMC Member

  • New Member
  • 277 posts

Posted 11 July 2008 - 10:41 PM

This time I'm going to tell the enemy to always jump when he reaches a cliff, but also give him a random chance of making it to the other side by sometimes reducing the jump height.


In my opinion, this also doesn't really make a realistic AI. If a user has to make a very large jump (I'm assuming there is variable jumping here, because otherwise this wouldn't make any sense anyway), he'll simply keep the up button pressed until he has passed the highest point in the jump, and will therefor always reach the maximum jump height. The mistake that a player would make, would be jumping either to early or to late, respectively trying to prevent falling of the edge and not making the jump.

That is what most human mistakes in games are, an incorrect estimation. However, most game AI's are programmed to react directly to the situation they are in, not to determine what situation they will most likely get in and decide in advance what moves they will make.

I agree with Sinaz, that the best way to determine where the AI should make mistakes is to look at how humans play the game and where they make mistakes. Take, for example, Guitar Hero. Simply adding a chance that it will play a certain note right looks in no way realistic, because that gives each note an equal chance to be played wrong. However, if you have a part where the notes are far apart and it is the same note over and over again, a human player would most likely not make any mistake at all.

Then, of course, you could make some way to check how many different notes are in the screen which the AI can "see" and increase or decrease the chance of playing a note wrong according to those values. However, this still leaves you with another problem, if there is a part that has 100 fast and different notes, the computer would play, for example, 2 notes wrong on every 10 notes that there are. However, a human player would most likely succeed in playing the first part, successfully hitting the first 25 notes, then he/she would "panic" or might simply not be able to keep it up anymore, making a lot of mistakes (hitting only 30 of the next 50 notes). During that part, the human would catch his/her breath, take it easy, and play the last part right again (hitting all 25 notes). Now, as you see, both would make an equal amount of mistakes, which is not really that hard to program, the hard thing however, is determining when and how the AI should make it mistakes.
  • 0

#5 Sinaz

Sinaz

    MCP Killer

  • Retired Staff
  • 2751 posts
  • Version:GM8

Posted 13 July 2008 - 05:48 PM

Please, everyone, remember the rules and guidelines of this forum. I've been deleting a lot of anecdotal and speculative replies. We need code, research, examples... not just guesses and what-ifs.

The spirit of this thread is to discuss concepts and ways of introducing imperfection into AI where it would be easy to just make it perfect and unbeatable. Why is this necessary? How do we make it seem natural and humanistic? What have you done in the past to solve this issue?

  • 0

#6 templargfx

templargfx

    GMC Member

  • New Member
  • 1940 posts

Posted 14 July 2008 - 05:17 AM

The most realistic way, in my opinion to create imperfect ai is to give your AI 2 things, reaction time, and mood or calmness.

Taking the jumping over a hole in a platformer example, something like this would be more realistic.

if (!place_meeting(x+sprite_width*2,y+1,ground_parent))
  {
  if (alarm[0] < 0)
	{
	alarm[0] = reaction_time*(1+random(reaction_time*mood));
	}
  }

ALARM[0] even contains the jumping code


reaction_time is a preset variable that represents the quickest possible time in which the AI can react or press a button like a real player

mood is a swinging variable that can have a value of 0-n where 0 is calm, and therefore the quickest reaction, and n is nervous, the highest state at which the AI is likely to stuff up.

Modifying mood is the key to making this seem realistic. exactly how to modify mood depends on the type of game, continuuing with the platformer example.

say the view is constantly scrolling from left to right, and the objective of the game is to jump over holes in the ground and the like, while keeping on screen. also assume you have 3 lives

var temp;
temp = point_distance(x,y,view_xview[0],y); //distance between ai and left edge of screen
if (temp < view_wview[0]/2)
  {
  mood = (temp/(view_wview/2)) * 1+(max_lives-lives); //the closer to the left, and less lives we have, the more accident prone the ai will be
  }
else
  {
  mood = 1-(lives/max_lives); //the less lives, the more likey a mistake will be made, but nothing like above
  }

thats just a quick example. the more things you accomodate into modifying mood, the more realistic it will become, in high pressure situations, the AI will be more likely to press a key too late, or release it too early (only pressing is shown above, but you get the idea)
  • 0

#7 tsa05

tsa05

    GMC Member

  • New Member
  • 713 posts
  • Version:GM:Studio

Posted 14 July 2008 - 05:43 PM

Edit: "Normal" distribution in this post should read "uniform" distribution. Thanks Schreib, for the correction! :blush:

Once upon a very long time ago, I posted a script that didn't get very many views or replies, but was precisely designed for this concept. It generates something we call "Gaussian random numbers." Game Maker, you see, does "normal" distribution random numbers. Consider the difference:

Normal Distribution: All numbers have an equal probability of occurring. For example, if we pick an integer from 1-10, and we choose 100 times, we will end up seeing each number selected approximately 10 times.

Gaussian Distribution: Numbers tend around a certain value and fall off in frequency towards the ends of a range known as the standard deviation. Numbers selected in a Gaussian distribution pattern will *average* the supplied value, but will vary by +- the deviation amount.

So, Game Maker has provided us with the most programmatically helpful random function, but the worst for natural behavior. Think about it--if you are selecting, randomly, one item out of an array (for example), you almost certainly want to choose truly randomly. You want every element in the array to have a chance to be selected. But, with natural behavior, every option isn't equally likely. What if you told a shooting AI to choose a direction to aim in randomly, for example. Would you use random(360)? It's silly to think that the AI could be completely off...

But then again, you can't calculate the exact angle, either, as the topic creator mentioned. The game would be too hard. You could, I suppose, hard-code an innacuracy... angle_to_object()-random(20)+10 <--There you have the exact angle +- 10 degrees... But this means your AI shoots arbitrarily at or away from your character. Instead, you could shoot at a Gaussian random average of the correct angle. That way, it's like the computer knows where to aim, but a certain amount of fallibility causes all of the shots to fall near, but not exactly at the same point. Just like a human.

And, Gaussian random can be used in countless other ways, too--not just aiming. Anything in which you can calculate an exact answer can be made more "human" with Gaussian random.

I dug up the link: http://gmc.yoyogames...&...t&p=1457194

On a different note...Also consider the types of actions allowable in a game when planning the AI. These are often referred to as "affordances." Affordances are defined as the powers of observation and action that an entity has at its disposal. Taking these into consideration can provide significant guidelines for your AI. Better, though, with an example.

Pacman--the non-intelligent AI.
The game of pacman gained immense popularity because of it's challenging, daring gameplay. Players must dodge the tirelessly pursuing ghosts, darting between advances to snatch power pellets. The near misses and inexorable cornering that the ghosts force upon the player create a sense of excitement and challenge. The feel of trying to trick the ghosts, out-maneuver them, out-smart them...and it's all an illusion. The early pacman games featured no complicated AI. No path-finding algorithms. No teamwork. And yet, players still crowded the machines at arcades to breathtakingly bob and weave between these seemingly smart, lifelike ghosts.

So, where do affordances come in? Think about what we can know and what we can do. The player is on a 2D field. The walls of this field are carefully arranged so that it is impossible for the player to move in more than one direction at a time--movement is therefore restricted severely. Also, the field is set up as a loose labyrinth, which means that a player can become trapped as much by the walls as by the ghosts. Now, what can the ghost know about the player? Not much. X-coordinate, Y-coordinate. And so, we have the pacman AI:
Choose a direction: Up/Down or Left/Right (50%)
If that direction is blocked both ways, use the other direction.
For the direction selected, determine the player's relative direction (eg, if Up/Down was chosen, determine whether player Y is > or < self Y. If Left/Right was selected, determine whether player X is >or < self X).
If coordinate==player coordinate on this axis, choose a direction arbitrarily
Else...Chance 1/4--set direction away from player. Chance 3/4--set direction towards player.
If direction is blocked, use opposite direction.
Move.

If it seems complicated, it's because of the length of the description. Basically, a ghost determines whether to move vertically or horizontally. If its choice would lead to no possible moves, it switches to the axis it hadn't chosen. Then, it moves one step, and tends to move "towards" the player. So, if it chose to move vertically, it would tend to move so that its y value got closer to the player's y value. That's it! In this way, the ghosts tend to try to match the player's coordinates, one axis at a time, and if they have a clear line towards the player, they tend to take it..BUT not always, which causes those tense near-misses. The thing is, it works because of the setup of the game. Since the playing field only allows one axis of motion at a time, we do not feel disappointed to see a ghost far to our right, for example, moving up or down. To us, it looks like the ghost is trying to figure out a clever way to get around a wall and still be in prime position to trap us. And yet, there's no pathfinding of any kind! In fact, those early gaming cabinets could never have handled that kind of processing.

So, it's just something to think about with AI--What limitations exist and how can those limitations create shortcuts for my AI?

Edited by tsa05, 22 July 2008 - 09:40 PM.

  • 0

#8 Schreib

Schreib

    Valen Shadowbreath

  • GMC Member
  • 1455 posts

Posted 17 July 2008 - 07:08 AM

You've got your terminology wrong there - normal distribution is the same as Gaussian distribution. The type of distribution you meant is uniform distribution; each element has the exact same probability of occuring.

To stay on topic, keep in mind that there are mainly two categories of mistakes humans mostly make, that correlate largely to the genre of the game. Consider for example the mistakes made in a game of chess to mistakes made in the high-action game Metal Slug. They differ largely in general type, so if you're trying to construct an AI with mistakes, first you will have to filter out which kinds of mistakes the AI is to make.

The first category is mainly an incorrect path of reasoning or deduction. Either the player missed consequences in the move he chose [1], arranged the future events in an incorrect order (or looked too short into the future)[2] or missed a better move from the start [3]. Implementing one of these in an AI can be tricky, since a computer is a slave to logic. It's almost impossible to create an AI with mistakes without using some type of randomness in it somewhere - soon the player can see patterns in the AI's mistakes and they're no mistakes any longer. Consider two games of chess where the player chooses the same opening in both; if the AI was to make a mistake in it, it would be the same both times.

To solve [1], you may wish to randomly select a few of the future movebranches and not evaluate them. To solve [2], you could randomly skip a player's turn or the like. To solve [3], you could select (randomly) the most apparent moves and evaluate them (and their futures), but not all. Nevertheless, constructing an algorithm to prioritize apparent moves and branches of moves in a tree, regardless of their contribution to the AI's success is not an easy task and varies from game to game. As Sinaz states, look on how humans perceive a game and what apparent moves they choose. If you start to recognize a pattern, it could be the pattern you wish to implement.

The second category deals with incorrect induction. As stated above by other members, a player might make an incorrect estimation on a cliff's length, or his own speed, etc. This problem is much more difficult to solve than the first, because it involves the player's evolution of judgement in the game. "Judgement" is a very broad concept, and can range from pressing the Reverse -> Drive sequence in Crazy Taxi in the right rythm to knowing the pattern of notes coming in Guitar Hero in your fingers, and such that if you lose one note you may continue your pattern although it no longer fits to the current. Many players stop their judgement for a moment and restart it upon a point of reference - and things can get quite complex very quickly. In general, these types of AI mistakes must be extremely specific for the type of game, and simplified - a lot. It's very hard to generalize any concepts in these, other than observation of players development of judgement.
  • 0

#9 correojon

correojon

    custom title

  • New Member
  • 461 posts

Posted 06 September 2008 - 11:15 AM

Interesting topic :D

I use a similar method to what Templargfx exposed, though I have never really developed it to the limit, only in small experiments or for cutscenes. First, I divide my AIs behaviour in 2 parts:
States: using finite state machines I create a set of scripts that describe the behaviour in every step (for example, stEnemyWalk, stEnemyJump...). The instances keep track of their state in a local variable called state (you saw that coming :medieval:) which in fact takes for value the names of the scripts. This way, by just altering the value of state the enemy will execute it´s current state thanks to this line in the step event:
script_execute(state);
States take care of motion, animation and some simple actions (transitions between different states), like falling if there´s no floor or basic navegation.

Brain: this is how I name the part responsible of making decissions, like attacking the player, escaping, calling for help, etc...In basic AIs it´s embbeded into the state scripts, but in more advanced AIs it´s a set of scripts of it´s own that is not called in the step event, but in a cyclic alarm. By defining a local variable intelligence I can set the time it takes for the alarm to trigger, for example:
//Alarm 0 event
decide();
alarm[0] = intelligence + floor(random(someNumber));
This way different instances of the same enemy will act slightly differently. Another thing you can do is create blackouts, as if the enemy is in his own world:
//Alarm 0 event
decide();
if (random(10) > 9) alarm[0] = someBigNumber;
else alarm[0] = intelligence + floor(random(someSmallNumber));
Note that this will not execute the actions themselves: the decide() script will only affect the local variable state and change it´s value. It only decides, the execution is done by the state scritps.

Rather than an active way for the AI to make mistakes it´s a pasive way: the AI will make mistakes by omission, by not doing what it should have done in a moment or because of trying to do it when it´s too late and the player´s already a step ahead.
  • 0

#10 CODE 609

CODE 609

    GMC Member

  • New Member
  • 244 posts

Posted 02 October 2008 - 07:59 PM

Interesting.

A big difference between a player and the CPU is that were the CPU can calculate things using in-game variables,
the player has to guess those things.

As an example:

Posted Image

The player has jumped the gaps, going over the moving platform in the center.
The AI, programmed to follow the player, now has to make a decision, whether to make or not
make the jump right now or wait for the platform to get closer.
Now suppose the maximum of pixels a player (or CPU) can jump is 35 and, as seen on the drawing,
the distance to the platform is 36 pixels and the CPU would jump, he would obviously die.
And being the CPU he is, he can calculate that he's not going to make it, and he waits.
A player on the other hand, would probably jump.
And that's understandable, the difference between 36 and 35 is just one mere pixel are you going to see that?

So to flaw the AI there's probably 2 (or more) ways to make it more human.
One stated in the first post is to give the CPU a 50% chance of jumping, in my eyes a bit unrealistic.

The other one is to calculate the distance, and to add some random numbers to it, that way you have a variable intelligence added to it
so that the CPU doesn't make really stupid decisions.

precision = argument0;

if( abs( x - platform.x ) + ( precision - random( precision ) ) < 35 )
{
  jump();
}

Simulating that the computer thinks he's going to (or not going to) make that jump,
he might jump and fall or stay and wait, he might make a just a little mistake.
But hey everyone makes mistakes, that's only human.
  • 0

#11 FireWire Games

FireWire Games

    GMC Member

  • New Member
  • 1548 posts

Posted 18 October 2008 - 08:56 PM

Imperfect A.I. is something I myself stumbled upon just last year.

My first code was highly unrealistic. The bots shot perfectly straight, right at your head, and were able to always dodge the bullets except from about a point-blank range. I realized this was not how normal humans behaved, so I played a few games and looked at some game engines (Unreal Engine, etc.) for inspiration. Ever since then I've been striving more and more to give my AI virtual personalities and traits, making them more and more human. Fortunately it's not hard to learn to do it.

WARNING - These views, theories, and ideas are meant to be read by those who can understand them.

My view on this incorporates a few variables and factors that make the A.I. extremely realistic. All of them add to the calculation for making decisions, producing a truly infinite amount of results:

1. varIntelligence-To start out, I want to make the point clear that we as humans are, indeed, random. Our personalities, intelligence, courage, etc. are determined some time around conception I believe. No one knows how or why it happens, because a really religious and good person can have a total delinquent, anti-religion child, as exhibited by my best friend. So the point stands that we are random. BUT, the random(x) function in GM does not properly exhibit human randomness. We do, however, have a fix for that. You can find it here. I recommend learning and understanding this code before following through with the rest of this post. Now onto the variable...

Intelligence was one of the first factors I introduced. I thought to myself "What if you have a SAW and the enemy has a M9 Beretta, but he's really an idiot?". So I decided to add this into the equation. It's very simple to do.
varIntelligence = random( 145 );
I chose 145 because not many people have an IQ over that. Now, this produces some pretty strange results when added to a decision about whether or not to charge into battle, as you can imagine. If you are painfully limited about reality and cannot imagine, however, think about this: That code could give you an intelligence of 1. If you have met someone like that, may whatever god or higher entity you worship have mercy on their soul.

This can be fixed, however, very easily. Not many people have an IQ lower than 55. In fact, about 1% of people have an IQ around 55, so let's just set the bar at around 99.5, which is average. Also, this time, let's use the gauss_random script.
varIntelligence = gauss_random( 99.5,22.25 );
That would make the code work well; mostly average people, but occasional smart people and screw-ups. But why not go farther with it?! Ever studied the current formulas and theories on the Intelligence Quota? Why not add about 3 and a half points if it's a girl enemy? Maybe you could add in a variable saying whether or not he had a large family? The possibilities just for this variable are almost endless!

2. varCourage-Adding this with the intelligence variable is an artificially intelligent wet dream. Imagine this: Our old friend with the M9 Beretta is, once again, facing us, who all have SAWs. He's smart this time and realizes he should probably call in backup. But what if he's a courageous fellow? He may run out, pop a few of us in the head, dive behind cover, roll out, and finish the rest of us off before we even begin to comprehend what's going on. That probably wouldn't happen, but it's a cool thought. And adding this variable makes it a possibility. And the good news is you don't have to go very in-depth with it like the intelligence variable. But it gives you the freedom to:

You could add in a variable saying that he was abused as a child. Facing a bunch of enemies might scare him if his delinquency wasn't very enjoyable, right? Or maybe it'll make him a fiercer warrior! He might imagine his alcoholic father's face on all of us and go Steven Seagal before we can even pull the trigger.

The courage formula is different from the intelligence one. Where intelligence can be measured, documented, and averaged, courage cannot. Do not use the gauss_random script for this. Use GM's random function.

3. varFear-This is more of an add-on to the courage variable, but still very effective. If he's too scared of a situation his courage might not even come into play. I like messing around with this because you could make everything from his environment to the darkness of an area affect it. If he's in a small room with little or no cover and a very dim lightbulb he would probably rather have an unwanted bowel movement than chase after an enemy, or at least that would be my case. This variable is great for messing with accuracy. Last time I checked extreme fear makes you shake, which could screw up his aiming pretty well.

This variable you can use the gaussian script. I'd set it very low on the scale with a large deviation because most people are very fearful of things, but some aren't. And some are scared of their own shadow. That's just life.

4. Allies-I mean this in both terms of AI against them (your guys) and for them (their guys). This should be one of the last factors to be calculated because it could adversely affect the probability of winning. Let's say that it's the one enemy against two of us; not very good chances for him, right? Well what if two more enemies came in to aid him. Now he would be able to handle us better than before, correct? But now about 5 guys come in to aid us. There goes the neighborhood, or...uh...abandoned warehouse storing WMD's. Whichever you prefer.

5. varAdrenaline-I LOVE THIS VARIABLE. It makes things so fantastic in your game. It's also really easy to implement; just add the amount of adrenaline into the final equation and it'll give the AI a nice little boost. Now, you may be asking "How would the AI get the adrenaline?". I applaud your question and respond with an intricate answer:

Adrenaline is a key component of "fight-or-flight", or the "stress reaction". Humans have had it coded into their DNA ever since the dawn of man when they would go hunting for crazy-looking creatures you might see while tripping on acid. It's a mechanism we evolved to protect our existence, and while we don't normally use it for extreme UFC fights against animals anymore, it's still with us. It is triggered by mental or physical pain. By mental I mean "OMFG, I have an exam today" or "Uh oh, I think I just fudged in my pants". If you need to know what I mean by physical pain, shank yourself in the face with a sharpened toothbrush. You'll get the picture. All jokes aside, use the fear variable with this. Fear will be categorized under mental pain. ALSO, whenever the AI gets hurt you should boost the adrenaline a little more. But remember, adrenaline will run out in the real world; we don't have an endless store of it. Make the AI eventually run out of it and have it recharge gradually.

So the final part of the adrenaline variable is how you should implement it. Well, in the stress reaction our eyes dilate so we can see better, our muscles tense up so we hit harder and run faster, blood is directed away from organs that aren't needed at the time, and our lungs open up for more oxygen. We basically become a temporary genetic soldier. Use your imagination.

I will be editing this again later, so don't fear. Work on your AI diligently.

Regards,
FireWire Games

Edited by FireWire Games, 24 November 2008 - 06:57 PM.

  • 0

#12 link3000

link3000

    Link3000

  • GMC Member
  • 1129 posts
  • Version:GM8

Posted 19 October 2008 - 11:48 PM

Now I'm making a 2d shooter game and I thought a lot about good AI..

I wanted enemies to shoot not so precise at player and have a reason for that.
So I thought about adding some of the psychological characteristics to them.

Like - when enemy sees player, he's a bit shocked
if he hears gunfire at the same time but hasn't been hit by a bullet, he's shocked and aware, he must take some time to concentrate on the task to kill the player
and if he has been hit by a bullet, he's shocked and unable to think clearly, so he either drops the weapon and runs away (if he's scared) or starts shooting up and down and doesn't end until some seconds after the time when he had no bullets left in his weapon.

These psychological characteristics are very easy to add to game but in my opinion it makes the gameplay experience better.

But, I'm against over-randomization of AI actions because they have no reason to do that.
For example, if AI should run & jump over gaps, maybe the jumping force should depend on heart beats?


For a game like that, psycological characteristics are important and not included in many games, but you need to include much more than that. The main difficulty that programmers need to overcome while programming AI, is that that you need to include tons of variables to replicate at least some human characteristics. An example of this is, mentioned above and later in my post, a AIs mood and personality. Obviously, humans and most living creatures have different personalities, so they wouldn't react to a situation the same way, even if they are 'trained' to do so. So, AIs programmed to replicate that wouldn't be the same if programmed correctly. Say an easily-scared person and a soldier are placed on the battlefield, the easily-scared person would most likely cower when gunfire arose, while the soldier would most likely fire back.

If an AI is jumping over a gap, they will probably know that the distance they jump is relative to the power they put behind the jump, and to the speed they are at. So, to make them jump correctly, they need to know their strength in their legs, and their acceleration, along with their max speed. That way, they can move back, and then run to the edge to make the jump, so they can get speed in order to jump the distance.

The AI also needs alot of randomization, but not to the point of making horrible decisions. This next part will be harder to program into a game, but would probably be worth it. The computer figures out the top 5 ways to get somewere while hitting good things, and avoiding bad things, and gives the list to the AI. The AI then randomly chooses a path, with more likely-hood of it choosing #3, instead of #1 or #5. That would replicate the human's quick decision making, which is not always the best, but not often the worst, and most of the time is in the middle.

So an in an AI, you'd give it a personality, maybe 'meek' or 'courageus', and you'd assign every map sector a number, starts at 50. when someone dies in an area, and manages to send out a signal, and the other AI picks up, the areas rating will drop down, eventually to a min of 0. If good things happen, and the AI hears about it, the rating goes up, to a max of 100. the 'meek' AIs won't go NEAR anywere bad things happen alot (<30), but the 'courageus' AIs will explore to try to find out what happned.

@FireWireGames
When an AI is targeting a still target, they would most likely shoot fairly accuratly, but not completly because the hand holding the weapon isn't perfectly still, and therefor will hit a little off, or a lot off, depending on the range and conditions. (rain, snow, heavy wind, under pressure, etc.) When targeting an active target, the AI will shoot probably a little in front of them, think rockets in shooting games, they don't reach their targets instantly, so a human, knowing that, would aim a distance ahead of their target, depending on the distance the target is from the attacker and how expeirienced that specific attacker is with the rocket they are using.

Edited by link3000, 31 December 2008 - 02:31 PM.

  • 0

#13 Pie Person!

Pie Person!

    GM 6+ Lover

  • GMC Member
  • 1973 posts

Posted 23 October 2008 - 04:07 AM

A huge factor to some one's skill is their reaction speed, as well as their physical ability. Let me focus on First Person Shooter AI, where you must turn and point your gun to aim. If the person was flexible and strong, they could turn much faster than some one who wasn't. People never have an infinite turning speed. When you decide to start looking behind you, you don't instantly point in that direction. Also, people have to guess where is the correct place to aim their gun. Because of perspective, it is made a bit difficult.

So we have three things to think about now:
  • Accuracy
  • Reaction Speed
  • Turning Around, Aiming
Accuracy
Accuracy is the usual. Just offset the gun's direction randomly:

radius = 5;

direction += random(radius)-random(radius);
pitch += random(radius)-random(radius);

Reaction Speeds
First you must check if the direction between the AI and his target is with-in his field of view. Then, make sure that his target isn't hidden behind something else by. To do this, cast a ray and return false if the ray ever happens to intersect with an object. Once the target is valid, delay it's notice.

if notice[target] > 0 then notice[target] -= 1;

reactionspeed = 15;
if valid(target) then notice[target] = reactionspeed;

if notice[target] = 0 then shoot(target);

Turning Around, Aiming
Make this script and call it angle_difference:
var d1,d2,t1,t2;
d1 = argument0;
d2 = argument1;

//Left Difference
if d1 > d2 t1 = (360 - d1) + d2 else t1 = d2 - d1;

//Right Difference
if d1 < d2 t2 = (360 - d2) + d1 else t2 = d1 - d2;

//Action
return(min(t1,t2));

And use it like this:
var turningspeed,dir,pit;
turningspeed = 10;
dir = angle_difference(direction,aim_direction);
pit = angle_difference(pitch,aim_pitch);

direction += sign( dir ) * turningspeed;
pitch += sign( pit ) * turningspeed;

if dir < turningspeed direction = aim_direction;
if pit < turningspeed direction = aim_pitch;

I hope some one knows what I am talking about :).
  • 0

#14 xtreme0ninja

xtreme0ninja

    The Xtreme

  • New Member
  • 684 posts

Posted 24 October 2008 - 01:08 AM

//Create
varIntelligence = random( 145 );
if ( varIntelligence < 99.5 ){
	varIntelligence = 99.5 + random( 45.5 );
}
varGender = floor( random( 2 ) );
varIntelligence += ( varGender * 3.5 );
varCourage = random( 10 );
varFear = random( 10 );

//See An Enemy
if ( objEnemy.varThreatLevel > 6 ){
	if ( varIntelligence

i like your ideas, and your code, yet i see a flaw with it. The varCourage and varFear both have a maximum of 10. that means that the enemy could be extremely courageous, yet extremely fearfull at the same time. maybe have it set the fear within 1 or 2 of the courage variable.

~Xtreme0 :whistle:
  • 0

#15 ??? Lauria

??? Lauria

    GMC Member

  • GMC Member
  • 126 posts
  • Version:GM8.1

Posted 24 October 2008 - 09:22 PM

Why not make it work like the human mind? We as humans can only have so many things on our mind at once before we start forgetting things.

How about having algorythms sorted in a "priority pie," where it has all the various algorythms for playing a perfect game given a certain percentage, like "jump to avoid spikes" or "duck to avoid bullet." As the computer encounters various objects, it'll give those things a higher priority since they're "fresh in its mind."

As a result, other algorythms lose priority. Some could lose more priority than others if the computer hasn't had to call upon them recently or they're not called upon that often, and once they get low enough, when the action is finally called upon a random chance could cause the computer not to actually do it, or "forget." Regardless of whether or not it actually does, the priority will rise again to simulate it "remembering."
  • 0

#16 drazzke

drazzke

    GMC Member

  • New Member
  • 1084 posts

Posted 25 October 2008 - 01:50 AM

FireWireGames, why do you, at the end there, have varIntelligence += ( varGender * 3.5 ); ? As far as I can tell, both genders are equally smart.

Link3000, yes, I agree. I haven't been coding AI for that long, and certainly not imperfect AI, but I am slowly starting to try and get it.

One thing that I also think should be taken into account is the reaction time. I notice that templargfx went into this a little bit. Reaction time is, in my opinion, one of the most important things to making imperfect AI. If the AI reacts within a 50th of a second, then it obviously isn't acting like a human in any way. Humans take time to react to something. By the time they see what has happened, and press the right key, I'm going to assume about half a second has gone by. (or a 3rd of a second, but you get the idea). Implementing this into AI can make large changes, usually for the better.

I also feel that people tend to put a lot of time into making very complicated AI. I can see why you may want to do this if you are making an FPS, or a top down shooter, etc. But for games like Cave Story, the AI doesn't have to be that complicated. It can be relatively simple, but still seem very well coded and complex. Although they still need that odd twist that makes them a bit imperfect and random, to make them feel individual and... well, imperfect.

There are so many things to consider when creating imperfect AI. Too many things, really, to program a perfect imperfect AI.
  • 0

#17 BiG-MaC

BiG-MaC

    GMC Member

  • New Member
  • 55 posts

Posted 14 November 2008 - 06:28 AM

Just thought I would give a little, during my time at highschool I studied IPT (Information Processing Technology). This was generaly to do with programing and most of our programing was either TurboPascal or Pascal in Delphi 5 if I remember right it was 4years ago. (Age 16)

We had to make a Game as a main assignment using Delphi, most of the students went with the classic number guessing or hang man options things that took a few hours of work to do. I went with a card game from the Final Fantasy 8 Game on PS1 as I enjoyed that game it was simple enough and at the time I had a ripper that would extract images and video files from PS1 games.

At first I just made it a PvP (player vs player) game but since I had finished that in a week and still had a spare 3 weeks to work on it, I continued to add AI. Now we had learned nothing about AI at that time and it was all poor coding and guess work on my half but think the concept for the AI is good and works to make it as human as possible.

It involved with checking all cards already on the fields locating highest, lowest and mid level numbers, cards that were already taken, total spaces left, determining who was winning and how many cards needed to win, it also had different types of AI from conservative to aggressive and different difficulties, aggressive would be irrational when it come to him/her losing while conservative would only attack a card with a number that was needed making sure to keep strong ones for latter. The different difficulties made somewhat of the final decisions but were ultimately affected by the current field and personality of the AI. As the field was examined it would then chose all possible moves assigning them all a relevance and type of move (defense or attack).

Varaibles that played in this was
emotional (this would increase as it realized the position it was in was more dire and would then latter affect its decisions higher meaning it will make a decision on more of a random affect then it would choose a better one)
personality (this mainly decided on the point of whether its move would be attack or defense and how over board it would go when doing either of those) - Example an emotional conservative could end up using a defense move by putting in a strong card to block 2 of that cards it already took but would most likely end up using a card that is much stronger then the players current cards when it could of used one a bit weaker but the player couldn't still beat.
difficulty - this generaly just chose how many options it would have, being a range so if you had options 1 -> 10 and difficulty was medium it would choose the middle 3 or 4 to choose from, but if it was easy it would choose the first 3 or 4 ( 1 being the less inteligent move and 10 being the smartest)


Now I never tried this way of AI or any AI atm on game maker before so I don't know how bad this kind could smack ya CPU usage, but it was pretty fast on a p4 2.3 at school 4 yrs ago and that was without the use of functions
  • 0

#18 Dagarnorth

Dagarnorth

    GMC Member

  • New Member
  • 10 posts

Posted 06 December 2008 - 05:23 AM

FireWire Games having IQ as in intelligence would be a good idea but making variations to A.I would take a while with lots of IFs and ELSEs and many other changing variables in the code.

For example:
intelligence = random(50) //and you could have some more, but with even more variables.
if intelligence = 1 { 
react = 5;//like wise in games of tds on how long it would need to wait until it would retaliate.
spd = speed*number;//number in the create event could be: number = random(10)
}
if intelligence = 25 {
react = 2.5;
spd = speed*number+random(10)-random(5);
}
In this case of having an intelligence of 25 for the A.I, everything would now be a bit faster, even the reaction
because imagining playing a TDS game and their intelligence is on 1 (easy level) and having no reaction speed
and the new player finding it hard to defeat something that is easy when the code is not varied.
if intelligence = 50 {
react = 0.05;
spd = speed*number+random(15)-random(20-number);
Now having a smart and difficult A.I would be good against the experienced players in the TDS and would know that
the A.I reacts almost immediately to shoot the player. Compared to the A.I intelligence of 1, that A.I would wait a little
when this A.I doesn't wait.

If you don't get why the speed of the A.I increases in having a higher intelligence, think about you playing a TDS and running around while its your first time playing;
1. You will get killed as you may not know how to play
2. Enemies pop-up out of no-where as you were running to get them to notice you.
3. You can't aim properly as running fast would increase the crosshair sensitivity.

New players of TDS games usually take their time and make sure their crosshair sensitivity is low and usually the experts run around and do stuff for fun as they know how to get them out of a troubled situation.
Though this may not be the full Perfect A.I, it would still be one step furthur to programming a perfect A.I. This is only some of what an A.I needs and even alot of varies to make it perfect.
  • 0

#19 margoose

margoose

    GMC Member

  • GMC Member
  • 277 posts

Posted 09 December 2008 - 07:21 AM

I dont normally program games with GM (ironically), but I spent ALOT of time programming and reprogramming pong to make it have better AI. When learning how to program AI I find that you should use a huge amount of learning and practice on basic AI concepts to try and improve them. Then when you want to program a more complicated AI your brain is more prepared for the vaster array of problems associated with it.

In Pong there are several factors that affect both the human and the bot: the location of the ball and paddle, the speed of the ball and paddle, and most importantly the reaction time of the human/bot.

Of course in the computer world the bot can have instant knowledge of all these factors and have an instant reaction time (or for more advanced programmers, it can know where the ball is going and how long it will take to get there which then taking consideration of the bots speed it could calculate exactly when to react or could get to the next location as soon as it hits the ball back to the player.

In the human world we do not have the luxury of knowing the precise mathematical locations of the ball, nor the precise speed, nor do we truly understand exactly how long it takes us to react. Everything we know has an estimated area. Every human has a different estimation, some are better than others, and some react faster than others, and some can estimate where the ball is going next faster than others.

These are the things that need to be brought to the table when considering how to humanize a bot. And the whole thing is truthfully a paradox in itself because we are asking how to make a world of precision into a world of guess-timating, and to furthur the paradox, a world of guess-timating created the world of precision therefore it can only be as precise as we can physically measure it.

Consider what a human needs inorder to know something precisely (or close enough to precise). We need a third party object for relativity. If we want to measure the length of something we must have another object in which we make that measure. To measure the speed of something we need both the measure of distance and time. The computer measures time in "clocks". We measure time via how often we NOTICE change.

In the pong example a human will measure the speed of the ball based on the size of the ball and how often they see it move that distance. We see, comprehend/calculate, and react to this in a general time zone of half a second. So for every half a second we look at how many times that ball has traveled a distance of its size. We also look at the angle in which the ball is traveling to estimate where its going to be when it reaches the paddle region and based on how fast we think its going (from above) we estimate about how far its got to come to a conclusion as to how long it will take to get there, and again this all takes about half a second to compute. Also, the human can only guess somewhat accurately at such a far distance (everyone is different).

We can emulate the estimation of distance via the gausian_random() function. For example: if we input an estimate of the size of the ball, and an estimate of the last place the ball was half a second ago then we can estimate the speed of the ball.

ballEstDistanceTraveled=gauss_random(lastEstLocation , random(ballLastEstDistanceTraveled*errorOfDistancePer
ception)) / gauss_random(actualBallSize , random(actualBallSize*errorOfDistancePerception));

ballEstTimeTraveled= gauss_random(timeNow-timeLastCalculated , random(ballLastEstTimeTraveled*errorOfTimePerception));

ballEstSpeed = ballEstDistanceTraveled/ballEstTimeTraveled;


*note- please keep in mind that this is a generalization

You could further better this code concept by, say, adding a feature to the estimation of distance traveled in which the longer ago the last calculation was made, the greater the percent of error will occur when estimating. I think that a not-so-much missed as it is overlooked importance to this concept is the use of both gauss_random and regular random to come up with an estimation. A good rule of thumb is the percentage of error should be determined by the regular random, and the actual value chosen should be determined by gauss_random while using the percent error determined by regular random to help come up with the final value.

Also, a human is only concentrating on one or two calculations at that half second time period, and the human also must judge when to make the final decision of where to go before moving.

So in order to humanize the bot you must determine how often a calculation should be made. You can do this by setting a timer, and when the timer goes off, the calculation is made. You can determine when the timer goes off through some of the posts above, using personality, etc. Then you should also determine when to make the final judgment call, which should be done by determining when two or more calculation estimations are close enough, but if no judgment call is made by a certain time, you must go for it at the last moment.

Also notice that when you are looking at the score, you are not looking at the ball, therefore, the bot should do the same thing, and when it looks at the score if its behind more than 2, it gets an "adrenaline rush" if you will and becomes more precise as mentioned in an above post. This can be done by temporarily changing the error of perception for example.

Another thing you should do before you complete your AI is simply watch a person play the game, what behavioral patterns do you see them doing. The number one pattern I saw people do with my pong game was as soon as they were done hitting the ball, they would return to the middle of the screen. They of course do this so that they have the best chance of hitting the ball every time. If they did not do that then it would take longer to reach the other side of the "court" and would have a much higher chance of missing it.

Your bot ought to have a similar behavioral pattern, because a person is most likely to enjoy a game that has AI that it can connect with at some level. If the AI is doing similar things as the player is, then they player is going to think its good AI. Ultimately the thing I learned out of this is that the funny thing about intelligence is that its greatness is relative to the intelligence interacting with it.


The best analogy I can come up with is this: When we look at a dog that does what we tell it to then we call it a smart dog. Even though the dog cannot grasp any intellectual concepts such as numbers, personal space, or beauty, we call it smart because it does what we want it to when we want it to. But if it didn't do anything other than what we wanted it to, when we wanted it to then it would be a dumb dog. The same is true for AI.

By stuffing a single AI with random deviation, true randomness, estimation, and human behavioral patterns into it, you will obtain a truly unique and awe-inspiring result.
  • 0

#20 Andyops

Andyops

    GMC Member

  • New Member
  • 120 posts

Posted 19 December 2008 - 11:34 PM

Nice discussion guys :P
I'll be focusing on a more technical view of imperfect AI.

An interesting idea would not to be using random numbers to control information, as these are by definition, too random and will not always result in an accurate AI.
In my opinion it would be better to analyse what makes humans play like humans.

Namely:
  • Sensory Memory
  • Reaction time
Sensory Memory lasts for approximately 1/10th of a second, and is used by the brain to make decisions based on visual and other sensory input. For an example of sensory memory, move the mouse cursor around the screen really quickly, and you will see that it appears that there are multiple cursors, when there is infact, only one. (Unless you have mouse trails turned on, which is probably the most useless feature of Windows.)

Reaction time is the amount of time which it takes for the human brain to process information, and do something about it. On average, this is about 180 - 200 milliseconds for visual stimuli and 140-160 milliseconds for sounds.

Therefore, the brain responds takes around 180-200 ms to respond to information up to 100 ms old.

So the way you would program this would be simple, keep an array of all the values required for the AI calculations with each index spanning over a little more than one-tenth of a second.
//Random example with generic variable names
	 //Let's assume the room speed is 30
	 playerX[2] = playerx[1];
	 playerX[1] = playerx[0];
	 playerX[0] = player.x;
	 // etc. etc.
	 // This could be turned into a function in order to make coding more convenient.
Now find the weighted value of all of the values, biased toward the present moment.

Example
playerXW = (playerX[0]*10+playerX[1]*5+playerX[2])/16;

With these weighted values, which will slightly skew values to what they were in the past, you program the AI to do an action based on the input. With whatever action the AI chooses to make, make it actually perform the action 180 - 200 ms later.

Example
//For this example I will be using alarms, although there are probably more efficient ways of doing this.
	 //Wherever you have the AI Code (Probably the step event I would imagine)
	 adrenalineFactor = 20;
	 minResponse = 180 - (adrenalineFactor*0.75);
	 maxResponse = 250 - adrenalineFactor;
	 
	 //Lots of code to do with calculating AI parameters goes here.
	 if (insert conditional statement related to AI here) {
	 alarm[0] = minResponse + random(maxResponse - minResponse);
	 }
	 
	 //Code for alarm[0]
	 do_something_trippy();
	 }

In the above example I also incorporated an Adrenaline variable, which will make the response times faster, making the AI more capable.

What this code will do will be that it takes out variables such as 'courage' and 'fear' which should be used to determine the AI's actions, not govern how well it performs the task. Better variables would be something like 'calmness', which would allow the AI to access the weighted variables with a stronger bias towards the present state of gameplay, and 'alertness' which would allow for faster reaction times.


-Andy
  • 1




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users