Skip to content

Instantly share code, notes, and snippets.

Created November 26, 2010 06:33
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/716352 to your computer and use it in GitHub Desktop.
Save anonymous/716352 to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "ants.h"
void runSimulation(int steps, int numAnts, int pathLength, double bias, double decay){
// Allocate a block of Nodes and Ants
// Assuming pathLength of 50, it'd be as follows:
// Node[0..49] : path to food A (A)
// Node[50..99] : path to food B (B)
// Node[100] : Center / Colony
// Node[101] : Food A
// Node[102] : Food B
FILE* file = fopen("ants.dat", "a");
Node *nodes = calloc(pathLength * 2 + 3, sizeof(Node));
Ant *ants = calloc(numAnts, sizeof(Ant));
/* Setup */
Node *center = &nodes[2*pathLength]; center->type = CenterNode;
Node *foodA = &nodes[2*pathLength + 1]; foodA->type = UnaryNode;
Node *foodB = &nodes[2*pathLength + 2]; foodB->type = UnaryNode;
Node *currentNode, *prevNode;
for (int path = 0; path < 2; path++) {
// Start each path with the center node
currentNode = &nodes[path*pathLength + 0];
currentNode->type = BinaryNode;
// Start the series on the correct branch
switch (path) {
case 0: // A
center->pathA = currentNode;
currentNode->prev = center;
break;
case 1: // B
center->pathB = currentNode;
currentNode->prev = center;
break;
}
prevNode = currentNode;
// Start at 1 since 1st node is already connected
for (int i = 1; i < pathLength; i++) {
// Set all nodes along each path as Binary
currentNode = &nodes[path*pathLength + i];
currentNode->type = BinaryNode;
// Link nodes
currentNode->prev = prevNode;
prevNode->next = currentNode;
// Assign previous to next
prevNode = currentNode;
}
// End each path with the appropriate endpoint
switch (path) {
case 0: // A
prevNode->next = foodA;
foodA->prev = prevNode;
break;
case 1: // B
prevNode->next = foodB;
foodB->prev = prevNode;
break;
}
}
// Set all ants to start at colony
for (int i = 0; i < numAnts; i++) {
ants[i].currentNode = center;
}
// Seed the random number generator
srand(time(NULL));
// Iterate through time steps
int antsOnA = 0;
for (int t = 0; t < steps; t++) {
antsOnA = 0;
/* Decay Pheromone */
for (int path = 0; path < 2; path++) {
Node *nodeToDecay = (path == 0)?(center->prev):(center->next);
while (nodeToDecay->type != UnaryNode) {
nodeToDecay->pheromone -= nodeToDecay->pheromone * decay;
nodeToDecay = nodeToDecay->next;
}
}
/* Move Ants */
for (int a = 0; a < numAnts; a++) {
Ant *ant = &ants[a];
if (ant->hasFood == true) {
/* Exploitation Movement :
* 1) If the ant has food, it should proceed directly back to the colony.
* 2) Once it reaches the center, it will lose its food and return to Scavenging Movement
*/
ant->currentNode = ant->currentNode->prev;
}
else {
/* Scavenging Movement
* 1) At each decision point, direction is biased based on pheromone
* 2) The food sources are infinitely attractive (ant will always enter it if it has food, and is next to it)
*/
switch (ant->currentNode->type) {
// NOTE: 'prev' is inward, 'next' is outward.
// A <========== C ===========> B
case UnaryNode: {// food A or B (only one movement options)
ant->currentNode = ant->currentNode->prev;
break;
}
case CenterNode:
// In the event of the ant being on the colony, the logic is identical to any other binary node.
// It should be noted that "next" is equivalent to "pathA" and "prev" is equivalent to "pathB"
case BinaryNode: { // path (two options, pheromone biased)
// (not using) 50/50 behavior
//ant->currentNode = (rand() % 2)?(ant->currentNode->next):(ant->currentNode->prev); break;
// Food sources infinitely attractive if they have food
if ((ant->currentNode->next == foodA && foodAtA) || (ant->currentNode->next == foodB && foodAtB)) {
ant->currentNode = ant->currentNode->next;
break;
}
// Normal case (biased by pheromone)
double nextPheromone = ant->currentNode->next->pheromone + 1;
double prevPheromone = ant->currentNode->prev->pheromone + 1;
double random = ((nextPheromone + prevPheromone) * rand()) / (RAND_MAX + 1.0);
//double random = ((double)rand()/RAND_MAX) * (nextPheromone + prevPheromone);
if (random <= nextPheromone) {
ant->currentNode = ant->currentNode->next;
}
else {
ant->currentNode = ant->currentNode->prev;
}
break;
}
default:
perror("Error: Invalid Node");
exit(-1);
break;
}
}
/* Toggle food */
if (ant->currentNode == foodA && foodAtA) {
ant->hasFood = true;
}
if (ant->currentNode == foodB && foodAtB) {
ant->hasFood = true;
}
if (ant->currentNode == center) {
ant->hasFood = false;
}
/* Deposit Pheromone */
if (ant->hasFood) {
ant->currentNode->pheromone += 1;
}
/* Tally ants on current branch */
Node *tallyNode = ant->currentNode;
if (tallyNode == center) {
continue;
}
while (tallyNode->type != UnaryNode) {
tallyNode = tallyNode->next;
}
if (tallyNode == foodA) {
antsOnA++;
}
} // a
} // t
// Output ants on path, and pheromone decay rate
fprintf(file, "%f %d\n", decay, antsOnA);
free(nodes);
free(ants);
fclose(file);
}
#ifndef _ANTS_H_
#define _ANTS_H_
// Boolean data type!
#import <stdbool.h>
#pragma mark Data Types
typedef enum {
NullaryNode = 0,
UnaryNode = 1,
BinaryNode = 2,
CenterNode = 3
} NodeType;
#pragma mark Structures
// Base Node
typedef struct node_struct Node;
struct node_struct {
double pheromone;
NodeType type;
union {
struct {
Node *next;
Node *prev;
};
struct {
Node *pathA;
Node *pathB;
};
};
};
const static int foodAtA = true;
const static int foodAtB = true;
typedef struct ant_struct Ant;
struct ant_struct {
bool hasFood;
Node *currentNode;
};
#pragma mark Functions
void runSimulation(int steps, int numAnts, int pathLength, double bias, double decay);
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment