Simple AI - JavaScript (using jQuery for animations)
Asked Answered
K

3

22

First off, I would like to let you know that I have been programming for a few years (mostly C-based languages, iOS development, web stuff, etc) as a hobby and am now developing an interest for creating a simple AI (most people start off with a tic tac toe game yes, but I am interested in making something using the principals of geneteic programming). The reason I would like the readers to know this is because I would appreciate it if the answers were not too complex (not too hard for a kid to understand since I haven't attended college computer science courses yet).

Here is my goal:

Terms

organsim: a CSS div
population: a group of organisms (5 or 10)
food source: another CSS div

Process

  1. A population is generated, each appearing to possess the same phenotypic attributes initially but differ in their skills (for this, speed)
  2. A single food source is generated (the same each time)
  3. After about 5 seconds of the environment being set up (steps 1 and 2), the population of organisms need to find a way to get to the food source competitively
  4. Only one organism may reach the food item. Upon reaching it, the environment is reset except the organism who found the food item the previous time is now benefitted and its speed level might increment while the others who did particularly terrible may get even slower or be terminated
  5. Process is repeated; the user may observe the traits of the population and see which ones are succeeding evolutionarily, etc.

Additional information

So as you can see, the above steps almost simulate evolution but in a very simple way (less conditions compared to real life situations for animals); Now here is why I'm asking here: I am completely lost. I really have no idea where to start (except for generating the population, I can most likely do that as well as getting them to move via jQuery animations). But being able to make them attract to a food source is what I can't do right now. So, I'd like help getting pointed in the right direction for this.

Keto answered 25/5, 2011 at 21:2 Comment(7)
Won't the organism that is the fastest always win?Apostolate
Interesting project! + ... @Nick ODell the food may appear closest to a slow one in the subsequent roundPaget
interesting question! i'd like to see the answers to :)Clearcut
@Nick ODell No, because each organism has different speed traits, so the ones that do win keep getting better while the the ones that can't will not. For example, say there are 10 organisms in the population. Organism A wins the first round because of its speed skill. So next round Organism I wins, for the same reasons. The remaining 8 have the opportunity to get to the food source and increase their skills but if they don't, eventually, after a few rounds, they will die. Then you'll have a population which are full of very fit organisms but even then they will battle for the food.Keto
(reply continued) And yes, the food is positioned somewhere else each time so the slower organisms could get to it and even beat the organisms who were at one time faster than they are.Keto
@Keto would you be offended if I did this for fun and gave you an example of how to do the entire thing.Spirant
Looks like Pac Man! Organism: Pac Man, Population: ghosts, Food source: Tic Tac's (white dots)Mccubbin
S
12

Live Example

Be warned this uses Raphael for rendering, and underscore for semantic sugar.

I wrote a very small program that kind of meets your requirements. (It was fun).

1 A population is generated, each appearing to possess the same phenotypic attributes initially but differ in their skills (for this, speed).

var Critter = function() {
    // default the speed to something random.
    this.speed = SPEED + Math.random()*SPEED;

    // logic module
    var logic = function() { ... }
}

...
// initialize an array of critters.
critters: _.map(_.range(0,COUNT), function() {
    return new Critter;    
})

Create a constructor function for your population member then populate an array of these guys. I've mapped an array of length count to an array of critters. (Cheeky for loop).

Each critter you create will be similar but have different skills (based on Math.random()) but they will contain the same logic unit.

2 A single food source is generated (the same each time)

// trivial Food object.
var Food = function() {
    // rectangle with random x, random y, and SIZE as width / height
    this.el = paper.rect(Math.random()*WIDTH, Math.random()*HEIGHT, SIZE, SIZE);    
};

The food object constructor just places a square randomly on the screen

3 After about 5 seconds of the environment being set up (steps 1 and 2), the population of organisms need to find a way to get to the food source competitively

Setting the environment up:

_.invoke(this.critters, "start", this.food.el.getBBox(), out_of_bounds);

For each critter you invoke their start method.

this.start = function(food) {
    // create a player (circle);
    this.el = paper.circle(Math.random()*WIDTH, Math.random()*HEIGHT, SIZE / 2);  
    // set an interval to run the logic over and over.
    loop = setInterval(_.bind(logic, this, food), 25);    
};

Each critter simply places itself randomly on the screen then calls its own logic over and over in a loop.

4 Only one organism may reach the food item. Upon reaching it, the environment is reset except the organism who found the food item the previous time is now benefitted and its speed level might increment while the others who did particularly terrible may get even slower or be terminated

var logic = function(food) {
    // if you hit food you win
    if (this.el.collision(food)) {
        this.win();
    }
}

// you won
this.win = function() {
    console.log("win");
    // increase speed
    this.speed += Math.random()*5;  
    // end round
    Game.end();
};

The critter will detect whether it has the food in the logic loop. Once it has the food it calls its own win method. This ends the current game round.

When a critter wins it gets a speed boost.

The game will restart itself when you call .end (after removing all current critters)

end: function () {
    // tell all critters to end their round
    _.invoke(this.critters, "remove");
    // remove the food
    this.food.el.remove();
    // start again !
    this.start();
},

5 Process is repeated; the user may observe the traits of the population and see which ones are succeeding evolutionarily, etc.

Watch the live example :)

6 What's next:

  • Tweak global numbers and other hard coded numbers
  • Implement some AI in the logic function.
  • Go through all the jsfiddles from /1 to /180 and see how it was build up.
  • Complain that comments are not detailed enough
  • Throw my code away and start from scratch now that you've seen an example.
  • The birth code just creates a "basic" Critter. It doesn't breed from two existing critters and doesn't have increased skills. This means no evolution.

Bonus:

Travels towards food

Warning: The above link does travel towards the food but it's doing something wrong, there's a dodgy bug in there I think. I don't think I'll get round to fixing that.

I'll explain the logic to travel towards the food

    // angle between critter and food
    var angle = Raphael.angle(
        this.el.getBBox().x,
        this.el.getBBox().y,
        food.x,
        food.y) - 135; // the 135 is the default direction (bottom right)
    // get a random speed
    var rand = Math.random()*this.speed;
    // travel towards the food box by rotating your vector by the angle
    var points = this.rotateVector([rand, rand], angle);

    // move towards the box
    this.el.translate(points[0], points[1]);

First rand creates a random vector that looks like this:

enter image description here

The Math.random() determines how far / fast the critter moves. This is pointing towards the bottom right corner.

Because it's pointing towards bottom right corner we have to remove 135 degrees from the angle for this vector

enter image description here

We then have to calculate the angle between the critter and the food. We do this by passing in two points to Raphael.angle and it calculates the angle for us.

enter image description here

Now we have the angle and we want to rotate our movement vector by that angle. The movement vector is currently pointing up (black) and we want to rotate it by the angle to it's new position (red). In the code this is this.rotateVector

enter image description here

Now were pointing in the right direction ! We can just call this.el.translate(points[0], points[1])

Spirant answered 25/5, 2011 at 23:13 Comment(1)
Pretty awesome start Raynos, and fast!Paget
S
0

You should break your problem into two parts:

Part 1: The organisms must be able to move toward a point you specify. Which would require a timer, and some mathematics to determine the coordinates you must move each organism in order to get it one step closer to its goal for each tick of the timer.

Google should be able to aid you in finding out the math to perform to make this work.

Part 2: The organisms need to select a food source (possibly the closest) and target that, then use the movement method described in part 1.

To do that, you might store each of your organisms and food sources in arrays. Then, during each tick of the timer, loop through your organisms, and then within that loop, loop through the food sources looking for the nearest one.

Again the math for determining distance between two sets of coordinates can be found with Google.

I don't think I can state this stuff any simpler than I have, but hopefully this gives you an idea of what direction to go in.

Swithbart answered 25/5, 2011 at 21:16 Comment(2)
Thanks! I was thinking about storing each organism's information into a database using a PHP backend.Keto
This is the right idea, but @Keto said there's only one food source.Statue
A
0

You might look at the various implementations of Conway's LIFE for inspiration. I believe you might already have seen something similar?

Interesting reading: Cellular Automata

Autohypnosis answered 25/5, 2011 at 21:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.