reflex snow_accumulation when: allow_snow_accumulation {
if (debug_snow){
//write "Accumulating snow in cycle: " + current_cycle;
}
float new_snow <- 0.0;
ask road {
float random_rate <- base_snow_accumulation_rate * (1.0 + rnd(0.2));
geometry road_line <- shape;
list<point>road_points <- points_on(road_line, 5.0);
loop pt over: road_points {
float new_value <- snow_field[pt] + random_rate;
snow_field[pt] <- new_value;
new_snow <- new_snow + random_rate;
total_snow <- total_snow + new_snow;
}
//save [current_cycle, self.name, total_snow] to:"snow_roads.csv" header:true rewrite:false;
}
diffuse var: snow_field on: snow_field proportion: 0.9;
}
And for the plows, I am now at the point where I have decided to move on with a logic of dividing the roads into chunks and each plow gets assigned a chunk to clear it from snow , but it is not working as expected:
species plows skills: [moving] control: simple_bdi {
// Existing variables
float view_dist <- 200.0;
float speed <- 900 #m/#h;
point target;
road current_road;
road selected_road;
road target_road;
list<road> zone_roads <- [];
path shortest_path;
// Helper plow coordination
plow helper_plow;
list<plow> helper_plows <- [];
float snow_threshold <- 1.0;
bool needs_help <- false;
bool is_waiting <- false;
bool helper_has_arrived <- false;
// Road clearing variables - restructured for better management
list<road> all_roads_to_clear <- []; // Master list of all roads that need clearing
list<road> current_clearing_batch <- []; // Current batch of roads being cleared
int batch_size <- 5; // Number of roads to process in each batch
//Road clearing variables CHUNKS !!!!
map<road, list<point>> road_chunks <- []; // Stores divided chunks per road
map<point, bool> chunk_cleared <- []; // Tracks which chunks are cleared
// Log that the simulation is initializing
init {
write "Simulation started: Road chunking system initialized.";
}
map<plows, point> plow_target <- [];
// road current_clearing_road <- nil;
// list<point> points_to_clear <-[];
// int current_road_index <- 0; // Index of the current road being cleared
// bool road_completed <- false;
// Road state tracking
map<road, float> road_initial_snow <- []; // Initial snow amount on each road
map<road, float> road_cleared_percentage <- []; // Percentage of snow cleared on each road
// Performance tracking
map<plows, float> snow_cleared <- [];
float total_snow_cleared <- 0.0;
list<list<string>> snow_cleared_log <- [];
string assigned_zone <- "Unknown";
// Road evaluation function - enhanced for better decision making
float calculate_road_score(road rd) {
float snow_amount <- snow_field[rd.location];
float priority_score <- 1.5 - (rd.priority * 0.5);
// Enhanced distance calculation with diminishing returns
float distance_to_road <- self.location distance_to rd.location;
float distance_factor <- exp(-distance_to_road / 500) * 0.1;
// Snow factor with threshold consideration
float snow_factor;
if (snow_amount < snow_threshold) {
snow_factor <- 0.1; // Very low priority if snow is below threshold
} else {
snow_factor <- (1 - exp(-snow_amount / 50)) * 0.7;
}
// Road connectivity factor - prioritize connected roads for efficient clearing
float connectivity_factor <- 0.0;
if (current_road != nil) {
list<road> connected_roads <- road_network neighbors_of current_road;
if (connected_roads contains rd) {
connectivity_factor <- 0.2; // Bonus for connected roads
}
}
// Final Score - with connectivity consideration
float final_score <- snow_factor + (distance_factor * 0.2) + priority_score + connectivity_factor;
return final_score;
}
// Initialize snow clearing system
reflex start_plow_movement when: current_cycle = 60 {
do add_desire(initialize_road_clearing);
}
action divide_road_into_chunks(road rd) {
float chunk_size <- 10.0;
list<point> road_points <- [];
list<point> chunks <- []; // Store generated chunks
float distance_traveled <- 0.0;
float total_length <- 0.0;
road_points <- rd.shape.points;
write "Processing Road " + rd + " with " + length(road_points) + " points.";
if (empty(road_points) or length(road_points) < 2) {
write "Warning: Road " + rd + " has too few points.";
return;
}
point last_point <- road_points[0];
// Calculate total road length
loop pt over: road_points {
float segment_distance <- last_point distance_to pt;
total_length <- total_length + segment_distance;
last_point <- pt;
}
write "Debug: Road " + rd + " total length: " + total_length + " meters.";
if (total_length < chunk_size) {
write "Warning: Road " + rd + " is too short for a chunk.";
return;
}
// Reset for chunking process
distance_traveled <- 0.0;
last_point <- road_points[0];
// Loop through points and create chunks
loop pt over: road_points {
float segment_distance <- last_point distance_to pt;
distance_traveled <- distance_traveled + segment_distance;
if (distance_traveled >= chunk_size) {
add pt to: chunks;
chunk_cleared[pt] <- false;
write "Chunk created at: " + pt;
distance_traveled <- 0.0;
}
last_point <- pt;
}
// Store chunks
if (!empty(chunks)) {
put chunks at: rd in: road_chunks;
write "Road " + rd + " divided into " + length(chunks) + " chunks.";
} else {
write "Warning: Road " + rd + " had points but no valid chunks.";
}
write "Finished chunking for road: " + rd;
}
action prepare_next_batch {
current_clearing_batch <- [];
int assigned <- 0;
write "Debug: Running prepare_next_batch...";
// Log how many roads have chunks
write "Debug: Total roads with chunks: " + length(road_chunks.keys);
loop rd over: all_roads_to_clear {
if (rd in road_chunks and !empty(road_chunks[rd])) {
loop chunk over: road_chunks[rd] {
if (chunk_cleared[chunk] = false and !(chunk in plow_target.values)) {
put chunk at: self in: plow_target;
assigned <- assigned + 1;
write name + " assigned to chunk at " + chunk;
break;
}
}
}
if (assigned >= 1) { break; } // Assign only one chunk per plow for now
}
// if (assigned = 0) {
// write name + " found no new chunks, retrying next cycle.";
// do prepare_next_batch;
// } else {
// do add_desire(clear_current_batch);
// }
}
plan clear_current_batch intention: clear_current_batch {
// If no target, get new chunk
if (!(self in plow_target) or chunk_cleared[plow_target[self]]) {
do remove_intention(clear_current_batch, true);
do prepare_next_batch();
return;
}
// Move to assigned chunk
target <- plow_target[self];
path followed_path <- goto(target: target, on: road_network, speed: speed);
// Clear snow only in assigned chunk
if (followed_path != nil and followed_path.shape != nil) {
float current_snow <- snow_field[location];
if (current_snow > 0) {
float snow_removed <- min(current_snow, 30.0);
snow_field[location] <- max(0, current_snow - snow_removed);
// Mark chunk as cleared if no snow remains
if (snow_field[location] = 0) {
chunk_cleared[plow_target[self]] <- true;
write name + " completed clearing chunk.";
//remove plow_targets[self]; // Remove plow's assignment
do prepare_next_batch(); // Assign next chunk
}
}
}
}
plan call_for_help intention: call_for_help {
if (length(helper_plows) > 0) {
is_waiting <- false;
helper_has_arrived <- true;
do remove_intention(call_for_help, true);
write name + " received help from " + length(helper_plows) + " helper plows";
}
}
// Perception of roads
perceive target: road {
float current_snow <- snow_field[location];
}
aspect default {
draw rectangle(6, 12) rotated_by (heading + 90) color: rgb(255, 95, 21) depth: 1 size: 20;
if (target != nil) {
// Visual indicators can be added here
}
}
}
Thank you.