/* Insert an unbound ball into a node. */ void node_insert (struct ball_node *node, struct ball *ball) { unsigned int offset; if (ball->node) { simlog (SLC_DEBUG, "node_insert: %s already at %s", ball->name, ball->node->name); return; } if (node_full_p (node) || !node->type) { simlog (SLC_DEBUG, "node_insert: %s not allowed", node->name); return; } offset = (node->head + node->count) % node->size; node->ball_queue[offset] = ball; node->count++; ball->node = node; ball->pos = offset; if (node->type->insert) node->type->insert (node, ball); #ifdef CONFIG_UI ui_update_ball_tracker (ball->index, node->name); #endif simlog (SLC_DEBUG, "node_insert: added %s to %s, count=%d", ball->name, node->name, node->count); if (node->unlocked && !node_full_p (node->next)) sim_time_register (100, FALSE, (time_handler_t)node_kick_delayed, node); }
/** * Move a ball to a specific location. */ void sim_ball_move (unsigned int ballno, unsigned int location) { unsigned int prev_location; if (ballno == -1) return; /* Remove the ball from its previous location */ prev_location = sim_ball_location[ballno]; if (prev_location != SIM_LOCATION_NONE) { sim_location_toggle (prev_location); sim_location_ball[location] = SIM_NO_BALL_HERE; } /* Set the ball at the new location */ sim_location_toggle (location); sim_ball_location[ballno] = location; sim_location_ball[location] = ballno; #ifdef CONFIG_UI ui_update_ball_tracker (ballno, location); #endif simlog (SLC_DEBUG, "Ball %d @ %s", ballno, sim_ball_location_name (location)); }
/* Move a ball from one location to another. The two nodes do not have to be connected via the default topology. */ void node_move (struct ball_node *dst, struct ball_node *src) { struct ball *ball; if (!dst || !src) return; /* If there are already too many balls in the destination, then don't allow the operation: it must remain where it is. */ if (node_full_p (dst)) { simlog (SLC_DEBUG, "node_kick %s: destination %s is full", src->name, dst->name); return; } ball = node_remove (src); if (!ball) { simlog (SLC_DEBUG, "node_kick: no balls in %s", src->name); return; } simlog (SLC_DEBUG, "node_kick: %s -> %s", src->name, dst->name); /* If no delay is associated with a movement from the source, then the move is instantaneous. Otherwise, it will be performed later; in the meantime the ball is not associated with any node. */ if (src->delay == 0) node_insert (dst, ball); else { #ifdef CONFIG_UI ui_update_ball_tracker (ball->index, src->name); #endif node_insert_delay (dst, ball, src->delay); } }
/* Remove the head of the node queue. */ struct ball *node_remove (struct ball_node *node) { unsigned int offset; struct ball *ball; if (node->count == 0) { simlog (SLC_DEBUG, "node_remove: no balls in %s", node->name); return NULL; } offset = node->head % node->size; ball = node->ball_queue[offset]; if (!ball) { simlog (SLC_DEBUG, "node_remove: count=%d but ball is null?", node->count); return NULL; } node->head++; node->count--; ball->node = NULL; if (node->type->remove) node->type->remove (node, ball); #ifdef CONFIG_UI ui_update_ball_tracker (ball->index, "Free"); #endif simlog (SLC_DEBUG, "node_remove: took %s from %s", ball->name, node->name); if (node->prev && node->prev->unlocked && node->prev->count != 0) { node_kick (node->prev); } return ball; }