简单AI - JavaScript(使用jQuery进行动画)

22
首先,我想让您知道我已经作为一项业余爱好编程了几年(主要是基于C的语言,iOS开发,网页等等),现在对创建一个简单的AI产生了兴趣(大多数人都从井字游戏开始,但我有兴趣使用遗传编程的原则制作一些东西)。我希望读者知道这一点,因为我希望答案不要过于复杂(对一个孩子来说不要太难理解,因为我还没有参加大学的计算机科学课程)。
这是我的目标:
术语 - organism:CSS div - population:一组生物体(5或10个) - food source:另一个CSS div
进程: 1.生成人口,每个人口最初看起来具有相同的表型属性,但在技能方面有所不同(例如速度) 2.生成单个食物来源(每次相同) 3.设置环境约5秒钟后(步骤1和2),生物人口需要找到一种竞争性地到达食物来源的方法 4.只有一个生物体可以到达食物。到达它后,环境被重置,除了上一次找到食物物品的生物体会得到益处,并且它的速度水平可能会增加,而那些特别糟糕的生物体可能会变得更慢或被终止 5.重复这个过程,用户可以观察人口的特征并看到哪些人成功地进化等等。
其他信息: 因此,如您所见,上述步骤几乎模拟了进化,但以一种非常简单的方式进行(与动物的现实情况相比少了条件); 现在我在这里问的原因是:我完全迷失了。 我真的不知道从哪里开始(除了生成人口,我最有可能做到这一点以及通过jQuery动画使它们移动)。 但是能够让它们吸引食物来源是我现在无法做到的。 因此,我希望得到帮助,指导我正确的方向。

3
速度最快的生物总是会获胜吗? - Nick ODell
有趣的项目!+ ... @Nick ODell 食物在下一轮中可能看起来最接近缓慢的一个。 - mVChr
有趣的问题!我想看看答案 :) - Patricia
是的,食物每次都会放在其他地方,这样较慢的生物就能够到达它,甚至可以赶超曾经比它们更快的生物。 - Alex
@Alex,如果我为了好玩而这样做,并给你一个如何完成整个事情的示例,你会感到冒犯吗? - Raynos
显示剩余2条评论
3个回答

12

实时示例

请注意,此代码使用 Raphael 进行渲染,并使用 underscore 进行语义糖。

我编写了一个非常小的程序,基本符合您的要求(这很有趣)。

1 生成一组个体,初始时每个个体看起来具有相同的表型属性,但在技能方面却不同(例如速度)。

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;    
})
创建一个人口成员的构造函数,然后用这些人口成员填充一个数组。我已经将长度为count的数组映射到了一个生物数组中。(使用了一个调皮的for循环)
每个你创建的生物都会相似,但具有不同的技能(基于Math.random()),但它们将包含相同的逻辑单元。

2 生成一个单一的食物源(每次相同)

// 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);    
};

食物对象构造函数只是随机地将一个正方形放置在屏幕上。

3 在设置环境(步骤1和2)约5秒钟后,生物种群需要竞争地找到一种方法到达食物来源

设置环境:

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

对于每个生物,调用其启动方法。

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);    
};

每个生物只是在屏幕上随机放置自己,然后在循环中反复调用自己的逻辑。

4 只有一个生物可以到达食物。达到目标后,环境将被重置,除了找到食物的生物上一次获益外,其速度级别可能会增加,而那些表现特别糟糕的生物可能会变得更慢或被终止。

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();
};

这个生物将在逻辑循环中检测是否有食物。一旦它获得了食物,就会调用自己的胜利方法。这会结束当前游戏回合。

当生物获胜时,它将获得速度提升。

当你调用.end时(在移除所有当前生物后),游戏将重新启动。

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 这个过程会被重复执行;用户可以观察种群的特征,看哪些特征在进化中成功等。

查看实时示例 :)

6 下一步:

  • 微调全局数字和其他硬编码数字
  • logic 函数中实现一些人工智能。
  • 从 /1 到 /180 遍历所有 jsfiddles,看看它是如何构建的。
  • 抱怨评论不够详细
  • 在您看到一个示例之后扔掉我的代码并重新开始。
  • 出生代码只创建一个 "基本的" Critter。它不会从两个现有的 Critters 繁殖,也没有增加技能。这意味着没有进化。

奖励:

向食物移动

警告:上面的链接确实会朝着食物前进,但其中有一个错误,我认为有一个虚假的 bug。我想我不会去修复它。

我将解释朝着食物前进的逻辑。

    // 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]);

rand首先创建一个看起来像这样的随机向量:

enter image description here

Math.random()确定了生物移动的距离/速度。这个向量指向右下角。

因为它指向右下角,所以我们必须从该向量的角度中减去135度。

enter image description here

然后,我们需要计算生物和食物之间的夹角。我们通过将两个点传递到Raphael.angle中来完成这个操作,并由它为我们计算出该角度。

enter image description here

现在我们有了角度,我们希望将我们的运动向量旋转该角度。运动向量当前指向上方(黑色),我们希望将其旋转到新位置(红色)。在代码中,这是通过this.rotateVector实现的。

enter image description here

现在我们指向了正确的方向!我们只需调用this.el.translate(points[0], points[1])即可。


4
很棒的开端,Raynos!而且速度很快! - mVChr

0

你应该将问题分成两个部分:

第一部分:生物必须能够朝着你指定的点移动。这需要一个计时器和一些数学知识来确定每个生物必须移动的坐标,以便在计时器的每个滴答声中使其更接近目标。

谷歌应该能够帮助你找到所需的数学知识。

第二部分:生物需要选择一个食物来源(可能是最近的),并将其作为目标,然后使用第一部分描述的移动方法。

为此,你可以将每个生物和食物来源存储在数组中。然后,在计时器的每个滴答声中,循环遍历你的生物,然后在该循环内,循环遍历食物来源,寻找最近的那一个。

同样,可以通过谷歌找到确定两组坐标之间距离的数学公式。

我认为我已经尽可能简单地阐述了这些内容,但希望这能给你一个方向。


谢谢!我在考虑使用PHP后端将每个生物体的信息存储到数据库中。 - Alex
1
这是正确的想法,但@Alex说只有一个食物来源。 - squidbe

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接