-
in order to limit memory usage, I'm trying to make a moore sequence function, basically to map the FLAMEGPU_AGENT_FUNCTION(get_game_list, flamegpu::MessageArray2D, flamegpu::MessageNone) {
const unsigned int my_x = FLAMEGPU->getVariable<unsigned int>("x_a");
const unsigned int my_y = FLAMEGPU->getVariable<unsigned int>("y_a");
const unsigned int my_id = FLAMEGPU->getID();
// iterate over all cells in the neighbourhood
// this also wraps across env boundaries.
unsigned int num_neighbours = 0;
unsigned int neighbour_id = 0;
unsigned int num_responders = 0;
for (auto &message : FLAMEGPU->message_in.wrap(my_x, my_y, 1)) {
flamegpu::id_t competitor_id = message.getVariable<flamegpu::id_t>("id");
// challenge competitor if competitor id is higher
if (competitor_id > my_id) {
// valid neighbour
++num_neighbours;
// we will challenge them
++num_responders;
FLAMEGPU->setVariable<flamegpu::id_t, 8>("game_list", neighbour_id, competitor_id);
} else {
if (competitor_id != flamegpu::ID_NOT_SET) {
// valid neighbour, but they are our challenger
++num_neighbours;
}
FLAMEGPU->setVariable<flamegpu::id_t, 8>("game_list", neighbour_id, flamegpu::ID_NOT_SET);
}
++neighbour_id;
}
// If there are no neighbours, it's time to move, otherwise let's play a game.
if (num_neighbours == 0) {
float my_energy = FLAMEGPU->getVariable<float>("energy");
float travel_cost = FLAMEGPU->environment.getProperty<float>("travel_cost");
// try and deduct travel cost, die if below zero, this will prevent
// unnecessary movement requests
my_energy -= travel_cost;
if (my_energy <= 0.0) {
return flamegpu::DEAD;
}
FLAMEGPU->setVariable<float>("energy", my_energy);
// we have to move
FLAMEGPU->setVariable<unsigned int>("agent_status", 32);
} else {
// we have to play a game
FLAMEGPU->setVariable<unsigned int>("agent_status", 8);
}
FLAMEGPU->setVariable<unsigned int>("challengers", num_neighbours - num_responders);
FLAMEGPU->setVariable<unsigned int>("responders", num_responders);
return flamegpu::ALIVE;
}
FLAMEGPU_HOST_DEVICE_FUNCTION void pos_from_moore_seq(const unsigned int x, const unsigned int y, unsigned int &move_index, unsigned int &new_x, unsigned int &new_y, const unsigned int env_max) {
// uniform int represents the direction to move,
// e.g. for radius 1, 0 = northwest, 1 = west, 2 = southwest, 3 = north
// (4 = no movement), 5 = south, 6 = northeast, 7 = east, 8 = southeast
if (move_index >= 4) {
++move_index;
} else if (move_index > 9) {
// wrap around the space, e.g. with radius 1, if move_index is 10, then move_index = 1.
move_index = move_index % 9;
}
// Convert to x,y offsets
const int new_x_offset = move_index / 3 - 1;
const int new_y_offset = move_index % 3 - 1;
// const int new_x_offset = move_index % 3 - 1;
// const int new_y_offset = move_index / 3 - 1;
// set location to new x,y and wrap around env boundaries
new_x = (x + new_x_offset) % env_max;
new_y = (y + new_y_offset) % env_max;
}
FLAMEGPU_AGENT_FUNCTION(play_challenge, flamegpu::MessageNone, flamegpu::MessageArray2D) {
unsigned int game_sequence = FLAMEGPU->getVariable<unsigned int>("game_sequence");
flamegpu::id_t opponent = FLAMEGPU->getVariable<flamegpu::id_t, 8>("game_list", game_sequence);
if (opponent == flamegpu::ID_NOT_SET) {
// no opponent in this sequence, move along
++game_sequence;
FLAMEGPU->setVariable<unsigned int>("game_sequence", game_sequence);
return flamegpu::ALIVE;
}
// opponent found, play a game
const unsigned int my_x = FLAMEGPU->getVariable<unsigned int>("x_a");
const unsigned int my_y = FLAMEGPU->getVariable<unsigned int>("y_a");
// opponent location
unsigned int opponent_x;
unsigned int opponent_y;
// this is dumb, but it's passed as a reference
unsigned int local_game_seq = game_sequence;
pos_from_moore_seq(my_x, my_y, local_game_seq, opponent_x, opponent_y, 32);
// set message to opponent
FLAMEGPU->message_out.setVariable<flamegpu::id_t>("id", FLAMEGPU->getID());
// no other agent should have the same opponent this round
// so no issue with multiple messages out
FLAMEGPU->message_out.setIndex(opponent_x, opponent_y);
const unsigned int num_challengers = FLAMEGPU->getVariable<unsigned int>("challengers");
unsigned int num_responders = FLAMEGPU->getVariable<unsigned int>("responders");
// decrement responders
--num_responders;
// update agent
if (num_responders + num_challengers <= 0) {
FLAMEGPU->setVariable<unsigned int>("agent_status", 16);
} else {
// we don't need to waste a variable set op
++game_sequence;
FLAMEGPU->setVariable<unsigned int>("game_sequence", game_sequence);
}
FLAMEGPU->setVariable<unsigned int>("responders", num_responders);
return flamegpu::ALIVE;
}
For my movement submodel, it seems to work perfectly, and agents move (starting with a random The problem I'm getting is with the previous layer (in a different submodel), which is the code outlined above. All the hardcoded When the agent Again, this must be something silly I've done (or another misunderstanding, or both), but as I understand it, if the agents have a sequence of runs in the submodel, their variable And if the execution of the game play is sequential, each agent should play either nobody, or another agent in the same direction as all the other players for that step, which should make multiple messages to the same index impossible, yet, the fact that it's happening points to some major flaw in my implementation haha. I looked at the code (https://docs.flamegpu.com/api/program_listing_file_include_flamegpu_runtime_messaging_MessageArray2D_MessageArray2DDevice.cuh.html), and as I understood it, the moore wrap works in the following way for radius of 1:
Full code here, if it's necessary, but it's...not exactly pretty: https://github.com/zeyus/SoCultABM/blob/OL_PD/src/pd/model.py If I can get my head around this and get this method working, I'll retroactively apply it to the movement, because I think it should more efficient, even though it might require a max of Maybe another approach might be to add another message layer and have a function input a message array, and check if there is any move attempt, and broadcast a new location...given the current configuration, agents only move if they have no neighbours, which makes it impossible for every space around them to be taken after agents move, there can only be a maximum of 4 agents trying to move to a particular grid location. Movement only with the game main model layers commented out (movement uses the same |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 18 replies
-
I expect this refers to 12 agents calling It probably also checks bins of the array list in order, so highly likely you have collisions in other elements of the arraylist too. As you've said in your other comment, you probably want agents to output a message at their own location, rather than at their desired location (as there might be a conflict there). If you want to support multiple messages at a location, you will need to switch to |
Beta Was this translation helpful? Give feedback.
I expect this refers to 12 agents calling
FLAMEGPU->message_out.setIndex(opponent_x, opponent_y);
with the arguments(0,0)
. It's thrown from a common method used by all 3 forms of array message, so the dimensions aren't available (it sees them all as 1D).It probably also checks bins of the array list in order, so highly likely you have collisions in other elements of the arraylist too.
As you've said in your other comment, you probably want agents to output a message at their own location, rather than at their desired location (as there might be a conflict ther…